mirror of https://github.com/zkat/miette.git
fix(graphical): Extend error text span to whole code points (#312)
Fixes: https://github.com/zkat/miette/issues/223 This fixes a panic when an error starts inside a Unicode code point. The range is extended to start (or end) at the beginning (or end) of the character inside which the byte offset is located.
This commit is contained in:
parent
d37ada876a
commit
a8b4ae012a
|
|
@ -651,11 +651,22 @@ impl GraphicalReportHandler {
|
|||
}
|
||||
|
||||
/// Returns the visual column position of a byte offset on a specific line.
|
||||
fn visual_offset(&self, line: &Line, offset: usize) -> usize {
|
||||
///
|
||||
/// If the offset occurs in the middle of a character, the returned column
|
||||
/// corresponds to that character's first column in `start` is true, or its
|
||||
/// last column if `start` is false.
|
||||
fn visual_offset(&self, line: &Line, offset: usize, start: bool) -> usize {
|
||||
let line_range = line.offset..=(line.offset + line.length);
|
||||
assert!(line_range.contains(&offset));
|
||||
|
||||
let text_index = offset - line.offset;
|
||||
let mut text_index = offset - line.offset;
|
||||
while text_index <= line.text.len() && !line.text.is_char_boundary(text_index) {
|
||||
if start {
|
||||
text_index -= 1;
|
||||
} else {
|
||||
text_index += 1;
|
||||
}
|
||||
}
|
||||
let text = &line.text[..text_index.min(line.text.len())];
|
||||
let text_width = self.line_visual_char_width(text).sum();
|
||||
if text_index > line.text.len() {
|
||||
|
|
@ -706,8 +717,8 @@ impl GraphicalReportHandler {
|
|||
.map(|hl| {
|
||||
let byte_start = hl.offset();
|
||||
let byte_end = hl.offset() + hl.len();
|
||||
let start = self.visual_offset(line, byte_start).max(highest);
|
||||
let end = self.visual_offset(line, byte_end).max(start + 1);
|
||||
let start = self.visual_offset(line, byte_start, true).max(highest);
|
||||
let end = self.visual_offset(line, byte_end, false).max(start + 1);
|
||||
|
||||
let vbar_offset = (start + end) / 2;
|
||||
let num_left = vbar_offset - start;
|
||||
|
|
|
|||
|
|
@ -1247,3 +1247,77 @@ fn primary_label() {
|
|||
|
||||
assert_eq!(expected, out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_line_with_wide_char_unaligned_span_start() -> Result<(), MietteError> {
|
||||
#[derive(Debug, Diagnostic, Error)]
|
||||
#[error("oops!")]
|
||||
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
||||
struct MyBad {
|
||||
#[source_code]
|
||||
src: NamedSource,
|
||||
#[label("this bit here")]
|
||||
highlight: SourceSpan,
|
||||
}
|
||||
|
||||
let src = "source\n 👼🏼text\n here".to_string();
|
||||
let err = MyBad {
|
||||
src: NamedSource::new("bad_file.rs", src),
|
||||
highlight: (10, 5).into(),
|
||||
};
|
||||
let out = fmt_report(err.into());
|
||||
println!("Error: {}", out);
|
||||
let expected = r#"oops::my::bad
|
||||
|
||||
× oops!
|
||||
╭─[bad_file.rs:2:4]
|
||||
1 │ source
|
||||
2 │ 👼🏼text
|
||||
· ──┬─
|
||||
· ╰── this bit here
|
||||
3 │ here
|
||||
╰────
|
||||
help: try doing it better next time?
|
||||
"#
|
||||
.trim_start()
|
||||
.to_string();
|
||||
assert_eq!(expected, out);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_line_with_wide_char_unaligned_span_end() -> Result<(), MietteError> {
|
||||
#[derive(Debug, Diagnostic, Error)]
|
||||
#[error("oops!")]
|
||||
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
|
||||
struct MyBad {
|
||||
#[source_code]
|
||||
src: NamedSource,
|
||||
#[label("this bit here")]
|
||||
highlight: SourceSpan,
|
||||
}
|
||||
|
||||
let src = "source\n text 👼🏼\n here".to_string();
|
||||
let err = MyBad {
|
||||
src: NamedSource::new("bad_file.rs", src),
|
||||
highlight: (9, 6).into(),
|
||||
};
|
||||
let out = fmt_report(err.into());
|
||||
println!("Error: {}", out);
|
||||
let expected = r#"oops::my::bad
|
||||
|
||||
× oops!
|
||||
╭─[bad_file.rs:2:3]
|
||||
1 │ source
|
||||
2 │ text 👼🏼
|
||||
· ───┬───
|
||||
· ╰── this bit here
|
||||
3 │ here
|
||||
╰────
|
||||
help: try doing it better next time?
|
||||
"#
|
||||
.trim_start()
|
||||
.to_string();
|
||||
assert_eq!(expected, out);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue