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
type LiteralType struct {
Token token.Token
// associated line comment, only when used in a list
LineComment *CommentGroup
}
func (l *LiteralType) Pos() token.Pos {

View File

@ -16,6 +16,7 @@ type Parser struct {
// Last read token
tok token.Token
commaPrev token.Token
comments []*ast.CommentGroup
leadComment *ast.CommentGroup // last lead comment
@ -147,7 +148,6 @@ func (p *Parser) objectItem() (*ast.ObjectItem, error) {
o.LineComment = p.lineComment
p.lineComment = nil
}
p.unscan()
return o, nil
}
@ -253,6 +253,17 @@ func (p *Parser) listType() (*ast.ListType, error) {
l.Add(node)
case token.COMMA:
// 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
case token.BOOL:
// 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 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 {
// The comment is on same line as the previous token; it
// 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.
ast.Walk(node, func(nn ast.Node) bool {
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:
if t.LeadComment != nil {
for _, comment := range t.LeadComment.List {
@ -83,6 +91,7 @@ func (p *printer) collectComments(node ast.Node) {
}
sort.Sort(ByPosition(p.standaloneComments))
}
// output prints creates b printable HCL output and returns it.
@ -98,8 +107,6 @@ func (p *printer) output(n interface{}) []byte {
var commented bool
for {
// TODO(arslan): refactor below comment printing, we have the same in objectType
// print upper leve stand alone comments
for _, c := range p.standaloneComments {
for _, comment := range c.List {
if index != len(t.Items) {
@ -115,7 +122,6 @@ func (p *printer) output(n interface{}) []byte {
}
buf.WriteString(comment.Text)
// TODO(arslan): do not print new lines if the comments are one liner
buf.WriteByte(newline)
if index != len(t.Items) {
@ -153,6 +159,9 @@ func (p *printer) output(n interface{}) []byte {
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 {
defer un(trace(p, fmt.Sprintf("ObjectItem: %s", o.Keys[0].Token.Text)))
var buf bytes.Buffer
@ -187,6 +196,8 @@ func (p *printer) objectItem(o *ast.ObjectItem) []byte {
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 {
defer un(trace(p, "ObjectType"))
var buf bytes.Buffer
@ -364,34 +375,55 @@ func (p *printer) alignedItems(items []*ast.ObjectItem) []byte {
return buf.Bytes()
}
func (p *printer) literal(l *ast.LiteralType) []byte {
return []byte(l.Token.Text)
}
// printList prints a HCL list
// list returns the printable HCL form of an list type.
func (p *printer) list(l *ast.ListType) []byte {
var buf bytes.Buffer
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 {
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))
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 {
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()
}

View File

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

View File

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