cmark_writer/
options.rs

1//! CommonMark formatting options.
2//!
3//! This module provides configuration options for the CommonMark writer.
4
5#[cfg(feature = "gfm")]
6use ecow::EcoString;
7
8/// CommonMark formatting options
9#[derive(Debug, Clone)]
10pub struct WriterOptions {
11    /// Whether to enable strict mode (strictly following CommonMark specification)
12    pub strict: bool,
13    /// Hard break mode (true uses two spaces followed by a newline, false uses backslash followed by a newline)
14    pub hard_break_spaces: bool,
15    /// Number of spaces to use for indentation levels
16    pub indent_spaces: usize,
17    /// Character to use for unordered list markers (-, +, or *)
18    pub list_marker: char,
19    /// Character to use for thematic breaks (-, *, or _)
20    pub thematic_break_char: char,
21    /// Character to use for emphasis (_, or *)
22    pub emphasis_char: char,
23    /// Character to use for strong emphasis (_, or *)
24    pub strong_char: char,
25    /// Whether to escape special characters in text content
26    pub escape_special_chars: bool,
27
28    /// Whether to enable GitHub Flavored Markdown (GFM) extensions
29    #[cfg(feature = "gfm")]
30    pub enable_gfm: bool,
31
32    /// Whether to enable GFM strikethrough syntax
33    #[cfg(feature = "gfm")]
34    pub gfm_strikethrough: bool,
35
36    /// Whether to enable GFM task lists
37    #[cfg(feature = "gfm")]
38    pub gfm_tasklists: bool,
39
40    /// Whether to enable GFM tables with alignment
41    #[cfg(feature = "gfm")]
42    pub gfm_tables: bool,
43
44    /// Whether to enable GFM autolinks without angle brackets
45    #[cfg(feature = "gfm")]
46    pub gfm_autolinks: bool,
47
48    /// List of disallowed HTML tag names in GFM mode
49    #[cfg(feature = "gfm")]
50    pub gfm_disallowed_html_tags: Vec<EcoString>,
51}
52
53impl Default for WriterOptions {
54    fn default() -> Self {
55        Self {
56            strict: true,
57            hard_break_spaces: false,
58            indent_spaces: 4,
59            list_marker: '-',
60            thematic_break_char: '-',
61            emphasis_char: '_',
62            strong_char: '*',
63            escape_special_chars: false,
64
65            #[cfg(feature = "gfm")]
66            enable_gfm: false,
67
68            #[cfg(feature = "gfm")]
69            gfm_strikethrough: false,
70
71            #[cfg(feature = "gfm")]
72            gfm_tasklists: false,
73
74            #[cfg(feature = "gfm")]
75            gfm_tables: false,
76
77            #[cfg(feature = "gfm")]
78            gfm_autolinks: false,
79
80            #[cfg(feature = "gfm")]
81            gfm_disallowed_html_tags: vec![
82                "title".into(),
83                "textarea".into(),
84                "style".into(),
85                "xmp".into(),
86                "iframe".into(),
87                "noembed".into(),
88                "noframes".into(),
89                "script".into(),
90                "plaintext".into(),
91            ],
92        }
93    }
94}
95
96/// Builder for WriterOptions
97pub struct WriterOptionsBuilder {
98    options: WriterOptions,
99}
100
101impl WriterOptionsBuilder {
102    /// Create a new WriterOptionsBuilder with default options
103    pub fn new() -> Self {
104        Self {
105            options: WriterOptions::default(),
106        }
107    }
108
109    /// Set strict mode (whether to strictly follow CommonMark specification)
110    pub fn strict(mut self, strict: bool) -> Self {
111        self.options.strict = strict;
112        self
113    }
114
115    /// Set hard break mode (true uses two spaces followed by a newline, false uses backslash)
116    pub fn hard_break_spaces(mut self, hard_break_spaces: bool) -> Self {
117        self.options.hard_break_spaces = hard_break_spaces;
118        self
119    }
120
121    /// Set number of spaces for indentation
122    pub fn indent_spaces(mut self, indent_spaces: usize) -> Self {
123        self.options.indent_spaces = indent_spaces;
124        self
125    }
126
127    /// Set the marker character for unordered lists (-, +, or *)
128    pub fn list_marker(mut self, marker: char) -> Self {
129        if marker == '-' || marker == '+' || marker == '*' {
130            self.options.list_marker = marker;
131        }
132        self
133    }
134
135    /// Set whether to escape special characters in text content
136    pub fn escape_special_chars(mut self, escape: bool) -> Self {
137        self.options.escape_special_chars = escape;
138        self
139    }
140
141    /// Set the character for thematic breaks (-, *, or _)
142    pub fn thematic_break_char(mut self, char: char) -> Self {
143        if char == '-' || char == '*' || char == '_' {
144            self.options.thematic_break_char = char;
145        }
146        self
147    }
148
149    /// Set the character for emphasis (_, or *)
150    pub fn emphasis_char(mut self, char: char) -> Self {
151        if char == '_' || char == '*' {
152            self.options.emphasis_char = char;
153        }
154        self
155    }
156
157    /// Set the character for strong emphasis (_, or *)
158    pub fn strong_char(mut self, char: char) -> Self {
159        if char == '_' || char == '*' {
160            self.options.strong_char = char;
161        }
162        self
163    }
164
165    /// Enable all GitHub Flavored Markdown (GFM) extensions
166    #[cfg(feature = "gfm")]
167    pub fn enable_gfm(mut self) -> Self {
168        self.options.enable_gfm = true;
169        self.options.gfm_strikethrough = true;
170        self.options.gfm_tasklists = true;
171        self.options.gfm_tables = true;
172        self.options.gfm_autolinks = true;
173        self
174    }
175
176    /// Enable or disable GFM strikethrough syntax
177    #[cfg(feature = "gfm")]
178    pub fn gfm_strikethrough(mut self, enable: bool) -> Self {
179        self.options.gfm_strikethrough = enable;
180        if enable {
181            self.options.enable_gfm = true;
182        }
183        self
184    }
185
186    /// Enable or disable GFM task lists
187    #[cfg(feature = "gfm")]
188    pub fn gfm_tasklists(mut self, enable: bool) -> Self {
189        self.options.gfm_tasklists = enable;
190        if enable {
191            self.options.enable_gfm = true;
192        }
193        self
194    }
195
196    /// Enable or disable GFM tables with alignment
197    #[cfg(feature = "gfm")]
198    pub fn gfm_tables(mut self, enable: bool) -> Self {
199        self.options.gfm_tables = enable;
200        if enable {
201            self.options.enable_gfm = true;
202        }
203        self
204    }
205
206    /// Enable or disable GFM autolinks without angle brackets
207    #[cfg(feature = "gfm")]
208    pub fn gfm_autolinks(mut self, enable: bool) -> Self {
209        self.options.gfm_autolinks = enable;
210        if enable {
211            self.options.enable_gfm = true;
212        }
213        self
214    }
215
216    /// Set list of disallowed HTML tags in GFM mode
217    #[cfg(feature = "gfm")]
218    pub fn gfm_disallowed_html_tags(mut self, tags: Vec<EcoString>) -> Self {
219        self.options.gfm_disallowed_html_tags = tags;
220        self
221    }
222
223    /// Build the WriterOptions
224    pub fn build(self) -> WriterOptions {
225        self.options
226    }
227}
228
229impl Default for WriterOptionsBuilder {
230    fn default() -> Self {
231        Self::new()
232    }
233}