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