1use crate::message::Message;
10use alloc::{format, string::String};
11
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13pub enum IndentOptions {
15 Mixed,
18 One,
20 Tab,
22}
23
24#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
26pub enum LineWrapping {
27 #[default]
29 Preserve,
30 Unwrap,
34}
35
36#[derive(Clone, Debug)]
38pub struct Options {
39 pub line_wrapping: LineWrapping,
41 pub bullet: char,
44 pub bullet_ordered: char,
47 pub bullet_other: char,
51 pub close_atx: bool,
54 pub emphasis: char,
56 pub fence: char,
58 pub fences: bool,
63 pub increment_list_marker: bool,
66 pub list_item_indent: IndentOptions,
68 pub quote: char,
70 pub resource_link: bool,
74 pub rule: char,
77 pub rule_repetition: u32,
80 pub rule_spaces: bool,
83 pub setext: bool,
90 pub single_dollar_text_math: bool,
95 pub strong: char,
97 pub tight_definitions: bool,
100}
101
102impl Default for Options {
103 fn default() -> Self {
104 Self {
105 line_wrapping: LineWrapping::default(),
106 bullet: '-',
107 bullet_ordered: '.',
108 bullet_other: '-',
109 close_atx: false,
110 emphasis: '*',
111 fence: '`',
112 fences: true,
113 increment_list_marker: true,
114 list_item_indent: IndentOptions::One,
115 quote: '"',
116 resource_link: false,
117 rule: '*',
118 rule_repetition: 3,
119 rule_spaces: false,
120 setext: false,
121 single_dollar_text_math: true,
122 strong: '*',
123 tight_definitions: false,
124 }
125 }
126}
127
128impl Options {
129 pub(super) fn check_bullet(&self) -> Result<char, Message> {
130 let marker = self.bullet;
131
132 if marker != '*' && marker != '+' && marker != '-' {
133 return Err(invalid_option(
134 format!("Cannot serialize items with `{marker}` for `options.bullet`, expected `*`, `+`, or `-`"),
135 "unexpected-marker",
136 ));
137 }
138
139 Ok(marker)
140 }
141
142 pub(super) fn check_bullet_ordered(&self) -> Result<char, Message> {
143 let marker = self.bullet_ordered;
144
145 if marker != '.' && marker != ')' {
146 return Err(invalid_option(format!("Cannot serialize items with `{marker}` for `options.bullet_ordered`, expected `.` or `)`"), "unexpected-marker"));
147 }
148
149 Ok(marker)
150 }
151
152 pub(super) fn check_bullet_other(&self) -> Result<char, Message> {
153 let bullet = self.check_bullet()?;
154 let mut bullet_other = self.bullet_other;
155
156 if bullet != '*' {
157 bullet_other = '*';
158 }
159
160 if bullet_other != '*' && bullet_other != '+' && bullet_other != '-' {
161 return Err(invalid_option(format!("Cannot serialize items with `{bullet_other}` for `options.bullet_other`, expected `*`, `+`, or `-`"), "unexpected-marker"));
162 }
163
164 if bullet_other == bullet {
165 return Err(invalid_option(
166 format!("Expected `bullet` (`{bullet}`) and `bullet_other` (`{bullet_other}`) to be different"),
167 "bullet-match-bullet_other",
168 ));
169 }
170
171 Ok(bullet_other)
172 }
173
174 pub(super) fn check_emphasis(&self) -> Result<char, Message> {
175 let marker = self.emphasis;
176
177 if marker != '*' && marker != '_' {
178 return Err(invalid_option(
179 format!("Cannot serialize emphasis with `{marker}` for `options.emphasis`, expected `*`, or `_`"),
180 "unexpected-marker",
181 ));
182 }
183
184 Ok(marker)
185 }
186
187 pub(super) fn check_fence(&self) -> Result<char, Message> {
188 let marker = self.fence;
189
190 if marker != '`' && marker != '~' {
191 return Err(invalid_option(
192 format!("Cannot serialize code with `{marker}` for `options.fence`, expected `` ` `` or `~`"),
193 "unexpected-marker",
194 ));
195 }
196
197 Ok(marker)
198 }
199
200 pub(super) fn check_quote(&self) -> Result<char, Message> {
201 let marker = self.quote;
202
203 if marker != '"' && marker != '\'' {
204 return Err(invalid_option(
205 format!("Cannot serialize title with `{marker}` for `options.quote`, expected `\"`, or `'`"),
206 "unexpected-marker",
207 ));
208 }
209
210 Ok(marker)
211 }
212
213 pub(super) fn check_rule(&self) -> Result<char, Message> {
214 let marker = self.rule;
215
216 if marker != '*' && marker != '-' && marker != '_' {
217 return Err(invalid_option(
218 format!("Cannot serialize rules with `{marker}` for `options.rule`, expected `*`, `-`, or `_`"),
219 "unexpected-marker",
220 ));
221 }
222
223 Ok(marker)
224 }
225
226 pub(super) fn check_rule_repetition(&self) -> Result<u32, Message> {
227 let repetition = self.rule_repetition;
228
229 if repetition < 3 {
230 return Err(invalid_option(format!("Cannot serialize rules with repetition `{repetition}` for `options.rule_repetition`, expected `3` or more"), "unexpected-marker"));
231 }
232
233 Ok(repetition)
234 }
235
236 pub(super) fn check_strong(&self) -> Result<char, Message> {
237 let marker = self.strong;
238
239 if marker != '*' && marker != '_' {
240 return Err(invalid_option(
241 format!("Cannot serialize strong with `{marker}` for `options.strong`, expected `*`, or `_`"),
242 "unexpected-marker",
243 ));
244 }
245
246 Ok(marker)
247 }
248}
249
250fn invalid_option(reason: String, rule_id: &'static str) -> Message {
251 Message {
252 span: None,
253 reason: reason.into(),
254 rule_id,
255 source: "mdast-util-to-markdown",
256 }
257}
258
259#[cfg(test)]
260mod tests;