tui_markdown/
options.rs

1//! Rendering configuration for tui-markdown.
2//!
3//! For now the only knob is the theme [`StyleSheet`]. This struct is `#[non_exhaustive]`, which
4//! allows us to add more options in the future without breaking existing code.
5
6use crate::{DefaultStyleSheet, StyleSheet};
7
8/// Collection of optional parameters that influence markdown rendering.
9///
10/// The generic `S` allows users to provide their own theme type that implements the
11/// [`StyleSheet`] trait. The default implementation is [`DefaultStyleSheet`], which provides a
12/// set of sensible defaults for styling markdown elements.
13///
14/// # Example
15///
16/// ```
17/// use tui_markdown::{DefaultStyleSheet, Options};
18/// let options = Options::default();
19///
20/// // or with a custom style sheet
21///
22/// use ratatui_core::style::{Style, Stylize};
23/// use tui_markdown::StyleSheet;
24///
25/// #[derive(Debug, Clone)]
26/// struct MyStyleSheet;
27///
28/// impl StyleSheet for MyStyleSheet {
29///     fn heading(&self, level: u8) -> Style {
30///         Style::new().bold()
31///     }
32///
33///     fn code(&self) -> Style {
34///         Style::new().white().on_dark_gray()
35///     }
36///
37///     fn link(&self) -> Style {
38///         Style::new().blue().underlined()
39///     }
40///
41///     fn blockquote(&self) -> Style {
42///         Style::new().yellow()
43///     }
44///
45///     fn heading_meta(&self) -> Style {
46///         Style::new().dim()
47///     }
48///
49///     fn metadata_block(&self) -> Style {
50///         Style::new().light_yellow()
51///     }
52/// }
53///
54/// let options = Options::new(MyStyleSheet);
55/// ```
56#[derive(Debug, Clone)]
57#[non_exhaustive]
58pub struct Options<S: StyleSheet = DefaultStyleSheet> {
59    /// The [`StyleSheet`] implementation that will be consulted every time the renderer needs a
60    /// color choice.
61    pub(crate) styles: S,
62}
63
64impl<S: StyleSheet> Options<S> {
65    /// Creates a new `Options` instance with the provided style sheet.
66    pub fn new(styles: S) -> Self {
67        Self { styles }
68    }
69}
70
71impl Default for Options<DefaultStyleSheet> {
72    fn default() -> Self {
73        Self::new(DefaultStyleSheet)
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use ratatui_core::style::Style;
80
81    use super::*;
82
83    #[test]
84    fn default() {
85        let options: Options = Default::default();
86        assert_eq!(
87            options.styles.heading(1),
88            Style::new().on_cyan().bold().underlined()
89        );
90    }
91
92    #[test]
93    fn custom_style_sheet() {
94        #[derive(Debug, Clone)]
95        struct CustomStyleSheet;
96
97        impl StyleSheet for CustomStyleSheet {
98            fn heading(&self, level: u8) -> Style {
99                match level {
100                    1 => Style::new().red().bold(),
101                    _ => Style::new().green(),
102                }
103            }
104
105            fn code(&self) -> Style {
106                Style::new().white().on_black()
107            }
108
109            fn link(&self) -> Style {
110                Style::new().blue().underlined()
111            }
112
113            fn blockquote(&self) -> Style {
114                Style::new().yellow()
115            }
116
117            fn heading_meta(&self) -> Style {
118                Style::new().dim()
119            }
120
121            fn metadata_block(&self) -> Style {
122                Style::new().light_yellow()
123            }
124        }
125
126        let options = Options {
127            styles: CustomStyleSheet,
128        };
129
130        assert_eq!(options.styles.heading(1), Style::new().red().bold());
131        assert_eq!(options.styles.heading(2), Style::new().green());
132        assert_eq!(options.styles.code(), Style::new().white().on_black());
133        assert_eq!(options.styles.link(), Style::new().blue().underlined());
134        assert_eq!(options.styles.blockquote(), Style::new().yellow());
135        assert_eq!(options.styles.heading_meta(), Style::new().dim());
136        assert_eq!(options.styles.metadata_block(), Style::new().light_yellow());
137    }
138}