From a23c3e3c81d818adbe534d74682a0cfa70269c07 Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Thu, 26 Mar 2020 15:50:39 -0400 Subject: [PATCH] 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. --- command/format/diagnostic.go | 26 ++++++++++------ command/format/diagnostic_test.go | 49 +++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 9 deletions(-) diff --git a/command/format/diagnostic.go b/command/format/diagnostic.go index 6b8232650e..dc1dfe5bf7 100644 --- a/command/format/diagnostic.go +++ b/command/format/diagnostic.go @@ -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), + ) + } } } diff --git a/command/format/diagnostic_test.go b/command/format/diagnostic_test.go index 18812089ca..8848e4b295 100644 --- a/command/format/diagnostic_test.go +++ b/command/format/diagnostic_test.go @@ -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) + } +}