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