From 958093df591216cde9847268e24747b66b85de94 Mon Sep 17 00:00:00 2001 From: Fatih Arslan Date: Sun, 25 Oct 2015 16:08:09 +0300 Subject: [PATCH] printer: implement a working version --- printer/nodes.go | 76 ++++++++++++++++++++++++++++++++++------- printer/printer.go | 43 ++--------------------- printer/printer_test.go | 9 +++-- 3 files changed, 71 insertions(+), 57 deletions(-) diff --git a/printer/nodes.go b/printer/nodes.go index 9be9f4e..f03e132 100644 --- a/printer/nodes.go +++ b/printer/nodes.go @@ -3,30 +3,38 @@ package printer import ( "bytes" "fmt" + "io" "github.com/fatih/hcl/ast" ) +const ( + blank = byte(' ') + newline = byte('\n') + tab = byte('\t') +) + func (p *printer) printNode(n ast.Node) []byte { var buf bytes.Buffer switch t := n.(type) { case *ast.ObjectList: - fmt.Println("printing objectList", t) - for _, item := range t.Items { + for i, item := range t.Items { buf.Write(p.printObjectItem(item)) + if i != len(t.Items)-1 { + buf.WriteByte(newline) + } } case *ast.ObjectKey: - fmt.Println("printing objectKey", t) + buf.WriteString(t.Token.Text) case *ast.ObjectItem: - fmt.Println("printing objectItem", t) buf.Write(p.printObjectItem(t)) case *ast.LiteralType: - buf.Write(p.printLiteral(t)) + buf.WriteString(t.Token.Text) case *ast.ListType: buf.Write(p.printList(t)) case *ast.ObjectType: - fmt.Println("printing ObjectType", t) + buf.Write(p.printObjectType(t)) default: fmt.Printf(" unknown type: %T\n", n) } @@ -39,14 +47,12 @@ func (p *printer) printObjectItem(o *ast.ObjectItem) []byte { for i, k := range o.Keys { buf.WriteString(k.Token.Text) - if i != len(o.Keys)-1 || len(o.Keys) == 1 { - buf.WriteString(" ") - } + buf.WriteByte(blank) // reach end of key if i == len(o.Keys)-1 { buf.WriteString("=") - buf.WriteString(" ") + buf.WriteByte(blank) } } @@ -58,6 +64,26 @@ func (p *printer) printLiteral(l *ast.LiteralType) []byte { return []byte(l.Token.Text) } +func (p *printer) printObjectType(o *ast.ObjectType) []byte { + var buf bytes.Buffer + buf.WriteString("{") + buf.WriteByte(newline) + + for _, item := range o.List.Items { + // buf.WriteByte(tab) + // buf.Write(p.printObjectItem(item)) + + a := p.printObjectItem(item) + a = indent(a) + buf.Write(a) + + buf.WriteByte(newline) + } + + buf.WriteString("}") + return buf.Bytes() +} + func (p *printer) printList(l *ast.ListType) []byte { var buf bytes.Buffer buf.WriteString("[") @@ -65,20 +91,44 @@ func (p *printer) printList(l *ast.ListType) []byte { for i, item := range l.List { if item.Pos().Line != l.Lbrack.Line { // not same line - buf.WriteString("\n") + buf.WriteByte(newline) } + buf.WriteByte(tab) buf.Write(p.printNode(item)) if i != len(l.List)-1 { buf.WriteString(",") - buf.WriteString(" ") + buf.WriteByte(blank) } else if item.Pos().Line != l.Lbrack.Line { buf.WriteString(",") - buf.WriteString("\n") + buf.WriteByte(newline) } } buf.WriteString("]") return buf.Bytes() } + +func writeBlank(buf io.ByteWriter, indent int) { + for i := 0; i < indent; i++ { + buf.WriteByte(blank) + } +} + +func indent(buf []byte) []byte { + splitted := bytes.Split(buf, []byte{newline}) + newBuf := make([]byte, len(splitted)) + for i, s := range splitted { + s = append(s, 0) + copy(s[1:], s[0:]) + s[0] = tab + newBuf = append(newBuf, s...) + + if i != len(splitted)-1 { + newBuf = append(newBuf, newline) + } + } + + return newBuf +} diff --git a/printer/printer.go b/printer/printer.go index 4121569..a8ddca5 100644 --- a/printer/printer.go +++ b/printer/printer.go @@ -1,7 +1,6 @@ package printer import ( - "fmt" "io" "text/tabwriter" @@ -15,24 +14,12 @@ type printer struct { } func (p *printer) output() []byte { - fmt.Println("STARTING OUTPUT") return p.printNode(p.node) } -// A Mode value is a set of flags (or 0). They control printing. -type Mode uint - -const ( - RawFormat Mode = 1 << iota // do not use a tabwriter; if set, UseSpaces is ignored - TabIndent // use tabs for indentation independent of UseSpaces - UseSpaces // use spaces instead of tabs for alignment -) - // A Config node controls the output of Fprint. type Config struct { - Mode Mode // default: 0 - Tabwidth int // default: 4 - Indent int // default: 0 (all code is indented at least by this much) + SpaceWidth int // if set, it will use spaces instead of tabs for alignment } func (c *Config) fprint(output io.Writer, node ast.Node) error { @@ -41,32 +28,6 @@ func (c *Config) fprint(output io.Writer, node ast.Node) error { node: node, } - // TODO(arslan): implement this - // redirect output through a trimmer to eliminate trailing whitespace - // (Input to a tabwriter must be untrimmed since trailing tabs provide - // formatting information. The tabwriter could provide trimming - // functionality but no tabwriter is used when RawFormat is set.) - // output = &trimmer{output: output} - - // redirect output through a tabwriter if necessary - if c.Mode&RawFormat == 0 { - minwidth := c.Tabwidth - - padchar := byte('\t') - if c.Mode&UseSpaces != 0 { - padchar = ' ' - } - - twmode := tabwriter.DiscardEmptyColumns - if c.Mode&TabIndent != 0 { - minwidth = 0 - twmode |= tabwriter.TabIndent - } - - output = tabwriter.NewWriter(output, minwidth, c.Tabwidth, 1, padchar, twmode) - } - - // write printer result via tabwriter/trimmer to output if _, err := output.Write(p.output()); err != nil { return err } @@ -87,5 +48,5 @@ func (c *Config) Fprint(output io.Writer, node ast.Node) error { // Fprint "pretty-prints" an HCL node to output // It calls Config.Fprint with default settings. func Fprint(output io.Writer, node ast.Node) error { - return (&Config{Tabwidth: 4}).Fprint(output, node) + return (&Config{}).Fprint(output, node) } diff --git a/printer/printer_test.go b/printer/printer_test.go index 493733b..e7bf891 100644 --- a/printer/printer_test.go +++ b/printer/printer_test.go @@ -1,6 +1,7 @@ package printer import ( + "fmt" "os" "testing" @@ -9,7 +10,7 @@ import ( var listHCL = `foo = ["fatih", "arslan"]` var listHCL2 = `foo = [ - "fatih", + "fatih", "arslan", ]` @@ -58,8 +59,8 @@ output "web_ip" { ` func TestPrint(t *testing.T) { - // node, err := parser.Parse([]byte(complexHcl)) - node, err := parser.Parse([]byte(listHCL2)) + node, err := parser.Parse([]byte(complexHcl)) + // node, err := parser.Parse([]byte(listHCL2)) if err != nil { t.Fatal(err) } @@ -67,4 +68,6 @@ func TestPrint(t *testing.T) { if err := Fprint(os.Stdout, node); err != nil { t.Error(err) } + + fmt.Println("") }