1// Counts the number of crabs lurking around.
2
3use super::block_rule::BlockFerris;
4use super::inline_rule::InlineFerris;
5use markdown_it::parser::core::CoreRule;
6use markdown_it::{MarkdownIt, Node, NodeValue, Renderer};
7
8#[derive(Debug)]
9// This is a structure that represents your custom Node in AST,
10// it has one single argument - crab counter.
11pub struct FerrisCounter(usize);
12
13// This defines how your custom node should be rendered.
14impl NodeValue for FerrisCounter {
15 fn render(&self, node: &Node, fmt: &mut dyn Renderer) {
16 // `node.attrs` are custom attributes added by other plugins
17 // (for example, source mapping information)
18 let mut attrs = node.attrs.clone();
19
20 // add a custom class attribute
21 attrs.push(("class", "ferris-counter".into()));
22
23 fmt.cr(); // linebreak, multiples get merged
24 fmt.open("footer", &attrs);
25 #[allow(clippy::useless_format)] // for simplicity's sake
26 fmt.text(&match self.0 {
27 0 => format!("No crabs around here."),
28 1 => format!("There is a crab lurking in this document."),
29 _ => format!("There are {} crabs lurking in this document.", self.0),
30 });
31 fmt.close("footer");
32 fmt.cr();
33 }
34}
35
36// This is an extension for the markdown parser.
37struct FerrisCounterRule;
38
39impl CoreRule for FerrisCounterRule {
40 // This is a custom function that will be invoked once per document.
41 //
42 // It has `root` node of the AST as an argument and may modify its
43 // contents as you like.
44 //
45 fn run(root: &mut Node, _: &MarkdownIt) {
46 let mut counter = 0;
47
48 // walk through AST recursively and count the number of two
49 // custom nodes added by other two rules
50 root.walk(|node, _| {
51 if node.is::<InlineFerris>() || node.is::<BlockFerris>() {
52 counter += 1;
53 }
54 });
55
56 // append a counter to the root as a custom node
57 root.children.push(Node::new(FerrisCounter(counter)))
58 }
59}
60
61pub fn add(md: &mut MarkdownIt) {
62 // insert this rule into parser
63 md.add_rule::<FerrisCounterRule>();
64}