feat(protocol): improvements to snippets API

This commit is contained in:
Kat Marchán 2021-08-07 22:59:20 -04:00
parent 80e7dabbe4
commit 3584dc600c
No known key found for this signature in database
GPG Key ID: AEB529C08A3C7E9E
3 changed files with 29 additions and 19 deletions

View File

@ -4,7 +4,7 @@ that you can implement to get access to miette's (and related library's) full
reporting and such features.
*/
use std::fmt::Display;
use std::{fmt::Display, sync::Arc};
use crate::MietteError;
@ -36,14 +36,16 @@ pub trait Diagnostic: std::error::Error {
/// Additional contextual snippets. This is typically used for adding
/// 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
}
}
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 {
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 {
/// Read the bytes for a specific span from this Source.
fn read_span<'a>(&'a self, span: &SourceSpan)
-> Result<Box<dyn SpanContents + 'a>, MietteError>;
fn read_span<'a>(
&'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.
*/
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct DiagnosticSnippet {
/// Explanation of this specific diagnostic snippet.
pub message: Option<String>,
/// The "filename" for this snippet.
pub source_name: String,
/// 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.
pub context: SourceSpan,
/// Additional [SourceSpan]s that mark specific sections of the span, for

View File

@ -7,7 +7,7 @@ use std::fmt;
use indenter::indented;
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
@ -17,7 +17,11 @@ you want custom reporting for your tool or app.
pub struct 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 _;
write!(f, "\n[{}]", snippet.source_name)?;
if let Some(msg) = &snippet.message {
@ -126,7 +130,7 @@ impl DiagnosticReporter for MietteReporter {
if let Some(snippets) = diagnostic.snippets() {
writeln!(f)?;
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!!!!",
diagnostic.code(),
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())
)?;

View File

@ -27,8 +27,8 @@ impl Diagnostic for MyBad {
Some(&"try doing it better next time?")
}
fn snippets(&self) -> Option<&[DiagnosticSnippet]> {
Some(&self.snippets)
fn snippets(&self) -> Option<Box<dyn Iterator<Item = DiagnosticSnippet>>> {
Some(Box::new(self.snippets.clone().into_iter()))
}
}
@ -48,20 +48,22 @@ fn basic() -> Result<(), MietteError> {
#[test]
fn fancy() -> Result<(), MietteError> {
let src = "source\n text\n here".to_string();
let len = src.len();
let err = MyBad {
snippets: vec![DiagnosticSnippet {
message: Some("This is the part that broke".into()),
source_name: "bad_file.rs".into(),
source: Box::new(src.clone()),
highlights: Some(vec![
("this bit here".into(), SourceSpan {
source: Arc::new(src),
highlights: Some(vec![(
"this bit here".into(),
SourceSpan {
start: 9.into(),
end: 12.into(),
})
]),
},
)]),
context: SourceSpan {
start: 0.into(),
end: (src.len() - 1).into(),
end: (len - 1).into(),
},
}],
};