-
-
Notifications
You must be signed in to change notification settings - Fork 126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Render inner diagnostics #170
Changes from all commits
ce4d9c6
66af796
4791251
1c53b57
48f5dab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
|
@@ -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)] | ||
|
@@ -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()); | ||
|
||
|
@@ -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 | ||
╰──── | ||
Comment on lines
+183
to
+187
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently causes come before snippets. This makes it look somewhat awkward. But I am not sure that this should be changed (if at all?) in this PR. |
||
|
||
Yooo, a footer | ||
"#; | ||
Comment on lines
+172
to
+190
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the crux of the change IMO. You can see that nested diagnostics actually get printed out as they are intended to be IMO |
||
|
||
assert_eq!(expected, out); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is, ultimately, the desired user experience for this? Can you give some examples, and how this scales for more complex errors? I'm concerned that this will just create a lot of unintended noise, rather than help users focus on the error at hand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea is that if a developer chooses to go into giving a complete error experience they do not have to go and implement their own printer and instead can re-use the existing infrastructure.
As a concrete example I have the following error tree possible:
related
.source_code
s etcAn example output of this:
Now, this screenshot is without this patch, but once added I will be able to attach more info to the inner error and thus have a clear hierarchy of what happened and how the user could fix it.