From 9076cbf66336e5137b47dc7a52df2999b6c82598 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sun, 12 Nov 2023 12:44:16 -0700 Subject: [PATCH 01/12] feat: Add `Renderer` --- benches/simple.rs | 7 ++++--- examples/expected_type.rs | 7 ++++--- examples/footer.rs | 7 ++++--- examples/format.rs | 7 ++++--- examples/multislice.rs | 7 ++++--- src/lib.rs | 1 + src/renderer/mod.rs | 11 +++++++++++ tests/fixtures_test.rs | 7 ++++--- tests/formatter.rs | 16 +++++++++++----- 9 files changed, 47 insertions(+), 23 deletions(-) create mode 100644 src/renderer/mod.rs diff --git a/benches/simple.rs b/benches/simple.rs index 4c13a8f0..4427afde 100644 --- a/benches/simple.rs +++ b/benches/simple.rs @@ -4,8 +4,9 @@ extern crate criterion; use criterion::{black_box, Criterion}; +use annotate_snippets::renderer::Renderer; use annotate_snippets::{ - display_list::{DisplayList, FormatOptions}, + display_list::FormatOptions, snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, }; @@ -62,8 +63,8 @@ fn create_snippet() { }, }; - let dl = DisplayList::from(snippet); - let _result = dl.to_string(); + let renderer = Renderer; + let _result = renderer.render(snippet).to_string(); } pub fn criterion_benchmark(c: &mut Criterion) { diff --git a/examples/expected_type.rs b/examples/expected_type.rs index 6f2a0d9a..cd23bfcf 100644 --- a/examples/expected_type.rs +++ b/examples/expected_type.rs @@ -1,5 +1,6 @@ +use annotate_snippets::renderer::Renderer; use annotate_snippets::{ - display_list::{DisplayList, FormatOptions}, + display_list::FormatOptions, snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, }; @@ -38,6 +39,6 @@ fn main() { }, }; - let dl = DisplayList::from(snippet); - println!("{}", dl); + let renderer = Renderer; + println!("{}", renderer.render(snippet)); } diff --git a/examples/footer.rs b/examples/footer.rs index f3c15c41..6bf6f5ed 100644 --- a/examples/footer.rs +++ b/examples/footer.rs @@ -1,5 +1,6 @@ +use annotate_snippets::renderer::Renderer; use annotate_snippets::{ - display_list::{DisplayList, FormatOptions}, + display_list::FormatOptions, snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, }; @@ -34,6 +35,6 @@ fn main() { }, }; - let dl = DisplayList::from(snippet); - println!("{}", dl); + let renderer = Renderer; + println!("{}", renderer.render(snippet)); } diff --git a/examples/format.rs b/examples/format.rs index 98b77a14..a053ccc2 100644 --- a/examples/format.rs +++ b/examples/format.rs @@ -1,5 +1,6 @@ +use annotate_snippets::renderer::Renderer; use annotate_snippets::{ - display_list::{DisplayList, FormatOptions}, + display_list::FormatOptions, snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, }; @@ -56,6 +57,6 @@ fn main() { }, }; - let dl = DisplayList::from(snippet); - println!("{}", dl); + let renderer = Renderer; + println!("{}", renderer.render(snippet)); } diff --git a/examples/multislice.rs b/examples/multislice.rs index 5675a07d..a875ae26 100644 --- a/examples/multislice.rs +++ b/examples/multislice.rs @@ -1,5 +1,6 @@ +use annotate_snippets::renderer::Renderer; use annotate_snippets::{ - display_list::{DisplayList, FormatOptions}, + display_list::FormatOptions, snippet::{Annotation, AnnotationType, Slice, Snippet}, }; @@ -33,6 +34,6 @@ fn main() { }, }; - let dl = DisplayList::from(snippet); - println!("{}", dl); + let renderer = Renderer; + println!("{}", renderer.render(snippet)); } diff --git a/src/lib.rs b/src/lib.rs index d5813672..e11e9d58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,5 +50,6 @@ pub mod display_list; pub mod formatter; +pub mod renderer; pub mod snippet; pub mod stylesheets; diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs new file mode 100644 index 00000000..9a66c1c2 --- /dev/null +++ b/src/renderer/mod.rs @@ -0,0 +1,11 @@ +use crate::display_list::DisplayList; +use crate::snippet::Snippet; +use std::fmt::Display; + +pub struct Renderer; + +impl Renderer { + pub fn render<'a>(&'a self, snippet: Snippet<'a>) -> impl Display + 'a { + DisplayList::from(snippet) + } +} diff --git a/tests/fixtures_test.rs b/tests/fixtures_test.rs index 13f85431..8dfd229e 100644 --- a/tests/fixtures_test.rs +++ b/tests/fixtures_test.rs @@ -2,7 +2,8 @@ mod diff; mod snippet; use crate::snippet::SnippetDef; -use annotate_snippets::{display_list::DisplayList, snippet::Snippet}; +use annotate_snippets::renderer::Renderer; +use annotate_snippets::snippet::Snippet; use glob::glob; use std::{error::Error, fs::File, io, io::prelude::*}; @@ -30,8 +31,8 @@ fn test_fixtures() { let snippet = read_fixture(&src).expect("Failed to read file"); let expected_out = read_file(&path_out).expect("Failed to read file"); - let dl = DisplayList::from(snippet); - let actual_out = dl.to_string(); + let renderer = Renderer; + let actual_out = renderer.render(snippet).to_string(); println!("{}", expected_out); println!("{}", actual_out.trim_end()); diff --git a/tests/formatter.rs b/tests/formatter.rs index f95b0026..1226ab49 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -1,4 +1,5 @@ use annotate_snippets::display_list::*; +use annotate_snippets::renderer::Renderer; use annotate_snippets::snippet::{self, Snippet}; #[test] @@ -548,7 +549,8 @@ fn test_i_29() { | ^^^^ oops |"#; - assert_eq!(DisplayList::from(snippets).to_string(), expected); + let renderer = Renderer; + assert_eq!(renderer.render(snippets).to_string(), expected); } #[test] @@ -576,7 +578,8 @@ fn test_point_to_double_width_characters() { | ^^^^ world |"#; - assert_eq!(DisplayList::from(snippets).to_string(), expected); + let renderer = Renderer; + assert_eq!(renderer.render(snippets).to_string(), expected); } #[test] @@ -606,7 +609,8 @@ fn test_point_to_double_width_characters_across_lines() { | |______^ Good morning |"#; - assert_eq!(DisplayList::from(snippets).to_string(), expected); + let renderer = Renderer; + assert_eq!(renderer.render(snippets).to_string(), expected); } #[test] @@ -643,7 +647,8 @@ fn test_point_to_double_width_characters_multiple() { | ---- note: Sushi2 |"#; - assert_eq!(DisplayList::from(snippets).to_string(), expected); + let renderer = Renderer; + assert_eq!(renderer.render(snippets).to_string(), expected); } #[test] @@ -671,5 +676,6 @@ fn test_point_to_double_width_characters_mixed() { | ^^^^^^^^^^^ New world |"#; - assert_eq!(DisplayList::from(snippets).to_string(), expected); + let renderer = Renderer; + assert_eq!(renderer.render(snippets).to_string(), expected); } From d0c65b26493d60f86a82c5919ef736b35808c23a Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 2 Dec 2023 13:01:27 -0700 Subject: [PATCH 02/12] fix!: Move format options to `Renderer` BREAKING CHANGE: This removes `opt` from `Snippet` --- benches/simple.rs | 16 +-- examples/expected_type.rs | 11 +- examples/footer.rs | 11 +- examples/format.rs | 11 +- examples/multislice.rs | 11 +- src/display_list/mod.rs | 43 +++--- src/renderer/mod.rs | 49 ++++++- src/snippet.rs | 3 - tests/{snippet => deserialize}/mod.rs | 131 +++++++++--------- tests/dl_from_snippet.rs | 27 ++-- tests/fixtures/no-color/issue_52.toml | 6 +- tests/fixtures/no-color/issue_9.toml | 14 +- .../no-color/multiline_annotation.toml | 8 +- .../no-color/multiline_annotation2.toml | 6 +- .../no-color/multiline_annotation3.toml | 6 +- .../no-color/multiple_annotations.toml | 8 +- tests/fixtures/no-color/simple.toml | 10 +- tests/fixtures/no-color/strip_line.toml | 10 +- tests/fixtures/no-color/strip_line_char.toml | 10 +- .../fixtures/no-color/strip_line_non_ws.toml | 11 +- tests/fixtures_test.rs | 11 +- tests/formatter.rs | 15 +- 22 files changed, 208 insertions(+), 220 deletions(-) rename tests/{snippet => deserialize}/mod.rs (88%) diff --git a/benches/simple.rs b/benches/simple.rs index 4427afde..8ccd18f7 100644 --- a/benches/simple.rs +++ b/benches/simple.rs @@ -5,12 +5,9 @@ extern crate criterion; use criterion::{black_box, Criterion}; use annotate_snippets::renderer::Renderer; -use annotate_snippets::{ - display_list::FormatOptions, - snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, -}; +use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}; -fn create_snippet() { +fn create_snippet(renderer: Renderer) { let snippet = Snippet { slices: vec![Slice { source: r#") -> Option { @@ -57,18 +54,15 @@ fn create_snippet() { annotation_type: AnnotationType::Error, }), footer: vec![], - opt: FormatOptions { - color: true, - ..Default::default() - }, }; - let renderer = Renderer; let _result = renderer.render(snippet).to_string(); } pub fn criterion_benchmark(c: &mut Criterion) { - c.bench_function("format", |b| b.iter(|| black_box(create_snippet()))); + c.bench_function("format", |b| { + b.iter(|| black_box(create_snippet(Renderer::plain()))) + }); } criterion_group!(benches, criterion_benchmark); diff --git a/examples/expected_type.rs b/examples/expected_type.rs index cd23bfcf..959419c2 100644 --- a/examples/expected_type.rs +++ b/examples/expected_type.rs @@ -1,8 +1,5 @@ use annotate_snippets::renderer::Renderer; -use annotate_snippets::{ - display_list::FormatOptions, - snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, -}; +use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}; fn main() { let snippet = Snippet { @@ -33,12 +30,8 @@ fn main() { }, ], }], - opt: FormatOptions { - color: true, - ..Default::default() - }, }; - let renderer = Renderer; + let renderer = Renderer::plain(); println!("{}", renderer.render(snippet)); } diff --git a/examples/footer.rs b/examples/footer.rs index 6bf6f5ed..0191c1d6 100644 --- a/examples/footer.rs +++ b/examples/footer.rs @@ -1,8 +1,5 @@ use annotate_snippets::renderer::Renderer; -use annotate_snippets::{ - display_list::FormatOptions, - snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, -}; +use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}; fn main() { let snippet = Snippet { @@ -29,12 +26,8 @@ fn main() { annotation_type: AnnotationType::Error, }], }], - opt: FormatOptions { - color: true, - ..Default::default() - }, }; - let renderer = Renderer; + let renderer = Renderer::plain(); println!("{}", renderer.render(snippet)); } diff --git a/examples/format.rs b/examples/format.rs index a053ccc2..7302eefe 100644 --- a/examples/format.rs +++ b/examples/format.rs @@ -1,8 +1,5 @@ use annotate_snippets::renderer::Renderer; -use annotate_snippets::{ - display_list::FormatOptions, - snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, -}; +use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}; fn main() { let snippet = Snippet { @@ -51,12 +48,8 @@ fn main() { annotation_type: AnnotationType::Error, }), footer: vec![], - opt: FormatOptions { - color: true, - ..Default::default() - }, }; - let renderer = Renderer; + let renderer = Renderer::plain(); println!("{}", renderer.render(snippet)); } diff --git a/examples/multislice.rs b/examples/multislice.rs index a875ae26..dc51d4f5 100644 --- a/examples/multislice.rs +++ b/examples/multislice.rs @@ -1,8 +1,5 @@ use annotate_snippets::renderer::Renderer; -use annotate_snippets::{ - display_list::FormatOptions, - snippet::{Annotation, AnnotationType, Slice, Snippet}, -}; +use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet}; fn main() { let snippet = Snippet { @@ -28,12 +25,8 @@ fn main() { annotations: vec![], }, ], - opt: FormatOptions { - color: true, - ..Default::default() - }, }; - let renderer = Renderer; + let renderer = Renderer::plain(); println!("{}", renderer.render(snippet)); } diff --git a/src/display_list/mod.rs b/src/display_list/mod.rs index 1ad328aa..1498dc5e 100644 --- a/src/display_list/mod.rs +++ b/src/display_list/mod.rs @@ -108,13 +108,28 @@ impl<'a> Display for DisplayList<'a> { } impl<'a> From> for DisplayList<'a> { - fn from( + fn from(snippet: snippet::Snippet<'a>) -> DisplayList<'a> { + Self::new(snippet, false, false, None) + } +} + +impl<'a> DisplayList<'a> { + const ANONYMIZED_LINE_NUM: &'static str = "LL"; + const ERROR_TXT: &'static str = "error"; + const HELP_TXT: &'static str = "help"; + const INFO_TXT: &'static str = "info"; + const NOTE_TXT: &'static str = "note"; + const WARNING_TXT: &'static str = "warning"; + + pub(crate) fn new( snippet::Snippet { title, footer, slices, - opt, }: snippet::Snippet<'a>, + color: bool, + anonymized_line_numbers: bool, + margin: Option, ) -> DisplayList<'a> { let mut body = vec![]; if let Some(annotation) = title { @@ -126,7 +141,7 @@ impl<'a> From> for DisplayList<'a> { slice, idx == 0, !footer.is_empty(), - opt.margin, + margin, )); } @@ -134,12 +149,6 @@ impl<'a> From> for DisplayList<'a> { body.append(&mut format_annotation(annotation)); } - let FormatOptions { - color, - anonymized_line_numbers, - margin, - } = opt; - Self { body, stylesheet: get_term_style(color), @@ -147,15 +156,6 @@ impl<'a> From> for DisplayList<'a> { margin, } } -} - -impl<'a> DisplayList<'a> { - const ANONYMIZED_LINE_NUM: &'static str = "LL"; - const ERROR_TXT: &'static str = "error"; - const HELP_TXT: &'static str = "help"; - const INFO_TXT: &'static str = "info"; - const NOTE_TXT: &'static str = "note"; - const WARNING_TXT: &'static str = "warning"; #[inline] fn format_annotation_type( @@ -527,13 +527,6 @@ impl<'a> DisplayList<'a> { } } -#[derive(Debug, Default, Copy, Clone)] -pub struct FormatOptions { - pub color: bool, - pub anonymized_line_numbers: bool, - pub margin: Option, -} - #[derive(Clone, Copy, Debug)] pub struct Margin { /// The available whitespace in the left that can be consumed when centering. diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 9a66c1c2..b1f5f055 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,11 +1,54 @@ -use crate::display_list::DisplayList; +use crate::display_list::{DisplayList, Margin}; use crate::snippet::Snippet; use std::fmt::Display; -pub struct Renderer; +#[derive(Clone)] +pub struct Renderer { + color: bool, + anonymized_line_numbers: bool, + margin: Option, +} impl Renderer { + /// No terminal styling + pub fn plain() -> Self { + Self { + color: false, + anonymized_line_numbers: false, + margin: None, + } + } + + /// Default terminal styling + pub fn styled() -> Self { + Self { + color: true, + anonymized_line_numbers: false, + margin: None, + } + } + + pub fn anonymized_line_numbers(mut self, anonymized_line_numbers: bool) -> Self { + self.anonymized_line_numbers = anonymized_line_numbers; + self + } + + pub fn color(mut self, color: bool) -> Self { + self.color = color; + self + } + + pub fn margin(mut self, margin: Option) -> Self { + self.margin = margin; + self + } + pub fn render<'a>(&'a self, snippet: Snippet<'a>) -> impl Display + 'a { - DisplayList::from(snippet) + DisplayList::new( + snippet, + self.color, + self.anonymized_line_numbers, + self.margin, + ) } } diff --git a/src/snippet.rs b/src/snippet.rs index bc7ba009..c1914c96 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -28,10 +28,8 @@ //! annotations: vec![], //! }, //! ], -//! opt: Default::default(), //! }; //! ``` -use crate::display_list::FormatOptions; /// Primary structure provided for formatting #[derive(Debug, Default)] @@ -39,7 +37,6 @@ pub struct Snippet<'a> { pub title: Option>, pub footer: Vec>, pub slices: Vec>, - pub opt: FormatOptions, } /// Structure containing the slice of text to be annotated and diff --git a/tests/snippet/mod.rs b/tests/deserialize/mod.rs similarity index 88% rename from tests/snippet/mod.rs rename to tests/deserialize/mod.rs index 92d272de..58d14ef0 100644 --- a/tests/snippet/mod.rs +++ b/tests/deserialize/mod.rs @@ -1,10 +1,19 @@ use serde::{Deserialize, Deserializer, Serialize}; +use annotate_snippets::renderer::Renderer; use annotate_snippets::{ - display_list::{FormatOptions, Margin}, + display_list::Margin, snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, }; +#[derive(Deserialize)] +pub struct Fixture<'a> { + #[serde(default)] + pub renderer: RendererDef, + #[serde(borrow)] + pub snippet: SnippetDef<'a>, +} + #[derive(Deserialize)] pub struct SnippetDef<'a> { #[serde(deserialize_with = "deserialize_annotation")] @@ -15,9 +24,6 @@ pub struct SnippetDef<'a> { #[serde(default)] #[serde(borrow)] pub footer: Vec>, - #[serde(deserialize_with = "deserialize_opt")] - #[serde(default)] - pub opt: FormatOptions, #[serde(deserialize_with = "deserialize_slices")] #[serde(borrow)] pub slices: Vec>, @@ -28,76 +34,16 @@ impl<'a> From> for Snippet<'a> { let SnippetDef { title, footer, - opt, slices, } = val; Snippet { title, footer, slices, - opt, } } } -fn deserialize_opt<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - #[derive(Deserialize)] - struct Wrapper(#[serde(with = "FormatOptionsDef")] FormatOptions); - - Wrapper::deserialize(deserializer).map(|w| w.0) -} - -#[derive(Deserialize)] -#[serde(remote = "FormatOptions")] -pub struct FormatOptionsDef { - #[serde(default)] - pub color: bool, - #[serde(default)] - pub anonymized_line_numbers: bool, - #[serde(deserialize_with = "deserialize_margin")] - #[serde(default)] - pub margin: Option, -} - -fn deserialize_margin<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - #[derive(Deserialize)] - struct Wrapper { - whitespace_left: usize, - span_left: usize, - span_right: usize, - label_right: usize, - column_width: usize, - max_line_len: usize, - } - - Option::::deserialize(deserializer).map(|opt_wrapped: Option| { - opt_wrapped.map(|wrapped: Wrapper| { - let Wrapper { - whitespace_left, - span_left, - span_right, - label_right, - column_width, - max_line_len, - } = wrapped; - Margin::new( - whitespace_left, - span_left, - span_right, - label_right, - column_width, - max_line_len, - ) - }) - }) -} - fn deserialize_slices<'de, D>(deserializer: D) -> Result>, D::Error> where D: Deserializer<'de>, @@ -206,3 +152,60 @@ enum AnnotationTypeDef { Note, Help, } + +#[derive(Default, Deserialize)] +pub struct RendererDef { + #[serde(default)] + anonymized_line_numbers: bool, + #[serde(deserialize_with = "deserialize_margin")] + #[serde(default)] + margin: Option, +} + +impl From for Renderer { + fn from(val: RendererDef) -> Self { + let RendererDef { + anonymized_line_numbers, + margin, + } = val; + Renderer::plain() + .anonymized_line_numbers(anonymized_line_numbers) + .margin(margin) + } +} + +fn deserialize_margin<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + #[derive(Deserialize)] + struct Wrapper { + whitespace_left: usize, + span_left: usize, + span_right: usize, + label_right: usize, + column_width: usize, + max_line_len: usize, + } + + Option::::deserialize(deserializer).map(|opt_wrapped: Option| { + opt_wrapped.map(|wrapped: Wrapper| { + let Wrapper { + whitespace_left, + span_left, + span_right, + label_right, + column_width, + max_line_len, + } = wrapped; + Margin::new( + whitespace_left, + span_left, + span_right, + label_right, + column_width, + max_line_len, + ) + }) + }) +} diff --git a/tests/dl_from_snippet.rs b/tests/dl_from_snippet.rs index 06f2ff76..9971c7eb 100644 --- a/tests/dl_from_snippet.rs +++ b/tests/dl_from_snippet.rs @@ -11,7 +11,6 @@ fn test_format_title() { }), footer: vec![], slices: vec![], - opt: Default::default(), }; let output = dl::DisplayList { body: vec![dl::DisplayLine::Raw(dl::DisplayRawLine::Annotation { @@ -26,8 +25,8 @@ fn test_format_title() { source_aligned: false, continuation: false, })], - stylesheet: get_term_style(input.opt.color), - anonymized_line_numbers: input.opt.anonymized_line_numbers, + stylesheet: get_term_style(false), + anonymized_line_numbers: false, margin: None, }; assert_eq!(dl::DisplayList::from(input), output); @@ -48,7 +47,6 @@ fn test_format_slice() { annotations: vec![], fold: false, }], - opt: Default::default(), }; let output = dl::DisplayList { body: vec![ @@ -79,8 +77,8 @@ fn test_format_slice() { line: dl::DisplaySourceLine::Empty, }, ], - stylesheet: get_term_style(input.opt.color), - anonymized_line_numbers: input.opt.anonymized_line_numbers, + stylesheet: get_term_style(false), + anonymized_line_numbers: false, margin: None, }; assert_eq!(dl::DisplayList::from(input), output); @@ -111,7 +109,6 @@ fn test_format_slices_continuation() { fold: false, }, ], - opt: Default::default(), }; let output = dl::DisplayList { body: vec![ @@ -162,8 +159,8 @@ fn test_format_slices_continuation() { line: dl::DisplaySourceLine::Empty, }, ], - stylesheet: get_term_style(input.opt.color), - anonymized_line_numbers: input.opt.anonymized_line_numbers, + stylesheet: get_term_style(false), + anonymized_line_numbers: false, margin: None, }; assert_eq!(dl::DisplayList::from(input), output); @@ -190,7 +187,6 @@ fn test_format_slice_annotation_standalone() { }], fold: false, }], - opt: Default::default(), }; let output = dl::DisplayList { body: vec![ @@ -238,8 +234,8 @@ fn test_format_slice_annotation_standalone() { line: dl::DisplaySourceLine::Empty, }, ], - stylesheet: get_term_style(input.opt.color), - anonymized_line_numbers: input.opt.anonymized_line_numbers, + stylesheet: get_term_style(false), + anonymized_line_numbers: false, margin: None, }; assert_eq!(dl::DisplayList::from(input), output); @@ -255,7 +251,6 @@ fn test_format_label() { annotation_type: snippet::AnnotationType::Error, }], slices: vec![], - opt: Default::default(), }; let output = dl::DisplayList { body: vec![dl::DisplayLine::Raw(dl::DisplayRawLine::Annotation { @@ -270,8 +265,8 @@ fn test_format_label() { source_aligned: true, continuation: false, })], - stylesheet: get_term_style(input.opt.color), - anonymized_line_numbers: input.opt.anonymized_line_numbers, + stylesheet: get_term_style(false), + anonymized_line_numbers: false, margin: None, }; assert_eq!(dl::DisplayList::from(input), output); @@ -296,7 +291,6 @@ fn test_i26() { origin: None, fold: false, }], - opt: Default::default(), }; let _ = dl::DisplayList::from(input); @@ -322,7 +316,6 @@ fn test_i_29() { }], fold: true, }], - opt: Default::default(), }; let expected = DisplayList { diff --git a/tests/fixtures/no-color/issue_52.toml b/tests/fixtures/no-color/issue_52.toml index 8d54613f..d31e0cb2 100644 --- a/tests/fixtures/no-color/issue_52.toml +++ b/tests/fixtures/no-color/issue_52.toml @@ -1,7 +1,7 @@ -[title] +[snippet.title] annotation_type = "Error" -[[slices]] +[[snippet.slices]] source = """ @@ -10,7 +10,7 @@ invalid syntax line_start = 1 origin = "path/to/error.rs" fold = true -[[slices.annotations]] +[[snippet.slices.annotations]] label = "error here" annotation_type = "Warning" range = [2,16] diff --git a/tests/fixtures/no-color/issue_9.toml b/tests/fixtures/no-color/issue_9.toml index a30563b2..ee1fe27b 100644 --- a/tests/fixtures/no-color/issue_9.toml +++ b/tests/fixtures/no-color/issue_9.toml @@ -1,28 +1,28 @@ -[title] +[snippet.title] label = "expected one of `.`, `;`, `?`, or an operator, found `for`" annotation_type = "Error" -[[slices]] +[[snippet.slices]] source = "let x = vec![1];" line_start = 4 origin = "/code/rust/src/test/ui/annotate-snippet/suggestion.rs" -[[slices.annotations]] +[[snippet.slices.annotations]] label = "move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait" annotation_type = "Warning" range = [4, 5] -[[slices]] +[[snippet.slices]] source = "let y = x;" line_start = 7 -[[slices.annotations]] +[[snippet.slices.annotations]] label = "value moved here" annotation_type = "Warning" range = [8, 9] -[[slices]] +[[snippet.slices]] source = "x;" line_start = 9 -[[slices.annotations]] +[[snippet.slices.annotations]] label = "value used here after move" annotation_type = "Error" range = [0, 1] diff --git a/tests/fixtures/no-color/multiline_annotation.toml b/tests/fixtures/no-color/multiline_annotation.toml index c3dc1e9e..604e04b0 100644 --- a/tests/fixtures/no-color/multiline_annotation.toml +++ b/tests/fixtures/no-color/multiline_annotation.toml @@ -1,4 +1,4 @@ -[[slices]] +[[snippet.slices]] source = """ ) -> Option { for ann in annotations { @@ -26,15 +26,15 @@ source = """ line_start = 51 origin = "src/format.rs" fold = true -[[slices.annotations]] +[[snippet.slices.annotations]] label = "expected `std::option::Option` because of return type" annotation_type = "Warning" range = [5, 19] -[[slices.annotations]] +[[snippet.slices.annotations]] label = "expected enum `std::option::Option`, found ()" annotation_type = "Error" range = [22, 766] -[title] +[snippet.title] label = "mismatched types" id = "E0308" annotation_type = "Error" diff --git a/tests/fixtures/no-color/multiline_annotation2.toml b/tests/fixtures/no-color/multiline_annotation2.toml index 845bf9f2..3287fdce 100644 --- a/tests/fixtures/no-color/multiline_annotation2.toml +++ b/tests/fixtures/no-color/multiline_annotation2.toml @@ -1,4 +1,4 @@ -[[slices]] +[[snippet.slices]] source = """ if let DisplayLine::Source { ref mut inline_marks, @@ -7,12 +7,12 @@ source = """ line_start = 139 origin = "src/display_list.rs" fold = false -[[slices.annotations]] +[[snippet.slices.annotations]] label = "missing fields `lineno`, `content`" annotation_type = "Error" range = [31, 128] -[title] +[snippet.title] label = "pattern does not mention fields `lineno`, `content`" id = "E0027" annotation_type = "Error" diff --git a/tests/fixtures/no-color/multiline_annotation3.toml b/tests/fixtures/no-color/multiline_annotation3.toml index 21bbcd85..9fe85fb4 100644 --- a/tests/fixtures/no-color/multiline_annotation3.toml +++ b/tests/fixtures/no-color/multiline_annotation3.toml @@ -1,4 +1,4 @@ -[[slices]] +[[snippet.slices]] source = """ This is an exampl e of an edge case of an annotation overflowing @@ -7,12 +7,12 @@ to exactly one character on next line. line_start = 26 origin = "foo.txt" fold = false -[[slices.annotations]] +[[snippet.slices.annotations]] label = "this should not be on separate lines" annotation_type = "Error" range = [11, 18] -[title] +[snippet.title] label = "spacing error found" id = "E####" annotation_type = "Error" diff --git a/tests/fixtures/no-color/multiple_annotations.toml b/tests/fixtures/no-color/multiple_annotations.toml index 84efc5f1..f037c9a1 100644 --- a/tests/fixtures/no-color/multiple_annotations.toml +++ b/tests/fixtures/no-color/multiple_annotations.toml @@ -1,4 +1,4 @@ -[[slices]] +[[snippet.slices]] source = """ fn add_title_line(result: &mut Vec, main_annotation: Option<&Annotation>) { if let Some(annotation) = main_annotation { @@ -11,15 +11,15 @@ fn add_title_line(result: &mut Vec, main_annotation: Option<&Annotation> } """ line_start = 96 -[[slices.annotations]] +[[snippet.slices.annotations]] label = "Variable defined here" annotation_type = "Error" range = [100, 110] -[[slices.annotations]] +[[snippet.slices.annotations]] label = "Referenced here" annotation_type = "Error" range = [184, 194] -[[slices.annotations]] +[[snippet.slices.annotations]] label = "Referenced again here" annotation_type = "Error" range = [243, 253] diff --git a/tests/fixtures/no-color/simple.toml b/tests/fixtures/no-color/simple.toml index 6c38674a..2e9b6d89 100644 --- a/tests/fixtures/no-color/simple.toml +++ b/tests/fixtures/no-color/simple.toml @@ -1,18 +1,18 @@ -[[slices]] +[[snippet.slices]] source = """ }) for line in &self.body {""" line_start = 169 origin = "src/format_color.rs" -[[slices.annotations]] +[[snippet.slices.annotations]] label = "unexpected token" annotation_type = "Error" range = [20, 23] -[[slices.annotations]] +[[snippet.slices.annotations]] label = "expected one of `.`, `;`, `?`, or an operator here" annotation_type = "Warning" range = [10, 11] -[title] +[snippet.title] label = "expected one of `.`, `;`, `?`, or an operator, found `for`" -annotation_type = "Error" +annotation_type = "Error" \ No newline at end of file diff --git a/tests/fixtures/no-color/strip_line.toml b/tests/fixtures/no-color/strip_line.toml index 76d9519b..4c609c45 100644 --- a/tests/fixtures/no-color/strip_line.toml +++ b/tests/fixtures/no-color/strip_line.toml @@ -1,22 +1,22 @@ -[title] +[snippet.title] id = "E0308" label = "mismatched types" annotation_type = "Error" -[[slices]] +[[snippet.slices]] source = " let _: () = 42;" line_start = 4 origin = "$DIR/whitespace-trimming.rs" -[[slices.annotations]] +[[snippet.slices.annotations]] label = "expected (), found integer" annotation_type = "Error" range = [192, 194] -[opt] +[renderer] color = false anonymized_line_numbers = true -[opt.margin] +[renderer.margin] whitespace_left = 180 span_left = 192 span_right = 194 diff --git a/tests/fixtures/no-color/strip_line_char.toml b/tests/fixtures/no-color/strip_line_char.toml index 5b432beb..76ea7499 100644 --- a/tests/fixtures/no-color/strip_line_char.toml +++ b/tests/fixtures/no-color/strip_line_char.toml @@ -1,22 +1,22 @@ -[title] +[snippet.title] id = "E0308" label = "mismatched types" annotation_type = "Error" -[[slices]] +[[snippet.slices]] source = " let _: () = 42ñ" line_start = 4 origin = "$DIR/whitespace-trimming.rs" -[[slices.annotations]] +[[snippet.slices.annotations]] label = "expected (), found integer" annotation_type = "Error" range = [192, 194] -[opt] +[renderer] color = false anonymized_line_numbers = true -[opt.margin] +[renderer.margin] whitespace_left = 180 span_left = 192 span_right = 194 diff --git a/tests/fixtures/no-color/strip_line_non_ws.toml b/tests/fixtures/no-color/strip_line_non_ws.toml index 5129f5ce..c46d6e27 100644 --- a/tests/fixtures/no-color/strip_line_non_ws.toml +++ b/tests/fixtures/no-color/strip_line_non_ws.toml @@ -1,22 +1,21 @@ -[title] +[snippet.title] id = "E0308" label = "mismatched types" annotation_type = "Error" -[[slices]] +[[snippet.slices]] source = " let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = ();" line_start = 4 origin = "$DIR/non-whitespace-trimming.rs" -[[slices.annotations]] +[[snippet.slices.annotations]] label = "expected (), found integer" annotation_type = "Error" range = [240, 242] -[opt] -color = false +[renderer] anonymized_line_numbers = true -[opt.margin] +[renderer.margin] whitespace_left = 4 span_left = 240 span_right = 242 diff --git a/tests/fixtures_test.rs b/tests/fixtures_test.rs index 8dfd229e..854719ff 100644 --- a/tests/fixtures_test.rs +++ b/tests/fixtures_test.rs @@ -1,7 +1,7 @@ +mod deserialize; mod diff; -mod snippet; -use crate::snippet::SnippetDef; +use crate::deserialize::Fixture; use annotate_snippets::renderer::Renderer; use annotate_snippets::snippet::Snippet; use glob::glob; @@ -14,8 +14,8 @@ fn read_file(path: &str) -> Result { Ok(s.trim_end().to_string()) } -fn read_fixture(src: &str) -> Result, Box> { - Ok(toml::from_str(src).map(|a: SnippetDef| a.into())?) +fn read_fixture(src: &str) -> Result<(Renderer, Snippet<'_>), Box> { + Ok(toml::from_str(src).map(|a: Fixture| (a.renderer.into(), a.snippet.into()))?) } #[test] @@ -28,10 +28,9 @@ fn test_fixtures() { let path_out = path_in.replace(".toml", ".txt"); let src = read_file(path_in).expect("Failed to read file"); - let snippet = read_fixture(&src).expect("Failed to read file"); + let (renderer, snippet) = read_fixture(&src).expect("Failed to read file"); let expected_out = read_file(&path_out).expect("Failed to read file"); - let renderer = Renderer; let actual_out = renderer.render(snippet).to_string(); println!("{}", expected_out); println!("{}", actual_out.trim_end()); diff --git a/tests/formatter.rs b/tests/formatter.rs index 1226ab49..2117fec2 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -539,7 +539,6 @@ fn test_i_29() { }], fold: true, }], - opt: Default::default(), }; let expected = r#"error: oops --> :2:8 @@ -549,7 +548,7 @@ fn test_i_29() { | ^^^^ oops |"#; - let renderer = Renderer; + let renderer = Renderer::plain(); assert_eq!(renderer.render(snippets).to_string(), expected); } @@ -569,7 +568,6 @@ fn test_point_to_double_width_characters() { }], title: None, footer: vec![], - opt: Default::default(), }; let expected = r#" --> :1:7 @@ -578,7 +576,7 @@ fn test_point_to_double_width_characters() { | ^^^^ world |"#; - let renderer = Renderer; + let renderer = Renderer::plain(); assert_eq!(renderer.render(snippets).to_string(), expected); } @@ -598,7 +596,6 @@ fn test_point_to_double_width_characters_across_lines() { }], title: None, footer: vec![], - opt: Default::default(), }; let expected = r#" --> :1:3 @@ -609,7 +606,7 @@ fn test_point_to_double_width_characters_across_lines() { | |______^ Good morning |"#; - let renderer = Renderer; + let renderer = Renderer::plain(); assert_eq!(renderer.render(snippets).to_string(), expected); } @@ -636,7 +633,6 @@ fn test_point_to_double_width_characters_multiple() { }], title: None, footer: vec![], - opt: Default::default(), }; let expected = r#" --> :1:1 @@ -647,7 +643,7 @@ fn test_point_to_double_width_characters_multiple() { | ---- note: Sushi2 |"#; - let renderer = Renderer; + let renderer = Renderer::plain(); assert_eq!(renderer.render(snippets).to_string(), expected); } @@ -667,7 +663,6 @@ fn test_point_to_double_width_characters_mixed() { }], title: None, footer: vec![], - opt: Default::default(), }; let expected = r#" --> :1:7 @@ -676,6 +671,6 @@ fn test_point_to_double_width_characters_mixed() { | ^^^^^^^^^^^ New world |"#; - let renderer = Renderer; + let renderer = Renderer::plain(); assert_eq!(renderer.render(snippets).to_string(), expected); } From 4affdfb50ea0670d85e52737c082c03f89ae8ada Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 2 Dec 2023 13:36:57 -0700 Subject: [PATCH 03/12] fix!: Move to a new `StyleSheet` BREAKING CHANGE: This removes the `formatter` and `stylesheets` modules --- src/display_list/mod.rs | 114 +++++++++++++++++------------------- src/formatter/mod.rs | 23 -------- src/formatter/style.rs | 51 ---------------- src/lib.rs | 2 - src/renderer/mod.rs | 68 +++++++++++++++++---- src/renderer/stylesheet.rs | 62 ++++++++++++++++++++ src/stylesheets/color.rs | 50 ---------------- src/stylesheets/mod.rs | 11 ---- src/stylesheets/no_color.rs | 31 ---------- tests/dl_from_snippet.rs | 15 ++--- 10 files changed, 182 insertions(+), 245 deletions(-) delete mode 100644 src/formatter/mod.rs delete mode 100644 src/formatter/style.rs create mode 100644 src/renderer/stylesheet.rs delete mode 100644 src/stylesheets/color.rs delete mode 100644 src/stylesheets/mod.rs delete mode 100644 src/stylesheets/no_color.rs diff --git a/src/display_list/mod.rs b/src/display_list/mod.rs index 1498dc5e..6b1720f9 100644 --- a/src/display_list/mod.rs +++ b/src/display_list/mod.rs @@ -31,18 +31,18 @@ //! styling. //! //! The above snippet has been built out of the following structure: +use crate::snippet; use std::cmp::{max, min}; use std::fmt::{Display, Write}; use std::{cmp, fmt}; +use yansi_term::Style; -use crate::formatter::style::{Style, StyleClass}; -use crate::formatter::{get_term_style, style::Stylesheet}; -use crate::snippet; +use crate::renderer::stylesheet::Stylesheet; /// List of lines to be displayed. pub struct DisplayList<'a> { pub body: Vec>, - pub stylesheet: Box, + pub stylesheet: Stylesheet, pub anonymized_line_numbers: bool, pub margin: Option, } @@ -52,7 +52,7 @@ impl<'a> From>> for DisplayList<'a> { Self { body, anonymized_line_numbers: false, - stylesheet: get_term_style(false), + stylesheet: Stylesheet::default(), margin: None, } } @@ -109,7 +109,7 @@ impl<'a> Display for DisplayList<'a> { impl<'a> From> for DisplayList<'a> { fn from(snippet: snippet::Snippet<'a>) -> DisplayList<'a> { - Self::new(snippet, false, false, None) + Self::new(snippet, Stylesheet::default(), false, None) } } @@ -127,7 +127,7 @@ impl<'a> DisplayList<'a> { footer, slices, }: snippet::Snippet<'a>, - color: bool, + stylesheet: Stylesheet, anonymized_line_numbers: bool, margin: Option, ) -> DisplayList<'a> { @@ -151,7 +151,7 @@ impl<'a> DisplayList<'a> { Self { body, - stylesheet: get_term_style(color), + stylesheet, anonymized_line_numbers, margin, } @@ -183,15 +183,15 @@ impl<'a> DisplayList<'a> { } } - fn get_annotation_style(&self, annotation_type: &DisplayAnnotationType) -> Box { - self.stylesheet.get_style(match annotation_type { - DisplayAnnotationType::Error => StyleClass::Error, - DisplayAnnotationType::Warning => StyleClass::Warning, - DisplayAnnotationType::Info => StyleClass::Info, - DisplayAnnotationType::Note => StyleClass::Note, - DisplayAnnotationType::Help => StyleClass::Help, - DisplayAnnotationType::None => StyleClass::None, - }) + fn get_annotation_style(&self, annotation_type: &DisplayAnnotationType) -> &Style { + match annotation_type { + DisplayAnnotationType::Error => self.stylesheet.error(), + DisplayAnnotationType::Warning => self.stylesheet.warning(), + DisplayAnnotationType::Info => self.stylesheet.info(), + DisplayAnnotationType::Note => self.stylesheet.note(), + DisplayAnnotationType::Help => self.stylesheet.help(), + DisplayAnnotationType::None => self.stylesheet.none(), + } } fn format_label( @@ -199,12 +199,12 @@ impl<'a> DisplayList<'a> { label: &[DisplayTextFragment<'_>], f: &mut fmt::Formatter<'_>, ) -> fmt::Result { - let emphasis_style = self.stylesheet.get_style(StyleClass::Emphasis); + let emphasis_style = self.stylesheet.emphasis(); for fragment in label { match fragment.style { DisplayTextStyle::Regular => fragment.content.fmt(f)?, - DisplayTextStyle::Emphasis => emphasis_style.paint(fragment.content, f)?, + DisplayTextStyle::Emphasis => emphasis_style.paint(fragment.content).fmt(f)?, } } Ok(()) @@ -231,8 +231,8 @@ impl<'a> DisplayList<'a> { if formatted_len == 0 { self.format_label(&annotation.label, f) } else { - color.paint_fn( - Box::new(|f| { + color + .paint_fn(Box::new(|f: &mut fmt::Formatter<'_>| { Self::format_annotation_type(&annotation.annotation_type, f)?; if let Some(id) = &annotation.id { f.write_char('[')?; @@ -240,18 +240,17 @@ impl<'a> DisplayList<'a> { f.write_char(']')?; } Ok(()) - }), - f, - )?; + })) + .fmt(f)?; + if !is_annotation_empty(annotation) { if in_source { - color.paint_fn( - Box::new(|f| { + color + .paint_fn(Box::new(|f: &mut fmt::Formatter<'_>| { f.write_str(": ")?; self.format_label(&annotation.label, f) - }), - f, - )?; + })) + .fmt(f)?; } else { f.write_str(": ")?; self.format_label(&annotation.label, f)?; @@ -362,27 +361,25 @@ impl<'a> DisplayList<'a> { _ => range.0, }; - color.paint_fn( - Box::new(|f| { + color + .paint_fn(|f| { format_repeat_char(indent_char, indent_length + 1, f)?; format_repeat_char(mark, range.1 - indent_length, f) - }), - f, - )?; + }) + .fmt(f)?; if !is_annotation_empty(annotation) { f.write_char(' ')?; - color.paint_fn( - Box::new(|f| { + color + .paint_fn(|f| { self.format_annotation( annotation, annotation_part == &DisplayAnnotationPart::LabelContinuation, true, f, ) - }), - f, - )?; + }) + .fmt(f)?; } Ok(()) @@ -407,11 +404,11 @@ impl<'a> DisplayList<'a> { DisplayHeaderType::Initial => "-->", DisplayHeaderType::Continuation => ":::", }; - let lineno_color = self.stylesheet.get_style(StyleClass::LineNo); + let lineno_color = self.stylesheet.line_no(); if let Some((col, row)) = pos { format_repeat_char(' ', lineno_width, f)?; - lineno_color.paint(header_sigil, f)?; + lineno_color.paint(header_sigil).fmt(f)?; f.write_char(' ')?; path.fmt(f)?; f.write_char(':')?; @@ -420,7 +417,7 @@ impl<'a> DisplayList<'a> { row.fmt(f) } else { format_repeat_char(' ', lineno_width, f)?; - lineno_color.paint(header_sigil, f)?; + lineno_color.paint(header_sigil).fmt(f)?; f.write_char(' ')?; path.fmt(f) } @@ -434,10 +431,10 @@ impl<'a> DisplayList<'a> { if *continuation { format_repeat_char(' ', lineno_width + 3, f)?; } else { - let lineno_color = self.stylesheet.get_style(StyleClass::LineNo); + let lineno_color = self.stylesheet.line_no(); format_repeat_char(' ', lineno_width, f)?; f.write_char(' ')?; - lineno_color.paint("=", f)?; + lineno_color.paint("=").fmt(f)?; f.write_char(' ')?; } } @@ -460,26 +457,24 @@ impl<'a> DisplayList<'a> { inline_marks, line, } => { - let lineno_color = self.stylesheet.get_style(StyleClass::LineNo); + let lineno_color = self.stylesheet.line_no(); if self.anonymized_line_numbers && lineno.is_some() { - lineno_color.paint_fn( - Box::new(|f| { + lineno_color + .paint_fn(Box::new(|f: &mut fmt::Formatter<'_>| { f.write_str(Self::ANONYMIZED_LINE_NUM)?; f.write_str(" |") - }), - f, - )?; + })) + .fmt(f)?; } else { - lineno_color.paint_fn( - Box::new(|f| { + lineno_color + .paint_fn(Box::new(|f: &mut fmt::Formatter<'_>| { match lineno { Some(n) => write!(f, "{:>width$}", n, width = lineno_width), None => format_repeat_char(' ', lineno_width, f), }?; f.write_str(" |") - }), - f, - )?; + })) + .fmt(f)?; } if *line != DisplaySourceLine::Empty { if !inline_marks.is_empty() || 0 < inline_marks_width { @@ -513,15 +508,14 @@ impl<'a> DisplayList<'a> { ) -> fmt::Result { format_repeat_char(' ', inline_marks_width - inline_marks.len(), f)?; for mark in inline_marks { - self.get_annotation_style(&mark.annotation_type).paint_fn( - Box::new(|f| { + self.get_annotation_style(&mark.annotation_type) + .paint_fn(Box::new(|f: &mut fmt::Formatter<'_>| { f.write_char(match mark.mark_type { DisplayMarkType::AnnotationThrough => '|', DisplayMarkType::AnnotationStart => '/', }) - }), - f, - )?; + })) + .fmt(f)?; } Ok(()) } diff --git a/src/formatter/mod.rs b/src/formatter/mod.rs deleted file mode 100644 index 72bf9c77..00000000 --- a/src/formatter/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -pub mod style; - -use self::style::Stylesheet; - -#[cfg(feature = "color")] -use crate::stylesheets::color::AnsiTermStylesheet; -use crate::stylesheets::no_color::NoColorStylesheet; - -#[cfg(feature = "color")] -#[inline] -pub fn get_term_style(color: bool) -> Box { - if color { - Box::new(AnsiTermStylesheet) - } else { - Box::new(NoColorStylesheet) - } -} - -#[cfg(not(feature = "color"))] -#[inline] -pub fn get_term_style(_color: bool) -> Box { - Box::new(NoColorStylesheet) -} diff --git a/src/formatter/style.rs b/src/formatter/style.rs deleted file mode 100644 index 3fc01c19..00000000 --- a/src/formatter/style.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! Set of structures required to implement a stylesheet -//! -//! In order to provide additional styling information for the -//! formatter, a structs can implement `Stylesheet` and `Style` -//! traits. -//! -use std::fmt; - -/// StyleClass is a collection of named variants of style classes -pub enum StyleClass { - /// Message indicating an error. - Error, - /// Message indicating a warning. - Warning, - /// Message indicating an information. - Info, - /// Message indicating a note. - Note, - /// Message indicating a help. - Help, - - /// Style for line numbers. - LineNo, - - /// Parts of the text that are to be emphasised. - Emphasis, - - /// Parts of the text that are regular. Usually a no-op. - None, -} - -/// This trait implements a return value for the `Stylesheet::get_style`. -pub trait Style { - /// The method used to write text with formatter - fn paint(&self, text: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result; - /// The method used to write display function with formatter - fn paint_fn<'a>( - &self, - c: Box) -> fmt::Result + 'a>, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result; - /// The method used by the `Formatter` to display the message in bold font. - fn bold(&self) -> Box; -} - -/// Trait to annotate structs that can provide `Style` implementations for -/// every `StyleClass` variant. -pub trait Stylesheet { - /// Returns a `Style` implementer based on the requested `StyleClass` variant. - fn get_style(&self, class: StyleClass) -> Box; -} diff --git a/src/lib.rs b/src/lib.rs index e11e9d58..bf0dc058 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,5 @@ // TODO: check documentation pub mod display_list; -pub mod formatter; pub mod renderer; pub mod snippet; -pub mod stylesheets; diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index b1f5f055..a79d8d2b 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,30 +1,43 @@ +pub mod stylesheet; + use crate::display_list::{DisplayList, Margin}; use crate::snippet::Snippet; use std::fmt::Display; +use stylesheet::Stylesheet; +use yansi_term::Color::Fixed; +use yansi_term::Style; #[derive(Clone)] pub struct Renderer { - color: bool, anonymized_line_numbers: bool, margin: Option, + stylesheet: Stylesheet, } impl Renderer { /// No terminal styling pub fn plain() -> Self { Self { - color: false, anonymized_line_numbers: false, margin: None, + stylesheet: Stylesheet::default(), } } /// Default terminal styling pub fn styled() -> Self { Self { - color: true, - anonymized_line_numbers: false, - margin: None, + stylesheet: Stylesheet { + error: Fixed(9).bold(), + warning: Fixed(11).bold(), + info: Fixed(12).bold(), + note: Style::new().bold(), + help: Fixed(14).bold(), + line_no: Fixed(12).bold(), + emphasis: Style::new().bold(), + none: Style::new(), + }, + ..Self::plain() } } @@ -33,20 +46,55 @@ impl Renderer { self } - pub fn color(mut self, color: bool) -> Self { - self.color = color; + pub fn margin(mut self, margin: Option) -> Self { + self.margin = margin; self } - pub fn margin(mut self, margin: Option) -> Self { - self.margin = margin; + pub fn error(mut self, style: Style) -> Self { + self.stylesheet.error = style; + self + } + + pub fn warning(mut self, style: Style) -> Self { + self.stylesheet.warning = style; + self + } + + pub fn info(mut self, style: Style) -> Self { + self.stylesheet.info = style; + self + } + + pub fn note(mut self, style: Style) -> Self { + self.stylesheet.note = style; + self + } + + pub fn help(mut self, style: Style) -> Self { + self.stylesheet.help = style; + self + } + + pub fn line_no(mut self, style: Style) -> Self { + self.stylesheet.line_no = style; + self + } + + pub fn emphasis(mut self, style: Style) -> Self { + self.stylesheet.emphasis = style; + self + } + + pub fn none(mut self, style: Style) -> Self { + self.stylesheet.none = style; self } pub fn render<'a>(&'a self, snippet: Snippet<'a>) -> impl Display + 'a { DisplayList::new( snippet, - self.color, + self.stylesheet, self.anonymized_line_numbers, self.margin, ) diff --git a/src/renderer/stylesheet.rs b/src/renderer/stylesheet.rs new file mode 100644 index 00000000..f52c1396 --- /dev/null +++ b/src/renderer/stylesheet.rs @@ -0,0 +1,62 @@ +use yansi_term::Style; + +#[derive(Clone, Copy, Debug)] +pub struct Stylesheet { + pub(crate) error: Style, + pub(crate) warning: Style, + pub(crate) info: Style, + pub(crate) note: Style, + pub(crate) help: Style, + pub(crate) line_no: Style, + pub(crate) emphasis: Style, + pub(crate) none: Style, +} + +impl Default for Stylesheet { + fn default() -> Self { + Self { + error: Style::new(), + warning: Style::new(), + info: Style::new(), + note: Style::new(), + help: Style::new(), + line_no: Style::new(), + emphasis: Style::new(), + none: Style::new(), + } + } +} + +impl Stylesheet { + pub(crate) fn error(&self) -> &Style { + &self.error + } + + pub(crate) fn warning(&self) -> &Style { + &self.warning + } + + pub(crate) fn info(&self) -> &Style { + &self.info + } + + pub(crate) fn note(&self) -> &Style { + &self.note + } + + pub(crate) fn help(&self) -> &Style { + &self.help + } + + pub(crate) fn line_no(&self) -> &Style { + &self.line_no + } + + pub(crate) fn emphasis(&self) -> &Style { + &self.emphasis + } + + pub(crate) fn none(&self) -> &Style { + &self.none + } +} diff --git a/src/stylesheets/color.rs b/src/stylesheets/color.rs deleted file mode 100644 index 024dd06f..00000000 --- a/src/stylesheets/color.rs +++ /dev/null @@ -1,50 +0,0 @@ -use std::fmt::{self, Display}; - -use yansi_term::{Color::Fixed, Style as AnsiTermStyle}; - -use crate::formatter::style::{Style, StyleClass, Stylesheet}; - -struct AnsiTermStyleWrapper { - style: AnsiTermStyle, -} - -impl Style for AnsiTermStyleWrapper { - fn paint(&self, text: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.style.paint(text).fmt(f) - } - - fn paint_fn<'a>( - &self, - c: Box) -> fmt::Result + 'a>, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - self.style.paint_fn(c).fmt(f) - } - - fn bold(&self) -> Box { - Box::new(AnsiTermStyleWrapper { style: self.style }) - } -} - -pub struct AnsiTermStylesheet; - -impl Stylesheet for AnsiTermStylesheet { - fn get_style(&self, class: StyleClass) -> Box { - let ansi_term_style = match class { - StyleClass::Error => Fixed(9).bold(), - StyleClass::Warning => Fixed(11).bold(), - StyleClass::Info => Fixed(12).bold(), - StyleClass::Note => AnsiTermStyle::new().bold(), - StyleClass::Help => Fixed(14).bold(), - - StyleClass::LineNo => Fixed(12).bold(), - - StyleClass::Emphasis => AnsiTermStyle::new().bold(), - - StyleClass::None => AnsiTermStyle::new(), - }; - Box::new(AnsiTermStyleWrapper { - style: ansi_term_style, - }) - } -} diff --git a/src/stylesheets/mod.rs b/src/stylesheets/mod.rs deleted file mode 100644 index 4648852a..00000000 --- a/src/stylesheets/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! List of stylesheets -//! -//! The list depends on what optional dependencies the crate has been -//! compiled with. -//! -//! By default the `no_color` is available. If the crate gets compiled -//! with `ansi_term`, the `color` stylesheet is added. - -#[cfg(feature = "color")] -pub mod color; -pub mod no_color; diff --git a/src/stylesheets/no_color.rs b/src/stylesheets/no_color.rs deleted file mode 100644 index 21cb2695..00000000 --- a/src/stylesheets/no_color.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::fmt; - -use crate::formatter::style::{Style, StyleClass, Stylesheet}; - -pub struct NoOpStyle {} - -impl Style for NoOpStyle { - fn paint(&self, text: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(text) - } - - fn paint_fn<'a>( - &self, - c: Box) -> fmt::Result + 'a>, - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - c(f) - } - - fn bold(&self) -> Box { - Box::new(NoOpStyle {}) - } -} - -pub struct NoColorStylesheet; - -impl Stylesheet for NoColorStylesheet { - fn get_style(&self, _class: StyleClass) -> Box { - Box::new(NoOpStyle {}) - } -} diff --git a/tests/dl_from_snippet.rs b/tests/dl_from_snippet.rs index 9971c7eb..5fb0762d 100644 --- a/tests/dl_from_snippet.rs +++ b/tests/dl_from_snippet.rs @@ -1,5 +1,6 @@ use annotate_snippets::display_list::DisplayList; -use annotate_snippets::{display_list as dl, formatter::get_term_style, snippet}; +use annotate_snippets::renderer::stylesheet::Stylesheet; +use annotate_snippets::{display_list as dl, snippet}; #[test] fn test_format_title() { @@ -25,7 +26,7 @@ fn test_format_title() { source_aligned: false, continuation: false, })], - stylesheet: get_term_style(false), + stylesheet: Stylesheet::default(), anonymized_line_numbers: false, margin: None, }; @@ -77,7 +78,7 @@ fn test_format_slice() { line: dl::DisplaySourceLine::Empty, }, ], - stylesheet: get_term_style(false), + stylesheet: Stylesheet::default(), anonymized_line_numbers: false, margin: None, }; @@ -159,7 +160,7 @@ fn test_format_slices_continuation() { line: dl::DisplaySourceLine::Empty, }, ], - stylesheet: get_term_style(false), + stylesheet: Stylesheet::default(), anonymized_line_numbers: false, margin: None, }; @@ -234,7 +235,7 @@ fn test_format_slice_annotation_standalone() { line: dl::DisplaySourceLine::Empty, }, ], - stylesheet: get_term_style(false), + stylesheet: Stylesheet::default(), anonymized_line_numbers: false, margin: None, }; @@ -265,7 +266,7 @@ fn test_format_label() { source_aligned: true, continuation: false, })], - stylesheet: get_term_style(false), + stylesheet: Stylesheet::default(), anonymized_line_numbers: false, margin: None, }; @@ -381,7 +382,7 @@ fn test_i_29() { line: dl::DisplaySourceLine::Empty, }, ], - stylesheet: get_term_style(false), + stylesheet: Stylesheet::default(), anonymized_line_numbers: false, margin: None, }; From dfd4e87d6f31ec50d29af26d7310cff5e66ca978 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 2 Dec 2023 13:53:43 -0700 Subject: [PATCH 04/12] fix!: Switch to `anstyle` for color BREAKING CHANGE: This removes `color` feature --- Cargo.lock | 11 +-- Cargo.toml | 4 +- src/display_list/mod.rs | 134 ++++++++++++++++++++----------------- src/renderer/mod.rs | 17 +++-- src/renderer/stylesheet.rs | 2 +- tests/diff/mod.rs | 32 +++++++-- 6 files changed, 109 insertions(+), 91 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c15507c8..0d9659ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,13 +21,13 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" name = "annotate-snippets" version = "0.9.2" dependencies = [ + "anstyle", "criterion", "difference", "glob", "serde", "toml", "unicode-width", - "yansi-term", ] [[package]] @@ -688,12 +688,3 @@ name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "yansi-term" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" -dependencies = [ - "winapi", -] diff --git a/Cargo.toml b/Cargo.toml index 86666519..ec39e99d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,8 +14,8 @@ keywords = ["code", "analysis", "ascii", "errors", "debug"] maintenance = { status = "actively-developed" } [dependencies] +anstyle = "1.0.4" unicode-width = "0.1.11" -yansi-term = { version = "0.1.2", optional = true } [dev-dependencies] criterion = "0.5.1" @@ -23,7 +23,6 @@ difference = "2.0.0" glob = "0.3.1" serde = { version = "1.0.192", features = ["derive"] } toml = "0.5.11" -yansi-term = "0.1.2" [[bench]] name = "simple" @@ -31,4 +30,3 @@ harness = false [features] default = [] -color = ["yansi-term"] diff --git a/src/display_list/mod.rs b/src/display_list/mod.rs index 6b1720f9..b07d2506 100644 --- a/src/display_list/mod.rs +++ b/src/display_list/mod.rs @@ -35,9 +35,8 @@ use crate::snippet; use std::cmp::{max, min}; use std::fmt::{Display, Write}; use std::{cmp, fmt}; -use yansi_term::Style; -use crate::renderer::stylesheet::Stylesheet; +use crate::renderer::{stylesheet::Stylesheet, Style}; /// List of lines to be displayed. pub struct DisplayList<'a> { @@ -204,7 +203,15 @@ impl<'a> DisplayList<'a> { for fragment in label { match fragment.style { DisplayTextStyle::Regular => fragment.content.fmt(f)?, - DisplayTextStyle::Emphasis => emphasis_style.paint(fragment.content).fmt(f)?, + DisplayTextStyle::Emphasis => { + write!( + f, + "{}{}{}", + emphasis_style.render(), + fragment.content, + emphasis_style.render_reset() + )?; + } } } Ok(()) @@ -231,26 +238,21 @@ impl<'a> DisplayList<'a> { if formatted_len == 0 { self.format_label(&annotation.label, f) } else { - color - .paint_fn(Box::new(|f: &mut fmt::Formatter<'_>| { - Self::format_annotation_type(&annotation.annotation_type, f)?; - if let Some(id) = &annotation.id { - f.write_char('[')?; - f.write_str(id)?; - f.write_char(']')?; - } - Ok(()) - })) - .fmt(f)?; + write!(f, "{}", color.render())?; + Self::format_annotation_type(&annotation.annotation_type, f)?; + if let Some(id) = &annotation.id { + f.write_char('[')?; + f.write_str(id)?; + f.write_char(']')?; + } + write!(f, "{}", color.render_reset())?; if !is_annotation_empty(annotation) { if in_source { - color - .paint_fn(Box::new(|f: &mut fmt::Formatter<'_>| { - f.write_str(": ")?; - self.format_label(&annotation.label, f) - })) - .fmt(f)?; + write!(f, "{}", color.render())?; + f.write_str(": ")?; + self.format_label(&annotation.label, f)?; + write!(f, "{}", color.render_reset())?; } else { f.write_str(": ")?; self.format_label(&annotation.label, f)?; @@ -361,25 +363,21 @@ impl<'a> DisplayList<'a> { _ => range.0, }; - color - .paint_fn(|f| { - format_repeat_char(indent_char, indent_length + 1, f)?; - format_repeat_char(mark, range.1 - indent_length, f) - }) - .fmt(f)?; + write!(f, "{}", color.render())?; + format_repeat_char(indent_char, indent_length + 1, f)?; + format_repeat_char(mark, range.1 - indent_length, f)?; + write!(f, "{}", color.render_reset())?; if !is_annotation_empty(annotation) { f.write_char(' ')?; - color - .paint_fn(|f| { - self.format_annotation( - annotation, - annotation_part == &DisplayAnnotationPart::LabelContinuation, - true, - f, - ) - }) - .fmt(f)?; + write!(f, "{}", color.render())?; + self.format_annotation( + annotation, + annotation_part == &DisplayAnnotationPart::LabelContinuation, + true, + f, + )?; + write!(f, "{}", color.render_reset())?; } Ok(()) @@ -408,7 +406,13 @@ impl<'a> DisplayList<'a> { if let Some((col, row)) = pos { format_repeat_char(' ', lineno_width, f)?; - lineno_color.paint(header_sigil).fmt(f)?; + write!( + f, + "{}{}{}", + lineno_color.render(), + header_sigil, + lineno_color.render_reset() + )?; f.write_char(' ')?; path.fmt(f)?; f.write_char(':')?; @@ -417,7 +421,13 @@ impl<'a> DisplayList<'a> { row.fmt(f) } else { format_repeat_char(' ', lineno_width, f)?; - lineno_color.paint(header_sigil).fmt(f)?; + write!( + f, + "{}{}{}", + lineno_color.render(), + header_sigil, + lineno_color.render_reset() + )?; f.write_char(' ')?; path.fmt(f) } @@ -434,7 +444,12 @@ impl<'a> DisplayList<'a> { let lineno_color = self.stylesheet.line_no(); format_repeat_char(' ', lineno_width, f)?; f.write_char(' ')?; - lineno_color.paint("=").fmt(f)?; + write!( + f, + "{}={}", + lineno_color.render(), + lineno_color.render_reset() + )?; f.write_char(' ')?; } } @@ -459,22 +474,18 @@ impl<'a> DisplayList<'a> { } => { let lineno_color = self.stylesheet.line_no(); if self.anonymized_line_numbers && lineno.is_some() { - lineno_color - .paint_fn(Box::new(|f: &mut fmt::Formatter<'_>| { - f.write_str(Self::ANONYMIZED_LINE_NUM)?; - f.write_str(" |") - })) - .fmt(f)?; + write!(f, "{}", lineno_color.render())?; + f.write_str(Self::ANONYMIZED_LINE_NUM)?; + f.write_str(" |")?; + write!(f, "{}", lineno_color.render_reset())?; } else { - lineno_color - .paint_fn(Box::new(|f: &mut fmt::Formatter<'_>| { - match lineno { - Some(n) => write!(f, "{:>width$}", n, width = lineno_width), - None => format_repeat_char(' ', lineno_width, f), - }?; - f.write_str(" |") - })) - .fmt(f)?; + write!(f, "{}", lineno_color.render())?; + match lineno { + Some(n) => write!(f, "{:>width$}", n, width = lineno_width), + None => format_repeat_char(' ', lineno_width, f), + }?; + f.write_str(" |")?; + write!(f, "{}", lineno_color.render_reset())?; } if *line != DisplaySourceLine::Empty { if !inline_marks.is_empty() || 0 < inline_marks_width { @@ -508,14 +519,13 @@ impl<'a> DisplayList<'a> { ) -> fmt::Result { format_repeat_char(' ', inline_marks_width - inline_marks.len(), f)?; for mark in inline_marks { - self.get_annotation_style(&mark.annotation_type) - .paint_fn(Box::new(|f: &mut fmt::Formatter<'_>| { - f.write_char(match mark.mark_type { - DisplayMarkType::AnnotationThrough => '|', - DisplayMarkType::AnnotationStart => '/', - }) - })) - .fmt(f)?; + let annotation_style = self.get_annotation_style(&mark.annotation_type); + write!(f, "{}", annotation_style.render())?; + f.write_char(match mark.mark_type { + DisplayMarkType::AnnotationThrough => '|', + DisplayMarkType::AnnotationStart => '/', + })?; + write!(f, "{}", annotation_style.render_reset())?; } Ok(()) } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index a79d8d2b..5b6d55be 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -2,10 +2,9 @@ pub mod stylesheet; use crate::display_list::{DisplayList, Margin}; use crate::snippet::Snippet; +pub use anstyle::*; use std::fmt::Display; use stylesheet::Stylesheet; -use yansi_term::Color::Fixed; -use yansi_term::Style; #[derive(Clone)] pub struct Renderer { @@ -28,13 +27,13 @@ impl Renderer { pub fn styled() -> Self { Self { stylesheet: Stylesheet { - error: Fixed(9).bold(), - warning: Fixed(11).bold(), - info: Fixed(12).bold(), - note: Style::new().bold(), - help: Fixed(14).bold(), - line_no: Fixed(12).bold(), - emphasis: Style::new().bold(), + error: AnsiColor::BrightRed.on_default().effects(Effects::BOLD), + warning: AnsiColor::BrightYellow.on_default().effects(Effects::BOLD), + info: AnsiColor::BrightBlue.on_default().effects(Effects::BOLD), + note: Style::new().effects(Effects::BOLD), + help: AnsiColor::BrightCyan.on_default().effects(Effects::BOLD), + line_no: AnsiColor::BrightBlue.on_default().effects(Effects::BOLD), + emphasis: Style::new().effects(Effects::BOLD), none: Style::new(), }, ..Self::plain() diff --git a/src/renderer/stylesheet.rs b/src/renderer/stylesheet.rs index f52c1396..899d9a76 100644 --- a/src/renderer/stylesheet.rs +++ b/src/renderer/stylesheet.rs @@ -1,4 +1,4 @@ -use yansi_term::Style; +use anstyle::Style; #[derive(Clone, Copy, Debug)] pub struct Stylesheet { diff --git a/tests/diff/mod.rs b/tests/diff/mod.rs index 576c6c4d..60ccae19 100644 --- a/tests/diff/mod.rs +++ b/tests/diff/mod.rs @@ -1,6 +1,7 @@ +use annotate_snippets::renderer::{AnsiColor, Color, Style}; use difference::{Changeset, Difference}; -use yansi_term::Color::{Black, Green, Red}; +const GREEN: Style = AnsiColor::Green.on_default(); pub fn get_diff(left: &str, right: &str) -> String { let mut output = String::new(); @@ -14,15 +15,28 @@ pub fn get_diff(left: &str, right: &str) -> String { Difference::Add(ref x) => { match diffs[i - 1] { Difference::Rem(ref y) => { - output += &format!("{}", Green.paint("+")); + output += &format!("{}+{}", GREEN.render(), GREEN.render_reset()); let Changeset { diffs, .. } = Changeset::new(y, x, " "); for c in diffs { match c { Difference::Same(ref z) => { - output += &format!("{} ", Green.paint(z.as_str())); + output += &format!( + "{}{}{} ", + GREEN.render(), + z.as_str(), + GREEN.render_reset() + ); } Difference::Add(ref z) => { - output += &format!("{} ", Black.on(Green).paint(z.as_str())); + let black_on_green = Style::new() + .bg_color(Some(Color::Ansi(AnsiColor::Green))) + .fg_color(Some(Color::Ansi(AnsiColor::Black))); + output += &format!( + "{}{}{} ", + black_on_green.render(), + z.as_str(), + black_on_green.render_reset() + ); } _ => (), } @@ -30,12 +44,18 @@ pub fn get_diff(left: &str, right: &str) -> String { output += "\n"; } _ => { - output += &format!("+{}\n", Green.paint(x.as_str())); + output += &format!( + "+{}{}{}\n", + GREEN.render(), + x.as_str(), + GREEN.render_reset() + ); } }; } Difference::Rem(ref x) => { - output += &format!("-{}\n", Red.paint(x.as_str())); + let red = AnsiColor::Red.on_default(); + output += &format!("-{}{}{}\n", red.render(), x.as_str(), red.render_reset()); } } } From 79f657ea252c3c0ce55fa69894ee520f8820b4bf Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 2 Dec 2023 13:57:04 -0700 Subject: [PATCH 05/12] fix!: Move `Margin` to `renderer` --- src/display_list/mod.rs | 117 +------------------------------------- src/renderer/margin.rs | 119 +++++++++++++++++++++++++++++++++++++++ src/renderer/mod.rs | 4 +- tests/deserialize/mod.rs | 2 +- 4 files changed, 124 insertions(+), 118 deletions(-) create mode 100644 src/renderer/margin.rs diff --git a/src/display_list/mod.rs b/src/display_list/mod.rs index b07d2506..d9b7f34e 100644 --- a/src/display_list/mod.rs +++ b/src/display_list/mod.rs @@ -32,11 +32,10 @@ //! //! The above snippet has been built out of the following structure: use crate::snippet; -use std::cmp::{max, min}; use std::fmt::{Display, Write}; use std::{cmp, fmt}; -use crate::renderer::{stylesheet::Stylesheet, Style}; +use crate::renderer::{stylesheet::Stylesheet, Margin, Style}; /// List of lines to be displayed. pub struct DisplayList<'a> { @@ -531,120 +530,6 @@ impl<'a> DisplayList<'a> { } } -#[derive(Clone, Copy, Debug)] -pub struct Margin { - /// The available whitespace in the left that can be consumed when centering. - whitespace_left: usize, - /// The column of the beginning of left-most span. - span_left: usize, - /// The column of the end of right-most span. - span_right: usize, - /// The beginning of the line to be displayed. - computed_left: usize, - /// The end of the line to be displayed. - computed_right: usize, - /// The current width of the terminal. 140 by default and in tests. - column_width: usize, - /// The end column of a span label, including the span. Doesn't account for labels not in the - /// same line as the span. - label_right: usize, -} - -impl Margin { - pub fn new( - whitespace_left: usize, - span_left: usize, - span_right: usize, - label_right: usize, - column_width: usize, - max_line_len: usize, - ) -> Self { - // The 6 is padding to give a bit of room for `...` when displaying: - // ``` - // error: message - // --> file.rs:16:58 - // | - // 16 | ... fn foo(self) -> Self::Bar { - // | ^^^^^^^^^ - // ``` - - let mut m = Margin { - whitespace_left: whitespace_left.saturating_sub(6), - span_left: span_left.saturating_sub(6), - span_right: span_right + 6, - computed_left: 0, - computed_right: 0, - column_width, - label_right: label_right + 6, - }; - m.compute(max_line_len); - m - } - - pub(crate) fn was_cut_left(&self) -> bool { - self.computed_left > 0 - } - - pub(crate) fn was_cut_right(&self, line_len: usize) -> bool { - let right = - if self.computed_right == self.span_right || self.computed_right == self.label_right { - // Account for the "..." padding given above. Otherwise we end up with code lines that - // do fit but end in "..." as if they were trimmed. - self.computed_right - 6 - } else { - self.computed_right - }; - right < line_len && self.computed_left + self.column_width < line_len - } - - fn compute(&mut self, max_line_len: usize) { - // When there's a lot of whitespace (>20), we want to trim it as it is useless. - self.computed_left = if self.whitespace_left > 20 { - self.whitespace_left - 16 // We want some padding. - } else { - 0 - }; - // We want to show as much as possible, max_line_len is the right-most boundary for the - // relevant code. - self.computed_right = max(max_line_len, self.computed_left); - - if self.computed_right - self.computed_left > self.column_width { - // Trimming only whitespace isn't enough, let's get craftier. - if self.label_right - self.whitespace_left <= self.column_width { - // Attempt to fit the code window only trimming whitespace. - self.computed_left = self.whitespace_left; - self.computed_right = self.computed_left + self.column_width; - } else if self.label_right - self.span_left <= self.column_width { - // Attempt to fit the code window considering only the spans and labels. - let padding_left = (self.column_width - (self.label_right - self.span_left)) / 2; - self.computed_left = self.span_left.saturating_sub(padding_left); - self.computed_right = self.computed_left + self.column_width; - } else if self.span_right - self.span_left <= self.column_width { - // Attempt to fit the code window considering the spans and labels plus padding. - let padding_left = (self.column_width - (self.span_right - self.span_left)) / 5 * 2; - self.computed_left = self.span_left.saturating_sub(padding_left); - self.computed_right = self.computed_left + self.column_width; - } else { - // Mostly give up but still don't show the full line. - self.computed_left = self.span_left; - self.computed_right = self.span_right; - } - } - } - - pub(crate) fn left(&self, line_len: usize) -> usize { - min(self.computed_left, line_len) - } - - pub(crate) fn right(&self, line_len: usize) -> usize { - if line_len.saturating_sub(self.computed_left) <= self.column_width { - line_len - } else { - min(line_len, self.computed_right) - } - } -} - /// Inline annotation which can be used in either Raw or Source line. #[derive(Debug, PartialEq)] pub struct Annotation<'a> { diff --git a/src/renderer/margin.rs b/src/renderer/margin.rs new file mode 100644 index 00000000..361f5f36 --- /dev/null +++ b/src/renderer/margin.rs @@ -0,0 +1,119 @@ +use std::cmp::{max, min}; + +const ELLIPSIS_PASSING: usize = 6; +const LONG_WHITESPACE: usize = 20; +const LONG_WHITESPACE_PADDING: usize = 4; + +#[derive(Clone, Copy, Debug)] +pub struct Margin { + /// The available whitespace in the left that can be consumed when centering. + whitespace_left: usize, + /// The column of the beginning of left-most span. + span_left: usize, + /// The column of the end of right-most span. + span_right: usize, + /// The beginning of the line to be displayed. + computed_left: usize, + /// The end of the line to be displayed. + computed_right: usize, + /// The current width of the terminal. 140 by default and in tests. + column_width: usize, + /// The end column of a span label, including the span. Doesn't account for labels not in the + /// same line as the span. + label_right: usize, +} + +impl Margin { + pub fn new( + whitespace_left: usize, + span_left: usize, + span_right: usize, + label_right: usize, + column_width: usize, + max_line_len: usize, + ) -> Self { + // The 6 is padding to give a bit of room for `...` when displaying: + // ``` + // error: message + // --> file.rs:16:58 + // | + // 16 | ... fn foo(self) -> Self::Bar { + // | ^^^^^^^^^ + // ``` + + let mut m = Margin { + whitespace_left: whitespace_left.saturating_sub(ELLIPSIS_PASSING), + span_left: span_left.saturating_sub(ELLIPSIS_PASSING), + span_right: span_right + ELLIPSIS_PASSING, + computed_left: 0, + computed_right: 0, + column_width, + label_right: label_right + ELLIPSIS_PASSING, + }; + m.compute(max_line_len); + m + } + + pub(crate) fn was_cut_left(&self) -> bool { + self.computed_left > 0 + } + + pub(crate) fn was_cut_right(&self, line_len: usize) -> bool { + let right = + if self.computed_right == self.span_right || self.computed_right == self.label_right { + // Account for the "..." padding given above. Otherwise we end up with code lines that + // do fit but end in "..." as if they were trimmed. + self.computed_right - ELLIPSIS_PASSING + } else { + self.computed_right + }; + right < line_len && self.computed_left + self.column_width < line_len + } + + fn compute(&mut self, max_line_len: usize) { + // When there's a lot of whitespace (>20), we want to trim it as it is useless. + self.computed_left = if self.whitespace_left > LONG_WHITESPACE { + self.whitespace_left - (LONG_WHITESPACE - LONG_WHITESPACE_PADDING) // We want some padding. + } else { + 0 + }; + // We want to show as much as possible, max_line_len is the right-most boundary for the + // relevant code. + self.computed_right = max(max_line_len, self.computed_left); + + if self.computed_right - self.computed_left > self.column_width { + // Trimming only whitespace isn't enough, let's get craftier. + if self.label_right - self.whitespace_left <= self.column_width { + // Attempt to fit the code window only trimming whitespace. + self.computed_left = self.whitespace_left; + self.computed_right = self.computed_left + self.column_width; + } else if self.label_right - self.span_left <= self.column_width { + // Attempt to fit the code window considering only the spans and labels. + let padding_left = (self.column_width - (self.label_right - self.span_left)) / 2; + self.computed_left = self.span_left.saturating_sub(padding_left); + self.computed_right = self.computed_left + self.column_width; + } else if self.span_right - self.span_left <= self.column_width { + // Attempt to fit the code window considering the spans and labels plus padding. + let padding_left = (self.column_width - (self.span_right - self.span_left)) / 5 * 2; + self.computed_left = self.span_left.saturating_sub(padding_left); + self.computed_right = self.computed_left + self.column_width; + } else { + // Mostly give up but still don't show the full line. + self.computed_left = self.span_left; + self.computed_right = self.span_right; + } + } + } + + pub(crate) fn left(&self, line_len: usize) -> usize { + min(self.computed_left, line_len) + } + + pub(crate) fn right(&self, line_len: usize) -> usize { + if line_len.saturating_sub(self.computed_left) <= self.column_width { + line_len + } else { + min(line_len, self.computed_right) + } + } +} diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 5b6d55be..712d2039 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,8 +1,10 @@ +mod margin; pub mod stylesheet; -use crate::display_list::{DisplayList, Margin}; +use crate::display_list::DisplayList; use crate::snippet::Snippet; pub use anstyle::*; +pub use margin::Margin; use std::fmt::Display; use stylesheet::Stylesheet; diff --git a/tests/deserialize/mod.rs b/tests/deserialize/mod.rs index 58d14ef0..af959cbf 100644 --- a/tests/deserialize/mod.rs +++ b/tests/deserialize/mod.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Deserializer, Serialize}; use annotate_snippets::renderer::Renderer; use annotate_snippets::{ - display_list::Margin, + renderer::Margin, snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, }; From da45f4858af3ec4c0d792ecc40225e27fdd2bac8 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 2 Dec 2023 14:04:43 -0700 Subject: [PATCH 06/12] fix!: Make `display_list` private --- src/display_list/mod.rs | 899 ++++++++++++++++++++++++++++++++++++- src/lib.rs | 21 +- src/renderer/mod.rs | 2 +- src/renderer/stylesheet.rs | 2 +- tests/dl_from_snippet.rs | 391 ---------------- tests/formatter.rs | 518 --------------------- 6 files changed, 903 insertions(+), 930 deletions(-) delete mode 100644 tests/dl_from_snippet.rs diff --git a/src/display_list/mod.rs b/src/display_list/mod.rs index d9b7f34e..da1a05b2 100644 --- a/src/display_list/mod.rs +++ b/src/display_list/mod.rs @@ -38,7 +38,7 @@ use std::{cmp, fmt}; use crate::renderer::{stylesheet::Stylesheet, Margin, Style}; /// List of lines to be displayed. -pub struct DisplayList<'a> { +pub(crate) struct DisplayList<'a> { pub body: Vec>, pub stylesheet: Stylesheet, pub anonymized_line_numbers: bool, @@ -343,7 +343,6 @@ impl<'a> DisplayList<'a> { let indent_char = match annotation_part { DisplayAnnotationPart::Standalone => ' ', DisplayAnnotationPart::LabelContinuation => ' ', - DisplayAnnotationPart::Consequitive => ' ', DisplayAnnotationPart::MultilineStart => '_', DisplayAnnotationPart::MultilineEnd => '_', }; @@ -358,7 +357,6 @@ impl<'a> DisplayList<'a> { let color = self.get_annotation_style(annotation_type); let indent_length = match annotation_part { DisplayAnnotationPart::LabelContinuation => range.1, - DisplayAnnotationPart::Consequitive => range.1, _ => range.0, }; @@ -626,8 +624,6 @@ pub enum DisplayAnnotationPart { Standalone, /// A continuation of a multi-line label of an annotation. LabelContinuation, - /// A consequitive annotation in case multiple annotations annotate a single line. - Consequitive, /// A line starting a multiline annotation. MultilineStart, /// A line ending a multiline annotation. @@ -1228,3 +1224,896 @@ fn is_annotation_empty(annotation: &Annotation<'_>) -> bool { .iter() .all(|fragment| fragment.content.is_empty()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_format_title() { + let input = snippet::Snippet { + title: Some(snippet::Annotation { + id: Some("E0001"), + label: Some("This is a title"), + annotation_type: snippet::AnnotationType::Error, + }), + footer: vec![], + slices: vec![], + }; + let output = DisplayList { + body: vec![DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Error, + id: Some("E0001"), + label: vec![DisplayTextFragment { + content: "This is a title", + style: DisplayTextStyle::Emphasis, + }], + }, + source_aligned: false, + continuation: false, + })], + stylesheet: Stylesheet::default(), + anonymized_line_numbers: false, + margin: None, + }; + assert_eq!(DisplayList::from(input), output); + } + + #[test] + fn test_format_slice() { + let line_1 = "This is line 1"; + let line_2 = "This is line 2"; + let source = [line_1, line_2].join("\n"); + let input = snippet::Snippet { + title: None, + footer: vec![], + slices: vec![snippet::Slice { + source: &source, + line_start: 5402, + origin: None, + annotations: vec![], + fold: false, + }], + }; + let output = DisplayList { + body: vec![ + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + DisplayLine::Source { + lineno: Some(5402), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: line_1, + range: (0, line_1.len()), + }, + }, + DisplayLine::Source { + lineno: Some(5403), + inline_marks: vec![], + line: DisplaySourceLine::Content { + range: (line_1.len() + 1, source.len()), + text: line_2, + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + ], + stylesheet: Stylesheet::default(), + anonymized_line_numbers: false, + margin: None, + }; + assert_eq!(DisplayList::from(input), output); + } + + #[test] + fn test_format_slices_continuation() { + let src_0 = "This is slice 1"; + let src_0_len = src_0.len(); + let src_1 = "This is slice 2"; + let src_1_len = src_1.len(); + let input = snippet::Snippet { + title: None, + footer: vec![], + slices: vec![ + snippet::Slice { + source: src_0, + line_start: 5402, + origin: Some("file1.rs"), + annotations: vec![], + fold: false, + }, + snippet::Slice { + source: src_1, + line_start: 2, + origin: Some("file2.rs"), + annotations: vec![], + fold: false, + }, + ], + }; + let output = DisplayList { + body: vec![ + DisplayLine::Raw(DisplayRawLine::Origin { + path: "file1.rs", + pos: None, + header_type: DisplayHeaderType::Initial, + }), + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + DisplayLine::Source { + lineno: Some(5402), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: src_0, + range: (0, src_0_len), + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + DisplayLine::Raw(DisplayRawLine::Origin { + path: "file2.rs", + pos: None, + header_type: DisplayHeaderType::Continuation, + }), + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + DisplayLine::Source { + lineno: Some(2), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: src_1, + range: (0, src_1_len), + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + ], + stylesheet: Stylesheet::default(), + anonymized_line_numbers: false, + margin: None, + }; + assert_eq!(DisplayList::from(input), output); + } + + #[test] + fn test_format_slice_annotation_standalone() { + let line_1 = "This is line 1"; + let line_2 = "This is line 2"; + let source = [line_1, line_2].join("\n"); + // In line 2 + let range = (22, 24); + let input = snippet::Snippet { + title: None, + footer: vec![], + slices: vec![snippet::Slice { + source: &source, + line_start: 5402, + origin: None, + annotations: vec![snippet::SourceAnnotation { + range, + label: "Test annotation", + annotation_type: snippet::AnnotationType::Info, + }], + fold: false, + }], + }; + let output = DisplayList { + body: vec![ + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + DisplayLine::Source { + lineno: Some(5402), + inline_marks: vec![], + line: DisplaySourceLine::Content { + range: (0, line_1.len()), + text: line_1, + }, + }, + DisplayLine::Source { + lineno: Some(5403), + inline_marks: vec![], + line: DisplaySourceLine::Content { + range: (line_1.len() + 1, source.len()), + text: line_2, + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Info, + id: None, + label: vec![DisplayTextFragment { + content: "Test annotation", + style: DisplayTextStyle::Regular, + }], + }, + range: (range.0 - (line_1.len() + 1), range.1 - (line_1.len() + 1)), + annotation_type: DisplayAnnotationType::Info, + annotation_part: DisplayAnnotationPart::Standalone, + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + ], + stylesheet: Stylesheet::default(), + anonymized_line_numbers: false, + margin: None, + }; + assert_eq!(DisplayList::from(input), output); + } + + #[test] + fn test_format_label() { + let input = snippet::Snippet { + title: None, + footer: vec![snippet::Annotation { + id: None, + label: Some("This __is__ a title"), + annotation_type: snippet::AnnotationType::Error, + }], + slices: vec![], + }; + let output = DisplayList { + body: vec![DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Error, + id: None, + label: vec![DisplayTextFragment { + content: "This __is__ a title", + style: DisplayTextStyle::Regular, + }], + }, + source_aligned: true, + continuation: false, + })], + stylesheet: Stylesheet::default(), + anonymized_line_numbers: false, + margin: None, + }; + assert_eq!(DisplayList::from(input), output); + } + + #[test] + #[should_panic] + fn test_i26() { + let source = "short"; + let label = "label"; + let input = snippet::Snippet { + title: None, + footer: vec![], + slices: vec![snippet::Slice { + annotations: vec![snippet::SourceAnnotation { + range: (0, source.len() + 1), + label, + annotation_type: snippet::AnnotationType::Error, + }], + source, + line_start: 0, + origin: None, + fold: false, + }], + }; + + let _ = DisplayList::from(input); + } + + #[test] + fn test_i_29() { + let snippets = snippet::Snippet { + title: Some(snippet::Annotation { + id: None, + label: Some("oops"), + annotation_type: snippet::AnnotationType::Error, + }), + footer: vec![], + slices: vec![snippet::Slice { + source: "First line\r\nSecond oops line", + line_start: 1, + origin: Some(""), + annotations: vec![snippet::SourceAnnotation { + range: (19, 23), + label: "oops", + annotation_type: snippet::AnnotationType::Error, + }], + fold: true, + }], + }; + + let expected = DisplayList { + body: vec![ + DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Error, + id: None, + label: vec![DisplayTextFragment { + content: "oops", + style: DisplayTextStyle::Emphasis, + }], + }, + source_aligned: false, + continuation: false, + }), + DisplayLine::Raw(DisplayRawLine::Origin { + path: "", + pos: Some((2, 8)), + header_type: DisplayHeaderType::Initial, + }), + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + DisplayLine::Source { + lineno: Some(1), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: "First line", + range: (0, 10), + }, + }, + DisplayLine::Source { + lineno: Some(2), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: "Second oops line", + range: (12, 28), + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::None, + id: None, + label: vec![DisplayTextFragment { + content: "oops", + style: DisplayTextStyle::Regular, + }], + }, + range: (7, 11), + annotation_type: DisplayAnnotationType::Error, + annotation_part: DisplayAnnotationPart::Standalone, + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + ], + stylesheet: Stylesheet::default(), + anonymized_line_numbers: false, + margin: None, + }; + + assert_eq!(DisplayList::from(snippets), expected); + } + + #[test] + fn test_source_empty() { + let dl = DisplayList::from(vec![DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }]); + + assert_eq!(dl.to_string(), " |"); + } + + #[test] + fn test_source_content() { + let dl = DisplayList::from(vec![ + DisplayLine::Source { + lineno: Some(56), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: "This is an example", + range: (0, 19), + }, + }, + DisplayLine::Source { + lineno: Some(57), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: "of content lines", + range: (0, 19), + }, + }, + ]); + + assert_eq!( + dl.to_string(), + "56 | This is an example\n57 | of content lines" + ); + } + + #[test] + fn test_source_annotation_standalone_singleline() { + let dl = DisplayList::from(vec![DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + range: (0, 5), + annotation: Annotation { + annotation_type: DisplayAnnotationType::None, + id: None, + label: vec![DisplayTextFragment { + content: "Example string", + style: DisplayTextStyle::Regular, + }], + }, + annotation_type: DisplayAnnotationType::Error, + annotation_part: DisplayAnnotationPart::Standalone, + }, + }]); + + assert_eq!(dl.to_string(), " | ^^^^^ Example string"); + } + + #[test] + fn test_source_annotation_standalone_multiline() { + let dl = DisplayList::from(vec![ + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + range: (0, 5), + annotation: Annotation { + annotation_type: DisplayAnnotationType::Help, + id: None, + label: vec![DisplayTextFragment { + content: "Example string", + style: DisplayTextStyle::Regular, + }], + }, + annotation_type: DisplayAnnotationType::Warning, + annotation_part: DisplayAnnotationPart::Standalone, + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + range: (0, 5), + annotation: Annotation { + annotation_type: DisplayAnnotationType::Help, + id: None, + label: vec![DisplayTextFragment { + content: "Second line", + style: DisplayTextStyle::Regular, + }], + }, + annotation_type: DisplayAnnotationType::Warning, + annotation_part: DisplayAnnotationPart::LabelContinuation, + }, + }, + ]); + + assert_eq!( + dl.to_string(), + " | ----- help: Example string\n | Second line" + ); + } + + #[test] + fn test_source_annotation_standalone_multi_annotation() { + let dl = DisplayList::from(vec![ + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + range: (0, 5), + annotation: Annotation { + annotation_type: DisplayAnnotationType::Info, + id: None, + label: vec![DisplayTextFragment { + content: "Example string", + style: DisplayTextStyle::Regular, + }], + }, + annotation_type: DisplayAnnotationType::Note, + annotation_part: DisplayAnnotationPart::Standalone, + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + range: (0, 5), + annotation: Annotation { + annotation_type: DisplayAnnotationType::Info, + id: None, + label: vec![DisplayTextFragment { + content: "Second line", + style: DisplayTextStyle::Regular, + }], + }, + annotation_type: DisplayAnnotationType::Note, + annotation_part: DisplayAnnotationPart::LabelContinuation, + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + range: (0, 5), + annotation: Annotation { + annotation_type: DisplayAnnotationType::Warning, + id: None, + label: vec![DisplayTextFragment { + content: "Second line of the warning", + style: DisplayTextStyle::Regular, + }], + }, + annotation_type: DisplayAnnotationType::Note, + annotation_part: DisplayAnnotationPart::LabelContinuation, + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + range: (0, 5), + annotation: Annotation { + annotation_type: DisplayAnnotationType::Info, + id: None, + label: vec![DisplayTextFragment { + content: "This is an info", + style: DisplayTextStyle::Regular, + }], + }, + annotation_type: DisplayAnnotationType::Info, + annotation_part: DisplayAnnotationPart::Standalone, + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + range: (0, 5), + annotation: Annotation { + annotation_type: DisplayAnnotationType::Help, + id: None, + label: vec![DisplayTextFragment { + content: "This is help", + style: DisplayTextStyle::Regular, + }], + }, + annotation_type: DisplayAnnotationType::Help, + annotation_part: DisplayAnnotationPart::Standalone, + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + range: (0, 0), + annotation: Annotation { + annotation_type: DisplayAnnotationType::None, + id: None, + label: vec![DisplayTextFragment { + content: "This is an annotation of type none", + style: DisplayTextStyle::Regular, + }], + }, + annotation_type: DisplayAnnotationType::None, + annotation_part: DisplayAnnotationPart::Standalone, + }, + }, + ]); + + assert_eq!(dl.to_string(), " | ----- info: Example string\n | Second line\n | Second line of the warning\n | ----- info: This is an info\n | ----- help: This is help\n | This is an annotation of type none"); + } + + #[test] + fn test_fold_line() { + let dl = DisplayList::from(vec![ + DisplayLine::Source { + lineno: Some(5), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: "This is line 5", + range: (0, 19), + }, + }, + DisplayLine::Fold { + inline_marks: vec![], + }, + DisplayLine::Source { + lineno: Some(10021), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: "... and now we're at line 10021", + range: (0, 19), + }, + }, + ]); + + assert_eq!( + dl.to_string(), + " 5 | This is line 5\n...\n10021 | ... and now we're at line 10021" + ); + } + + #[test] + fn test_raw_origin_initial_nopos() { + let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { + path: "src/test.rs", + pos: None, + header_type: DisplayHeaderType::Initial, + })]); + + assert_eq!(dl.to_string(), "--> src/test.rs"); + } + + #[test] + fn test_raw_origin_initial_pos() { + let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { + path: "src/test.rs", + pos: Some((23, 15)), + header_type: DisplayHeaderType::Initial, + })]); + + assert_eq!(dl.to_string(), "--> src/test.rs:23:15"); + } + + #[test] + fn test_raw_origin_continuation() { + let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { + path: "src/test.rs", + pos: Some((23, 15)), + header_type: DisplayHeaderType::Continuation, + })]); + + assert_eq!(dl.to_string(), "::: src/test.rs:23:15"); + } + + #[test] + fn test_raw_annotation_unaligned() { + let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Error, + id: Some("E0001"), + label: vec![DisplayTextFragment { + content: "This is an error", + style: DisplayTextStyle::Regular, + }], + }, + source_aligned: false, + continuation: false, + })]); + + assert_eq!(dl.to_string(), "error[E0001]: This is an error"); + } + + #[test] + fn test_raw_annotation_unaligned_multiline() { + let dl = DisplayList::from(vec![ + DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Warning, + id: Some("E0001"), + label: vec![DisplayTextFragment { + content: "This is an error", + style: DisplayTextStyle::Regular, + }], + }, + source_aligned: false, + continuation: false, + }), + DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Warning, + id: Some("E0001"), + label: vec![DisplayTextFragment { + content: "Second line of the error", + style: DisplayTextStyle::Regular, + }], + }, + source_aligned: false, + continuation: true, + }), + ]); + + assert_eq!( + dl.to_string(), + "warning[E0001]: This is an error\n Second line of the error" + ); + } + + #[test] + fn test_raw_annotation_aligned() { + let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Error, + id: Some("E0001"), + label: vec![DisplayTextFragment { + content: "This is an error", + style: DisplayTextStyle::Regular, + }], + }, + source_aligned: true, + continuation: false, + })]); + + assert_eq!(dl.to_string(), " = error[E0001]: This is an error"); + } + + #[test] + fn test_raw_annotation_aligned_multiline() { + let dl = DisplayList::from(vec![ + DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Warning, + id: Some("E0001"), + label: vec![DisplayTextFragment { + content: "This is an error", + style: DisplayTextStyle::Regular, + }], + }, + source_aligned: true, + continuation: false, + }), + DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Warning, + id: Some("E0001"), + label: vec![DisplayTextFragment { + content: "Second line of the error", + style: DisplayTextStyle::Regular, + }], + }, + source_aligned: true, + continuation: true, + }), + ]); + + assert_eq!( + dl.to_string(), + " = warning[E0001]: This is an error\n Second line of the error" + ); + } + + #[test] + fn test_different_annotation_types() { + let dl = DisplayList::from(vec![ + DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Note, + id: None, + label: vec![DisplayTextFragment { + content: "This is a note", + style: DisplayTextStyle::Regular, + }], + }, + source_aligned: false, + continuation: false, + }), + DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::None, + id: None, + label: vec![DisplayTextFragment { + content: "This is just a string", + style: DisplayTextStyle::Regular, + }], + }, + source_aligned: false, + continuation: false, + }), + DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::None, + id: None, + label: vec![DisplayTextFragment { + content: "Second line of none type annotation", + style: DisplayTextStyle::Regular, + }], + }, + source_aligned: false, + continuation: true, + }), + ]); + + assert_eq!( + dl.to_string(), + "note: This is a note\nThis is just a string\n Second line of none type annotation", + ); + } + + #[test] + fn test_inline_marks_empty_line() { + let dl = DisplayList::from(vec![DisplayLine::Source { + lineno: None, + inline_marks: vec![DisplayMark { + mark_type: DisplayMarkType::AnnotationThrough, + annotation_type: DisplayAnnotationType::Error, + }], + line: DisplaySourceLine::Empty, + }]); + + assert_eq!(dl.to_string(), " | |",); + } + + #[test] + fn test_anon_lines() { + let mut dl = DisplayList::from(vec![ + DisplayLine::Source { + lineno: Some(56), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: "This is an example", + range: (0, 19), + }, + }, + DisplayLine::Source { + lineno: Some(57), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: "of content lines", + range: (0, 19), + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: "abc", + range: (0, 19), + }, + }, + ]); + + dl.anonymized_line_numbers = true; + assert_eq!( + dl.to_string(), + "LL | This is an example\nLL | of content lines\n |\n | abc" + ); + } + + #[test] + fn test_raw_origin_initial_pos_anon_lines() { + let mut dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { + path: "src/test.rs", + pos: Some((23, 15)), + header_type: DisplayHeaderType::Initial, + })]); + + // Using anonymized_line_numbers should not affect the initial position + dl.anonymized_line_numbers = true; + assert_eq!(dl.to_string(), "--> src/test.rs:23:15"); + } +} diff --git a/src/lib.rs b/src/lib.rs index bf0dc058..342db23c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,28 +26,21 @@ //! The crate uses a three stage process with two conversions between states: //! //! ```text -//! Snippet --> DisplayList --> String +//! Snippet --> Renderer --> impl Display //! ``` //! //! The input type - [Snippet](self::snippet) is a structure designed //! to align with likely output from any parser whose code snippet is to be //! annotated. //! -//! The middle structure - [DisplayList](self::display_list) is a -//! structure designed to store the snippet data converted into a vector -//! of lines containing semantic information about each line. -//! This structure is the easiest to manipulate and organize. +//! The middle structure - [Renderer](self::renderer) is a structure designed +//! to convert a snippet into an internal structure that is designed to store +//! the snippet data in a way that is easy to format. +//! [Renderer](self::renderer) also handles the user-configurable formatting +//! options, such as color, or margins. //! //! Finally, `impl Display` into a final `String` output. -//! -//! A user of the crate may choose to provide their own equivalent of the input -//! structure with an `Into` trait. -//! -//! A user of the crate may also choose to provide their own formatter logic, -//! to convert a `DisplayList` into a `String`, or just a `Stylesheet` to -//! use the crate's formatting logic, but with a custom stylesheet. -// TODO: check documentation -pub mod display_list; +mod display_list; pub mod renderer; pub mod snippet; diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 712d2039..2f033418 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,5 +1,5 @@ mod margin; -pub mod stylesheet; +pub(crate) mod stylesheet; use crate::display_list::DisplayList; use crate::snippet::Snippet; diff --git a/src/renderer/stylesheet.rs b/src/renderer/stylesheet.rs index 899d9a76..b3dbbc3d 100644 --- a/src/renderer/stylesheet.rs +++ b/src/renderer/stylesheet.rs @@ -1,7 +1,7 @@ use anstyle::Style; #[derive(Clone, Copy, Debug)] -pub struct Stylesheet { +pub(crate) struct Stylesheet { pub(crate) error: Style, pub(crate) warning: Style, pub(crate) info: Style, diff --git a/tests/dl_from_snippet.rs b/tests/dl_from_snippet.rs deleted file mode 100644 index 5fb0762d..00000000 --- a/tests/dl_from_snippet.rs +++ /dev/null @@ -1,391 +0,0 @@ -use annotate_snippets::display_list::DisplayList; -use annotate_snippets::renderer::stylesheet::Stylesheet; -use annotate_snippets::{display_list as dl, snippet}; - -#[test] -fn test_format_title() { - let input = snippet::Snippet { - title: Some(snippet::Annotation { - id: Some("E0001"), - label: Some("This is a title"), - annotation_type: snippet::AnnotationType::Error, - }), - footer: vec![], - slices: vec![], - }; - let output = dl::DisplayList { - body: vec![dl::DisplayLine::Raw(dl::DisplayRawLine::Annotation { - annotation: dl::Annotation { - annotation_type: dl::DisplayAnnotationType::Error, - id: Some("E0001"), - label: vec![dl::DisplayTextFragment { - content: "This is a title", - style: dl::DisplayTextStyle::Emphasis, - }], - }, - source_aligned: false, - continuation: false, - })], - stylesheet: Stylesheet::default(), - anonymized_line_numbers: false, - margin: None, - }; - assert_eq!(dl::DisplayList::from(input), output); -} - -#[test] -fn test_format_slice() { - let line_1 = "This is line 1"; - let line_2 = "This is line 2"; - let source = [line_1, line_2].join("\n"); - let input = snippet::Snippet { - title: None, - footer: vec![], - slices: vec![snippet::Slice { - source: &source, - line_start: 5402, - origin: None, - annotations: vec![], - fold: false, - }], - }; - let output = dl::DisplayList { - body: vec![ - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - dl::DisplayLine::Source { - lineno: Some(5402), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - text: line_1, - range: (0, line_1.len()), - }, - }, - dl::DisplayLine::Source { - lineno: Some(5403), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - range: (line_1.len() + 1, source.len()), - text: line_2, - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - ], - stylesheet: Stylesheet::default(), - anonymized_line_numbers: false, - margin: None, - }; - assert_eq!(dl::DisplayList::from(input), output); -} - -#[test] -fn test_format_slices_continuation() { - let src_0 = "This is slice 1"; - let src_0_len = src_0.len(); - let src_1 = "This is slice 2"; - let src_1_len = src_1.len(); - let input = snippet::Snippet { - title: None, - footer: vec![], - slices: vec![ - snippet::Slice { - source: src_0, - line_start: 5402, - origin: Some("file1.rs"), - annotations: vec![], - fold: false, - }, - snippet::Slice { - source: src_1, - line_start: 2, - origin: Some("file2.rs"), - annotations: vec![], - fold: false, - }, - ], - }; - let output = dl::DisplayList { - body: vec![ - dl::DisplayLine::Raw(dl::DisplayRawLine::Origin { - path: "file1.rs", - pos: None, - header_type: dl::DisplayHeaderType::Initial, - }), - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - dl::DisplayLine::Source { - lineno: Some(5402), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - text: src_0, - range: (0, src_0_len), - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - dl::DisplayLine::Raw(dl::DisplayRawLine::Origin { - path: "file2.rs", - pos: None, - header_type: dl::DisplayHeaderType::Continuation, - }), - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - dl::DisplayLine::Source { - lineno: Some(2), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - text: src_1, - range: (0, src_1_len), - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - ], - stylesheet: Stylesheet::default(), - anonymized_line_numbers: false, - margin: None, - }; - assert_eq!(dl::DisplayList::from(input), output); -} - -#[test] -fn test_format_slice_annotation_standalone() { - let line_1 = "This is line 1"; - let line_2 = "This is line 2"; - let source = [line_1, line_2].join("\n"); - // In line 2 - let range = (22, 24); - let input = snippet::Snippet { - title: None, - footer: vec![], - slices: vec![snippet::Slice { - source: &source, - line_start: 5402, - origin: None, - annotations: vec![snippet::SourceAnnotation { - range, - label: "Test annotation", - annotation_type: snippet::AnnotationType::Info, - }], - fold: false, - }], - }; - let output = dl::DisplayList { - body: vec![ - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - dl::DisplayLine::Source { - lineno: Some(5402), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - range: (0, line_1.len()), - text: line_1, - }, - }, - dl::DisplayLine::Source { - lineno: Some(5403), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - range: (line_1.len() + 1, source.len()), - text: line_2, - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Annotation { - annotation: dl::Annotation { - annotation_type: dl::DisplayAnnotationType::Info, - id: None, - label: vec![dl::DisplayTextFragment { - content: "Test annotation", - style: dl::DisplayTextStyle::Regular, - }], - }, - range: (range.0 - (line_1.len() + 1), range.1 - (line_1.len() + 1)), - annotation_type: dl::DisplayAnnotationType::Info, - annotation_part: dl::DisplayAnnotationPart::Standalone, - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - ], - stylesheet: Stylesheet::default(), - anonymized_line_numbers: false, - margin: None, - }; - assert_eq!(dl::DisplayList::from(input), output); -} - -#[test] -fn test_format_label() { - let input = snippet::Snippet { - title: None, - footer: vec![snippet::Annotation { - id: None, - label: Some("This __is__ a title"), - annotation_type: snippet::AnnotationType::Error, - }], - slices: vec![], - }; - let output = dl::DisplayList { - body: vec![dl::DisplayLine::Raw(dl::DisplayRawLine::Annotation { - annotation: dl::Annotation { - annotation_type: dl::DisplayAnnotationType::Error, - id: None, - label: vec![dl::DisplayTextFragment { - content: "This __is__ a title", - style: dl::DisplayTextStyle::Regular, - }], - }, - source_aligned: true, - continuation: false, - })], - stylesheet: Stylesheet::default(), - anonymized_line_numbers: false, - margin: None, - }; - assert_eq!(dl::DisplayList::from(input), output); -} - -#[test] -#[should_panic] -fn test_i26() { - let source = "short"; - let label = "label"; - let input = snippet::Snippet { - title: None, - footer: vec![], - slices: vec![snippet::Slice { - annotations: vec![snippet::SourceAnnotation { - range: (0, source.len() + 1), - label, - annotation_type: snippet::AnnotationType::Error, - }], - source, - line_start: 0, - origin: None, - fold: false, - }], - }; - - let _ = dl::DisplayList::from(input); -} - -#[test] -fn test_i_29() { - let snippets = snippet::Snippet { - title: Some(snippet::Annotation { - id: None, - label: Some("oops"), - annotation_type: snippet::AnnotationType::Error, - }), - footer: vec![], - slices: vec![snippet::Slice { - source: "First line\r\nSecond oops line", - line_start: 1, - origin: Some(""), - annotations: vec![snippet::SourceAnnotation { - range: (19, 23), - label: "oops", - annotation_type: snippet::AnnotationType::Error, - }], - fold: true, - }], - }; - - let expected = DisplayList { - body: vec![ - dl::DisplayLine::Raw(dl::DisplayRawLine::Annotation { - annotation: dl::Annotation { - annotation_type: dl::DisplayAnnotationType::Error, - id: None, - label: vec![dl::DisplayTextFragment { - content: "oops", - style: dl::DisplayTextStyle::Emphasis, - }], - }, - source_aligned: false, - continuation: false, - }), - dl::DisplayLine::Raw(dl::DisplayRawLine::Origin { - path: "", - pos: Some((2, 8)), - header_type: dl::DisplayHeaderType::Initial, - }), - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - dl::DisplayLine::Source { - lineno: Some(1), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - text: "First line", - range: (0, 10), - }, - }, - dl::DisplayLine::Source { - lineno: Some(2), - inline_marks: vec![], - line: dl::DisplaySourceLine::Content { - text: "Second oops line", - range: (12, 28), - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Annotation { - annotation: dl::Annotation { - annotation_type: dl::DisplayAnnotationType::None, - id: None, - label: vec![dl::DisplayTextFragment { - content: "oops", - style: dl::DisplayTextStyle::Regular, - }], - }, - range: (7, 11), - annotation_type: dl::DisplayAnnotationType::Error, - annotation_part: dl::DisplayAnnotationPart::Standalone, - }, - }, - dl::DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: dl::DisplaySourceLine::Empty, - }, - ], - stylesheet: Stylesheet::default(), - anonymized_line_numbers: false, - margin: None, - }; - - assert_eq!(DisplayList::from(snippets), expected); -} diff --git a/tests/formatter.rs b/tests/formatter.rs index 2117fec2..3f85b695 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -1,524 +1,6 @@ -use annotate_snippets::display_list::*; use annotate_snippets::renderer::Renderer; use annotate_snippets::snippet::{self, Snippet}; -#[test] -fn test_source_empty() { - let dl = DisplayList::from(vec![DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }]); - - assert_eq!(dl.to_string(), " |"); -} - -#[test] -fn test_source_content() { - let dl = DisplayList::from(vec![ - DisplayLine::Source { - lineno: Some(56), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "This is an example", - range: (0, 19), - }, - }, - DisplayLine::Source { - lineno: Some(57), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "of content lines", - range: (0, 19), - }, - }, - ]); - - assert_eq!( - dl.to_string(), - "56 | This is an example\n57 | of content lines" - ); -} - -#[test] -fn test_source_annotation_standalone_singleline() { - let dl = DisplayList::from(vec![DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::None, - id: None, - label: vec![DisplayTextFragment { - content: "Example string", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Error, - annotation_part: DisplayAnnotationPart::Standalone, - }, - }]); - - assert_eq!(dl.to_string(), " | ^^^^^ Example string"); -} - -#[test] -fn test_source_annotation_standalone_multiline() { - let dl = DisplayList::from(vec![ - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Help, - id: None, - label: vec![DisplayTextFragment { - content: "Example string", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Warning, - annotation_part: DisplayAnnotationPart::Standalone, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Help, - id: None, - label: vec![DisplayTextFragment { - content: "Second line", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Warning, - annotation_part: DisplayAnnotationPart::LabelContinuation, - }, - }, - ]); - - assert_eq!( - dl.to_string(), - " | ----- help: Example string\n | Second line" - ); -} - -#[test] -fn test_source_annotation_standalone_multi_annotation() { - let dl = DisplayList::from(vec![ - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Info, - id: None, - label: vec![DisplayTextFragment { - content: "Example string", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Note, - annotation_part: DisplayAnnotationPart::Standalone, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Info, - id: None, - label: vec![DisplayTextFragment { - content: "Second line", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Note, - annotation_part: DisplayAnnotationPart::LabelContinuation, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Warning, - id: None, - label: vec![DisplayTextFragment { - content: "This is a note", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Note, - annotation_part: DisplayAnnotationPart::Consequitive, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Warning, - id: None, - label: vec![DisplayTextFragment { - content: "Second line of the warning", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Note, - annotation_part: DisplayAnnotationPart::LabelContinuation, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Info, - id: None, - label: vec![DisplayTextFragment { - content: "This is an info", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Info, - annotation_part: DisplayAnnotationPart::Standalone, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 5), - annotation: Annotation { - annotation_type: DisplayAnnotationType::Help, - id: None, - label: vec![DisplayTextFragment { - content: "This is help", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::Help, - annotation_part: DisplayAnnotationPart::Standalone, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - range: (0, 0), - annotation: Annotation { - annotation_type: DisplayAnnotationType::None, - id: None, - label: vec![DisplayTextFragment { - content: "This is an annotation of type none", - style: DisplayTextStyle::Regular, - }], - }, - annotation_type: DisplayAnnotationType::None, - annotation_part: DisplayAnnotationPart::Standalone, - }, - }, - ]); - - assert_eq!(dl.to_string(), " | ----- info: Example string\n | Second line\n | warning: This is a note\n | Second line of the warning\n | ----- info: This is an info\n | ----- help: This is help\n | This is an annotation of type none"); -} - -#[test] -fn test_fold_line() { - let dl = DisplayList::from(vec![ - DisplayLine::Source { - lineno: Some(5), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "This is line 5", - range: (0, 19), - }, - }, - DisplayLine::Fold { - inline_marks: vec![], - }, - DisplayLine::Source { - lineno: Some(10021), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "... and now we're at line 10021", - range: (0, 19), - }, - }, - ]); - - assert_eq!( - dl.to_string(), - " 5 | This is line 5\n...\n10021 | ... and now we're at line 10021" - ); -} - -#[test] -fn test_raw_origin_initial_nopos() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { - path: "src/test.rs", - pos: None, - header_type: DisplayHeaderType::Initial, - })]); - - assert_eq!(dl.to_string(), "--> src/test.rs"); -} - -#[test] -fn test_raw_origin_initial_pos() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { - path: "src/test.rs", - pos: Some((23, 15)), - header_type: DisplayHeaderType::Initial, - })]); - - assert_eq!(dl.to_string(), "--> src/test.rs:23:15"); -} - -#[test] -fn test_raw_origin_continuation() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { - path: "src/test.rs", - pos: Some((23, 15)), - header_type: DisplayHeaderType::Continuation, - })]); - - assert_eq!(dl.to_string(), "::: src/test.rs:23:15"); -} - -#[test] -fn test_raw_annotation_unaligned() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Error, - id: Some("E0001"), - label: vec![DisplayTextFragment { - content: "This is an error", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: false, - continuation: false, - })]); - - assert_eq!(dl.to_string(), "error[E0001]: This is an error"); -} - -#[test] -fn test_raw_annotation_unaligned_multiline() { - let dl = DisplayList::from(vec![ - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Warning, - id: Some("E0001"), - label: vec![DisplayTextFragment { - content: "This is an error", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: false, - continuation: false, - }), - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Warning, - id: Some("E0001"), - label: vec![DisplayTextFragment { - content: "Second line of the error", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: false, - continuation: true, - }), - ]); - - assert_eq!( - dl.to_string(), - "warning[E0001]: This is an error\n Second line of the error" - ); -} - -#[test] -fn test_raw_annotation_aligned() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Error, - id: Some("E0001"), - label: vec![DisplayTextFragment { - content: "This is an error", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: true, - continuation: false, - })]); - - assert_eq!(dl.to_string(), " = error[E0001]: This is an error"); -} - -#[test] -fn test_raw_annotation_aligned_multiline() { - let dl = DisplayList::from(vec![ - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Warning, - id: Some("E0001"), - label: vec![DisplayTextFragment { - content: "This is an error", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: true, - continuation: false, - }), - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Warning, - id: Some("E0001"), - label: vec![DisplayTextFragment { - content: "Second line of the error", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: true, - continuation: true, - }), - ]); - - assert_eq!( - dl.to_string(), - " = warning[E0001]: This is an error\n Second line of the error" - ); -} - -#[test] -fn test_different_annotation_types() { - let dl = DisplayList::from(vec![ - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Note, - id: None, - label: vec![DisplayTextFragment { - content: "This is a note", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: false, - continuation: false, - }), - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::None, - id: None, - label: vec![DisplayTextFragment { - content: "This is just a string", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: false, - continuation: false, - }), - DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::None, - id: None, - label: vec![DisplayTextFragment { - content: "Second line of none type annotation", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: false, - continuation: true, - }), - ]); - - assert_eq!( - dl.to_string(), - "note: This is a note\nThis is just a string\n Second line of none type annotation", - ); -} - -#[test] -fn test_inline_marks_empty_line() { - let dl = DisplayList::from(vec![DisplayLine::Source { - lineno: None, - inline_marks: vec![DisplayMark { - mark_type: DisplayMarkType::AnnotationThrough, - annotation_type: DisplayAnnotationType::Error, - }], - line: DisplaySourceLine::Empty, - }]); - - assert_eq!(dl.to_string(), " | |",); -} - -#[test] -fn test_anon_lines() { - let mut dl = DisplayList::from(vec![ - DisplayLine::Source { - lineno: Some(56), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "This is an example", - range: (0, 19), - }, - }, - DisplayLine::Source { - lineno: Some(57), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "of content lines", - range: (0, 19), - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "abc", - range: (0, 19), - }, - }, - ]); - - dl.anonymized_line_numbers = true; - assert_eq!( - dl.to_string(), - "LL | This is an example\nLL | of content lines\n |\n | abc" - ); -} - -#[test] -fn test_raw_origin_initial_pos_anon_lines() { - let mut dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { - path: "src/test.rs", - pos: Some((23, 15)), - header_type: DisplayHeaderType::Initial, - })]); - - // Using anonymized_line_numbers should not affect the initial position - dl.anonymized_line_numbers = true; - assert_eq!(dl.to_string(), "--> src/test.rs:23:15"); -} - #[test] fn test_i_29() { let snippets = Snippet { From d45fbd42ff4eef34f8088a8a4a8dbac1b9af277a Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 2 Dec 2023 14:38:59 -0700 Subject: [PATCH 07/12] refactor(display_list): Remove `From` impls --- src/display_list/mod.rs | 493 +++++++++++++++++-------------------- src/renderer/stylesheet.rs | 6 + 2 files changed, 235 insertions(+), 264 deletions(-) diff --git a/src/display_list/mod.rs b/src/display_list/mod.rs index da1a05b2..b88b2138 100644 --- a/src/display_list/mod.rs +++ b/src/display_list/mod.rs @@ -45,17 +45,6 @@ pub(crate) struct DisplayList<'a> { pub margin: Option, } -impl<'a> From>> for DisplayList<'a> { - fn from(body: Vec>) -> DisplayList<'a> { - Self { - body, - anonymized_line_numbers: false, - stylesheet: Stylesheet::default(), - margin: None, - } - } -} - impl<'a> PartialEq for DisplayList<'a> { fn eq(&self, other: &Self) -> bool { self.body == other.body && self.anonymized_line_numbers == other.anonymized_line_numbers @@ -105,12 +94,6 @@ impl<'a> Display for DisplayList<'a> { } } -impl<'a> From> for DisplayList<'a> { - fn from(snippet: snippet::Snippet<'a>) -> DisplayList<'a> { - Self::new(snippet, Stylesheet::default(), false, None) - } -} - impl<'a> DisplayList<'a> { const ANONYMIZED_LINE_NUM: &'static str = "LL"; const ERROR_TXT: &'static str = "error"; @@ -1229,6 +1212,17 @@ fn is_annotation_empty(annotation: &Annotation<'_>) -> bool { mod tests { use super::*; + const STYLESHEET: Stylesheet = Stylesheet::plain(); + + fn from_display_lines(lines: Vec>) -> DisplayList<'_> { + DisplayList { + body: lines, + stylesheet: STYLESHEET, + anonymized_line_numbers: false, + margin: None, + } + } + #[test] fn test_format_title() { let input = snippet::Snippet { @@ -1240,24 +1234,19 @@ mod tests { footer: vec![], slices: vec![], }; - let output = DisplayList { - body: vec![DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Error, - id: Some("E0001"), - label: vec![DisplayTextFragment { - content: "This is a title", - style: DisplayTextStyle::Emphasis, - }], - }, - source_aligned: false, - continuation: false, - })], - stylesheet: Stylesheet::default(), - anonymized_line_numbers: false, - margin: None, - }; - assert_eq!(DisplayList::from(input), output); + let output = from_display_lines(vec![DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Error, + id: Some("E0001"), + label: vec![DisplayTextFragment { + content: "This is a title", + style: DisplayTextStyle::Emphasis, + }], + }, + source_aligned: false, + continuation: false, + })]); + assert_eq!(DisplayList::new(input, STYLESHEET, false, None), output); } #[test] @@ -1276,40 +1265,35 @@ mod tests { fold: false, }], }; - let output = DisplayList { - body: vec![ - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }, - DisplayLine::Source { - lineno: Some(5402), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: line_1, - range: (0, line_1.len()), - }, - }, - DisplayLine::Source { - lineno: Some(5403), - inline_marks: vec![], - line: DisplaySourceLine::Content { - range: (line_1.len() + 1, source.len()), - text: line_2, - }, + let output = from_display_lines(vec![ + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + DisplayLine::Source { + lineno: Some(5402), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: line_1, + range: (0, line_1.len()), }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, + }, + DisplayLine::Source { + lineno: Some(5403), + inline_marks: vec![], + line: DisplaySourceLine::Content { + range: (line_1.len() + 1, source.len()), + text: line_2, }, - ], - stylesheet: Stylesheet::default(), - anonymized_line_numbers: false, - margin: None, - }; - assert_eq!(DisplayList::from(input), output); + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + ]); + assert_eq!(DisplayList::new(input, STYLESHEET, false, None), output); } #[test] @@ -1338,60 +1322,55 @@ mod tests { }, ], }; - let output = DisplayList { - body: vec![ - DisplayLine::Raw(DisplayRawLine::Origin { - path: "file1.rs", - pos: None, - header_type: DisplayHeaderType::Initial, - }), - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }, - DisplayLine::Source { - lineno: Some(5402), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: src_0, - range: (0, src_0_len), - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }, - DisplayLine::Raw(DisplayRawLine::Origin { - path: "file2.rs", - pos: None, - header_type: DisplayHeaderType::Continuation, - }), - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }, - DisplayLine::Source { - lineno: Some(2), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: src_1, - range: (0, src_1_len), - }, + let output = from_display_lines(vec![ + DisplayLine::Raw(DisplayRawLine::Origin { + path: "file1.rs", + pos: None, + header_type: DisplayHeaderType::Initial, + }), + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + DisplayLine::Source { + lineno: Some(5402), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: src_0, + range: (0, src_0_len), }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + DisplayLine::Raw(DisplayRawLine::Origin { + path: "file2.rs", + pos: None, + header_type: DisplayHeaderType::Continuation, + }), + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + DisplayLine::Source { + lineno: Some(2), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: src_1, + range: (0, src_1_len), }, - ], - stylesheet: Stylesheet::default(), - anonymized_line_numbers: false, - margin: None, - }; - assert_eq!(DisplayList::from(input), output); + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + ]); + assert_eq!(DisplayList::new(input, STYLESHEET, false, None), output); } #[test] @@ -1416,57 +1395,52 @@ mod tests { fold: false, }], }; - let output = DisplayList { - body: vec![ - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }, - DisplayLine::Source { - lineno: Some(5402), - inline_marks: vec![], - line: DisplaySourceLine::Content { - range: (0, line_1.len()), - text: line_1, - }, + let output = from_display_lines(vec![ + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + DisplayLine::Source { + lineno: Some(5402), + inline_marks: vec![], + line: DisplaySourceLine::Content { + range: (0, line_1.len()), + text: line_1, }, - DisplayLine::Source { - lineno: Some(5403), - inline_marks: vec![], - line: DisplaySourceLine::Content { - range: (line_1.len() + 1, source.len()), - text: line_2, - }, + }, + DisplayLine::Source { + lineno: Some(5403), + inline_marks: vec![], + line: DisplaySourceLine::Content { + range: (line_1.len() + 1, source.len()), + text: line_2, }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Info, - id: None, - label: vec![DisplayTextFragment { - content: "Test annotation", - style: DisplayTextStyle::Regular, - }], - }, - range: (range.0 - (line_1.len() + 1), range.1 - (line_1.len() + 1)), + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + annotation: Annotation { annotation_type: DisplayAnnotationType::Info, - annotation_part: DisplayAnnotationPart::Standalone, + id: None, + label: vec![DisplayTextFragment { + content: "Test annotation", + style: DisplayTextStyle::Regular, + }], }, + range: (range.0 - (line_1.len() + 1), range.1 - (line_1.len() + 1)), + annotation_type: DisplayAnnotationType::Info, + annotation_part: DisplayAnnotationPart::Standalone, }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }, - ], - stylesheet: Stylesheet::default(), - anonymized_line_numbers: false, - margin: None, - }; - assert_eq!(DisplayList::from(input), output); + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + ]); + assert_eq!(DisplayList::new(input, STYLESHEET, false, None), output); } #[test] @@ -1480,24 +1454,19 @@ mod tests { }], slices: vec![], }; - let output = DisplayList { - body: vec![DisplayLine::Raw(DisplayRawLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::Error, - id: None, - label: vec![DisplayTextFragment { - content: "This __is__ a title", - style: DisplayTextStyle::Regular, - }], - }, - source_aligned: true, - continuation: false, - })], - stylesheet: Stylesheet::default(), - anonymized_line_numbers: false, - margin: None, - }; - assert_eq!(DisplayList::from(input), output); + let output = from_display_lines(vec![DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Error, + id: None, + label: vec![DisplayTextFragment { + content: "This __is__ a title", + style: DisplayTextStyle::Regular, + }], + }, + source_aligned: true, + continuation: false, + })]); + assert_eq!(DisplayList::new(input, STYLESHEET, false, None), output); } #[test] @@ -1520,8 +1489,7 @@ mod tests { fold: false, }], }; - - let _ = DisplayList::from(input); + let _ = DisplayList::new(input, STYLESHEET, false, None); } #[test] @@ -1546,80 +1514,77 @@ mod tests { }], }; - let expected = DisplayList { - body: vec![ - DisplayLine::Raw(DisplayRawLine::Annotation { + let expected = from_display_lines(vec![ + DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::Error, + id: None, + label: vec![DisplayTextFragment { + content: "oops", + style: DisplayTextStyle::Emphasis, + }], + }, + source_aligned: false, + continuation: false, + }), + DisplayLine::Raw(DisplayRawLine::Origin { + path: "", + pos: Some((2, 8)), + header_type: DisplayHeaderType::Initial, + }), + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + DisplayLine::Source { + lineno: Some(1), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: "First line", + range: (0, 10), + }, + }, + DisplayLine::Source { + lineno: Some(2), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: "Second oops line", + range: (12, 28), + }, + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { annotation: Annotation { - annotation_type: DisplayAnnotationType::Error, + annotation_type: DisplayAnnotationType::None, id: None, label: vec![DisplayTextFragment { content: "oops", - style: DisplayTextStyle::Emphasis, + style: DisplayTextStyle::Regular, }], }, - source_aligned: false, - continuation: false, - }), - DisplayLine::Raw(DisplayRawLine::Origin { - path: "", - pos: Some((2, 8)), - header_type: DisplayHeaderType::Initial, - }), - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, - }, - DisplayLine::Source { - lineno: Some(1), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "First line", - range: (0, 10), - }, - }, - DisplayLine::Source { - lineno: Some(2), - inline_marks: vec![], - line: DisplaySourceLine::Content { - text: "Second oops line", - range: (12, 28), - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Annotation { - annotation: Annotation { - annotation_type: DisplayAnnotationType::None, - id: None, - label: vec![DisplayTextFragment { - content: "oops", - style: DisplayTextStyle::Regular, - }], - }, - range: (7, 11), - annotation_type: DisplayAnnotationType::Error, - annotation_part: DisplayAnnotationPart::Standalone, - }, - }, - DisplayLine::Source { - lineno: None, - inline_marks: vec![], - line: DisplaySourceLine::Empty, + range: (7, 11), + annotation_type: DisplayAnnotationType::Error, + annotation_part: DisplayAnnotationPart::Standalone, }, - ], - stylesheet: Stylesheet::default(), - anonymized_line_numbers: false, - margin: None, - }; - - assert_eq!(DisplayList::from(snippets), expected); + }, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + ]); + assert_eq!( + DisplayList::new(snippets, STYLESHEET, false, None), + expected + ); } #[test] fn test_source_empty() { - let dl = DisplayList::from(vec![DisplayLine::Source { + let dl = from_display_lines(vec![DisplayLine::Source { lineno: None, inline_marks: vec![], line: DisplaySourceLine::Empty, @@ -1630,7 +1595,7 @@ mod tests { #[test] fn test_source_content() { - let dl = DisplayList::from(vec![ + let dl = from_display_lines(vec![ DisplayLine::Source { lineno: Some(56), inline_marks: vec![], @@ -1657,7 +1622,7 @@ mod tests { #[test] fn test_source_annotation_standalone_singleline() { - let dl = DisplayList::from(vec![DisplayLine::Source { + let dl = from_display_lines(vec![DisplayLine::Source { lineno: None, inline_marks: vec![], line: DisplaySourceLine::Annotation { @@ -1680,7 +1645,7 @@ mod tests { #[test] fn test_source_annotation_standalone_multiline() { - let dl = DisplayList::from(vec![ + let dl = from_display_lines(vec![ DisplayLine::Source { lineno: None, inline_marks: vec![], @@ -1725,7 +1690,7 @@ mod tests { #[test] fn test_source_annotation_standalone_multi_annotation() { - let dl = DisplayList::from(vec![ + let dl = from_display_lines(vec![ DisplayLine::Source { lineno: None, inline_marks: vec![], @@ -1835,7 +1800,7 @@ mod tests { #[test] fn test_fold_line() { - let dl = DisplayList::from(vec![ + let dl = from_display_lines(vec![ DisplayLine::Source { lineno: Some(5), inline_marks: vec![], @@ -1865,7 +1830,7 @@ mod tests { #[test] fn test_raw_origin_initial_nopos() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { + let dl = from_display_lines(vec![DisplayLine::Raw(DisplayRawLine::Origin { path: "src/test.rs", pos: None, header_type: DisplayHeaderType::Initial, @@ -1876,7 +1841,7 @@ mod tests { #[test] fn test_raw_origin_initial_pos() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { + let dl = from_display_lines(vec![DisplayLine::Raw(DisplayRawLine::Origin { path: "src/test.rs", pos: Some((23, 15)), header_type: DisplayHeaderType::Initial, @@ -1887,7 +1852,7 @@ mod tests { #[test] fn test_raw_origin_continuation() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { + let dl = from_display_lines(vec![DisplayLine::Raw(DisplayRawLine::Origin { path: "src/test.rs", pos: Some((23, 15)), header_type: DisplayHeaderType::Continuation, @@ -1898,7 +1863,7 @@ mod tests { #[test] fn test_raw_annotation_unaligned() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Annotation { + let dl = from_display_lines(vec![DisplayLine::Raw(DisplayRawLine::Annotation { annotation: Annotation { annotation_type: DisplayAnnotationType::Error, id: Some("E0001"), @@ -1916,7 +1881,7 @@ mod tests { #[test] fn test_raw_annotation_unaligned_multiline() { - let dl = DisplayList::from(vec![ + let dl = from_display_lines(vec![ DisplayLine::Raw(DisplayRawLine::Annotation { annotation: Annotation { annotation_type: DisplayAnnotationType::Warning, @@ -1951,7 +1916,7 @@ mod tests { #[test] fn test_raw_annotation_aligned() { - let dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Annotation { + let dl = from_display_lines(vec![DisplayLine::Raw(DisplayRawLine::Annotation { annotation: Annotation { annotation_type: DisplayAnnotationType::Error, id: Some("E0001"), @@ -1969,7 +1934,7 @@ mod tests { #[test] fn test_raw_annotation_aligned_multiline() { - let dl = DisplayList::from(vec![ + let dl = from_display_lines(vec![ DisplayLine::Raw(DisplayRawLine::Annotation { annotation: Annotation { annotation_type: DisplayAnnotationType::Warning, @@ -2004,7 +1969,7 @@ mod tests { #[test] fn test_different_annotation_types() { - let dl = DisplayList::from(vec![ + let dl = from_display_lines(vec![ DisplayLine::Raw(DisplayRawLine::Annotation { annotation: Annotation { annotation_type: DisplayAnnotationType::Note, @@ -2051,7 +2016,7 @@ mod tests { #[test] fn test_inline_marks_empty_line() { - let dl = DisplayList::from(vec![DisplayLine::Source { + let dl = from_display_lines(vec![DisplayLine::Source { lineno: None, inline_marks: vec![DisplayMark { mark_type: DisplayMarkType::AnnotationThrough, @@ -2065,7 +2030,7 @@ mod tests { #[test] fn test_anon_lines() { - let mut dl = DisplayList::from(vec![ + let mut dl = from_display_lines(vec![ DisplayLine::Source { lineno: Some(56), inline_marks: vec![], @@ -2106,7 +2071,7 @@ mod tests { #[test] fn test_raw_origin_initial_pos_anon_lines() { - let mut dl = DisplayList::from(vec![DisplayLine::Raw(DisplayRawLine::Origin { + let mut dl = from_display_lines(vec![DisplayLine::Raw(DisplayRawLine::Origin { path: "src/test.rs", pos: Some((23, 15)), header_type: DisplayHeaderType::Initial, diff --git a/src/renderer/stylesheet.rs b/src/renderer/stylesheet.rs index b3dbbc3d..ee1ab937 100644 --- a/src/renderer/stylesheet.rs +++ b/src/renderer/stylesheet.rs @@ -14,6 +14,12 @@ pub(crate) struct Stylesheet { impl Default for Stylesheet { fn default() -> Self { + Self::plain() + } +} + +impl Stylesheet { + pub(crate) const fn plain() -> Self { Self { error: Style::new(), warning: Style::new(), From a9bf3857a4d66e3186870d2375125a86275d2721 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 2 Dec 2023 14:40:42 -0700 Subject: [PATCH 08/12] refactor(display_list): Take a reference to `StyleSheet` --- src/display_list/mod.rs | 20 ++++++++++---------- src/renderer/mod.rs | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/display_list/mod.rs b/src/display_list/mod.rs index b88b2138..02e14a50 100644 --- a/src/display_list/mod.rs +++ b/src/display_list/mod.rs @@ -40,7 +40,7 @@ use crate::renderer::{stylesheet::Stylesheet, Margin, Style}; /// List of lines to be displayed. pub(crate) struct DisplayList<'a> { pub body: Vec>, - pub stylesheet: Stylesheet, + pub stylesheet: &'a Stylesheet, pub anonymized_line_numbers: bool, pub margin: Option, } @@ -108,7 +108,7 @@ impl<'a> DisplayList<'a> { footer, slices, }: snippet::Snippet<'a>, - stylesheet: Stylesheet, + stylesheet: &'a Stylesheet, anonymized_line_numbers: bool, margin: Option, ) -> DisplayList<'a> { @@ -1217,7 +1217,7 @@ mod tests { fn from_display_lines(lines: Vec>) -> DisplayList<'_> { DisplayList { body: lines, - stylesheet: STYLESHEET, + stylesheet: &STYLESHEET, anonymized_line_numbers: false, margin: None, } @@ -1246,7 +1246,7 @@ mod tests { source_aligned: false, continuation: false, })]); - assert_eq!(DisplayList::new(input, STYLESHEET, false, None), output); + assert_eq!(DisplayList::new(input, &STYLESHEET, false, None), output); } #[test] @@ -1293,7 +1293,7 @@ mod tests { line: DisplaySourceLine::Empty, }, ]); - assert_eq!(DisplayList::new(input, STYLESHEET, false, None), output); + assert_eq!(DisplayList::new(input, &STYLESHEET, false, None), output); } #[test] @@ -1370,7 +1370,7 @@ mod tests { line: DisplaySourceLine::Empty, }, ]); - assert_eq!(DisplayList::new(input, STYLESHEET, false, None), output); + assert_eq!(DisplayList::new(input, &STYLESHEET, false, None), output); } #[test] @@ -1440,7 +1440,7 @@ mod tests { line: DisplaySourceLine::Empty, }, ]); - assert_eq!(DisplayList::new(input, STYLESHEET, false, None), output); + assert_eq!(DisplayList::new(input, &STYLESHEET, false, None), output); } #[test] @@ -1466,7 +1466,7 @@ mod tests { source_aligned: true, continuation: false, })]); - assert_eq!(DisplayList::new(input, STYLESHEET, false, None), output); + assert_eq!(DisplayList::new(input, &STYLESHEET, false, None), output); } #[test] @@ -1489,7 +1489,7 @@ mod tests { fold: false, }], }; - let _ = DisplayList::new(input, STYLESHEET, false, None); + let _ = DisplayList::new(input, &STYLESHEET, false, None); } #[test] @@ -1577,7 +1577,7 @@ mod tests { }, ]); assert_eq!( - DisplayList::new(snippets, STYLESHEET, false, None), + DisplayList::new(snippets, &STYLESHEET, false, None), expected ); } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 2f033418..69f1cf41 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -95,7 +95,7 @@ impl Renderer { pub fn render<'a>(&'a self, snippet: Snippet<'a>) -> impl Display + 'a { DisplayList::new( snippet, - self.stylesheet, + &self.stylesheet, self.anonymized_line_numbers, self.margin, ) From 748b79263dc59ea3c8604fd9e3f0657d10c76c90 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 2 Dec 2023 14:46:46 -0700 Subject: [PATCH 09/12] refactor(renderer): Make functions `const` --- src/renderer/mod.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 69f1cf41..bf6bf696 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -17,16 +17,16 @@ pub struct Renderer { impl Renderer { /// No terminal styling - pub fn plain() -> Self { + pub const fn plain() -> Self { Self { anonymized_line_numbers: false, margin: None, - stylesheet: Stylesheet::default(), + stylesheet: Stylesheet::plain(), } } /// Default terminal styling - pub fn styled() -> Self { + pub const fn styled() -> Self { Self { stylesheet: Stylesheet { error: AnsiColor::BrightRed.on_default().effects(Effects::BOLD), @@ -42,52 +42,52 @@ impl Renderer { } } - pub fn anonymized_line_numbers(mut self, anonymized_line_numbers: bool) -> Self { + pub const fn anonymized_line_numbers(mut self, anonymized_line_numbers: bool) -> Self { self.anonymized_line_numbers = anonymized_line_numbers; self } - pub fn margin(mut self, margin: Option) -> Self { + pub const fn margin(mut self, margin: Option) -> Self { self.margin = margin; self } - pub fn error(mut self, style: Style) -> Self { + pub const fn error(mut self, style: Style) -> Self { self.stylesheet.error = style; self } - pub fn warning(mut self, style: Style) -> Self { + pub const fn warning(mut self, style: Style) -> Self { self.stylesheet.warning = style; self } - pub fn info(mut self, style: Style) -> Self { + pub const fn info(mut self, style: Style) -> Self { self.stylesheet.info = style; self } - pub fn note(mut self, style: Style) -> Self { + pub const fn note(mut self, style: Style) -> Self { self.stylesheet.note = style; self } - pub fn help(mut self, style: Style) -> Self { + pub const fn help(mut self, style: Style) -> Self { self.stylesheet.help = style; self } - pub fn line_no(mut self, style: Style) -> Self { + pub const fn line_no(mut self, style: Style) -> Self { self.stylesheet.line_no = style; self } - pub fn emphasis(mut self, style: Style) -> Self { + pub const fn emphasis(mut self, style: Style) -> Self { self.stylesheet.emphasis = style; self } - pub fn none(mut self, style: Style) -> Self { + pub const fn none(mut self, style: Style) -> Self { self.stylesheet.none = style; self } From b0848f70cdf54b4601bd01d4ae99ce4c63a80be9 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Mon, 4 Dec 2023 16:21:30 -0700 Subject: [PATCH 10/12] chore(renderer): Add doc comments --- src/renderer/mod.rs | 75 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index bf6bf696..ce080d36 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,3 +1,37 @@ +//! The renderer for [`Snippet`]s +//! +//! # Example +//! ``` +//! use annotate_snippets::renderer::Renderer; +//! use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet}; +//! let snippet = Snippet { +//! title: Some(Annotation { +//! label: Some("mismatched types"), +//! id: None, +//! annotation_type: AnnotationType::Error, +//! }), +//! footer: vec![], +//! slices: vec![ +//! Slice { +//! source: "Foo", +//! line_start: 51, +//! origin: Some("src/format.rs"), +//! fold: false, +//! annotations: vec![], +//! }, +//! Slice { +//! source: "Faa", +//! line_start: 129, +//! origin: Some("src/display.rs"), +//! fold: false, +//! annotations: vec![], +//! }, +//! ], +//! }; +//! +//! let renderer = Renderer::styled(); +//! println!("{}", renderer.render(snippet)); + mod margin; pub(crate) mod stylesheet; @@ -8,6 +42,7 @@ pub use margin::Margin; use std::fmt::Display; use stylesheet::Stylesheet; +/// A renderer for [`Snippet`]s #[derive(Clone)] pub struct Renderer { anonymized_line_numbers: bool, @@ -42,56 +77,96 @@ impl Renderer { } } + /// Anonymize line numbers + /// + /// This enables (or disables) line number anonymization. When enabled, line numbers are replaced + /// with `LL`. + /// + /// # Example + /// + /// ```text + /// --> $DIR/whitespace-trimming.rs:4:193 + /// | + /// LL | ... let _: () = 42; + /// | ^^ expected (), found integer + /// | + /// ``` pub const fn anonymized_line_numbers(mut self, anonymized_line_numbers: bool) -> Self { self.anonymized_line_numbers = anonymized_line_numbers; self } + /// Set the margin for the output + /// + /// This controls the various margins of the output. + /// + /// # Example + /// + /// ```text + /// error: expected type, found `22` + /// --> examples/footer.rs:29:25 + /// | + /// 26 | ... annotations: vec![SourceAnnotation { + /// | ---------------- info: while parsing this struct + /// ... + /// 29 | ... range: <22, 25>, + /// | ^^ + /// | + /// ``` pub const fn margin(mut self, margin: Option) -> Self { self.margin = margin; self } + /// Set the output style for `error` pub const fn error(mut self, style: Style) -> Self { self.stylesheet.error = style; self } + /// Set the output style for `warning` pub const fn warning(mut self, style: Style) -> Self { self.stylesheet.warning = style; self } + /// Set the output style for `info` pub const fn info(mut self, style: Style) -> Self { self.stylesheet.info = style; self } + /// Set the output style for `note` pub const fn note(mut self, style: Style) -> Self { self.stylesheet.note = style; self } + /// Set the output style for `help` pub const fn help(mut self, style: Style) -> Self { self.stylesheet.help = style; self } + /// Set the output style for line numbers pub const fn line_no(mut self, style: Style) -> Self { self.stylesheet.line_no = style; self } + /// Set the output style for emphasis pub const fn emphasis(mut self, style: Style) -> Self { self.stylesheet.emphasis = style; self } + /// Set the output style for none pub const fn none(mut self, style: Style) -> Self { self.stylesheet.none = style; self } + /// Render a snippet into a `Display`able object pub fn render<'a>(&'a self, snippet: Snippet<'a>) -> impl Display + 'a { DisplayList::new( snippet, From a1007ddf2fc6f76e960a4fc01207228e64e9fae7 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 5 Dec 2023 11:39:46 -0700 Subject: [PATCH 11/12] fix!: Move around items in the public api BREAKING CHANGE: This moves `snippet::*` and `Renderer` to root --- benches/simple.rs | 3 +-- examples/expected_type.rs | 3 +-- examples/footer.rs | 3 +-- examples/format.rs | 3 +-- examples/multislice.rs | 3 +-- src/lib.rs | 12 ++++++++---- src/renderer/mod.rs | 3 +-- src/snippet.rs | 2 +- tests/deserialize/mod.rs | 4 +--- tests/fixtures_test.rs | 4 ++-- tests/formatter.rs | 41 +++++++++++++++++++-------------------- 11 files changed, 38 insertions(+), 43 deletions(-) diff --git a/benches/simple.rs b/benches/simple.rs index 8ccd18f7..3a40bbf5 100644 --- a/benches/simple.rs +++ b/benches/simple.rs @@ -4,8 +4,7 @@ extern crate criterion; use criterion::{black_box, Criterion}; -use annotate_snippets::renderer::Renderer; -use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}; +use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation}; fn create_snippet(renderer: Renderer) { let snippet = Snippet { diff --git a/examples/expected_type.rs b/examples/expected_type.rs index 959419c2..bbd1fe64 100644 --- a/examples/expected_type.rs +++ b/examples/expected_type.rs @@ -1,5 +1,4 @@ -use annotate_snippets::renderer::Renderer; -use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}; +use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation}; fn main() { let snippet = Snippet { diff --git a/examples/footer.rs b/examples/footer.rs index 0191c1d6..ca021198 100644 --- a/examples/footer.rs +++ b/examples/footer.rs @@ -1,5 +1,4 @@ -use annotate_snippets::renderer::Renderer; -use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}; +use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation}; fn main() { let snippet = Snippet { diff --git a/examples/format.rs b/examples/format.rs index 7302eefe..41f852ee 100644 --- a/examples/format.rs +++ b/examples/format.rs @@ -1,5 +1,4 @@ -use annotate_snippets::renderer::Renderer; -use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}; +use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation}; fn main() { let snippet = Snippet { diff --git a/examples/multislice.rs b/examples/multislice.rs index dc51d4f5..63ebb650 100644 --- a/examples/multislice.rs +++ b/examples/multislice.rs @@ -1,5 +1,4 @@ -use annotate_snippets::renderer::Renderer; -use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet}; +use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet}; fn main() { let snippet = Snippet { diff --git a/src/lib.rs b/src/lib.rs index 342db23c..5da3575a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,18 +29,22 @@ //! Snippet --> Renderer --> impl Display //! ``` //! -//! The input type - [Snippet](self::snippet) is a structure designed +//! The input type - [Snippet] is a structure designed //! to align with likely output from any parser whose code snippet is to be //! annotated. //! -//! The middle structure - [Renderer](self::renderer) is a structure designed +//! The middle structure - [Renderer] is a structure designed //! to convert a snippet into an internal structure that is designed to store //! the snippet data in a way that is easy to format. -//! [Renderer](self::renderer) also handles the user-configurable formatting +//! [Renderer] also handles the user-configurable formatting //! options, such as color, or margins. //! //! Finally, `impl Display` into a final `String` output. mod display_list; pub mod renderer; -pub mod snippet; +mod snippet; + +#[doc(inline)] +pub use renderer::Renderer; +pub use snippet::*; diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index ce080d36..5f655c89 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -2,8 +2,7 @@ //! //! # Example //! ``` -//! use annotate_snippets::renderer::Renderer; -//! use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet}; +//! use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet}; //! let snippet = Snippet { //! title: Some(Annotation { //! label: Some("mismatched types"), diff --git a/src/snippet.rs b/src/snippet.rs index c1914c96..02e70cc1 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -3,7 +3,7 @@ //! Example: //! //! ``` -//! use annotate_snippets::snippet::*; +//! use annotate_snippets::*; //! //! Snippet { //! title: Some(Annotation { diff --git a/tests/deserialize/mod.rs b/tests/deserialize/mod.rs index af959cbf..1763005a 100644 --- a/tests/deserialize/mod.rs +++ b/tests/deserialize/mod.rs @@ -1,9 +1,7 @@ use serde::{Deserialize, Deserializer, Serialize}; -use annotate_snippets::renderer::Renderer; use annotate_snippets::{ - renderer::Margin, - snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, + renderer::Margin, Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation, }; #[derive(Deserialize)] diff --git a/tests/fixtures_test.rs b/tests/fixtures_test.rs index 854719ff..063829a6 100644 --- a/tests/fixtures_test.rs +++ b/tests/fixtures_test.rs @@ -2,8 +2,8 @@ mod deserialize; mod diff; use crate::deserialize::Fixture; -use annotate_snippets::renderer::Renderer; -use annotate_snippets::snippet::Snippet; +use annotate_snippets::Renderer; +use annotate_snippets::Snippet; use glob::glob; use std::{error::Error, fs::File, io, io::prelude::*}; diff --git a/tests/formatter.rs b/tests/formatter.rs index 3f85b695..97c7be3b 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -1,23 +1,22 @@ -use annotate_snippets::renderer::Renderer; -use annotate_snippets::snippet::{self, Snippet}; +use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation}; #[test] fn test_i_29() { let snippets = Snippet { - title: Some(snippet::Annotation { + title: Some(Annotation { id: None, label: Some("oops"), - annotation_type: snippet::AnnotationType::Error, + annotation_type: AnnotationType::Error, }), footer: vec![], - slices: vec![snippet::Slice { + slices: vec![Slice { source: "First line\r\nSecond oops line", line_start: 1, origin: Some(""), - annotations: vec![snippet::SourceAnnotation { + annotations: vec![SourceAnnotation { range: (19, 23), label: "oops", - annotation_type: snippet::AnnotationType::Error, + annotation_type: AnnotationType::Error, }], fold: true, }], @@ -37,14 +36,14 @@ fn test_i_29() { #[test] fn test_point_to_double_width_characters() { let snippets = Snippet { - slices: vec![snippet::Slice { + slices: vec![Slice { source: "こんにちは、世界", line_start: 1, origin: Some(""), - annotations: vec![snippet::SourceAnnotation { + annotations: vec![SourceAnnotation { range: (6, 8), label: "world", - annotation_type: snippet::AnnotationType::Error, + annotation_type: AnnotationType::Error, }], fold: false, }], @@ -65,14 +64,14 @@ fn test_point_to_double_width_characters() { #[test] fn test_point_to_double_width_characters_across_lines() { let snippets = Snippet { - slices: vec![snippet::Slice { + slices: vec![Slice { source: "おはよう\nございます", line_start: 1, origin: Some(""), - annotations: vec![snippet::SourceAnnotation { + annotations: vec![SourceAnnotation { range: (2, 8), label: "Good morning", - annotation_type: snippet::AnnotationType::Error, + annotation_type: AnnotationType::Error, }], fold: false, }], @@ -95,20 +94,20 @@ fn test_point_to_double_width_characters_across_lines() { #[test] fn test_point_to_double_width_characters_multiple() { let snippets = Snippet { - slices: vec![snippet::Slice { + slices: vec![Slice { source: "お寿司\n食べたい🍣", line_start: 1, origin: Some(""), annotations: vec![ - snippet::SourceAnnotation { + SourceAnnotation { range: (0, 3), label: "Sushi1", - annotation_type: snippet::AnnotationType::Error, + annotation_type: AnnotationType::Error, }, - snippet::SourceAnnotation { + SourceAnnotation { range: (6, 8), label: "Sushi2", - annotation_type: snippet::AnnotationType::Note, + annotation_type: AnnotationType::Note, }, ], fold: false, @@ -132,14 +131,14 @@ fn test_point_to_double_width_characters_multiple() { #[test] fn test_point_to_double_width_characters_mixed() { let snippets = Snippet { - slices: vec![snippet::Slice { + slices: vec![Slice { source: "こんにちは、新しいWorld!", line_start: 1, origin: Some(""), - annotations: vec![snippet::SourceAnnotation { + annotations: vec![SourceAnnotation { range: (6, 14), label: "New world", - annotation_type: snippet::AnnotationType::Error, + annotation_type: AnnotationType::Error, }], fold: false, }], From 71b1eb527b41da38fb6d4a70a1fc53afea4c3785 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 5 Dec 2023 11:58:27 -0700 Subject: [PATCH 12/12] refactor: Move `display_list` under `renderer` --- src/lib.rs | 1 - src/{display_list/mod.rs => renderer/display_list.rs} | 0 src/renderer/mod.rs | 3 ++- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{display_list/mod.rs => renderer/display_list.rs} (100%) diff --git a/src/lib.rs b/src/lib.rs index 5da3575a..80eac530 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,7 +41,6 @@ //! //! Finally, `impl Display` into a final `String` output. -mod display_list; pub mod renderer; mod snippet; diff --git a/src/display_list/mod.rs b/src/renderer/display_list.rs similarity index 100% rename from src/display_list/mod.rs rename to src/renderer/display_list.rs diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 5f655c89..0e19c08b 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -31,12 +31,13 @@ //! let renderer = Renderer::styled(); //! println!("{}", renderer.render(snippet)); +mod display_list; mod margin; pub(crate) mod stylesheet; -use crate::display_list::DisplayList; use crate::snippet::Snippet; pub use anstyle::*; +use display_list::DisplayList; pub use margin::Margin; use std::fmt::Display; use stylesheet::Stylesheet;