1#![deny(
4 clippy::all,
5 missing_debug_implementations,
6 missing_copy_implementations,
7 missing_docs
8)]
9#![warn(clippy::pedantic, clippy::nursery)]
10
11use mdbook::book::{Book, Chapter};
12use mdbook::errors::Error;
13use mdbook::preprocess::{Preprocessor, PreprocessorContext};
14use mdbook::BookItem;
15use pulldown_cmark::{CodeBlockKind, CowStr, Event, Options, Parser, Tag, TagEnd};
16use pulldown_cmark_to_cmark::cmark;
17
18mod backend;
19use backend::{Backend, RenderContext};
20
21mod config;
22
23#[derive(Default, Clone, Copy, Debug)]
25pub struct D2;
26
27impl Preprocessor for D2 {
28 fn name(&self) -> &'static str {
29 "d2"
30 }
31
32 fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result<Book, Error> {
33 let backend = Backend::from_context(ctx);
34
35 book.for_each_mut(|section| {
36 if let BookItem::Chapter(chapter) = section {
37 let events = process_events(
38 &backend,
39 chapter,
40 Parser::new_ext(&chapter.content, Options::all()),
41 );
42
43 let mut buf = String::with_capacity(chapter.content.len() + 128);
45
46 cmark(events, &mut buf).unwrap();
48 chapter.content = buf;
49 }
50 });
51
52 Ok(book)
53 }
54}
55
56fn process_events<'a>(
57 backend: &'a Backend,
58 chapter: &'a Chapter,
59 events: impl Iterator<Item = Event<'a>> + 'a,
60) -> impl Iterator<Item = Event<'a>> + 'a {
61 let mut in_block = false;
62 let mut diagram = String::new();
66 let mut diagram_index = 0;
67
68 events.flat_map(move |event| {
69 match (&event, in_block) {
70 (
72 Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(CowStr::Borrowed("d2")))),
73 false,
74 ) => {
75 in_block = true;
76 diagram.clear();
77 diagram_index += 1;
78 vec![]
79 }
80 (Event::Text(content), true) => {
82 diagram.push_str(content);
83 vec![]
84 }
85 (Event::End(TagEnd::CodeBlock), true) => {
87 in_block = false;
88 let render_context = RenderContext::new(
89 chapter.source_path.as_ref().unwrap(),
90 &chapter.name,
91 chapter.number.as_ref(),
92 diagram_index,
93 );
94 backend
95 .render(&render_context, &diagram)
96 .unwrap_or_else(|e| {
97 eprintln!("{e}");
100 vec![]
101 })
102 }
103 _ => vec![event],
105 }
106 })
107}