From 24c305668ceefca18633eca5f8c317fd3d10676f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 12 Mar 2024 14:49:02 -0500 Subject: [PATCH 1/6] refactor(render): Decouple title from Label --- src/renderer/display_list.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/renderer/display_list.rs b/src/renderer/display_list.rs index d54282fe..b75c809a 100644 --- a/src/renderer/display_list.rs +++ b/src/renderer/display_list.rs @@ -119,13 +119,7 @@ impl<'a> DisplayList<'a> { ) -> DisplayList<'a> { let mut body = vec![]; - body.push(format_title( - snippet::Label { - level, - label: title, - }, - id, - )); + body.push(format_title(level, id, title)); for (idx, snippet) in snippets.into_iter().enumerate() { body.append(&mut format_slice( @@ -740,12 +734,12 @@ fn format_label( result } -fn format_title<'a>(title: snippet::Label<'a>, id: Option<&'a str>) -> DisplayLine<'a> { +fn format_title<'a>(level: crate::Level, id: Option<&'a str>, label: &'a str) -> DisplayLine<'a> { DisplayLine::Raw(DisplayRawLine::Annotation { annotation: Annotation { - annotation_type: DisplayAnnotationType::from(title.level), + annotation_type: DisplayAnnotationType::from(level), id, - label: format_label(Some(title.label), Some(DisplayTextStyle::Emphasis)), + label: format_label(Some(label), Some(DisplayTextStyle::Emphasis)), }, source_aligned: false, continuation: false, From 568b1a30d93f9067ea20e1a61256b6484ba6b5d2 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 12 Mar 2024 14:52:28 -0500 Subject: [PATCH 2/6] refactor(render): Emphasize top-down order --- src/renderer/display_list.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/renderer/display_list.rs b/src/renderer/display_list.rs index b75c809a..2bbc2902 100644 --- a/src/renderer/display_list.rs +++ b/src/renderer/display_list.rs @@ -719,21 +719,6 @@ impl<'a> Iterator for CursorLines<'a> { } } -fn format_label( - label: Option<&str>, - style: Option, -) -> Vec> { - let mut result = vec![]; - if let Some(label) = label { - let element_style = style.unwrap_or(DisplayTextStyle::Regular); - result.push(DisplayTextFragment { - content: label, - style: element_style, - }); - } - result -} - fn format_title<'a>(level: crate::Level, id: Option<&'a str>, label: &'a str) -> DisplayLine<'a> { DisplayLine::Raw(DisplayRawLine::Annotation { annotation: Annotation { @@ -762,6 +747,21 @@ fn format_footer(footer: snippet::Label<'_>) -> Vec> { result } +fn format_label( + label: Option<&str>, + style: Option, +) -> Vec> { + let mut result = vec![]; + if let Some(label) = label { + let element_style = style.unwrap_or(DisplayTextStyle::Regular); + result.push(DisplayTextFragment { + content: label, + style: element_style, + }); + } + result +} + fn format_slice( snippet: snippet::Snippet<'_>, is_first: bool, From 20842e5afa1540fb25e3dadab643bdd69c32c47c Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 12 Mar 2024 14:53:11 -0500 Subject: [PATCH 3/6] refactor(render): Update fn name for slice -> snippet --- src/renderer/display_list.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/display_list.rs b/src/renderer/display_list.rs index 2bbc2902..5c2581c1 100644 --- a/src/renderer/display_list.rs +++ b/src/renderer/display_list.rs @@ -122,7 +122,7 @@ impl<'a> DisplayList<'a> { body.push(format_title(level, id, title)); for (idx, snippet) in snippets.into_iter().enumerate() { - body.append(&mut format_slice( + body.append(&mut format_snippet( snippet, idx == 0, !footer.is_empty(), @@ -762,7 +762,7 @@ fn format_label( result } -fn format_slice( +fn format_snippet( snippet: snippet::Snippet<'_>, is_first: bool, has_footer: bool, From 25d519a5071a2175631fef5ce10ade7f72b22192 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 12 Mar 2024 15:01:52 -0500 Subject: [PATCH 4/6] refactor(render): Pull out Message formatting --- src/renderer/display_list.rs | 55 +++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/renderer/display_list.rs b/src/renderer/display_list.rs index 5c2581c1..c3890ba8 100644 --- a/src/renderer/display_list.rs +++ b/src/renderer/display_list.rs @@ -106,33 +106,12 @@ impl<'a> DisplayList<'a> { const WARNING_TXT: &'static str = "warning"; pub(crate) fn new( - snippet::Message { - level, - id, - title, - footer, - snippets, - }: snippet::Message<'a>, + message: snippet::Message<'a>, stylesheet: &'a Stylesheet, anonymized_line_numbers: bool, margin: Option, ) -> DisplayList<'a> { - let mut body = vec![]; - - body.push(format_title(level, id, title)); - - for (idx, snippet) in snippets.into_iter().enumerate() { - body.append(&mut format_snippet( - snippet, - idx == 0, - !footer.is_empty(), - margin, - )); - } - - for annotation in footer { - body.append(&mut format_footer(annotation)); - } + let body = format_message(message, margin); Self { body, @@ -719,6 +698,36 @@ impl<'a> Iterator for CursorLines<'a> { } } +fn format_message<'a>( + snippet::Message { + level, + id, + title, + footer, + snippets, + }: snippet::Message<'a>, + margin: Option, +) -> Vec> { + let mut body = vec![]; + + body.push(format_title(level, id, title)); + + for (idx, snippet) in snippets.into_iter().enumerate() { + body.append(&mut format_snippet( + snippet, + idx == 0, + !footer.is_empty(), + margin, + )); + } + + for annotation in footer { + body.append(&mut format_footer(annotation)); + } + + body +} + fn format_title<'a>(level: crate::Level, id: Option<&'a str>, label: &'a str) -> DisplayLine<'a> { DisplayLine::Raw(DisplayRawLine::Annotation { annotation: Annotation { From ce736be5742f873a03627cad0340964e2d44c61d Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 12 Mar 2024 15:13:10 -0500 Subject: [PATCH 5/6] fix!: Generalize footer to be any `Message` Fixes #96 --- examples/footer.rs | 4 ++-- src/renderer/display_list.rs | 31 ++++++++++++++++---------- src/snippet.rs | 41 +++-------------------------------- tests/fixtures/deserialize.rs | 24 +++----------------- 4 files changed, 28 insertions(+), 72 deletions(-) diff --git a/examples/footer.rs b/examples/footer.rs index 8b4d0780..35809050 100644 --- a/examples/footer.rs +++ b/examples/footer.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{Label, Level, Renderer, Snippet}; +use annotate_snippets::{Level, Renderer, Snippet}; fn main() { let message = @@ -13,7 +13,7 @@ fn main() { "expected struct `annotate_snippets::snippet::Slice`, found reference", )), ) - .footer(Label::note( + .footer(Level::Note.title( "expected type: `snippet::Annotation`\n found type: `__&__snippet::Annotation`", )); diff --git a/src/renderer/display_list.rs b/src/renderer/display_list.rs index c3890ba8..74036360 100644 --- a/src/renderer/display_list.rs +++ b/src/renderer/display_list.rs @@ -111,7 +111,7 @@ impl<'a> DisplayList<'a> { anonymized_line_numbers: bool, margin: Option, ) -> DisplayList<'a> { - let body = format_message(message, margin); + let body = format_message(message, margin, true); Self { body, @@ -698,19 +698,24 @@ impl<'a> Iterator for CursorLines<'a> { } } -fn format_message<'a>( +fn format_message( snippet::Message { level, id, title, footer, snippets, - }: snippet::Message<'a>, + }: snippet::Message<'_>, margin: Option, -) -> Vec> { + primary: bool, +) -> Vec> { let mut body = vec![]; - body.push(format_title(level, id, title)); + if !snippets.is_empty() || primary { + body.push(format_title(level, id, title)); + } else { + body.append(&mut format_footer(level, id, title)); + } for (idx, snippet) in snippets.into_iter().enumerate() { body.append(&mut format_snippet( @@ -722,7 +727,7 @@ fn format_message<'a>( } for annotation in footer { - body.append(&mut format_footer(annotation)); + body.append(&mut format_message(annotation, margin, false)); } body @@ -740,13 +745,17 @@ fn format_title<'a>(level: crate::Level, id: Option<&'a str>, label: &'a str) -> }) } -fn format_footer(footer: snippet::Label<'_>) -> Vec> { +fn format_footer<'a>( + level: crate::Level, + id: Option<&'a str>, + label: &'a str, +) -> Vec> { let mut result = vec![]; - for (i, line) in footer.label.lines().enumerate() { + for (i, line) in label.lines().enumerate() { result.push(DisplayLine::Raw(DisplayRawLine::Annotation { annotation: Annotation { - annotation_type: DisplayAnnotationType::from(footer.level), - id: None, + annotation_type: DisplayAnnotationType::from(level), + id, label: format_label(Some(line), None), }, source_aligned: true, @@ -1447,7 +1456,7 @@ mod tests { fn test_format_label() { let input = snippet::Level::Error .title("") - .footer(snippet::Label::error("This __is__ a title")); + .footer(snippet::Level::Error.title("This __is__ a title")); let output = from_display_lines(vec![ DisplayLine::Raw(DisplayRawLine::Annotation { annotation: Annotation { diff --git a/src/snippet.rs b/src/snippet.rs index 6ba2d2d8..e7d4bef6 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -20,7 +20,7 @@ pub struct Message<'a> { pub(crate) id: Option<&'a str>, pub(crate) title: &'a str, pub(crate) snippets: Vec>, - pub(crate) footer: Vec>, + pub(crate) footer: Vec>, } impl<'a> Message<'a> { @@ -39,52 +39,17 @@ impl<'a> Message<'a> { self } - pub fn footer(mut self, footer: Label<'a>) -> Self { + pub fn footer(mut self, footer: Message<'a>) -> Self { self.footer.push(footer); self } - pub fn footers(mut self, footer: impl IntoIterator>) -> Self { + pub fn footers(mut self, footer: impl IntoIterator>) -> Self { self.footer.extend(footer); self } } -pub struct Label<'a> { - pub(crate) level: Level, - pub(crate) label: &'a str, -} - -impl<'a> Label<'a> { - pub fn new(level: Level, label: &'a str) -> Self { - Self { level, label } - } - pub fn error(label: &'a str) -> Self { - Self::new(Level::Error, label) - } - - pub fn warning(label: &'a str) -> Self { - Self::new(Level::Warning, label) - } - - pub fn info(label: &'a str) -> Self { - Self::new(Level::Info, label) - } - - pub fn note(label: &'a str) -> Self { - Self::new(Level::Note, label) - } - - pub fn help(label: &'a str) -> Self { - Self::new(Level::Help, label) - } - - pub fn label(mut self, label: &'a str) -> Self { - self.label = label; - self - } -} - /// Structure containing the slice of text to be annotated and /// basic information about the location of the slice. /// diff --git a/tests/fixtures/deserialize.rs b/tests/fixtures/deserialize.rs index 6bfe76f9..165c3418 100644 --- a/tests/fixtures/deserialize.rs +++ b/tests/fixtures/deserialize.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Deserializer, Serialize}; use std::ops::Range; -use annotate_snippets::{renderer::Margin, Annotation, Label, Level, Message, Renderer, Snippet}; +use annotate_snippets::{renderer::Margin, Annotation, Level, Message, Renderer, Snippet}; #[derive(Deserialize)] pub struct Fixture<'a> { @@ -20,10 +20,9 @@ pub struct MessageDef<'a> { #[serde(default)] #[serde(borrow)] pub id: Option<&'a str>, - #[serde(deserialize_with = "deserialize_labels")] #[serde(default)] #[serde(borrow)] - pub footer: Vec>, + pub footer: Vec>, #[serde(deserialize_with = "deserialize_snippets")] #[serde(borrow)] pub snippets: Vec>, @@ -43,28 +42,11 @@ impl<'a> From> for Message<'a> { message = message.id(id); } message = message.snippets(snippets); - message = message.footers(footer); + message = message.footers(footer.into_iter().map(Into::into)); message } } -fn deserialize_labels<'de, D>(deserializer: D) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - #[derive(Deserialize)] - struct Wrapper<'a>( - #[serde(with = "LabelDef")] - #[serde(borrow)] - LabelDef<'a>, - ); - - let v = Vec::deserialize(deserializer)?; - Ok(v.into_iter() - .map(|Wrapper(a)| Label::new(a.level, a.label)) - .collect()) -} - fn deserialize_snippets<'de, D>(deserializer: D) -> Result>, D::Error> where D: Deserializer<'de>, From 535e146651e68f183682083cca6bb58c37e8b481 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 12 Mar 2024 15:16:05 -0500 Subject: [PATCH 6/6] refactor(render): Prefer 'extend' over 'append' --- src/renderer/display_list.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/renderer/display_list.rs b/src/renderer/display_list.rs index 74036360..d0444a31 100644 --- a/src/renderer/display_list.rs +++ b/src/renderer/display_list.rs @@ -714,11 +714,11 @@ fn format_message( if !snippets.is_empty() || primary { body.push(format_title(level, id, title)); } else { - body.append(&mut format_footer(level, id, title)); + body.extend(format_footer(level, id, title)); } for (idx, snippet) in snippets.into_iter().enumerate() { - body.append(&mut format_snippet( + body.extend(format_snippet( snippet, idx == 0, !footer.is_empty(), @@ -727,7 +727,7 @@ fn format_message( } for annotation in footer { - body.append(&mut format_message(annotation, margin, false)); + body.extend(format_message(annotation, margin, false)); } body @@ -789,14 +789,14 @@ fn format_snippet( let main_range = snippet.annotations.first().map(|x| x.range.start); let origin = snippet.origin; let need_empty_header = origin.is_some() || is_first; - let mut body = format_body(snippet, need_empty_header, has_footer, margin); + let body = format_body(snippet, need_empty_header, has_footer, margin); let header = format_header(origin, main_range, &body, is_first); let mut result = vec![]; if let Some(header) = header { result.push(header); } - result.append(&mut body); + result.extend(body); result }