Skip to content

Commit

Permalink
Format in vertical when removing blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
minamijoyo committed Mar 11, 2020
1 parent f723869 commit fcdd883
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 2 deletions.
2 changes: 1 addition & 1 deletion editor/block_remove.go
Expand Up @@ -16,7 +16,7 @@ func RemoveBlock(r io.Reader, w io.Writer, filename string, address string) erro
filters: []Filter{
&blockRemove{address: address},
},
sink: &formater{},
sink: &verticalFormater{},
}

return e.Apply(r, w)
Expand Down
1 change: 0 additions & 1 deletion editor/block_remove_test.go
Expand Up @@ -28,7 +28,6 @@ b2 l1 {
ok: true,
want: `
a0 = v0
b2 l1 {
}
`,
Expand Down
76 changes: 76 additions & 0 deletions editor/sink.go
@@ -1,6 +1,7 @@
package editor

import (
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/hcl/v2/hclwrite"
)

Expand All @@ -20,3 +21,78 @@ func (f *formater) Sink(inFile *hclwrite.File) ([]byte, error) {
out := hclwrite.Format(raw)
return out, nil
}

// verticalFormater is a Sink implementation to format HCL.
// At time of writing, the default hcl formatter does not support vertical
// formatting. However, it's useful in some cases such as removing a block
// because leading and trailing newline tokens don't belong to a block, so
// deleting a block leaves extra newline tokens.
// This is not included in the original hcl implementation, so we should not be
// the default behavior of the formater not to break existing fomatted hcl configurations.
// Opt-in only where you neeed this feature.
// Note that verticalFormatter formats not only in vertical but also horizontal
// because we cannot use multiple Sink implementations at once.
type verticalFormater struct {
}

// Sink reads HCL and writes formatted contents in vertical and horizontal.
func (f *verticalFormater) Sink(inFile *hclwrite.File) ([]byte, error) {
tokens := inFile.BuildTokens(nil)

vertical := VerticalFormat(tokens)

// default horizontal format
out := hclwrite.Format(vertical.Bytes())
return out, nil
}

// VerticalFormat formats token in vertical.
func VerticalFormat(tokens hclwrite.Tokens) hclwrite.Tokens {
trimmed := trimNewLine(tokens)
removed := removeDuplicatedNewLine(trimmed)
return removed
}

// trimNewLine trimsleading and trailing newlines from tokens
func trimNewLine(tokens hclwrite.Tokens) hclwrite.Tokens {
begin := 0
for ; begin < len(tokens); begin++ {
if tokens[begin].Type != hclsyntax.TokenNewline {
break
}
}

end := len(tokens)
var eof *hclwrite.Token
for ; end > begin; end-- {
if tokens[end-1].Type == hclsyntax.TokenEOF {
// skip EOF
eof = tokens[end-1]
continue
}
if tokens[end-1].Type != hclsyntax.TokenNewline {
break
}
}

ret := append(tokens[begin:end], eof)
return ret
}

// removeDuplicatedNewLine removes duplicated newlines
func removeDuplicatedNewLine(tokens hclwrite.Tokens) hclwrite.Tokens {
var removed hclwrite.Tokens
before := false

for _, token := range tokens {
if token.Type != hclsyntax.TokenNewline {
removed = append(removed, token)
before = false
} else if !before {
removed = append(removed, token)
before = true
}
}

return removed
}

0 comments on commit fcdd883

Please sign in to comment.