ferris/inline_rule.rs
1// Replaces `(\/)` with `🦀`.
2
3use markdown_that::parser::inline::{InlineRule, InlineState};
4use markdown_that::{MarkdownThat, Node, NodeValue, Renderer};
5
6const CRAB_CLAW: &str = r#"(\/)"#;
7
8#[derive(Debug)]
9// This is a structure that represents your custom Node in AST.
10pub struct InlineFerris;
11
12// This defines how your custom node should be rendered.
13impl NodeValue for InlineFerris {
14 fn render(&self, node: &Node, fmt: &mut dyn Renderer) {
15 // `node.attrs` are custom attributes added by other plugins
16 // (for example, source mapping information)
17 let mut attrs = node.attrs.clone();
18
19 // add a custom class attribute
20 attrs.push(("class", "ferris-inline".into()));
21
22 fmt.open("span", &attrs);
23 fmt.text("🦀");
24 fmt.close("span");
25 }
26}
27
28// This is an extension for the inline subparser.
29struct FerrisInlineScanner;
30
31impl InlineRule for FerrisInlineScanner {
32 // This is a character that starts your custom structure
33 // (other characters may get skipped over).
34 const MARKER: char = '(';
35
36 // This is a custom function that will be invoked on every character
37 // in an inline context.
38 //
39 // It should look for `state.src` exactly at position `state.pos`
40 // and report if your custom structure appears there.
41 //
42 // If custom structure is found, it:
43 // - creates a new `Node` in AST
44 // - returns length of it
45 //
46 fn run(state: &mut InlineState) -> Option<(Node, usize)> {
47 let input = &state.src[state.pos..state.pos_max]; // look for stuff at state.pos
48 if !input.starts_with(CRAB_CLAW) {
49 return None;
50 } // return None if it's not found
51
52 // return new node and length of this structure
53 Some((Node::new(InlineFerris), CRAB_CLAW.len()))
54 }
55}
56
57pub fn add(md: &mut MarkdownThat) {
58 // insert this rule into inline subparser
59 md.inline.add_rule::<FerrisInlineScanner>();
60}