summaryrefslogtreecommitdiffstats
path: root/crates/atuin-run/src/markdown.rs
blob: f3e3c0c2daf583921832c2850cc78a7aa1d548b9 (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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use comrak::{
    arena_tree::NodeEdge,
    nodes::{AstNode, NodeValue},
    parse_document, Arena, ComrakOptions,
};

#[derive(Debug)]
pub struct Block {
    pub info: String,
    pub code: String,
}

// why yes, this is stolen from the examples:
// https://github.com/kivikakk/comrak/blob/56581d7275d8180f1a55771a2f3d41b6ebef26a6/examples/traverse_demo.rs
fn extract_text_traverse<'a>(root: &'a AstNode<'a>) -> Vec<Block> {
    let mut output_blocks = Vec::new();

    // Use `traverse` to get an iterator of `NodeEdge` and process each.
    for edge in root.traverse() {
        if let NodeEdge::Start(node) = edge {
            if let NodeValue::CodeBlock(ref block) = node.data.borrow().value {
                let block = Block {
                    code: block.literal.clone(),
                    info: block.info.clone(),
                };

                output_blocks.push(block);
            }
        }
    }

    output_blocks
}

pub fn parse(md: &str) -> Vec<Block> {
    // setup parser
    let arena = Arena::new();
    let options = ComrakOptions::default();

    // parse document and return root.
    let root = parse_document(&arena, md, &options);

    // extract text and print
    extract_text_traverse(root)
}

#[cfg(test)]
mod test {
    use crate::markdown::parse;

    // Test if we can parse some markdown containing a single code block
    #[test]
    fn test_parse_simple() {
        let md = "
```bash
echo 'foo bar'
```
";

        let blocks = parse(md);

        assert_eq!(blocks.len(), 1);
        assert_eq!(blocks[0].info, "bash");
        assert_eq!(blocks[0].code, "echo 'foo bar'\n");
    }

    #[test]
    fn test_parse_not_so_simple() {
        let md = "
# Hello I am a doc

## Here is how you do some things

### This thing is really cool
```bash
echo 'foo bar'
```

### This thing is cooler and with a better shell

```zsh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo install atuin
```
";

        let blocks = parse(md);

        assert_eq!(blocks.len(), 2);

        assert_eq!(blocks[0].info, "bash");
        assert_eq!(blocks[0].code, "echo 'foo bar'\n");

        assert_eq!(blocks[1].info, "zsh");
        assert_eq!(
            blocks[1].code,
            "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\ncargo install atuin\n"
        );
    }
}