command/format: Fix multi-line diagnostic output

Previously, if a diagnostic context spanned multiple lines, any lines
which did not overlap with the highlight range would be displayed as
blank. This commit fixes the bug.

The problem was caused by the unconditional use of `PartitionAround` to
split the line into before/highlighted/after ranges. When two ranges
don't overlap, this method returns empty ranges, which results in a
blank line. Instead, we first check if the ranges do overlap, and if not
we print the entire line from the context.
This commit is contained in:
Alisdair McDiarmid 2020-03-26 15:50:39 -04:00
parent 537c1bedcf
commit a23c3e3c81
2 changed files with 66 additions and 9 deletions

View File

@ -100,15 +100,23 @@ func Diagnostic(diag tfdiags.Diagnostic, sources map[string][]byte, color *color
if !lineRange.Overlaps(snippetRange) {
continue
}
beforeRange, highlightedRange, afterRange := lineRange.PartitionAround(highlightRange)
before := beforeRange.SliceBytes(src)
highlighted := highlightedRange.SliceBytes(src)
after := afterRange.SliceBytes(src)
fmt.Fprintf(
&buf, color.Color("%4d: %s[underline]%s[reset]%s\n"),
lineRange.Start.Line,
before, highlighted, after,
)
if lineRange.Overlaps(highlightRange) {
beforeRange, highlightedRange, afterRange := lineRange.PartitionAround(highlightRange)
before := beforeRange.SliceBytes(src)
highlighted := highlightedRange.SliceBytes(src)
after := afterRange.SliceBytes(src)
fmt.Fprintf(
&buf, color.Color("%4d: %s[underline]%s[reset]%s\n"),
lineRange.Start.Line,
before, highlighted, after,
)
} else {
fmt.Fprintf(
&buf, "%4d: %s\n",
lineRange.Start.Line,
lineRange.SliceBytes(src),
)
}
}
}

View File

@ -71,3 +71,52 @@ func TestDiagnosticWarningsCompact(t *testing.T) {
)
}
}
// Test case via https://github.com/hashicorp/terraform/issues/21359
func TestDiagnostic_nonOverlappingHighlightContext(t *testing.T) {
var diags tfdiags.Diagnostics
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Some error",
Detail: "...",
Subject: &hcl.Range{
Filename: "source.tf",
Start: hcl.Pos{Line: 1, Column: 5, Byte: 5},
End: hcl.Pos{Line: 1, Column: 5, Byte: 5},
},
Context: &hcl.Range{
Filename: "source.tf",
Start: hcl.Pos{Line: 1, Column: 5, Byte: 5},
End: hcl.Pos{Line: 4, Column: 2, Byte: 60},
},
})
sources := map[string][]byte{
"source.tf": []byte(`x = somefunc("testing", {
alpha = "foo"
beta = "bar"
})
`),
}
color := &colorstring.Colorize{
Colors: colorstring.DefaultColors,
Reset: true,
Disable: true,
}
expected := `
Error: Some error
on source.tf line 1:
1: x = somefunc("testing", {
2: alpha = "foo"
3: beta = "bar"
4: })
...
`
output := Diagnostic(diags[0], sources, color, 80)
if output != expected {
t.Fatalf("unexpected output: got:\n%s\nwant\n%s\n", output, expected)
}
}