hcl/printer/nodes.go
2015-10-27 01:42:05 +03:00

146 lines
2.8 KiB
Go

package printer
import (
"bytes"
"fmt"
"github.com/fatih/hcl/ast"
)
const (
blank = byte(' ')
newline = byte('\n')
tab = byte('\t')
)
// output prints creates a printable HCL output and returns it.
func (p *printer) output(n interface{}) []byte {
var buf bytes.Buffer
switch t := n.(type) {
case *ast.ObjectList:
for i, item := range t.Items {
buf.Write(p.objectItem(item))
if i != len(t.Items)-1 {
buf.Write([]byte{newline, newline})
}
}
case *ast.ObjectKey:
buf.WriteString(t.Token.Text)
case *ast.ObjectItem:
buf.Write(p.objectItem(t))
case *ast.LiteralType:
buf.WriteString(t.Token.Text)
case *ast.ListType:
buf.Write(p.list(t))
case *ast.ObjectType:
buf.Write(p.objectType(t))
default:
fmt.Printf(" unknown type: %T\n", n)
}
return buf.Bytes()
}
func (p *printer) objectItem(o *ast.ObjectItem) []byte {
var buf bytes.Buffer
if o.LeadComment != nil {
for _, comment := range o.LeadComment.List {
buf.WriteString(comment.Text)
buf.WriteByte(newline)
}
}
for i, k := range o.Keys {
buf.WriteString(k.Token.Text)
buf.WriteByte(blank)
// reach end of key
if i == len(o.Keys)-1 && len(o.Keys) == 1 {
buf.WriteString("=")
buf.WriteByte(blank)
}
}
buf.Write(p.output(o.Val))
if o.Val.Pos().Line == o.Keys[0].Pos().Line && o.LineComment != nil {
buf.WriteByte(blank)
for _, comment := range o.LineComment.List {
buf.WriteString(comment.Text)
}
}
return buf.Bytes()
}
func (p *printer) literal(l *ast.LiteralType) []byte {
return []byte(l.Token.Text)
}
func (p *printer) objectType(o *ast.ObjectType) []byte {
var buf bytes.Buffer
buf.WriteString("{")
buf.WriteByte(newline)
for _, item := range o.List.Items {
buf.Write(p.indent(p.objectItem(item)))
buf.WriteByte(newline)
}
buf.WriteString("}")
return buf.Bytes()
}
// printList prints a HCL list
func (p *printer) list(l *ast.ListType) []byte {
var buf bytes.Buffer
buf.WriteString("[")
for i, item := range l.List {
if item.Pos().Line != l.Lbrack.Line {
// multiline list, add newline before we add each item
buf.WriteByte(newline)
// also indent each line
buf.Write(p.indent(p.output(item)))
} else {
buf.Write(p.output(item))
}
if i != len(l.List)-1 {
buf.WriteString(",")
buf.WriteByte(blank)
} else if item.Pos().Line != l.Lbrack.Line {
buf.WriteString(",")
buf.WriteByte(newline)
}
}
buf.WriteString("]")
return buf.Bytes()
}
// indent indents the lines of the given buffer for each non-empty line
func (p *printer) indent(buf []byte) []byte {
var prefix []byte
if p.cfg.SpacesWidth != 0 {
for i := 0; i < p.cfg.SpacesWidth; i++ {
prefix = append(prefix, blank)
}
} else {
prefix = []byte{tab}
}
var res []byte
bol := true
for _, c := range buf {
if bol && c != '\n' {
res = append(res, prefix...)
}
res = append(res, c)
bol = c == '\n'
}
return res
}