mirror of https://github.com/zkat/miette.git
feat!(render): `render_report` can accept more types
You can now pass a `&dyn Diagnostic` (as before), or a `Report` (or `&Report`, `&mut Report`, or `Box<Report>`), or anything else that implements `Diagnostic` to `render_report`. More generally, users can use the `AsDiagnostic` trait wherever they want to write functions that accept either a `Report` or `Diagnostic` — this improves ergonomics in a world where `impl Diagnostic for Report` is impossible. BREAKING CHANGE: Because more types can now be passed to `render_report`, `Report::as_ref()` can get confused about types and inference fails. The solution is removing the `.as_ref()` altogether since `Report` is now a directly accepted type.
This commit is contained in:
parent
8d95934d86
commit
dc8afb8fbc
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::{protocol::Diagnostic, ReportHandler};
|
use crate::{protocol::Diagnostic, AsDiagnostic, ReportHandler};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
[`ReportHandler`] that renders plain text and avoids extraneous graphics.
|
[`ReportHandler`] that renders plain text and avoids extraneous graphics.
|
||||||
|
|
@ -31,8 +31,9 @@ impl DebugReportHandler {
|
||||||
pub fn render_report(
|
pub fn render_report(
|
||||||
&self,
|
&self,
|
||||||
f: &mut fmt::Formatter<'_>,
|
f: &mut fmt::Formatter<'_>,
|
||||||
diagnostic: &(dyn Diagnostic),
|
diagnostic: impl AsDiagnostic,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
|
let diagnostic = diagnostic.as_dyn();
|
||||||
let mut diag = f.debug_struct("Diagnostic");
|
let mut diag = f.debug_struct("Diagnostic");
|
||||||
diag.field("message", &format!("{}", diagnostic));
|
diag.field("message", &format!("{}", diagnostic));
|
||||||
if let Some(code) = diagnostic.code() {
|
if let Some(code) = diagnostic.code() {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use crate::diagnostic_chain::{DiagnosticChain, ErrorKind};
|
||||||
use crate::handlers::theme::*;
|
use crate::handlers::theme::*;
|
||||||
use crate::highlighters::{Highlighter, MietteHighlighter};
|
use crate::highlighters::{Highlighter, MietteHighlighter};
|
||||||
use crate::protocol::{Diagnostic, Severity};
|
use crate::protocol::{Diagnostic, Severity};
|
||||||
use crate::{LabeledSpan, ReportHandler, SourceCode, SourceSpan, SpanContents};
|
use crate::{AsDiagnostic, LabeledSpan, ReportHandler, SourceCode, SourceSpan, SpanContents};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A [`ReportHandler`] that displays a given [`Report`](crate::Report) in a
|
A [`ReportHandler`] that displays a given [`Report`](crate::Report) in a
|
||||||
|
|
@ -215,8 +215,9 @@ impl GraphicalReportHandler {
|
||||||
pub fn render_report(
|
pub fn render_report(
|
||||||
&self,
|
&self,
|
||||||
f: &mut impl fmt::Write,
|
f: &mut impl fmt::Write,
|
||||||
diagnostic: &(dyn Diagnostic),
|
diagnostic: impl AsDiagnostic,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
|
let diagnostic = diagnostic.as_dyn();
|
||||||
self.render_header(f, diagnostic)?;
|
self.render_header(f, diagnostic)?;
|
||||||
self.render_causes(f, diagnostic)?;
|
self.render_causes(f, diagnostic)?;
|
||||||
let src = diagnostic.source_code();
|
let src = diagnostic.source_code();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
diagnostic_chain::DiagnosticChain, protocol::Diagnostic, ReportHandler, Severity, SourceCode,
|
diagnostic_chain::DiagnosticChain, protocol::Diagnostic, AsDiagnostic, ReportHandler, Severity,
|
||||||
|
SourceCode,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -60,8 +61,9 @@ impl JSONReportHandler {
|
||||||
pub fn render_report(
|
pub fn render_report(
|
||||||
&self,
|
&self,
|
||||||
f: &mut impl fmt::Write,
|
f: &mut impl fmt::Write,
|
||||||
diagnostic: &(dyn Diagnostic),
|
diagnostic: impl AsDiagnostic,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
|
let diagnostic = diagnostic.as_dyn();
|
||||||
self._render_report(f, diagnostic, None)
|
self._render_report(f, diagnostic, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
|
||||||
|
|
||||||
use crate::diagnostic_chain::DiagnosticChain;
|
use crate::diagnostic_chain::DiagnosticChain;
|
||||||
use crate::protocol::{Diagnostic, Severity};
|
use crate::protocol::{Diagnostic, Severity};
|
||||||
use crate::{LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents};
|
use crate::{
|
||||||
|
AsDiagnostic, LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
[`ReportHandler`] that renders plain text and avoids extraneous graphics.
|
[`ReportHandler`] that renders plain text and avoids extraneous graphics.
|
||||||
|
|
@ -69,8 +71,9 @@ impl NarratableReportHandler {
|
||||||
pub fn render_report(
|
pub fn render_report(
|
||||||
&self,
|
&self,
|
||||||
f: &mut impl fmt::Write,
|
f: &mut impl fmt::Write,
|
||||||
diagnostic: &(dyn Diagnostic),
|
diagnostic: impl AsDiagnostic,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
|
let diagnostic = diagnostic.as_dyn();
|
||||||
self.render_header(f, diagnostic)?;
|
self.render_header(f, diagnostic)?;
|
||||||
if self.with_cause_chain {
|
if self.with_cause_chain {
|
||||||
self.render_causes(f, diagnostic)?;
|
self.render_causes(f, diagnostic)?;
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use std::{
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::MietteError;
|
use crate::{MietteError, Report};
|
||||||
|
|
||||||
/// Adds rich metadata to your Error that can be used by
|
/// Adds rich metadata to your Error that can be used by
|
||||||
/// [`Report`](crate::Report) to print really nice and human-friendly error
|
/// [`Report`](crate::Report) to print really nice and human-friendly error
|
||||||
|
|
@ -231,6 +231,44 @@ impl From<Box<dyn std::error::Error + Send + Sync>> for Box<dyn Diagnostic + Sen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// WOOF
|
||||||
|
pub trait AsDiagnostic {
|
||||||
|
/// BARK
|
||||||
|
fn as_dyn(&self) -> &dyn Diagnostic;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsDiagnostic for &dyn Diagnostic {
|
||||||
|
fn as_dyn(&self) -> &dyn Diagnostic {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsDiagnostic for Report {
|
||||||
|
fn as_dyn(&self) -> &dyn Diagnostic {
|
||||||
|
self.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! blanket_ref_impls {
|
||||||
|
($($ref_type:ty),+ $(,)?) => {
|
||||||
|
$(
|
||||||
|
impl AsDiagnostic for $ref_type {
|
||||||
|
fn as_dyn(&self) -> &dyn Diagnostic {
|
||||||
|
(**self).as_dyn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
blanket_ref_impls!(&Report, &mut Report, Box<Report>);
|
||||||
|
|
||||||
|
impl<T: Diagnostic> AsDiagnostic for T {
|
||||||
|
fn as_dyn(&self) -> &dyn Diagnostic {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
[`Diagnostic`] severity. Intended to be used by
|
[`Diagnostic`] severity. Intended to be used by
|
||||||
[`ReportHandler`](crate::ReportHandler)s to change the way different
|
[`ReportHandler`](crate::ReportHandler)s to change the way different
|
||||||
|
|
|
||||||
|
|
@ -13,24 +13,24 @@ fn fmt_report(diag: Report) -> String {
|
||||||
GraphicalReportHandler::new_themed(GraphicalTheme::unicode())
|
GraphicalReportHandler::new_themed(GraphicalTheme::unicode())
|
||||||
.with_width(80)
|
.with_width(80)
|
||||||
.with_footer("this is a footer".into())
|
.with_footer("this is a footer".into())
|
||||||
.render_report(&mut out, diag.as_ref())
|
.render_report(&mut out, &diag)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else if std::env::var("NARRATED").is_ok() {
|
} else if std::env::var("NARRATED").is_ok() {
|
||||||
NarratableReportHandler::new()
|
NarratableReportHandler::new()
|
||||||
.render_report(&mut out, diag.as_ref())
|
.render_report(&mut out, diag)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else if let Ok(w) = std::env::var("REPLACE_TABS") {
|
} else if let Ok(w) = std::env::var("REPLACE_TABS") {
|
||||||
GraphicalReportHandler::new_themed(GraphicalTheme::unicode_nocolor())
|
GraphicalReportHandler::new_themed(GraphicalTheme::unicode_nocolor())
|
||||||
.without_syntax_highlighting()
|
.without_syntax_highlighting()
|
||||||
.with_width(80)
|
.with_width(80)
|
||||||
.tab_width(w.parse().expect("Invalid tab width."))
|
.tab_width(w.parse().expect("Invalid tab width."))
|
||||||
.render_report(&mut out, diag.as_ref())
|
.render_report(&mut out, &diag)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
GraphicalReportHandler::new_themed(GraphicalTheme::unicode_nocolor())
|
GraphicalReportHandler::new_themed(GraphicalTheme::unicode_nocolor())
|
||||||
.without_syntax_highlighting()
|
.without_syntax_highlighting()
|
||||||
.with_width(80)
|
.with_width(80)
|
||||||
.render_report(&mut out, diag.as_ref())
|
.render_report(&mut out, &diag)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
};
|
};
|
||||||
out
|
out
|
||||||
|
|
@ -46,7 +46,7 @@ fn fmt_report_with_settings(
|
||||||
GraphicalTheme::unicode_nocolor(),
|
GraphicalTheme::unicode_nocolor(),
|
||||||
));
|
));
|
||||||
|
|
||||||
handler.render_report(&mut out, diag.as_ref()).unwrap();
|
handler.render_report(&mut out, diag).unwrap();
|
||||||
|
|
||||||
println!("Error:\n```\n{}\n```", out);
|
println!("Error:\n```\n{}\n```", out);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,11 @@ fn fmt_report(diag: Report) -> String {
|
||||||
if cfg!(feature = "fancy-no-backtrace") && std::env::var("STYLE").is_ok() {
|
if cfg!(feature = "fancy-no-backtrace") && std::env::var("STYLE").is_ok() {
|
||||||
#[cfg(feature = "fancy-no-backtrace")]
|
#[cfg(feature = "fancy-no-backtrace")]
|
||||||
GraphicalReportHandler::new_themed(GraphicalTheme::unicode())
|
GraphicalReportHandler::new_themed(GraphicalTheme::unicode())
|
||||||
.render_report(&mut out, diag.as_ref())
|
.render_report(&mut out, diag)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
NarratableReportHandler::new()
|
NarratableReportHandler::new()
|
||||||
.render_report(&mut out, diag.as_ref())
|
.render_report(&mut out, diag)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
};
|
};
|
||||||
out
|
out
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ mod json_report_handler {
|
||||||
fn fmt_report(diag: Report) -> String {
|
fn fmt_report(diag: Report) -> String {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
JSONReportHandler::new()
|
JSONReportHandler::new()
|
||||||
.render_report(&mut out, diag.as_ref())
|
.render_report(&mut out, diag)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue