From fa570ff00893d03067d98201db5f64684071349d Mon Sep 17 00:00:00 2001 From: unbyte Date: Wed, 8 Jan 2025 22:57:03 +0800 Subject: [PATCH] fix(graphical): prevent leading newline when no link/code --- src/handlers/graphical.rs | 18 +++++++++--- tests/graphical.rs | 40 +++++++++++++-------------- tests/test_diagnostic_source_macro.rs | 19 +++++++++---- 3 files changed, 46 insertions(+), 31 deletions(-) diff --git a/src/handlers/graphical.rs b/src/handlers/graphical.rs index fcbec052..3e9c7902 100644 --- a/src/handlers/graphical.rs +++ b/src/handlers/graphical.rs @@ -237,7 +237,7 @@ impl GraphicalReportHandler { parent_src: Option<&dyn SourceCode>, ) -> fmt::Result { let src = diagnostic.source_code().or(parent_src); - self.render_header(f, diagnostic)?; + self.render_header(f, diagnostic, false)?; self.render_causes(f, diagnostic, src)?; self.render_snippets(f, diagnostic, src)?; self.render_footer(f, diagnostic)?; @@ -261,13 +261,19 @@ impl GraphicalReportHandler { Ok(()) } - fn render_header(&self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic)) -> fmt::Result { + fn render_header( + &self, + f: &mut impl fmt::Write, + diagnostic: &(dyn Diagnostic), + is_nested: bool, + ) -> fmt::Result { let severity_style = match diagnostic.severity() { Some(Severity::Error) | None => self.theme.styles.error, Some(Severity::Warning) => self.theme.styles.warning, Some(Severity::Advice) => self.theme.styles.advice, }; let mut header = String::new(); + let mut need_newline = is_nested; if self.links == LinkStyle::Link && diagnostic.url().is_some() { let url = diagnostic.url().unwrap(); // safe let code = if let Some(code) = diagnostic.code() { @@ -284,6 +290,7 @@ impl GraphicalReportHandler { ); write!(header, "{}", link)?; writeln!(f, "{}", header)?; + need_newline = true; } else if let Some(code) = diagnostic.code() { write!(header, "{}", code.style(severity_style),)?; if self.links == LinkStyle::Text && diagnostic.url().is_some() { @@ -291,8 +298,11 @@ impl GraphicalReportHandler { write!(header, " ({})", url.style(self.theme.styles.link))?; } writeln!(f, "{}", header)?; + need_newline = true; + } + if need_newline { + writeln!(f)?; } - writeln!(f)?; Ok(()) } @@ -493,7 +503,7 @@ impl GraphicalReportHandler { Some(Severity::Warning) => write!(f, "Warning: ")?, Some(Severity::Advice) => write!(f, "Advice: ")?, }; - inner_renderer.render_header(f, rel)?; + inner_renderer.render_header(f, rel, true)?; let src = rel.source_code().or(parent_src); inner_renderer.render_causes(f, rel, src)?; inner_renderer.render_snippets(f, rel, src)?; diff --git a/tests/graphical.rs b/tests/graphical.rs index 31768127..b80e16db 100644 --- a/tests/graphical.rs +++ b/tests/graphical.rs @@ -59,7 +59,7 @@ fn word_wrap_options() -> Result<(), MietteError> { let out = fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| handler); - let expected = "\n × abcdefghijklmnopqrstuvwxyz\n".to_string(); + let expected = " × abcdefghijklmnopqrstuvwxyz\n".to_string(); assert_eq!(expected, out); // A long word can break with a smaller width @@ -75,14 +75,14 @@ fn word_wrap_options() -> Result<(), MietteError> { │ uvwx │ yz "# - .to_string(); + .trim_start_matches('\n'); assert_eq!(expected, out); // Unless, word breaking is disabled let out = fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| { handler.with_width(10).with_break_words(false) }); - let expected = "\n × abcdefghijklmnopqrstuvwxyz\n".to_string(); + let expected = " × abcdefghijklmnopqrstuvwxyz\n".to_string(); assert_eq!(expected, out); // Breaks should start at the boundary of each word if possible @@ -104,7 +104,7 @@ fn word_wrap_options() -> Result<(), MietteError> { │ 5678 │ 90 "# - .to_string(); + .trim_start_matches('\n'); assert_eq!(expected, out); // But long words should not break if word breaking is disabled @@ -121,7 +121,7 @@ fn word_wrap_options() -> Result<(), MietteError> { │ 1234567 │ 1234567890 "# - .to_string(); + .trim_start_matches('\n'); assert_eq!(expected, out); // Unless, of course, there are hyphens @@ -149,7 +149,7 @@ fn word_wrap_options() -> Result<(), MietteError> { │ f-g- │ h "# - .to_string(); + .trim_start_matches('\n'); assert_eq!(expected, out); // Which requires an additional opt-out @@ -171,7 +171,7 @@ fn word_wrap_options() -> Result<(), MietteError> { │ a-b-c-d-e-f-g │ a-b-c-d-e-f-g-h "# - .to_string(); + .trim_start_matches('\n'); assert_eq!(expected, out); // Or if there are _other_ unicode word boundaries @@ -199,7 +199,7 @@ fn word_wrap_options() -> Result<(), MietteError> { │ f/g/ │ h "# - .to_string(); + .trim_start_matches('\n'); assert_eq!(expected, out); // Such things require you to opt-in to only breaking on ASCII whitespace @@ -221,7 +221,7 @@ fn word_wrap_options() -> Result<(), MietteError> { │ a/b/c/d/e/f/g │ a/b/c/d/e/f/g/h "# - .to_string(); + .trim_start_matches('\n'); assert_eq!(expected, out); Ok(()) @@ -245,7 +245,7 @@ fn wrap_option() -> Result<(), MietteError> { │ pqr stu │ vwx yz "# - .to_string(); + .trim_start_matches('\n'); assert_eq!(expected, out); // Unless, wrapping is disabled @@ -254,7 +254,7 @@ fn wrap_option() -> Result<(), MietteError> { |handler| handler.with_width(15).with_wrap_lines(false), ); let expected = - "\n × abc def ghi jkl mno pqr stu vwx yz abc def ghi jkl mno pqr stu vwx yz\n".to_string(); + " × 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 @@ -267,7 +267,7 @@ fn wrap_option() -> Result<(), MietteError> { │ abc def ghi jkl mno pqr stu vwx yz │ abc def ghi jkl mno pqr stu vwx yz "# - .to_string(); + .trim_start_matches('\n'); assert_eq!(expected, out); Ok(()) @@ -485,8 +485,7 @@ if true { · ╰──── big ╰──── "# - .to_string(); - + .trim_start_matches('\n'); assert_eq!(expected, out); } @@ -517,8 +516,7 @@ fn single_line_highlight_span_full_line() { · ╰── This bit here ╰──── "# - .to_string(); - + .trim_start_matches('\n'); assert_eq!(expected, out); } @@ -1781,8 +1779,7 @@ fn zero_length_eol_span() { · ╰── This bit here ╰──── "# - .to_string(); - + .trim_start_matches('\n'); assert_eq!(expected, out); } @@ -1817,8 +1814,7 @@ fn primary_label() { · ╰── nope ╰──── "# - .to_string(); - + .trim_start_matches('\n'); assert_eq!(expected, out); } @@ -1968,7 +1964,8 @@ fn syntax_highlighter() { · ╰── this is a label 3 │ } ╰──── -"#; +"# + .trim_start_matches('\n'); assert!(out.contains("\u{1b}[38;2;180;142;173m")); assert_eq!(expected, strip_ansi_escapes::strip_str(out)) } @@ -2028,6 +2025,7 @@ fn syntax_highlighter_on_real_file() { l2 = line, l3 = line + 1 ); + let expected = expected.trim_start_matches('\n'); assert!(out.contains("\u{1b}[38;2;180;142;173m")); assert_eq!(expected, strip_ansi_escapes::strip_str(out)); } diff --git a/tests/test_diagnostic_source_macro.rs b/tests/test_diagnostic_source_macro.rs index 71429efb..e038830d 100644 --- a/tests/test_diagnostic_source_macro.rs +++ b/tests/test_diagnostic_source_macro.rs @@ -118,7 +118,8 @@ fn test_diagnostic_source_pass_extra_info() { this is a footer "# - .to_string(); + .trim_start_matches('\n'); + assert_eq!(expected, out); } @@ -149,7 +150,8 @@ fn test_diagnostic_source_is_output() { ╰──── help: That's where the error is! -"#; +"# + .trim_start_matches('\n'); assert_eq!(expected, out); } @@ -208,7 +210,8 @@ fn test_nested_diagnostic_source_is_output() { ╰──── Yooo, a footer -"#; +"# + .trim_start_matches('\n'); assert_eq!(expected, out); } @@ -295,7 +298,8 @@ fn test_nested_cause_chains_for_related_errors_are_output() { ╰──── Yooo, a footer -"#; +"# + .trim_start_matches('\n'); assert_eq!(expected, out); } @@ -354,7 +358,9 @@ fn test_display_related_errors_as_nested() { · ╰── here ╰──── help: Get a grip... -"#; +"# + .trim_start_matches('\n'); + assert_eq!(expected, out); } @@ -403,7 +409,8 @@ fn source_is_inherited_to_causes() { Yooo, a footer -"#; +"# + .trim_start_matches('\n'); assert_eq!(expected, out); }