mirror of https://github.com/zkat/miette.git
fix(graphical): fix nested error wrapping (#358)
Fixes: https://github.com/zkat/miette/issues/333
This commit is contained in:
parent
ca646f3119
commit
3eabbcebf1
|
|
@ -6,35 +6,9 @@ use crate::{Diagnostic, LabeledSpan, Report, SourceCode};
|
||||||
|
|
||||||
use crate as miette;
|
use crate as miette;
|
||||||
|
|
||||||
#[repr(transparent)]
|
|
||||||
pub(crate) struct DisplayError<M>(pub(crate) M);
|
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub(crate) struct MessageError<M>(pub(crate) M);
|
pub(crate) struct MessageError<M>(pub(crate) M);
|
||||||
|
|
||||||
pub(crate) struct NoneError;
|
|
||||||
|
|
||||||
impl<M> Debug for DisplayError<M>
|
|
||||||
where
|
|
||||||
M: Display,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
Display::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M> Display for DisplayError<M>
|
|
||||||
where
|
|
||||||
M: Display,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
Display::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M> StdError for DisplayError<M> where M: Display + 'static {}
|
|
||||||
impl<M> Diagnostic for DisplayError<M> where M: Display + 'static {}
|
|
||||||
|
|
||||||
impl<M> Debug for MessageError<M>
|
impl<M> Debug for MessageError<M>
|
||||||
where
|
where
|
||||||
M: Display + Debug,
|
M: Display + Debug,
|
||||||
|
|
@ -56,21 +30,6 @@ where
|
||||||
impl<M> StdError for MessageError<M> where M: Display + Debug + 'static {}
|
impl<M> StdError for MessageError<M> where M: Display + Debug + 'static {}
|
||||||
impl<M> Diagnostic for MessageError<M> where M: Display + Debug + 'static {}
|
impl<M> Diagnostic for MessageError<M> where M: Display + Debug + 'static {}
|
||||||
|
|
||||||
impl Debug for NoneError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
Debug::fmt("Option was None", f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for NoneError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
Display::fmt("Option was None", f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StdError for NoneError {}
|
|
||||||
impl Diagnostic for NoneError {}
|
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub(crate) struct BoxedError(pub(crate) Box<dyn Diagnostic + Send + Sync>);
|
pub(crate) struct BoxedError(pub(crate) Box<dyn Diagnostic + Send + Sync>);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
|
||||||
use owo_colors::{OwoColorize, Style, StyledList};
|
use owo_colors::{OwoColorize, Style, StyledList};
|
||||||
use unicode_width::UnicodeWidthChar;
|
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
|
||||||
|
|
||||||
use crate::diagnostic_chain::{DiagnosticChain, ErrorKind};
|
use crate::diagnostic_chain::{DiagnosticChain, ErrorKind};
|
||||||
use crate::handlers::theme::*;
|
use crate::handlers::theme::*;
|
||||||
|
|
@ -225,7 +225,7 @@ impl GraphicalReportHandler {
|
||||||
self.render_related(f, diagnostic, src)?;
|
self.render_related(f, diagnostic, src)?;
|
||||||
if let Some(footer) = &self.footer {
|
if let Some(footer) = &self.footer {
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
let width = self.termwidth.saturating_sub(4);
|
let width = self.termwidth.saturating_sub(2);
|
||||||
let mut opts = textwrap::Options::new(width)
|
let mut opts = textwrap::Options::new(width)
|
||||||
.initial_indent(" ")
|
.initial_indent(" ")
|
||||||
.subsequent_indent(" ")
|
.subsequent_indent(" ")
|
||||||
|
|
@ -265,7 +265,6 @@ 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() {
|
||||||
|
|
@ -273,8 +272,8 @@ 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)?;
|
|
||||||
}
|
}
|
||||||
|
writeln!(f)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -354,8 +353,12 @@ impl GraphicalReportHandler {
|
||||||
inner_renderer.footer = None;
|
inner_renderer.footer = None;
|
||||||
// Cause chains are already flattened, so don't double-print the nested error
|
// Cause chains are already flattened, so don't double-print the nested error
|
||||||
inner_renderer.with_cause_chain = false;
|
inner_renderer.with_cause_chain = false;
|
||||||
|
// Since everything from here on is indented, shrink the virtual terminal
|
||||||
|
inner_renderer.termwidth -= rest_indent.width();
|
||||||
inner_renderer.render_report(&mut inner, diag)?;
|
inner_renderer.render_report(&mut inner, diag)?;
|
||||||
|
|
||||||
|
// If there was no header, remove the leading newline
|
||||||
|
let inner = inner.trim_start_matches('\n');
|
||||||
writeln!(f, "{}", self.wrap(&inner, opts))?;
|
writeln!(f, "{}", self.wrap(&inner, opts))?;
|
||||||
}
|
}
|
||||||
ErrorKind::StdError(err) => {
|
ErrorKind::StdError(err) => {
|
||||||
|
|
@ -370,7 +373,7 @@ impl GraphicalReportHandler {
|
||||||
|
|
||||||
fn render_footer(&self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic)) -> fmt::Result {
|
fn render_footer(&self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic)) -> fmt::Result {
|
||||||
if let Some(help) = diagnostic.help() {
|
if let Some(help) = diagnostic.help() {
|
||||||
let width = self.termwidth.saturating_sub(4);
|
let width = self.termwidth.saturating_sub(2);
|
||||||
let initial_indent = " help: ".style(self.theme.styles.help).to_string();
|
let initial_indent = " help: ".style(self.theme.styles.help).to_string();
|
||||||
let mut opts = textwrap::Options::new(width)
|
let mut opts = textwrap::Options::new(width)
|
||||||
.initial_indent(&initial_indent)
|
.initial_indent(&initial_indent)
|
||||||
|
|
@ -398,8 +401,8 @@ impl GraphicalReportHandler {
|
||||||
let mut inner_renderer = self.clone();
|
let mut inner_renderer = self.clone();
|
||||||
// Re-enable the printing of nested cause chains for related errors
|
// Re-enable the printing of nested cause chains for related errors
|
||||||
inner_renderer.with_cause_chain = true;
|
inner_renderer.with_cause_chain = true;
|
||||||
writeln!(f)?;
|
|
||||||
for rel in related {
|
for rel in related {
|
||||||
|
writeln!(f)?;
|
||||||
match rel.severity() {
|
match rel.severity() {
|
||||||
Some(Severity::Error) | None => write!(f, "Error: ")?,
|
Some(Severity::Error) | None => write!(f, "Error: ")?,
|
||||||
Some(Severity::Warning) => write!(f, "Warning: ")?,
|
Some(Severity::Warning) => write!(f, "Warning: ")?,
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,14 @@ fn related() {
|
||||||
#[derive(Error, Debug, Diagnostic)]
|
#[derive(Error, Debug, Diagnostic)]
|
||||||
#[error("welp")]
|
#[error("welp")]
|
||||||
#[diagnostic(code(foo::bar::baz))]
|
#[diagnostic(code(foo::bar::baz))]
|
||||||
|
#[allow(dead_code)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
#[related]
|
#[related]
|
||||||
related: Vec<Baz>,
|
related: Vec<Baz>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug, Diagnostic)]
|
#[derive(Error, Debug, Diagnostic)]
|
||||||
|
#[allow(dead_code)]
|
||||||
enum Bar {
|
enum Bar {
|
||||||
#[error("variant1")]
|
#[error("variant1")]
|
||||||
#[diagnostic(code(foo::bar::baz))]
|
#[diagnostic(code(foo::bar::baz))]
|
||||||
|
|
@ -29,6 +31,7 @@ fn related() {
|
||||||
|
|
||||||
#[derive(Error, Debug, Diagnostic)]
|
#[derive(Error, Debug, Diagnostic)]
|
||||||
#[error("welp2")]
|
#[error("welp2")]
|
||||||
|
#[allow(dead_code)]
|
||||||
struct Baz;
|
struct Baz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,6 +40,7 @@ fn related_report() {
|
||||||
#[derive(Error, Debug, Diagnostic)]
|
#[derive(Error, Debug, Diagnostic)]
|
||||||
#[error("welp")]
|
#[error("welp")]
|
||||||
#[diagnostic(code(foo::bar::baz))]
|
#[diagnostic(code(foo::bar::baz))]
|
||||||
|
#[allow(dead_code)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
#[related]
|
#[related]
|
||||||
related: Vec<Report>,
|
related: Vec<Report>,
|
||||||
|
|
@ -288,6 +292,7 @@ fn test_snippet_named_struct() {
|
||||||
#[derive(Debug, Diagnostic, Error)]
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
#[error("welp")]
|
#[error("welp")]
|
||||||
#[diagnostic(code(foo::bar::baz))]
|
#[diagnostic(code(foo::bar::baz))]
|
||||||
|
#[allow(dead_code)]
|
||||||
struct Foo<'a> {
|
struct Foo<'a> {
|
||||||
#[source_code]
|
#[source_code]
|
||||||
src: &'a str,
|
src: &'a str,
|
||||||
|
|
@ -310,6 +315,7 @@ fn test_snippet_unnamed_struct() {
|
||||||
#[derive(Debug, Diagnostic, Error)]
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
#[error("welp")]
|
#[error("welp")]
|
||||||
#[diagnostic(code(foo::bar::baz))]
|
#[diagnostic(code(foo::bar::baz))]
|
||||||
|
#[allow(dead_code)]
|
||||||
struct Foo<'a>(
|
struct Foo<'a>(
|
||||||
#[source_code] &'a str,
|
#[source_code] &'a str,
|
||||||
#[label("{0}")] SourceSpan,
|
#[label("{0}")] SourceSpan,
|
||||||
|
|
|
||||||
|
|
@ -59,14 +59,15 @@ fn word_wrap_options() -> Result<(), MietteError> {
|
||||||
let out =
|
let out =
|
||||||
fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| handler);
|
fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| handler);
|
||||||
|
|
||||||
let expected = " × abcdefghijklmnopqrstuvwxyz\n".to_string();
|
let expected = "\n × abcdefghijklmnopqrstuvwxyz\n".to_string();
|
||||||
assert_eq!(expected, out);
|
assert_eq!(expected, out);
|
||||||
|
|
||||||
// A long word can break with a smaller width
|
// A long word can break with a smaller width
|
||||||
let out = fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| {
|
let out = fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| {
|
||||||
handler.with_width(10)
|
handler.with_width(10)
|
||||||
});
|
});
|
||||||
let expected = r#" × abcd
|
let expected = r#"
|
||||||
|
× abcd
|
||||||
│ efgh
|
│ efgh
|
||||||
│ ijkl
|
│ ijkl
|
||||||
│ mnop
|
│ mnop
|
||||||
|
|
@ -81,7 +82,7 @@ fn word_wrap_options() -> Result<(), MietteError> {
|
||||||
let out = fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| {
|
let out = fmt_report_with_settings(Report::msg("abcdefghijklmnopqrstuvwxyz"), |handler| {
|
||||||
handler.with_width(10).with_break_words(false)
|
handler.with_width(10).with_break_words(false)
|
||||||
});
|
});
|
||||||
let expected = " × abcdefghijklmnopqrstuvwxyz\n".to_string();
|
let expected = "\n × abcdefghijklmnopqrstuvwxyz\n".to_string();
|
||||||
assert_eq!(expected, out);
|
assert_eq!(expected, out);
|
||||||
|
|
||||||
// Breaks should start at the boundary of each word if possible
|
// Breaks should start at the boundary of each word if possible
|
||||||
|
|
@ -89,7 +90,8 @@ fn word_wrap_options() -> Result<(), MietteError> {
|
||||||
Report::msg("12 123 1234 12345 123456 1234567 1234567890"),
|
Report::msg("12 123 1234 12345 123456 1234567 1234567890"),
|
||||||
|handler| handler.with_width(10),
|
|handler| handler.with_width(10),
|
||||||
);
|
);
|
||||||
let expected = r#" × 12
|
let expected = r#"
|
||||||
|
× 12
|
||||||
│ 123
|
│ 123
|
||||||
│ 1234
|
│ 1234
|
||||||
│ 1234
|
│ 1234
|
||||||
|
|
@ -110,7 +112,8 @@ fn word_wrap_options() -> Result<(), MietteError> {
|
||||||
Report::msg("12 123 1234 12345 123456 1234567 1234567890"),
|
Report::msg("12 123 1234 12345 123456 1234567 1234567890"),
|
||||||
|handler| handler.with_width(10).with_break_words(false),
|
|handler| handler.with_width(10).with_break_words(false),
|
||||||
);
|
);
|
||||||
let expected = r#" × 12
|
let expected = r#"
|
||||||
|
× 12
|
||||||
│ 123
|
│ 123
|
||||||
│ 1234
|
│ 1234
|
||||||
│ 12345
|
│ 12345
|
||||||
|
|
@ -126,7 +129,8 @@ fn word_wrap_options() -> Result<(), MietteError> {
|
||||||
Report::msg("a-b a-b-c a-b-c-d a-b-c-d-e a-b-c-d-e-f a-b-c-d-e-f-g a-b-c-d-e-f-g-h"),
|
Report::msg("a-b a-b-c a-b-c-d a-b-c-d-e a-b-c-d-e-f a-b-c-d-e-f-g a-b-c-d-e-f-g-h"),
|
||||||
|handler| handler.with_width(10).with_break_words(false),
|
|handler| handler.with_width(10).with_break_words(false),
|
||||||
);
|
);
|
||||||
let expected = r#" × a-b
|
let expected = r#"
|
||||||
|
× a-b
|
||||||
│ a-b-
|
│ a-b-
|
||||||
│ c a-
|
│ c a-
|
||||||
│ b-c-
|
│ b-c-
|
||||||
|
|
@ -158,7 +162,8 @@ fn word_wrap_options() -> Result<(), MietteError> {
|
||||||
.with_word_splitter(textwrap::WordSplitter::NoHyphenation)
|
.with_word_splitter(textwrap::WordSplitter::NoHyphenation)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let expected = r#" × a-b
|
let expected = r#"
|
||||||
|
× a-b
|
||||||
│ a-b-c
|
│ a-b-c
|
||||||
│ a-b-c-d
|
│ a-b-c-d
|
||||||
│ a-b-c-d-e
|
│ a-b-c-d-e
|
||||||
|
|
@ -174,7 +179,8 @@ fn word_wrap_options() -> Result<(), MietteError> {
|
||||||
Report::msg("a/b a/b/c a/b/c/d a/b/c/d/e a/b/c/d/e/f a/b/c/d/e/f/g a/b/c/d/e/f/g/h"),
|
Report::msg("a/b a/b/c a/b/c/d a/b/c/d/e a/b/c/d/e/f a/b/c/d/e/f/g a/b/c/d/e/f/g/h"),
|
||||||
|handler| handler.with_width(10).with_break_words(false),
|
|handler| handler.with_width(10).with_break_words(false),
|
||||||
);
|
);
|
||||||
let expected = r#" × a/b
|
let expected = r#"
|
||||||
|
× a/b
|
||||||
│ a/b/
|
│ a/b/
|
||||||
│ c a/
|
│ c a/
|
||||||
│ b/c/
|
│ b/c/
|
||||||
|
|
@ -206,7 +212,8 @@ fn word_wrap_options() -> Result<(), MietteError> {
|
||||||
.with_word_separator(textwrap::WordSeparator::AsciiSpace)
|
.with_word_separator(textwrap::WordSeparator::AsciiSpace)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let expected = r#" × a/b
|
let expected = r#"
|
||||||
|
× a/b
|
||||||
│ a/b/c
|
│ a/b/c
|
||||||
│ a/b/c/d
|
│ a/b/c/d
|
||||||
│ a/b/c/d/e
|
│ a/b/c/d/e
|
||||||
|
|
@ -227,7 +234,8 @@ fn wrap_option() -> Result<(), MietteError> {
|
||||||
Report::msg("abc def ghi jkl mno pqr stu vwx yz abc def ghi jkl mno pqr stu vwx yz"),
|
Report::msg("abc def ghi jkl mno pqr stu vwx yz abc def ghi jkl mno pqr stu vwx yz"),
|
||||||
|handler| handler.with_width(15),
|
|handler| handler.with_width(15),
|
||||||
);
|
);
|
||||||
let expected = r#" × abc def
|
let expected = r#"
|
||||||
|
× abc def
|
||||||
│ ghi jkl
|
│ ghi jkl
|
||||||
│ mno pqr
|
│ mno pqr
|
||||||
│ stu vwx
|
│ stu vwx
|
||||||
|
|
@ -246,7 +254,7 @@ fn wrap_option() -> Result<(), MietteError> {
|
||||||
|handler| handler.with_width(15).with_wrap_lines(false),
|
|handler| handler.with_width(15).with_wrap_lines(false),
|
||||||
);
|
);
|
||||||
let expected =
|
let expected =
|
||||||
" × abc def ghi jkl mno pqr stu vwx yz abc def ghi jkl mno pqr stu vwx yz\n".to_string();
|
"\n × abc def ghi jkl mno pqr stu vwx yz abc def ghi jkl mno pqr stu vwx yz\n".to_string();
|
||||||
assert_eq!(expected, out);
|
assert_eq!(expected, out);
|
||||||
|
|
||||||
// Then, user-defined new lines should be preserved wrapping is disabled
|
// Then, user-defined new lines should be preserved wrapping is disabled
|
||||||
|
|
@ -254,7 +262,8 @@ fn wrap_option() -> Result<(), MietteError> {
|
||||||
Report::msg("abc def ghi jkl mno pqr stu vwx yz\nabc def ghi jkl mno pqr stu vwx yz\nabc def ghi jkl mno pqr stu vwx yz"),
|
Report::msg("abc def ghi jkl mno pqr stu vwx yz\nabc def ghi jkl mno pqr stu vwx yz\nabc def ghi jkl mno pqr stu vwx yz"),
|
||||||
|handler| handler.with_width(15).with_wrap_lines(false),
|
|handler| handler.with_width(15).with_wrap_lines(false),
|
||||||
);
|
);
|
||||||
let expected = r#" × abc def ghi jkl mno pqr stu vwx yz
|
let expected = r#"
|
||||||
|
× abc def ghi jkl mno pqr stu vwx yz
|
||||||
│ abc def ghi jkl mno pqr stu vwx yz
|
│ abc def ghi jkl mno pqr stu vwx yz
|
||||||
│ abc def ghi jkl mno pqr stu vwx yz
|
│ abc def ghi jkl mno pqr stu vwx yz
|
||||||
"#
|
"#
|
||||||
|
|
@ -264,6 +273,143 @@ fn wrap_option() -> Result<(), MietteError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wrapping_nested_errors() -> Result<(), MietteError> {
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
#[error("This is the parent error, the error withhhhh the children, kiddos, pups, as it were, and so on...")]
|
||||||
|
#[diagnostic(
|
||||||
|
code(mama::error),
|
||||||
|
help(
|
||||||
|
"try doing it better next time? I mean, you could have also done better thisssss time, but no?"
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
struct MamaError {
|
||||||
|
#[diagnostic_source]
|
||||||
|
baby: BabyError,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
#[error("Wah wah: I may be small, but I'll cause a proper bout of trouble — justt try wrapping this mess of a line, buddo!")]
|
||||||
|
#[diagnostic(
|
||||||
|
code(baby::error),
|
||||||
|
help(
|
||||||
|
"it cannot be helped... woulddddddd you really want to get rid of an error that's so cute?"
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
struct BabyError;
|
||||||
|
|
||||||
|
let err = MamaError { baby: BabyError };
|
||||||
|
let out = fmt_report_with_settings(err.into(), |handler| handler.with_width(50));
|
||||||
|
let expected = r#"mama::error
|
||||||
|
|
||||||
|
× This is the parent error, the error withhhhh
|
||||||
|
│ the children, kiddos, pups, as it were, and
|
||||||
|
│ so on...
|
||||||
|
╰─▶ baby::error
|
||||||
|
|
||||||
|
× Wah wah: I may be small, but I'll
|
||||||
|
│ cause a proper bout of trouble — justt
|
||||||
|
│ try wrapping this mess of a line,
|
||||||
|
│ buddo!
|
||||||
|
help: it cannot be helped... woulddddddd
|
||||||
|
you really want to get rid of an
|
||||||
|
error that's so cute?
|
||||||
|
|
||||||
|
help: try doing it better next time? I mean,
|
||||||
|
you could have also done better thisssss
|
||||||
|
time, but no?
|
||||||
|
"#;
|
||||||
|
assert_eq!(expected, out);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wrapping_related_errors() -> Result<(), MietteError> {
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
#[error("This is the parent error, the error withhhhh the children, kiddos, pups, as it were, and so on...")]
|
||||||
|
#[diagnostic(
|
||||||
|
code(mama::error),
|
||||||
|
help(
|
||||||
|
"try doing it better next time? I mean, you could have also done better thisssss time, but no?"
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
struct MamaError {
|
||||||
|
#[diagnostic_source]
|
||||||
|
baby: BrotherError,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
#[error("Welcome to the brother-error brotherhood — where all of the wee baby errors join into a formidable force")]
|
||||||
|
#[diagnostic(code(brother::error))]
|
||||||
|
struct BrotherError {
|
||||||
|
#[related]
|
||||||
|
brethren: Vec<Box<dyn Diagnostic + Send + Sync>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
#[error("Wah wah: I may be small, but I'll cause a proper bout of trouble — justt try wrapping this mess of a line, buddo!")]
|
||||||
|
#[diagnostic(help(
|
||||||
|
"it cannot be helped... woulddddddd you really want to get rid of an error that's so cute?"
|
||||||
|
))]
|
||||||
|
struct BabyError;
|
||||||
|
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
#[error("Wah wah: I may be small, but I'll cause a proper bout of trouble — justt try wrapping this mess of a line, buddo!")]
|
||||||
|
#[diagnostic(severity(Warning))]
|
||||||
|
struct BabyWarning;
|
||||||
|
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
#[error("Wah wah: I may be small, but I'll cause a proper bout of trouble — justt try wrapping this mess of a line, buddo!")]
|
||||||
|
#[diagnostic(severity(Advice))]
|
||||||
|
struct BabyAdvice;
|
||||||
|
|
||||||
|
let err = MamaError {
|
||||||
|
baby: BrotherError {
|
||||||
|
brethren: vec![BabyError.into(), BabyWarning.into(), BabyAdvice.into()],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let out = fmt_report_with_settings(err.into(), |handler| handler.with_width(50));
|
||||||
|
let expected = r#"mama::error
|
||||||
|
|
||||||
|
× This is the parent error, the error withhhhh
|
||||||
|
│ the children, kiddos, pups, as it were, and
|
||||||
|
│ so on...
|
||||||
|
╰─▶ brother::error
|
||||||
|
|
||||||
|
× Welcome to the brother-error
|
||||||
|
│ brotherhood — where all of the wee
|
||||||
|
│ baby errors join into a formidable
|
||||||
|
│ force
|
||||||
|
|
||||||
|
Error:
|
||||||
|
× Wah wah: I may be small, but I'll
|
||||||
|
│ cause a proper bout of trouble — justt
|
||||||
|
│ try wrapping this mess of a line,
|
||||||
|
│ buddo!
|
||||||
|
help: it cannot be helped... woulddddddd
|
||||||
|
you really want to get rid of an
|
||||||
|
error that's so cute?
|
||||||
|
|
||||||
|
Warning:
|
||||||
|
⚠ Wah wah: I may be small, but I'll
|
||||||
|
│ cause a proper bout of trouble — justt
|
||||||
|
│ try wrapping this mess of a line,
|
||||||
|
│ buddo!
|
||||||
|
|
||||||
|
Advice:
|
||||||
|
☞ Wah wah: I may be small, but I'll
|
||||||
|
│ cause a proper bout of trouble — justt
|
||||||
|
│ try wrapping this mess of a line,
|
||||||
|
│ buddo!
|
||||||
|
|
||||||
|
help: try doing it better next time? I mean,
|
||||||
|
you could have also done better thisssss
|
||||||
|
time, but no?
|
||||||
|
"#;
|
||||||
|
assert_eq!(expected, out);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_source() -> Result<(), MietteError> {
|
fn empty_source() -> Result<(), MietteError> {
|
||||||
#[derive(Debug, Diagnostic, Error)]
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
|
@ -326,7 +472,8 @@ if true {
|
||||||
let out = fmt_report(err.into());
|
let out = fmt_report(err.into());
|
||||||
println!("Error: {}", out);
|
println!("Error: {}", out);
|
||||||
|
|
||||||
let expected = r#" × oops!
|
let expected = r#"
|
||||||
|
× oops!
|
||||||
╭─[issue:1:1]
|
╭─[issue:1:1]
|
||||||
1 │ ╭─▶ if true {
|
1 │ ╭─▶ if true {
|
||||||
2 │ │ a
|
2 │ │ a
|
||||||
|
|
@ -361,7 +508,8 @@ 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#" × oops!
|
let expected = r#"
|
||||||
|
× oops!
|
||||||
╭─[issue:2:1]
|
╭─[issue:2:1]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
|
|
@ -1411,7 +1559,6 @@ Error: oops::my::bad
|
||||||
2 │ text
|
2 │ text
|
||||||
╰────
|
╰────
|
||||||
help: try doing it better next time?
|
help: try doing it better next time?
|
||||||
|
|
||||||
"#
|
"#
|
||||||
.trim_start()
|
.trim_start()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
@ -1578,6 +1725,7 @@ Error: oops::my::related::error
|
||||||
2 │ text
|
2 │ text
|
||||||
╰────
|
╰────
|
||||||
help: try doing it better next time?
|
help: try doing it better next time?
|
||||||
|
|
||||||
Warning: oops::my::related::warning
|
Warning: oops::my::related::warning
|
||||||
|
|
||||||
⚠ oops!
|
⚠ oops!
|
||||||
|
|
@ -1588,6 +1736,7 @@ Warning: oops::my::related::warning
|
||||||
2 │ text
|
2 │ text
|
||||||
╰────
|
╰────
|
||||||
help: try doing it better next time?
|
help: try doing it better next time?
|
||||||
|
|
||||||
Advice: oops::my::related::advice
|
Advice: oops::my::related::advice
|
||||||
|
|
||||||
☞ oops!
|
☞ oops!
|
||||||
|
|
@ -1623,7 +1772,8 @@ 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#" × oops!
|
let expected = r#"
|
||||||
|
× oops!
|
||||||
╭─[issue:2:1]
|
╭─[issue:2: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
|
||||||
|
|
@ -1657,7 +1807,8 @@ fn primary_label() {
|
||||||
println!("Error: {}", out);
|
println!("Error: {}", out);
|
||||||
|
|
||||||
// line 2 should be the primary, not line 1
|
// line 2 should be the primary, not line 1
|
||||||
let expected = r#" × oops!
|
let expected = r#"
|
||||||
|
× oops!
|
||||||
╭─[issue:2:2]
|
╭─[issue:2:2]
|
||||||
1 │ this is the first line
|
1 │ this is the first line
|
||||||
· ────
|
· ────
|
||||||
|
|
@ -1808,7 +1959,8 @@ fn syntax_highlighter() {
|
||||||
GraphicalReportHandler::new_themed(GraphicalTheme::unicode())
|
GraphicalReportHandler::new_themed(GraphicalTheme::unicode())
|
||||||
.render_report(&mut out, &err)
|
.render_report(&mut out, &err)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expected = r#" × This is an error
|
let expected = r#"
|
||||||
|
× This is an error
|
||||||
╭─[hello_world:2:5]
|
╭─[hello_world:2:5]
|
||||||
1 │ fn main() {
|
1 │ fn main() {
|
||||||
2 │ println!("Hello, World!");
|
2 │ println!("Hello, World!");
|
||||||
|
|
@ -1862,7 +2014,8 @@ fn syntax_highlighter_on_real_file() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let expected = format!(
|
let expected = format!(
|
||||||
r#" × This is an error
|
r#"
|
||||||
|
× This is an error
|
||||||
╭─[{filename}:{l2}:{CO}]
|
╭─[{filename}:{l2}:{CO}]
|
||||||
{l1} │
|
{l1} │
|
||||||
{l2} │ let (filename, line) = (file!(), line!() as usize);
|
{l2} │ let (filename, line) = (file!(), line!() as usize);
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,8 @@ fn test_diagnostic_source_pass_extra_info() {
|
||||||
.render_report(&mut out, &diag)
|
.render_report(&mut out, &diag)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("Error: {}", out);
|
println!("Error: {}", out);
|
||||||
let expected = r#" × TestError
|
let expected = r#"
|
||||||
|
× TestError
|
||||||
╰─▶ × A complex error happened
|
╰─▶ × A complex error happened
|
||||||
╭─[1:2]
|
╭─[1:2]
|
||||||
1 │ Hello
|
1 │ Hello
|
||||||
|
|
@ -138,7 +139,8 @@ fn test_diagnostic_source_is_output() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("{}", out);
|
println!("{}", out);
|
||||||
|
|
||||||
let expected = r#" × TestError
|
let expected = r#"
|
||||||
|
× TestError
|
||||||
╰─▶ × A complex error happened
|
╰─▶ × A complex error happened
|
||||||
╭────
|
╭────
|
||||||
1 │ right here
|
1 │ right here
|
||||||
|
|
@ -186,7 +188,8 @@ fn test_nested_diagnostic_source_is_output() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("{}", out);
|
println!("{}", out);
|
||||||
|
|
||||||
let expected = r#" × A nested error happened
|
let expected = r#"
|
||||||
|
× A nested error happened
|
||||||
├─▶ × TestError
|
├─▶ × TestError
|
||||||
│
|
│
|
||||||
╰─▶ × A complex error happened
|
╰─▶ × A complex error happened
|
||||||
|
|
@ -252,10 +255,12 @@ fn test_nested_cause_chains_for_related_errors_are_output() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("{}", out);
|
println!("{}", out);
|
||||||
|
|
||||||
let expected = r#" × A nested error happened
|
let expected = r#"
|
||||||
|
× A nested error happened
|
||||||
╰─▶ × A multi-error happened
|
╰─▶ × A multi-error happened
|
||||||
|
|
||||||
Error: × A nested error happened
|
Error:
|
||||||
|
× A nested error happened
|
||||||
├─▶ × TestError
|
├─▶ × TestError
|
||||||
│
|
│
|
||||||
╰─▶ × A complex error happened
|
╰─▶ × A complex error happened
|
||||||
|
|
@ -271,7 +276,9 @@ fn test_nested_cause_chains_for_related_errors_are_output() {
|
||||||
· ──┬─
|
· ──┬─
|
||||||
· ╰── here
|
· ╰── here
|
||||||
╰────
|
╰────
|
||||||
Error: × A complex error happened
|
|
||||||
|
Error:
|
||||||
|
× A complex error happened
|
||||||
╭────
|
╭────
|
||||||
1 │ You're actually a mess
|
1 │ You're actually a mess
|
||||||
· ──┬─
|
· ──┬─
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue