summaryrefslogtreecommitdiff
path: root/src/visitor/typesetting.rs
blob: 8d73f3ee3a183cb646df4582bb51e39f0bb18296 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use crate::panhelper;
use crate::typeset;
use crate::{Bindings, Style, Warnings};

use pandoc_ast::{Block, Inline, MutVisitor};

/// Visitor for the pandoc AST.
///
/// This includes rendering stuff which we find as we go
pub struct TypesettingVisitor<'a> {
    style: Style,
    bindings: &'a Bindings,
    warnings: Warnings,
}

impl<'a> TypesettingVisitor<'a> {
    pub fn new(style: Style, bindings: &'a Bindings) -> Self {
        TypesettingVisitor {
            style,
            bindings,
            warnings: Warnings::default(),
        }
    }

    pub fn warnings(self) -> Warnings {
        self.warnings
    }
}

// Visit interesting parts of the Pandoc abstract syntax tree. The
// document top level is a vector of blocks and we visit that and
// replace any fenced code block with the scenario tag with a typeset
// paragraph. Also, replace fenced code blocks with known diagram
// markup with the rendered SVG image.
impl<'a> MutVisitor for TypesettingVisitor<'a> {
    fn visit_vec_block(&mut self, vec_block: &mut Vec<Block>) {
        use panhelper::is_class;
        for block in vec_block {
            match block {
                Block::CodeBlock(attr, s) => {
                    if is_class(attr, "scenario") {
                        *block = typeset::scenario_snippet(self.bindings, s, &mut self.warnings)
                    } else if is_class(attr, "file") {
                        *block = typeset::file_block(attr, s)
                    } else if is_class(attr, "dot") {
                        *block = typeset::dot_to_block(s, &mut self.warnings)
                    } else if is_class(attr, "plantuml") {
                        *block = typeset::plantuml_to_block(s, &mut self.warnings)
                    } else if is_class(attr, "roadmap") {
                        *block = typeset::roadmap_to_block(s, &mut self.warnings)
                    } else if is_class(attr, "pikchr") {
                        let other_classes: Vec<_> = attr
                            .1
                            .iter()
                            .map(String::as_str)
                            .filter(|s| *s != "pikchr")
                            .collect();
                        let class = if other_classes.is_empty() {
                            None
                        } else {
                            Some(other_classes.join(" "))
                        };
                        let class = class.as_deref();
                        *block = typeset::pikchr_to_block(s, class, &mut self.warnings)
                    }
                }
                _ => {
                    self.visit_block(block);
                }
            }
        }
    }
    fn visit_vec_inline(&mut self, vec_inline: &mut Vec<Inline>) {
        for inline in vec_inline {
            match inline {
                Inline::Link(attr, vec, target) if self.style.links_as_notes() => {
                    *inline = typeset::link_as_note(attr.clone(), vec.to_vec(), target.clone());
                }
                _ => {
                    self.visit_inline(inline);
                }
            }
        }
    }
}