Skip to content

Commit ef8a98b

Browse files
authored
Merge pull request #243 from octo/single-line-lists
printer: Simplify the formatting of single-line lists.
2 parents e9ccac6 + b07f6fa commit ef8a98b

File tree

5 files changed

+108
-93
lines changed

5 files changed

+108
-93
lines changed

hcl/printer/nodes.go

Lines changed: 91 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -517,8 +517,13 @@ func (p *printer) alignedItems(items []*ast.ObjectItem) []byte {
517517

518518
// list returns the printable HCL form of an list type.
519519
func (p *printer) list(l *ast.ListType) []byte {
520+
if p.isSingleLineList(l) {
521+
return p.singleLineList(l)
522+
}
523+
520524
var buf bytes.Buffer
521525
buf.WriteString("[")
526+
buf.WriteByte(newline)
522527

523528
var longestLine int
524529
for _, item := range l.List {
@@ -531,115 +536,112 @@ func (p *printer) list(l *ast.ListType) []byte {
531536
}
532537
}
533538

534-
insertSpaceBeforeItem := false
535-
lastHadLeadComment := false
539+
haveEmptyLine := false
536540
for i, item := range l.List {
537-
// Keep track of whether this item is a heredoc since that has
538-
// unique behavior.
539-
heredoc := false
540-
if lit, ok := item.(*ast.LiteralType); ok && lit.Token.Type == token.HEREDOC {
541-
heredoc = true
542-
}
543-
544-
if item.Pos().Line != l.Lbrack.Line {
545-
// multiline list, add newline before we add each item
546-
buf.WriteByte(newline)
547-
insertSpaceBeforeItem = false
548-
549-
// If we have a lead comment, then we want to write that first
550-
leadComment := false
551-
if lit, ok := item.(*ast.LiteralType); ok && lit.LeadComment != nil {
552-
leadComment = true
553-
554-
// If this isn't the first item and the previous element
555-
// didn't have a lead comment, then we need to add an extra
556-
// newline to properly space things out. If it did have a
557-
// lead comment previously then this would be done
558-
// automatically.
559-
if i > 0 && !lastHadLeadComment {
560-
buf.WriteByte(newline)
561-
}
562-
563-
for _, comment := range lit.LeadComment.List {
564-
buf.Write(p.indent([]byte(comment.Text)))
565-
buf.WriteByte(newline)
566-
}
541+
// If we have a lead comment, then we want to write that first
542+
leadComment := false
543+
if lit, ok := item.(*ast.LiteralType); ok && lit.LeadComment != nil {
544+
leadComment = true
545+
546+
// Ensure an empty line before every element with a
547+
// lead comment (except the first item in a list).
548+
if !haveEmptyLine && i != 0 {
549+
buf.WriteByte(newline)
567550
}
568551

569-
// also indent each line
570-
val := p.output(item)
571-
curLen := len(val)
572-
buf.Write(p.indent(val))
573-
574-
// if this item is a heredoc, then we output the comma on
575-
// the next line. This is the only case this happens.
576-
comma := []byte{','}
577-
if heredoc {
552+
for _, comment := range lit.LeadComment.List {
553+
buf.Write(p.indent([]byte(comment.Text)))
578554
buf.WriteByte(newline)
579-
comma = p.indent(comma)
580555
}
556+
}
581557

582-
buf.Write(comma)
558+
// also indent each line
559+
val := p.output(item)
560+
curLen := len(val)
561+
buf.Write(p.indent(val))
583562

584-
if lit, ok := item.(*ast.LiteralType); ok && lit.LineComment != nil {
585-
// if the next item doesn't have any comments, do not align
586-
buf.WriteByte(blank) // align one space
587-
for i := 0; i < longestLine-curLen; i++ {
588-
buf.WriteByte(blank)
589-
}
563+
// if this item is a heredoc, then we output the comma on
564+
// the next line. This is the only case this happens.
565+
comma := []byte{','}
566+
if lit, ok := item.(*ast.LiteralType); ok && lit.Token.Type == token.HEREDOC {
567+
buf.WriteByte(newline)
568+
comma = p.indent(comma)
569+
}
590570

591-
for _, comment := range lit.LineComment.List {
592-
buf.WriteString(comment.Text)
593-
}
594-
}
571+
buf.Write(comma)
595572

596-
lastItem := i == len(l.List)-1
597-
if lastItem {
598-
buf.WriteByte(newline)
573+
if lit, ok := item.(*ast.LiteralType); ok && lit.LineComment != nil {
574+
// if the next item doesn't have any comments, do not align
575+
buf.WriteByte(blank) // align one space
576+
for i := 0; i < longestLine-curLen; i++ {
577+
buf.WriteByte(blank)
599578
}
600579

601-
if leadComment && !lastItem {
602-
buf.WriteByte(newline)
580+
for _, comment := range lit.LineComment.List {
581+
buf.WriteString(comment.Text)
603582
}
583+
}
604584

605-
lastHadLeadComment = leadComment
606-
} else {
607-
if insertSpaceBeforeItem {
608-
buf.WriteByte(blank)
609-
insertSpaceBeforeItem = false
610-
}
585+
buf.WriteByte(newline)
611586

612-
// Output the item itself
613-
// also indent each line
614-
val := p.output(item)
615-
curLen := len(val)
616-
buf.Write(val)
587+
// Ensure an empty line after every element with a
588+
// lead comment (except the first item in a list).
589+
haveEmptyLine = leadComment && i != len(l.List)-1
590+
if haveEmptyLine {
591+
buf.WriteByte(newline)
592+
}
593+
}
617594

618-
// If this is a heredoc item we always have to output a newline
619-
// so that it parses properly.
620-
if heredoc {
621-
buf.WriteByte(newline)
622-
}
595+
buf.WriteString("]")
596+
return buf.Bytes()
597+
}
623598

624-
// If this isn't the last element, write a comma.
625-
if i != len(l.List)-1 {
626-
buf.WriteString(",")
627-
insertSpaceBeforeItem = true
628-
}
599+
// isSingleLineList returns true if:
600+
// * they were previously formatted entirely on one line
601+
// * they consist entirely of literals
602+
// * there are either no heredoc strings or the list has exactly one element
603+
// * there are no line comments
604+
func (printer) isSingleLineList(l *ast.ListType) bool {
605+
for _, item := range l.List {
606+
if item.Pos().Line != l.Lbrack.Line {
607+
return false
608+
}
629609

630-
if lit, ok := item.(*ast.LiteralType); ok && lit.LineComment != nil {
631-
// if the next item doesn't have any comments, do not align
632-
buf.WriteByte(blank) // align one space
633-
for i := 0; i < longestLine-curLen; i++ {
634-
buf.WriteByte(blank)
635-
}
610+
lit, ok := item.(*ast.LiteralType)
611+
if !ok {
612+
return false
613+
}
636614

637-
for _, comment := range lit.LineComment.List {
638-
buf.WriteString(comment.Text)
639-
}
640-
}
615+
if lit.Token.Type == token.HEREDOC && len(l.List) != 1 {
616+
return false
617+
}
618+
619+
if lit.LineComment != nil {
620+
return false
641621
}
622+
}
642623

624+
return true
625+
}
626+
627+
// singleLineList prints a simple single line list.
628+
// For a definition of "simple", see isSingleLineList above.
629+
func (p *printer) singleLineList(l *ast.ListType) []byte {
630+
buf := &bytes.Buffer{}
631+
632+
buf.WriteString("[")
633+
for i, item := range l.List {
634+
if i != 0 {
635+
buf.WriteString(", ")
636+
}
637+
638+
// Output the item itself
639+
buf.Write(p.output(item))
640+
641+
// The heredoc marker needs to be at the end of line.
642+
if lit, ok := item.(*ast.LiteralType); ok && lit.Token.Type == token.HEREDOC {
643+
buf.WriteByte(newline)
644+
}
643645
}
644646

645647
buf.WriteString("]")

hcl/printer/printer_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ func TestFormatValidOutput(t *testing.T) {
154154
"#\x00",
155155
"#\ue123t",
156156
"x=//\n0y=<<_\n_\n",
157+
"y=[1,//\n]",
157158
"Y=<<4\n4/\n\n\n/4/@=4/\n\n\n/4000000004\r\r\n00004\n",
158159
"x=<<_\n_\r\r\n_\n",
159160
"X=<<-\n\r\r\n",

hcl/printer/testdata/list.golden

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ foo = ["fatih", "arslan"]
22

33
foo = ["bar", "qaz"]
44

5-
foo = ["zeynep",
5+
foo = [
6+
"zeynep",
67
"arslan",
78
]
89

9-
foo = ["fatih", "zeynep",
10+
foo = [
11+
"fatih",
12+
"zeynep",
1013
"arslan",
1114
]
1215

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
foo = [1, # Hello
1+
foo = [
2+
1, # Hello
23
2,
34
]
45

5-
foo = [1, # Hello
6+
foo = [
7+
1, # Hello
68
2, # World
79
]
10+
11+
foo = [
12+
1, # Hello
13+
]

hcl/printer/testdata/list_comment.input

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ foo = [1, # Hello
44
foo = [1, # Hello
55
2, # World
66
]
7+
8+
foo = [1, # Hello
9+
]

0 commit comments

Comments
 (0)