From 9076cbf66336e5137b47dc7a52df2999b6c82598 Mon Sep 17 00:00:00 2001
From: Scott Schafer <schaferjscott@gmail.com>
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 <schaferjscott@gmail.com>
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<String> {
@@ -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<snippet::Snippet<'a>> 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<Margin>,
     ) -> DisplayList<'a> {
         let mut body = vec![];
         if let Some(annotation) = title {
@@ -126,7 +141,7 @@ impl<'a> From<snippet::Snippet<'a>> for DisplayList<'a> {
                 slice,
                 idx == 0,
                 !footer.is_empty(),
-                opt.margin,
+                margin,
             ));
         }
 
@@ -134,12 +149,6 @@ impl<'a> From<snippet::Snippet<'a>> 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<snippet::Snippet<'a>> 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<Margin>,
-}
-
 #[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<Margin>,
+}
 
 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<Margin>) -> 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<Annotation<'a>>,
     pub footer: Vec<Annotation<'a>>,
     pub slices: Vec<Slice<'a>>,
-    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<Annotation<'a>>,
-    #[serde(deserialize_with = "deserialize_opt")]
-    #[serde(default)]
-    pub opt: FormatOptions,
     #[serde(deserialize_with = "deserialize_slices")]
     #[serde(borrow)]
     pub slices: Vec<Slice<'a>>,
@@ -28,76 +34,16 @@ impl<'a> From<SnippetDef<'a>> for Snippet<'a> {
         let SnippetDef {
             title,
             footer,
-            opt,
             slices,
         } = val;
         Snippet {
             title,
             footer,
             slices,
-            opt,
         }
     }
 }
 
-fn deserialize_opt<'de, D>(deserializer: D) -> Result<FormatOptions, D::Error>
-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<Margin>,
-}
-
-fn deserialize_margin<'de, D>(deserializer: D) -> Result<Option<Margin>, 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::<Wrapper>::deserialize(deserializer).map(|opt_wrapped: Option<Wrapper>| {
-        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<Vec<Slice<'de>>, 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<Margin>,
+}
+
+impl From<RendererDef> 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<Option<Margin>, 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::<Wrapper>::deserialize(deserializer).map(|opt_wrapped: Option<Wrapper>| {
+        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<i32>`, 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<String> {
     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<std::string::String>` 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<String>, main_annotation: Option<&Annotation>) {
     if let Some(annotation) = main_annotation {
@@ -11,15 +11,15 @@ fn add_title_line(result: &mut Vec<String>, 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<String, io::Error> {
     Ok(s.trim_end().to_string())
 }
 
-fn read_fixture(src: &str) -> Result<Snippet<'_>, Box<dyn Error>> {
-    Ok(toml::from_str(src).map(|a: SnippetDef| a.into())?)
+fn read_fixture(src: &str) -> Result<(Renderer, Snippet<'_>), Box<dyn Error>> {
+    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
  --> <current file>: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#" --> <current file>: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#" --> <current file>: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#" --> <current file>: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#" --> <current file>: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 <schaferjscott@gmail.com>
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<DisplayLine<'a>>,
-    pub stylesheet: Box<dyn Stylesheet>,
+    pub stylesheet: Stylesheet,
     pub anonymized_line_numbers: bool,
     pub margin: Option<Margin>,
 }
@@ -52,7 +52,7 @@ impl<'a> From<Vec<DisplayLine<'a>>> 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<snippet::Snippet<'a>> 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<Margin>,
     ) -> 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<dyn Style> {
-        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<dyn Stylesheet> {
-    if color {
-        Box::new(AnsiTermStylesheet)
-    } else {
-        Box::new(NoColorStylesheet)
-    }
-}
-
-#[cfg(not(feature = "color"))]
-#[inline]
-pub fn get_term_style(_color: bool) -> Box<dyn Stylesheet> {
-    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<dyn FnOnce(&mut fmt::Formatter<'_>) -> 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<dyn Style>;
-}
-
-/// 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<dyn Style>;
-}
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<Margin>,
+    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<Margin>) -> Self {
+        self.margin = margin;
         self
     }
 
-    pub fn margin(mut self, margin: Option<Margin>) -> 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<dyn FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result + 'a>,
-        f: &mut fmt::Formatter<'_>,
-    ) -> fmt::Result {
-        self.style.paint_fn(c).fmt(f)
-    }
-
-    fn bold(&self) -> Box<dyn Style> {
-        Box::new(AnsiTermStyleWrapper { style: self.style })
-    }
-}
-
-pub struct AnsiTermStylesheet;
-
-impl Stylesheet for AnsiTermStylesheet {
-    fn get_style(&self, class: StyleClass) -> Box<dyn Style> {
-        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<dyn FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result + 'a>,
-        f: &mut fmt::Formatter<'_>,
-    ) -> fmt::Result {
-        c(f)
-    }
-
-    fn bold(&self) -> Box<dyn Style> {
-        Box::new(NoOpStyle {})
-    }
-}
-
-pub struct NoColorStylesheet;
-
-impl Stylesheet for NoColorStylesheet {
-    fn get_style(&self, _class: StyleClass) -> Box<dyn Style> {
-        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 <schaferjscott@gmail.com>
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 <schaferjscott@gmail.com>
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 <schaferjscott@gmail.com>
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<DisplayLine<'a>>,
     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("<current file>"),
+                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: "<current file>",
+                    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<DisplayList>` 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("<current file>"),
-            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: "<current file>",
-                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 <schaferjscott@gmail.com>
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<Margin>,
 }
 
-impl<'a> From<Vec<DisplayLine<'a>>> for DisplayList<'a> {
-    fn from(body: Vec<DisplayLine<'a>>) -> 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<snippet::Snippet<'a>> 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<DisplayLine<'_>>) -> 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: "<current file>",
+                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: "<current file>",
-                    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 <schaferjscott@gmail.com>
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<DisplayLine<'a>>,
-    pub stylesheet: Stylesheet,
+    pub stylesheet: &'a Stylesheet,
     pub anonymized_line_numbers: bool,
     pub margin: Option<Margin>,
 }
@@ -108,7 +108,7 @@ impl<'a> DisplayList<'a> {
             footer,
             slices,
         }: snippet::Snippet<'a>,
-        stylesheet: Stylesheet,
+        stylesheet: &'a Stylesheet,
         anonymized_line_numbers: bool,
         margin: Option<Margin>,
     ) -> DisplayList<'a> {
@@ -1217,7 +1217,7 @@ mod tests {
     fn from_display_lines(lines: Vec<DisplayLine<'_>>) -> 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 <schaferjscott@gmail.com>
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<Margin>) -> Self {
+    pub const fn margin(mut self, margin: Option<Margin>) -> 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 <schaferjscott@gmail.com>
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<Margin>) -> 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 <schaferjscott@gmail.com>
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("<current file>"),
-            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("<current file>"),
-            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("<current file>"),
-            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("<current file>"),
             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("<current file>"),
-            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 <schaferjscott@gmail.com>
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;