diff --git a/src/handlers/graphical.rs b/src/handlers/graphical.rs index 021ba34c..78129258 100644 --- a/src/handlers/graphical.rs +++ b/src/handlers/graphical.rs @@ -317,9 +317,10 @@ impl GraphicalReportHandler { ErrorKind::Diagnostic(diag) => { let mut inner = String::new(); - // Don't print footer for inner errors let mut inner_renderer = self.clone(); + // Don't print footer for inner errors inner_renderer.footer = None; + // Cause chains are already flattened, so don't double-print the nested error inner_renderer.with_cause_chain = false; inner_renderer.render_report(&mut inner, diag)?; @@ -362,6 +363,9 @@ impl GraphicalReportHandler { parent_src: Option<&dyn SourceCode>, ) -> fmt::Result { if let Some(related) = diagnostic.related() { + let mut inner_renderer = self.clone(); + // Re-enable the printing of nested cause chains for related errors + inner_renderer.with_cause_chain = true; writeln!(f)?; for rel in related { match rel.severity() { @@ -369,12 +373,12 @@ impl GraphicalReportHandler { Some(Severity::Warning) => write!(f, "Warning: ")?, Some(Severity::Advice) => write!(f, "Advice: ")?, }; - self.render_header(f, rel)?; - self.render_causes(f, rel)?; + inner_renderer.render_header(f, rel)?; + inner_renderer.render_causes(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, src)?; + inner_renderer.render_snippets(f, rel, src)?; + inner_renderer.render_footer(f, rel)?; + inner_renderer.render_related(f, rel, src)?; } } Ok(()) diff --git a/tests/test_diagnostic_source_macro.rs b/tests/test_diagnostic_source_macro.rs index 334ca349..e5305acd 100644 --- a/tests/test_diagnostic_source_macro.rs +++ b/tests/test_diagnostic_source_macro.rs @@ -194,3 +194,85 @@ fn test_nested_diagnostic_source_is_output() { assert_eq!(expected, out); } + +#[derive(Debug, miette::Diagnostic, thiserror::Error)] +#[error("A multi-error happened")] +struct MultiError { + #[related] + related_errs: Vec>, +} + +#[cfg(feature = "fancy-no-backtrace")] +#[test] +fn test_nested_cause_chains_for_related_errors_are_output() { + let inner_error = TestStructError { + asdf_inner_foo: SourceError { + code: String::from("This is another error"), + help: String::from("You should fix this"), + label: (3, 4), + }, + }; + let first_error = NestedError { + code: String::from("right here"), + label: (6, 4), + the_other_err: Box::new(inner_error), + }; + let second_error = SourceError { + code: String::from("You're actually a mess"), + help: String::from("Get a grip..."), + label: (3, 4), + }; + let multi_error = MultiError { + related_errs: vec![Box::new(first_error), Box::new(second_error)], + }; + let diag = NestedError { + code: String::from("the outside world"), + label: (6, 4), + the_other_err: Box::new(multi_error), + }; + let mut out = String::new(); + miette::GraphicalReportHandler::new_themed(miette::GraphicalTheme::unicode_nocolor()) + .with_width(80) + .with_footer("Yooo, a footer".to_string()) + .render_report(&mut out, &diag) + .unwrap(); + println!("{}", out); + + let expected = r#" × A nested error happened + ╰─▶ × A multi-error happened + + Error: × A nested error happened + ├─▶ × TestError + │ + ╰─▶ × A complex error happened + ╭──── + 1 │ This is another error + · ──┬─ + · ╰── here + ╰──── + help: You should fix this + + ╭──── + 1 │ right here + · ──┬─ + · ╰── here + ╰──── + Error: × A complex error happened + ╭──── + 1 │ You're actually a mess + · ──┬─ + · ╰── here + ╰──── + help: Get a grip... + + ╭──── + 1 │ the outside world + · ──┬─ + · ╰── here + ╰──── + + Yooo, a footer +"#; + + assert_eq!(expected, out); +}