1use std::{
2 cell::{Cell, RefCell},
3 ops::Range,
4 rc::Rc,
5 sync::Arc,
6};
7
8use collections::HashSet;
9use gpui::{App, AppContext, Context, Entity};
10use itertools::Itertools;
11use language::{Buffer, BufferSnapshot};
12use rope::Point;
13use sum_tree::{Dimensions, SumTree};
14use text::{Bias, BufferId, Edit, OffsetRangeExt, Patch};
15use util::rel_path::RelPath;
16use ztracing::instrument;
17
18use crate::{
19 Anchor, BufferState, DiffChangeKind, Event, Excerpt, ExcerptOffset, ExcerptRange,
20 ExcerptSummary, ExpandExcerptDirection, MultiBuffer, MultiBufferOffset, PathKeyIndex,
21 build_excerpt_ranges,
22};
23
24#[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Hash, Debug)]
25pub struct PathKey {
26 // Used by the derived PartialOrd & Ord
27 pub sort_prefix: Option<u64>,
28 pub path: Arc<RelPath>,
29}
30
31impl PathKey {
32 pub fn min() -> Self {
33 Self {
34 sort_prefix: None,
35 path: RelPath::empty().into_arc(),
36 }
37 }
38
39 pub fn max() -> Self {
40 Self {
41 sort_prefix: Some(u64::MAX),
42 path: RelPath::empty().into_arc(),
43 }
44 }
45
46 pub fn sorted(sort_prefix: u64) -> Self {
47 Self {
48 sort_prefix: Some(sort_prefix),
49 path: RelPath::empty().into_arc(),
50 }
51 }
52 pub fn with_sort_prefix(sort_prefix: u64, path: Arc<RelPath>) -> Self {
53 Self {
54 sort_prefix: Some(sort_prefix),
55 path,
56 }
57 }
58
59 pub fn for_buffer(buffer: &Entity<Buffer>, cx: &App) -> Self {
60 if let Some(file) = buffer.read(cx).file() {
61 Self::with_sort_prefix(file.worktree_id(cx).to_proto(), file.path().clone())
62 } else {
63 Self {
64 sort_prefix: None,
65 path: RelPath::unix(&buffer.entity_id().to_string())
66 .unwrap()
67 .into_arc(),
68 }
69 }
70 }
71}
72
73impl MultiBuffer {
74 pub fn paths(&self) -> impl Iterator<Item = &PathKey> + '_ {
75 self.excerpts_by_path.keys()
76 }
77
78 pub fn excerpts_for_path(&self, path: &PathKey) -> impl '_ + Iterator<Item = ExcerptId> {
79 self.excerpts_by_path
80 .get(path)
81 .map(|excerpts| excerpts.as_slice())
82 .unwrap_or_default()
83 .iter()
84 .copied()
85 }
86
87 pub fn buffer_for_path(&self, path: &PathKey, cx: &App) -> Option<Entity<Buffer>> {
88 let excerpt_id = self.excerpts_by_path.get(path)?.first()?;
89 let snapshot = self.read(cx);
90 let excerpt = snapshot.excerpt(*excerpt_id)?;
91 self.buffer(excerpt.buffer_id)
92 }
93
94 pub fn location_for_path(&self, path: &PathKey, cx: &App) -> Option<Anchor> {
95 let excerpt_id = self.excerpts_by_path.get(path)?.first()?;
96 let snapshot = self.read(cx);
97 let excerpt = snapshot.excerpt(*excerpt_id)?;
98 Some(Anchor::text(excerpt.id, excerpt.range.context.start))
99 }
100
101 pub fn set_excerpts_for_buffer(
102 &mut self,
103 buffer: Entity<Buffer>,
104 ranges: impl IntoIterator<Item = Range<Point>>,
105 context_line_count: u32,
106 cx: &mut Context<Self>,
107 ) -> (Vec<Range<Anchor>>, bool) {
108 let path = PathKey::for_buffer(&buffer, cx);
109 self.set_excerpts_for_path(path, buffer, ranges, context_line_count, cx)
110 }
111
112 /// Sets excerpts, returns `true` if at least one new excerpt was added.
113 #[instrument(skip_all)]
114 pub fn set_excerpts_for_path(
115 &mut self,
116 path: PathKey,
117 buffer: Entity<Buffer>,
118 ranges: impl IntoIterator<Item = Range<Point>>,
119 context_line_count: u32,
120 cx: &mut Context<Self>,
121 ) -> (Vec<Range<Anchor>>, bool) {
122 let buffer_snapshot = buffer.read(cx).snapshot();
123 let ranges: Vec<_> = ranges.into_iter().collect();
124 let excerpt_ranges =
125 build_excerpt_ranges(ranges.clone(), context_line_count, &buffer_snapshot);
126
127 let (new, _) = Self::merge_excerpt_ranges(&excerpt_ranges);
128 let inserted =
129 self.set_merged_excerpt_ranges_for_path(path, buffer, &buffer_snapshot, new, cx);
130 // todo!() move this into the callers that care
131 let anchors = ranges
132 .into_iter()
133 .map(|range| Anchor::range_in_buffer(buffer_snapshot.anchor_range_around(range)))
134 .collect::<Vec<_>>();
135 (anchors, inserted)
136 }
137
138 pub fn set_excerpt_ranges_for_path(
139 &mut self,
140 path: PathKey,
141 buffer: Entity<Buffer>,
142 buffer_snapshot: &BufferSnapshot,
143 excerpt_ranges: Vec<ExcerptRange<Point>>,
144 cx: &mut Context<Self>,
145 ) -> (Vec<Range<Anchor>>, bool) {
146 let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges);
147 let inserted =
148 self.set_merged_excerpt_ranges_for_path(path, buffer, buffer_snapshot, new, cx);
149 // todo!() move this into the callers that care
150 let anchors = excerpt_ranges
151 .into_iter()
152 .map(|range| {
153 Anchor::range_in_buffer(buffer_snapshot.anchor_range_around(range.primary))
154 })
155 .collect::<Vec<_>>();
156 (anchors, inserted)
157 }
158
159 pub fn set_anchored_excerpts_for_path(
160 &self,
161 path_key: PathKey,
162 buffer: Entity<Buffer>,
163 ranges: Vec<Range<text::Anchor>>,
164 context_line_count: u32,
165 cx: &Context<Self>,
166 ) -> impl Future<Output = Vec<Range<Anchor>>> + use<> {
167 let buffer_snapshot = buffer.read(cx).snapshot();
168 let multi_buffer = cx.weak_entity();
169 let mut app = cx.to_async();
170 async move {
171 let snapshot = buffer_snapshot.clone();
172 let (ranges, merged_excerpt_ranges) = app
173 .background_spawn(async move {
174 let point_ranges = ranges.iter().map(|range| range.to_point(&snapshot));
175 let excerpt_ranges =
176 build_excerpt_ranges(point_ranges, context_line_count, &snapshot);
177 let (new, _) = Self::merge_excerpt_ranges(&excerpt_ranges);
178 (ranges, new)
179 })
180 .await;
181
182 multi_buffer
183 .update(&mut app, move |multi_buffer, cx| {
184 multi_buffer.set_merged_excerpt_ranges_for_path(
185 path_key,
186 buffer,
187 &buffer_snapshot,
188 merged_excerpt_ranges,
189 cx,
190 );
191 ranges
192 .into_iter()
193 .map(|range| Anchor::range_in_buffer(range))
194 .collect()
195 })
196 .ok()
197 .unwrap_or_default()
198 }
199 }
200
201 pub(super) fn expand_excerpts_with_paths(
202 &mut self,
203 anchors: impl IntoIterator<Item = Anchor>,
204 line_count: u32,
205 direction: ExpandExcerptDirection,
206 cx: &mut Context<Self>,
207 ) {
208 let snapshot = self.snapshot(cx);
209 let mut sorted_anchors = anchors.into_iter().collect::<Vec<_>>();
210 sorted_anchors.sort_by(|a, b| a.cmp(b, &snapshot));
211 let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>(());
212 let mut sorted_anchors = sorted_anchors.into_iter().peekable();
213 while let Some(anchor) = sorted_anchors.next() {
214 let Some(path) = snapshot.path_for_anchor(anchor) else {
215 continue;
216 };
217 let Some(buffer) = self.buffer_for_path(&path, cx) else {
218 continue;
219 };
220 let buffer_snapshot = buffer.read(cx).snapshot();
221
222 let mut expanded_ranges = Vec::new();
223 // Move to the first excerpt for this path
224 cursor.seek_forward(&path, Bias::Left);
225 while let Some(anchor) = sorted_anchors.peek().copied()
226 && snapshot.path_for_anchor(anchor).as_ref() == Some(&path)
227 {
228 sorted_anchors.next();
229 let Some(target) = snapshot.anchor_seek_target(anchor) else {
230 continue;
231 };
232 // Move to the next excerpt to be expanded, and push unchanged ranges for intervening excerpts
233 expanded_ranges.extend(
234 cursor
235 .slice(&target, Bias::Left)
236 .iter()
237 .map(|excerpt| excerpt.range.clone()),
238 );
239 let Some(excerpt) = cursor.item() else {
240 continue;
241 };
242 if excerpt.path_key != path {
243 continue;
244 }
245 // Expand the range for this excerpt
246 let mut context = excerpt.range.context.to_point(&buffer_snapshot);
247 match direction {
248 ExpandExcerptDirection::Up => {
249 context.start.row = context.start.row.saturating_sub(line_count);
250 context.start.column = 0;
251 }
252 ExpandExcerptDirection::Down => {
253 context.end.row =
254 (context.end.row + line_count).min(excerpt.buffer.max_point().row);
255 context.end.column = excerpt.buffer.line_len(context.end.row);
256 }
257 ExpandExcerptDirection::UpAndDown => {
258 context.start.row = context.start.row.saturating_sub(line_count);
259 context.start.column = 0;
260 context.end.row =
261 (context.end.row + line_count).min(excerpt.buffer.max_point().row);
262 context.end.column = excerpt.buffer.line_len(context.end.row);
263 }
264 }
265 let context = excerpt.buffer.anchor_range_around(context);
266 expanded_ranges.push(ExcerptRange {
267 context,
268 primary: excerpt.range.primary.clone(),
269 });
270 cursor.next();
271 }
272
273 // Add unchanged ranges for this path after the last expanded excerpt
274 while let Some(excerpt) = cursor.item()
275 && excerpt.path_key == path
276 {
277 expanded_ranges.push(excerpt.range.clone());
278 cursor.next();
279 }
280
281 let mut merged_ranges: Vec<ExcerptRange<text::Anchor>> = Vec::new();
282 for range in expanded_ranges {
283 if let Some(last_range) = merged_ranges.last_mut()
284 && last_range
285 .context
286 .end
287 .cmp(&range.context.start, &buffer_snapshot)
288 .is_ge()
289 {
290 last_range.context.end = range.context.end;
291 continue;
292 }
293 merged_ranges.push(range)
294 }
295 self.update_path_excerpts(path.clone(), buffer, &buffer_snapshot, &merged_ranges, cx);
296 }
297 }
298
299 /// Sets excerpts, returns `true` if at least one new excerpt was added.
300 fn set_merged_excerpt_ranges_for_path(
301 &mut self,
302 path: PathKey,
303 buffer: Entity<Buffer>,
304 buffer_snapshot: &BufferSnapshot,
305 new: Vec<ExcerptRange<Point>>,
306 cx: &mut Context<Self>,
307 ) -> bool {
308 let anchor_ranges = new
309 .into_iter()
310 .map(|r| ExcerptRange {
311 context: buffer_snapshot.anchor_range_around(r.context),
312 primary: buffer_snapshot.anchor_range_around(r.primary),
313 })
314 .collect::<Vec<_>>();
315 self.update_path_excerpts(path, buffer, buffer_snapshot, &anchor_ranges, cx)
316 }
317
318 pub fn update_path_excerpts<'a>(
319 &mut self,
320 path_key: PathKey,
321 buffer: Entity<Buffer>,
322 buffer_snapshot: &BufferSnapshot,
323 to_insert: &Vec<ExcerptRange<text::Anchor>>,
324 cx: &mut Context<Self>,
325 ) -> bool {
326 if to_insert.len() == 0 {
327 self.remove_excerpts_for_path(path_key.clone(), cx);
328 if let Some(old_path_key) = self
329 .snapshot(cx)
330 .path_for_buffer(buffer_snapshot.remote_id())
331 && old_path_key != &path_key
332 {
333 self.remove_excerpts_for_path(old_path_key.clone(), cx);
334 }
335
336 return false;
337 }
338 assert_eq!(self.history.transaction_depth(), 0);
339 self.sync_mut(cx);
340
341 let buffer_snapshot = buffer.read(cx).snapshot();
342 let buffer_id = buffer_snapshot.remote_id();
343 let buffer_state = self.buffers.entry(buffer_id).or_insert_with(|| {
344 self.buffer_changed_since_sync.replace(true);
345 buffer.update(cx, |buffer, _| {
346 buffer.record_changes(Rc::downgrade(&self.buffer_changed_since_sync));
347 });
348 BufferState {
349 last_version: RefCell::new(buffer_snapshot.version().clone()),
350 last_non_text_state_update_count: Cell::new(
351 buffer_snapshot.non_text_state_update_count(),
352 ),
353 _subscriptions: [
354 cx.observe(&buffer, |_, _, cx| cx.notify()),
355 cx.subscribe(&buffer, Self::on_buffer_event),
356 ],
357 buffer: buffer.clone(),
358 }
359 });
360
361 let mut snapshot = self.snapshot.get_mut();
362 let mut cursor = snapshot
363 .excerpts
364 .cursor::<Dimensions<PathKey, ExcerptOffset>>(());
365 let mut new_excerpts = SumTree::new(());
366
367 let mut to_insert = to_insert.iter().peekable();
368 let mut patch = Patch::empty();
369 let mut added_new_excerpt = false;
370
371 let path_key_index = snapshot
372 .path_keys_by_index
373 .iter()
374 // todo!() perf? (but ExcerptIdMapping was doing this)
375 .find(|(_, existing_path)| existing_path == &&path_key)
376 .map(|(index, _)| *index);
377 let path_key_index = path_key_index.unwrap_or_else(|| {
378 let index = snapshot
379 .path_keys_by_index
380 .last()
381 .map(|(index, _)| PathKeyIndex(index.0 + 1))
382 .unwrap_or(PathKeyIndex(0));
383 snapshot.path_keys_by_index.insert(index, path_key.clone());
384 index
385 });
386 let old_path_key = snapshot
387 .path_keys_by_buffer
388 .insert_or_replace(buffer_id, path_key.clone());
389 // handle the case where the buffer's path key has changed by
390 // removing any old excerpts for the buffer
391 if let Some(old_path_key) = &old_path_key
392 && old_path_key < &path_key
393 {
394 new_excerpts.append(cursor.slice(old_path_key, Bias::Left), ());
395 let before = cursor.position.1;
396 cursor.seek_forward(old_path_key, Bias::Right);
397 let after = cursor.position.1;
398 patch.push(Edit {
399 old: before..after,
400 new: new_excerpts.summary().len()..new_excerpts.summary().len(),
401 });
402 }
403
404 new_excerpts.append(cursor.slice(&path_key, Bias::Left), ());
405
406 // handle the case where the path key used to be associated
407 // with a different buffer by removing its excerpts.
408 if let Some(excerpt) = cursor.item()
409 && excerpt.path_key == path_key
410 && excerpt.buffer.remote_id() != buffer_id
411 {
412 let before = cursor.position.1;
413 cursor.seek_forward(&path_key, Bias::Right);
414 let after = cursor.position.1;
415 patch.push(Edit {
416 old: before..after,
417 new: new_excerpts.summary().len()..new_excerpts.summary().len(),
418 });
419 }
420
421 let buffer_snapshot = Arc::new(buffer_snapshot);
422 while let Some(excerpt) = cursor.item()
423 && excerpt.path_key == path_key
424 {
425 assert_eq!(excerpt.buffer.remote_id(), buffer_id);
426 let Some(next_excerpt) = to_insert.peek() else {
427 break;
428 };
429 if &&excerpt.range == next_excerpt {
430 new_excerpts.push(excerpt.clone(), ());
431 to_insert.next();
432 cursor.next();
433 continue;
434 }
435
436 if excerpt
437 .range
438 .context
439 .start
440 .cmp(&next_excerpt.context.start, &buffer_snapshot)
441 .is_le()
442 {
443 // remove old excerpt
444 let before = cursor.position.1;
445 cursor.next();
446 let after = cursor.position.1;
447 patch.push(Edit {
448 old: before..after,
449 new: new_excerpts.summary().len()..new_excerpts.summary().len(),
450 });
451 } else {
452 // insert new excerpt
453 let next_excerpt = to_insert.next().unwrap();
454 added_new_excerpt = true;
455 let before = new_excerpts.summary().len();
456 new_excerpts.push(
457 Excerpt::new(
458 path_key.clone(),
459 buffer_snapshot.clone(),
460 next_excerpt.clone(),
461 to_insert.peek().is_some(),
462 ),
463 (),
464 );
465 let after = new_excerpts.summary().len();
466 patch.push(Edit {
467 old: cursor.position.1..cursor.position.1,
468 new: before..after,
469 });
470 }
471 }
472
473 // remove any further trailing excerpts
474 let before = cursor.position.1;
475 cursor.seek_forward(&path_key, Bias::Right);
476 let after = cursor.position.1;
477 patch.push(Edit {
478 old: before..after,
479 new: new_excerpts.summary().len()..new_excerpts.summary().len(),
480 });
481
482 // handle the case where the buffer's path key has changed by
483 // removing any old excerpts for the buffer
484 if let Some(old_path_key) = &old_path_key
485 && old_path_key > &path_key
486 {
487 new_excerpts.append(cursor.slice(old_path_key, Bias::Left), ());
488 let before = cursor.position.1;
489 cursor.seek_forward(old_path_key, Bias::Right);
490 let after = cursor.position.1;
491 patch.push(Edit {
492 old: before..after,
493 new: new_excerpts.summary().len()..new_excerpts.summary().len(),
494 });
495 }
496
497 let suffix = cursor.suffix();
498 let changed_trailing_excerpt = suffix.is_empty();
499 new_excerpts.append(suffix, ());
500 let new_ranges = snapshot
501 .excerpt_ranges_for_path(&path_key)
502 .map(|range| range.context)
503 .collect();
504 drop(cursor);
505 snapshot.excerpts = new_excerpts;
506 if changed_trailing_excerpt {
507 snapshot.trailing_excerpt_update_count += 1;
508 }
509
510 let edits = Self::sync_diff_transforms(
511 &mut snapshot,
512 patch.into_inner(),
513 DiffChangeKind::BufferEdited,
514 );
515 if !edits.is_empty() {
516 self.subscriptions.publish(edits);
517 }
518
519 cx.emit(Event::Edited {
520 edited_buffer: None,
521 });
522 cx.emit(Event::BufferUpdated {
523 buffer,
524 path_key: path_key.clone(),
525 ranges: new_ranges,
526 });
527 cx.notify();
528
529 added_new_excerpt
530 }
531
532 pub fn remove_excerpts_for_path(&mut self, path: PathKey, cx: &mut Context<Self>) {
533 let mut patch = Patch::empty();
534
535 let mut snapshot = self.snapshot.get_mut();
536 let mut cursor = snapshot
537 .excerpts
538 .cursor::<Dimensions<PathKey, ExcerptOffset>>(());
539 let mut new_excerpts = SumTree::new(());
540
541 if let Some(old_path_key) = old_path_key
542 && old_path_key < path_key
543 {
544 new_excerpts.append(cursor.slice(&old_path_key, Bias::Left), ());
545 let before = cursor.position.1;
546 cursor.seek_forward(&old_path_key, Bias::Right);
547 let after = cursor.position.1;
548 patch.push(Edit {
549 old: before..after,
550 new: new_excerpts.summary().len()..new_excerpts.summary().len(),
551 });
552 }
553
554 let suffix = cursor.suffix();
555 let changed_trailing_excerpt = suffix.is_empty();
556 new_excerpts.append(suffix, ());
557
558 for buffer_id in removed_excerpts_for_buffers {
559 match self.buffers.get(&buffer_id) {
560 Some(buffer_state) => {
561 snapshot
562 .buffer_locators
563 .insert(buffer_id, buffer_state.excerpts.iter().cloned().collect());
564 }
565 None => {
566 snapshot.buffer_locators.remove(&buffer_id);
567 }
568 }
569 }
570 snapshot.excerpts = new_excerpts;
571 if changed_trailing_excerpt {
572 snapshot.trailing_excerpt_update_count += 1;
573 }
574
575 let edits = Self::sync_diff_transforms(
576 &mut snapshot,
577 patch.into_inner(),
578 DiffChangeKind::BufferEdited,
579 );
580 if !edits.is_empty() {
581 self.subscriptions.publish(edits);
582 }
583
584 cx.emit(Event::Edited {
585 edited_buffer: None,
586 });
587 // todo!() is this right? different event?
588 cx.emit(Event::BufferUpdated {
589 buffer,
590 path_key: path.clone(),
591 ranges: Vec::new(),
592 });
593 cx.notify();
594 }
595}