Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 353a040

Browse files
committedApr 16, 2025··
feat: Add custom Levels
1 parent ab5ca18 commit 353a040

19 files changed

+352
-263
lines changed
 

‎benches/bench.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
1+
use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet};
22

33
#[divan::bench]
44
fn simple() -> String {
@@ -24,7 +24,7 @@ fn simple() -> String {
2424
_ => continue,
2525
}
2626
}"#;
27-
let message = Level::Error.message("mismatched types").id("E0308").group(
27+
let message = Level::ERROR.message("mismatched types").id("E0308").group(
2828
Group::new().element(
2929
Snippet::source(source)
3030
.line_start(51)
@@ -69,7 +69,7 @@ fn fold(bencher: divan::Bencher<'_, '_>, context: usize) {
6969
(input, span)
7070
})
7171
.bench_values(|(input, span)| {
72-
let message = Level::Error.message("mismatched types").id("E0308").group(
72+
let message = Level::ERROR.message("mismatched types").id("E0308").group(
7373
Group::new().element(
7474
Snippet::source(&input)
7575
.fold(true)

‎examples/custom_error.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use annotate_snippets::renderer::OutputTheme;
2-
use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
2+
use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet};
33

44
fn main() {
55
let source = r#"//@ compile-flags: -Ztreat-err-as-bug
@@ -15,8 +15,10 @@ fn main() {
1515
pub static C: u32 = 0 - 1;
1616
//~^ ERROR could not evaluate static initializer
1717
"#;
18-
let message = Level::None
19-
.message("error: internal compiler error[E0080]: could not evaluate static initializer")
18+
let message = Level::ERROR
19+
.text(Some("error: internal compiler error"))
20+
.message("could not evaluate static initializer")
21+
.id("E0080")
2022
.group(
2123
Group::new().element(
2224
Snippet::source(source)

‎examples/custom_error.svg

Lines changed: 3 additions & 2 deletions
Loading

‎examples/custom_level.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use annotate_snippets::renderer::OutputTheme;
2-
use annotate_snippets::{AnnotationKind, Group, Level, Patch, Renderer, Snippet};
2+
use annotate_snippets::{level::Level, AnnotationKind, Group, Patch, Renderer, Snippet};
33

44
fn main() {
55
let source = r#"// Regression test for issue #114529
@@ -29,7 +29,7 @@ fn main() {
2929
}
3030
}
3131
"#;
32-
let message = Level::Error
32+
let message = Level::ERROR
3333
.message("`break` with value from a `while` loop")
3434
.id("E0571")
3535
.group(
@@ -52,9 +52,11 @@ fn main() {
5252
)
5353
.group(
5454
Group::new()
55-
.element(Level::None.title(
56-
"suggestion: use `break` on its own without a value inside this `while` loop",
57-
))
55+
.element(
56+
Level::HELP
57+
.text(Some("suggestion"))
58+
.title("use `break` on its own without a value inside this `while` loop"),
59+
)
5860
.element(
5961
Snippet::source(source)
6062
.line_start(1)

‎examples/custom_level.svg

Lines changed: 2 additions & 1 deletion
Loading

‎examples/expected_type.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
1+
use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet};
22

33
fn main() {
44
let source = r#" annotations: vec![SourceAnnotation {
55
label: "expected struct `annotate_snippets::snippet::Slice`, found reference"
66
,
77
range: <22, 25>,"#;
88
let message =
9-
Level::Error.message("expected type, found `22`").group(
9+
Level::ERROR.message("expected type, found `22`").group(
1010
Group::new().element(
1111
Snippet::source(source)
1212
.line_start(26)

‎examples/footer.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
1+
use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet};
22

33
fn main() {
4-
let message = Level::Error
4+
let message = Level::ERROR
55
.message("mismatched types")
66
.id("E0308")
77
.group(
@@ -14,7 +14,7 @@ fn main() {
1414
)),
1515
),
1616
)
17-
.group(Group::new().element(Level::Note.title(
17+
.group(Group::new().element(Level::NOTE.title(
1818
"expected type: `snippet::Annotation`\n found type: `__&__snippet::Annotation`",
1919
)));
2020

‎examples/format.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
1+
use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet};
22

33
fn main() {
44
let source = r#") -> Option<String> {
@@ -23,7 +23,7 @@ fn main() {
2323
_ => continue,
2424
}
2525
}"#;
26-
let message = Level::Error.message("mismatched types").id("E0308").group(
26+
let message = Level::ERROR.message("mismatched types").id("E0308").group(
2727
Group::new().element(
2828
Snippet::source(source)
2929
.line_start(51)

‎examples/highlight_source.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
1+
use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet};
22

33
fn main() {
44
let source = r#"//@ compile-flags: -Z teach
@@ -9,7 +9,7 @@ const CON: Vec<i32> = vec![1, 2, 3]; //~ ERROR E0010
99
//~| ERROR cannot call non-const method
1010
fn main() {}
1111
"#;
12-
let message = Level::Error
12+
let message = Level::ERROR
1313
.message("allocations are not allowed in constants")
1414
.id("E0010")
1515
.group(
@@ -26,7 +26,7 @@ fn main() {}
2626
),
2727
)
2828
.element(
29-
Level::Note.title("The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created."),
29+
Level::NOTE.title("The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created."),
3030
),
3131
);
3232

‎examples/highlight_title.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
1+
use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet};
22
use anstyle::Effects;
33

44
fn main() {
@@ -43,7 +43,7 @@ fn main() {
4343
magenta.render_reset()
4444
);
4545

46-
let message = Level::Error.message("mismatched types").id("E0308").group(
46+
let message = Level::ERROR.message("mismatched types").id("E0308").group(
4747
Group::new()
4848
.element(
4949
Snippet::source(source)
@@ -60,7 +60,7 @@ fn main() {
6060
.label("arguments to this function are incorrect"),
6161
),
6262
)
63-
.element(Level::Note.title(&title)),
63+
.element(Level::NOTE.title(&title)),
6464
);
6565

6666
let renderer = Renderer::styled().anonymized_line_numbers(true);

‎examples/multislice.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use annotate_snippets::{Annotation, Group, Level, Renderer, Snippet};
1+
use annotate_snippets::{level::Level, Annotation, Group, Renderer, Snippet};
22

33
fn main() {
4-
let message = Level::Error.message("mismatched types").group(
4+
let message = Level::ERROR.message("mismatched types").group(
55
Group::new()
66
.element(
77
Snippet::<Annotation<'_>>::source("Foo")

‎src/level.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
use crate::renderer::stylesheet::Stylesheet;
2+
use crate::snippet::{ERROR_TXT, HELP_TXT, INFO_TXT, NOTE_TXT, WARNING_TXT};
3+
use crate::{Element, Group, Message, Title};
4+
use anstyle::Style;
5+
6+
pub const ERROR: Level<'_> = Level {
7+
name: None,
8+
level: LevelInner::Error,
9+
};
10+
11+
pub const WARNING: Level<'_> = Level {
12+
name: None,
13+
level: LevelInner::Warning,
14+
};
15+
16+
pub const INFO: Level<'_> = Level {
17+
name: None,
18+
level: LevelInner::Info,
19+
};
20+
21+
pub const NOTE: Level<'_> = Level {
22+
name: None,
23+
level: LevelInner::Note,
24+
};
25+
26+
pub const HELP: Level<'_> = Level {
27+
name: None,
28+
level: LevelInner::Help,
29+
};
30+
31+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
32+
pub struct Level<'a> {
33+
pub(crate) name: Option<Option<&'a str>>,
34+
pub(crate) level: LevelInner,
35+
}
36+
37+
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
38+
pub enum Level2<'a> {
39+
Builtin(LevelInner),
40+
Custom {
41+
name: Option<&'a str>,
42+
level: LevelInner,
43+
},
44+
None,
45+
}
46+
47+
impl<'a> Level<'a> {
48+
pub const ERROR: Level<'a> = ERROR;
49+
pub const WARNING: Level<'a> = WARNING;
50+
pub const INFO: Level<'a> = INFO;
51+
pub const NOTE: Level<'a> = NOTE;
52+
pub const HELP: Level<'a> = HELP;
53+
54+
/// Text passed to this function is considered "untrusted input", as such
55+
/// all text is passed through a normalization function. Pre-styled text is
56+
/// not allowed to be passed to this function.
57+
pub fn text(self, text: Option<&'a str>) -> Level<'a> {
58+
Level {
59+
name: Some(text),
60+
level: self.level,
61+
}
62+
}
63+
}
64+
65+
impl<'a> Level<'a> {
66+
/// Text passed to this function is considered "untrusted input", as such
67+
/// all text is passed through a normalization function. Pre-styled text is
68+
/// not allowed to be passed to this function.
69+
pub fn message(self, title: &'a str) -> Message<'a> {
70+
Message {
71+
id: None,
72+
groups: vec![Group::new().element(Element::Title(Title {
73+
level: self,
74+
title,
75+
primary: true,
76+
}))],
77+
}
78+
}
79+
80+
/// Text passed to this function is allowed to be pre-styled, as such all
81+
/// text is considered "trusted input" and has no normalizations applied to
82+
/// it. [`normalize_untrusted_str`](crate::normalize_untrusted_str) can be
83+
/// used to normalize untrusted text before it is passed to this function.
84+
pub fn title(self, title: &'a str) -> Title<'a> {
85+
Title {
86+
level: self,
87+
title,
88+
primary: false,
89+
}
90+
}
91+
92+
pub(crate) fn as_str(&self) -> &'a str {
93+
match (self.name, self.level) {
94+
(Some(Some(name)), _) => name,
95+
(Some(None), _) => "",
96+
(None, LevelInner::Error) => ERROR_TXT,
97+
(None, LevelInner::Warning) => WARNING_TXT,
98+
(None, LevelInner::Info) => INFO_TXT,
99+
(None, LevelInner::Note) => NOTE_TXT,
100+
(None, LevelInner::Help) => HELP_TXT,
101+
}
102+
}
103+
104+
pub(crate) fn style(&self, stylesheet: &Stylesheet) -> Style {
105+
self.level.style(stylesheet)
106+
}
107+
}
108+
109+
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
110+
pub enum LevelInner {
111+
Error,
112+
Warning,
113+
Info,
114+
Note,
115+
Help,
116+
}
117+
118+
impl LevelInner {
119+
pub(crate) fn style(self, stylesheet: &Stylesheet) -> Style {
120+
match self {
121+
LevelInner::Error => stylesheet.error,
122+
LevelInner::Warning => stylesheet.warning,
123+
LevelInner::Info => stylesheet.info,
124+
LevelInner::Note => stylesheet.note,
125+
LevelInner::Help => stylesheet.help,
126+
}
127+
}
128+
}

‎src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#![warn(clippy::print_stdout)]
4343
#![warn(missing_debug_implementations)]
4444

45+
pub mod level;
4546
pub mod renderer;
4647
mod snippet;
4748

‎src/renderer/mod.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! # Example
66
//! ```
77
//! use annotate_snippets::*;
8+
//! use annotate_snippets::level::Level;
89
//!
910
//! let source = r#"
1011
//! use baz::zed::bar;
@@ -17,7 +18,7 @@
1718
//! bar();
1819
//! }
1920
//! "#;
20-
//! Level::Error
21+
//! Level::ERROR
2122
//! .message("unresolved import `baz::zed`")
2223
//! .id("E0432")
2324
//! .group(
@@ -40,13 +41,12 @@ pub(crate) mod source_map;
4041
mod styled_buffer;
4142
pub(crate) mod stylesheet;
4243

44+
use crate::level::{Level, LevelInner};
4345
use crate::renderer::source_map::{
4446
AnnotatedLineInfo, LineInfo, Loc, SourceMap, SubstitutionHighlight,
4547
};
4648
use crate::renderer::styled_buffer::StyledBuffer;
47-
use crate::{
48-
Annotation, AnnotationKind, Element, Group, Level, Message, Origin, Patch, Snippet, Title,
49-
};
49+
use crate::{Annotation, AnnotationKind, Element, Group, Message, Origin, Patch, Snippet, Title};
5050
pub use anstyle::*;
5151
use margin::Margin;
5252
use std::borrow::Cow;
@@ -207,7 +207,7 @@ impl Renderer {
207207
};
208208
let title = message.groups.remove(0).elements.remove(0);
209209
let level = if let Element::Title(title) = &title {
210-
title.level
210+
title.level.clone()
211211
} else {
212212
panic!("Expected a title as the first element of the message")
213213
};
@@ -345,7 +345,7 @@ impl Renderer {
345345
);
346346

347347
if g == 0 && group_len > 1 {
348-
if matches!(peek, Some(Element::Title(level)) if level.level != Level::None)
348+
if matches!(peek, Some(Element::Title(level)) if level.level.name != Some(None))
349349
{
350350
self.draw_col_separator_no_space(
351351
buffer,
@@ -394,15 +394,15 @@ impl Renderer {
394394
if g == 0
395395
&& (matches!(section, Element::Origin(_))
396396
|| (matches!(section, Element::Title(_)) && i == 0)
397-
|| matches!(section, Element::Title(level) if level.level == Level::None))
397+
|| matches!(section, Element::Title(level) if level.level.name == Some(None)))
398398
{
399399
if peek.is_none() && group_len > 1 {
400400
self.draw_col_separator_end(
401401
buffer,
402402
buffer.num_lines(),
403403
max_line_num_len + 1,
404404
);
405-
} else if matches!(peek, Some(Element::Title(level)) if level.level != Level::None)
405+
} else if matches!(peek, Some(Element::Title(level)) if level.level.name != Some(None))
406406
{
407407
self.draw_col_separator_no_space(
408408
buffer,
@@ -445,7 +445,7 @@ impl Renderer {
445445
buffer.prepend(line_offset, " ", ElementStyle::NoStyle);
446446
}
447447

448-
if title.level != Level::None {
448+
if title.level.name != Some(None) {
449449
self.draw_note_separator(buffer, line_offset, max_line_num_len + 1, is_cont);
450450
buffer.append(
451451
line_offset,
@@ -476,26 +476,26 @@ impl Renderer {
476476
} else {
477477
let mut label_width = 0;
478478

479-
if title.level != Level::None {
479+
if title.level.name != Some(None) {
480480
buffer.append(
481481
line_offset,
482482
title.level.as_str(),
483-
ElementStyle::Level(title.level),
483+
ElementStyle::Level(title.level.level),
484484
);
485485
}
486486
label_width += title.level.as_str().len();
487487
if let Some(id) = id {
488-
buffer.append(line_offset, "[", ElementStyle::Level(title.level));
489-
buffer.append(line_offset, id, ElementStyle::Level(title.level));
490-
buffer.append(line_offset, "]", ElementStyle::Level(title.level));
488+
buffer.append(line_offset, "[", ElementStyle::Level(title.level.level));
489+
buffer.append(line_offset, id, ElementStyle::Level(title.level.level));
490+
buffer.append(line_offset, "]", ElementStyle::Level(title.level.level));
491491
label_width += 2 + id.len();
492492
}
493493
let header_style = if is_secondary {
494494
ElementStyle::HeaderMsg
495495
} else {
496496
ElementStyle::MainHeaderMsg
497497
};
498-
if title.level != Level::None {
498+
if title.level.name != Some(None) {
499499
buffer.append(line_offset, ": ", header_style);
500500
label_width += 2;
501501
}
@@ -647,7 +647,7 @@ impl Renderer {
647647
buffer_msg_line_offset + 1,
648648
max_line_num_len + 1,
649649
);
650-
let title = Level::Note.title(label);
650+
let title = Level::NOTE.title(label);
651651
self.render_title(buffer, &title, None, max_line_num_len, true, None, false);
652652
}
653653
}
@@ -2654,13 +2654,13 @@ pub(crate) enum ElementStyle {
26542654
LabelPrimary,
26552655
LabelSecondary,
26562656
NoStyle,
2657-
Level(Level),
2657+
Level(LevelInner),
26582658
Addition,
26592659
Removal,
26602660
}
26612661

26622662
impl ElementStyle {
2663-
fn color_spec(&self, level: Level, stylesheet: &Stylesheet) -> Style {
2663+
fn color_spec(&self, level: &Level<'_>, stylesheet: &Stylesheet) -> Style {
26642664
match self {
26652665
ElementStyle::Addition => stylesheet.addition,
26662666
ElementStyle::Removal => stylesheet.removal,

‎src/renderer/styled_buffer.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
//!
33
//! [styled_buffer]: https://github.com/rust-lang/rust/blob/894f7a4ba6554d3797404bbf550d9919df060b97/compiler/rustc_errors/src/styled_buffer.rs
44
5+
use crate::level::Level;
56
use crate::renderer::stylesheet::Stylesheet;
67
use crate::renderer::ElementStyle;
7-
use crate::Level;
88

99
use std::fmt;
1010
use std::fmt::Write;
@@ -41,14 +41,14 @@ impl StyledBuffer {
4141

4242
pub(crate) fn render(
4343
&self,
44-
level: Level,
44+
level: Level<'_>,
4545
stylesheet: &Stylesheet,
4646
) -> Result<String, fmt::Error> {
4747
let mut str = String::new();
4848
for (i, line) in self.lines.iter().enumerate() {
4949
let mut current_style = stylesheet.none;
5050
for StyledChar { ch, style } in line {
51-
let ch_style = style.color_spec(level, stylesheet);
51+
let ch_style = style.color_spec(&level, stylesheet);
5252
if ch_style != current_style {
5353
if !line.is_empty() {
5454
write!(str, "{}", current_style.render_reset())?;

‎src/snippet.rs

Lines changed: 2 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
//! Structures used as an input for the library.
22
3+
use crate::level::Level;
34
use crate::renderer::source_map::SourceMap;
4-
use crate::renderer::stylesheet::Stylesheet;
5-
use anstyle::Style;
65
use std::ops::Range;
76

87
pub(crate) const ERROR_TXT: &str = "error";
@@ -143,7 +142,7 @@ pub struct ColumnSeparator;
143142

144143
#[derive(Debug)]
145144
pub struct Title<'a> {
146-
pub(crate) level: Level,
145+
pub(crate) level: Level<'a>,
147146
pub(crate) title: &'a str,
148147
pub(crate) primary: bool,
149148
}
@@ -155,66 +154,6 @@ impl Title<'_> {
155154
}
156155
}
157156

158-
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
159-
pub enum Level {
160-
Error,
161-
Warning,
162-
Info,
163-
Note,
164-
Help,
165-
None,
166-
}
167-
168-
impl Level {
169-
/// Text passed to this function is considered "untrusted input", as such
170-
/// all text is passed through a normalization function. Pre-styled text is
171-
/// not allowed to be passed to this function.
172-
pub fn message(self, title: &str) -> Message<'_> {
173-
Message {
174-
id: None,
175-
groups: vec![Group::new().element(Element::Title(Title {
176-
level: self,
177-
title,
178-
primary: true,
179-
}))],
180-
}
181-
}
182-
183-
/// Text passed to this function is allowed to be pre-styled, as such all
184-
/// text is considered "trusted input" and has no normalizations applied to
185-
/// it. [`normalize_untrusted_str`](crate::normalize_untrusted_str) can be
186-
/// used to normalize untrusted text before it is passed to this function.
187-
pub fn title(self, title: &str) -> Title<'_> {
188-
Title {
189-
level: self,
190-
title,
191-
primary: false,
192-
}
193-
}
194-
195-
pub(crate) fn as_str(self) -> &'static str {
196-
match self {
197-
Level::Error => ERROR_TXT,
198-
Level::Warning => WARNING_TXT,
199-
Level::Info => INFO_TXT,
200-
Level::Note => NOTE_TXT,
201-
Level::Help => HELP_TXT,
202-
Level::None => "",
203-
}
204-
}
205-
206-
pub(crate) fn style(&self, stylesheet: &Stylesheet) -> Style {
207-
match self {
208-
Level::Error => stylesheet.error,
209-
Level::Warning => stylesheet.warning,
210-
Level::Info => stylesheet.info,
211-
Level::Note => stylesheet.note,
212-
Level::Help => stylesheet.help,
213-
Level::None => stylesheet.none,
214-
}
215-
}
216-
}
217-
218157
#[derive(Debug)]
219158
pub struct Snippet<'a, T> {
220159
pub(crate) origin: Option<&'a str>,

‎tests/fixtures/deserialize.rs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::ops::Range;
33

44
use annotate_snippets::renderer::DEFAULT_TERM_WIDTH;
55
use annotate_snippets::{
6-
Annotation, AnnotationKind, Element, Group, Level, Message, Patch, Renderer, Snippet,
6+
level::Level, Annotation, AnnotationKind, Element, Group, Message, Patch, Renderer, Snippet,
77
};
88

99
#[derive(Deserialize)]
@@ -15,8 +15,7 @@ pub(crate) struct Fixture {
1515

1616
#[derive(Deserialize)]
1717
pub struct MessageDef {
18-
#[serde(with = "LevelDef")]
19-
pub level: Level,
18+
pub level: LevelDef,
2019
pub title: String,
2120
#[serde(default)]
2221
pub id: Option<String>,
@@ -32,13 +31,15 @@ impl<'a> From<&'a MessageDef> for Message<'a> {
3231
id,
3332
sections,
3433
} = val;
35-
let mut message = level.message(title);
34+
let mut message = Level::from(level).message(title);
3635
if let Some(id) = id {
3736
message = message.id(id);
3837
}
3938

4039
message = message.group(Group::new().elements(sections.iter().map(|s| match s {
41-
ElementDef::Title(title) => Element::Title(title.level.title(&title.title)),
40+
ElementDef::Title(title) => {
41+
Element::Title(Level::from(&title.level).title(&title.title))
42+
}
4243
ElementDef::Cause(cause) => Element::Cause(Snippet::from(cause)),
4344
ElementDef::Suggestion(suggestion) => Element::Suggestion(Snippet::from(suggestion)),
4445
})));
@@ -57,7 +58,9 @@ pub enum ElementDef {
5758
impl<'a> From<&'a ElementDef> for Element<'a> {
5859
fn from(val: &'a ElementDef) -> Self {
5960
match val {
60-
ElementDef::Title(title) => Element::Title(title.level.title(&title.title)),
61+
ElementDef::Title(title) => {
62+
Element::Title(Level::from(&title.level).title(&title.title))
63+
}
6164
ElementDef::Cause(cause) => Element::Cause(Snippet::from(cause)),
6265
ElementDef::Suggestion(suggestion) => Element::Suggestion(Snippet::from(suggestion)),
6366
}
@@ -67,8 +70,7 @@ impl<'a> From<&'a ElementDef> for Element<'a> {
6770
#[derive(Deserialize)]
6871
pub struct TitleDef {
6972
pub title: String,
70-
#[serde(with = "LevelDef")]
71-
pub level: Level,
73+
pub level: LevelDef,
7274
}
7375

7476
#[derive(Deserialize)]
@@ -164,16 +166,27 @@ impl<'a> From<&'a PatchDef> for Patch<'a> {
164166
}
165167

166168
#[allow(dead_code)]
167-
#[derive(Deserialize)]
168-
#[serde(remote = "Level")]
169-
enum LevelDef {
169+
#[derive(Clone, Copy, Deserialize)]
170+
pub enum LevelDef {
170171
Error,
171172
Warning,
172173
Info,
173174
Note,
174175
Help,
175176
}
176177

178+
impl<'a> From<&'a LevelDef> for Level<'a> {
179+
fn from(val: &'a LevelDef) -> Self {
180+
match val {
181+
LevelDef::Error => Level::ERROR,
182+
LevelDef::Warning => Level::WARNING,
183+
LevelDef::Info => Level::INFO,
184+
LevelDef::Note => Level::NOTE,
185+
LevelDef::Help => Level::HELP,
186+
}
187+
}
188+
}
189+
177190
#[derive(Default, Deserialize)]
178191
pub struct RendererDef {
179192
#[serde(default)]

‎tests/formatter.rs

Lines changed: 97 additions & 95 deletions
Large diffs are not rendered by default.

‎tests/rustc_tests.rs

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! [parser-tests]: https://github.com/rust-lang/rust/blob/894f7a4ba6554d3797404bbf550d9919df060b97/compiler/rustc_parse/src/parser/tests.rs
44
5-
use annotate_snippets::{AnnotationKind, Group, Level, Origin, Renderer, Snippet};
5+
use annotate_snippets::{level::Level, AnnotationKind, Group, Origin, Renderer, Snippet};
66

77
use snapbox::{assert_data_eq, str};
88

@@ -12,7 +12,7 @@ fn ends_on_col0() {
1212
fn foo() {
1313
}
1414
"#;
15-
let input = Level::Error.message("foo").group(
15+
let input = Level::ERROR.message("foo").group(
1616
Group::new().element(
1717
Snippet::source(source)
1818
.line_start(1)
@@ -42,7 +42,7 @@ fn foo() {
4242
4343
}
4444
"#;
45-
let input = Level::Error.message("foo").group(
45+
let input = Level::ERROR.message("foo").group(
4646
Group::new().element(
4747
Snippet::source(source)
4848
.line_start(1)
@@ -74,7 +74,7 @@ fn foo() {
7474
X2 Y2
7575
}
7676
"#;
77-
let input = Level::Error.message("foo").group(
77+
let input = Level::ERROR.message("foo").group(
7878
Group::new().element(
7979
Snippet::source(source)
8080
.line_start(1)
@@ -117,7 +117,7 @@ fn foo() {
117117
Y1 X1
118118
}
119119
"#;
120-
let input = Level::Error.message("foo").group(
120+
let input = Level::ERROR.message("foo").group(
121121
Group::new().element(
122122
Snippet::source(source)
123123
.line_start(1)
@@ -161,7 +161,7 @@ fn foo() {
161161
X3 Y3 Z3
162162
}
163163
"#;
164-
let input = Level::Error.message("foo").group(
164+
let input = Level::ERROR.message("foo").group(
165165
Group::new().element(
166166
Snippet::source(source)
167167
.line_start(1)
@@ -205,7 +205,7 @@ fn foo() {
205205
X2 Y2 Z2
206206
}
207207
"#;
208-
let input = Level::Error.message("foo").group(
208+
let input = Level::ERROR.message("foo").group(
209209
Group::new().element(
210210
Snippet::source(source)
211211
.line_start(1)
@@ -252,7 +252,7 @@ fn foo() {
252252
X2 Y2 Z2
253253
}
254254
"#;
255-
let input = Level::Error.message("foo").group(
255+
let input = Level::ERROR.message("foo").group(
256256
Group::new().element(
257257
Snippet::source(source)
258258
.line_start(1)
@@ -300,7 +300,7 @@ fn foo() {
300300
X3 Y3 Z3
301301
}
302302
"#;
303-
let input = Level::Error.message("foo").group(
303+
let input = Level::ERROR.message("foo").group(
304304
Group::new().element(
305305
Snippet::source(source)
306306
.line_start(1)
@@ -350,7 +350,7 @@ fn foo() {
350350
X3 Y3 Z3
351351
}
352352
"#;
353-
let input = Level::Error.message("foo").group(
353+
let input = Level::ERROR.message("foo").group(
354354
Group::new().element(
355355
Snippet::source(source)
356356
.line_start(1)
@@ -394,7 +394,7 @@ fn foo() {
394394
X3 Y3 Z3
395395
}
396396
"#;
397-
let input = Level::Error.message("foo").group(
397+
let input = Level::ERROR.message("foo").group(
398398
Group::new().element(
399399
Snippet::source(source)
400400
.line_start(1)
@@ -437,7 +437,7 @@ fn foo() {
437437
a { b { c } d }
438438
}
439439
"#;
440-
let input = Level::Error.message("foo").group(
440+
let input = Level::ERROR.message("foo").group(
441441
Group::new().element(
442442
Snippet::source(source)
443443
.line_start(1)
@@ -470,7 +470,7 @@ fn foo() {
470470
a { b { c } d }
471471
}
472472
"#;
473-
let input = Level::Error.message("foo").group(
473+
let input = Level::ERROR.message("foo").group(
474474
Group::new().element(
475475
Snippet::source(source)
476476
.line_start(1)
@@ -502,7 +502,7 @@ fn foo() {
502502
a { b { c } d }
503503
}
504504
"#;
505-
let input = Level::Error.message("foo").group(
505+
let input = Level::ERROR.message("foo").group(
506506
Group::new().element(
507507
Snippet::source(source)
508508
.line_start(1)
@@ -537,7 +537,7 @@ fn foo() {
537537
a { b { c } d }
538538
}
539539
"#;
540-
let input = Level::Error.message("foo").group(
540+
let input = Level::ERROR.message("foo").group(
541541
Group::new().element(
542542
Snippet::source(source)
543543
.line_start(1)
@@ -571,7 +571,7 @@ fn foo() {
571571
a bc d
572572
}
573573
"#;
574-
let input = Level::Error.message("foo").group(
574+
let input = Level::ERROR.message("foo").group(
575575
Group::new().element(
576576
Snippet::source(source)
577577
.line_start(1)
@@ -605,7 +605,7 @@ fn foo() {
605605
a { b { c } d }
606606
}
607607
"#;
608-
let input = Level::Error.message("foo").group(
608+
let input = Level::ERROR.message("foo").group(
609609
Group::new().element(
610610
Snippet::source(source)
611611
.line_start(1)
@@ -633,7 +633,7 @@ fn foo() {
633633
a { b { c } d }
634634
}
635635
"#;
636-
let input = Level::Error.message("foo").group(
636+
let input = Level::ERROR.message("foo").group(
637637
Group::new().element(
638638
Snippet::source(source)
639639
.line_start(1)
@@ -662,7 +662,7 @@ fn foo() {
662662
a { b { c } d }
663663
}
664664
"#;
665-
let input = Level::Error.message("foo").group(
665+
let input = Level::ERROR.message("foo").group(
666666
Group::new().element(
667667
Snippet::source(source)
668668
.line_start(1)
@@ -701,7 +701,7 @@ fn foo() {
701701
a { b { c } d }
702702
}
703703
"#;
704-
let input = Level::Error.message("foo").group(
704+
let input = Level::ERROR.message("foo").group(
705705
Group::new().element(
706706
Snippet::source(source)
707707
.line_start(1)
@@ -732,7 +732,7 @@ fn foo() {
732732
a { b { c } d }
733733
}
734734
"#;
735-
let input = Level::Error.message("foo").group(
735+
let input = Level::ERROR.message("foo").group(
736736
Group::new().element(
737737
Snippet::source(source)
738738
.line_start(1)
@@ -772,7 +772,7 @@ fn foo() {
772772
X3 Y3 Z3
773773
}
774774
"#;
775-
let input = Level::Error.message("foo").group(
775+
let input = Level::ERROR.message("foo").group(
776776
Group::new().element(
777777
Snippet::source(source)
778778
.line_start(1)
@@ -832,7 +832,7 @@ fn foo() {
832832
X3 Y3 Z3
833833
}
834834
"#;
835-
let input = Level::Error.message("foo").group(
835+
let input = Level::ERROR.message("foo").group(
836836
Group::new().element(
837837
Snippet::source(source)
838838
.line_start(1)
@@ -886,7 +886,7 @@ fn issue_91334() {
886886
887887
fn f(){||yield(((){),
888888
"#;
889-
let input = Level::Error
889+
let input = Level::ERROR
890890
.message("this file contains an unclosed delimiter")
891891
.group(
892892
Group::new().element(
@@ -957,7 +957,7 @@ fn main() {
957957
}
958958
}
959959
"#;
960-
let input = Level::Error
960+
let input = Level::ERROR
961961
.message("`break` with value from a `while` loop")
962962
.id("E0571")
963963
.group(
@@ -981,7 +981,7 @@ fn main() {
981981
.group(
982982
Group::new()
983983
.element(
984-
Level::Help
984+
Level::HELP
985985
.title("use `break` on its own without a value inside this `while` loop"),
986986
)
987987
.element(
@@ -1167,7 +1167,7 @@ fn nsize() {
11671167
}
11681168
"#;
11691169
let input =
1170-
Level::Error
1170+
Level::ERROR
11711171
.message("`V0usize` cannot be safely transmuted into `[usize; 2]`")
11721172
.id("E0277")
11731173
.group(
@@ -1183,7 +1183,7 @@ fn nsize() {
11831183
)
11841184
.group(
11851185
Group::new()
1186-
.element(Level::Note.title("required by a bound in `is_transmutable`"))
1186+
.element(Level::NOTE.title("required by a bound in `is_transmutable`"))
11871187
.element(
11881188
Snippet::source(source)
11891189
.line_start(1)
@@ -1253,7 +1253,7 @@ fn main() {
12531253
assert::is_maybe_transmutable::<&'static [u8; 0], &'static [u16; 0]>(); //~ ERROR `&[u8; 0]` cannot be safely transmuted into `&[u16; 0]`
12541254
}
12551255
"#;
1256-
let input = Level::Error
1256+
let input = Level::ERROR
12571257
.message("`&[u8; 0]` cannot be safely transmuted into `&[u16; 0]`")
12581258
.id("E027s7")
12591259
.group(
@@ -1322,7 +1322,7 @@ fn g() {
13221322
}
13231323
fn main() {}
13241324
"#;
1325-
let input = Level::Error
1325+
let input = Level::ERROR
13261326
.message("expected function, found `{integer}`")
13271327
.id("E0618")
13281328
.group(
@@ -1413,7 +1413,7 @@ macro_rules! outer_macro {
14131413
14141414
outer_macro!(FirstStruct, FirstAttrStruct);
14151415
"#;
1416-
let input = Level::Warning
1416+
let input = Level::WARNING
14171417
.message("non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module")
14181418
.group(
14191419
Group::new()
@@ -1441,17 +1441,17 @@ outer_macro!(FirstStruct, FirstAttrStruct);
14411441
),
14421442
)
14431443
.element(
1444-
Level::Help
1444+
Level::HELP
14451445
.title("remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main`")
14461446
)
14471447
.element(
1448-
Level::Note
1448+
Level::NOTE
14491449
.title("a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute")
14501450
),
14511451
)
14521452
.group(
14531453
Group::new()
1454-
.element(Level::Note.title("the lint level is defined here"))
1454+
.element(Level::NOTE.title("the lint level is defined here"))
14551455
.element(
14561456
Snippet::source(source)
14571457
.line_start(1)
@@ -1546,7 +1546,7 @@ macro_rules! inline {
15461546
() => ()
15471547
}
15481548
"#;
1549-
let input = Level::Error
1549+
let input = Level::ERROR
15501550
.message("can't call method `pow` on ambiguous numeric type `{integer}`")
15511551
.id("E0689")
15521552
.group(
@@ -1560,7 +1560,7 @@ macro_rules! inline {
15601560
)
15611561
.group(
15621562
Group::new()
1563-
.element(Level::Help.title("you must specify a type for this binding, like `i32`"))
1563+
.element(Level::HELP.title("you must specify a type for this binding, like `i32`"))
15641564
.element(
15651565
Snippet::source(aux_source)
15661566
.line_start(1)
@@ -1610,7 +1610,7 @@ fn courier_to_des_moines_and_points_west(data: &[u32]) -> String {
16101610
fn main() {}
16111611
"#;
16121612

1613-
let input = Level::Error
1613+
let input = Level::ERROR
16141614
.message("type annotations needed")
16151615
.id("E0282")
16161616
.group(
@@ -1716,7 +1716,7 @@ fn nonempty<const N: usize>(arrayN_of_empty: [!; N]) {
17161716
fn main() {}
17171717
"##;
17181718

1719-
let input = Level::Error
1719+
let input = Level::ERROR
17201720
.message(
17211721
"non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered"
17221722
)
@@ -1736,7 +1736,7 @@ fn main() {}
17361736
)
17371737
.group(
17381738
Group::new()
1739-
.element(Level::Note.title("`NonEmptyEnum5` defined here"))
1739+
.element(Level::NOTE.title("`NonEmptyEnum5` defined here"))
17401740
.element(
17411741
Snippet::source(source)
17421742
.line_start(1)
@@ -1749,13 +1749,13 @@ fn main() {}
17491749
.annotation(AnnotationKind::Context.span(878..880).label("not covered"))
17501750
.annotation(AnnotationKind::Context.span(890..892).label("not covered"))
17511751
)
1752-
.element(Level::Note.title("the matched value is of type `NonEmptyEnum5`"))
1753-
.element(Level::Note.title("match arms with guards don't count towards exhaustivity"))
1752+
.element(Level::NOTE.title("the matched value is of type `NonEmptyEnum5`"))
1753+
.element(Level::NOTE.title("match arms with guards don't count towards exhaustivity"))
17541754
)
17551755
.group(
17561756
Group::new()
17571757
.element(
1758-
Level::Help
1758+
Level::HELP
17591759
.title("ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms")
17601760
)
17611761
.element(
@@ -1818,7 +1818,7 @@ fn main() {
18181818
//~^ ERROR must be specified
18191819
}
18201820
"#;
1821-
let input = Level::Error
1821+
let input = Level::ERROR
18221822
.message("the trait alias `EqAlias` is not dyn compatible")
18231823
.id("E0038")
18241824
.group(
@@ -1837,7 +1837,7 @@ fn main() {
18371837
.group(
18381838
Group::new()
18391839
.element(
1840-
Level::Note
1840+
Level::NOTE
18411841
.title("for a trait to be dyn compatible it needs to allow building a vtable\nfor more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>"))
18421842
.element(
18431843
Origin::new("$SRC_DIR/core/src/cmp.rs")

0 commit comments

Comments
 (0)
Please sign in to comment.