1pub mod modifier;
5
6
7use std::collections::HashSet;
8use std::fmt::Debug;
9use std::sync::Arc;
10use getset::{Getters, Setters};
11use indexmap::IndexMap;
12use modifier::base_modifier::BaseModifier;
13use modifier::{Modifier, ModifierIdentifier};
14use self::modifier::standard_paragraph_modifier::StandardParagraphModifier;
15use self::modifier::standard_text_modifier::StandardTextModifier;
16use crate::assembler::html_assembler::HtmlAssembler;
17use crate::assembler::Assembler;
18use crate::compilable_text::compilable_text_part::CompilableTextPart;
19use crate::compilable_text::CompilableText;
20use crate::compilation::compilation_rule::replacement_rule::replacement_rule_part::closure_replacement_rule_part::ClosureReplacementRuleReplacerPart;
21use crate::compilation::compilation_rule::replacement_rule::replacement_rule_part::fixed_replacement_rule_part::FixedReplacementRuleReplacerPart;
22use crate::compilation::compilation_rule::replacement_rule::replacement_rule_part::single_capture_group_replacement_rule_part::SingleCaptureGroupReplacementRuleReplacerPart;
23use crate::compilation::compilation_rule::replacement_rule::ReplacementRule;
24use crate::dossier::document::chapter::paragraph::paragraph_loading_rule::block_quote_paragraph_loading_rule::BlockQuoteParagraphLoadingRule;
25use crate::dossier::document::chapter::paragraph::paragraph_loading_rule::common_paragraph_loading_rule::CommonParagraphLoadingRule;
26use crate::dossier::document::chapter::paragraph::paragraph_loading_rule::focus_block_paragraph_loading_rule::FocusBlockParagraphLoadingRule;
27use crate::dossier::document::chapter::paragraph::paragraph_loading_rule::image_paragraph_loading_rule::ImageParagraphLoadingRule;
28use crate::dossier::document::chapter::paragraph::paragraph_loading_rule::list_paragraph_loading_rule::ListParagraphLoadingRule;
29use crate::dossier::document::chapter::paragraph::paragraph_loading_rule::metadata_wrapper_paragraph_loading_rule::MetadataWrapperParagraphLoadingRule;
30use crate::dossier::document::chapter::paragraph::paragraph_loading_rule::replacement_rule_paragraph_loading_rule::ReplacementRuleParagraphLoadingRule;
31use crate::dossier::document::chapter::paragraph::paragraph_loading_rule::table_paragraph_loading_rule::TableParagraphLoadingRule;
32use crate::dossier::document::chapter::paragraph::paragraph_loading_rule::{MultiParagraphLoadingRule, ParagraphLoadingRule};
33use crate::output_format::OutputFormat;
34use crate::resource::resource_reference::ResourceReference;
35use crate::utility::text_utility;
36use super::compilation::compilation_rule::constants::ESCAPE_HTML;
37use super::compilation::compilation_rule::html_cite_rule::HtmlCiteRule;
38use super::compilation::compilation_rule::html_greek_letter_rule::HtmlGreekLettersRule;
39use super::compilation::compilation_rule::reference_rule::ReferenceRule;
40use super::compilation::compilation_rule::CompilationRule;
41
42
43pub type TextModifierOrderedMap = IndexMap<ModifierIdentifier, (Box<dyn Modifier>, Box<dyn CompilationRule>)>;
44pub type ParagraphModifierOrderedMap = IndexMap<ModifierIdentifier, (Box<dyn Modifier>, Box<dyn ParagraphLoadingRule>)>;
45pub type FallbackParagraph = (ModifierIdentifier, Box<dyn MultiParagraphLoadingRule>);
46
47
48#[derive(Debug, Getters, Setters)]
51pub struct Codex {
52
53 #[getset(get = "pub", set = "pub")]
54 text_modifiers: TextModifierOrderedMap,
55
56 #[getset(get = "pub", set = "pub")]
57 paragraph_modifiers: ParagraphModifierOrderedMap,
58
59 #[getset(get = "pub", set = "pub")]
60 fallback_paragraph: Option<FallbackParagraph>,
61
62 #[getset(get = "pub", set = "pub")]
63 assembler: Box<dyn Assembler>
64}
65
66impl Codex {
67
68 pub fn from(format: &OutputFormat) -> Self {
69 match format {
70 OutputFormat::Html => Self::of_html()
71 }
72 }
73
74 pub fn new(text_modifiers: TextModifierOrderedMap, paragraph_modifiers: ParagraphModifierOrderedMap,
76 fallback_paragraph_modifier: Option<FallbackParagraph>,
77 assembler: Box<dyn Assembler>,) -> Self {
78
79 Self {
80 text_modifiers,
81 paragraph_modifiers,
82 fallback_paragraph: fallback_paragraph_modifier,
83 assembler
84 }
85 }
86
87 pub fn retain(&mut self, identifiers: HashSet<ModifierIdentifier>) {
89
90 self.text_modifiers.retain(|id, _| identifiers.contains(id));
91 self.paragraph_modifiers.retain(|id, _| identifiers.contains(id));
92 }
93
94
95 pub fn remove(&mut self, identifiers: HashSet<ModifierIdentifier>) {
97 identifiers.iter().for_each(|id: &ModifierIdentifier| {
98
99 self.text_modifiers.shift_remove(id);
100 self.paragraph_modifiers.shift_remove(id);
101 });
102 }
103
104 pub fn of_html() -> Self {
106
107 let text_rules: TextModifierOrderedMap = TextModifierOrderedMap::from([
108 (
109 StandardTextModifier::InlineCode.identifier().clone(),
110 (
111 Box::new(Into::<BaseModifier>::into(StandardTextModifier::InlineCode)) as Box<dyn Modifier>,
112 Box::new(ReplacementRule::new(
113 StandardTextModifier::InlineCode.modifier_pattern().clone(),
114 vec![
115 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<code class="language-markup inline-code">"#))),
116 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::InlineCode.incompatible_modifiers())),
117 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</code>"#))),
118 ]
119 )) as Box<dyn CompilationRule>
120 ) as (Box<dyn Modifier>, Box<dyn CompilationRule>)
121 ),
122 (
123 StandardTextModifier::InlineMath.identifier().clone(),
124 (
125 Box::new(Into::<BaseModifier>::into(StandardTextModifier::InlineMath)),
126 Box::new(ReplacementRule::new(
127 StandardTextModifier::InlineMath.modifier_pattern().clone(),
128 vec![
129 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<span class="inline-math">$"#))),
130 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::InlineMath.incompatible_modifiers())),
131 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"$</span>"#))),
132 ]
133 ))
134 )
135 ),
136 (
137 StandardTextModifier::Comment.identifier().clone(),
138 (
139 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Comment)),
140 Box::new(ReplacementRule::new(
141 StandardTextModifier::Comment.modifier_pattern().clone(),
142 vec![
143 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<!-- "#))),
144 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::Comment.incompatible_modifiers())),
145 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#" -->"#))),
146 ]
147 ))
148 )
149 ),
150 (
151 StandardTextModifier::GreekLetter.identifier().clone(),
152 (
153 Box::new(Into::<BaseModifier>::into(StandardTextModifier::GreekLetter)),
154 Box::new(HtmlGreekLettersRule::new())
155 ),
156 ),
157 (
158 StandardTextModifier::Todo.identifier().clone(),
159 (
160 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Todo)) as Box<dyn Modifier>,
161 Box::new(ReplacementRule::new(
162 StandardTextModifier::Todo.modifier_pattern().clone(),
163 vec![
164 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<div class="todo"><div class="todo-title"></div><div class="todo-description">"#))),
165 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::Todo.incompatible_modifiers())),
166 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</div></div>"#))),
167 ]
168 )) as Box<dyn CompilationRule>,
169 ) as (Box<dyn Modifier>, Box<dyn CompilationRule>)
170 ),
171 (
172 StandardTextModifier::Bookmark.identifier().clone(),
173 (
174 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Bookmark)),
175 Box::new(ReplacementRule::new(
176 StandardTextModifier::Bookmark.modifier_pattern().clone(),
177 vec![
178 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|captures, _, _, _, cco| {
179
180 let mut identifier_class = String::new();
181 let mut id_attr = String::new();
182 if let Some(raw_id) = captures.get(2) {
183 id_attr = format!(
184 r#"id="{}""#,
185 ResourceReference::of_internal_from_without_sharp(raw_id.as_str(), cco.document_name().as_ref())?.build(),
186 );
187
188 identifier_class = String::from("identifier");
189 }
190
191 Ok(CompilableText::from(vec![
192 CompilableTextPart::new_fixed(format!(
193 r#"<div class="{} bookmark" {}><div class="bookmark-title">"#,
194 identifier_class,
195 id_attr
196 ))
197 ]))
198 }))),
199 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::Bookmark.incompatible_modifiers())),
200 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</div><div class="bookmark-description">"#))),
201 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(3, ESCAPE_HTML.clone(), StandardTextModifier::Bookmark.incompatible_modifiers())),
202 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</div></div>"#))),
203 ])),
204 )
205 ),
206 (
207 StandardTextModifier::AbridgedBookmark.identifier().clone(),
208 (
209 Box::new(Into::<BaseModifier>::into(StandardTextModifier::AbridgedBookmark)),
210 Box::new(ReplacementRule::new(
211 StandardTextModifier::AbridgedBookmark.modifier_pattern().clone(),
212 vec![
213 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|captures, _, _, _, cco| {
214
215 let mut identifier_class = String::new();
216 let mut id_attr = String::new();
217 if let Some(raw_id) = captures.get(2) {
218 id_attr = format!(
219 r#"id="{}""#,
220 ResourceReference::of_internal_from_without_sharp(raw_id.as_str(), cco.document_name().as_ref())?.build(),
221 );
222
223 identifier_class = String::from("identifier");
224 }
225
226 Ok(CompilableText::from(vec![
227 CompilableTextPart::new_fixed(format!(
228 r#"<div class="{} abridged-bookmark" {}><div class="abridged-bookmark-title">"#,
229 identifier_class,
230 id_attr,
231 ))
232 ]))
233 }))),
234 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::AbridgedBookmark.incompatible_modifiers())),
235 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</div></div>"#)))
236 ]
237 ))
238 )
239 ),
240 (
241 StandardTextModifier::EmbeddedStyle.identifier().clone(),
242 (
243 Box::new(Into::<BaseModifier>::into(StandardTextModifier::EmbeddedStyle)),
244 Box::new(ReplacementRule::new(
245 StandardTextModifier::EmbeddedStyle.modifier_pattern().clone(),
246 vec![
247 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|captures, _, _, _, cco| {
248
249 let (styles, classes) = text_utility::split_styles_and_classes(captures.get(3).unwrap().as_str());
250
251 let mut identifier_class = String::new();
252 let mut id_attr = String::new();
253 if let Some(raw_id) = captures.get(2) {
254 id_attr = format!(
255 r#"id="{}""#,
256 ResourceReference::of_internal_from_without_sharp(raw_id.as_str(), cco.document_name().as_ref())?.build(),
257 );
258
259 identifier_class = String::from("identifier");
260 }
261
262 Ok(CompilableText::from(vec![
263 CompilableTextPart::new_fixed(format!(
264 r#"<span class="{} embedded-style {}" {} style="{}">"#,
265 identifier_class,
266 classes.unwrap_or(String::new()),
267 id_attr,
268 styles.unwrap_or(String::new())
269 ))
270 ]))
271 }))),
272 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::EmbeddedStyle.incompatible_modifiers())),
273 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</span>"#)))
274 ]
275 ))
276 )
277 ),
278 (
279 StandardTextModifier::AbridgedEmbeddedStyle.identifier().clone(),
280 (
281 Box::new(Into::<BaseModifier>::into(StandardTextModifier::AbridgedEmbeddedStyle)),
282 Box::new(ReplacementRule::new(
283 StandardTextModifier::AbridgedEmbeddedStyle.modifier_pattern().clone(),
284 vec![
285 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|captures, _, _, _, cco| {
286
287 let mut identifier_class = String::new();
288 let mut id_attr = String::new();
289 if let Some(raw_id) = captures.get(2) {
290 id_attr = format!(
291 r#"id="{}""#,
292 ResourceReference::of_internal_from_without_sharp(raw_id.as_str(), cco.document_name().as_ref())?.build(),
293 );
294
295 identifier_class = String::from("identifier");
296 }
297
298 let mut color_style = String::new();
299 if let Some(color) = captures.get(4) {
300 color_style = format!("color: {};", color.as_str());
301 }
302
303 let mut bg_style = String::new();
304 if let Some(bg) = captures.get(5) {
305 bg_style = format!("background-color: {};", bg.as_str());
306 }
307
308 let mut font_style = String::new();
309 if let Some(font) = captures.get(6) {
310 font_style = format!("font-family: {};", font.as_str());
311 }
312
313 Ok(CompilableText::from(vec![
314 CompilableTextPart::new_fixed(format!(
315 r#"<span class="{} abridged-embedded-style" {} style="{} {} {}">"#,
316 identifier_class,
317 id_attr,
318 color_style,
319 bg_style,
320 font_style,
321 ))
322 ]))
323 }))),
324 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::AbridgedEmbeddedStyle.incompatible_modifiers())),
325 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</span>"#)))
326 ]
327 ))
328 )
329 ),
330 (
331 StandardTextModifier::Identifier.identifier().clone(),
332 (
333 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Identifier)),
334 Box::new(ReplacementRule::new(
335 StandardTextModifier::Identifier.modifier_pattern().clone(),
336 vec![
337 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|captures, _, _, _, cco| {
338
339 Ok(CompilableText::from(vec![
340 CompilableTextPart::new_fixed(format!(
341 r#"<span class="identifier" id="{}">"#,
342 ResourceReference::of_internal_from_without_sharp(captures.get(2).unwrap().as_str(), cco.document_name().as_ref())?.build(),
343 ))
344 ]))
345 }))),
346 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::Identifier.incompatible_modifiers())),
347 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</span>"#)))
348 ]
349 ))
350 )
351 ),
352 (
353 StandardTextModifier::Highlight.identifier().clone(),
354 (
355 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Highlight)),
356 Box::new(ReplacementRule::new(
357 StandardTextModifier::Highlight.modifier_pattern().clone(),
358 vec![
359 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<mark class="highlight">"#))),
360 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::Highlight.incompatible_modifiers())),
361 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</mark>"#))),
362 ]
363 ))
364 )
365 ),
366 (
367 StandardTextModifier::BoldStarVersion.identifier().clone(),
368 (
369 Box::new(Into::<BaseModifier>::into(StandardTextModifier::BoldStarVersion)),
370 Box::new(ReplacementRule::new(
371 StandardTextModifier::BoldStarVersion.modifier_pattern().clone(),
372 vec![
373 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<strong class="bold">"#))),
374 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::BoldStarVersion.incompatible_modifiers())),
375 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</strong>"#))),
376 ]
377 ))
378 )
379 ),
380 (
381 StandardTextModifier::BoldUnderscoreVersion.identifier().clone(),
382 (
383 Box::new(Into::<BaseModifier>::into(StandardTextModifier::BoldUnderscoreVersion)),
384 Box::new(ReplacementRule::new(
385 StandardTextModifier::BoldUnderscoreVersion.modifier_pattern().clone(),
386 vec![
387 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<strong class="bold">"#))),
388 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::BoldUnderscoreVersion.incompatible_modifiers())),
389 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</strong>"#))),
390 ]
391 ))
392 )
393 ),
394 (
395 StandardTextModifier::ItalicStarVersion.identifier().clone(),
396 (
397 Box::new(Into::<BaseModifier>::into(StandardTextModifier::ItalicStarVersion)),
398 Box::new(ReplacementRule::new(
399 StandardTextModifier::ItalicStarVersion.modifier_pattern().clone(),
400 vec![
401 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<em class="italic">"#))),
402 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::ItalicStarVersion.incompatible_modifiers())),
403 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</em>"#))),
404 ]
405 ))
406 )
407 ),
408 (
409 StandardTextModifier::ItalicUnderscoreVersion.identifier().clone(),
410 (
411 Box::new(Into::<BaseModifier>::into(StandardTextModifier::ItalicUnderscoreVersion)),
412 Box::new(ReplacementRule::new(
413 StandardTextModifier::ItalicUnderscoreVersion.modifier_pattern().clone(),
414 vec![
415 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<em class="italic">"#))),
416 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::ItalicUnderscoreVersion.incompatible_modifiers())),
417 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</em>"#))),
418 ]
419 ))
420 )
421 ),
422 (
423 StandardTextModifier::Strikethrough.identifier().clone(),
424 (
425 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Strikethrough)),
426 Box::new(ReplacementRule::new(
427 StandardTextModifier::Strikethrough.modifier_pattern().clone(),
428 vec![
429 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<del class="strikethrough">"#))),
430 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::Strikethrough.incompatible_modifiers())),
431 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</del>"#))),
432 ]
433 ))
434 )
435 ),
436 (
437 StandardTextModifier::Underlined.identifier().clone(),
438 (
439 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Underlined)),
440 Box::new(ReplacementRule::new(
441 StandardTextModifier::Underlined.modifier_pattern().clone(),
442 vec![
443 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<u class="underlined">"#))),
444 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::Underlined.incompatible_modifiers())),
445 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</u>"#))),
446 ]
447 ))
448 )
449 ),
450 (
451 StandardTextModifier::Superscript.identifier().clone(),
452 (
453 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Superscript)),
454 Box::new(ReplacementRule::new(
455 StandardTextModifier::Superscript.modifier_pattern().clone(),
456 vec![
457 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<sup class="superscript">"#))),
458 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::Superscript.incompatible_modifiers())),
459 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</sup>"#))),
460 ]
461 ))
462 )
463 ),
464 (
465 StandardTextModifier::Subscript.identifier().clone(),
466 (
467 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Subscript)),
468 Box::new(ReplacementRule::new(
469 StandardTextModifier::Subscript.modifier_pattern().clone(),
470 vec![
471 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<sub class="subscript">"#))),
472 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::Subscript.incompatible_modifiers())),
473 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</sub>"#))),
474 ]
475 ))
476 )
477 ),
478 (
479 StandardTextModifier::Link.identifier().clone(),
480 (
481 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Link)),
482 Box::new(ReplacementRule::new(
483 StandardTextModifier::Link.modifier_pattern().clone(),
484 vec![
485 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|captures, _, _, _, cco| {
486
487 Ok(CompilableText::from(vec![
488 CompilableTextPart::new_fixed(format!(
489 r#"<a href="{}" class="link">"#,
490 ResourceReference::of(captures.get(2).unwrap().as_str(), cco.document_name().as_ref())?.build(),
491 ))
492 ]))
493 }))),
494 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::Link.incompatible_modifiers())),
495 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</a>"#)))
496 ]
497 ))
498 )
499 ),
500 (
501 StandardTextModifier::Checkbox.identifier().clone(),
502 (
503 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Checkbox)),
504 Box::new(ReplacementRule::new(
505 StandardTextModifier::Checkbox.modifier_pattern().clone(),
506 vec![
507 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<div class="checkbox checkbox-unchecked"></div>"#))),
508 ]
509 ))
510 )
511 ),
512 (
513 StandardTextModifier::CheckboxChecked.identifier().clone(),
514 (
515 Box::new(Into::<BaseModifier>::into(StandardTextModifier::CheckboxChecked)),
516 Box::new(ReplacementRule::new(
517 StandardTextModifier::CheckboxChecked.modifier_pattern().clone(),
518 vec![
519 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<div class="checkbox checkbox-checked"></div>"#))),
520 ]
521 ))
522 )
523 ),
524 (
525 StandardTextModifier::Emoji.identifier().clone(),
526 (
527 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Emoji)),
528 Box::new(ReplacementRule::new(
529 StandardTextModifier::Emoji.modifier_pattern().clone(),
530 vec![
531 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|captures, _, _, _, _| {
532
533 Ok(CompilableText::from(vec![
534 CompilableTextPart::new_fixed(format!(
535 r#"<i class="em-svg em-{}" aria-role="presentation"></i>"#,
536 captures.get(1).unwrap().as_str(),
537 ))
538 ]))
539 }))),
540 ]
541 ))
542 )
543 ),
544 (
545 StandardTextModifier::Escape.identifier().clone(),
546 (
547 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Escape)) as Box<dyn Modifier>,
548 Box::new(ReplacementRule::new(
549 StandardTextModifier::Escape.modifier_pattern().clone(),
550 vec![
551 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardTextModifier::Escape.incompatible_modifiers())),
552 ]
553 )) as Box<dyn CompilationRule>
554 ) as (Box<dyn Modifier>, Box<dyn CompilationRule>)
555 ),
556 (
557 StandardTextModifier::Reference.identifier().clone(),
558 (
559 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Reference)),
560 Box::new(ReferenceRule::new())
561 )
562 ),
563 (
564 StandardTextModifier::Cite.identifier().clone(),
565 (
566 Box::new(Into::<BaseModifier>::into(StandardTextModifier::Cite)),
567 Box::new(HtmlCiteRule::new())
568 )
569 ),
570 ]);
571
572 let paragraph_rules: ParagraphModifierOrderedMap = ParagraphModifierOrderedMap::from([
573 (
574 StandardParagraphModifier::CodeBlock.identifier().clone(),
575 (
576 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::CodeBlock)) as Box<dyn Modifier>,
577 Box::new(ReplacementRuleParagraphLoadingRule::new(
578 ReplacementRule::new(
579 StandardParagraphModifier::CodeBlock.modifier_pattern().clone(),
580 vec![
581 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|captures, compilable, _, _, _| {
582
583 let mut lang_class = String::from("language-markup");
584 if let Some(lang) = captures.get(1) {
585 lang_class = format!("language-{}", lang.as_str());
586 }
587
588 Ok(CompilableText::from(vec![
589 CompilableTextPart::new_fixed(format!(
590 r#"<pre{}><code class="{} code-block">{}</code></pre>"#,
591 text_utility::html_nuid_tag_or_nothing(compilable.nuid().as_ref()),
592 lang_class,
593 text_utility::replace(captures.get(2).unwrap().as_str(), &ESCAPE_HTML),
594 )
595 )
596 ]))
597 }))),
598 ]
599 )
600 )) as Box<dyn ParagraphLoadingRule>
601 ) as (Box<dyn Modifier>, Box<dyn ParagraphLoadingRule>)
602 ),
603 (
604 StandardParagraphModifier::MathBlock.identifier().clone(),
605 (
606 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::MathBlock)) as Box<dyn Modifier>,
607 Box::new(ReplacementRuleParagraphLoadingRule::new(
608 ReplacementRule::new(
609 StandardParagraphModifier::MathBlock.modifier_pattern().clone(),
610 vec![
611 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|captures, compilable, _, _, _| {
612
613 Ok(CompilableText::from(vec![
614 CompilableTextPart::new_fixed(format!(
615 r#"<p class="math-block"{}>$${}$$</p>"#,
616 text_utility::html_nuid_tag_or_nothing(compilable.nuid().as_ref()),
617 text_utility::replace(captures.get(1).unwrap().as_str(), &ESCAPE_HTML),
618 )
619 )
620 ]))
621 }))),
622 ]
623 )
624 ))
625 )
626 ),
627 (
628 StandardParagraphModifier::EmbeddedParagraphStyle.identifier().clone(),
629 (
630 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::EmbeddedParagraphStyle)) as Box<dyn Modifier>,
631 Box::new(MetadataWrapperParagraphLoadingRule::new(
632 StandardParagraphModifier::EmbeddedParagraphStyle.modifier_pattern_regex().clone(),
633 1,
634 Some(2),
635 Some(3),
636 Some(Arc::new(|style, there_is_id| {
637
638 if there_is_id {
639
640 text_utility::split_styles_and_classes_with_default(style, (None, Some(String::from("identifier embedded-paragraph-style"))))
641
642 } else {
643
644 text_utility::split_styles_and_classes_with_default(style, (None, Some(String::from("embedded-paragraph-style"))))
645 }
646
647 })),
648 ))
649 )
650 ),
651 (
652 StandardParagraphModifier::ParagraphIdentifier.identifier().clone(),
653 (
654 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::ParagraphIdentifier)) as Box<dyn Modifier>,
655 Box::new(MetadataWrapperParagraphLoadingRule::new(
656 StandardParagraphModifier::ParagraphIdentifier.modifier_pattern_regex().clone(),
657 1,
658 Some(2),
659 None,
660 None,
661 ))
662 )
663 ),
664 (
665 StandardParagraphModifier::Table.identifier(),
666 (
667 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::Table)) as Box<dyn Modifier>,
668 Box::new(TableParagraphLoadingRule::new()) as Box<dyn ParagraphLoadingRule>
669 ) as (Box<dyn Modifier>, Box<dyn ParagraphLoadingRule>)
670 ),
671 (
672 StandardParagraphModifier::ExtendedBlockQuote.identifier().clone(),
673 (
674 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::ExtendedBlockQuote)) as Box<dyn Modifier>,
675 Box::new(BlockQuoteParagraphLoadingRule::new()),
676 )
677 ),
678 (
679 StandardParagraphModifier::FocusBlock.identifier().clone(),
680 (
681 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::FocusBlock)) as Box<dyn Modifier>,
682 Box::new(FocusBlockParagraphLoadingRule::new(StandardParagraphModifier::FocusBlock.modifier_pattern_regex().clone())),
683 )
684 ),
685 (
686 StandardParagraphModifier::List.identifier().clone(),
687 (
688 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::List)) as Box<dyn Modifier>,
689 Box::new(ListParagraphLoadingRule::new()),
690 )
691 ),
692 (
693 StandardParagraphModifier::MultilineTodo.identifier().clone(),
694 (
695 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::MultilineTodo)) as Box<dyn Modifier>,
696 Box::new(ReplacementRuleParagraphLoadingRule::new(
697 ReplacementRule::new(
698 StandardParagraphModifier::MultilineTodo.modifier_pattern().clone(),
699 vec![
700 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|_, compilable, _, _, _| {
701
702 Ok(CompilableText::from(CompilableTextPart::new_fixed(format!(
703 r#"<div class="todo multiline-todo"{}><div class="todo-title"></div><div class="todo-description">"#,
704 text_utility::html_nuid_tag_or_nothing(compilable.nuid().as_ref()),
705 ))
706 ))
707 }))),
708 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardParagraphModifier::MultilineTodo.incompatible_modifiers())),
709 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</div>"#)))
710 ]
711 )
712 ))
713 )
714 ),
715 (
716 StandardParagraphModifier::Todo.identifier().clone(),
717 (
718 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::Todo)) as Box<dyn Modifier>,
719 Box::new(ReplacementRuleParagraphLoadingRule::new(
720 ReplacementRule::new(
721 StandardParagraphModifier::Todo.modifier_pattern().clone(),
722 vec![
723 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|_, compilable, _, _, _| {
724
725 Ok(CompilableText::from(CompilableTextPart::new_fixed(format!(
726 r#"<div class="todo"{}><div class="todo-title"></div>"#,
727 text_utility::html_nuid_tag_or_nothing(compilable.nuid().as_ref()),
728 ))
729 ))
730 }))),
731 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, ESCAPE_HTML.clone(), StandardParagraphModifier::Todo.incompatible_modifiers())),
732 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"</div>"#)))
733 ]
734 )
735 ))
736 )
737 ),
738 (
739 StandardParagraphModifier::AbridgedTodo.identifier().clone(),
740 (
741 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::AbridgedTodo)) as Box<dyn Modifier>,
742 Box::new(ReplacementRuleParagraphLoadingRule::new(
743 ReplacementRule::new(
744 StandardParagraphModifier::AbridgedTodo.modifier_pattern().clone(),
745 vec![
746 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|_, compilable, _, _, _| {
747
748 Ok(CompilableText::from(CompilableTextPart::new_fixed(format!(
749 r#"<div class="todo abridged-todo"{}><div class="todo-title"></div></div>"#,
750 text_utility::html_nuid_tag_or_nothing(compilable.nuid().as_ref()),
751 ))
752 ))
753 }))),
754 ]
755 )
756 ))
757 )
758 ),
759 (
760 StandardParagraphModifier::MultiImage.identifier().clone(),
761 (
762 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::MultiImage)) as Box<dyn Modifier>,
763 Box::new(ImageParagraphLoadingRule::MultiImage)
764 )
765 ),
766 (
767 StandardParagraphModifier::Image.identifier().clone(),
768 (
769 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::Image)) as Box<dyn Modifier>,
770 Box::new(ImageParagraphLoadingRule::SingleImage)
771 )
772 ),
773 (
774 StandardParagraphModifier::AbridgedImage.identifier().clone(),
775 (
776 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::AbridgedImage)) as Box<dyn Modifier>,
777 Box::new(ImageParagraphLoadingRule::AbridgedImage)
778 )
779 ),
780 (
781 StandardParagraphModifier::PageBreak.identifier().clone(),
782 (
783 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::PageBreak)) as Box<dyn Modifier>,
784 Box::new(ReplacementRuleParagraphLoadingRule::new(
785 ReplacementRule::new(
786 StandardParagraphModifier::PageBreak.modifier_pattern().clone(),
787 vec![
788 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<div class="page-break"></div>"#)))
789 ]
790 )
791 ))
792 )
793 ),
794 (
795 StandardParagraphModifier::LineBreakDash.identifier().clone(),
796 (
797 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::LineBreakDash)) as Box<dyn Modifier>,
798 Box::new(ReplacementRuleParagraphLoadingRule::new(
799 ReplacementRule::new(
800 StandardParagraphModifier::LineBreakDash.modifier_pattern().clone(),
801 vec![
802 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|_, compilable, _, _, _| {
803
804 Ok(CompilableText::from(vec![
805 CompilableTextPart::new_fixed(format!(
806 r#"<hr class="line-break line-break-dash"{}>"#,
807 text_utility::html_nuid_tag_or_nothing(compilable.nuid().as_ref()),
808 )
809 )
810 ]))
811 }))),
812 ]
813 )
814 ))
815 )
816 ),
817 (
818 StandardParagraphModifier::LineBreakStar.identifier().clone(),
819 (
820 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::LineBreakStar)) as Box<dyn Modifier>,
821 Box::new(ReplacementRuleParagraphLoadingRule::new(
822 ReplacementRule::new(
823 StandardParagraphModifier::LineBreakDash.modifier_pattern().clone(),
824 vec![
825 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|_, compilable, _, _, _| {
826
827 Ok(CompilableText::from(vec![
828 CompilableTextPart::new_fixed(format!(
829 r#"<hr class="line-break line-break-star"{}>"#,
830 text_utility::html_nuid_tag_or_nothing(compilable.nuid().as_ref()),
831 )
832 )
833 ]))
834 }))),
835 ]
836 )
837 ))
838 )
839 ),
840 (
841 StandardParagraphModifier::LineBreakPlus.identifier().clone(),
842 (
843 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::LineBreakPlus)) as Box<dyn Modifier>,
844 Box::new(ReplacementRuleParagraphLoadingRule::new(
845 ReplacementRule::new(
846 StandardParagraphModifier::LineBreakDash.modifier_pattern().clone(),
847 vec![
848 Arc::new(ClosureReplacementRuleReplacerPart::new(Arc::new(|_, compilable, _, _, _| {
849
850 Ok(CompilableText::from(vec![
851 CompilableTextPart::new_fixed(format!(
852 r#"<hr class="line-break line-break-plus"{}>"#,
853 text_utility::html_nuid_tag_or_nothing(compilable.nuid().as_ref()),
854 )
855 )
856 ]))
857 }))),
858 ]
859 )
860 ))
861 )
862 ),
863 (
864 StandardParagraphModifier::CommentBlock.identifier().clone(),
865 (
866 Box::new(Into::<BaseModifier>::into(StandardParagraphModifier::CommentBlock)) as Box<dyn Modifier>,
867 Box::new(ReplacementRuleParagraphLoadingRule::new(
868 ReplacementRule::new(
869 StandardParagraphModifier::CommentBlock.modifier_pattern().clone(),
870 vec![
871 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"<!--"#))),
872 Arc::new(SingleCaptureGroupReplacementRuleReplacerPart::new(1, Vec::new(), StandardParagraphModifier::CommentBlock.incompatible_modifiers())),
873 Arc::new(FixedReplacementRuleReplacerPart::new(String::from(r#"-->"#))),
874 ]
875 )
876 ))
877 )
878 ),
879 ]);
880
881 Self::new(
882 text_rules,
883 paragraph_rules,
884 Some(
885 (
886 StandardParagraphModifier::CommonParagraph.identifier().clone(),
887 Box::new(CommonParagraphLoadingRule::new())
888 ),
889 ),
890 Box::new(HtmlAssembler::new())
891 )
892 }
893}
894
895#[cfg(test)]
896mod test {
897
898 use indexmap::IndexMap;
899 use modifier::base_modifier::BaseModifier;
900 use super::*;
901
902
903 #[test]
904 fn correct_order() {
905
906 let codex = Codex::new(
907 IndexMap::new(),
908 IndexMap::from([
909 (
910 String::from("a"),
911 (
912 Box::new(Into::<BaseModifier>::into(StandardTextModifier::BoldStarVersion)) as Box<dyn Modifier>,
913 Box::new(ReplacementRuleParagraphLoadingRule::new(
914 ReplacementRule::new(
915 String::from("fake"),
916 vec![
917 ]
918 )
919 )) as Box<dyn ParagraphLoadingRule>
920 ) as (Box<dyn Modifier>, Box<dyn ParagraphLoadingRule>)
921 ),
922 (
923 String::from("b"),
924 (
925 Box::new(Into::<BaseModifier>::into(StandardTextModifier::BoldStarVersion)) as Box<dyn Modifier>,
926 Box::new(ReplacementRuleParagraphLoadingRule::new(
927 ReplacementRule::new(
928 String::from("fake"),
929 vec![
930 ]
931 )
932 )) as Box<dyn ParagraphLoadingRule>
933 ) as (Box<dyn Modifier>, Box<dyn ParagraphLoadingRule>)
934 ),
935 (
936 String::from("e"),
937 (
938 Box::new(Into::<BaseModifier>::into(StandardTextModifier::BoldStarVersion)) as Box<dyn Modifier>,
939 Box::new(ReplacementRuleParagraphLoadingRule::new(
940 ReplacementRule::new(
941 String::from("fake"),
942 vec![
943 ]
944 )
945 )) as Box<dyn ParagraphLoadingRule>
946 ) as (Box<dyn Modifier>, Box<dyn ParagraphLoadingRule>)
947 ),
948 (
949 String::from("c"),
950 (
951 Box::new(Into::<BaseModifier>::into(StandardTextModifier::BoldStarVersion)) as Box<dyn Modifier>,
952 Box::new(ReplacementRuleParagraphLoadingRule::new(
953 ReplacementRule::new(
954 String::from("fake"),
955 vec![
956 ]
957 )
958 )) as Box<dyn ParagraphLoadingRule>
959 ) as (Box<dyn Modifier>, Box<dyn ParagraphLoadingRule>)
960 ),
961 (
962 String::from("i"),
963 (
964 Box::new(Into::<BaseModifier>::into(StandardTextModifier::BoldStarVersion)) as Box<dyn Modifier>,
965 Box::new(ReplacementRuleParagraphLoadingRule::new(
966 ReplacementRule::new(
967 String::from("fake"),
968 vec![
969 ]
970 )
971 )) as Box<dyn ParagraphLoadingRule>
972 ) as (Box<dyn Modifier>, Box<dyn ParagraphLoadingRule>)
973 ),
974 ]),
975 None,
976 Box::new(HtmlAssembler::new())
977 );
978
979
980 let ids: Vec<String> = codex.paragraph_modifiers.into_iter().map(|tm| tm.0).collect();
981
982 assert_eq!(ids.join(""), "abeci");
983 }
984}