1use std::cmp::Ordering;
6use std::collections::HashMap;
7use std::sync::{Arc, Mutex, Weak};
8
9use crate::document::BoundingRect;
10use crate::{BaseDocument, NodeData, NodeId, NodeTree};
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub struct RangeBoundary {
14 pub node: NodeId,
15 pub offset: usize,
16}
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub struct RangeBounds {
20 pub start: RangeBoundary,
21 pub end: RangeBoundary,
22}
23
24impl RangeBounds {
25 pub fn collapsed(self) -> bool {
26 self.start == self.end
27 }
28}
29
30#[derive(Clone, Debug)]
31pub struct LiveRange(pub(crate) Arc<Mutex<RangeBounds>>);
32
33impl LiveRange {
34 pub fn bounds(&self) -> RangeBounds {
35 *self.0.lock().unwrap()
36 }
37
38 pub fn set_bounds(&self, bounds: RangeBounds) {
39 *self.0.lock().unwrap() = bounds;
40 }
41
42 pub fn same_range(&self, other: &Self) -> bool {
43 Arc::ptr_eq(&self.0, &other.0)
44 }
45}
46
47#[derive(Clone, Debug)]
48pub enum RangeContent {
49 Full(NodeId),
50 Partial(NodeId, Vec<RangeContent>),
51 Data(NodeId, usize, usize),
52}
53
54pub fn utf16_slice(value: &str, start: usize, end: usize) -> String {
55 let units: Vec<u16> = value
56 .encode_utf16()
57 .skip(start)
58 .take(end.saturating_sub(start))
59 .collect();
60 String::from_utf16_lossy(&units)
61}
62
63fn contains(nodes: &NodeTree, ancestor: NodeId, mut descendant: NodeId) -> bool {
64 loop {
65 if ancestor == descendant {
66 return true;
67 }
68 let Some(parent) = nodes.get(descendant).and_then(|node| node.parent) else {
69 return false;
70 };
71 descendant = parent;
72 }
73}
74
75impl BaseDocument {
76 pub fn create_live_range(&mut self, bounds: RangeBounds) -> LiveRange {
77 self.live_ranges.retain(|range| range.strong_count() != 0);
78 let range = LiveRange(Arc::new(Mutex::new(bounds)));
79 self.live_ranges.push(Arc::downgrade(&range.0));
80 range
81 }
82
83 pub fn range_character_data(&self, id: NodeId) -> Option<&str> {
84 match &self.get_node(id)?.data {
85 NodeData::Text(text) => Some(&text.content),
86 NodeData::Comment { contents } => Some(contents),
87 _ => None,
88 }
89 }
90
91 pub fn range_node_length(&self, id: NodeId) -> Option<usize> {
92 let node = self.get_node(id)?;
93 Some(match self.range_character_data(id) {
94 Some(text) => text.encode_utf16().count(),
95 None => node.children.len(),
96 })
97 }
98
99 pub fn range_contains(&self, ancestor: NodeId, descendant: NodeId) -> bool {
100 contains(&self.nodes, ancestor, descendant)
101 }
102
103 fn range_path(&self, mut id: NodeId) -> Vec<NodeId> {
104 let mut path = vec![id];
105 while let Some(parent) = self.get_node(id).and_then(|node| node.parent) {
106 path.push(parent);
107 id = parent;
108 }
109 path.reverse();
110 path
111 }
112
113 pub fn range_root(&self, id: NodeId) -> NodeId {
114 self.range_path(id)[0]
115 }
116
117 pub fn range_common_ancestor(&self, bounds: RangeBounds) -> Option<NodeId> {
118 self.range_path(bounds.start.node)
119 .iter()
120 .zip(self.range_path(bounds.end.node))
121 .take_while(|(left, right)| **left == *right)
122 .map(|(left, _)| *left)
123 .last()
124 }
125
126 pub fn compare_range_boundaries(
127 &self,
128 left: RangeBoundary,
129 right: RangeBoundary,
130 ) -> Option<Ordering> {
131 if left.node == right.node {
132 return Some(left.offset.cmp(&right.offset));
133 }
134 let a = self.range_path(left.node);
135 let b = self.range_path(right.node);
136 if a.first() != b.first() {
137 return None;
138 }
139 let common = a.iter().zip(&b).take_while(|(a, b)| a == b).count();
140 let parent = self.get_node(a[common - 1])?;
141 if common == a.len() {
142 let index = parent.index_of_child(b[common])?;
143 return Some(if index < left.offset {
144 Ordering::Greater
145 } else {
146 Ordering::Less
147 });
148 }
149 if common == b.len() {
150 let index = parent.index_of_child(a[common])?;
151 return Some(if index < right.offset {
152 Ordering::Less
153 } else {
154 Ordering::Greater
155 });
156 }
157 Some(
158 parent
159 .index_of_child(a[common])?
160 .cmp(&parent.index_of_child(b[common])?),
161 )
162 }
163
164 fn update_live_ranges(&mut self, mut update: impl FnMut(&mut RangeBoundary)) {
165 self.live_ranges.retain(|weak| {
166 let Some(range) = weak.upgrade() else {
167 return false;
168 };
169 let mut bounds = range.lock().unwrap();
170 update(&mut bounds.start);
171 update(&mut bounds.end);
172 true
173 });
174 }
175
176 pub(crate) fn range_remove_node(&mut self, id: NodeId) {
177 if self.live_ranges.is_empty() {
178 return;
179 }
180 let Some(parent) = self.get_node(id).and_then(|node| node.parent) else {
181 return;
182 };
183 let Some(index) = self
184 .get_node(parent)
185 .and_then(|node| node.index_of_child(id))
186 else {
187 return;
188 };
189 let nodes = &self.nodes;
190 self.live_ranges.retain(|weak| {
191 let Some(range) = weak.upgrade() else {
192 return false;
193 };
194 let mut guard = range.lock().unwrap();
195 let bounds = &mut *guard;
196 for point in [&mut bounds.start, &mut bounds.end] {
197 if contains(nodes, id, point.node) {
198 *point = RangeBoundary {
199 node: parent,
200 offset: index,
201 };
202 } else if point.node == parent && point.offset > index {
203 point.offset -= 1;
204 }
205 }
206 true
207 });
208 }
209
210 pub(crate) fn range_insert_nodes(&mut self, parent: NodeId, index: usize, count: usize) {
211 if count == 0 || self.live_ranges.is_empty() {
212 return;
213 }
214 self.update_live_ranges(|point| {
215 if point.node == parent && point.offset > index {
216 point.offset += count;
217 }
218 });
219 }
220
221 pub(crate) fn range_replace_data(
222 &mut self,
223 id: NodeId,
224 offset: usize,
225 removed: usize,
226 added: usize,
227 ) {
228 if self.live_ranges.is_empty() {
229 return;
230 }
231 self.update_live_ranges(|point| {
232 if point.node != id {
233 return;
234 }
235 if point.offset > offset && point.offset <= offset + removed {
236 point.offset = offset;
237 } else if point.offset > offset + removed {
238 point.offset = point.offset - removed + added;
239 }
240 });
241 }
242
243 pub(crate) fn range_split_text(
244 &mut self,
245 old: NodeId,
246 new: NodeId,
247 offset: usize,
248 parent_position: Option<(NodeId, usize)>,
249 ) {
250 self.update_live_ranges(|point| {
251 if point.node == old && point.offset > offset {
252 point.node = new;
253 point.offset -= offset;
254 } else if let Some((parent, index)) = parent_position
255 && point.node == parent
256 && point.offset == index + 1
257 {
258 point.offset += 1;
259 }
260 });
261 }
262
263 pub fn range_merge_text(&mut self, keeper: NodeId, removed: NodeId, prefix: usize) {
265 let position = self.get_node(removed).and_then(|node| {
266 let parent = node.parent?;
267 Some((parent, self.get_node(parent)?.index_of_child(removed)?))
268 });
269 self.update_live_ranges(|point| {
270 if point.node == removed {
271 point.node = keeper;
272 point.offset += prefix;
273 } else if let Some((parent, index)) = position
274 && point.node == parent
275 && point.offset == index
276 {
277 *point = RangeBoundary {
278 node: keeper,
279 offset: prefix,
280 };
281 }
282 });
283 }
284
285 pub fn range_contents(&self, bounds: RangeBounds) -> Vec<RangeContent> {
286 if bounds.collapsed() {
287 return Vec::new();
288 }
289 let Some(common) = self.range_common_ancestor(bounds) else {
290 return Vec::new();
291 };
292 if self.range_character_data(common).is_some() {
293 return vec![RangeContent::Data(
294 common,
295 bounds.start.offset,
296 bounds.end.offset,
297 )];
298 }
299 self.get_node(common)
300 .into_iter()
301 .flat_map(|node| node.children.iter().copied())
302 .filter_map(|id| self.range_content(id, bounds))
303 .collect()
304 }
305
306 fn range_content(&self, id: NodeId, bounds: RangeBounds) -> Option<RangeContent> {
307 let node = self.get_node(id)?;
308 let parent = node.parent?;
309 let index = self.get_node(parent)?.index_of_child(id)?;
310 let before = RangeBoundary {
311 node: parent,
312 offset: index,
313 };
314 let after = RangeBoundary {
315 node: parent,
316 offset: index + 1,
317 };
318 if self.compare_range_boundaries(bounds.end, before)? != Ordering::Greater
319 || self.compare_range_boundaries(bounds.start, after)? != Ordering::Less
320 {
321 return None;
322 }
323 if self.compare_range_boundaries(bounds.start, before)? != Ordering::Greater
324 && self.compare_range_boundaries(bounds.end, after)? != Ordering::Less
325 {
326 return Some(RangeContent::Full(id));
327 }
328 if let Some(text) = self.range_character_data(id) {
329 let start = if bounds.start.node == id {
330 bounds.start.offset
331 } else {
332 0
333 };
334 let end = if bounds.end.node == id {
335 bounds.end.offset
336 } else {
337 text.encode_utf16().count()
338 };
339 return Some(RangeContent::Data(id, start, end));
340 }
341 Some(RangeContent::Partial(
342 id,
343 node.children
344 .iter()
345 .filter_map(|id| self.range_content(*id, bounds))
346 .collect(),
347 ))
348 }
349
350 pub fn range_collapse_after_deletion(&self, bounds: RangeBounds) -> RangeBoundary {
351 if self.range_contains(bounds.start.node, bounds.end.node) {
352 return bounds.start;
353 }
354 let common = self
355 .range_common_ancestor(bounds)
356 .expect("range has one root");
357 let mut child = bounds.start.node;
358 while self.get_node(child).and_then(|node| node.parent) != Some(common) {
359 child = self
360 .get_node(child)
361 .and_then(|node| node.parent)
362 .expect("range ancestor");
363 }
364 RangeBoundary {
365 node: common,
366 offset: self
367 .get_node(common)
368 .unwrap()
369 .index_of_child(child)
370 .unwrap()
371 + 1,
372 }
373 }
374
375 pub fn range_text_parts(&self, bounds: RangeBounds) -> Vec<(NodeId, usize, usize)> {
376 fn append(
377 doc: &BaseDocument,
378 content: &RangeContent,
379 result: &mut Vec<(NodeId, usize, usize)>,
380 ) {
381 match content {
382 RangeContent::Data(id, start, end) => {
383 if doc.get_node(*id).is_some_and(|node| node.is_text_node()) {
384 result.push((*id, *start, *end));
385 }
386 }
387 RangeContent::Partial(_, children) => {
388 for child in children {
389 append(doc, child, result);
390 }
391 }
392 RangeContent::Full(id) => {
393 let mut stack = vec![*id];
394 while let Some(id) = stack.pop() {
395 let Some(node) = doc.get_node(id) else {
396 continue;
397 };
398 if let NodeData::Text(text) = &node.data {
399 result.push((id, 0, text.content.encode_utf16().count()));
400 } else {
401 stack.extend(node.children.iter().rev().copied());
402 }
403 }
404 }
405 }
406 }
407 let mut result = Vec::new();
408 for content in self.range_contents(bounds) {
409 append(self, &content, &mut result);
410 }
411 result
412 }
413
414 pub fn range_string(&self, bounds: RangeBounds) -> String {
415 let mut result = String::new();
416 for (id, start, end) in self.range_text_parts(bounds) {
417 if let Some(text) = self.range_character_data(id) {
418 result.push_str(&utf16_slice(text, start, end));
419 }
420 }
421 result
422 }
423
424 fn range_layout_extents(&self, root: NodeId) -> HashMap<NodeId, (usize, usize)> {
425 use parley::PositionedLayoutItem;
426 let mut result: HashMap<NodeId, (usize, usize)> = HashMap::new();
427 let Some(inline) = self
428 .get_node(root)
429 .and_then(|node| node.element_data())
430 .and_then(|element| element.inline_layout_data.as_ref())
431 else {
432 return result;
433 };
434 for line in inline.layout.lines() {
435 for item in line.items() {
436 if let PositionedLayoutItem::GlyphRun(run) = item
437 && let Some(id) = run.style().brush.text_node
438 {
439 let range = run.run().text_range();
440 result
441 .entry(id)
442 .and_modify(|(start, end)| {
443 *start = (*start).min(range.start);
444 *end = (*end).max(range.end);
445 })
446 .or_insert((range.start, range.end));
447 }
448 }
449 }
450 result
451 }
452
453 pub fn range_layout_ranges(&self, bounds: RangeBounds) -> Vec<(NodeId, usize, usize)> {
456 let mut extents = HashMap::new();
457 let mut result: Vec<(NodeId, usize, usize)> = Vec::new();
458 for (id, start, end) in self.range_text_parts(bounds) {
459 let Some(root) = self
460 .get_node(id)
461 .filter(|node| node.flags.is_in_document())
462 .and_then(|node| node.inline_root_ancestor())
463 .map(|node| node.id)
464 else {
465 continue;
466 };
467 let map = extents
468 .entry(root)
469 .or_insert_with(|| self.range_layout_extents(root));
470 let Some(&(base, limit)) = map.get(&id) else {
471 continue;
472 };
473 let Some(text) = self.range_character_data(id) else {
474 continue;
475 };
476 let start = (base + utf16_slice(text, 0, start).len()).min(limit);
477 let end = (base + utf16_slice(text, 0, end).len()).min(limit);
478 if start == end {
479 continue;
480 }
481 if let Some((last_root, _, last_end)) = result.last_mut()
482 && *last_root == root
483 && *last_end == start
484 {
485 *last_end = end;
486 } else {
487 result.push((root, start, end));
488 }
489 }
490 result
491 }
492
493 pub fn range_boundary_from_layout(
494 &self,
495 root: NodeId,
496 offset: usize,
497 end_boundary: bool,
498 ) -> Option<RangeBoundary> {
499 let extents = self.range_layout_extents(root);
500 let mut candidates: Vec<_> = extents.into_iter().collect();
501 candidates.sort_by_key(|(_, (start, _))| *start);
502 for (id, (start, end)) in candidates {
503 let matches = if end_boundary {
504 offset > start && offset <= end
505 } else {
506 offset >= start && offset < end
507 };
508 if matches {
509 let text = self.range_character_data(id)?;
510 let mut bytes = offset.saturating_sub(start).min(text.len());
511 while !text.is_char_boundary(bytes) {
512 bytes -= 1;
513 }
514 return Some(RangeBoundary {
515 node: id,
516 offset: text[..bytes].encode_utf16().count(),
517 });
518 }
519 }
520 None
521 }
522
523 pub fn range_client_rects(&self, bounds: RangeBounds) -> Vec<crate::kurbo::Rect> {
524 use parley::{Affinity, Cursor, Selection};
525
526 fn element_rects(
527 doc: &BaseDocument,
528 content: &RangeContent,
529 result: &mut Vec<crate::kurbo::Rect>,
530 ) {
531 match content {
532 RangeContent::Full(id)
533 if doc.get_node(*id).is_some_and(|node| node.is_element()) =>
534 {
535 result.extend(doc.node_client_rects(*id).into_iter().map(|rect| {
536 crate::kurbo::Rect::new(
537 rect.x,
538 rect.y,
539 rect.x + rect.width,
540 rect.y + rect.height,
541 )
542 }));
543 }
544 RangeContent::Partial(_, children) => {
545 for child in children {
546 element_rects(doc, child, result);
547 }
548 }
549 _ => {}
550 }
551 }
552
553 let mut result = Vec::new();
554 for content in self.range_contents(bounds) {
555 element_rects(self, &content, &mut result);
556 }
557 for (root_id, start, end) in self.range_layout_ranges(bounds) {
558 let Some(root) = self.get_node(root_id) else {
559 continue;
560 };
561 let Some(inline) = root
562 .element_data()
563 .and_then(|element| element.inline_layout_data.as_ref())
564 else {
565 continue;
566 };
567 let layout = &inline.layout;
568 let scale = layout.scale() as f64;
569 let box_layout = root.final_layout();
570 let position = root.absolute_position(0.0, 0.0);
571 let x = position.x as f64 + (box_layout.padding.left + box_layout.border.left) as f64
572 - self.viewport_scroll.x;
573 let y = position.y as f64 + (box_layout.padding.top + box_layout.border.top) as f64
574 - self.viewport_scroll.y;
575 let selection = Selection::new(
576 Cursor::from_byte_index(layout, start, Affinity::Downstream),
577 Cursor::from_byte_index(layout, end, Affinity::Downstream),
578 );
579 selection.geometry_with(layout, |rect, _| {
580 let rect = self.transformed_client_rect(
581 root_id,
582 BoundingRect {
583 x: x + rect.x0 / scale,
584 y: y + rect.y0 / scale,
585 width: (rect.x1 - rect.x0) / scale,
586 height: (rect.y1 - rect.y0) / scale,
587 },
588 );
589 result.push(crate::kurbo::Rect::new(
590 rect.x,
591 rect.y,
592 rect.x + rect.width,
593 rect.y + rect.height,
594 ));
595 });
596 }
597 result
598 }
599}
600
601pub(crate) type WeakRange = Weak<Mutex<RangeBounds>>;