1use nom::IResult;
2use std::cell::RefCell;
3use std::collections::HashMap;
4use std::rc::Rc;
5use std::sync::{Arc, OnceLock};
6
7type ElementMapFn<ELT> = Rc<RefCell<Box<dyn FnMut(ELT) -> ELT>>>;
9
10type ElementFlatMapFn<ELT> = Rc<RefCell<Box<dyn FnMut(ELT) -> Vec<ELT>>>>;
12
13type CustomBlockParserFn =
15 Rc<RefCell<Box<dyn for<'a> FnMut(&'a str) -> IResult<&'a str, Vec<crate::ast::Block>>>>>;
16
17type CustomInlineParserFn =
19 Rc<RefCell<Box<dyn for<'a> FnMut(&'a str) -> IResult<&'a str, Vec<crate::ast::Inline>>>>>;
20
21pub const DEFAULT_MAX_NESTING_DEPTH: usize = 32;
23
24#[derive(Clone)]
26pub enum ElementBehavior<ELT> {
27 Parse,
29
30 Ignore,
33
34 Skip,
36
37 Map(ElementMapFn<ELT>),
39
40 FlatMap(ElementFlatMapFn<ELT>),
42}
43
44#[derive(Clone)]
46pub struct MarkdownParserConfig {
47 pub(crate) allow_no_space_in_headings: bool,
49
50 pub(crate) html_entities_map: Arc<HashMap<String, &'static entities::Entity>>,
53
54 pub(crate) max_nesting_depth: usize,
57
58 pub(crate) block_blockquote_behavior: ElementBehavior<crate::ast::Block>,
60
61 pub(crate) block_github_alert_behavior: ElementBehavior<crate::ast::Block>,
63
64 pub(crate) block_heading_v1_behavior: ElementBehavior<crate::ast::Block>,
66
67 pub(crate) block_heading_v2_behavior: ElementBehavior<crate::ast::Block>,
69
70 pub(crate) block_thematic_break_behavior: ElementBehavior<crate::ast::Block>,
72
73 pub(crate) block_list_behavior: ElementBehavior<crate::ast::Block>,
75
76 pub(crate) block_code_block_behavior: ElementBehavior<crate::ast::Block>,
78
79 pub(crate) block_html_block_behavior: ElementBehavior<crate::ast::Block>,
81
82 pub(crate) block_footnote_definition_behavior: ElementBehavior<crate::ast::Block>,
84
85 pub(crate) block_link_definition_behavior: ElementBehavior<crate::ast::Block>,
87
88 pub(crate) block_table_behavior: ElementBehavior<crate::ast::Block>,
90
91 pub(crate) block_paragraph_behavior: ElementBehavior<crate::ast::Block>,
93
94 pub(crate) inline_autolink_behavior: ElementBehavior<crate::ast::Inline>,
96
97 pub(crate) inline_link_behavior: ElementBehavior<crate::ast::Inline>,
99
100 pub(crate) inline_footnote_reference_behavior: ElementBehavior<crate::ast::Inline>,
102
103 pub(crate) inline_reference_link_behavior: ElementBehavior<crate::ast::Inline>,
105
106 pub(crate) inline_hard_newline_behavior: ElementBehavior<crate::ast::Inline>,
108
109 pub(crate) inline_image_behavior: ElementBehavior<crate::ast::Inline>,
111
112 pub(crate) inline_code_span_behavior: ElementBehavior<crate::ast::Inline>,
114
115 pub(crate) inline_emphasis_behavior: ElementBehavior<crate::ast::Inline>,
117
118 pub(crate) inline_strikethrough_behavior: ElementBehavior<crate::ast::Inline>,
120
121 pub(crate) inline_text_behavior: ElementBehavior<crate::ast::Inline>,
123
124 pub(crate) custom_block_parser: Option<CustomBlockParserFn>,
126
127 pub(crate) custom_inline_parser: Option<CustomInlineParserFn>,
129}
130
131impl Default for MarkdownParserConfig {
132 fn default() -> Self {
133 Self {
134 allow_no_space_in_headings: false,
135 html_entities_map: Self::make_html_entities_map(),
136 max_nesting_depth: DEFAULT_MAX_NESTING_DEPTH,
137 block_blockquote_behavior: ElementBehavior::Parse,
138 block_github_alert_behavior: ElementBehavior::Parse,
139 block_heading_v1_behavior: ElementBehavior::Parse,
140 block_heading_v2_behavior: ElementBehavior::Parse,
141 block_thematic_break_behavior: ElementBehavior::Parse,
142 block_list_behavior: ElementBehavior::Parse,
143 block_code_block_behavior: ElementBehavior::Parse,
144 block_html_block_behavior: ElementBehavior::Parse,
145 block_footnote_definition_behavior: ElementBehavior::Parse,
146 block_link_definition_behavior: ElementBehavior::Parse,
147 block_table_behavior: ElementBehavior::Parse,
148 block_paragraph_behavior: ElementBehavior::Parse,
149 inline_autolink_behavior: ElementBehavior::Parse,
150 inline_link_behavior: ElementBehavior::Parse,
151 inline_footnote_reference_behavior: ElementBehavior::Parse,
152 inline_reference_link_behavior: ElementBehavior::Parse,
153 inline_hard_newline_behavior: ElementBehavior::Parse,
154 inline_image_behavior: ElementBehavior::Parse,
155 inline_code_span_behavior: ElementBehavior::Parse,
156 inline_emphasis_behavior: ElementBehavior::Parse,
157 inline_strikethrough_behavior: ElementBehavior::Parse,
158 inline_text_behavior: ElementBehavior::Parse,
159 custom_block_parser: None,
160 custom_inline_parser: None,
161 }
162 }
163}
164
165impl MarkdownParserConfig {
166 fn make_html_entities_map() -> Arc<HashMap<String, &'static entities::Entity>> {
167 static DEFAULT: OnceLock<Arc<HashMap<String, &'static entities::Entity>>> = OnceLock::new();
168 DEFAULT
169 .get_or_init(|| {
170 let mut map = HashMap::with_capacity(entities::ENTITIES.len());
171 for entity in entities::ENTITIES.iter() {
172 map.insert(entity.entity.to_string(), entity);
173 }
174 Arc::new(map)
175 })
176 .clone()
177 }
178
179 pub fn with_allow_no_space_in_headings(self) -> Self {
181 Self {
182 allow_no_space_in_headings: true,
183 ..self
184 }
185 }
186
187 pub fn with_max_nesting_depth(self, depth: usize) -> Self {
198 Self {
199 max_nesting_depth: depth,
200 ..self
201 }
202 }
203
204 pub fn with_html_entities_map(
206 self,
207 html_entities_map: HashMap<String, &'static entities::Entity>,
208 ) -> Self {
209 Self {
210 html_entities_map: Arc::new(html_entities_map),
211 ..self
212 }
213 }
214
215 pub fn with_block_blockquote_behavior(
217 self,
218 behavior: ElementBehavior<crate::ast::Block>,
219 ) -> Self {
220 Self {
221 block_blockquote_behavior: behavior,
222 ..self
223 }
224 }
225
226 pub fn with_block_github_alert_behavior(
228 self,
229 behavior: ElementBehavior<crate::ast::Block>,
230 ) -> Self {
231 Self {
232 block_github_alert_behavior: behavior,
233 ..self
234 }
235 }
236
237 pub fn with_block_heading_v1_behavior(
239 self,
240 behavior: ElementBehavior<crate::ast::Block>,
241 ) -> Self {
242 Self {
243 block_heading_v1_behavior: behavior,
244 ..self
245 }
246 }
247
248 pub fn with_block_heading_v2_behavior(
250 self,
251 behavior: ElementBehavior<crate::ast::Block>,
252 ) -> Self {
253 Self {
254 block_heading_v2_behavior: behavior,
255 ..self
256 }
257 }
258
259 pub fn with_block_thematic_break_behavior(
261 self,
262 behavior: ElementBehavior<crate::ast::Block>,
263 ) -> Self {
264 Self {
265 block_thematic_break_behavior: behavior,
266 ..self
267 }
268 }
269
270 pub fn with_block_list_behavior(self, behavior: ElementBehavior<crate::ast::Block>) -> Self {
272 Self {
273 block_list_behavior: behavior,
274 ..self
275 }
276 }
277
278 pub fn with_block_code_block_behavior(
280 self,
281 behavior: ElementBehavior<crate::ast::Block>,
282 ) -> Self {
283 Self {
284 block_code_block_behavior: behavior,
285 ..self
286 }
287 }
288
289 pub fn with_block_html_block_behavior(
291 self,
292 behavior: ElementBehavior<crate::ast::Block>,
293 ) -> Self {
294 Self {
295 block_html_block_behavior: behavior,
296 ..self
297 }
298 }
299
300 pub fn with_block_footnote_definition_behavior(
302 self,
303 behavior: ElementBehavior<crate::ast::Block>,
304 ) -> Self {
305 Self {
306 block_footnote_definition_behavior: behavior,
307 ..self
308 }
309 }
310
311 pub fn with_block_link_definition_behavior(
313 self,
314 behavior: ElementBehavior<crate::ast::Block>,
315 ) -> Self {
316 Self {
317 block_link_definition_behavior: behavior,
318 ..self
319 }
320 }
321
322 pub fn with_block_table_behavior(self, behavior: ElementBehavior<crate::ast::Block>) -> Self {
324 Self {
325 block_table_behavior: behavior,
326 ..self
327 }
328 }
329
330 pub fn with_block_paragraph_behavior(
332 self,
333 behavior: ElementBehavior<crate::ast::Block>,
334 ) -> Self {
335 Self {
336 block_paragraph_behavior: behavior,
337 ..self
338 }
339 }
340
341 pub fn with_inline_autolink_behavior(
343 self,
344 behavior: ElementBehavior<crate::ast::Inline>,
345 ) -> Self {
346 Self {
347 inline_autolink_behavior: behavior,
348 ..self
349 }
350 }
351
352 pub fn with_inline_link_behavior(self, behavior: ElementBehavior<crate::ast::Inline>) -> Self {
354 Self {
355 inline_link_behavior: behavior,
356 ..self
357 }
358 }
359
360 pub fn with_inline_footnote_reference_behavior(
362 self,
363 behavior: ElementBehavior<crate::ast::Inline>,
364 ) -> Self {
365 Self {
366 inline_footnote_reference_behavior: behavior,
367 ..self
368 }
369 }
370
371 pub fn with_inline_reference_link_behavior(
373 self,
374 behavior: ElementBehavior<crate::ast::Inline>,
375 ) -> Self {
376 Self {
377 inline_reference_link_behavior: behavior,
378 ..self
379 }
380 }
381
382 pub fn with_inline_hard_newline_behavior(
384 self,
385 behavior: ElementBehavior<crate::ast::Inline>,
386 ) -> Self {
387 Self {
388 inline_hard_newline_behavior: behavior,
389 ..self
390 }
391 }
392
393 pub fn with_inline_image_behavior(self, behavior: ElementBehavior<crate::ast::Inline>) -> Self {
395 Self {
396 inline_image_behavior: behavior,
397 ..self
398 }
399 }
400
401 pub fn with_inline_code_span_behavior(
403 self,
404 behavior: ElementBehavior<crate::ast::Inline>,
405 ) -> Self {
406 Self {
407 inline_code_span_behavior: behavior,
408 ..self
409 }
410 }
411
412 pub fn with_inline_emphasis_behavior(
414 self,
415 behavior: ElementBehavior<crate::ast::Inline>,
416 ) -> Self {
417 Self {
418 inline_emphasis_behavior: behavior,
419 ..self
420 }
421 }
422
423 pub fn with_inline_strikethrough_behavior(
425 self,
426 behavior: ElementBehavior<crate::ast::Inline>,
427 ) -> Self {
428 Self {
429 inline_strikethrough_behavior: behavior,
430 ..self
431 }
432 }
433
434 pub fn with_inline_text_behavior(self, behavior: ElementBehavior<crate::ast::Inline>) -> Self {
436 Self {
437 inline_text_behavior: behavior,
438 ..self
439 }
440 }
441
442 pub fn with_custom_block_parser(self, parser: CustomBlockParserFn) -> Self {
444 Self {
445 custom_block_parser: Some(parser),
446 ..self
447 }
448 }
449
450 pub fn with_custom_inline_parser(self, parser: CustomInlineParserFn) -> Self {
452 Self {
453 custom_inline_parser: Some(parser),
454 ..self
455 }
456 }
457}