diff --git a/hcl/printer/nodes.go b/hcl/printer/nodes.go index eea4f5c..a733159 100644 --- a/hcl/printer/nodes.go +++ b/hcl/printer/nodes.go @@ -171,7 +171,15 @@ func (p *printer) output(n interface{}) []byte { buf.Write(p.output(t.Items[index])) if index != len(t.Items)-1 { - buf.Write([]byte{newline, newline}) + // Always write a newline to separate us from the next item + buf.WriteByte(newline) + + // If the next item is an object that is exactly one line, + // then we don't output another newline. + next := t.Items[index+1] + if next.Pos().Line != t.Items[index].Pos().Line+1 || !p.isSingleLineObject(next) { + buf.WriteByte(newline) + } } index++ } @@ -683,6 +691,36 @@ func (p *printer) heredocIndent(buf []byte) []byte { return res } +// isSingleLineObject tells whether the given object item is a single +// line object such as "obj {}". +// +// A single line object: +// +// * has no lead comments (hence multi-line) +// * has no assignment +// * has no values in the stanza (within {}) +// +func (p *printer) isSingleLineObject(val *ast.ObjectItem) bool { + // If there is a lead comment, can't be one line + if val.LeadComment != nil { + return false + } + + // If there is assignment, we always break by line + if val.Assign.IsValid() { + return false + } + + // If it isn't an object type, then its not a single line object + ot, ok := val.Val.(*ast.ObjectType) + if !ok { + return false + } + + // If the object has no items, it is single line! + return len(ot.List.Items) == 0 +} + func lines(txt string) int { endline := 1 for i := 0; i < len(txt); i++ { diff --git a/hcl/printer/printer_test.go b/hcl/printer/printer_test.go index 6189acb..23662db 100644 --- a/hcl/printer/printer_test.go +++ b/hcl/printer/printer_test.go @@ -44,6 +44,7 @@ var data = []entry{ {"empty_block.input", "empty_block.golden"}, {"list_of_objects.input", "list_of_objects.golden"}, {"multiline_string.input", "multiline_string.golden"}, + {"object_singleline.input", "object_singleline.golden"}, {"object_with_heredoc.input", "object_with_heredoc.golden"}, } diff --git a/hcl/printer/testdata/empty_block.golden b/hcl/printer/testdata/empty_block.golden index b7d9280..4ff1cb3 100644 --- a/hcl/printer/testdata/empty_block.golden +++ b/hcl/printer/testdata/empty_block.golden @@ -1,5 +1,4 @@ variable "foo" {} - variable "foo" {} variable "foo" { diff --git a/hcl/printer/testdata/object_singleline.golden b/hcl/printer/testdata/object_singleline.golden new file mode 100644 index 0000000..defd790 --- /dev/null +++ b/hcl/printer/testdata/object_singleline.golden @@ -0,0 +1,20 @@ +variable "foo" {} +variable "bar" {} +variable "baz" {} + +variable "qux" {} + +variable "foo" { + foo = "bar" +} + +variable "foo" {} + +# lead comment +variable "bar" {} + +# Purposeful newline check below: + +variable "foo" {} + +variable "purposeful-newline" {} diff --git a/hcl/printer/testdata/object_singleline.input b/hcl/printer/testdata/object_singleline.input new file mode 100644 index 0000000..a6e8dbb --- /dev/null +++ b/hcl/printer/testdata/object_singleline.input @@ -0,0 +1,16 @@ +variable "foo" {} +variable "bar" {} +variable "baz" {} + +variable "qux" {} +variable "foo" { foo = "bar" } + +variable "foo" {} +# lead comment +variable "bar" {} + +# Purposeful newline check below: + +variable "foo" {} + +variable "purposeful-newline" {}