liwe/model/
node.rs

1use crate::model::document::LinkType;
2use crate::model::graph::{blocks_to_markdown_sparce_skip_frontmatter, GraphInlines};
3use crate::model::{Key, NodeId};
4
5use super::config::MarkdownOptions;
6use super::graph::{blocks_to_markdown_sparce, GraphInline};
7use super::projector::Projector;
8use super::tree::Tree;
9
10#[derive(Clone, Debug, PartialEq)]
11pub enum Node {
12    Document(Key, Option<String>),
13    Section(GraphInlines),
14    Quote(),
15    BulletList(),
16    OrderedList(),
17    Leaf(GraphInlines),
18    Raw(Option<String>, String),
19    HorizontalRule(),
20    Reference(Reference),
21    Table(Table),
22}
23
24impl Node {
25    pub fn plain_text(&self) -> String {
26        match self {
27            Node::Section(inlines) => inlines.iter().map(|i| i.plain_text()).collect(),
28            Node::Leaf(inlines) => inlines.iter().map(|i| i.plain_text()).collect(),
29            Node::Reference(reference) => reference.text.clone(),
30            Node::Raw(_, content) => content.clone(),
31            _ => "".to_string(),
32        }
33    }
34
35    pub fn reference_key(&self) -> Option<Key> {
36        match self {
37            Node::Reference(reference) => Some(reference.key.clone()),
38            _ => None,
39        }
40    }
41
42    pub fn reference_text(&self) -> Option<String> {
43        match self {
44            Node::Reference(reference) => Some(reference.text.clone()),
45            _ => None,
46        }
47    }
48
49    pub fn is_reference(&self) -> bool {
50        matches!(self, Node::Reference(_))
51    }
52}
53
54#[derive(Clone, Copy, Debug, PartialEq)]
55pub enum ReferenceType {
56    Regular,
57    WikiLink,
58    WikiLinkPiped,
59}
60
61impl ReferenceType {
62    pub fn to_link_type(&self) -> LinkType {
63        match self {
64            ReferenceType::Regular => LinkType::Markdown,
65            ReferenceType::WikiLink => LinkType::WikiLink,
66            ReferenceType::WikiLinkPiped => LinkType::WikiLinkPiped,
67        }
68    }
69}
70
71#[derive(Clone, Debug, PartialEq)]
72pub struct Reference {
73    pub key: Key,
74    pub text: String,
75    pub reference_type: ReferenceType,
76}
77
78#[derive(Clone, Debug, PartialEq)]
79pub struct Table {
80    pub header: Vec<GraphInlines>,
81    pub alignment: Vec<ColumnAlignment>,
82    pub rows: Vec<Vec<GraphInlines>>,
83}
84
85#[derive(Debug, Clone, PartialEq, Copy)]
86pub enum ColumnAlignment {
87    None,
88    Left,
89    Center,
90    Right,
91}
92
93pub trait NodeIter<'a>: Sized {
94    fn next(&self) -> Option<Self>;
95    fn child(&self) -> Option<Self>;
96    fn node(&self) -> Option<Node>;
97
98    fn to_markdown(self, parent: &str, options: &MarkdownOptions) -> String {
99        let blocks = Projector::project(self, parent);
100        blocks_to_markdown_sparce(&blocks, options)
101    }
102
103    fn to_markdown_skip_frontmatter(self, parent: &str, options: &MarkdownOptions) -> String {
104        let blocks = Projector::project(self, parent);
105        blocks_to_markdown_sparce_skip_frontmatter(&blocks, options)
106    }
107
108    fn plain_text(&self) -> String {
109        self.inlines().iter().map(|i| i.plain_text()).collect()
110    }
111
112    fn to_default_markdown(self) -> String {
113        self.to_markdown("", &MarkdownOptions::default())
114    }
115
116    fn ref_type(&self) -> Option<ReferenceType> {
117        self.node().and_then(|node| {
118            if let Node::Reference(reference) = node {
119                Some(reference.reference_type)
120            } else {
121                None
122            }
123        })
124    }
125
126    fn lang(&self) -> Option<String> {
127        self.node().and_then(|node| {
128            if let Node::Raw(lang, _) = node {
129                lang.clone()
130            } else {
131                None
132            }
133        })
134    }
135
136    fn table_header(&self) -> Option<Vec<GraphInlines>> {
137        self.node().and_then(|node| {
138            if let Node::Table(table) = node {
139                Some(table.header.clone())
140            } else {
141                None
142            }
143        })
144    }
145
146    fn table_alignment(&self) -> Option<Vec<ColumnAlignment>> {
147        self.node().and_then(|node| {
148            if let Node::Table(table) = node {
149                Some(table.alignment.clone())
150            } else {
151                None
152            }
153        })
154    }
155
156    fn table_rows(&self) -> Option<Vec<Vec<GraphInlines>>> {
157        self.node().and_then(|node| {
158            if let Node::Table(table) = node {
159                Some(table.rows.clone())
160            } else {
161                None
162            }
163        })
164    }
165
166    fn content(&self) -> Option<String> {
167        self.node().and_then(|node| {
168            if let Node::Raw(_, content) = node {
169                Some(content.clone())
170            } else {
171                None
172            }
173        })
174    }
175
176    fn ref_text(&self) -> Option<String> {
177        self.node().and_then(|node| {
178            if let Node::Reference(reference) = node {
179                Some(reference.text.clone())
180            } else {
181                None
182            }
183        })
184    }
185
186    fn ref_key2(&self) -> Option<Key> {
187        self.node().and_then(|node| {
188            if let Node::Reference(reference) = node {
189                Some(reference.key.clone())
190            } else {
191                None
192            }
193        })
194    }
195
196    fn inlines(&self) -> GraphInlines {
197        self.node()
198            .map(|node| match node {
199                Node::Section(inlines) => inlines.clone(),
200                Node::Leaf(inlines) => inlines.clone(),
201                Node::Reference(reference) => vec![GraphInline::Str(reference.text)],
202                _ => vec![],
203            })
204            .unwrap_or_default()
205    }
206
207    fn is_list(&self) -> bool {
208        self.is_ordered_list() || self.is_bullet_list()
209    }
210
211    fn is_document(&self) -> bool {
212        matches!(self.node(), Some(Node::Document(_, _)))
213    }
214
215    fn is_section(&self) -> bool {
216        matches!(self.node(), Some(Node::Section(_)))
217    }
218
219    fn is_ordered_list(&self) -> bool {
220        matches!(self.node(), Some(Node::OrderedList()))
221    }
222
223    fn is_bullet_list(&self) -> bool {
224        matches!(self.node(), Some(Node::BulletList()))
225    }
226
227    fn is_reference(&self) -> bool {
228        matches!(self.node(), Some(Node::Reference(_)))
229    }
230
231    fn is_horizontal_rule(&self) -> bool {
232        matches!(self.node(), Some(Node::HorizontalRule()))
233    }
234
235    fn is_raw(&self) -> bool {
236        matches!(self.node(), Some(Node::Raw(_, _)))
237    }
238
239    fn is_leaf(&self) -> bool {
240        matches!(self.node(), Some(Node::Leaf(_)))
241    }
242
243    fn is_quote(&self) -> bool {
244        matches!(self.node(), Some(Node::Quote()))
245    }
246}
247
248pub trait NodePointer<'a>: NodeIter<'a> {
249    fn id(&self) -> Option<NodeId>;
250    fn next_id(&self) -> Option<NodeId>;
251    fn child_id(&self) -> Option<NodeId>;
252    fn prev_id(&self) -> Option<NodeId>;
253    fn to_node(&self, id: NodeId) -> Self;
254    fn to_key(&self, key: Key) -> Option<Self>;
255
256    fn at(&self, id: NodeId) -> bool {
257        self.id() == Some(id)
258    }
259
260    fn node_key(&self) -> Key {
261        self.to_document().and_then(|v| v.document_key()).unwrap()
262    }
263
264    fn is_header(&self) -> bool {
265        !self.is_in_list() && self.is_section()
266    }
267
268    fn collect_tree(self) -> Tree {
269        Tree::from_pointer(self).expect("to have node")
270    }
271
272    fn squash_tree(self, depth: u8) -> Tree {
273        Tree::squash_from_pointer(self, depth)
274            .first()
275            .cloned()
276            .unwrap()
277    }
278
279    fn to_prev(&self) -> Option<Self> {
280        self.prev_id().map(|id| self.to_node(id))
281    }
282
283    fn to_next(&self) -> Option<Self> {
284        self.next_id().map(|id| self.to_node(id))
285    }
286
287    fn to_child(&self) -> Option<Self> {
288        self.child_id().map(|id| self.to_node(id))
289    }
290
291    fn get_next_sections(&self) -> Vec<NodeId> {
292        let mut sections = vec![];
293        if self.is_section() {
294            if let Some(id) = self.id() {
295                sections.push(id);
296            }
297        }
298        if let Some(next) = self.to_next() {
299            sections.extend(next.get_next_sections());
300        }
301        sections
302    }
303
304    fn ref_key(&self) -> Option<Key> {
305        self.node().and_then(|node| {
306            if let Node::Reference(reference) = node {
307                Some(reference.key.clone())
308            } else {
309                None
310            }
311        })
312    }
313
314    fn document_key(&self) -> Option<Key> {
315        self.node().and_then(|node| {
316            if let Node::Document(key, _) = node {
317                Some(key.clone())
318            } else {
319                None
320            }
321        })
322    }
323
324    fn is_primary_section(&self) -> bool {
325        self.is_section() && self.to_prev().map(|p| p.is_document()).unwrap_or(false)
326    }
327
328    fn to_parent(&self) -> Option<Self> {
329        if let Some(prev) = self.to_prev() {
330            if let Some(id) = self.id() {
331                if prev.is_parent_of(id) {
332                    return Some(prev);
333                }
334            }
335            prev.to_parent()
336        } else {
337            None
338        }
339    }
340
341    fn to_self(&self) -> Option<Self> {
342        self.id().map(|id| self.to_node(id))
343    }
344
345    fn get_list(&self) -> Option<Self> {
346        if self.is_ordered_list() || self.is_bullet_list() {
347            return self.to_self();
348        }
349        if self.is_document() {
350            return None;
351        }
352        self.to_parent().and_then(|p| p.get_list())
353    }
354
355    fn get_top_level_list(&self) -> Option<Self> {
356        if self.is_list() && !self.to_parent().map(|p| p.is_in_list()).unwrap_or(false) {
357            return self.to_self();
358        }
359        if self.is_document() {
360            return None;
361        }
362        self.to_parent().and_then(|p| p.get_top_level_list())
363    }
364
365    fn to_document(&self) -> Option<Self> {
366        if self.is_document() {
367            Some(self.to_node(self.id()?))
368        } else {
369            self.to_prev().and_then(|prev| prev.to_document())
370        }
371    }
372
373    fn is_parent_of(&self, other: NodeId) -> bool {
374        self.child_id().is_some() && self.child_id().unwrap() == other
375    }
376
377    fn get_sub_nodes(&self) -> Vec<NodeId> {
378        self.to_child()
379            .map_or(Vec::new(), |child| child.get_next_nodes())
380    }
381
382    fn get_all_sub_nodes(&self) -> Vec<NodeId> {
383        let mut nodes = vec![self.id().unwrap_or_default()];
384        if let Some(child) = self.to_child() {
385            nodes.extend(child.get_all_sub_nodes());
386        }
387        nodes.extend(
388            self.to_next()
389                .map(|n| n.get_all_sub_nodes())
390                .unwrap_or_else(Vec::new),
391        );
392        nodes
393    }
394
395    fn get_next_nodes(&self) -> Vec<NodeId> {
396        let mut nodes = vec![];
397        if let Some(id) = self.id() {
398            nodes.push(id);
399        }
400        if let Some(next) = self.to_next() {
401            nodes.extend(next.get_next_nodes());
402        }
403        nodes
404    }
405
406    fn get_sub_sections(&self) -> Vec<NodeId> {
407        if !self.is_section() {
408            panic!("get_sub_sections called on non-section node")
409        }
410        self.to_child()
411            .map(|n| n.get_next_sections())
412            .unwrap_or(vec![])
413    }
414
415    fn get_all_sub_headers(&self) -> Vec<NodeId> {
416        if !self.is_section() {
417            panic!("get_all_sub_headers called on non-section node")
418        }
419        let mut headers = vec![];
420        if let Some(id) = self.id() {
421            headers.push(id);
422        }
423        if let Some(child) = self.to_child() {
424            headers.extend(child.get_all_sub_headers());
425        }
426        headers.extend(
427            self.to_next()
428                .map(|n| n.get_all_sub_headers())
429                .unwrap_or_else(Vec::new),
430        );
431        headers
432    }
433
434    fn to_first_section_at_the_same_level(&self) -> Self {
435        self.to_prev()
436            .filter(|p| p.is_section() && p.is_prev_of(self.id().expect("Expected node ID")))
437            .map(|p| p.to_first_section_at_the_same_level())
438            .unwrap_or_else(|| self.id().map(|id| self.to_node(id)).unwrap())
439    }
440
441    fn is_prev_of(&self, other: NodeId) -> bool {
442        self.next_id().is_some() && self.next_id().unwrap() == other
443    }
444
445    fn is_in_list(&self) -> bool {
446        if self.is_ordered_list() || self.is_bullet_list() {
447            return true;
448        }
449        if self.is_document() {
450            return false;
451        }
452        self.to_parent().map(|p| p.is_in_list()).unwrap_or(false)
453    }
454
455    fn get_section(&self) -> Option<Self> {
456        if self.is_section() && !self.is_in_list() {
457            return self.id().map(|id| self.to_node(id));
458        }
459        if self.is_document() {
460            return None;
461        }
462        self.to_parent().and_then(|p| p.get_section())
463    }
464}