mirror of https://github.com/zkat/miette.git
feat(nested): Render inner diagnostics (#170)
This commit is contained in:
parent
46adb3bc6a
commit
aefe323780
|
|
@ -3,7 +3,7 @@ use std::fmt::{self, Write};
|
||||||
use owo_colors::{OwoColorize, Style};
|
use owo_colors::{OwoColorize, Style};
|
||||||
use unicode_width::UnicodeWidthChar;
|
use unicode_width::UnicodeWidthChar;
|
||||||
|
|
||||||
use crate::diagnostic_chain::DiagnosticChain;
|
use crate::diagnostic_chain::{DiagnosticChain, ErrorKind};
|
||||||
use crate::handlers::theme::*;
|
use crate::handlers::theme::*;
|
||||||
use crate::protocol::{Diagnostic, Severity};
|
use crate::protocol::{Diagnostic, Severity};
|
||||||
use crate::{LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents};
|
use crate::{LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents};
|
||||||
|
|
@ -151,7 +151,6 @@ impl GraphicalReportHandler {
|
||||||
diagnostic: &(dyn Diagnostic),
|
diagnostic: &(dyn Diagnostic),
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
self.render_header(f, diagnostic)?;
|
self.render_header(f, diagnostic)?;
|
||||||
writeln!(f)?;
|
|
||||||
self.render_causes(f, diagnostic)?;
|
self.render_causes(f, diagnostic)?;
|
||||||
let src = diagnostic.source_code();
|
let src = diagnostic.source_code();
|
||||||
self.render_snippets(f, diagnostic, src)?;
|
self.render_snippets(f, diagnostic, src)?;
|
||||||
|
|
@ -190,6 +189,7 @@ impl GraphicalReportHandler {
|
||||||
);
|
);
|
||||||
write!(header, "{}", link)?;
|
write!(header, "{}", link)?;
|
||||||
writeln!(f, "{}", header)?;
|
writeln!(f, "{}", header)?;
|
||||||
|
writeln!(f)?;
|
||||||
} else if let Some(code) = diagnostic.code() {
|
} else if let Some(code) = diagnostic.code() {
|
||||||
write!(header, "{}", code.style(severity_style),)?;
|
write!(header, "{}", code.style(severity_style),)?;
|
||||||
if self.links == LinkStyle::Text && diagnostic.url().is_some() {
|
if self.links == LinkStyle::Text && diagnostic.url().is_some() {
|
||||||
|
|
@ -197,6 +197,7 @@ impl GraphicalReportHandler {
|
||||||
write!(header, " ({})", url.style(self.theme.styles.link))?;
|
write!(header, " ({})", url.style(self.theme.styles.link))?;
|
||||||
}
|
}
|
||||||
writeln!(f, "{}", header)?;
|
writeln!(f, "{}", header)?;
|
||||||
|
writeln!(f)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -253,7 +254,22 @@ impl GraphicalReportHandler {
|
||||||
let opts = textwrap::Options::new(width)
|
let opts = textwrap::Options::new(width)
|
||||||
.initial_indent(&initial_indent)
|
.initial_indent(&initial_indent)
|
||||||
.subsequent_indent(&rest_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))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -287,7 +303,6 @@ impl GraphicalReportHandler {
|
||||||
Some(Severity::Advice) => write!(f, "Advice: ")?,
|
Some(Severity::Advice) => write!(f, "Advice: ")?,
|
||||||
};
|
};
|
||||||
self.render_header(f, rel)?;
|
self.render_header(f, rel)?;
|
||||||
writeln!(f)?;
|
|
||||||
self.render_causes(f, rel)?;
|
self.render_causes(f, rel)?;
|
||||||
let src = rel.source_code().or(parent_src);
|
let src = rel.source_code().or(parent_src);
|
||||||
self.render_snippets(f, rel, src)?;
|
self.render_snippets(f, rel, src)?;
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,7 @@ fn single_line_highlight_span_full_line() {
|
||||||
let out = fmt_report(err.into());
|
let out = fmt_report(err.into());
|
||||||
println!("Error: {}", out);
|
println!("Error: {}", out);
|
||||||
|
|
||||||
let expected = r#"
|
let expected = r#" × oops!
|
||||||
× oops!
|
|
||||||
╭─[issue:1:1]
|
╭─[issue:1:1]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
|
|
@ -1201,8 +1200,7 @@ fn zero_length_eol_span() {
|
||||||
let out = fmt_report(err.into());
|
let out = fmt_report(err.into());
|
||||||
println!("Error: {}", out);
|
println!("Error: {}", out);
|
||||||
|
|
||||||
let expected = r#"
|
let expected = r#" × oops!
|
||||||
× oops!
|
|
||||||
╭─[issue:1:1]
|
╭─[issue:1:1]
|
||||||
1 │ this is the first line
|
1 │ this is the first line
|
||||||
2 │ this is the second line
|
2 │ this is the second line
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,16 @@
|
||||||
use miette::Diagnostic;
|
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)]
|
#[derive(Debug, miette::Diagnostic, thiserror::Error)]
|
||||||
#[error("AnErr")]
|
#[error("AnErr")]
|
||||||
struct AnErr;
|
struct AnErr;
|
||||||
|
|
@ -8,7 +19,7 @@ struct AnErr;
|
||||||
#[error("TestError")]
|
#[error("TestError")]
|
||||||
struct TestStructError {
|
struct TestStructError {
|
||||||
#[diagnostic_source]
|
#[diagnostic_source]
|
||||||
asdf_inner_foo: AnErr,
|
asdf_inner_foo: SourceError,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, miette::Diagnostic, thiserror::Error)]
|
#[derive(Debug, miette::Diagnostic, thiserror::Error)]
|
||||||
|
|
@ -37,7 +48,11 @@ struct TestArcedError(#[diagnostic_source] std::sync::Arc<dyn Diagnostic>);
|
||||||
#[test]
|
#[test]
|
||||||
fn test_diagnostic_source() {
|
fn test_diagnostic_source() {
|
||||||
let error = TestStructError {
|
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());
|
assert!(error.diagnostic_source().is_some());
|
||||||
|
|
||||||
|
|
@ -59,3 +74,120 @@ fn test_diagnostic_source() {
|
||||||
let error = TestArcedError(std::sync::Arc::new(AnErr));
|
let error = TestArcedError(std::sync::Arc::new(AnErr));
|
||||||
assert!(error.diagnostic_source().is_some());
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue