mirror of https://github.com/zkat/miette.git
Add default strategy for selecting primary label. Change attribute syntax to #[label(primary)].
This commit is contained in:
parent
4c970fb4cf
commit
1905af07ef
|
|
@ -25,6 +25,7 @@ struct Label {
|
||||||
|
|
||||||
struct LabelAttr {
|
struct LabelAttr {
|
||||||
label: Option<Display>,
|
label: Option<Display>,
|
||||||
|
primary: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for LabelAttr {
|
impl Parse for LabelAttr {
|
||||||
|
|
@ -41,10 +42,22 @@ impl Parse for LabelAttr {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let la = input.lookahead1();
|
let la = input.lookahead1();
|
||||||
let label = if la.peek(syn::token::Paren) {
|
let (primary, label) = if la.peek(syn::token::Paren) {
|
||||||
// #[label("{}", x)]
|
// #[label(primary?, "{}", x)]
|
||||||
let content;
|
let content;
|
||||||
parenthesized!(content in input);
|
parenthesized!(content in input);
|
||||||
|
|
||||||
|
let primary = if content.peek(syn::Ident) {
|
||||||
|
let ident: syn::Ident = content.parse()?;
|
||||||
|
if ident != "primary" {
|
||||||
|
return Err(syn::Error::new(input.span(), "Invalid argument to label() attribute. The argument must be a literal string or the keyword `primary`."));
|
||||||
|
}
|
||||||
|
let _ = content.parse::<Token![,]>();
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
if content.peek(syn::LitStr) {
|
if content.peek(syn::LitStr) {
|
||||||
let fmt = content.parse()?;
|
let fmt = content.parse()?;
|
||||||
let args = if content.is_empty() {
|
let args = if content.is_empty() {
|
||||||
|
|
@ -57,22 +70,27 @@ impl Parse for LabelAttr {
|
||||||
args,
|
args,
|
||||||
has_bonus_display: false,
|
has_bonus_display: false,
|
||||||
};
|
};
|
||||||
Some(display)
|
(primary, Some(display))
|
||||||
|
} else if !primary {
|
||||||
|
return Err(syn::Error::new(input.span(), "Invalid argument to label() attribute. The argument must be a literal string or the keyword `primary`."));
|
||||||
} else {
|
} else {
|
||||||
return Err(syn::Error::new(input.span(), "Invalid argument to label() attribute. The first argument must be a literal string."));
|
(primary, None)
|
||||||
}
|
}
|
||||||
} else if la.peek(Token![=]) {
|
} else if la.peek(Token![=]) {
|
||||||
// #[label = "blabla"]
|
// #[label = "blabla"]
|
||||||
input.parse::<Token![=]>()?;
|
input.parse::<Token![=]>()?;
|
||||||
Some(Display {
|
(
|
||||||
fmt: input.parse()?,
|
false,
|
||||||
args: TokenStream::new(),
|
Some(Display {
|
||||||
has_bonus_display: false,
|
fmt: input.parse()?,
|
||||||
})
|
args: TokenStream::new(),
|
||||||
|
has_bonus_display: false,
|
||||||
|
}),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
(false, None)
|
||||||
};
|
};
|
||||||
Ok(LabelAttr { label })
|
Ok(LabelAttr { label, primary })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,16 +109,7 @@ impl Labels {
|
||||||
let mut labels = Vec::new();
|
let mut labels = Vec::new();
|
||||||
for (i, field) in fields.iter().enumerate() {
|
for (i, field) in fields.iter().enumerate() {
|
||||||
for attr in &field.attrs {
|
for attr in &field.attrs {
|
||||||
let is_label = attr.path().is_ident("label");
|
if attr.path().is_ident("label") {
|
||||||
let is_primary_label = attr.path().is_ident("primary_label");
|
|
||||||
if is_label || is_primary_label {
|
|
||||||
if is_primary_label && labels.iter().any(|l: &Label| l.primary) {
|
|
||||||
return Err(syn::Error::new(
|
|
||||||
field.span(),
|
|
||||||
"Cannot have more than one primary label.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let span = if let Some(ident) = field.ident.clone() {
|
let span = if let Some(ident) = field.ident.clone() {
|
||||||
syn::Member::Named(ident)
|
syn::Member::Named(ident)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -110,13 +119,21 @@ impl Labels {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
let LabelAttr { label } =
|
let LabelAttr { label, primary } =
|
||||||
syn::parse2::<LabelAttr>(attr.meta.to_token_stream())?;
|
syn::parse2::<LabelAttr>(attr.meta.to_token_stream())?;
|
||||||
|
|
||||||
|
if primary && labels.iter().any(|l: &Label| l.primary) {
|
||||||
|
return Err(syn::Error::new(
|
||||||
|
field.span(),
|
||||||
|
"Cannot have more than one primary label.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
labels.push(Label {
|
labels.push(Label {
|
||||||
label,
|
label,
|
||||||
span,
|
span,
|
||||||
ty: field.ty.clone(),
|
ty: field.ty.clone(),
|
||||||
primary: is_primary_label,
|
primary,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -391,7 +391,10 @@ impl GraphicalReportHandler {
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
let (contents, lines) = self.get_lines(source, context.inner())?;
|
let (contents, lines) = self.get_lines(source, context.inner())?;
|
||||||
|
|
||||||
let primary_label = labels.iter().find(|label| label.primary());
|
let primary_label = labels
|
||||||
|
.iter()
|
||||||
|
.find(|label| label.primary())
|
||||||
|
.or_else(|| labels.first());
|
||||||
|
|
||||||
// sorting is your friend
|
// sorting is your friend
|
||||||
let labels = labels
|
let labels = labels
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,7 @@ impl MietteDiagnostic {
|
||||||
/// ```
|
/// ```
|
||||||
pub fn and_labels(mut self, labels: impl IntoIterator<Item = LabeledSpan>) -> Self {
|
pub fn and_labels(mut self, labels: impl IntoIterator<Item = LabeledSpan>) -> Self {
|
||||||
let mut all_labels = self.labels.unwrap_or_default();
|
let mut all_labels = self.labels.unwrap_or_default();
|
||||||
all_labels.extend(labels.into_iter());
|
all_labels.extend(labels);
|
||||||
self.labels = Some(all_labels);
|
self.labels = Some(all_labels);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ fn single_line_highlight_span_full_line() {
|
||||||
println!("Error: {}", out);
|
println!("Error: {}", out);
|
||||||
|
|
||||||
let expected = r#" × oops!
|
let expected = r#" × oops!
|
||||||
╭─[issue:1:1]
|
╭─[issue:2:1]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
· ──┬─
|
· ──┬─
|
||||||
|
|
@ -120,7 +120,7 @@ fn single_line_with_wide_char() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:7]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ 👼🏼text
|
2 │ 👼🏼text
|
||||||
· ───┬──
|
· ───┬──
|
||||||
|
|
@ -159,7 +159,7 @@ fn single_line_with_two_tabs() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:3]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
· ──┬─
|
· ──┬─
|
||||||
|
|
@ -198,7 +198,7 @@ fn single_line_with_tab_in_middle() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:8]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text = text
|
2 │ text = text
|
||||||
· ──┬─
|
· ──┬─
|
||||||
|
|
@ -235,7 +235,7 @@ fn single_line_highlight() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:3]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
· ──┬─
|
· ──┬─
|
||||||
|
|
@ -270,7 +270,7 @@ fn external_source() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:3]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
· ──┬─
|
· ──┬─
|
||||||
|
|
@ -343,7 +343,7 @@ fn single_line_highlight_offset_end_of_line() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:1:7]
|
||||||
1 │ source
|
1 │ source
|
||||||
· ▲
|
· ▲
|
||||||
· ╰── this bit here
|
· ╰── this bit here
|
||||||
|
|
@ -379,7 +379,7 @@ fn single_line_highlight_include_end_of_line() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:3]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
· ──┬──
|
· ──┬──
|
||||||
|
|
@ -416,7 +416,7 @@ fn single_line_highlight_include_end_of_line_crlf() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:3]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
· ──┬──
|
· ──┬──
|
||||||
|
|
@ -453,7 +453,7 @@ fn single_line_highlight_with_empty_span() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:3]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
· ▲
|
· ▲
|
||||||
|
|
@ -490,7 +490,7 @@ fn single_line_highlight_no_label() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:3]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
· ────
|
· ────
|
||||||
|
|
@ -526,7 +526,7 @@ fn single_line_highlight_at_line_start() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:1]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
· ──┬─
|
· ──┬─
|
||||||
|
|
@ -569,7 +569,7 @@ fn multiple_same_line_highlights() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:3]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text text text text text
|
2 │ text text text text text
|
||||||
· ──┬─ ──┬─ ──┬─
|
· ──┬─ ──┬─ ──┬─
|
||||||
|
|
@ -616,7 +616,7 @@ fn multiple_same_line_highlights_with_tabs_in_middle() -> Result<(), MietteError
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:3]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text text text text text
|
2 │ text text text text text
|
||||||
· ──┬─ ──┬─ ──┬─
|
· ──┬─ ──┬─ ──┬─
|
||||||
|
|
@ -655,7 +655,7 @@ fn multiline_highlight_adjacent() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:3]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ ╭─▶ text
|
2 │ ╭─▶ text
|
||||||
3 │ ├─▶ here
|
3 │ ├─▶ here
|
||||||
|
|
@ -969,7 +969,7 @@ fn related() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:3]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
· ──┬─
|
· ──┬─
|
||||||
|
|
@ -1031,7 +1031,7 @@ fn related_source_code_propagation() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:3]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
· ──┬─
|
· ──┬─
|
||||||
|
|
@ -1136,7 +1136,7 @@ fn related_severity() -> Result<(), MietteError> {
|
||||||
let expected = r#"oops::my::bad
|
let expected = r#"oops::my::bad
|
||||||
|
|
||||||
× oops!
|
× oops!
|
||||||
╭─[bad_file.rs:1:1]
|
╭─[bad_file.rs:2:3]
|
||||||
1 │ source
|
1 │ source
|
||||||
2 │ text
|
2 │ text
|
||||||
· ──┬─
|
· ──┬─
|
||||||
|
|
@ -1201,7 +1201,7 @@ fn zero_length_eol_span() {
|
||||||
println!("Error: {}", out);
|
println!("Error: {}", out);
|
||||||
|
|
||||||
let expected = r#" × oops!
|
let expected = r#" × oops!
|
||||||
╭─[issue:1: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
|
||||||
· ▲
|
· ▲
|
||||||
|
|
@ -1220,22 +1220,27 @@ fn primary_label() {
|
||||||
struct MyBad {
|
struct MyBad {
|
||||||
#[source_code]
|
#[source_code]
|
||||||
src: NamedSource,
|
src: NamedSource,
|
||||||
#[primary_label("The root cause")]
|
#[label]
|
||||||
bad_bit: SourceSpan,
|
first_label: SourceSpan,
|
||||||
|
#[label(primary, "nope")]
|
||||||
|
second_label: SourceSpan,
|
||||||
}
|
}
|
||||||
let err = MyBad {
|
let err = MyBad {
|
||||||
src: NamedSource::new("issue", "this is the first line\nthis is the second line"),
|
src: NamedSource::new("issue", "this is the first line\nthis is the second line"),
|
||||||
bad_bit: (24, 4).into(),
|
first_label: (2, 4).into(),
|
||||||
|
second_label: (24, 4).into(),
|
||||||
};
|
};
|
||||||
let out = fmt_report(err.into());
|
let out = fmt_report(err.into());
|
||||||
println!("Error: {}", out);
|
println!("Error: {}", out);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
· ────
|
||||||
2 │ this is the second line
|
2 │ this is the second line
|
||||||
· ──┬─
|
· ──┬─
|
||||||
· ╰── The root cause
|
· ╰── nope
|
||||||
╰────
|
╰────
|
||||||
"#
|
"#
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ fn test_diagnostic_source_pass_extra_info() {
|
||||||
println!("Error: {}", out);
|
println!("Error: {}", out);
|
||||||
let expected = r#" × TestError
|
let expected = r#" × TestError
|
||||||
╰─▶ × A complex error happened
|
╰─▶ × A complex error happened
|
||||||
╭─[1:1]
|
╭─[1:2]
|
||||||
1 │ Hello
|
1 │ Hello
|
||||||
· ──┬─
|
· ──┬─
|
||||||
· ╰── here
|
· ╰── here
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue