wayver's git archive


an obsidian renderer
git clone https://git.wayver.dev/sable

sable-markdown/src/render/index.rs@main

raw
Date Commit Message Author Files + -
2026-02-23 01:55 initial mvp wayverd 139 17808 0
...

1use std::collections::HashMap;
2
3use crate::ast::{Block, Document, Inline, LinkDefinition};
4
5struct Index {
6    footnote_indices: HashMap<String, usize>,
7    link_definitions: HashMap<Vec<Inline>, LinkDefinition>,
8    last_footnote_index: usize,
9}
10
11impl Index {
12    pub(crate) fn new() -> Self {
13        Self {
14            footnote_indices: HashMap::new(),
15            link_definitions: HashMap::new(),
16            last_footnote_index: 1,
17        }
18    }
19
20    pub(crate) fn add_footnote(&mut self, label: String) {
21        if let std::collections::hash_map::Entry::Vacant(e) = self.footnote_indices.entry(label) {
22            e.insert(self.last_footnote_index);
23            self.last_footnote_index += 1;
24        }
25    }
26}
27
28pub(super) fn get_indicies(
29    ast: &Document,
30) -> (HashMap<String, usize>, HashMap<Vec<Inline>, LinkDefinition>) {
31    let mut index = Index::new();
32
33    for block in &ast.blocks {
34        get_block_indicies(&mut index, block);
35    }
36
37    (index.footnote_indices, index.link_definitions)
38}
39
40fn get_block_indicies(index: &mut Index, block: &Block) {
41    match block {
42        Block::Paragraph(v) => {
43            for inline in v {
44                get_inline_indicies(index, inline);
45            }
46        }
47        Block::Heading(v) => {
48            for inline in &v.content {
49                get_inline_indicies(index, inline);
50            }
51        }
52        Block::BlockQuote(v) => {
53            for block in v {
54                get_block_indicies(index, block);
55            }
56        }
57        Block::List(v) => {
58            for item in &v.items {
59                for block in &item.blocks {
60                    get_block_indicies(index, block);
61                }
62            }
63        }
64        Block::Definition(v) => {
65            index.link_definitions.insert(v.label.clone(), v.clone());
66            for inline in &v.label {
67                get_inline_indicies(index, inline);
68            }
69        }
70        Block::Table(v) => {
71            for row in &v.rows {
72                for cell in row {
73                    for inline in cell {
74                        get_inline_indicies(index, inline);
75                    }
76                }
77            }
78        }
79        Block::FootnoteDefinition(v) => {
80            for block in &v.blocks {
81                get_block_indicies(index, block);
82            }
83        }
84        Block::Callout(v) => {
85            for block in &v.blocks {
86                get_block_indicies(index, block);
87            }
88        }
89        Block::Empty | Block::CodeBlock(_) | Block::HtmlBlock(_) | Block::ThematicBreak => (),
90    }
91}
92
93fn get_inline_indicies(index: &mut Index, inline: &Inline) {
94    if let Inline::FootnoteReference(label) = inline {
95        index.add_footnote(label.clone());
96    }
97}
98