Skip to content

Commit

Permalink
hclwrite: Suspend indentation adjustment inside heredocs
Browse files Browse the repository at this point in the history
Leading whitespace is significant in heredocs, so we'll avoid making any
indentation adjustments for lines between OHeredoc and CHeredoc.

This fixes hashicorp#31.
  • Loading branch information
apparentlymart committed Dec 14, 2018
1 parent 002296d commit 4c4fdbd
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 3 deletions.
47 changes: 44 additions & 3 deletions hclwrite/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,22 @@ func formatIndent(lines []formatLine) {
// which should be more than enough for reasonable HCL uses.
indents := make([]int, 0, 10)

inHeredoc := false
for i := range lines {
// TODO: need to track when we're inside a multi-line template and
// suspend indentation processing.

line := &lines[i]
if len(line.lead) == 0 {
continue
}

if inHeredoc {
for _, token := range line.lead {
if token.Type == hclsyntax.TokenCHeredoc {
inHeredoc = false
}
}
continue // don't touch indentation inside heredocs
}

if line.lead[0].Type == hclsyntax.TokenNewline {
// Never place spaces before a newline
line.lead[0].SpacesBefore = 0
Expand All @@ -74,6 +82,9 @@ func formatIndent(lines []formatLine) {
}
for _, token := range line.assign {
netBrackets += tokenBracketChange(token)
if token.Type == hclsyntax.TokenOHeredoc {
inHeredoc = true
}
}

switch {
Expand Down Expand Up @@ -309,6 +320,15 @@ func spaceAfterToken(subject, before, after *Token) bool {
// Never spaces before colons
return false

// In the unlikely event that an interpolation expression is just
// a single object constructor, we'll put a space between the ${ and
// the following { to make this more obvious, and then the same
// thing for the two braces at the end.
case (subject.Type == hclsyntax.TokenTemplateInterp || subject.Type == hclsyntax.TokenTemplateControl) && after.Type == hclsyntax.TokenOBrace:
return true
case subject.Type == hclsyntax.TokenCBrace && after.Type == hclsyntax.TokenTemplateSeqEnd:
return true

case tokenBracketChange(subject) > 0:
// No spaces after open brackets
return false
Expand Down Expand Up @@ -371,6 +391,7 @@ func linesForFormat(tokens Tokens) []formatLine {

// Now we'll pick off any trailing comments and attribute assignments
// to shuffle off into the "comment" and "assign" cells.
inHeredoc := false
for i := range lines {
line := &lines[i]
if len(line.lead) == 0 {
Expand All @@ -380,6 +401,26 @@ func linesForFormat(tokens Tokens) []formatLine {
continue
}

if inHeredoc {
for _, tok := range line.lead {
if tok.Type == hclsyntax.TokenCHeredoc {
inHeredoc = false
break
}
}
// Inside a heredoc everything is "lead", even if there's a
// template interpolation embedded in there that might otherwise
// confuse our logic below.
continue
}

for _, tok := range line.lead {
if tok.Type == hclsyntax.TokenOHeredoc {
inHeredoc = true
break
}
}

if len(line.lead) > 1 && line.lead[len(line.lead)-1].Type == hclsyntax.TokenComment {
line.comment = line.lead[len(line.lead)-1:]
line.lead = line.lead[:len(line.lead)-1]
Expand Down
80 changes: 80 additions & 0 deletions hclwrite/format_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,86 @@ foo {
# ...
]
}
`,
},
{
`
foo {
bar = <<EOT
Foo bar baz
EOT
}
`,
`
foo {
bar = <<EOT
Foo bar baz
EOT
}
`,
},
{
`
foo {
bar = <<-EOT
Foo bar baz
EOT
}
`,
`
foo {
bar = <<-EOT
Foo bar baz
EOT
}
`,
},
{
`
foo {
bar = <<-EOT
Foo bar baz
EOT
}
`,
`
foo {
bar = <<-EOT
Foo bar baz
EOT
}
`,
},
{
`
foo {
bar = <<-EOT
blahblahblah = x
EOT
}
`,
`
foo {
bar = <<-EOT
blahblahblah = x
EOT
}
`,
},
{
`
foo {
bar = <<-EOT
${{ blahblahblah = x }}
EOT
}
`,
`
foo {
bar = <<-EOT
${ { blahblahblah = x } }
EOT
}
`,
},
}
Expand Down

0 comments on commit 4c4fdbd

Please sign in to comment.