From 14cfe59a5259d532d402745a8cdb67a87cb2120e Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Sun, 14 Jan 2018 12:07:33 -0800 Subject: [PATCH] hcl: Simplify the text DiagnosticWriter using new Range functions Now that we have helper methods for computing relationships between ranges, we can eliminate all of the tricky line-counting and byte-counting code here and instead use the higher-level operations. The result is a single loop using the RangeScanner. --- hcl/diagnostic_text.go | 52 ++++++++++--------------------------- hcl/diagnostic_text_test.go | 6 +++++ 2 files changed, 20 insertions(+), 38 deletions(-) diff --git a/hcl/diagnostic_text.go b/hcl/diagnostic_text.go index 9776f04..6f5be7b 100644 --- a/hcl/diagnostic_text.go +++ b/hcl/diagnostic_text.go @@ -2,7 +2,6 @@ package hcl import ( "bufio" - "bytes" "errors" "fmt" "io" @@ -70,21 +69,15 @@ func (w *diagnosticTextWriter) WriteDiagnostic(diag *Diagnostic) error { if diag.Subject != nil { file := w.files[diag.Subject.Filename] - if file == nil || file.Bytes == nil { + if file == nil || file.Bytes == nil || diag.Subject.Empty() { fmt.Fprintf(w.wr, " on %s line %d:\n (source code not available)\n\n", diag.Subject.Filename, diag.Subject.Start.Line) } else { - src := file.Bytes - r := bytes.NewReader(src) - sc := bufio.NewScanner(r) - sc.Split(bufio.ScanLines) - - var startLine, endLine int + snipRange := *diag.Subject if diag.Context != nil { - startLine = diag.Context.Start.Line - endLine = diag.Context.End.Line - } else { - startLine = diag.Subject.Start.Line - endLine = diag.Subject.End.Line + // Show enough of the source code to include both the subject + // and context ranges, which overlap in all reasonable + // situations. + snipRange = RangeOver(snipRange, *diag.Context) } var contextLine string @@ -95,35 +88,18 @@ func (w *diagnosticTextWriter) WriteDiagnostic(diag *Diagnostic) error { } } - li := 1 - var ls string - for sc.Scan() { - ls = sc.Text() - - if li == startLine { - break - } - li++ - } - fmt.Fprintf(w.wr, " on %s line %d%s:\n", diag.Subject.Filename, diag.Subject.Start.Line, contextLine) - // TODO: Generate markers for the specific characters that are in the Context and Subject ranges. - // For now, we just print out the lines. + src := file.Bytes + sc := NewRangeScanner(src, diag.Subject.Filename, bufio.ScanLines) - fmt.Fprintf(w.wr, "%4d: %s\n", li, ls) - - if endLine > li { - for sc.Scan() { - ls = sc.Text() - li++ - - fmt.Fprintf(w.wr, "%4d: %s\n", li, ls) - - if li == endLine { - break - } + for sc.Scan() { + lineRange := sc.Range() + if !lineRange.Overlaps(snipRange) { + continue } + + fmt.Fprintf(w.wr, "%4d: %s\n", lineRange.Start.Line, sc.Bytes()) } w.wr.Write([]byte{'\n'}) diff --git a/hcl/diagnostic_text_test.go b/hcl/diagnostic_text_test.go index 40c03df..67c1e64 100644 --- a/hcl/diagnostic_text_test.go +++ b/hcl/diagnostic_text_test.go @@ -45,10 +45,12 @@ All splines must be pre-reticulated. Detail: `"baz" is not a supported top-level attribute. Did you mean "bam"?`, Subject: &Range{ Start: Pos{ + Byte: 16, Column: 1, Line: 3, }, End: Pos{ + Byte: 19, Column: 4, Line: 3, }, @@ -71,10 +73,12 @@ attribute. Did you mean "bam"? Detail: `"pizza" is not a supported attribute. Did you mean "pizzetta"?`, Subject: &Range{ Start: Pos{ + Byte: 42, Column: 3, Line: 5, }, End: Pos{ + Byte: 47, Column: 8, Line: 5, }, @@ -83,10 +87,12 @@ attribute. Did you mean "bam"? // whether we're able to show a multi-line context when needed. Context: &Range{ Start: Pos{ + Byte: 24, Column: 1, Line: 4, }, End: Pos{ + Byte: 60, Column: 2, Line: 6, },