printer: align comments in lists

This commit is contained in:
Fatih Arslan 2015-11-01 03:23:33 +03:00
parent 566c59bf69
commit c73430cb1e
7 changed files with 81 additions and 24 deletions

View File

@ -97,6 +97,9 @@ func (o *ObjectKey) Pos() token.Pos {
// token.NUMBER, token.FLOAT, token.BOOL and token.STRING // token.NUMBER, token.FLOAT, token.BOOL and token.STRING
type LiteralType struct { type LiteralType struct {
Token token.Token Token token.Token
// associated line comment, only when used in a list
LineComment *CommentGroup
} }
func (l *LiteralType) Pos() token.Pos { func (l *LiteralType) Pos() token.Pos {

View File

@ -15,7 +15,8 @@ type Parser struct {
sc *scanner.Scanner sc *scanner.Scanner
// Last read token // Last read token
tok token.Token tok token.Token
commaPrev token.Token
comments []*ast.CommentGroup comments []*ast.CommentGroup
leadComment *ast.CommentGroup // last lead comment leadComment *ast.CommentGroup // last lead comment
@ -147,7 +148,6 @@ func (p *Parser) objectItem() (*ast.ObjectItem, error) {
o.LineComment = p.lineComment o.LineComment = p.lineComment
p.lineComment = nil p.lineComment = nil
} }
p.unscan() p.unscan()
return o, nil return o, nil
} }
@ -253,6 +253,17 @@ func (p *Parser) listType() (*ast.ListType, error) {
l.Add(node) l.Add(node)
case token.COMMA: case token.COMMA:
// get next list item or we are at the end // get next list item or we are at the end
// do a look-ahead for line comment
p.scan()
if p.lineComment != nil {
lit, ok := l.List[len(l.List)-1].(*ast.LiteralType)
if ok {
lit.LineComment = p.lineComment
l.List[len(l.List)-1] = lit
p.lineComment = nil
}
}
p.unscan()
continue continue
case token.BOOL: case token.BOOL:
// TODO(arslan) should we support? not supported by HCL yet // TODO(arslan) should we support? not supported by HCL yet
@ -299,7 +310,8 @@ func (p *Parser) scan() token.Token {
var comment *ast.CommentGroup var comment *ast.CommentGroup
var endline int var endline int
// fmt.Printf("p.tok.Pos.Line = %+v prev: %d \n", p.tok.Pos.Line, prev.Pos.Line) // fmt.Printf("p.tok.Pos.Line = %+v prev: %d endline %d \n",
// p.tok.Pos.Line, prev.Pos.Line, endline)
if p.tok.Pos.Line == prev.Pos.Line { if p.tok.Pos.Line == prev.Pos.Line {
// The comment is on same line as the previous token; it // The comment is on same line as the previous token; it
// cannot be a lead comment but may be a line comment. // cannot be a lead comment but may be a line comment.

View File

@ -57,6 +57,14 @@ func (p *printer) collectComments(node ast.Node) {
// assigned to any kind of node. // assigned to any kind of node.
ast.Walk(node, func(nn ast.Node) bool { ast.Walk(node, func(nn ast.Node) bool {
switch t := nn.(type) { switch t := nn.(type) {
case *ast.LiteralType:
if t.LineComment != nil {
for _, comment := range t.LineComment.List {
if _, ok := standaloneComments[comment.Pos()]; ok {
delete(standaloneComments, comment.Pos())
}
}
}
case *ast.ObjectItem: case *ast.ObjectItem:
if t.LeadComment != nil { if t.LeadComment != nil {
for _, comment := range t.LeadComment.List { for _, comment := range t.LeadComment.List {
@ -83,6 +91,7 @@ func (p *printer) collectComments(node ast.Node) {
} }
sort.Sort(ByPosition(p.standaloneComments)) sort.Sort(ByPosition(p.standaloneComments))
} }
// output prints creates b printable HCL output and returns it. // output prints creates b printable HCL output and returns it.
@ -98,8 +107,6 @@ func (p *printer) output(n interface{}) []byte {
var commented bool var commented bool
for { for {
// TODO(arslan): refactor below comment printing, we have the same in objectType // TODO(arslan): refactor below comment printing, we have the same in objectType
// print upper leve stand alone comments
for _, c := range p.standaloneComments { for _, c := range p.standaloneComments {
for _, comment := range c.List { for _, comment := range c.List {
if index != len(t.Items) { if index != len(t.Items) {
@ -115,7 +122,6 @@ func (p *printer) output(n interface{}) []byte {
} }
buf.WriteString(comment.Text) buf.WriteString(comment.Text)
// TODO(arslan): do not print new lines if the comments are one liner
buf.WriteByte(newline) buf.WriteByte(newline)
if index != len(t.Items) { if index != len(t.Items) {
@ -153,6 +159,9 @@ func (p *printer) output(n interface{}) []byte {
return buf.Bytes() return buf.Bytes()
} }
// objectItem returns the printable HCL form of an object item. An object type
// starts with one/multiple keys and has a value. The value might be of any
// type.
func (p *printer) objectItem(o *ast.ObjectItem) []byte { func (p *printer) objectItem(o *ast.ObjectItem) []byte {
defer un(trace(p, fmt.Sprintf("ObjectItem: %s", o.Keys[0].Token.Text))) defer un(trace(p, fmt.Sprintf("ObjectItem: %s", o.Keys[0].Token.Text)))
var buf bytes.Buffer var buf bytes.Buffer
@ -187,6 +196,8 @@ func (p *printer) objectItem(o *ast.ObjectItem) []byte {
return buf.Bytes() return buf.Bytes()
} }
// objectType returns the printable HCL form of an object type. An object type
// begins with a brace and ends with a brace.
func (p *printer) objectType(o *ast.ObjectType) []byte { func (p *printer) objectType(o *ast.ObjectType) []byte {
defer un(trace(p, "ObjectType")) defer un(trace(p, "ObjectType"))
var buf bytes.Buffer var buf bytes.Buffer
@ -364,32 +375,53 @@ func (p *printer) alignedItems(items []*ast.ObjectItem) []byte {
return buf.Bytes() return buf.Bytes()
} }
func (p *printer) literal(l *ast.LiteralType) []byte { // list returns the printable HCL form of an list type.
return []byte(l.Token.Text)
}
// printList prints a HCL list
func (p *printer) list(l *ast.ListType) []byte { func (p *printer) list(l *ast.ListType) []byte {
var buf bytes.Buffer var buf bytes.Buffer
buf.WriteString("[") buf.WriteString("[")
var longestLine int
for _, item := range l.List {
// for now we assume that the list only contains literal types
if lit, ok := item.(*ast.LiteralType); ok {
lineLen := len(lit.Token.Text)
if lineLen > longestLine {
longestLine = lineLen
}
}
}
for i, item := range l.List { for i, item := range l.List {
if item.Pos().Line != l.Lbrack.Line { if item.Pos().Line != l.Lbrack.Line {
// multiline list, add newline before we add each item // multiline list, add newline before we add each item
buf.WriteByte(newline) buf.WriteByte(newline)
// also indent each line // also indent each line
buf.Write(p.indent(p.output(item))) val := p.output(item)
curLen := len(val)
buf.Write(p.indent(val))
buf.WriteString(",")
if lit, ok := item.(*ast.LiteralType); ok && lit.LineComment != nil {
for i := 0; i < longestLine-curLen+1; i++ {
buf.WriteByte(blank)
}
for _, comment := range lit.LineComment.List {
buf.WriteString(comment.Text)
}
}
if i == len(l.List)-1 {
buf.WriteByte(newline)
}
} else { } else {
buf.Write(p.output(item)) buf.Write(p.output(item))
if i != len(l.List)-1 {
buf.WriteString(",")
buf.WriteByte(blank)
}
} }
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("]") buf.WriteString("]")

View File

@ -17,4 +17,9 @@ aligned = {
default = { default = {
bar = "example" bar = "example"
} }
security_groups = [
"foo", # kenya 1
"${aws_security_group.firewall.foo}", # kenya 2
]
} }

View File

@ -13,4 +13,9 @@ aligned {
default = { default = {
bar = "example" bar = "example"
} }
security_groups = [
"foo", # kenya 1
"${aws_security_group.firewall.foo}", # kenya 2
]
} }

View File

@ -22,7 +22,7 @@ resource aws_instance "web" {
ami = "${var.foo}" ami = "${var.foo}"
security_groups = [ security_groups = [
"foo", "foo",
"${aws_security_group.firewall.foo}", "${aws_security_group.firewall.foo}",
] ]

View File

@ -11,8 +11,8 @@ foo = ["fatih", "zeynep",
] ]
foo = [ foo = [
"vim-go", "vim-go",
"golang", "golang",
"hcl", "hcl",
] ]
@ -21,7 +21,7 @@ foo = []
foo = [1, 2, 3, 4] foo = [1, 2, 3, 4]
foo = [ foo = [
"kenya", "kenya",
"ethiopia", "ethiopia",
"columbia", "columbia",
] ]