1use mdbook::{
2 book::Book,
3 errors::Error,
4 preprocess::{Preprocessor, PreprocessorContext},
5 BookItem,
6};
7use pulldown_cmark::{CodeBlockKind, CowStr, Event, Options, Parser, Tag};
8use pulldown_cmark_to_cmark::cmark;
9use svgbob::Settings;
10
11pub struct Bob;
12
13impl Bob {
14 pub fn new() -> Self {
15 Self
16 }
17}
18
19impl Default for Bob {
20 fn default() -> Self {
21 Self::new()
22 }
23}
24
25impl Preprocessor for Bob {
26 fn name(&self) -> &str {
27 "svgbob2"
28 }
29
30 fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result<Book, Error> {
31 let mut settings = svgbob::Settings {
34 background: "transparent".to_owned(),
35 stroke_color: "var(--fg)".to_owned(),
36 ..Default::default()
37 };
38
39 let mut font_color = "var(--fg)".to_owned();
40
41 if let Some(cfg) = ctx.config.get_preprocessor(self.name()) {
42 cfg.iter().for_each(|(key, val)| match key.as_str() {
43 "font_size" => settings.font_size = val.clone().try_into().unwrap(),
44 "font_family" => settings.font_family = val.clone().try_into().unwrap(),
45 "fill_color" => settings.fill_color = val.clone().try_into().unwrap(),
46 "background" => settings.background = val.clone().try_into().unwrap(),
47 "stroke_color" => settings.stroke_color = val.clone().try_into().unwrap(),
48 "stroke_width" => settings.stroke_width = val.clone().try_into().unwrap(),
49 "scale" => settings.scale = val.clone().try_into().unwrap(),
50 "enhance_circuitries" => {
51 settings.enhance_circuitries = val.clone().try_into().unwrap()
52 }
53 "include_backdrop" => settings.include_backdrop = val.clone().try_into().unwrap(),
54 "include_styles" => settings.include_styles = val.clone().try_into().unwrap(),
55 "include_defs" => settings.include_defs = val.clone().try_into().unwrap(),
56 "merge_line_with_shapes" => {
57 settings.merge_line_with_shapes = val.clone().try_into().unwrap()
58 }
59
60 "font_color" => font_color = val.clone().try_into().unwrap(),
62
63 _ => (), });
65 }
66
67 book.for_each_mut(|item| {
68 if let BookItem::Chapter(chapter) = item {
69 let mut in_block = false;
71
72 let mut diagram = String::new();
76 let events =
77 Parser::new_ext(&chapter.content, Options::all()).filter_map(|event| {
78 match (&event, in_block) {
79 (
81 Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(
82 CowStr::Borrowed("svgbob"),
83 ))),
84 false,
85 ) => {
86 in_block = true;
87 diagram.clear();
88 None
89 }
90 (Event::Text(content), true) => {
92 diagram.push_str(content);
93 None
94 }
95 (
97 Event::End(Tag::CodeBlock(CodeBlockKind::Fenced(
98 CowStr::Borrowed("svgbob"),
99 ))),
100 true,
101 ) => {
102 in_block = false;
103 Some(Event::Html(
104 create_svg_html(&diagram, &settings, &font_color).into(),
105 ))
106 }
107 _ => Some(event),
109 }
110 });
111
112 let mut buf = String::with_capacity(chapter.content.len() + 128);
114
115 cmark(events, &mut buf).unwrap();
117 chapter.content = buf;
118 }
119 });
120
121 Ok(book)
122 }
123
124 fn supports_renderer(&self, renderer: &str) -> bool {
125 renderer == "html"
126 }
127}
128
129fn create_svg_html(s: &str, settings: &Settings, font_color: &str) -> String {
130 let svg = svgbob::to_svg_with_settings(s, settings);
131
132 format!(
135 "<pre class=\"svgbob\"><style>text{{fill:{}}}</style>{}</pre>",
136 font_color, svg
137 )
138}