1use super::{location::*, ExcerptSummary, MultiBufferSnapshot, ToOffset};
2use anyhow::{anyhow, Result};
3use smallvec::SmallVec;
4use std::{cmp::Ordering, ops::Range};
5use sum_tree::Bias;
6use text::{rope::TextDimension, AnchorRangeExt, ToOffset as _};
7
8#[derive(Clone, Eq, PartialEq, Debug, Hash)]
9pub struct Anchor {
10 excerpt_id: ExcerptId,
11 text_anchor: text::Anchor,
12}
13
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct AnchorRangeMap<T> {
16 entries: SmallVec<[(ExcerptId, text::AnchorRangeMap<T>); 1]>,
17}
18
19impl Anchor {
20 pub fn min() -> Self {
21 Self {
22 excerpt_id: ExcerptId::min(),
23 text_anchor: text::Anchor::min(),
24 }
25 }
26
27 pub fn max() -> Self {
28 Self {
29 excerpt_id: ExcerptId::max(),
30 text_anchor: text::Anchor::max(),
31 }
32 }
33
34 pub fn cmp<'a>(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Result<Ordering> {
35 let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id);
36 if excerpt_id_cmp.is_eq() {
37 self.text_anchor.cmp(
38 &other.text_anchor,
39 snapshot
40 .buffer_snapshot_for_excerpt(&self.excerpt_id)
41 .ok_or_else(|| anyhow!("excerpt {:?} not found", self.excerpt_id))?,
42 )
43 } else {
44 return Ok(excerpt_id_cmp);
45 }
46 }
47
48 pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
49 if self.text_anchor.bias != Bias::Left {
50 if let Some(buffer_snapshot) = snapshot.buffer_snapshot_for_excerpt(&self.excerpt_id) {
51 return Self {
52 excerpt_id: self.excerpt_id.clone(),
53 text_anchor: self.text_anchor.bias_left(buffer_snapshot),
54 };
55 }
56 }
57 self.clone()
58 }
59
60 pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
61 if self.text_anchor.bias != Bias::Right {
62 if let Some(buffer_snapshot) = snapshot.buffer_snapshot_for_excerpt(&self.excerpt_id) {
63 return Self {
64 excerpt_id: self.excerpt_id.clone(),
65 text_anchor: self.text_anchor.bias_right(buffer_snapshot),
66 };
67 }
68 }
69 self.clone()
70 }
71}
72
73impl<T> AnchorRangeMap<T> {
74 pub fn len(&self) -> usize {
75 self.entries
76 .iter()
77 .map(|(_, text_map)| text_map.len())
78 .sum()
79 }
80
81 pub fn ranges<'a, D>(
82 &'a self,
83 snapshot: &'a MultiBufferSnapshot,
84 ) -> impl Iterator<Item = (Range<D>, &'a T)> + 'a
85 where
86 D: TextDimension + Clone,
87 {
88 let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>();
89 self.entries
90 .iter()
91 .filter_map(move |(excerpt_id, text_map)| {
92 cursor.seek_forward(excerpt_id, Bias::Left, &());
93 if let Some(excerpt) = cursor.item() {
94 if excerpt.id == *excerpt_id {
95 let mut excerpt_start = D::from_text_summary(&cursor.start().text);
96 excerpt_start.add_summary(&excerpt.header_summary(), &());
97 return Some(text_map.ranges::<D>(&excerpt.buffer).map(
98 move |(range, value)| {
99 let mut full_range = excerpt_start.clone()..excerpt_start.clone();
100 full_range.start.add_assign(&range.start);
101 full_range.end.add_assign(&range.end);
102 (full_range, value)
103 },
104 ));
105 }
106 }
107 None
108 })
109 .flatten()
110 }
111
112 pub fn intersecting_ranges<'a, D, I>(
113 &'a self,
114 range: Range<(I, Bias)>,
115 snapshot: &'a MultiBufferSnapshot,
116 ) -> impl Iterator<Item = (Range<D>, &'a T)> + 'a
117 where
118 D: TextDimension,
119 I: ToOffset,
120 {
121 let start_bias = range.start.1;
122 let end_bias = range.end.1;
123 let start_offset = range.start.0.to_offset(snapshot);
124 let end_offset = range.end.0.to_offset(snapshot);
125
126 let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>();
127 cursor.seek(&start_offset, start_bias, &());
128 let start_excerpt_id = &cursor.start().excerpt_id;
129 let start_ix = match self
130 .entries
131 .binary_search_by_key(&start_excerpt_id, |e| &e.0)
132 {
133 Ok(ix) | Err(ix) => ix,
134 };
135
136 let mut entry_ranges = None;
137 let mut entries = self.entries[start_ix..].iter();
138 std::iter::from_fn(move || loop {
139 match &mut entry_ranges {
140 None => {
141 let (excerpt_id, text_map) = entries.next()?;
142 cursor.seek(excerpt_id, Bias::Left, &());
143 if cursor.start().text.bytes >= end_offset {
144 return None;
145 }
146
147 if let Some(excerpt) = cursor.item() {
148 if excerpt.id == *excerpt_id {
149 let mut excerpt_start = D::from_text_summary(&cursor.start().text);
150 excerpt_start.add_summary(&excerpt.header_summary(), &());
151
152 let excerpt_start_offset = cursor.start().text.bytes;
153 let excerpt_end_offset = cursor.end(&()).text.bytes;
154 let excerpt_buffer_range = excerpt.range.to_offset(&excerpt.buffer);
155
156 let start;
157 if start_offset >= excerpt_start_offset {
158 start = (
159 excerpt_buffer_range.start + start_offset
160 - excerpt_start_offset,
161 start_bias,
162 );
163 } else {
164 start = (excerpt_buffer_range.start, Bias::Left);
165 }
166
167 let end;
168 if end_offset <= excerpt_end_offset {
169 end = (
170 excerpt_buffer_range.start + end_offset - excerpt_start_offset,
171 end_bias,
172 );
173 } else {
174 end = (excerpt_buffer_range.end, Bias::Right);
175 }
176
177 entry_ranges = Some(
178 text_map
179 .intersecting_ranges(start..end, &excerpt.buffer)
180 .map(move |(range, value)| {
181 let mut full_range =
182 excerpt_start.clone()..excerpt_start.clone();
183 full_range.start.add_assign(&range.start);
184 full_range.end.add_assign(&range.end);
185 (full_range, value)
186 }),
187 );
188 }
189 }
190 }
191 Some(ranges) => {
192 if let Some(item) = ranges.next() {
193 return Some(item);
194 } else {
195 entry_ranges.take();
196 }
197 }
198 }
199 })
200 }
201
202 pub fn min_by_key<'a, D, F, K>(
203 &self,
204 snapshot: &'a MultiBufferSnapshot,
205 extract_key: F,
206 ) -> Option<(Range<D>, &T)>
207 where
208 D: TextDimension,
209 F: FnMut(&T) -> K,
210 K: Ord,
211 {
212 self.min_or_max_by_key(snapshot, Ordering::Less, extract_key)
213 }
214
215 pub fn max_by_key<'a, D, F, K>(
216 &self,
217 snapshot: &'a MultiBufferSnapshot,
218 extract_key: F,
219 ) -> Option<(Range<D>, &T)>
220 where
221 D: TextDimension,
222 F: FnMut(&T) -> K,
223 K: Ord,
224 {
225 self.min_or_max_by_key(snapshot, Ordering::Greater, extract_key)
226 }
227
228 fn min_or_max_by_key<'a, D, F, K>(
229 &self,
230 snapshot: &'a MultiBufferSnapshot,
231 target_ordering: Ordering,
232 mut extract_key: F,
233 ) -> Option<(Range<D>, &T)>
234 where
235 D: TextDimension,
236 F: FnMut(&T) -> K,
237 K: Ord,
238 {
239 let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>();
240 let mut max = None;
241 for (excerpt_id, text_map) in &self.entries {
242 cursor.seek(excerpt_id, Bias::Left, &());
243 if let Some(excerpt) = cursor.item() {
244 if excerpt.id == *excerpt_id {
245 if let Some((range, value)) =
246 text_map.max_by_key(&excerpt.buffer, &mut extract_key)
247 {
248 if max.as_ref().map_or(true, |(_, max_value)| {
249 extract_key(value).cmp(&extract_key(*max_value)) == target_ordering
250 }) {
251 let mut excerpt_start = D::from_text_summary(&cursor.start().text);
252 excerpt_start.add_summary(&excerpt.header_summary(), &());
253 let mut full_range = excerpt_start.clone()..excerpt_start.clone();
254 full_range.start.add_assign(&range.start);
255 full_range.end.add_assign(&range.end);
256 max = Some((full_range, value));
257 }
258 }
259 }
260 }
261 }
262 max
263 }
264}
265
266impl ToOffset for Anchor {
267 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
268 let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>();
269 cursor.seek(&self.excerpt_id, Bias::Left, &());
270 if let Some(excerpt) = cursor.item() {
271 if excerpt.id == self.excerpt_id {
272 let buffer_offset = self.text_anchor.to_offset(&excerpt.buffer);
273 return cursor.start().text.bytes
274 + excerpt.header_height as usize
275 + buffer_offset.saturating_sub(excerpt.range.start.to_offset(&excerpt.buffer));
276 }
277 }
278 cursor.start().text.bytes
279 }
280}