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 let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id, snapshot);
61 if excerpt_id_cmp.is_ne() {
62 return excerpt_id_cmp;
63 }
64 if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() {
65 return Ordering::Equal;
66 }
67 if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
68 let text_cmp = self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer);
69 if text_cmp.is_ne() {
70 return text_cmp;
71 }
72 if self.diff_base_anchor.is_some() || other.diff_base_anchor.is_some() {
73 if let Some(diff_base) = snapshot.diffs.get(&excerpt.buffer_id) {
74 let self_anchor = self
75 .diff_base_anchor
76 .filter(|a| diff_base.base_text.can_resolve(a));
77 let other_anchor = other
78 .diff_base_anchor
79 .filter(|a| diff_base.base_text.can_resolve(a));
80 return match (self_anchor, other_anchor) {
81 (Some(a), Some(b)) => a.cmp(&b, &diff_base.base_text),
82 (Some(_), None) => match other.text_anchor.bias {
83 Bias::Left => Ordering::Greater,
84 Bias::Right => Ordering::Less,
85 },
86 (None, Some(_)) => match self.text_anchor.bias {
87 Bias::Left => Ordering::Less,
88 Bias::Right => Ordering::Greater,
89 },
90 (None, None) => Ordering::Equal,
91 };
92 }
93 }
94 }
95 Ordering::Equal
96 }
97
98 pub fn bias(&self) -> Bias {
99 self.text_anchor.bias
100 }
101
102 pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
103 if self.text_anchor.bias != Bias::Left {
104 if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
105 return Self {
106 buffer_id: self.buffer_id,
107 excerpt_id: self.excerpt_id,
108 text_anchor: self.text_anchor.bias_left(&excerpt.buffer),
109 diff_base_anchor: self.diff_base_anchor.map(|a| {
110 if let Some(base) = snapshot.diffs.get(&excerpt.buffer_id) {
111 if a.buffer_id == Some(base.base_text.remote_id()) {
112 return a.bias_left(&base.base_text);
113 }
114 }
115 a
116 }),
117 };
118 }
119 }
120 *self
121 }
122
123 pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
124 if self.text_anchor.bias != Bias::Right {
125 if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
126 return Self {
127 buffer_id: self.buffer_id,
128 excerpt_id: self.excerpt_id,
129 text_anchor: self.text_anchor.bias_right(&excerpt.buffer),
130 diff_base_anchor: self.diff_base_anchor.map(|a| {
131 if let Some(base) = snapshot.diffs.get(&excerpt.buffer_id) {
132 if a.buffer_id == Some(base.base_text.remote_id()) {
133 return a.bias_right(&base.base_text);
134 }
135 }
136 a
137 }),
138 };
139 }
140 }
141 *self
142 }
143
144 pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
145 where
146 D: TextDimension + Ord + Sub<D, Output = D>,
147 {
148 snapshot.summary_for_anchor(self)
149 }
150
151 pub fn is_valid(&self, snapshot: &MultiBufferSnapshot) -> bool {
152 if *self == Anchor::min() || *self == Anchor::max() {
153 true
154 } else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
155 excerpt.contains(self)
156 && (self.text_anchor == excerpt.range.context.start
157 || self.text_anchor == excerpt.range.context.end
158 || self.text_anchor.is_valid(&excerpt.buffer))
159 } else {
160 false
161 }
162 }
163}
164
165impl ToOffset for Anchor {
166 fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize {
167 self.summary(snapshot)
168 }
169}
170
171impl ToOffsetUtf16 for Anchor {
172 fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
173 self.summary(snapshot)
174 }
175}
176
177impl ToPoint for Anchor {
178 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
179 self.summary(snapshot)
180 }
181}
182
183pub trait AnchorRangeExt {
184 fn cmp(&self, b: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering;
185 fn overlaps(&self, b: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool;
186 fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
187 fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
188}
189
190impl AnchorRangeExt for Range<Anchor> {
191 fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering {
192 match self.start.cmp(&other.start, buffer) {
193 Ordering::Equal => other.end.cmp(&self.end, buffer),
194 ord => ord,
195 }
196 }
197
198 fn overlaps(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool {
199 self.end.cmp(&other.start, buffer).is_ge() && self.start.cmp(&other.end, buffer).is_le()
200 }
201
202 fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
203 self.start.to_offset(content)..self.end.to_offset(content)
204 }
205
206 fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point> {
207 self.start.to_point(content)..self.end.to_point(content)
208 }
209}
210
211#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash, Ord, PartialOrd)]
212pub struct Offset(pub usize);