1use crate::node::{Mark, Node};
32use crate::normalize::{normalize_children, NormalizeOptions};
33use serde::{Deserialize, Serialize};
34use std::fmt;
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
40pub struct Position {
41 pub child: usize,
43 pub offset: usize,
45}
46
47impl Position {
48 #[inline]
50 pub fn new(child: usize, offset: usize) -> Self {
51 Self { child, offset }
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
58pub struct Range {
59 pub start: Position,
61 pub end: Position,
63}
64
65impl Range {
66 #[inline]
68 pub fn new(start: Position, end: Position) -> Self {
69 Self { start, end }
70 }
71
72 #[inline]
74 pub fn collapsed(pos: Position) -> Self {
75 Self {
76 start: pos,
77 end: pos,
78 }
79 }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq)]
84pub enum RangeError {
85 ChildOutOfRange {
87 child: usize,
89 },
90 OffsetOutOfRange {
92 child: usize,
94 offset: usize,
96 },
97 NotTextNode {
99 child: usize,
101 },
102 InvertedRange,
104}
105
106impl fmt::Display for RangeError {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 match self {
109 RangeError::ChildOutOfRange { child } => write!(f, "range: child {child} out of range"),
110 RangeError::OffsetOutOfRange { child, offset } => {
111 write!(f, "range: offset {offset} out of range in child {child}")
112 }
113 RangeError::NotTextNode { child } => {
114 write!(f, "range: child {child} is not a text node")
115 }
116 RangeError::InvertedRange => write!(f, "range: end precedes start"),
117 }
118 }
119}
120
121impl std::error::Error for RangeError {}
122
123impl Node {
124 pub fn insert_text(
128 &mut self,
129 pos: Position,
130 text: &str,
131 marks: Option<&[Mark]>,
132 ) -> Result<(), RangeError> {
133 let children = self.children_mut();
134 let i = ensure_boundary(children, pos)?;
135 children.insert(i, make_text(text, marks));
136 normalize_children(children, &NormalizeOptions::default());
137 Ok(())
138 }
139
140 pub fn delete_range(&mut self, range: Range) -> Result<(), RangeError> {
143 let children = self.children_mut();
144 let (s, e) = resolve_range(children, range)?;
145 children.drain(s..e);
146 normalize_children(children, &NormalizeOptions::default());
147 Ok(())
148 }
149
150 pub fn replace_range(
152 &mut self,
153 range: Range,
154 text: &str,
155 marks: Option<&[Mark]>,
156 ) -> Result<(), RangeError> {
157 let children = self.children_mut();
158 let (s, e) = resolve_range(children, range)?;
159 children.drain(s..e);
160 if !text.is_empty() {
161 children.insert(s, make_text(text, marks));
162 }
163 normalize_children(children, &NormalizeOptions::default());
164 Ok(())
165 }
166
167 pub fn add_mark_range(&mut self, range: Range, mark: Mark) -> Result<(), RangeError> {
170 let children = self.children_mut();
171 let (s, e) = resolve_range(children, range)?;
172 for node in &mut children[s..e] {
173 if is_text(node) {
174 node.add_mark(mark.clone());
175 }
176 }
177 normalize_children(children, &NormalizeOptions::default());
178 Ok(())
179 }
180
181 pub fn remove_mark_range(&mut self, range: Range, mark_type: &str) -> Result<(), RangeError> {
183 let children = self.children_mut();
184 let (s, e) = resolve_range(children, range)?;
185 for node in &mut children[s..e] {
186 if is_text(node) {
187 node.remove_mark(mark_type);
188 }
189 }
190 normalize_children(children, &NormalizeOptions::default());
191 Ok(())
192 }
193
194 pub fn toggle_mark_range(&mut self, range: Range, mark: Mark) -> Result<(), RangeError> {
198 let children = self.children_mut();
199 let (s, e) = resolve_range(children, range)?;
200 let all_have = children[s..e]
201 .iter()
202 .filter(|n| is_text(n))
203 .all(|n| n.has_mark(&mark.mark_type));
204 for node in &mut children[s..e] {
205 if is_text(node) {
206 if all_have {
207 node.remove_mark(&mark.mark_type);
208 } else {
209 node.add_mark(mark.clone());
210 }
211 }
212 }
213 normalize_children(children, &NormalizeOptions::default());
214 Ok(())
215 }
216}
217
218#[inline]
219fn is_text(n: &Node) -> bool {
220 n.node_type.as_deref() == Some("text")
221}
222
223#[inline]
224fn char_len(n: &Node) -> usize {
225 n.text.as_deref().unwrap_or("").chars().count()
226}
227
228fn make_text(text: &str, marks: Option<&[Mark]>) -> Node {
230 match marks {
231 Some(m) if !m.is_empty() => Node::text_with_marks(text, m.iter().cloned()),
232 _ => Node::text(text),
233 }
234}
235
236fn split_text_at(node: &Node, k: usize) -> (Node, Node) {
239 let s = node.text.as_deref().unwrap_or("");
240 let byte = s.char_indices().nth(k).map_or(s.len(), |(b, _)| b);
241 let (l, r) = s.split_at(byte);
242 let mut left = node.clone();
243 left.text = Some(l.to_owned());
244 let mut right = node.clone();
245 right.text = Some(r.to_owned());
246 (left, right)
247}
248
249fn ensure_boundary(children: &mut Vec<Node>, pos: Position) -> Result<usize, RangeError> {
252 if pos.child > children.len() {
253 return Err(RangeError::ChildOutOfRange { child: pos.child });
254 }
255 if pos.child == children.len() {
256 return if pos.offset == 0 {
258 Ok(children.len())
259 } else {
260 Err(RangeError::OffsetOutOfRange {
261 child: pos.child,
262 offset: pos.offset,
263 })
264 };
265 }
266 if is_text(&children[pos.child]) {
267 let cl = char_len(&children[pos.child]);
268 if pos.offset == 0 {
269 return Ok(pos.child);
270 }
271 if pos.offset == cl {
272 return Ok(pos.child + 1);
273 }
274 if pos.offset > cl {
275 return Err(RangeError::OffsetOutOfRange {
276 child: pos.child,
277 offset: pos.offset,
278 });
279 }
280 let (l, r) = split_text_at(&children[pos.child], pos.offset);
281 children[pos.child] = l;
282 children.insert(pos.child + 1, r);
283 Ok(pos.child + 1)
284 } else if pos.offset == 0 {
285 Ok(pos.child)
286 } else {
287 Err(RangeError::NotTextNode { child: pos.child })
288 }
289}
290
291fn resolve_range(children: &mut Vec<Node>, range: Range) -> Result<(usize, usize), RangeError> {
295 let (sp, ep) = (range.start, range.end);
296 if (ep.child, ep.offset) < (sp.child, sp.offset) {
297 return Err(RangeError::InvertedRange);
298 }
299 let e = ensure_boundary(children, ep)?;
300 let len_after_end = children.len();
301 let s = ensure_boundary(children, sp)?;
302 let start_split_inserted = children.len() > len_after_end;
303 let e = if start_split_inserted && s <= e {
304 e + 1
305 } else {
306 e
307 };
308 Ok((s, e))
309}