mirror of https://github.com/zkat/miette.git
feat(protocol): improvements to snippets API
This commit is contained in:
parent
80e7dabbe4
commit
3584dc600c
|
|
@ -4,7 +4,7 @@ that you can implement to get access to miette's (and related library's) full
|
||||||
reporting and such features.
|
reporting and such features.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::fmt::Display;
|
use std::{fmt::Display, sync::Arc};
|
||||||
|
|
||||||
use crate::MietteError;
|
use crate::MietteError;
|
||||||
|
|
||||||
|
|
@ -36,14 +36,16 @@ pub trait Diagnostic: std::error::Error {
|
||||||
|
|
||||||
/// Additional contextual snippets. This is typically used for adding
|
/// Additional contextual snippets. This is typically used for adding
|
||||||
/// marked-up source file output the way compilers often do.
|
/// marked-up source file output the way compilers often do.
|
||||||
fn snippets(&self) -> Option<&[DiagnosticSnippet]> {
|
fn snippets(&self) -> Option<Box<dyn Iterator<Item = DiagnosticSnippet>>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for Box<dyn Diagnostic> {}
|
impl std::error::Error for Box<dyn Diagnostic> {}
|
||||||
|
|
||||||
impl<T: Diagnostic + Send + Sync + 'static> From<T> for Box<dyn Diagnostic + Send + Sync + 'static> {
|
impl<T: Diagnostic + Send + Sync + 'static> From<T>
|
||||||
|
for Box<dyn Diagnostic + Send + Sync + 'static>
|
||||||
|
{
|
||||||
fn from(diag: T) -> Self {
|
fn from(diag: T) -> Self {
|
||||||
Box::new(diag)
|
Box::new(diag)
|
||||||
}
|
}
|
||||||
|
|
@ -112,8 +114,10 @@ support Sources which are gigabytes or larger in size.
|
||||||
*/
|
*/
|
||||||
pub trait Source: std::fmt::Debug + Send + Sync + 'static {
|
pub trait Source: std::fmt::Debug + Send + Sync + 'static {
|
||||||
/// Read the bytes for a specific span from this Source.
|
/// Read the bytes for a specific span from this Source.
|
||||||
fn read_span<'a>(&'a self, span: &SourceSpan)
|
fn read_span<'a>(
|
||||||
-> Result<Box<dyn SpanContents + 'a>, MietteError>;
|
&'a self,
|
||||||
|
span: &SourceSpan,
|
||||||
|
) -> Result<Box<dyn SpanContents + 'a>, MietteError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -166,14 +170,14 @@ impl<'a> SpanContents for MietteSpanContents<'a> {
|
||||||
/**
|
/**
|
||||||
A snippet from a [Source] to be displayed with a message and possibly some highlights.
|
A snippet from a [Source] to be displayed with a message and possibly some highlights.
|
||||||
*/
|
*/
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DiagnosticSnippet {
|
pub struct DiagnosticSnippet {
|
||||||
/// Explanation of this specific diagnostic snippet.
|
/// Explanation of this specific diagnostic snippet.
|
||||||
pub message: Option<String>,
|
pub message: Option<String>,
|
||||||
/// The "filename" for this snippet.
|
/// The "filename" for this snippet.
|
||||||
pub source_name: String,
|
pub source_name: String,
|
||||||
/// A [Source] that can be used to read the actual text of a source.
|
/// A [Source] that can be used to read the actual text of a source.
|
||||||
pub source: Box<dyn Source>,
|
pub source: Arc<dyn Source>,
|
||||||
/// The primary [SourceSpan] where this diagnostic is located.
|
/// The primary [SourceSpan] where this diagnostic is located.
|
||||||
pub context: SourceSpan,
|
pub context: SourceSpan,
|
||||||
/// Additional [SourceSpan]s that mark specific sections of the span, for
|
/// Additional [SourceSpan]s that mark specific sections of the span, for
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use std::fmt;
|
||||||
use indenter::indented;
|
use indenter::indented;
|
||||||
|
|
||||||
use crate::chain::Chain;
|
use crate::chain::Chain;
|
||||||
use crate::protocol::{Diagnostic, DiagnosticSnippet, DiagnosticReporter, Severity};
|
use crate::protocol::{Diagnostic, DiagnosticReporter, DiagnosticSnippet, Severity};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reference implementation of the [DiagnosticReporter] trait. This is generally
|
Reference implementation of the [DiagnosticReporter] trait. This is generally
|
||||||
|
|
@ -17,7 +17,11 @@ you want custom reporting for your tool or app.
|
||||||
pub struct MietteReporter;
|
pub struct MietteReporter;
|
||||||
|
|
||||||
impl MietteReporter {
|
impl MietteReporter {
|
||||||
fn render_snippet(&self, f: &mut fmt::Formatter<'_>, snippet: &DiagnosticSnippet) -> fmt::Result {
|
fn render_snippet(
|
||||||
|
&self,
|
||||||
|
f: &mut fmt::Formatter<'_>,
|
||||||
|
snippet: &DiagnosticSnippet,
|
||||||
|
) -> fmt::Result {
|
||||||
use fmt::Write as _;
|
use fmt::Write as _;
|
||||||
write!(f, "\n[{}]", snippet.source_name)?;
|
write!(f, "\n[{}]", snippet.source_name)?;
|
||||||
if let Some(msg) = &snippet.message {
|
if let Some(msg) = &snippet.message {
|
||||||
|
|
@ -126,7 +130,7 @@ impl DiagnosticReporter for MietteReporter {
|
||||||
if let Some(snippets) = diagnostic.snippets() {
|
if let Some(snippets) = diagnostic.snippets() {
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
for snippet in snippets {
|
for snippet in snippets {
|
||||||
self.render_snippet(f, snippet)?;
|
self.render_snippet(f, &snippet)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,7 +170,7 @@ impl DiagnosticReporter for JokeReporter {
|
||||||
"miette, her eyes enormous: you {} miette? you {}? oh! oh! jail for mother! jail for mother for One Thousand Years!!!!",
|
"miette, her eyes enormous: you {} miette? you {}? oh! oh! jail for mother! jail for mother for One Thousand Years!!!!",
|
||||||
diagnostic.code(),
|
diagnostic.code(),
|
||||||
diagnostic.snippets().map(|snippets| {
|
diagnostic.snippets().map(|snippets| {
|
||||||
snippets.iter().map(|snippet| snippet.message.clone()).collect::<Option<Vec<String>>>()
|
snippets.map(|snippet| snippet.message).collect::<Option<Vec<String>>>()
|
||||||
}).flatten().map(|x| x.join(", ")).unwrap_or_else(||"try and cause miette to panic".into())
|
}).flatten().map(|x| x.join(", ")).unwrap_or_else(||"try and cause miette to panic".into())
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ impl Diagnostic for MyBad {
|
||||||
Some(&"try doing it better next time?")
|
Some(&"try doing it better next time?")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn snippets(&self) -> Option<&[DiagnosticSnippet]> {
|
fn snippets(&self) -> Option<Box<dyn Iterator<Item = DiagnosticSnippet>>> {
|
||||||
Some(&self.snippets)
|
Some(Box::new(self.snippets.clone().into_iter()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,20 +48,22 @@ fn basic() -> Result<(), MietteError> {
|
||||||
#[test]
|
#[test]
|
||||||
fn fancy() -> Result<(), MietteError> {
|
fn fancy() -> Result<(), MietteError> {
|
||||||
let src = "source\n text\n here".to_string();
|
let src = "source\n text\n here".to_string();
|
||||||
|
let len = src.len();
|
||||||
let err = MyBad {
|
let err = MyBad {
|
||||||
snippets: vec![DiagnosticSnippet {
|
snippets: vec![DiagnosticSnippet {
|
||||||
message: Some("This is the part that broke".into()),
|
message: Some("This is the part that broke".into()),
|
||||||
source_name: "bad_file.rs".into(),
|
source_name: "bad_file.rs".into(),
|
||||||
source: Box::new(src.clone()),
|
source: Arc::new(src),
|
||||||
highlights: Some(vec![
|
highlights: Some(vec![(
|
||||||
("this bit here".into(), SourceSpan {
|
"this bit here".into(),
|
||||||
|
SourceSpan {
|
||||||
start: 9.into(),
|
start: 9.into(),
|
||||||
end: 12.into(),
|
end: 12.into(),
|
||||||
})
|
},
|
||||||
]),
|
)]),
|
||||||
context: SourceSpan {
|
context: SourceSpan {
|
||||||
start: 0.into(),
|
start: 0.into(),
|
||||||
end: (src.len() - 1).into(),
|
end: (len - 1).into(),
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue