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