1use crate::MultiBufferPoint;
2
3use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToPoint};
4use language::{OffsetUtf16, Point, TextDimension};
5use std::{
6 cmp::Ordering,
7 ops::{Range, Sub},
8};
9use sum_tree::Bias;
10use text::BufferId;
11
12#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
13pub struct Anchor {
14 pub buffer_id: Option<BufferId>,
15 pub excerpt_id: ExcerptId,
16 pub text_anchor: text::Anchor,
17 /// Some if this anchor points to within a deleted diff hunk.
18 pub diff_base_anchor: Option<text::Anchor>,
19}
20
21impl Anchor {
22 pub fn with_diff_base_anchor(self, diff_base_anchor: text::Anchor) -> Self {
23 Self {
24 diff_base_anchor: Some(diff_base_anchor),
25 ..self
26 }
27 }
28
29 pub fn in_buffer(
30 excerpt_id: ExcerptId,
31 buffer_id: BufferId,
32 text_anchor: text::Anchor,
33 ) -> Self {
34 Self {
35 buffer_id: Some(buffer_id),
36 excerpt_id,
37 text_anchor,
38 diff_base_anchor: None,
39 }
40 }
41
42 pub fn range_in_buffer(
43 excerpt_id: ExcerptId,
44 buffer_id: BufferId,
45 range: Range<text::Anchor>,
46 ) -> Range<Self> {
47 Self::in_buffer(excerpt_id, buffer_id, range.start)
48 ..Self::in_buffer(excerpt_id, buffer_id, range.end)
49 }
50
51 pub fn min() -> Self {
52 Self {
53 buffer_id: None,
54 excerpt_id: ExcerptId::min(),
55 text_anchor: text::Anchor::MIN,
56 diff_base_anchor: None,
57 }
58 }
59
60 pub fn max() -> Self {
61 Self {
62 buffer_id: None,
63 excerpt_id: ExcerptId::max(),
64 text_anchor: text::Anchor::MAX,
65 diff_base_anchor: None,
66 }
67 }
68
69 pub fn cmp(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering {
70 if self == other {
71 return Ordering::Equal;
72 }
73
74 let self_excerpt_id = snapshot.latest_excerpt_id(self.excerpt_id);
75 let other_excerpt_id = snapshot.latest_excerpt_id(other.excerpt_id);
76
77 let excerpt_id_cmp = self_excerpt_id.cmp(&other_excerpt_id, snapshot);
78 if excerpt_id_cmp.is_ne() {
79 return excerpt_id_cmp;
80 }
81 if self_excerpt_id == ExcerptId::min() || self_excerpt_id == ExcerptId::max() {
82 return Ordering::Equal;
83 }
84 if let Some(excerpt) = snapshot.excerpt(self_excerpt_id) {
85 let text_cmp = self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer);
86 if text_cmp.is_ne() {
87 return text_cmp;
88 }
89 if (self.diff_base_anchor.is_some() || other.diff_base_anchor.is_some())
90 && let Some(base_text) = snapshot
91 .diffs
92 .get(&excerpt.buffer_id)
93 .map(|diff| diff.base_text())
94 {
95 let self_anchor = self.diff_base_anchor.filter(|a| base_text.can_resolve(a));
96 let other_anchor = other.diff_base_anchor.filter(|a| base_text.can_resolve(a));
97 return match (self_anchor, other_anchor) {
98 (Some(a), Some(b)) => a.cmp(&b, base_text),
99 (Some(_), None) => match other.text_anchor.bias {
100 Bias::Left => Ordering::Greater,
101 Bias::Right => Ordering::Less,
102 },
103 (None, Some(_)) => match self.text_anchor.bias {
104 Bias::Left => Ordering::Less,
105 Bias::Right => Ordering::Greater,
106 },
107 (None, None) => Ordering::Equal,
108 };
109 }
110 }
111 Ordering::Equal
112 }
113
114 pub fn bias(&self) -> Bias {
115 self.text_anchor.bias
116 }
117
118 pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
119 if self.text_anchor.bias != Bias::Left
120 && let Some(excerpt) = snapshot.excerpt(self.excerpt_id)
121 {
122 return Self {
123 buffer_id: self.buffer_id,
124 excerpt_id: self.excerpt_id,
125 text_anchor: self.text_anchor.bias_left(&excerpt.buffer),
126 diff_base_anchor: self.diff_base_anchor.map(|a| {
127 if let Some(base_text) = snapshot
128 .diffs
129 .get(&excerpt.buffer_id)
130 .map(|diff| diff.base_text())
131 && a.buffer_id == Some(base_text.remote_id())
132 {
133 return a.bias_left(base_text);
134 }
135 a
136 }),
137 };
138 }
139 *self
140 }
141
142 pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
143 if self.text_anchor.bias != Bias::Right
144 && let Some(excerpt) = snapshot.excerpt(self.excerpt_id)
145 {
146 return Self {
147 buffer_id: self.buffer_id,
148 excerpt_id: self.excerpt_id,
149 text_anchor: self.text_anchor.bias_right(&excerpt.buffer),
150 diff_base_anchor: self.diff_base_anchor.map(|a| {
151 if let Some(base_text) = snapshot
152 .diffs
153 .get(&excerpt.buffer_id)
154 .map(|diff| diff.base_text())
155 && a.buffer_id == Some(base_text.remote_id())
156 {
157 return a.bias_right(base_text);
158 }
159 a
160 }),
161 };
162 }
163 *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 snapshot.summary_for_anchor(self)
183 }
184 fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
185 snapshot.summary_for_anchor(self)
186 }
187}
188
189impl ToPoint for Anchor {
190 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> MultiBufferPoint {
191 snapshot.summary_for_anchor(self)
192 }
193 fn to_point_utf16(&self, snapshot: &MultiBufferSnapshot) -> rope::PointUtf16 {
194 snapshot.summary_for_anchor(self)
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<MultiBufferPoint>;
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<MultiBufferPoint> {
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);