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