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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
//! [`ResolvedPos`] — an absolute document position resolved into the path of
//! ancestor nodes that contain it.
use crate::error::DocError;
use crate::node::Node;
#[derive(Debug, Clone)]
struct PathStep {
node: Node,
index: usize,
/// Absolute position just inside `node` (before its first child).
start: usize,
}
/// An absolute position together with its enclosing-node path.
///
/// Produced by [`resolve`](ResolvedPos::resolve). Depth 0 is the root passed
/// to `resolve` (normally the document node).
#[derive(Debug, Clone)]
pub struct ResolvedPos {
pos: usize,
path: Vec<PathStep>,
parent_offset: usize,
}
impl ResolvedPos {
/// Resolve `pos` against `root` (treated as the document).
///
/// Returns [`DocError::PositionOutOfRange`] if `pos` is not in
/// `0..=root.content().size()`.
pub fn resolve(root: &Node, pos: usize) -> Result<ResolvedPos, DocError> {
let max = root.content().size();
if pos > max {
return Err(DocError::PositionOutOfRange { pos, max });
}
let mut path = Vec::new();
let mut node = root.clone();
let mut start = 0usize;
let mut parent_offset = pos;
loop {
let (index, offset) = node.content().find_index(parent_offset);
let rem = parent_offset - offset;
path.push(PathStep {
node: node.clone(),
index,
start: start + offset,
});
if rem == 0 {
break;
}
let child = node.child(index).clone();
if child.is_text() {
break;
}
start += offset + 1;
parent_offset = rem - 1;
node = child;
}
Ok(ResolvedPos {
pos,
path,
parent_offset,
})
}
/// The absolute position.
pub fn pos(&self) -> usize {
self.pos
}
/// The deepest depth (0 = root).
pub fn depth(&self) -> usize {
self.path.len() - 1
}
/// The offset of this position within its immediate parent's content.
pub fn parent_offset(&self) -> usize {
self.parent_offset
}
/// The ancestor node at `depth`.
///
/// # Panics
/// Panics if `depth > self.depth()`.
pub fn node(&self, depth: usize) -> &Node {
&self.path[depth].node
}
/// The immediate parent of this position.
pub fn parent(&self) -> &Node {
&self.path[self.depth()].node
}
/// The document (root) node.
pub fn doc(&self) -> &Node {
&self.path[0].node
}
/// The child index into `node(depth)` that this position points at or
/// into.
pub fn index(&self, depth: usize) -> usize {
self.path[depth].index
}
/// Absolute position just inside `node(depth)` (before its first child).
/// `start(0)` is always 0.
pub fn start(&self, depth: usize) -> usize {
if depth == 0 {
0
} else {
self.path[depth - 1].start + 1
}
}
/// Absolute position just after the last child of `node(depth)`.
pub fn end(&self, depth: usize) -> usize {
self.start(depth) + self.path[depth].node.content().size()
}
/// Position directly before `node(depth)` (for `1 <= depth <= self.depth()`).
///
/// # Panics
/// Panics if `depth == 0` (the root has no position before it).
pub fn before(&self, depth: usize) -> usize {
assert!(depth >= 1, "no position before the root");
self.path[depth - 1].start
}
/// Position directly after `node(depth)` (for `1 <= depth <= self.depth()`).
///
/// # Panics
/// Panics if `depth == 0` (the root has no position after it).
pub fn after(&self, depth: usize) -> usize {
assert!(depth >= 1, "no position after the root");
self.path[depth - 1].start + self.path[depth].node.node_size()
}
/// The offset into the text node at this position. Zero when the position
/// is not inside a text run.
pub fn text_offset(&self) -> usize {
self.pos - self.path[self.depth()].start
}
/// The deepest depth at which this position and `pos` lie in the same
/// ancestor node.
pub fn shared_depth(&self, pos: usize) -> usize {
let mut depth = self.depth();
while depth > 0 {
if self.start(depth) <= pos && self.end(depth) >= pos {
return depth;
}
depth -= 1;
}
0
}
/// The node directly after this position within its parent, or `None` at
/// the end of the parent. When the position is inside a text run, the
/// returned node is the remaining tail of that run.
pub fn node_after(&self) -> Option<Node> {
let parent = self.parent();
let index = self.index(self.depth());
if index == parent.child_count() {
return None;
}
let d_off = self.text_offset();
let child = parent.child(index);
if d_off > 0 {
Some(child.cut(d_off, child.node_size()))
} else {
Some(child.clone())
}
}
/// The node directly before this position within its parent, or `None`
/// at the start. When inside a text run, the returned node is the leading
/// head of that run.
pub fn node_before(&self) -> Option<Node> {
let index = self.index(self.depth());
let d_off = self.text_offset();
if d_off > 0 {
return Some(self.parent().child(index).cut(0, d_off));
}
if index == 0 {
None
} else {
Some(self.parent().child(index - 1).clone())
}
}
}