1use super::{Point, ToOffset};
2use crate::{rope::TextDimension, BufferSnapshot, PointUtf16, ToPoint, ToPointUtf16};
3use anyhow::Result;
4use std::{cmp::Ordering, fmt::Debug, ops::Range};
5use sum_tree::Bias;
6
7#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
8pub struct Anchor {
9 pub timestamp: clock::Local,
10 pub offset: usize,
11 pub bias: Bias,
12}
13
14impl Anchor {
15 pub const MIN: Self = Self {
16 timestamp: clock::Local::MIN,
17 offset: usize::MIN,
18 bias: Bias::Left,
19 };
20
21 pub const MAX: Self = Self {
22 timestamp: clock::Local::MAX,
23 offset: usize::MAX,
24 bias: Bias::Right,
25 };
26
27 pub fn cmp(&self, other: &Anchor, buffer: &BufferSnapshot) -> Ordering {
28 let fragment_id_comparison = if self.timestamp == other.timestamp {
29 Ordering::Equal
30 } else {
31 buffer
32 .fragment_id_for_anchor(self)
33 .cmp(&buffer.fragment_id_for_anchor(other))
34 };
35
36 fragment_id_comparison
37 .then_with(|| self.offset.cmp(&other.offset))
38 .then_with(|| self.bias.cmp(&other.bias))
39 }
40
41 pub fn min(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
42 if self.cmp(other, buffer).is_le() {
43 self.clone()
44 } else {
45 other.clone()
46 }
47 }
48
49 pub fn max(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
50 if self.cmp(other, buffer).is_ge() {
51 self.clone()
52 } else {
53 other.clone()
54 }
55 }
56
57 pub fn bias(&self, bias: Bias, buffer: &BufferSnapshot) -> Anchor {
58 if bias == Bias::Left {
59 self.bias_left(buffer)
60 } else {
61 self.bias_right(buffer)
62 }
63 }
64
65 pub fn bias_left(&self, buffer: &BufferSnapshot) -> Anchor {
66 if self.bias == Bias::Left {
67 self.clone()
68 } else {
69 buffer.anchor_before(self)
70 }
71 }
72
73 pub fn bias_right(&self, buffer: &BufferSnapshot) -> Anchor {
74 if self.bias == Bias::Right {
75 self.clone()
76 } else {
77 buffer.anchor_after(self)
78 }
79 }
80
81 pub fn summary<'a, D>(&self, content: &'a BufferSnapshot) -> D
82 where
83 D: TextDimension,
84 {
85 content.summary_for_anchor(self)
86 }
87}
88
89pub trait OffsetRangeExt {
90 fn to_offset(&self, snapshot: &BufferSnapshot) -> Range<usize>;
91 fn to_point(&self, snapshot: &BufferSnapshot) -> Range<Point>;
92 fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range<PointUtf16>;
93}
94
95impl<T> OffsetRangeExt for Range<T>
96where
97 T: ToOffset,
98{
99 fn to_offset(&self, snapshot: &BufferSnapshot) -> Range<usize> {
100 self.start.to_offset(snapshot)..self.end.to_offset(&snapshot)
101 }
102
103 fn to_point(&self, snapshot: &BufferSnapshot) -> Range<Point> {
104 self.start.to_offset(snapshot).to_point(snapshot)
105 ..self.end.to_offset(snapshot).to_point(snapshot)
106 }
107
108 fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range<PointUtf16> {
109 self.start.to_offset(snapshot).to_point_utf16(snapshot)
110 ..self.end.to_offset(snapshot).to_point_utf16(snapshot)
111 }
112}
113
114pub trait AnchorRangeExt {
115 fn cmp(&self, b: &Range<Anchor>, buffer: &BufferSnapshot) -> Result<Ordering>;
116}
117
118impl AnchorRangeExt for Range<Anchor> {
119 fn cmp(&self, other: &Range<Anchor>, buffer: &BufferSnapshot) -> Result<Ordering> {
120 Ok(match self.start.cmp(&other.start, buffer) {
121 Ordering::Equal => other.end.cmp(&self.end, buffer),
122 ord @ _ => ord,
123 })
124 }
125}