Skip to content

Commit

Permalink
feat(nested): Render inner diagnostics (#170)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheNeikos committed May 18, 2023
1 parent 46adb3b commit aefe323
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 10 deletions.
23 changes: 19 additions & 4 deletions src/handlers/graphical.rs
Expand Up @@ -3,7 +3,7 @@ use std::fmt::{self, Write};
use owo_colors::{OwoColorize, Style};
use unicode_width::UnicodeWidthChar;

use crate::diagnostic_chain::DiagnosticChain;
use crate::diagnostic_chain::{DiagnosticChain, ErrorKind};
use crate::handlers::theme::*;
use crate::protocol::{Diagnostic, Severity};
use crate::{LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents};
Expand Down Expand Up @@ -151,7 +151,6 @@ impl GraphicalReportHandler {
diagnostic: &(dyn Diagnostic),
) -> fmt::Result {
self.render_header(f, diagnostic)?;
writeln!(f)?;
self.render_causes(f, diagnostic)?;
let src = diagnostic.source_code();
self.render_snippets(f, diagnostic, src)?;
Expand Down Expand Up @@ -190,13 +189,15 @@ 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() {
let url = diagnostic.url().unwrap(); // safe
write!(header, " ({})", url.style(self.theme.styles.link))?;
}
writeln!(f, "{}", header)?;
writeln!(f)?;
}
Ok(())
}
Expand Down Expand Up @@ -253,7 +254,22 @@ impl GraphicalReportHandler {
let opts = textwrap::Options::new(width)
.initial_indent(&initial_indent)
.subsequent_indent(&rest_indent);
writeln!(f, "{}", textwrap::fill(&error.to_string(), opts))?;
match error {
ErrorKind::Diagnostic(diag) => {
let mut inner = String::new();

// Don't print footer for inner errors
let mut inner_renderer = self.clone();
inner_renderer.footer = None;
inner_renderer.with_cause_chain = false;
inner_renderer.render_report(&mut inner, diag)?;

writeln!(f, "{}", textwrap::fill(&inner, opts))?;
}
ErrorKind::StdError(err) => {
writeln!(f, "{}", textwrap::fill(&err.to_string(), opts))?;
}
}
}
}

Expand Down Expand Up @@ -287,7 +303,6 @@ impl GraphicalReportHandler {
Some(Severity::Advice) => write!(f, "Advice: ")?,
};
self.render_header(f, rel)?;
writeln!(f)?;
self.render_causes(f, rel)?;
let src = rel.source_code().or(parent_src);
self.render_snippets(f, rel, src)?;
Expand Down
6 changes: 2 additions & 4 deletions tests/graphical.rs
Expand Up @@ -85,8 +85,7 @@ 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:1:1]
1 │ source
2 │ text
Expand Down Expand Up @@ -1201,8 +1200,7 @@ fn zero_length_eol_span() {
let out = fmt_report(err.into());
println!("Error: {}", out);

let expected = r#"
× oops!
let expected = r#" × oops!
╭─[issue:1:1]
1 │ this is the first line
2 │ this is the second line
Expand Down
136 changes: 134 additions & 2 deletions tests/test_diagnostic_source_macro.rs
@@ -1,5 +1,16 @@
use miette::Diagnostic;

#[derive(Debug, miette::Diagnostic, thiserror::Error)]
#[error("A complex error happened")]
struct SourceError {
#[source_code]
code: String,
#[help]
help: String,
#[label("here")]
label: (usize, usize),
}

#[derive(Debug, miette::Diagnostic, thiserror::Error)]
#[error("AnErr")]
struct AnErr;
Expand All @@ -8,7 +19,7 @@ struct AnErr;
#[error("TestError")]
struct TestStructError {
#[diagnostic_source]
asdf_inner_foo: AnErr,
asdf_inner_foo: SourceError,
}

#[derive(Debug, miette::Diagnostic, thiserror::Error)]
Expand Down Expand Up @@ -37,7 +48,11 @@ struct TestArcedError(#[diagnostic_source] std::sync::Arc<dyn Diagnostic>);
#[test]
fn test_diagnostic_source() {
let error = TestStructError {
asdf_inner_foo: AnErr,
asdf_inner_foo: SourceError {
code: String::new(),
help: String::new(),
label: (0, 0),
},
};
assert!(error.diagnostic_source().is_some());

Expand All @@ -59,3 +74,120 @@ fn test_diagnostic_source() {
let error = TestArcedError(std::sync::Arc::new(AnErr));
assert!(error.diagnostic_source().is_some());
}

#[test]
fn test_diagnostic_source_pass_extra_info() {
let diag = TestBoxedError(Box::new(SourceError {
code: String::from("Hello\nWorld!"),
help: format!("Have you tried turning it on and off again?"),
label: (1, 4),
}));
let mut out = String::new();
miette::GraphicalReportHandler::new_themed(miette::GraphicalTheme::unicode_nocolor())
.with_width(80)
.with_footer("this is a footer".into())
.render_report(&mut out, &diag)
.unwrap();
println!("Error: {}", out);
let expected = r#" × TestError
╰─▶ × A complex error happened
╭─[1:1]
1 │ Hello
· ──┬─
· ╰── here
2 │ World!
╰────
help: Have you tried turning it on and off again?
this is a footer
"#
.to_string();
assert_eq!(expected, out);
}

#[test]
fn test_diagnostic_source_is_output() {
let diag = TestStructError {
asdf_inner_foo: SourceError {
code: String::from("right here"),
help: String::from("That's where the error is!"),
label: (6, 4),
},
};
let mut out = String::new();
miette::GraphicalReportHandler::new_themed(miette::GraphicalTheme::unicode_nocolor())
.with_width(80)
.render_report(&mut out, &diag)
.unwrap();
println!("{}", out);

let expected = r#" × TestError
╰─▶ × A complex error happened
╭────
1 │ right here
· ──┬─
· ╰── here
╰────
help: That's where the error is!
"#;

assert_eq!(expected, out);
}

#[derive(Debug, miette::Diagnostic, thiserror::Error)]
#[error("A nested error happened")]
struct NestedError {
#[source_code]
code: String,
#[label("here")]
label: (usize, usize),
#[diagnostic_source]
the_other_err: Box<dyn Diagnostic>,
}

#[test]
fn test_nested_diagnostic_source_is_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 diag = NestedError {
code: String::from("right here"),
label: (6, 4),
the_other_err: Box::new(inner_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
├─▶ × TestError
╰─▶ × A complex error happened
╭────
1 │ This is another error
· ──┬─
· ╰── here
╰────
help: You should fix this
╭────
1 │ right here
· ──┬─
· ╰── here
╰────
Yooo, a footer
"#;

assert_eq!(expected, out);
}

0 comments on commit aefe323

Please sign in to comment.