diff --git a/src/handlers/graphical.rs b/src/handlers/graphical.rs index 98d5e54..ea293e5 100644 --- a/src/handlers/graphical.rs +++ b/src/handlers/graphical.rs @@ -110,9 +110,10 @@ impl GraphicalReportHandler { self.render_header(f, diagnostic)?; writeln!(f)?; self.render_causes(f, diagnostic)?; - self.render_snippets(f, diagnostic)?; + let src = diagnostic.source_code(); + self.render_snippets(f, diagnostic, src)?; self.render_footer(f, diagnostic)?; - self.render_related(f, diagnostic)?; + self.render_related(f, diagnostic, src)?; if let Some(footer) = &self.footer { writeln!(f)?; let width = self.termwidth.saturating_sub(4); @@ -226,6 +227,7 @@ impl GraphicalReportHandler { &self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic), + parent_src: Option<&dyn SourceCode>, ) -> fmt::Result { if let Some(related) = diagnostic.related() { writeln!(f)?; @@ -234,9 +236,10 @@ impl GraphicalReportHandler { self.render_header(f, rel)?; writeln!(f)?; self.render_causes(f, rel)?; - self.render_snippets(f, rel)?; + let src = rel.source_code().or(parent_src); + self.render_snippets(f, rel, src)?; self.render_footer(f, rel)?; - self.render_related(f, rel)?; + self.render_related(f, rel, src)?; } } Ok(()) @@ -246,8 +249,9 @@ impl GraphicalReportHandler { &self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic), + opt_source: Option<&dyn SourceCode>, ) -> fmt::Result { - if let Some(source) = diagnostic.source_code() { + if let Some(source) = opt_source { if let Some(labels) = diagnostic.labels() { let mut labels = labels.collect::>(); labels.sort_unstable_by_key(|l| l.inner().offset()); diff --git a/src/handlers/narratable.rs b/src/handlers/narratable.rs index 31e75cf..c1dd601 100644 --- a/src/handlers/narratable.rs +++ b/src/handlers/narratable.rs @@ -58,9 +58,10 @@ impl NarratableReportHandler { ) -> fmt::Result { self.render_header(f, diagnostic)?; self.render_causes(f, diagnostic)?; - self.render_snippets(f, diagnostic)?; + let src = diagnostic.source_code(); + self.render_snippets(f, diagnostic, src)?; self.render_footer(f, diagnostic)?; - self.render_related(f, diagnostic)?; + self.render_related(f, diagnostic, src)?; if let Some(footer) = &self.footer { writeln!(f, "{}", footer)?; } @@ -105,6 +106,7 @@ impl NarratableReportHandler { &self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic), + parent_src: Option<&dyn SourceCode>, ) -> fmt::Result { if let Some(related) = diagnostic.related() { writeln!(f)?; @@ -113,9 +115,10 @@ impl NarratableReportHandler { self.render_header(f, rel)?; writeln!(f)?; self.render_causes(f, rel)?; - self.render_snippets(f, rel)?; + let src = rel.source_code().or(parent_src); + self.render_snippets(f, rel, src)?; self.render_footer(f, rel)?; - self.render_related(f, rel)?; + self.render_related(f, rel, src)?; } } Ok(()) @@ -125,8 +128,9 @@ impl NarratableReportHandler { &self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic), + source_code: Option<&dyn SourceCode>, ) -> fmt::Result { - if let Some(source) = diagnostic.source_code() { + if let Some(source) = source_code { if let Some(labels) = diagnostic.labels() { let mut labels = labels.collect::>(); labels.sort_unstable_by_key(|l| l.inner().offset()); diff --git a/tests/graphical.rs b/tests/graphical.rs index 4503f8f..1c5a6ba 100644 --- a/tests/graphical.rs +++ b/tests/graphical.rs @@ -820,3 +820,63 @@ Error: oops::my::bad assert_eq!(expected, out); Ok(()) } + +#[test] +fn related_source_code_propagation() -> 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, + #[related] + related: Vec, + } + + #[derive(Debug, Diagnostic, Error)] + #[error("oops!")] + #[diagnostic(code(oops::my::bad))] + struct InnerError { + #[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.clone()), + highlight: (9, 4).into(), + related: vec![InnerError { + highlight: (0, 6).into(), + }], + }; + let out = fmt_report(err.into()); + println!("Error: {}", out); + let expected = r#"oops::my::bad + + × oops! + ╭─[bad_file.rs:1:1] + 1 │ source + 2 │ text + · ──┬─ + · ╰── this bit here + 3 │ here + ╰──── + help: try doing it better next time? + +Error: oops::my::bad + + × oops! + ╭─[bad_file.rs:1:1] + 1 │ source + · ───┬── + · ╰── this bit here + 2 │ text + ╰──── +"# + .trim_start() + .to_string(); + assert_eq!(expected, out); + Ok(()) +} diff --git a/tests/narrated.rs b/tests/narrated.rs index 5d2eff1..93d9695 100644 --- a/tests/narrated.rs +++ b/tests/narrated.rs @@ -605,3 +605,62 @@ diagnostic code: oops::my::bad assert_eq!(expected, out); Ok(()) } + +#[test] +fn related_source_code_propagation() -> 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, + #[related] + related: Vec, + } + + #[derive(Debug, Diagnostic, Error)] + #[error("oops!")] + #[diagnostic(code(oops::my::bad))] + struct InnerError { + #[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.clone()), + highlight: (9, 4).into(), + related: vec![InnerError { + highlight: (0, 6).into(), + }], + }; + let out = fmt_report(err.into()); + println!("Error: {}", out); + let expected = r#"oops! + Diagnostic severity: error +Begin snippet for bad_file.rs starting at line 1, column 1 + +snippet line 1: source +snippet line 2: text + label at line 2, columns 3 to 6: this bit here +snippet line 3: here +diagnostic help: try doing it better next time? +diagnostic code: oops::my::bad + +Error: oops! + Diagnostic severity: error + +Begin snippet for bad_file.rs starting at line 1, column 1 + +snippet line 1: source + label at line 1, columns 1 to 6: this bit here +snippet line 2: text +diagnostic code: oops::my::bad +"# + .trim_start() + .to_string(); + assert_eq!(expected, out); + Ok(()) +}