mdbook_mermaid_animate/
lib.rs1extern crate serde_json;
2
3use anyhow::Result;
4use mdbook_preprocessor::book::{Book, BookItem, Chapter};
5use mdbook_preprocessor::{Preprocessor, PreprocessorContext};
6use regex::Regex;
8
9pub mod mermaid_of_frame;
10pub mod model;
11pub mod process_diagram;
12use process_diagram::process_diagram;
13pub mod handlebar_helpers;
14pub mod tests;
15
16pub struct MermaidAnimatePreprocessor;
17
18fn run_section(ctx: &PreprocessorContext, section: &BookItem) -> Result<BookItem> {
19 let section = match section {
21 BookItem::Chapter(chapter) => run_chapter(ctx, chapter)?,
22 _ => {
23 dbg!("non-chapter section: {:?}", §ion);
24 unimplemented!()
25 }
26 };
27 Ok(BookItem::Chapter(section))
28}
29
30fn run_chapter(ctx: &PreprocessorContext, chapter: &Chapter) -> Result<Chapter> {
31 let re = Regex::new(r#"(?ms)(?<mermaid><pre .*?class=\"mermaid\".*?</pre>)"#).unwrap();
32 let mut replacements: Vec<(String, String)> = vec![];
33 let mut data = chapter.content.clone();
34 loop {
35 let caps = re.captures(&data);
36 if caps.is_none() {
37 break;
38 }
39 let caps = caps.unwrap();
40 let diagram = &caps["mermaid"];
42 let processed_diagram = process_diagram(ctx, diagram)?;
43 let id = uuid::Uuid::new_v4();
46 replacements.push((id.to_string(), processed_diagram.clone()));
48 let mut dst = String::new();
49 dst.push_str(&data[..caps.get(0).unwrap().start()]);
50 dst.push_str(id.to_string().as_str());
51 dst.push_str(&data[caps.get(0).unwrap().end()..]);
52 data = dst;
53 }
54
55 let mut chapter = chapter.clone();
56 for (id, processed_diagram) in replacements {
57 data = data.replace(&id, &processed_diagram);
58 }
59
60 chapter.content = data;
61
62 let sub_items: Vec<_> = chapter
63 .sub_items
64 .iter()
65 .map(|c| run_section(ctx, c))
66 .collect::<Result<Vec<_>>>()?;
67
68 chapter.sub_items = sub_items;
69
70 Ok(chapter.clone())
71}
72
73fn run_all(ctx: &PreprocessorContext, book: &Book) -> Result<Book> {
74 let items: &Vec<BookItem> = &book
75 .items
76 .iter()
77 .map(|section| run_section(ctx, section))
78 .collect::<Result<Vec<_>>>()?;
79
80 let book: &mut Book = &mut book.clone();
81 book.items = items.clone();
82 Ok(book.clone())
83}
84
85impl Preprocessor for MermaidAnimatePreprocessor {
86 fn name(&self) -> &str {
87 "mermaid-animate"
88 }
89
90 fn run(&self, ctx: &PreprocessorContext, book: Book) -> Result<Book> {
91 log::info!("Running mermaid-animate preprocessor");
92
93 let processed_book = run_all(ctx, &book);
94 match processed_book {
95 Err(e) => {
96 eprintln!("Error during processing: {e}");
97 Ok(book)
98 }
99 Ok(b) => Ok(b),
100 }
101 }
102
103 fn supports_renderer(&self, renderer: &str) -> Result<bool> {
104 Ok(renderer == "html")
105 }
106}