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"
|
||||
miette-derive = { path = "miette-derive", version = "=3.3.1-alpha.0"}
|
||||
once_cell = "1.8.0"
|
||||
unicode-width = "0.1.9"
|
||||
|
||||
owo-colors = { version = "3.0.0", optional = true }
|
||||
atty = { version = "0.2.14", optional = true }
|
||||
|
|
@ -45,7 +46,7 @@ fancy = [
|
|||
"supports-hyperlinks",
|
||||
"supports-color",
|
||||
"supports-unicode",
|
||||
"backtrace"
|
||||
"backtrace",
|
||||
]
|
||||
|
||||
[workspace]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use std::fmt;
|
||||
|
||||
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
|
||||
|
||||
use crate::chain::Chain;
|
||||
use crate::protocol::{Diagnostic, Severity};
|
||||
use crate::{LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents};
|
||||
|
|
@ -208,23 +210,44 @@ impl NarratableReportHandler {
|
|||
writeln!(f)?;
|
||||
for line in &lines {
|
||||
writeln!(f, "snippet line {}: {}", line.line_number, line.text)?;
|
||||
let relevant = labels.iter().filter(|l| line.span_starts(l.inner()));
|
||||
for label in relevant {
|
||||
let contents = source
|
||||
.read_span(label.inner(), self.context_lines, self.context_lines)
|
||||
.map_err(|_| fmt::Error)?;
|
||||
if contents.line() + 1 == line.line_number {
|
||||
write!(
|
||||
f,
|
||||
" label starting at line {}, column {}",
|
||||
contents.line() + 1,
|
||||
contents.column() + 1
|
||||
)?;
|
||||
if let Some(label) = label.label() {
|
||||
write!(f, ": {}", label)?;
|
||||
let relevant = labels
|
||||
.iter()
|
||||
.filter_map(|l| line.span_attach(l.inner()).map(|a| (a, l)));
|
||||
for (attach, label) in relevant {
|
||||
match attach {
|
||||
SpanAttach::Contained { col_start, col_end } if col_start == col_end => {
|
||||
write!(
|
||||
f,
|
||||
" label at line {}, column {}",
|
||||
line.line_number, col_start,
|
||||
)?;
|
||||
}
|
||||
SpanAttach::Contained { col_start, col_end } => {
|
||||
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(())
|
||||
|
|
@ -281,6 +304,7 @@ impl NarratableReportHandler {
|
|||
line_number: line,
|
||||
offset: line_offset,
|
||||
text: line_str.clone(),
|
||||
at_end_of_file,
|
||||
});
|
||||
line_str.clear();
|
||||
line_offset = offset;
|
||||
|
|
@ -308,12 +332,62 @@ struct Line {
|
|||
line_number: usize,
|
||||
offset: usize,
|
||||
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 {
|
||||
// Does this line contain the *beginning* of this multiline span?
|
||||
// This assumes self.span_applies() is true already.
|
||||
fn span_starts(&self, span: &SourceSpan) -> bool {
|
||||
span.offset() >= self.offset
|
||||
fn span_attach(&self, span: &SourceSpan) -> Option<SpanAttach> {
|
||||
let span_end = span.offset() + span.len();
|
||||
let line_end = self.offset + self.text.len();
|
||||
|
||||
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
|
||||
|
||||
snippet line 1: source
|
||||
label starting at line 1, column 1: this bit here
|
||||
snippet line 2: 👼🏼text
|
||||
label at line 2, columns 3 to 6: this bit here
|
||||
snippet line 3: here
|
||||
diagnostic help: try doing it better next time?
|
||||
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
|
||||
|
||||
snippet line 1: source
|
||||
label starting at line 1, column 1: this bit here
|
||||
snippet line 2: text
|
||||
label at line 2, columns 3 to 6: this bit here
|
||||
snippet line 3: here
|
||||
diagnostic help: try doing it better next time?
|
||||
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
|
||||
|
||||
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
|
||||
diagnostic help: try doing it better next time?
|
||||
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
|
||||
|
||||
snippet line 1: source
|
||||
label starting at line 1, column 1: this bit here
|
||||
snippet line 2: text
|
||||
label at line 2, column 3: this bit here
|
||||
snippet line 3: here
|
||||
diagnostic help: try doing it better next time?
|
||||
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
|
||||
|
||||
snippet line 1: source
|
||||
label starting at line 1, column 1
|
||||
snippet line 2: text
|
||||
label at line 2, columns 3 to 6
|
||||
snippet line 3: here
|
||||
diagnostic help: try doing it better next time?
|
||||
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
|
||||
|
||||
snippet line 1: source
|
||||
label starting at line 1, column 1: this bit here
|
||||
snippet line 2: text
|
||||
label at line 2, columns 1 to 4: this bit here
|
||||
snippet line 3: here
|
||||
diagnostic help: try doing it better next time?
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
diagnostic help: try doing it better next time?
|
||||
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
|
||||
|
||||
snippet line 1: source
|
||||
label starting at line 1, column 1: these two lines
|
||||
snippet line 2: text
|
||||
label starting at line 2, column 3: these two lines
|
||||
snippet line 3: here
|
||||
label ending at line 3, column 6: these two lines
|
||||
diagnostic help: try doing it better next time?
|
||||
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
|
||||
label starting at line 1, column 1: block 1
|
||||
label starting at line 1, column 1: block 2
|
||||
snippet line 2: line2
|
||||
label starting at line 2, column 5: block 2
|
||||
snippet line 3: line3
|
||||
snippet line 4: line4
|
||||
label ending at line 4, column 1: block 2
|
||||
snippet line 5: line5
|
||||
label ending at line 5, column 5: block 1
|
||||
diagnostic help: try doing it better next time?
|
||||
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
|
||||
label starting at line 1, column 1: block 1
|
||||
label starting at line 1, column 1
|
||||
snippet line 2: line2
|
||||
label starting at line 2, column 5
|
||||
snippet line 3: line3
|
||||
snippet line 4: line4
|
||||
label ending at line 4, column 1
|
||||
snippet line 5: line5
|
||||
label ending at line 5, column 5: block 1
|
||||
diagnostic help: try doing it better next time?
|
||||
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
|
||||
label starting at line 1, column 1: this bit here
|
||||
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
|
||||
label starting at line 3, column 7: also this bit
|
||||
snippet line 4: more here
|
||||
label ending at line 4, column 3: also this bit
|
||||
diagnostic help: try doing it better next time?
|
||||
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
|
||||
|
||||
snippet line 1: source
|
||||
label starting at line 1, column 1: this bit here
|
||||
snippet line 2: text
|
||||
label at line 2, columns 3 to 6: this bit here
|
||||
snippet line 3: here
|
||||
diagnostic help: try doing it better next time?
|
||||
diagnostic code: oops::my::bad
|
||||
|
|
@ -587,7 +594,7 @@ Error: oops!
|
|||
Begin snippet for bad_file.rs starting at line 1, column 1
|
||||
|
||||
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
|
||||
diagnostic help: try doing it better next time?
|
||||
diagnostic code: oops::my::bad
|
||||
|
|
|
|||
Loading…
Reference in New Issue