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 path = snapshot.path_for_anchor(anchor);
215 let Some(buffer) = self.buffer_for_path(&path, cx) else {
216 continue;
217 };
218 let buffer_snapshot = buffer.read(cx).snapshot();
219
220 let mut expanded_ranges = Vec::new();
221 // Move to the first excerpt for this path
222 cursor.seek_forward(&path, Bias::Left);
223 while let Some(anchor) = sorted_anchors.peek().copied()
224 && snapshot.path_for_anchor(anchor) == path
225 {
226 sorted_anchors.next();
227 let Some(target) = snapshot.anchor_seek_target(anchor) else {
228 continue;
229 };
230 // Move to the next excerpt to be expanded, and push unchanged ranges for intervening excerpts
231 expanded_ranges.extend(
232 cursor
233 .slice(&target, Bias::Left)
234 .iter()
235 .map(|excerpt| excerpt.range.clone()),
236 );
237 let Some(excerpt) = cursor.item() else {
238 continue;
239 };
240 if excerpt.path_key != path {
241 continue;
242 }
243 // Expand the range for this excerpt
244 let mut context = excerpt.range.context.to_point(&buffer_snapshot);
245 match direction {
246 ExpandExcerptDirection::Up => {
247 context.start.row = context.start.row.saturating_sub(line_count);
248 context.start.column = 0;
249 }
250 ExpandExcerptDirection::Down => {
251 context.end.row =
252 (context.end.row + line_count).min(excerpt.buffer.max_point().row);
253 context.end.column = excerpt.buffer.line_len(context.end.row);
254 }
255 ExpandExcerptDirection::UpAndDown => {
256 context.start.row = context.start.row.saturating_sub(line_count);
257 context.start.column = 0;
258 context.end.row =
259 (context.end.row + line_count).min(excerpt.buffer.max_point().row);
260 context.end.column = excerpt.buffer.line_len(context.end.row);
261 }
262 }
263 let context = excerpt.buffer.anchor_range_around(context);
264 expanded_ranges.push(ExcerptRange {
265 context,
266 primary: excerpt.range.primary.clone(),
267 });
268 cursor.next();
269 }
270
271 // Add unchanged ranges for this path after the last expanded excerpt
272 while let Some(excerpt) = cursor.item()
273 && excerpt.path_key == path
274 {
275 expanded_ranges.push(excerpt.range.clone());
276 cursor.next();
277 }
278
279 let mut merged_ranges: Vec<ExcerptRange<text::Anchor>> = Vec::new();
280 for range in expanded_ranges {
281 if let Some(last_range) = merged_ranges.last_mut()
282 && last_range
283 .context
284 .end
285 .cmp(&range.context.start, &buffer_snapshot)
286 .is_ge()
287 {
288 last_range.context.end = range.context.end;
289 continue;
290 }
291 merged_ranges.push(range)
292 }
293 self.update_path_excerpts(path.clone(), buffer, &buffer_snapshot, &merged_ranges, cx);
294 }
295 }
296
297 /// Sets excerpts, returns `true` if at least one new excerpt was added.
298 fn set_merged_excerpt_ranges_for_path(
299 &mut self,
300 path: PathKey,
301 buffer: Entity<Buffer>,
302 buffer_snapshot: &BufferSnapshot,
303 new: Vec<ExcerptRange<Point>>,
304 cx: &mut Context<Self>,
305 ) -> bool {
306 let anchor_ranges = new
307 .into_iter()
308 .map(|r| ExcerptRange {
309 context: buffer_snapshot.anchor_range_around(r.context),
310 primary: buffer_snapshot.anchor_range_around(r.primary),
311 })
312 .collect::<Vec<_>>();
313 self.update_path_excerpts(path, buffer, buffer_snapshot, &anchor_ranges, cx)
314 }
315
316 pub fn update_path_excerpts<'a>(
317 &mut self,
318 path_key: PathKey,
319 buffer: Entity<Buffer>,
320 buffer_snapshot: &BufferSnapshot,
321 to_insert: &Vec<ExcerptRange<text::Anchor>>,
322 cx: &mut Context<Self>,
323 ) -> bool {
324 if to_insert.len() == 0 {
325 self.remove_excerpts_for_path(path_key.clone(), cx);
326 if let Some(old_path_key) = self
327 .snapshot(cx)
328 .path_for_buffer(buffer_snapshot.remote_id())
329 && old_path_key != &path_key
330 {
331 self.remove_excerpts_for_path(old_path_key.clone(), cx);
332 }
333
334 return false;
335 }
336 assert_eq!(self.history.transaction_depth(), 0);
337 self.sync_mut(cx);
338
339 let buffer_snapshot = buffer.read(cx).snapshot();
340 let buffer_id = buffer_snapshot.remote_id();
341 let buffer_state = self.buffers.entry(buffer_id).or_insert_with(|| {
342 self.buffer_changed_since_sync.replace(true);
343 buffer.update(cx, |buffer, _| {
344 buffer.record_changes(Rc::downgrade(&self.buffer_changed_since_sync));
345 });
346 BufferState {
347 last_version: RefCell::new(buffer_snapshot.version().clone()),
348 last_non_text_state_update_count: Cell::new(
349 buffer_snapshot.non_text_state_update_count(),
350 ),
351 _subscriptions: [
352 cx.observe(&buffer, |_, _, cx| cx.notify()),
353 cx.subscribe(&buffer, Self::on_buffer_event),
354 ],
355 buffer: buffer.clone(),
356 }
357 });
358
359 let mut snapshot = self.snapshot.get_mut();
360 let mut cursor = snapshot
361 .excerpts
362 .cursor::<Dimensions<PathKey, ExcerptOffset>>(());
363 let mut new_excerpts = SumTree::new(());
364
365 let mut to_insert = to_insert.iter().peekable();
366 let mut patch = Patch::empty();
367 let mut added_new_excerpt = false;
368
369 let path_key_index = snapshot
370 .path_keys_by_index
371 .iter()
372 // todo!() perf? (but ExcerptIdMapping was doing this)
373 .find(|(_, existing_path)| existing_path == &&path_key)
374 .map(|(index, _)| *index);
375 let path_key_index = path_key_index.unwrap_or_else(|| {
376 let index = snapshot
377 .path_keys_by_index
378 .last()
379 .map(|(index, _)| PathKeyIndex(index.0 + 1))
380 .unwrap_or(PathKeyIndex(0));
381 snapshot.path_keys_by_index.insert(index, path_key.clone());
382 index
383 });
384 let old_path_key = snapshot
385 .path_keys_by_buffer
386 .insert_or_replace(buffer_id, path_key.clone());
387 // handle the case where the buffer's path key has changed by
388 // removing any old excerpts for the buffer
389 if let Some(old_path_key) = &old_path_key
390 && old_path_key < &path_key
391 {
392 new_excerpts.append(cursor.slice(old_path_key, Bias::Left), ());
393 let before = cursor.position.1;
394 cursor.seek_forward(old_path_key, Bias::Right);
395 let after = cursor.position.1;
396 patch.push(Edit {
397 old: before..after,
398 new: new_excerpts.summary().len()..new_excerpts.summary().len(),
399 });
400 }
401
402 new_excerpts.append(cursor.slice(&path_key, Bias::Left), ());
403
404 // handle the case where the path key used to be associated
405 // with a different buffer by removing its excerpts.
406 if let Some(excerpt) = cursor.item()
407 && excerpt.path_key == path_key
408 && excerpt.buffer.remote_id() != buffer_id
409 {
410 let before = cursor.position.1;
411 cursor.seek_forward(&path_key, Bias::Right);
412 let after = cursor.position.1;
413 patch.push(Edit {
414 old: before..after,
415 new: new_excerpts.summary().len()..new_excerpts.summary().len(),
416 });
417 }
418
419 let buffer_snapshot = Arc::new(buffer_snapshot);
420 while let Some(excerpt) = cursor.item()
421 && excerpt.path_key == path_key
422 {
423 assert_eq!(excerpt.buffer.remote_id(), buffer_id);
424 let Some(next_excerpt) = to_insert.peek() else {
425 break;
426 };
427 if &&excerpt.range == next_excerpt {
428 new_excerpts.push(excerpt.clone(), ());
429 to_insert.next();
430 cursor.next();
431 continue;
432 }
433
434 if excerpt
435 .range
436 .context
437 .start
438 .cmp(&next_excerpt.context.start, &buffer_snapshot)
439 .is_le()
440 {
441 // remove old excerpt
442 let before = cursor.position.1;
443 cursor.next();
444 let after = cursor.position.1;
445 patch.push(Edit {
446 old: before..after,
447 new: new_excerpts.summary().len()..new_excerpts.summary().len(),
448 });
449 } else {
450 // insert new excerpt
451 let next_excerpt = to_insert.next().unwrap();
452 added_new_excerpt = true;
453 let before = new_excerpts.summary().len();
454 new_excerpts.push(
455 Excerpt::new(
456 path_key.clone(),
457 buffer_snapshot.clone(),
458 next_excerpt.clone(),
459 to_insert.peek().is_some(),
460 ),
461 (),
462 );
463 let after = new_excerpts.summary().len();
464 patch.push(Edit {
465 old: cursor.position.1..cursor.position.1,
466 new: before..after,
467 });
468 }
469 }
470
471 // remove any further trailing excerpts
472 let before = cursor.position.1;
473 cursor.seek_forward(&path_key, Bias::Right);
474 let after = cursor.position.1;
475 patch.push(Edit {
476 old: before..after,
477 new: new_excerpts.summary().len()..new_excerpts.summary().len(),
478 });
479
480 // handle the case where the buffer's path key has changed by
481 // removing any old excerpts for the buffer
482 if let Some(old_path_key) = &old_path_key
483 && old_path_key > &path_key
484 {
485 new_excerpts.append(cursor.slice(old_path_key, Bias::Left), ());
486 let before = cursor.position.1;
487 cursor.seek_forward(old_path_key, Bias::Right);
488 let after = cursor.position.1;
489 patch.push(Edit {
490 old: before..after,
491 new: new_excerpts.summary().len()..new_excerpts.summary().len(),
492 });
493 }
494
495 let suffix = cursor.suffix();
496 let changed_trailing_excerpt = suffix.is_empty();
497 new_excerpts.append(suffix, ());
498 let new_ranges = snapshot
499 .excerpt_ranges_for_path(&path_key)
500 .map(|range| range.context)
501 .collect();
502 drop(cursor);
503 snapshot.excerpts = new_excerpts;
504 if changed_trailing_excerpt {
505 snapshot.trailing_excerpt_update_count += 1;
506 }
507
508 let edits = Self::sync_diff_transforms(
509 &mut snapshot,
510 patch.into_inner(),
511 DiffChangeKind::BufferEdited,
512 );
513 if !edits.is_empty() {
514 self.subscriptions.publish(edits);
515 }
516
517 cx.emit(Event::Edited {
518 edited_buffer: None,
519 });
520 cx.emit(Event::BufferUpdated {
521 buffer,
522 path_key: path_key.clone(),
523 ranges: new_ranges,
524 });
525 cx.notify();
526
527 added_new_excerpt
528 }
529
530 pub fn remove_excerpts_for_path(&mut self, path: PathKey, cx: &mut Context<Self>) {
531 let mut patch = Patch::empty();
532
533 let mut snapshot = self.snapshot.get_mut();
534 let mut cursor = snapshot
535 .excerpts
536 .cursor::<Dimensions<PathKey, ExcerptOffset>>(());
537 let mut new_excerpts = SumTree::new(());
538
539 if let Some(old_path_key) = old_path_key
540 && old_path_key < path_key
541 {
542 new_excerpts.append(cursor.slice(&old_path_key, Bias::Left), ());
543 let before = cursor.position.1;
544 cursor.seek_forward(&old_path_key, Bias::Right);
545 let after = cursor.position.1;
546 patch.push(Edit {
547 old: before..after,
548 new: new_excerpts.summary().len()..new_excerpts.summary().len(),
549 });
550 }
551
552 let suffix = cursor.suffix();
553 let changed_trailing_excerpt = suffix.is_empty();
554 new_excerpts.append(suffix, ());
555
556 for buffer_id in removed_excerpts_for_buffers {
557 match self.buffers.get(&buffer_id) {
558 Some(buffer_state) => {
559 snapshot
560 .buffer_locators
561 .insert(buffer_id, buffer_state.excerpts.iter().cloned().collect());
562 }
563 None => {
564 snapshot.buffer_locators.remove(&buffer_id);
565 }
566 }
567 }
568 snapshot.excerpts = new_excerpts;
569 if changed_trailing_excerpt {
570 snapshot.trailing_excerpt_update_count += 1;
571 }
572
573 let edits = Self::sync_diff_transforms(
574 &mut snapshot,
575 patch.into_inner(),
576 DiffChangeKind::BufferEdited,
577 );
578 if !edits.is_empty() {
579 self.subscriptions.publish(edits);
580 }
581
582 cx.emit(Event::Edited {
583 edited_buffer: None,
584 });
585 // todo!() is this right? different event?
586 cx.emit(Event::BufferUpdated {
587 buffer,
588 path_key: path.clone(),
589 ranges: Vec::new(),
590 });
591 cx.notify();
592 }
593}