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}