mirror of https://github.com/zkat/miette.git
feat(collection): allow LabeledSpan in label collections
To allow customization of the text for each label in a collection, add support for using LabeledSpan in collections instead of just regular spans
This commit is contained in:
parent
6d01ca1c2d
commit
7a54a9f1c8
26
README.md
26
README.md
|
|
@ -697,6 +697,32 @@ let report: miette::Report = MyError {
|
||||||
println!("{:?}", report.with_source_code("About something or another or yet another ...".to_string()));
|
println!("{:?}", report.with_source_code("About something or another or yet another ...".to_string()));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
A collection can also be of `LabeledSpan` if you want to have different text
|
||||||
|
for different labels. Labels with no text will use the one from the `label`
|
||||||
|
attribute
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
#[error("oops!")]
|
||||||
|
struct MyError {
|
||||||
|
#[label("main issue")]
|
||||||
|
primary_span: SourceSpan,
|
||||||
|
|
||||||
|
#[label(collection, "related to this")]
|
||||||
|
other_spans: Vec<LabeledSpan>, // LabeledSpan
|
||||||
|
}
|
||||||
|
|
||||||
|
let report: miette::Report = MyError {
|
||||||
|
primary_span: (6, 9).into(),
|
||||||
|
other_spans: vec![
|
||||||
|
LabeledSpan::new(None, 19, 7), // Use default text `related to this`
|
||||||
|
LabeledSpan::new(Some("and also this".to_string()), 30, 11), // Use specific text
|
||||||
|
],
|
||||||
|
}.into();
|
||||||
|
|
||||||
|
println!("{:?}", report.with_source_code("About something or another or yet another ...".to_string()));
|
||||||
|
```
|
||||||
|
|
||||||
### MSRV
|
### MSRV
|
||||||
|
|
||||||
This crate requires rustc 1.70.0 or later.
|
This crate requires rustc 1.70.0 or later.
|
||||||
|
|
|
||||||
|
|
@ -212,15 +212,17 @@ impl Labels {
|
||||||
};
|
};
|
||||||
Some(quote! {
|
Some(quote! {
|
||||||
let display = #display;
|
let display = #display;
|
||||||
#labels_gen_var.extend(
|
#labels_gen_var.extend(self.#span.iter().map(|label| {
|
||||||
self.#span.iter().map(|label| {
|
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(label)
|
||||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(label)
|
.map(|span| {
|
||||||
.map(|span| miette::LabeledSpan::new_with_span(
|
use miette::macro_helpers::{ToLabelSpanWrapper,ToLabeledSpan};
|
||||||
#display,
|
let mut labeled_span = ToLabelSpanWrapper::to_labeled_span(span.clone());
|
||||||
span.clone(),
|
if #display.is_some() && labeled_span.label().is_none() {
|
||||||
))
|
labeled_span.set_label(#display)
|
||||||
})
|
}
|
||||||
);
|
labeled_span
|
||||||
|
})
|
||||||
|
}));
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -299,15 +301,17 @@ impl Labels {
|
||||||
};
|
};
|
||||||
Some(quote! {
|
Some(quote! {
|
||||||
let display = #display;
|
let display = #display;
|
||||||
#labels_gen_var.extend(
|
#labels_gen_var.extend(#field.iter().map(|label| {
|
||||||
#field.iter().map(|label| {
|
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(label)
|
||||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(label)
|
.map(|span| {
|
||||||
.map(|span| miette::LabeledSpan::new_with_span(
|
use miette::macro_helpers::{ToLabelSpanWrapper,ToLabeledSpan};
|
||||||
#display,
|
let mut labeled_span = ToLabelSpanWrapper::to_labeled_span(span.clone());
|
||||||
span.clone(),
|
if #display.is_some() && labeled_span.label().is_none() {
|
||||||
))
|
labeled_span.set_label(#display)
|
||||||
})
|
}
|
||||||
);
|
labeled_span
|
||||||
|
})
|
||||||
|
}));
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
let variant_name = ident.clone();
|
let variant_name = ident.clone();
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::protocol::{LabeledSpan, SourceSpan};
|
||||||
|
|
||||||
// Huge thanks to @jam1gamer for this hack:
|
// Huge thanks to @jam1gamer for this hack:
|
||||||
// https://twitter.com/jam1garner/status/1515887996444323840
|
// https://twitter.com/jam1garner/status/1515887996444323840
|
||||||
|
|
||||||
|
|
@ -36,3 +38,24 @@ impl<T> ToOption for &OptionalWrapper<T> {
|
||||||
Some(value)
|
Some(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ToLabelSpanWrapper {}
|
||||||
|
pub trait ToLabeledSpan<T> {
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn to_labeled_span(span: T) -> LabeledSpan;
|
||||||
|
}
|
||||||
|
impl ToLabeledSpan<LabeledSpan> for ToLabelSpanWrapper {
|
||||||
|
fn to_labeled_span(span: LabeledSpan) -> LabeledSpan {
|
||||||
|
span
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> ToLabeledSpan<T> for ToLabelSpanWrapper
|
||||||
|
where
|
||||||
|
T: Into<SourceSpan>,
|
||||||
|
{
|
||||||
|
fn to_labeled_span(span: T) -> LabeledSpan {
|
||||||
|
LabeledSpan::new_with_span(None, span.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -293,6 +293,11 @@ impl LabeledSpan {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change the text of the label
|
||||||
|
pub fn set_label(&mut self, label: Option<String>) {
|
||||||
|
self.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
/// Makes a new label at specified span
|
/// Makes a new label at specified span
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,76 @@ fn attr_collection_of_range() {
|
||||||
assert_eq!(err_span, expectation);
|
assert_eq!(err_span, expectation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn attr_collection_of_labeled_span_in_struct() {
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
#[error("oops!")]
|
||||||
|
struct MyBad {
|
||||||
|
#[source_code]
|
||||||
|
src: NamedSource<String>,
|
||||||
|
#[label("this bit here")]
|
||||||
|
highlight: SourceSpan,
|
||||||
|
#[label(collection, "then there")]
|
||||||
|
highlight2: Vec<LabeledSpan>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let src = "source\n text\n here".to_string();
|
||||||
|
let err = MyBad {
|
||||||
|
src: NamedSource::new("bad_file.rs", src),
|
||||||
|
highlight: (9, 4).into(),
|
||||||
|
highlight2: vec![
|
||||||
|
LabeledSpan::new_with_span(Some("continuing here".to_string()), (1, 2)),
|
||||||
|
LabeledSpan::new_with_span(None, (3, 4)),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
let mut label_iter = err.labels().unwrap();
|
||||||
|
let err_span = label_iter.next().unwrap();
|
||||||
|
let expectation = LabeledSpan::new(Some("this bit here".into()), 9usize, 4usize);
|
||||||
|
assert_eq!(err_span, expectation);
|
||||||
|
let err_span = label_iter.next().unwrap();
|
||||||
|
let expectation = LabeledSpan::new(Some("continuing here".into()), 1usize, 2usize);
|
||||||
|
assert_eq!(err_span, expectation);
|
||||||
|
let err_span = label_iter.next().unwrap();
|
||||||
|
let expectation = LabeledSpan::new(Some("then there".into()), 3usize, 4usize);
|
||||||
|
assert_eq!(err_span, expectation);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn attr_collection_of_labeled_span_in_enum() {
|
||||||
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
#[error("oops!")]
|
||||||
|
enum MyBad {
|
||||||
|
Only {
|
||||||
|
#[source_code]
|
||||||
|
src: NamedSource<String>,
|
||||||
|
#[label("this bit here")]
|
||||||
|
highlight: SourceSpan,
|
||||||
|
#[label(collection, "then there")]
|
||||||
|
highlight2: Vec<LabeledSpan>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
let src = "source\n text\n here".to_string();
|
||||||
|
let err = MyBad::Only {
|
||||||
|
src: NamedSource::new("bad_file.rs", src),
|
||||||
|
highlight: (9, 4).into(),
|
||||||
|
highlight2: vec![
|
||||||
|
LabeledSpan::new_with_span(Some("continuing here".to_string()), (1, 2)),
|
||||||
|
LabeledSpan::new_with_span(None, (3, 4)),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
let mut label_iter = err.labels().unwrap();
|
||||||
|
let err_span = label_iter.next().unwrap();
|
||||||
|
let expectation = LabeledSpan::new(Some("this bit here".into()), 9usize, 4usize);
|
||||||
|
assert_eq!(err_span, expectation);
|
||||||
|
let err_span = label_iter.next().unwrap();
|
||||||
|
let expectation = LabeledSpan::new(Some("continuing here".into()), 1usize, 2usize);
|
||||||
|
assert_eq!(err_span, expectation);
|
||||||
|
let err_span = label_iter.next().unwrap();
|
||||||
|
let expectation = LabeledSpan::new(Some("then there".into()), 3usize, 4usize);
|
||||||
|
assert_eq!(err_span, expectation);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn attr_collection_multi() {
|
fn attr_collection_multi() {
|
||||||
#[derive(Debug, Diagnostic, Error)]
|
#[derive(Debug, Diagnostic, Error)]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue