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.
This commit is contained in:
Martin Atkins 2018-01-14 12:07:33 -08:00
parent 368a3f81c0
commit 14cfe59a52
2 changed files with 20 additions and 38 deletions

View File

@ -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'})

View File

@ -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,
},