From 786d11b3517819264aa498a91a625ff759abc89f Mon Sep 17 00:00:00 2001 From: Brooks J Rady Date: Tue, 26 Mar 2024 18:29:22 -0700 Subject: [PATCH] fix(graphical): fix wrapping of related errors --- src/handlers/graphical.rs | 5 +- tests/graphical.rs | 130 ++++++++++++++++++++++---- tests/test_diagnostic_source_macro.rs | 18 ++-- 3 files changed, 129 insertions(+), 24 deletions(-) diff --git a/src/handlers/graphical.rs b/src/handlers/graphical.rs index 4e9125a..863c4f7 100644 --- a/src/handlers/graphical.rs +++ b/src/handlers/graphical.rs @@ -265,7 +265,6 @@ impl GraphicalReportHandler { ); write!(header, "{}", link)?; writeln!(f, "{}", header)?; - writeln!(f)?; } else if let Some(code) = diagnostic.code() { write!(header, "{}", code.style(severity_style),)?; if self.links == LinkStyle::Text && diagnostic.url().is_some() { @@ -273,8 +272,8 @@ impl GraphicalReportHandler { write!(header, " ({})", url.style(self.theme.styles.link))?; } writeln!(f, "{}", header)?; - writeln!(f)?; } + writeln!(f)?; Ok(()) } @@ -358,6 +357,8 @@ impl GraphicalReportHandler { inner_renderer.termwidth -= rest_indent.width(); 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))?; } ErrorKind::StdError(err) => { diff --git a/tests/graphical.rs b/tests/graphical.rs index fdfda1c..a09bec8 100644 --- a/tests/graphical.rs +++ b/tests/graphical.rs @@ -59,14 +59,15 @@ fn word_wrap_options() -> Result<(), MietteError> { let out = 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); // A long word can break with a smaller width let out = fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| { handler.with_width(10) }); - let expected = r#" × abcd + let expected = r#" + × abcd │ efgh │ ijkl │ mnop @@ -81,7 +82,7 @@ fn word_wrap_options() -> Result<(), MietteError> { let out = fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| { 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); // 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"), |handler| handler.with_width(10), ); - let expected = r#" × 12 + let expected = r#" + × 12 │ 123 │ 1234 │ 1234 @@ -110,7 +112,8 @@ fn word_wrap_options() -> Result<(), MietteError> { Report::msg("12 123 1234 12345 123456 1234567 1234567890"), |handler| handler.with_width(10).with_break_words(false), ); - let expected = r#" × 12 + let expected = r#" + × 12 │ 123 │ 1234 │ 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"), |handler| handler.with_width(10).with_break_words(false), ); - let expected = r#" × a-b + let expected = r#" + × a-b │ a-b- │ c a- │ b-c- @@ -158,7 +162,8 @@ fn word_wrap_options() -> Result<(), MietteError> { .with_word_splitter(textwrap::WordSplitter::NoHyphenation) }, ); - let expected = r#" × a-b + let expected = r#" + × a-b │ a-b-c │ a-b-c-d │ 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"), |handler| handler.with_width(10).with_break_words(false), ); - let expected = r#" × a/b + let expected = r#" + × a/b │ a/b/ │ c a/ │ b/c/ @@ -206,7 +212,8 @@ fn word_wrap_options() -> Result<(), MietteError> { .with_word_separator(textwrap::WordSeparator::AsciiSpace) }, ); - let expected = r#" × a/b + let expected = r#" + × a/b │ a/b/c │ a/b/c/d │ 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"), |handler| handler.with_width(15), ); - let expected = r#" × abc def + let expected = r#" + × abc def │ ghi jkl │ mno pqr │ stu vwx @@ -246,7 +254,7 @@ fn wrap_option() -> Result<(), MietteError> { |handler| handler.with_width(15).with_wrap_lines(false), ); 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); // 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"), |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 "# @@ -314,6 +323,91 @@ fn wrapping_nested_errors() -> Result<(), MietteError> { 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>, + } + + #[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] fn empty_source() -> Result<(), MietteError> { #[derive(Debug, Diagnostic, Error)] @@ -376,7 +470,8 @@ if true { let out = fmt_report(err.into()); println!("Error: {}", out); - let expected = r#" × oops! + let expected = r#" + × oops! ╭─[issue:1:1] 1 │ ╭─▶ if true { 2 │ │ a @@ -411,7 +506,8 @@ fn single_line_highlight_span_full_line() { let out = fmt_report(err.into()); println!("Error: {}", out); - let expected = r#" × oops! + let expected = r#" + × oops! ╭─[issue:2:1] 1 │ source 2 │ text @@ -1673,7 +1769,8 @@ fn zero_length_eol_span() { let out = fmt_report(err.into()); println!("Error: {}", out); - let expected = r#" × oops! + let expected = r#" + × oops! ╭─[issue:2:1] 1 │ this is the first line 2 │ this is the second line @@ -1707,7 +1804,8 @@ fn primary_label() { println!("Error: {}", out); // line 2 should be the primary, not line 1 - let expected = r#" × oops! + let expected = r#" + × oops! ╭─[issue:2:2] 1 │ this is the first line · ──── diff --git a/tests/test_diagnostic_source_macro.rs b/tests/test_diagnostic_source_macro.rs index 939812c..54fa272 100644 --- a/tests/test_diagnostic_source_macro.rs +++ b/tests/test_diagnostic_source_macro.rs @@ -104,7 +104,8 @@ fn test_diagnostic_source_pass_extra_info() { .render_report(&mut out, &diag) .unwrap(); println!("Error: {}", out); - let expected = r#" × TestError + let expected = r#" + × TestError ╰─▶ × A complex error happened ╭─[1:2] 1 │ Hello @@ -138,7 +139,8 @@ fn test_diagnostic_source_is_output() { .unwrap(); println!("{}", out); - let expected = r#" × TestError + let expected = r#" + × TestError ╰─▶ × A complex error happened ╭──── 1 │ right here @@ -186,7 +188,8 @@ fn test_nested_diagnostic_source_is_output() { .unwrap(); println!("{}", out); - let expected = r#" × A nested error happened + let expected = r#" + × A nested error happened ├─▶ × TestError │ ╰─▶ × A complex error happened @@ -252,10 +255,12 @@ fn test_nested_cause_chains_for_related_errors_are_output() { .unwrap(); println!("{}", out); - let expected = r#" × A nested error happened + let expected = r#" + × A nested error happened ╰─▶ × A multi-error happened - Error: × A nested error happened + Error: + × A nested error happened ├─▶ × TestError │ ╰─▶ × A complex error happened @@ -271,7 +276,8 @@ fn test_nested_cause_chains_for_related_errors_are_output() { · ──┬─ · ╰── here ╰──── - Error: × A complex error happened + Error: + × A complex error happened ╭──── 1 │ You're actually a mess · ──┬─