Repository: rust-lang/annotate-snippets-rs
Pull request #67 (2023-12-02 22:28:36)

Move to a `Renderer` when for displaying a `Snippet`
This PR moves to using `Renderer` as the external type for handling displaying a `Snippet`.

 This has a few advantages:
- Keeps what is doing the actual formatting as an internal implementation detail
  - In the future, different types of renderers could be used and exposed as an option to "pick"
- Moves the formatting options to be part of the renderer, not an individual `Snippet`
- Makes a clearer distinction between what is a `Snippet` and what is going to be "rendering" it

This PR also:
- moves to `anstyle` for color and removes the `color` feature
  -  `anstyle` is lightweight and writes nothing if the color is `Style::new`
  -  `anstyle` is what `cargo` uses and it would be good if when we use this crate we only need one color library.
- moves many things to be internal details

Note: this is a step in the direction of the proposals for a more modern API (#12 and #13). I have been taking inspiration from both PRs to get a clear vision of what the future should look like.

---

To review this PR, look at it commit by commit


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index c15507c..0d9659e 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 8666651..ec39e99 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/benches/simple.rs b/benches/simple.rs
index 4c13a8f..3a40bbf 100644
--- a/benches/simple.rs
+++ b/benches/simple.rs
@@ -4,12 +4,9 @@ extern crate criterion;
 
 use criterion::{black_box, Criterion};
 
-use annotate_snippets::{
-    display_list::{DisplayList, FormatOptions},
-    snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
-};
+use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
 
-fn create_snippet() {
+fn create_snippet(renderer: Renderer) {
     let snippet = Snippet {
         slices: vec![Slice {
             source: r#") -> Option<String> {
@@ -56,18 +53,15 @@ fn create_snippet() {
             annotation_type: AnnotationType::Error,
         }),
         footer: vec![],
-        opt: FormatOptions {
-            color: true,
-            ..Default::default()
-        },
     };
 
-    let dl = DisplayList::from(snippet);
-    let _result = dl.to_string();
+    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 6f2a0d9..bbd1fe6 100644
--- a/examples/expected_type.rs
+++ b/examples/expected_type.rs
@@ -1,7 +1,4 @@
-use annotate_snippets::{
-    display_list::{DisplayList, FormatOptions},
-    snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
-};
+use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
 
 fn main() {
     let snippet = Snippet {
@@ -32,12 +29,8 @@ fn main() {
                 },
             ],
         }],
-        opt: FormatOptions {
-            color: true,
-            ..Default::default()
-        },
     };
 
-    let dl = DisplayList::from(snippet);
-    println!("{}", dl);
+    let renderer = Renderer::plain();
+    println!("{}", renderer.render(snippet));
 }
diff --git a/examples/footer.rs b/examples/footer.rs
index f3c15c4..ca02119 100644
--- a/examples/footer.rs
+++ b/examples/footer.rs
@@ -1,7 +1,4 @@
-use annotate_snippets::{
-    display_list::{DisplayList, FormatOptions},
-    snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
-};
+use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
 
 fn main() {
     let snippet = Snippet {
@@ -28,12 +25,8 @@ fn main() {
                 annotation_type: AnnotationType::Error,
             }],
         }],
-        opt: FormatOptions {
-            color: true,
-            ..Default::default()
-        },
     };
 
-    let dl = DisplayList::from(snippet);
-    println!("{}", dl);
+    let renderer = Renderer::plain();
+    println!("{}", renderer.render(snippet));
 }
diff --git a/examples/format.rs b/examples/format.rs
index 98b77a1..41f852e 100644
--- a/examples/format.rs
+++ b/examples/format.rs
@@ -1,7 +1,4 @@
-use annotate_snippets::{
-    display_list::{DisplayList, FormatOptions},
-    snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
-};
+use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
 
 fn main() {
     let snippet = Snippet {
@@ -50,12 +47,8 @@ fn main() {
             annotation_type: AnnotationType::Error,
         }),
         footer: vec![],
-        opt: FormatOptions {
-            color: true,
-            ..Default::default()
-        },
     };
 
-    let dl = DisplayList::from(snippet);
-    println!("{}", dl);
+    let renderer = Renderer::plain();
+    println!("{}", renderer.render(snippet));
 }
diff --git a/examples/multislice.rs b/examples/multislice.rs
index 5675a07..63ebb65 100644
--- a/examples/multislice.rs
+++ b/examples/multislice.rs
@@ -1,7 +1,4 @@
-use annotate_snippets::{
-    display_list::{DisplayList, FormatOptions},
-    snippet::{Annotation, AnnotationType, Slice, Snippet},
-};
+use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet};
 
 fn main() {
     let snippet = Snippet {
@@ -27,12 +24,8 @@ fn main() {
                 annotations: vec![],
             },
         ],
-        opt: FormatOptions {
-            color: true,
-            ..Default::default()
-        },
     };
 
-    let dl = DisplayList::from(snippet);
-    println!("{}", dl);
+    let renderer = Renderer::plain();
+    println!("{}", renderer.render(snippet));
 }
diff --git a/src/formatter/mod.rs b/src/formatter/mod.rs
deleted file mode 100644
index 72bf9c7..0000000
--- 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 3fc01c1..0000000
--- 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 d581367..80eac53 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -26,29 +26,24 @@
 //! 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
+//! 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 - [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] 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] 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;
-pub mod formatter;
-pub mod snippet;
-pub mod stylesheets;
+pub mod renderer;
+mod snippet;
+
+#[doc(inline)]
+pub use renderer::Renderer;
+pub use snippet::*;
diff --git a/src/display_list/mod.rs b/src/renderer/display_list.rs
similarity index 52%
rename from src/display_list/mod.rs
rename to src/renderer/display_list.rs
index 1ad328a..02e14a5 100644
--- a/src/display_list/mod.rs
+++ b/src/renderer/display_list.rs
@@ -31,33 +31,20 @@
 //! styling.
 //!
 //! The above snippet has been built out of the following structure:
-use std::cmp::{max, min};
+use crate::snippet;
 use std::fmt::{Display, Write};
 use std::{cmp, fmt};
 
-use crate::formatter::style::{Style, StyleClass};
-use crate::formatter::{get_term_style, style::Stylesheet};
-use crate::snippet;
+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: Box<dyn Stylesheet>,
+    pub stylesheet: &'a Stylesheet,
     pub anonymized_line_numbers: bool,
     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: get_term_style(false),
-            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
@@ -107,14 +94,23 @@ impl<'a> Display for DisplayList<'a> {
     }
 }
 
-impl<'a> From<snippet::Snippet<'a>> for DisplayList<'a> {
-    fn from(
+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>,
+        stylesheet: &'a Stylesheet,
+        anonymized_line_numbers: bool,
+        margin: Option<Margin>,
     ) -> DisplayList<'a> {
         let mut body = vec![];
         if let Some(annotation) = title {
@@ -126,7 +122,7 @@ impl<'a> From<snippet::Snippet<'a>> for DisplayList<'a> {
                 slice,
                 idx == 0,
                 !footer.is_empty(),
-                opt.margin,
+                margin,
             ));
         }
 
@@ -134,28 +130,13 @@ 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),
+            stylesheet,
             anonymized_line_numbers,
             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(
@@ -183,15 +164,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 +180,20 @@ 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 => {
+                    write!(
+                        f,
+                        "{}{}{}",
+                        emphasis_style.render(),
+                        fragment.content,
+                        emphasis_style.render_reset()
+                    )?;
+                }
             }
         }
         Ok(())
@@ -231,27 +220,21 @@ impl<'a> DisplayList<'a> {
         if formatted_len == 0 {
             self.format_label(&annotation.label, f)
         } else {
-            color.paint_fn(
-                Box::new(|f| {
-                    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(())
-                }),
-                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| {
-                            f.write_str(": ")?;
-                            self.format_label(&annotation.label, f)
-                        }),
-                        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)?;
@@ -343,7 +326,6 @@ impl<'a> DisplayList<'a> {
                 let indent_char = match annotation_part {
                     DisplayAnnotationPart::Standalone => ' ',
                     DisplayAnnotationPart::LabelContinuation => ' ',
-                    DisplayAnnotationPart::Consequitive => ' ',
                     DisplayAnnotationPart::MultilineStart => '_',
                     DisplayAnnotationPart::MultilineEnd => '_',
                 };
@@ -358,31 +340,24 @@ 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,
                 };
 
-                color.paint_fn(
-                    Box::new(|f| {
-                        format_repeat_char(indent_char, indent_length + 1, f)?;
-                        format_repeat_char(mark, range.1 - indent_length, f)
-                    }),
-                    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(
-                        Box::new(|f| {
-                            self.format_annotation(
-                                annotation,
-                                annotation_part == &DisplayAnnotationPart::LabelContinuation,
-                                true,
-                                f,
-                            )
-                        }),
+                    write!(f, "{}", color.render())?;
+                    self.format_annotation(
+                        annotation,
+                        annotation_part == &DisplayAnnotationPart::LabelContinuation,
+                        true,
                         f,
                     )?;
+                    write!(f, "{}", color.render_reset())?;
                 }
 
                 Ok(())
@@ -407,11 +382,17 @@ 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)?;
+                    write!(
+                        f,
+                        "{}{}{}",
+                        lineno_color.render(),
+                        header_sigil,
+                        lineno_color.render_reset()
+                    )?;
                     f.write_char(' ')?;
                     path.fmt(f)?;
                     f.write_char(':')?;
@@ -420,7 +401,13 @@ impl<'a> DisplayList<'a> {
                     row.fmt(f)
                 } else {
                     format_repeat_char(' ', lineno_width, f)?;
-                    lineno_color.paint(header_sigil, f)?;
+                    write!(
+                        f,
+                        "{}{}{}",
+                        lineno_color.render(),
+                        header_sigil,
+                        lineno_color.render_reset()
+                    )?;
                     f.write_char(' ')?;
                     path.fmt(f)
                 }
@@ -434,10 +421,15 @@ 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)?;
+                        write!(
+                            f,
+                            "{}={}",
+                            lineno_color.render(),
+                            lineno_color.render_reset()
+                        )?;
                         f.write_char(' ')?;
                     }
                 }
@@ -460,26 +452,20 @@ 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| {
-                            f.write_str(Self::ANONYMIZED_LINE_NUM)?;
-                            f.write_str(" |")
-                        }),
-                        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| {
-                            match lineno {
-                                Some(n) => write!(f, "{:>width$}", n, width = lineno_width),
-                                None => format_repeat_char(' ', lineno_width, f),
-                            }?;
-                            f.write_str(" |")
-                        }),
-                        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 {
@@ -513,141 +499,18 @@ 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| {
-                    f.write_char(match mark.mark_type {
-                        DisplayMarkType::AnnotationThrough => '|',
-                        DisplayMarkType::AnnotationStart => '/',
-                    })
-                }),
-                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(())
     }
 }
 
-#[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.
-    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> {
@@ -744,8 +607,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.
@@ -1346,3 +1207,878 @@ fn is_annotation_empty(annotation: &Annotation<'_>) -> bool {
         .iter()
         .all(|fragment| fragment.content.is_empty())
 }
+
+#[cfg(test)]
+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 {
+            title: Some(snippet::Annotation {
+                id: Some("E0001"),
+                label: Some("This is a title"),
+                annotation_type: snippet::AnnotationType::Error,
+            }),
+            footer: vec![],
+            slices: vec![],
+        };
+        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]
+    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 = 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: 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,
+            },
+        ]);
+        assert_eq!(DisplayList::new(input, &STYLESHEET, false, None), 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 = 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::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,
+            },
+        ]);
+        assert_eq!(DisplayList::new(input, &STYLESHEET, false, None), 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 = 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: 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,
+            },
+        ]);
+        assert_eq!(DisplayList::new(input, &STYLESHEET, false, None), 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 = 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]
+    #[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::new(input, &STYLESHEET, false, None);
+    }
+
+    #[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 = 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::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,
+            },
+        ]);
+        assert_eq!(
+            DisplayList::new(snippets, &STYLESHEET, false, None),
+            expected
+        );
+    }
+
+    #[test]
+    fn test_source_empty() {
+        let dl = from_display_lines(vec![DisplayLine::Source {
+            lineno: None,
+            inline_marks: vec![],
+            line: DisplaySourceLine::Empty,
+        }]);
+
+        assert_eq!(dl.to_string(), " |");
+    }
+
+    #[test]
+    fn test_source_content() {
+        let dl = from_display_lines(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 = from_display_lines(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 = from_display_lines(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 = from_display_lines(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 = from_display_lines(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 = from_display_lines(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 = from_display_lines(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 = from_display_lines(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 = from_display_lines(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 = from_display_lines(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 = from_display_lines(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 = from_display_lines(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 = from_display_lines(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 = from_display_lines(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 = from_display_lines(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 = from_display_lines(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/renderer/margin.rs b/src/renderer/margin.rs
new file mode 100644
index 0000000..361f5f3
--- /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
new file mode 100644
index 0000000..0e19c08
--- /dev/null
+++ b/src/renderer/mod.rs
@@ -0,0 +1,178 @@
+//! The renderer for [`Snippet`]s
+//!
+//! # Example
+//! ```
+//! use annotate_snippets::{Annotation, AnnotationType, Renderer, 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 display_list;
+mod margin;
+pub(crate) mod stylesheet;
+
+use crate::snippet::Snippet;
+pub use anstyle::*;
+use display_list::DisplayList;
+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,
+    margin: Option<Margin>,
+    stylesheet: Stylesheet,
+}
+
+impl Renderer {
+    /// No terminal styling
+    pub const fn plain() -> Self {
+        Self {
+            anonymized_line_numbers: false,
+            margin: None,
+            stylesheet: Stylesheet::plain(),
+        }
+    }
+
+    /// Default terminal styling
+    pub const fn styled() -> Self {
+        Self {
+            stylesheet: Stylesheet {
+                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()
+        }
+    }
+
+    /// 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,
+            &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 0000000..ee1ab93
--- /dev/null
+++ b/src/renderer/stylesheet.rs
@@ -0,0 +1,68 @@
+use anstyle::Style;
+
+#[derive(Clone, Copy, Debug)]
+pub(crate) 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::plain()
+    }
+}
+
+impl Stylesheet {
+    pub(crate) const fn plain() -> 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/snippet.rs b/src/snippet.rs
index bc7ba00..02e70cc 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 {
@@ -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/src/stylesheets/color.rs b/src/stylesheets/color.rs
deleted file mode 100644
index 024dd06..0000000
--- 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 4648852..0000000
--- 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 21cb269..0000000
--- 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 {})
-    }
-}


Test patch:
diff --git a/tests/snippet/mod.rs b/tests/deserialize/mod.rs
similarity index 87%
rename from tests/snippet/mod.rs
rename to tests/deserialize/mod.rs
index 92d272d..1763005 100644
--- a/tests/snippet/mod.rs
+++ b/tests/deserialize/mod.rs
@@ -1,10 +1,17 @@
 use serde::{Deserialize, Deserializer, Serialize};
 
 use annotate_snippets::{
-    display_list::{FormatOptions, Margin},
-    snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
+    renderer::Margin, Annotation, AnnotationType, Renderer, 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 +22,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 +32,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 +150,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/diff/mod.rs b/tests/diff/mod.rs
index 576c6c4..60ccae1 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());
             }
         }
     }
diff --git a/tests/dl_from_snippet.rs b/tests/dl_from_snippet.rs
deleted file mode 100644
index 06f2ff7..0000000
--- a/tests/dl_from_snippet.rs
+++ /dev/null
@@ -1,397 +0,0 @@
-use annotate_snippets::display_list::DisplayList;
-use annotate_snippets::{display_list as dl, formatter::get_term_style, 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![],
-        opt: Default::default(),
-    };
-    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: get_term_style(input.opt.color),
-        anonymized_line_numbers: input.opt.anonymized_line_numbers,
-        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,
-        }],
-        opt: Default::default(),
-    };
-    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: get_term_style(input.opt.color),
-        anonymized_line_numbers: input.opt.anonymized_line_numbers,
-        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,
-            },
-        ],
-        opt: Default::default(),
-    };
-    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: get_term_style(input.opt.color),
-        anonymized_line_numbers: input.opt.anonymized_line_numbers,
-        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,
-        }],
-        opt: Default::default(),
-    };
-    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: get_term_style(input.opt.color),
-        anonymized_line_numbers: input.opt.anonymized_line_numbers,
-        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![],
-        opt: Default::default(),
-    };
-    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: get_term_style(input.opt.color),
-        anonymized_line_numbers: input.opt.anonymized_line_numbers,
-        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,
-        }],
-        opt: Default::default(),
-    };
-
-    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,
-        }],
-        opt: Default::default(),
-    };
-
-    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: get_term_style(false),
-        anonymized_line_numbers: false,
-        margin: None,
-    };
-
-    assert_eq!(DisplayList::from(snippets), expected);
-}
diff --git a/tests/fixtures/no-color/issue_52.toml b/tests/fixtures/no-color/issue_52.toml
index 8d54613..d31e0cb 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 a30563b..ee1fe27 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 c3dc1e9..604e04b 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 845bf9f..3287fdc 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 21bbcd8..9fe85fb 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 84efc5f..f037c9a 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 6c38674..2e9b6d8 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 76d9519..4c609c4 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 5b432be..76ea749 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 5129f5c..c46d6e2 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 13f8543..063829a 100644
--- a/tests/fixtures_test.rs
+++ b/tests/fixtures_test.rs
@@ -1,8 +1,9 @@
+mod deserialize;
 mod diff;
-mod snippet;
 
-use crate::snippet::SnippetDef;
-use annotate_snippets::{display_list::DisplayList, snippet::Snippet};
+use crate::deserialize::Fixture;
+use annotate_snippets::Renderer;
+use annotate_snippets::Snippet;
 use glob::glob;
 use std::{error::Error, fs::File, io, io::prelude::*};
 
@@ -13,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]
@@ -27,11 +28,10 @@ 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 dl = DisplayList::from(snippet);
-        let actual_out = dl.to_string();
+        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 f95b002..97c7be3 100644
--- a/tests/formatter.rs
+++ b/tests/formatter.rs
@@ -1,544 +1,25 @@
-use annotate_snippets::display_list::*;
-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");
-}
+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,
         }],
-        opt: Default::default(),
     };
     let expected = r#"error: oops
  --> <current file>:2:8
@@ -548,26 +29,26 @@ fn test_i_29() {
   |        ^^^^ oops
   |"#;
 
-    assert_eq!(DisplayList::from(snippets).to_string(), expected);
+    let renderer = Renderer::plain();
+    assert_eq!(renderer.render(snippets).to_string(), expected);
 }
 
 #[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,
         }],
         title: None,
         footer: vec![],
-        opt: Default::default(),
     };
 
     let expected = r#" --> <current file>:1:7
@@ -576,26 +57,26 @@ fn test_point_to_double_width_characters() {
   |             ^^^^ world
   |"#;
 
-    assert_eq!(DisplayList::from(snippets).to_string(), expected);
+    let renderer = Renderer::plain();
+    assert_eq!(renderer.render(snippets).to_string(), expected);
 }
 
 #[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,
         }],
         title: None,
         footer: vec![],
-        opt: Default::default(),
     };
 
     let expected = r#" --> <current file>:1:3
@@ -606,33 +87,33 @@ fn test_point_to_double_width_characters_across_lines() {
   | |______^ Good morning
   |"#;
 
-    assert_eq!(DisplayList::from(snippets).to_string(), expected);
+    let renderer = Renderer::plain();
+    assert_eq!(renderer.render(snippets).to_string(), expected);
 }
 
 #[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,
         }],
         title: None,
         footer: vec![],
-        opt: Default::default(),
     };
 
     let expected = r#" --> <current file>:1:1
@@ -643,26 +124,26 @@ fn test_point_to_double_width_characters_multiple() {
   |     ---- note: Sushi2
   |"#;
 
-    assert_eq!(DisplayList::from(snippets).to_string(), expected);
+    let renderer = Renderer::plain();
+    assert_eq!(renderer.render(snippets).to_string(), expected);
 }
 
 #[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,
         }],
         title: None,
         footer: vec![],
-        opt: Default::default(),
     };
 
     let expected = r#" --> <current file>:1:7
@@ -671,5 +152,6 @@ fn test_point_to_double_width_characters_mixed() {
   |             ^^^^^^^^^^^ New world
   |"#;
 
-    assert_eq!(DisplayList::from(snippets).to_string(), expected);
+    let renderer = Renderer::plain();
+    assert_eq!(renderer.render(snippets).to_string(), expected);
 }