fix(graphical): fix wrapping of related errors

This commit is contained in:
Brooks J Rady 2024-03-26 18:29:22 -07:00
parent 4426f9c8ed
commit 786d11b351
3 changed files with 129 additions and 24 deletions

View File

@ -265,7 +265,6 @@ impl GraphicalReportHandler {
); );
write!(header, "{}", link)?; write!(header, "{}", link)?;
writeln!(f, "{}", header)?; writeln!(f, "{}", header)?;
writeln!(f)?;
} else if let Some(code) = diagnostic.code() { } else if let Some(code) = diagnostic.code() {
write!(header, "{}", code.style(severity_style),)?; write!(header, "{}", code.style(severity_style),)?;
if self.links == LinkStyle::Text && diagnostic.url().is_some() { if self.links == LinkStyle::Text && diagnostic.url().is_some() {
@ -273,8 +272,8 @@ impl GraphicalReportHandler {
write!(header, " ({})", url.style(self.theme.styles.link))?; write!(header, " ({})", url.style(self.theme.styles.link))?;
} }
writeln!(f, "{}", header)?; writeln!(f, "{}", header)?;
writeln!(f)?;
} }
writeln!(f)?;
Ok(()) Ok(())
} }
@ -358,6 +357,8 @@ impl GraphicalReportHandler {
inner_renderer.termwidth -= rest_indent.width(); inner_renderer.termwidth -= rest_indent.width();
inner_renderer.render_report(&mut inner, diag)?; inner_renderer.render_report(&mut inner, diag)?;
// If there was no header, remove the leading newline
let inner = inner.trim_start_matches('\n');
writeln!(f, "{}", self.wrap(&inner, opts))?; writeln!(f, "{}", self.wrap(&inner, opts))?;
} }
ErrorKind::StdError(err) => { ErrorKind::StdError(err) => {

View File

@ -59,14 +59,15 @@ fn word_wrap_options() -> Result<(), MietteError> {
let out = let out =
fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| handler); fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| handler);
let expected = " × abcdefghijklmnopqrstuvwxyz\n".to_string(); let expected = "\n × abcdefghijklmnopqrstuvwxyz\n".to_string();
assert_eq!(expected, out); assert_eq!(expected, out);
// A long word can break with a smaller width // A long word can break with a smaller width
let out = fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| { let out = fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| {
handler.with_width(10) handler.with_width(10)
}); });
let expected = r#" × abcd let expected = r#"
× abcd
efgh efgh
ijkl ijkl
mnop mnop
@ -81,7 +82,7 @@ fn word_wrap_options() -> Result<(), MietteError> {
let out = fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| { let out = fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| {
handler.with_width(10).with_break_words(false) handler.with_width(10).with_break_words(false)
}); });
let expected = " × abcdefghijklmnopqrstuvwxyz\n".to_string(); let expected = "\n × abcdefghijklmnopqrstuvwxyz\n".to_string();
assert_eq!(expected, out); assert_eq!(expected, out);
// Breaks should start at the boundary of each word if possible // Breaks should start at the boundary of each word if possible
@ -89,7 +90,8 @@ fn word_wrap_options() -> Result<(), MietteError> {
Report::msg("12 123 1234 12345 123456 1234567 1234567890"), Report::msg("12 123 1234 12345 123456 1234567 1234567890"),
|handler| handler.with_width(10), |handler| handler.with_width(10),
); );
let expected = r#" × 12 let expected = r#"
× 12
123 123
1234 1234
1234 1234
@ -110,7 +112,8 @@ fn word_wrap_options() -> Result<(), MietteError> {
Report::msg("12 123 1234 12345 123456 1234567 1234567890"), Report::msg("12 123 1234 12345 123456 1234567 1234567890"),
|handler| handler.with_width(10).with_break_words(false), |handler| handler.with_width(10).with_break_words(false),
); );
let expected = r#" × 12 let expected = r#"
× 12
123 123
1234 1234
12345 12345
@ -126,7 +129,8 @@ fn word_wrap_options() -> Result<(), MietteError> {
Report::msg("a-b a-b-c a-b-c-d a-b-c-d-e a-b-c-d-e-f a-b-c-d-e-f-g a-b-c-d-e-f-g-h"), Report::msg("a-b a-b-c a-b-c-d a-b-c-d-e a-b-c-d-e-f a-b-c-d-e-f-g a-b-c-d-e-f-g-h"),
|handler| handler.with_width(10).with_break_words(false), |handler| handler.with_width(10).with_break_words(false),
); );
let expected = r#" × a-b let expected = r#"
× a-b
a-b- a-b-
c a- c a-
b-c- b-c-
@ -158,7 +162,8 @@ fn word_wrap_options() -> Result<(), MietteError> {
.with_word_splitter(textwrap::WordSplitter::NoHyphenation) .with_word_splitter(textwrap::WordSplitter::NoHyphenation)
}, },
); );
let expected = r#" × a-b let expected = r#"
× a-b
a-b-c a-b-c
a-b-c-d a-b-c-d
a-b-c-d-e a-b-c-d-e
@ -174,7 +179,8 @@ fn word_wrap_options() -> Result<(), MietteError> {
Report::msg("a/b a/b/c a/b/c/d a/b/c/d/e a/b/c/d/e/f a/b/c/d/e/f/g a/b/c/d/e/f/g/h"), Report::msg("a/b a/b/c a/b/c/d a/b/c/d/e a/b/c/d/e/f a/b/c/d/e/f/g a/b/c/d/e/f/g/h"),
|handler| handler.with_width(10).with_break_words(false), |handler| handler.with_width(10).with_break_words(false),
); );
let expected = r#" × a/b let expected = r#"
× a/b
a/b/ a/b/
c a/ c a/
b/c/ b/c/
@ -206,7 +212,8 @@ fn word_wrap_options() -> Result<(), MietteError> {
.with_word_separator(textwrap::WordSeparator::AsciiSpace) .with_word_separator(textwrap::WordSeparator::AsciiSpace)
}, },
); );
let expected = r#" × a/b let expected = r#"
× a/b
a/b/c a/b/c
a/b/c/d a/b/c/d
a/b/c/d/e a/b/c/d/e
@ -227,7 +234,8 @@ fn wrap_option() -> Result<(), MietteError> {
Report::msg("abc def ghi jkl mno pqr stu vwx yz abc def ghi jkl mno pqr stu vwx yz"), Report::msg("abc def ghi jkl mno pqr stu vwx yz abc def ghi jkl mno pqr stu vwx yz"),
|handler| handler.with_width(15), |handler| handler.with_width(15),
); );
let expected = r#" × abc def let expected = r#"
× abc def
ghi jkl ghi jkl
mno pqr mno pqr
stu vwx stu vwx
@ -246,7 +254,7 @@ fn wrap_option() -> Result<(), MietteError> {
|handler| handler.with_width(15).with_wrap_lines(false), |handler| handler.with_width(15).with_wrap_lines(false),
); );
let expected = let expected =
" × abc def ghi jkl mno pqr stu vwx yz abc def ghi jkl mno pqr stu vwx yz\n".to_string(); "\n × abc def ghi jkl mno pqr stu vwx yz abc def ghi jkl mno pqr stu vwx yz\n".to_string();
assert_eq!(expected, out); assert_eq!(expected, out);
// Then, user-defined new lines should be preserved wrapping is disabled // Then, user-defined new lines should be preserved wrapping is disabled
@ -254,7 +262,8 @@ fn wrap_option() -> Result<(), MietteError> {
Report::msg("abc def ghi jkl mno pqr stu vwx yz\nabc def ghi jkl mno pqr stu vwx yz\nabc def ghi jkl mno pqr stu vwx yz"), Report::msg("abc def ghi jkl mno pqr stu vwx yz\nabc def ghi jkl mno pqr stu vwx yz\nabc def ghi jkl mno pqr stu vwx yz"),
|handler| handler.with_width(15).with_wrap_lines(false), |handler| handler.with_width(15).with_wrap_lines(false),
); );
let expected = r#" × abc def ghi jkl mno pqr stu vwx yz let expected = r#"
× abc def ghi jkl mno pqr stu vwx yz
abc def ghi jkl mno pqr stu vwx yz abc def ghi jkl mno pqr stu vwx yz
abc def ghi jkl mno pqr stu vwx yz abc def ghi jkl mno pqr stu vwx yz
"# "#
@ -314,6 +323,91 @@ fn wrapping_nested_errors() -> Result<(), MietteError> {
Ok(()) Ok(())
} }
#[test]
fn wrapping_related_errors() -> Result<(), MietteError> {
#[derive(Debug, Diagnostic, Error)]
#[error("This is the parent error, the error withhhhh the children, kiddos, pups, as it were, and so on...")]
#[diagnostic(
code(mama::error),
help(
"try doing it better next time? I mean, you could have also done better thisssss time, but no?"
)
)]
struct MamaError {
#[diagnostic_source]
baby: BrotherError,
}
#[derive(Debug, Diagnostic, Error)]
#[error("Welcome to the brother-error brotherhood — where all of the wee baby errors join into a formidable force")]
#[diagnostic(code(brother::error))]
struct BrotherError {
#[related]
brethren: Vec<Box<dyn Diagnostic + Send + Sync>>,
}
#[derive(Debug, Diagnostic, Error)]
#[error("Wah wah: I may be small, but I'll cause a proper bout of trouble — justt try wrapping this mess of a line, buddo!")]
#[diagnostic(help(
"it cannot be helped... woulddddddd you really want to get rid of an error that's so cute?"
))]
struct BabyError;
#[derive(Debug, Diagnostic, Error)]
#[error("Wah wah: I may be small, but I'll cause a proper bout of trouble — justt try wrapping this mess of a line, buddo!")]
#[diagnostic(severity(Warning))]
struct BabyWarning;
#[derive(Debug, Diagnostic, Error)]
#[error("Wah wah: I may be small, but I'll cause a proper bout of trouble — justt try wrapping this mess of a line, buddo!")]
#[diagnostic(severity(Advice))]
struct BabyAdvice;
let err = MamaError {
baby: BrotherError {
brethren: vec![BabyError.into(), BabyWarning.into(), BabyAdvice.into()],
},
};
let out = fmt_report_with_settings(err.into(), |handler| handler.with_width(50));
let expected = r#"mama::error
× This is the parent error, the error withhhhh
the children, kiddos, pups, as it were, and
so on...
brother::error
× Welcome to the brother-error
brotherhood where all of the wee
baby errors join into a formidable
force
Error:
× Wah wah: I may be small, but I'll
cause a proper bout of trouble justt
try wrapping this mess of a line,
buddo!
help: it cannot be helped... woulddddddd
you really want to get rid of an
error that's so cute?
Warning:
Wah wah: I may be small, but I'll
cause a proper bout of trouble justt
try wrapping this mess of a line,
buddo!
Advice:
Wah wah: I may be small, but I'll
cause a proper bout of trouble justt
try wrapping this mess of a line,
buddo!
help: try doing it better next time? I mean,
you could have also done better thisssss
time, but no?
"#;
assert_eq!(expected, out);
Ok(())
}
#[test] #[test]
fn empty_source() -> Result<(), MietteError> { fn empty_source() -> Result<(), MietteError> {
#[derive(Debug, Diagnostic, Error)] #[derive(Debug, Diagnostic, Error)]
@ -376,7 +470,8 @@ if true {
let out = fmt_report(err.into()); let out = fmt_report(err.into());
println!("Error: {}", out); println!("Error: {}", out);
let expected = r#" × oops! let expected = r#"
× oops!
[issue:1:1] [issue:1:1]
1 if true { 1 if true {
2 a 2 a
@ -411,7 +506,8 @@ fn single_line_highlight_span_full_line() {
let out = fmt_report(err.into()); let out = fmt_report(err.into());
println!("Error: {}", out); println!("Error: {}", out);
let expected = r#" × oops! let expected = r#"
× oops!
[issue:2:1] [issue:2:1]
1 source 1 source
2 text 2 text
@ -1673,7 +1769,8 @@ fn zero_length_eol_span() {
let out = fmt_report(err.into()); let out = fmt_report(err.into());
println!("Error: {}", out); println!("Error: {}", out);
let expected = r#" × oops! let expected = r#"
× oops!
[issue:2:1] [issue:2:1]
1 this is the first line 1 this is the first line
2 this is the second line 2 this is the second line
@ -1707,7 +1804,8 @@ fn primary_label() {
println!("Error: {}", out); println!("Error: {}", out);
// line 2 should be the primary, not line 1 // line 2 should be the primary, not line 1
let expected = r#" × oops! let expected = r#"
× oops!
[issue:2:2] [issue:2:2]
1 this is the first line 1 this is the first line
· ·

View File

@ -104,7 +104,8 @@ fn test_diagnostic_source_pass_extra_info() {
.render_report(&mut out, &diag) .render_report(&mut out, &diag)
.unwrap(); .unwrap();
println!("Error: {}", out); println!("Error: {}", out);
let expected = r#" × TestError let expected = r#"
× TestError
× A complex error happened × A complex error happened
[1:2] [1:2]
1 Hello 1 Hello
@ -138,7 +139,8 @@ fn test_diagnostic_source_is_output() {
.unwrap(); .unwrap();
println!("{}", out); println!("{}", out);
let expected = r#" × TestError let expected = r#"
× TestError
× A complex error happened × A complex error happened
1 right here 1 right here
@ -186,7 +188,8 @@ fn test_nested_diagnostic_source_is_output() {
.unwrap(); .unwrap();
println!("{}", out); println!("{}", out);
let expected = r#" × A nested error happened let expected = r#"
× A nested error happened
× TestError × TestError
× A complex error happened × A complex error happened
@ -252,10 +255,12 @@ fn test_nested_cause_chains_for_related_errors_are_output() {
.unwrap(); .unwrap();
println!("{}", out); println!("{}", out);
let expected = r#" × A nested error happened let expected = r#"
× A nested error happened
× A multi-error happened × A multi-error happened
Error: × A nested error happened Error:
× A nested error happened
× TestError × TestError
× A complex error happened × A complex error happened
@ -271,7 +276,8 @@ fn test_nested_cause_chains_for_related_errors_are_output() {
· ·
· here · here
Error: × A complex error happened Error:
× A complex error happened
1 You're actually a mess 1 You're actually a mess
· ·