1use std::{mem, ops::Range, sync::Arc};
2
3use collections::HashSet;
4use gpui::{App, AppContext, Context, Entity};
5use itertools::Itertools;
6use language::{Buffer, BufferSnapshot};
7use rope::Point;
8use text::{Bias, OffsetRangeExt, locator::Locator};
9use util::{post_inc, rel_path::RelPath};
10
11use crate::{
12 Anchor, ExcerptId, ExcerptRange, ExpandExcerptDirection, MultiBuffer, build_excerpt_ranges,
13};
14
15#[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Hash, Debug)]
16pub struct PathKey {
17 // Used by the derived PartialOrd & Ord
18 pub sort_prefix: Option<u64>,
19 pub path: Arc<RelPath>,
20}
21
22impl PathKey {
23 pub fn with_sort_prefix(sort_prefix: u64, path: Arc<RelPath>) -> Self {
24 Self {
25 sort_prefix: Some(sort_prefix),
26 path,
27 }
28 }
29
30 pub fn for_buffer(buffer: &Entity<Buffer>, cx: &App) -> Self {
31 if let Some(file) = buffer.read(cx).file() {
32 Self::with_sort_prefix(file.worktree_id(cx).to_proto(), file.path().clone())
33 } else {
34 Self {
35 sort_prefix: None,
36 path: RelPath::unix(&buffer.entity_id().to_string())
37 .unwrap()
38 .into_arc(),
39 }
40 }
41 }
42}
43
44impl MultiBuffer {
45 pub fn paths(&self) -> impl Iterator<Item = PathKey> + '_ {
46 self.excerpts_by_path.keys().cloned()
47 }
48
49 pub fn remove_excerpts_for_path(&mut self, path: PathKey, cx: &mut Context<Self>) {
50 if let Some(to_remove) = self.excerpts_by_path.remove(&path) {
51 self.remove_excerpts(to_remove, cx)
52 }
53 }
54
55 pub fn location_for_path(&self, path: &PathKey, cx: &App) -> Option<Anchor> {
56 let excerpt_id = self.excerpts_by_path.get(path)?.first()?;
57 let snapshot = self.read(cx);
58 let excerpt = snapshot.excerpt(*excerpt_id)?;
59 Some(Anchor::in_buffer(
60 *excerpt_id,
61 excerpt.buffer_id,
62 excerpt.range.context.start,
63 ))
64 }
65
66 pub fn excerpt_paths(&self) -> impl Iterator<Item = &PathKey> {
67 self.excerpts_by_path.keys()
68 }
69
70 /// Sets excerpts, returns `true` if at least one new excerpt was added.
71 pub fn set_excerpts_for_path(
72 &mut self,
73 path: PathKey,
74 buffer: Entity<Buffer>,
75 ranges: impl IntoIterator<Item = Range<Point>>,
76 context_line_count: u32,
77 cx: &mut Context<Self>,
78 ) -> (Vec<Range<Anchor>>, bool) {
79 let buffer_snapshot = buffer.read(cx).snapshot();
80 let excerpt_ranges = build_excerpt_ranges(ranges, context_line_count, &buffer_snapshot);
81
82 let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges);
83 self.set_merged_excerpt_ranges_for_path(
84 path,
85 buffer,
86 excerpt_ranges,
87 &buffer_snapshot,
88 new,
89 counts,
90 cx,
91 )
92 }
93
94 pub fn set_excerpt_ranges_for_path(
95 &mut self,
96 path: PathKey,
97 buffer: Entity<Buffer>,
98 buffer_snapshot: &BufferSnapshot,
99 excerpt_ranges: Vec<ExcerptRange<Point>>,
100 cx: &mut Context<Self>,
101 ) -> (Vec<Range<Anchor>>, bool) {
102 let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges);
103 self.set_merged_excerpt_ranges_for_path(
104 path,
105 buffer,
106 excerpt_ranges,
107 buffer_snapshot,
108 new,
109 counts,
110 cx,
111 )
112 }
113
114 pub fn set_anchored_excerpts_for_path(
115 &self,
116 path_key: PathKey,
117 buffer: Entity<Buffer>,
118 ranges: Vec<Range<text::Anchor>>,
119 context_line_count: u32,
120 cx: &Context<Self>,
121 ) -> impl Future<Output = Vec<Range<Anchor>>> + use<> {
122 let buffer_snapshot = buffer.read(cx).snapshot();
123 let multi_buffer = cx.weak_entity();
124 let mut app = cx.to_async();
125 async move {
126 let snapshot = buffer_snapshot.clone();
127 let (excerpt_ranges, new, counts) = app
128 .background_spawn(async move {
129 let ranges = ranges.into_iter().map(|range| range.to_point(&snapshot));
130 let excerpt_ranges =
131 build_excerpt_ranges(ranges, context_line_count, &snapshot);
132 let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges);
133 (excerpt_ranges, new, counts)
134 })
135 .await;
136
137 multi_buffer
138 .update(&mut app, move |multi_buffer, cx| {
139 let (ranges, _) = multi_buffer.set_merged_excerpt_ranges_for_path(
140 path_key,
141 buffer,
142 excerpt_ranges,
143 &buffer_snapshot,
144 new,
145 counts,
146 cx,
147 );
148 ranges
149 })
150 .ok()
151 .unwrap_or_default()
152 }
153 }
154
155 pub(super) fn expand_excerpts_with_paths(
156 &mut self,
157 ids: impl IntoIterator<Item = ExcerptId>,
158 line_count: u32,
159 direction: ExpandExcerptDirection,
160 cx: &mut Context<Self>,
161 ) {
162 let grouped = ids
163 .into_iter()
164 .chunk_by(|id| self.paths_by_excerpt.get(id).cloned())
165 .into_iter()
166 .flat_map(|(k, v)| Some((k?, v.into_iter().collect::<Vec<_>>())))
167 .collect::<Vec<_>>();
168 let snapshot = self.snapshot(cx);
169
170 for (path, ids) in grouped.into_iter() {
171 let Some(excerpt_ids) = self.excerpts_by_path.get(&path) else {
172 continue;
173 };
174
175 let ids_to_expand = HashSet::from_iter(ids);
176 let expanded_ranges = excerpt_ids.iter().filter_map(|excerpt_id| {
177 let excerpt = snapshot.excerpt(*excerpt_id)?;
178
179 let mut context = excerpt.range.context.to_point(&excerpt.buffer);
180 if ids_to_expand.contains(excerpt_id) {
181 match direction {
182 ExpandExcerptDirection::Up => {
183 context.start.row = context.start.row.saturating_sub(line_count);
184 context.start.column = 0;
185 }
186 ExpandExcerptDirection::Down => {
187 context.end.row =
188 (context.end.row + line_count).min(excerpt.buffer.max_point().row);
189 context.end.column = excerpt.buffer.line_len(context.end.row);
190 }
191 ExpandExcerptDirection::UpAndDown => {
192 context.start.row = context.start.row.saturating_sub(line_count);
193 context.start.column = 0;
194 context.end.row =
195 (context.end.row + line_count).min(excerpt.buffer.max_point().row);
196 context.end.column = excerpt.buffer.line_len(context.end.row);
197 }
198 }
199 }
200
201 Some(ExcerptRange {
202 context,
203 primary: excerpt.range.primary.to_point(&excerpt.buffer),
204 })
205 });
206 let mut merged_ranges: Vec<ExcerptRange<Point>> = Vec::new();
207 for range in expanded_ranges {
208 if let Some(last_range) = merged_ranges.last_mut()
209 && last_range.context.end >= range.context.start
210 {
211 last_range.context.end = range.context.end;
212 continue;
213 }
214 merged_ranges.push(range)
215 }
216 let Some(excerpt_id) = excerpt_ids.first() else {
217 continue;
218 };
219 let Some(buffer_id) = &snapshot.buffer_id_for_excerpt(*excerpt_id) else {
220 continue;
221 };
222
223 let Some(buffer) = self.buffers.get(buffer_id).map(|b| b.buffer.clone()) else {
224 continue;
225 };
226
227 let buffer_snapshot = buffer.read(cx).snapshot();
228 self.update_path_excerpts(path.clone(), buffer, &buffer_snapshot, merged_ranges, cx);
229 }
230 }
231
232 /// Sets excerpts, returns `true` if at least one new excerpt was added.
233 fn set_merged_excerpt_ranges_for_path(
234 &mut self,
235 path: PathKey,
236 buffer: Entity<Buffer>,
237 ranges: Vec<ExcerptRange<Point>>,
238 buffer_snapshot: &BufferSnapshot,
239 new: Vec<ExcerptRange<Point>>,
240 counts: Vec<usize>,
241 cx: &mut Context<Self>,
242 ) -> (Vec<Range<Anchor>>, bool) {
243 let (excerpt_ids, added_a_new_excerpt) =
244 self.update_path_excerpts(path, buffer, buffer_snapshot, new, cx);
245
246 let mut result = Vec::new();
247 let mut ranges = ranges.into_iter();
248 for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(counts.into_iter()) {
249 for range in ranges.by_ref().take(range_count) {
250 let range = Anchor::range_in_buffer(
251 excerpt_id,
252 buffer_snapshot.remote_id(),
253 buffer_snapshot.anchor_before(&range.primary.start)
254 ..buffer_snapshot.anchor_after(&range.primary.end),
255 );
256 result.push(range)
257 }
258 }
259 (result, added_a_new_excerpt)
260 }
261
262 fn update_path_excerpts(
263 &mut self,
264 path: PathKey,
265 buffer: Entity<Buffer>,
266 buffer_snapshot: &BufferSnapshot,
267 new: Vec<ExcerptRange<Point>>,
268 cx: &mut Context<Self>,
269 ) -> (Vec<ExcerptId>, bool) {
270 let mut insert_after = self
271 .excerpts_by_path
272 .range(..path.clone())
273 .next_back()
274 .map(|(_, value)| *value.last().unwrap())
275 .unwrap_or(ExcerptId::min());
276
277 let existing = self
278 .excerpts_by_path
279 .get(&path)
280 .cloned()
281 .unwrap_or_default();
282
283 let mut new_iter = new.into_iter().peekable();
284 let mut existing_iter = existing.into_iter().peekable();
285
286 let mut excerpt_ids = Vec::new();
287 let mut to_remove = Vec::new();
288 let mut to_insert: Vec<(ExcerptId, ExcerptRange<Point>)> = Vec::new();
289 let mut added_a_new_excerpt = false;
290 let snapshot = self.snapshot(cx);
291
292 let mut next_excerpt_id =
293 if let Some(last_entry) = self.snapshot.borrow().excerpt_ids.last() {
294 last_entry.id.0 + 1
295 } else {
296 1
297 };
298
299 let mut next_excerpt_id = move || ExcerptId(post_inc(&mut next_excerpt_id));
300
301 let mut excerpts_cursor = snapshot.excerpts.cursor::<Option<&Locator>>(());
302 excerpts_cursor.next();
303
304 loop {
305 let new = new_iter.peek();
306 let existing = if let Some(existing_id) = existing_iter.peek() {
307 let locator = snapshot.excerpt_locator_for_id(*existing_id);
308 excerpts_cursor.seek_forward(&Some(locator), Bias::Left);
309 if let Some(excerpt) = excerpts_cursor.item() {
310 if excerpt.buffer_id != buffer_snapshot.remote_id() {
311 to_remove.push(*existing_id);
312 existing_iter.next();
313 continue;
314 }
315 Some((
316 *existing_id,
317 excerpt.range.context.to_point(buffer_snapshot),
318 ))
319 } else {
320 None
321 }
322 } else {
323 None
324 };
325
326 if let Some((last_id, last)) = to_insert.last_mut() {
327 if let Some(new) = new
328 && last.context.end >= new.context.start
329 {
330 last.context.end = last.context.end.max(new.context.end);
331 excerpt_ids.push(*last_id);
332 new_iter.next();
333 continue;
334 }
335 if let Some((existing_id, existing_range)) = &existing
336 && last.context.end >= existing_range.start
337 {
338 last.context.end = last.context.end.max(existing_range.end);
339 to_remove.push(*existing_id);
340 self.snapshot
341 .get_mut()
342 .replaced_excerpts
343 .insert(*existing_id, *last_id);
344 existing_iter.next();
345 continue;
346 }
347 }
348
349 match (new, existing) {
350 (None, None) => break,
351 (None, Some((existing_id, _))) => {
352 existing_iter.next();
353 to_remove.push(existing_id);
354 continue;
355 }
356 (Some(_), None) => {
357 added_a_new_excerpt = true;
358 let new_id = next_excerpt_id();
359 excerpt_ids.push(new_id);
360 to_insert.push((new_id, new_iter.next().unwrap()));
361 continue;
362 }
363 (Some(new), Some((_, existing_range))) => {
364 if existing_range.end < new.context.start {
365 let existing_id = existing_iter.next().unwrap();
366 to_remove.push(existing_id);
367 continue;
368 } else if existing_range.start > new.context.end {
369 let new_id = next_excerpt_id();
370 excerpt_ids.push(new_id);
371 to_insert.push((new_id, new_iter.next().unwrap()));
372 continue;
373 }
374
375 if existing_range.start == new.context.start
376 && existing_range.end == new.context.end
377 {
378 self.insert_excerpts_with_ids_after(
379 insert_after,
380 buffer.clone(),
381 mem::take(&mut to_insert),
382 cx,
383 );
384 insert_after = existing_iter.next().unwrap();
385 excerpt_ids.push(insert_after);
386 new_iter.next();
387 } else {
388 let existing_id = existing_iter.next().unwrap();
389 let new_id = next_excerpt_id();
390 self.snapshot
391 .get_mut()
392 .replaced_excerpts
393 .insert(existing_id, new_id);
394 to_remove.push(existing_id);
395 let mut range = new_iter.next().unwrap();
396 range.context.start = range.context.start.min(existing_range.start);
397 range.context.end = range.context.end.max(existing_range.end);
398 excerpt_ids.push(new_id);
399 to_insert.push((new_id, range));
400 }
401 }
402 };
403 }
404
405 self.insert_excerpts_with_ids_after(insert_after, buffer, to_insert, cx);
406 self.remove_excerpts(to_remove, cx);
407 if excerpt_ids.is_empty() {
408 self.excerpts_by_path.remove(&path);
409 } else {
410 for excerpt_id in &excerpt_ids {
411 self.paths_by_excerpt.insert(*excerpt_id, path.clone());
412 }
413 self.excerpts_by_path
414 .insert(path, excerpt_ids.iter().dedup().cloned().collect());
415 }
416
417 (excerpt_ids, added_a_new_excerpt)
418 }
419}