mirror of https://github.com/zkat/miette.git
fix(handlers): Fix label position (#107)
Fixes #106 While fixing the bug I've also extended the handler to print not just where label starts but also where label ends. Also implements #97, but for narratabble handler only. This adds dependency on `unicode-width`, but it was already in the dependency chain (`textwidth` depends on it). Although, previously it was only for `"fancy"` feature, now it always required since narratable handler is supported without `"fancy"`.
This commit is contained in:
parent
9dcce5f1bd
commit
f158f4e370
|
|
@ -15,6 +15,7 @@ exclude = ["images/", "tests/", "miette-derive/"]
|
||||||
thiserror = "1.0.26"
|
thiserror = "1.0.26"
|
||||||
miette-derive = { path = "miette-derive", version = "=3.3.1-alpha.0"}
|
miette-derive = { path = "miette-derive", version = "=3.3.1-alpha.0"}
|
||||||
once_cell = "1.8.0"
|
once_cell = "1.8.0"
|
||||||
|
unicode-width = "0.1.9"
|
||||||
|
|
||||||
owo-colors = { version = "3.0.0", optional = true }
|
owo-colors = { version = "3.0.0", optional = true }
|
||||||
atty = { version = "0.2.14", optional = true }
|
atty = { version = "0.2.14", optional = true }
|
||||||
|
|
@ -45,7 +46,7 @@ fancy = [
|
||||||
"supports-hyperlinks",
|
"supports-hyperlinks",
|
||||||
"supports-color",
|
"supports-color",
|
||||||
"supports-unicode",
|
"supports-unicode",
|
||||||
"backtrace"
|
"backtrace",
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
|
||||||
|
|
||||||
use crate::chain::Chain;
|
use crate::chain::Chain;
|
||||||
use crate::protocol::{Diagnostic, Severity};
|
use crate::protocol::{Diagnostic, Severity};
|
||||||
use crate::{LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents};
|
use crate::{LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents};
|
||||||
|
|
@ -208,23 +210,44 @@ impl NarratableReportHandler {
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
for line in &lines {
|
for line in &lines {
|
||||||
writeln!(f, "snippet line {}: {}", line.line_number, line.text)?;
|
writeln!(f, "snippet line {}: {}", line.line_number, line.text)?;
|
||||||
let relevant = labels.iter().filter(|l| line.span_starts(l.inner()));
|
let relevant = labels
|
||||||
for label in relevant {
|
.iter()
|
||||||
let contents = source
|
.filter_map(|l| line.span_attach(l.inner()).map(|a| (a, l)));
|
||||||
.read_span(label.inner(), self.context_lines, self.context_lines)
|
for (attach, label) in relevant {
|
||||||
.map_err(|_| fmt::Error)?;
|
match attach {
|
||||||
if contents.line() + 1 == line.line_number {
|
SpanAttach::Contained { col_start, col_end } if col_start == col_end => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
" label starting at line {}, column {}",
|
" label at line {}, column {}",
|
||||||
contents.line() + 1,
|
line.line_number, col_start,
|
||||||
contents.column() + 1
|
)?;
|
||||||
)?;
|
}
|
||||||
if let Some(label) = label.label() {
|
SpanAttach::Contained { col_start, col_end } => {
|
||||||
write!(f, ": {}", label)?;
|
write!(
|
||||||
|
f,
|
||||||
|
" label at line {}, columns {} to {}",
|
||||||
|
line.line_number, col_start, col_end,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
SpanAttach::Starts { col_start } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
" label starting at line {}, column {}",
|
||||||
|
line.line_number, col_start,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
SpanAttach::Ends { col_end } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
" label ending at line {}, column {}",
|
||||||
|
line.line_number, col_end,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
writeln!(f)?;
|
|
||||||
}
|
}
|
||||||
|
if let Some(label) = label.label() {
|
||||||
|
write!(f, ": {}", label)?;
|
||||||
|
}
|
||||||
|
writeln!(f)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -281,6 +304,7 @@ impl NarratableReportHandler {
|
||||||
line_number: line,
|
line_number: line,
|
||||||
offset: line_offset,
|
offset: line_offset,
|
||||||
text: line_str.clone(),
|
text: line_str.clone(),
|
||||||
|
at_end_of_file,
|
||||||
});
|
});
|
||||||
line_str.clear();
|
line_str.clear();
|
||||||
line_offset = offset;
|
line_offset = offset;
|
||||||
|
|
@ -308,12 +332,62 @@ struct Line {
|
||||||
line_number: usize,
|
line_number: usize,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
text: String,
|
text: String,
|
||||||
|
at_end_of_file: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SpanAttach {
|
||||||
|
Contained { col_start: usize, col_end: usize },
|
||||||
|
Starts { col_start: usize },
|
||||||
|
Ends { col_end: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns column at offset, and nearest boundary if offset is in the middle of the character
|
||||||
|
fn safe_get_column(text: &str, offset: usize, start: bool) -> usize {
|
||||||
|
let mut column = text.get(0..offset).map(|s| s.width()).unwrap_or_else(|| {
|
||||||
|
let mut column = 0;
|
||||||
|
for (idx, c) in text.char_indices() {
|
||||||
|
if offset <= idx {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
column += c.width().unwrap_or(0);
|
||||||
|
}
|
||||||
|
column
|
||||||
|
});
|
||||||
|
if start {
|
||||||
|
// Offset are zero-based, so plus one
|
||||||
|
column += 1;
|
||||||
|
} // On the other hand for end span, offset refers for the next column
|
||||||
|
// So we should do -1. column+1-1 == column
|
||||||
|
column
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Line {
|
impl Line {
|
||||||
// Does this line contain the *beginning* of this multiline span?
|
fn span_attach(&self, span: &SourceSpan) -> Option<SpanAttach> {
|
||||||
// This assumes self.span_applies() is true already.
|
let span_end = span.offset() + span.len();
|
||||||
fn span_starts(&self, span: &SourceSpan) -> bool {
|
let line_end = self.offset + self.text.len();
|
||||||
span.offset() >= self.offset
|
|
||||||
|
let start_after = span.offset() >= self.offset;
|
||||||
|
let end_before = self.at_end_of_file || span_end <= line_end;
|
||||||
|
|
||||||
|
if start_after && end_before {
|
||||||
|
let col_start = safe_get_column(&self.text, span.offset() - self.offset, true);
|
||||||
|
let col_end = if span.is_empty() {
|
||||||
|
col_start
|
||||||
|
} else {
|
||||||
|
// span_end refers to the next character after token
|
||||||
|
// while col_end refers to the exact character, so -1
|
||||||
|
safe_get_column(&self.text, span_end - self.offset, false)
|
||||||
|
};
|
||||||
|
return Some(SpanAttach::Contained { col_start, col_end });
|
||||||
|
}
|
||||||
|
if start_after && span.offset() <= line_end {
|
||||||
|
let col_start = safe_get_column(&self.text, span.offset() - self.offset, true);
|
||||||
|
return Some(SpanAttach::Starts { col_start });
|
||||||
|
}
|
||||||
|
if end_before && span_end >= self.offset {
|
||||||
|
let col_end = safe_get_column(&self.text, span_end - self.offset, false);
|
||||||
|
return Some(SpanAttach::Ends { col_end });
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,8 @@ fn single_line_with_wide_char() -> Result<(), MietteError> {
|
||||||
Begin snippet for bad_file.rs starting at line 1, column 1
|
Begin snippet for bad_file.rs starting at line 1, column 1
|
||||||
|
|
||||||
snippet line 1: source
|
snippet line 1: source
|
||||||
label starting at line 1, column 1: this bit here
|
|
||||||
snippet line 2: 👼🏼text
|
snippet line 2: 👼🏼text
|
||||||
|
label at line 2, columns 3 to 6: this bit here
|
||||||
snippet line 3: here
|
snippet line 3: here
|
||||||
diagnostic help: try doing it better next time?
|
diagnostic help: try doing it better next time?
|
||||||
diagnostic code: oops::my::bad
|
diagnostic code: oops::my::bad
|
||||||
|
|
@ -82,8 +82,8 @@ fn single_line_highlight() -> Result<(), MietteError> {
|
||||||
Begin snippet for bad_file.rs starting at line 1, column 1
|
Begin snippet for bad_file.rs starting at line 1, column 1
|
||||||
|
|
||||||
snippet line 1: source
|
snippet line 1: source
|
||||||
label starting at line 1, column 1: this bit here
|
|
||||||
snippet line 2: text
|
snippet line 2: text
|
||||||
|
label at line 2, columns 3 to 6: this bit here
|
||||||
snippet line 3: here
|
snippet line 3: here
|
||||||
diagnostic help: try doing it better next time?
|
diagnostic help: try doing it better next time?
|
||||||
diagnostic code: oops::my::bad
|
diagnostic code: oops::my::bad
|
||||||
|
|
@ -118,7 +118,7 @@ fn single_line_highlight_offset_zero() -> Result<(), MietteError> {
|
||||||
Begin snippet for bad_file.rs starting at line 1, column 1
|
Begin snippet for bad_file.rs starting at line 1, column 1
|
||||||
|
|
||||||
snippet line 1: source
|
snippet line 1: source
|
||||||
label starting at line 1, column 1: this bit here
|
label at line 1, column 1: this bit here
|
||||||
snippet line 2: text
|
snippet line 2: text
|
||||||
diagnostic help: try doing it better next time?
|
diagnostic help: try doing it better next time?
|
||||||
diagnostic code: oops::my::bad
|
diagnostic code: oops::my::bad
|
||||||
|
|
@ -153,8 +153,8 @@ fn single_line_highlight_with_empty_span() -> Result<(), MietteError> {
|
||||||
Begin snippet for bad_file.rs starting at line 1, column 1
|
Begin snippet for bad_file.rs starting at line 1, column 1
|
||||||
|
|
||||||
snippet line 1: source
|
snippet line 1: source
|
||||||
label starting at line 1, column 1: this bit here
|
|
||||||
snippet line 2: text
|
snippet line 2: text
|
||||||
|
label at line 2, column 3: this bit here
|
||||||
snippet line 3: here
|
snippet line 3: here
|
||||||
diagnostic help: try doing it better next time?
|
diagnostic help: try doing it better next time?
|
||||||
diagnostic code: oops::my::bad
|
diagnostic code: oops::my::bad
|
||||||
|
|
@ -189,8 +189,8 @@ fn single_line_highlight_no_label() -> Result<(), MietteError> {
|
||||||
Begin snippet for bad_file.rs starting at line 1, column 1
|
Begin snippet for bad_file.rs starting at line 1, column 1
|
||||||
|
|
||||||
snippet line 1: source
|
snippet line 1: source
|
||||||
label starting at line 1, column 1
|
|
||||||
snippet line 2: text
|
snippet line 2: text
|
||||||
|
label at line 2, columns 3 to 6
|
||||||
snippet line 3: here
|
snippet line 3: here
|
||||||
diagnostic help: try doing it better next time?
|
diagnostic help: try doing it better next time?
|
||||||
diagnostic code: oops::my::bad
|
diagnostic code: oops::my::bad
|
||||||
|
|
@ -225,8 +225,8 @@ fn single_line_highlight_at_line_start() -> Result<(), MietteError> {
|
||||||
Begin snippet for bad_file.rs starting at line 1, column 1
|
Begin snippet for bad_file.rs starting at line 1, column 1
|
||||||
|
|
||||||
snippet line 1: source
|
snippet line 1: source
|
||||||
label starting at line 1, column 1: this bit here
|
|
||||||
snippet line 2: text
|
snippet line 2: text
|
||||||
|
label at line 2, columns 1 to 4: this bit here
|
||||||
snippet line 3: here
|
snippet line 3: here
|
||||||
diagnostic help: try doing it better next time?
|
diagnostic help: try doing it better next time?
|
||||||
diagnostic code: oops::my::bad
|
diagnostic code: oops::my::bad
|
||||||
|
|
@ -267,10 +267,10 @@ fn multiple_same_line_highlights() -> Result<(), MietteError> {
|
||||||
Begin snippet for bad_file.rs starting at line 1, column 1
|
Begin snippet for bad_file.rs starting at line 1, column 1
|
||||||
|
|
||||||
snippet line 1: source
|
snippet line 1: source
|
||||||
label starting at line 1, column 1: x
|
|
||||||
label starting at line 1, column 1: y
|
|
||||||
label starting at line 1, column 1: z
|
|
||||||
snippet line 2: text text text text text
|
snippet line 2: text text text text text
|
||||||
|
label at line 2, columns 3 to 6: x
|
||||||
|
label at line 2, columns 8 to 11: y
|
||||||
|
label at line 2, columns 18 to 21: z
|
||||||
snippet line 3: here
|
snippet line 3: here
|
||||||
diagnostic help: try doing it better next time?
|
diagnostic help: try doing it better next time?
|
||||||
diagnostic code: oops::my::bad
|
diagnostic code: oops::my::bad
|
||||||
|
|
@ -305,9 +305,10 @@ fn multiline_highlight_adjacent() -> Result<(), MietteError> {
|
||||||
Begin snippet for bad_file.rs starting at line 1, column 1
|
Begin snippet for bad_file.rs starting at line 1, column 1
|
||||||
|
|
||||||
snippet line 1: source
|
snippet line 1: source
|
||||||
label starting at line 1, column 1: these two lines
|
|
||||||
snippet line 2: text
|
snippet line 2: text
|
||||||
|
label starting at line 2, column 3: these two lines
|
||||||
snippet line 3: here
|
snippet line 3: here
|
||||||
|
label ending at line 3, column 6: these two lines
|
||||||
diagnostic help: try doing it better next time?
|
diagnostic help: try doing it better next time?
|
||||||
diagnostic code: oops::my::bad
|
diagnostic code: oops::my::bad
|
||||||
"#
|
"#
|
||||||
|
|
@ -352,11 +353,13 @@ Begin snippet for bad_file.rs starting at line 1, column 1
|
||||||
|
|
||||||
snippet line 1: line1
|
snippet line 1: line1
|
||||||
label starting at line 1, column 1: block 1
|
label starting at line 1, column 1: block 1
|
||||||
label starting at line 1, column 1: block 2
|
|
||||||
snippet line 2: line2
|
snippet line 2: line2
|
||||||
|
label starting at line 2, column 5: block 2
|
||||||
snippet line 3: line3
|
snippet line 3: line3
|
||||||
snippet line 4: line4
|
snippet line 4: line4
|
||||||
|
label ending at line 4, column 1: block 2
|
||||||
snippet line 5: line5
|
snippet line 5: line5
|
||||||
|
label ending at line 5, column 5: block 1
|
||||||
diagnostic help: try doing it better next time?
|
diagnostic help: try doing it better next time?
|
||||||
diagnostic code: oops::my::bad
|
diagnostic code: oops::my::bad
|
||||||
"#
|
"#
|
||||||
|
|
@ -418,11 +421,13 @@ Begin snippet for bad_file.rs starting at line 1, column 1
|
||||||
|
|
||||||
snippet line 1: line1
|
snippet line 1: line1
|
||||||
label starting at line 1, column 1: block 1
|
label starting at line 1, column 1: block 1
|
||||||
label starting at line 1, column 1
|
|
||||||
snippet line 2: line2
|
snippet line 2: line2
|
||||||
|
label starting at line 2, column 5
|
||||||
snippet line 3: line3
|
snippet line 3: line3
|
||||||
snippet line 4: line4
|
snippet line 4: line4
|
||||||
|
label ending at line 4, column 1
|
||||||
snippet line 5: line5
|
snippet line 5: line5
|
||||||
|
label ending at line 5, column 5: block 1
|
||||||
diagnostic help: try doing it better next time?
|
diagnostic help: try doing it better next time?
|
||||||
diagnostic code: oops::my::bad
|
diagnostic code: oops::my::bad
|
||||||
"
|
"
|
||||||
|
|
@ -461,9 +466,11 @@ Begin snippet for bad_file.rs starting at line 1, column 1
|
||||||
snippet line 1: source
|
snippet line 1: source
|
||||||
label starting at line 1, column 1: this bit here
|
label starting at line 1, column 1: this bit here
|
||||||
snippet line 2: text
|
snippet line 2: text
|
||||||
label starting at line 2, column 1: also this bit
|
label ending at line 2, column 3: this bit here
|
||||||
snippet line 3: here
|
snippet line 3: here
|
||||||
|
label starting at line 3, column 7: also this bit
|
||||||
snippet line 4: more here
|
snippet line 4: more here
|
||||||
|
label ending at line 4, column 3: also this bit
|
||||||
diagnostic help: try doing it better next time?
|
diagnostic help: try doing it better next time?
|
||||||
diagnostic code: oops::my::bad
|
diagnostic code: oops::my::bad
|
||||||
"
|
"
|
||||||
|
|
@ -575,8 +582,8 @@ fn related() -> Result<(), MietteError> {
|
||||||
Begin snippet for bad_file.rs starting at line 1, column 1
|
Begin snippet for bad_file.rs starting at line 1, column 1
|
||||||
|
|
||||||
snippet line 1: source
|
snippet line 1: source
|
||||||
label starting at line 1, column 1: this bit here
|
|
||||||
snippet line 2: text
|
snippet line 2: text
|
||||||
|
label at line 2, columns 3 to 6: this bit here
|
||||||
snippet line 3: here
|
snippet line 3: here
|
||||||
diagnostic help: try doing it better next time?
|
diagnostic help: try doing it better next time?
|
||||||
diagnostic code: oops::my::bad
|
diagnostic code: oops::my::bad
|
||||||
|
|
@ -587,7 +594,7 @@ Error: oops!
|
||||||
Begin snippet for bad_file.rs starting at line 1, column 1
|
Begin snippet for bad_file.rs starting at line 1, column 1
|
||||||
|
|
||||||
snippet line 1: source
|
snippet line 1: source
|
||||||
label starting at line 1, column 1: this bit here
|
label at line 1, columns 1 to 6: this bit here
|
||||||
snippet line 2: text
|
snippet line 2: text
|
||||||
diagnostic help: try doing it better next time?
|
diagnostic help: try doing it better next time?
|
||||||
diagnostic code: oops::my::bad
|
diagnostic code: oops::my::bad
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue