Skip to content

Commit 74c2517

Browse files
authored
Merge pull request #235 from Muscraft/group-primary-level
feat: Allow setting the primary level for a group
2 parents 08e68a3 + 5f0b425 commit 74c2517

File tree

5 files changed

+106
-12
lines changed

5 files changed

+106
-12
lines changed

examples/elide_header.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet};
2+
3+
fn main() {
4+
let source = r#"# Docstring followed by a newline
5+
6+
def foobar(door, bar={}):
7+
"""
8+
"""
9+
"#;
10+
11+
let message = &[Group::new()
12+
.primary_level(Level::NOTE)
13+
.element(
14+
Snippet::source(source)
15+
.fold(false)
16+
.annotation(AnnotationKind::Primary.span(56..58).label("B006")),
17+
)
18+
.element(Level::HELP.title("Replace with `None`; initialize within function"))];
19+
20+
let renderer = Renderer::styled();
21+
anstream::println!("{}", renderer.render(message));
22+
}

examples/elide_header.svg

Lines changed: 44 additions & 0 deletions
Loading

src/renderer/mod.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -275,14 +275,16 @@ impl Renderer {
275275
if og_primary_path.is_none() && primary_path.is_some() {
276276
og_primary_path = primary_path;
277277
}
278-
let level = group
279-
.elements
280-
.iter()
281-
.find_map(|s| match &s {
282-
Element::Title(title) => Some(title.level.clone()),
283-
_ => None,
284-
})
285-
.unwrap_or(Level::ERROR);
278+
let level = group.primary_level.clone().unwrap_or_else(|| {
279+
group
280+
.elements
281+
.first()
282+
.and_then(|s| match &s {
283+
Element::Title(title) => Some(title.level.clone()),
284+
_ => None,
285+
})
286+
.unwrap_or(Level::ERROR)
287+
});
286288
let mut source_map_annotated_lines = VecDeque::new();
287289
let mut max_depth = 0;
288290
for e in &group.elements {

src/snippet.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub(crate) struct Id<'a> {
2020
/// An [`Element`] container
2121
#[derive(Clone, Debug)]
2222
pub struct Group<'a> {
23+
pub(crate) primary_level: Option<Level<'a>>,
2324
pub(crate) elements: Vec<Element<'a>>,
2425
}
2526

@@ -31,7 +32,10 @@ impl Default for Group<'_> {
3132

3233
impl<'a> Group<'a> {
3334
pub fn new() -> Self {
34-
Self { elements: vec![] }
35+
Self {
36+
primary_level: None,
37+
elements: vec![],
38+
}
3539
}
3640

3741
pub fn element(mut self, section: impl Into<Element<'a>>) -> Self {
@@ -44,6 +48,15 @@ impl<'a> Group<'a> {
4448
self
4549
}
4650

51+
/// Set the primary [`Level`] for this [`Group`].
52+
///
53+
/// If not specified, use the [`Level`] of the first element in a [`Group`]
54+
/// if it is a [`Title`]. If not it will default to [`Level::ERROR`].
55+
pub fn primary_level(mut self, level: Level<'a>) -> Self {
56+
self.primary_level = Some(level);
57+
self
58+
}
59+
4760
pub fn is_empty(&self) -> bool {
4861
self.elements.is_empty()
4962
}
@@ -262,10 +275,16 @@ impl<'a> Annotation<'a> {
262275
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
263276
#[non_exhaustive]
264277
pub enum AnnotationKind {
265-
/// Color to the [`Level`] the first [`Title`] in [`Group`]. If no [`Title`]
266-
/// is present, it will default to `error`.
278+
/// Match the primary [`Level`] of the group.
279+
///
280+
/// See [`Group::primary_level`] for details about how this is determined
267281
Primary,
268-
/// "secondary"; fixed color
282+
/// Additional context to explain the [`Primary`][Self::Primary]
283+
/// [`Annotation`]
284+
///
285+
/// See also [`Renderer::context`].
286+
///
287+
/// [`Renderer::context`]: crate::renderer::Renderer
269288
Context,
270289
}
271290

tests/examples.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ fn custom_level() {
1414
assert_example(target, expected);
1515
}
1616

17+
#[test]
18+
fn elide_header() {
19+
let target = "elide_header";
20+
let expected = snapbox::file!["../examples/elide_header.svg": TermSvg];
21+
assert_example(target, expected);
22+
}
23+
1724
#[test]
1825
fn expected_type() {
1926
let target = "expected_type";

0 commit comments

Comments
 (0)