diff --git a/src/printer/graphical_printer.rs b/src/printer/graphical_printer.rs index 17e6e36..82a76b8 100644 --- a/src/printer/graphical_printer.rs +++ b/src/printer/graphical_printer.rs @@ -382,12 +382,13 @@ impl GraphicalReportPrinter { let mut highest = 0; let chars = &self.theme.characters; for hl in single_liners { + let hl_len = std::cmp::max(1, hl.len()); let local_offset = hl.offset() - line.offset; - let vbar_offset = local_offset + (hl.len() / 2); + let vbar_offset = local_offset + (hl_len / 2); let num_left = vbar_offset - local_offset; - let num_right = local_offset + hl.len() - vbar_offset - 1; + let num_right = local_offset + hl_len - vbar_offset - 1; let start = std::cmp::max(local_offset, highest); - let end = local_offset + hl.len(); + let end = local_offset + hl_len; if start < end { underlines.push_str( &format!( @@ -414,9 +415,10 @@ impl GraphicalReportPrinter { if let Some(label) = hl.label() { self.write_no_linum(f, linum_width)?; self.render_highlight_gutter(f, max_gutter, line, all_highlights)?; + let hl_len = std::cmp::max(1, hl.len()); let local_offset = hl.offset() - line.offset; - let vbar_offset = local_offset + (hl.len() / 2); - let num_right = local_offset + hl.len() - vbar_offset - 1; + let vbar_offset = local_offset + (hl_len / 2); + let num_right = local_offset + hl_len - vbar_offset - 1; let lines = format!( "{:width$}{}{} {}", " ", diff --git a/tests/printer.rs b/tests/printer.rs index cafa6c5..f2f91aa 100644 --- a/tests/printer.rs +++ b/tests/printer.rs @@ -65,6 +65,48 @@ fn single_line_highlight() -> Result<(), MietteError> { Ok(()) } +#[test] +fn single_line_highlight_with_empty_span() -> Result<(), MietteError> { + #[derive(Debug, Diagnostic, Error)] + #[error("oops!")] + #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] + struct MyBad { + src: String, + #[snippet(src, "This is the part that broke")] + ctx: SourceSpan, + #[highlight(ctx)] + highlight: SourceSpan, + } + + let src = "source\n text\n here".to_string(); + let len = src.len(); + let err = MyBad { + src, + ctx: ("bad_file.rs", 0, len).into(), + highlight: ("this bit here", 9, 0).into(), + }; + let out = fmt_report(err.into()); + println!("{}", out); + let expected = r#" +────[oops::my::bad]──────────────────── + + × oops! + + ╭───[bad_file.rs:1:1] This is the part that broke: + 1 │ source + 2 │ text + · ┬ + · ╰─ this bit here + 3 │ here + + ‽ try doing it better next time? +"# + .trim_start() + .to_string(); + assert_eq!(expected, out); + Ok(()) +} + #[test] fn single_line_highlight_no_label() -> Result<(), MietteError> { #[derive(Debug, Diagnostic, Error)]