1use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToOffsetUtf16, ToPoint};
2use language::{OffsetUtf16, Point, TextDimension};
3use std::{
4 cmp::Ordering,
5 ops::{Range, Sub},
6};
7use sum_tree::Bias;
8use text::BufferId;
9
10#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
11pub struct Anchor {
12 pub buffer_id: Option<BufferId>,
13 pub excerpt_id: ExcerptId,
14 pub text_anchor: text::Anchor,
15 pub diff_base_anchor: Option<text::Anchor>,
16}
17
18impl Anchor {
19 pub const fn with_diff_base_anchor(self, diff_base_anchor: text::Anchor) -> Self {
20 Self {
21 diff_base_anchor: Some(diff_base_anchor),
22 ..self
23 }
24 }
25
26 pub const fn in_buffer(
27 excerpt_id: ExcerptId,
28 buffer_id: BufferId,
29 text_anchor: text::Anchor,
30 ) -> Self {
31 Self {
32 buffer_id: Some(buffer_id),
33 excerpt_id,
34 text_anchor,
35 diff_base_anchor: None,
36 }
37 }
38
39 pub const fn range_in_buffer(
40 excerpt_id: ExcerptId,
41 buffer_id: BufferId,
42 range: Range<text::Anchor>,
43 ) -> Range<Self> {
44 Self::in_buffer(excerpt_id, buffer_id, range.start)
45 ..Self::in_buffer(excerpt_id, buffer_id, range.end)
46 }
47
48 pub const fn min() -> Self {
49 Self {
50 buffer_id: None,
51 excerpt_id: ExcerptId::min(),
52 text_anchor: text::Anchor::MIN,
53 diff_base_anchor: None,
54 }
55 }
56
57 pub const fn max() -> Self {
58 Self {
59 buffer_id: None,
60 excerpt_id: ExcerptId::max(),
61 text_anchor: text::Anchor::MAX,
62 diff_base_anchor: None,
63 }
64 }
65
66 pub fn cmp(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering {
67 if self == other {
68 return Ordering::Equal;
69 }
70
71 let self_excerpt_id = snapshot.latest_excerpt_id(self.excerpt_id);
72 let other_excerpt_id = snapshot.latest_excerpt_id(other.excerpt_id);
73
74 let excerpt_id_cmp = self_excerpt_id.cmp(&other_excerpt_id, snapshot);
75 if excerpt_id_cmp.is_ne() {
76 return excerpt_id_cmp;
77 }
78 if self_excerpt_id == ExcerptId::min() || self_excerpt_id == ExcerptId::max() {
79 return Ordering::Equal;
80 }
81 if let Some(excerpt) = snapshot.excerpt(self_excerpt_id) {
82 let text_cmp = self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer);
83 if text_cmp.is_ne() {
84 return text_cmp;
85 }
86 if (self.diff_base_anchor.is_some() || other.diff_base_anchor.is_some())
87 && let Some(base_text) = snapshot
88 .diffs
89 .get(&excerpt.buffer_id)
90 .map(|diff| diff.base_text())
91 {
92 let self_anchor = self.diff_base_anchor.filter(|a| base_text.can_resolve(a));
93 let other_anchor = other.diff_base_anchor.filter(|a| base_text.can_resolve(a));
94 return match (self_anchor, other_anchor) {
95 (Some(a), Some(b)) => a.cmp(&b, base_text),
96 (Some(_), None) => match other.text_anchor.bias {
97 Bias::Left => Ordering::Greater,
98 Bias::Right => Ordering::Less,
99 },
100 (None, Some(_)) => match self.text_anchor.bias {
101 Bias::Left => Ordering::Less,
102 Bias::Right => Ordering::Greater,
103 },
104 (None, None) => Ordering::Equal,
105 };
106 }
107 }
108 Ordering::Equal
109 }
110
111 pub const fn bias(&self) -> Bias {
112 self.text_anchor.bias
113 }
114
115 pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
116 if self.text_anchor.bias != Bias::Left
117 && let Some(excerpt) = snapshot.excerpt(self.excerpt_id)
118 {
119 return Self {
120 buffer_id: self.buffer_id,
121 excerpt_id: self.excerpt_id,
122 text_anchor: self.text_anchor.bias_left(&excerpt.buffer),
123 diff_base_anchor: self.diff_base_anchor.map(|a| {
124 if let Some(base_text) = snapshot
125 .diffs
126 .get(&excerpt.buffer_id)
127 .map(|diff| diff.base_text())
128 && a.buffer_id == Some(base_text.remote_id())
129 {
130 return a.bias_left(base_text);
131 }
132 a
133 }),
134 };
135 }
136 *self
137 }
138
139 pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
140 if self.text_anchor.bias != Bias::Right
141 && let Some(excerpt) = snapshot.excerpt(self.excerpt_id)
142 {
143 return Self {
144 buffer_id: self.buffer_id,
145 excerpt_id: self.excerpt_id,
146 text_anchor: self.text_anchor.bias_right(&excerpt.buffer),
147 diff_base_anchor: self.diff_base_anchor.map(|a| {
148 if let Some(base_text) = snapshot
149 .diffs
150 .get(&excerpt.buffer_id)
151 .map(|diff| diff.base_text())
152 && a.buffer_id == Some(base_text.remote_id())
153 {
154 return a.bias_right(base_text);
155 }
156 a
157 }),
158 };
159 }
160 *self
161 }
162
163 pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
164 where
165 D: TextDimension + Ord + Sub<D, Output = D>,
166 {
167 snapshot.summary_for_anchor(self)
168 }
169
170 pub fn is_valid(&self, snapshot: &MultiBufferSnapshot) -> bool {
171 if *self == Anchor::min() || *self == Anchor::max() {
172 true
173 } else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
174 (self.text_anchor == excerpt.range.context.start
175 || self.text_anchor == excerpt.range.context.end
176 || self.text_anchor.is_valid(&excerpt.buffer))
177 && excerpt.contains(self)
178 } else {
179 false
180 }
181 }
182}
183
184impl ToOffset for Anchor {
185 fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize {
186 self.summary(snapshot)
187 }
188}
189
190impl ToOffsetUtf16 for Anchor {
191 fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
192 self.summary(snapshot)
193 }
194}
195
196impl ToPoint for Anchor {
197 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
198 self.summary(snapshot)
199 }
200}
201
202pub trait AnchorRangeExt {
203 fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering;
204 fn includes(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool;
205 fn overlaps(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool;
206 fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
207 fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
208}
209
210impl AnchorRangeExt for Range<Anchor> {
211 fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering {
212 match self.start.cmp(&other.start, buffer) {
213 Ordering::Equal => other.end.cmp(&self.end, buffer),
214 ord => ord,
215 }
216 }
217
218 fn includes(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool {
219 self.start.cmp(&other.start, buffer).is_le() && other.end.cmp(&self.end, buffer).is_le()
220 }
221
222 fn overlaps(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool {
223 self.end.cmp(&other.start, buffer).is_ge() && self.start.cmp(&other.end, buffer).is_le()
224 }
225
226 fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
227 self.start.to_offset(content)..self.end.to_offset(content)
228 }
229
230 fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point> {
231 self.start.to_point(content)..self.end.to_point(content)
232 }
233}
234
235#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash, Ord, PartialOrd)]
236pub struct Offset(pub usize);