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
101
102
//! Positional addressing by index path.
//!
//! A *path* is a slice of child indices from a node, root = `&[]`. So in a
//! `doc -> paragraph -> text` tree, the text node is at `&[0, 0]`.
//!
//! There are no stored parent pointers; parent/sibling navigation is expressed
//! by slicing a path: the parent of `path` is `node.node_at(&path[..path.len()-1])`.
use crate::node::Node;
impl Node {
/// Node at `path` (relative to `self`), or `None` if any index is missing.
///
/// ```
/// use tiptap_rusty_parser::Document;
/// let doc = Document::from_json_str(
/// r#"{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"hi"}]}]}"#,
/// ).unwrap();
/// assert_eq!(doc.node_at(&[0, 0]).unwrap().get_text(), Some("hi"));
/// assert!(doc.node_at(&[5]).is_none());
/// ```
pub fn node_at(&self, path: &[usize]) -> Option<&Node> {
let mut cur = self;
for &i in path {
cur = cur.content.as_ref()?.get(i)?;
}
Some(cur)
}
/// Mutable variant of [`Node::node_at`].
pub fn node_at_mut(&mut self, path: &[usize]) -> Option<&mut Node> {
let mut cur = self;
for &i in path {
cur = cur.content.as_mut()?.get_mut(i)?;
}
Some(cur)
}
/// Path to the first node (incl. `self`) matching `pred`, pre-order.
///
/// Returns `Some(vec![])` when `self` matches.
///
/// ```
/// use tiptap_rusty_parser::Document;
/// let doc = Document::from_json_str(
/// r#"{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"hi"}]}]}"#,
/// ).unwrap();
/// let p = doc.path_to(|n| n.node_type.as_deref() == Some("text")).unwrap();
/// assert_eq!(p, vec![0, 0]);
/// assert_eq!(doc.node_at(&p).unwrap().get_text(), Some("hi"));
/// ```
pub fn path_to(&self, mut pred: impl FnMut(&Node) -> bool) -> Option<Vec<usize>> {
let mut path = Vec::new();
if path_to_rec(self, &mut pred, &mut path) {
Some(path)
} else {
None
}
}
/// Paths to every node (incl. `self`) matching `pred`, pre-order.
pub fn paths_to(&self, mut pred: impl FnMut(&Node) -> bool) -> Vec<Vec<usize>> {
let mut out = Vec::new();
let mut path = Vec::new();
paths_to_rec(self, &mut pred, &mut path, &mut out);
out
}
}
fn path_to_rec(node: &Node, pred: &mut impl FnMut(&Node) -> bool, path: &mut Vec<usize>) -> bool {
if pred(node) {
return true;
}
if let Some(children) = &node.content {
for (i, child) in children.iter().enumerate() {
path.push(i);
if path_to_rec(child, pred, path) {
return true;
}
path.pop();
}
}
false
}
fn paths_to_rec(
node: &Node,
pred: &mut impl FnMut(&Node) -> bool,
path: &mut Vec<usize>,
out: &mut Vec<Vec<usize>>,
) {
if pred(node) {
out.push(path.clone());
}
if let Some(children) = &node.content {
for (i, child) in children.iter().enumerate() {
path.push(i);
paths_to_rec(child, pred, path, out);
path.pop();
}
}
}