1mod anchor;
2#[cfg(test)]
3mod multi_buffer_tests;
4mod position;
5
6pub use anchor::{Anchor, AnchorRangeExt, Offset};
7pub use position::{TypedOffset, TypedPoint, TypedRow};
8
9use anyhow::{anyhow, Result};
10use clock::ReplicaId;
11use collections::{BTreeMap, Bound, HashMap, HashSet};
12use futures::{channel::mpsc, SinkExt};
13use git::diff::DiffHunkStatus;
14use gpui::{App, Context, Entity, EntityId, EventEmitter, Task};
15use itertools::Itertools;
16use language::{
17 language_settings::{language_settings, IndentGuideSettings, LanguageSettings},
18 AutoindentMode, Buffer, BufferChunks, BufferRow, BufferSnapshot, Capability, CharClassifier,
19 CharKind, Chunk, CursorShape, DiagnosticEntry, DiskState, File, IndentSize, Language,
20 LanguageScope, OffsetRangeExt, OffsetUtf16, Outline, OutlineItem, Point, PointUtf16, Selection,
21 TextDimension, TextObject, ToOffset as _, ToPoint as _, TransactionId, TreeSitterOptions,
22 Unclipped,
23};
24use project::buffer_store::{BufferChangeSet, BufferChangeSetEvent};
25use rope::DimensionPair;
26use smallvec::SmallVec;
27use smol::future::yield_now;
28use std::{
29 any::type_name,
30 borrow::Cow,
31 cell::{Ref, RefCell},
32 cmp, fmt,
33 future::Future,
34 io,
35 iter::{self, FromIterator},
36 mem,
37 ops::{Range, RangeBounds, Sub},
38 path::Path,
39 str,
40 sync::Arc,
41 time::{Duration, Instant},
42};
43use sum_tree::{Bias, Cursor, SumTree, TreeMap};
44use text::{
45 locator::Locator,
46 subscription::{Subscription, Topic},
47 BufferId, Edit, LineIndent, TextSummary,
48};
49use theme::SyntaxTheme;
50use util::post_inc;
51
52#[cfg(any(test, feature = "test-support"))]
53use gpui::AppContext as _;
54
55const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];
56
57#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
58pub struct ExcerptId(usize);
59
60/// One or more [`Buffers`](Buffer) being edited in a single view.
61///
62/// See <https://zed.dev/features#multi-buffers>
63pub struct MultiBuffer {
64 /// A snapshot of the [`Excerpt`]s in the MultiBuffer.
65 /// Use [`MultiBuffer::snapshot`] to get a up-to-date snapshot.
66 snapshot: RefCell<MultiBufferSnapshot>,
67 /// Contains the state of the buffers being edited
68 buffers: RefCell<HashMap<BufferId, BufferState>>,
69 // only used by consumers using `set_excerpts_for_buffer`
70 buffers_by_path: BTreeMap<PathKey, Vec<ExcerptId>>,
71 diff_bases: HashMap<BufferId, ChangeSetState>,
72 all_diff_hunks_expanded: bool,
73 subscriptions: Topic,
74 /// If true, the multi-buffer only contains a single [`Buffer`] and a single [`Excerpt`]
75 singleton: bool,
76 history: History,
77 title: Option<String>,
78 capability: Capability,
79}
80
81#[derive(Clone, Debug, PartialEq, Eq)]
82pub enum Event {
83 ExcerptsAdded {
84 buffer: Entity<Buffer>,
85 predecessor: ExcerptId,
86 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
87 },
88 ExcerptsRemoved {
89 ids: Vec<ExcerptId>,
90 },
91 ExcerptsExpanded {
92 ids: Vec<ExcerptId>,
93 },
94 ExcerptsEdited {
95 ids: Vec<ExcerptId>,
96 },
97 DiffHunksToggled,
98 Edited {
99 singleton_buffer_edited: bool,
100 edited_buffer: Option<Entity<Buffer>>,
101 },
102 TransactionUndone {
103 transaction_id: TransactionId,
104 },
105 Reloaded,
106 ReloadNeeded,
107
108 LanguageChanged(BufferId),
109 CapabilityChanged,
110 Reparsed(BufferId),
111 Saved,
112 FileHandleChanged,
113 Closed,
114 Discarded,
115 DirtyChanged,
116 DiagnosticsUpdated,
117}
118
119/// A diff hunk, representing a range of consequent lines in a multibuffer.
120#[derive(Debug, Clone, PartialEq, Eq)]
121pub struct MultiBufferDiffHunk {
122 /// The row range in the multibuffer where this diff hunk appears.
123 pub row_range: Range<MultiBufferRow>,
124 /// The buffer ID that this hunk belongs to.
125 pub buffer_id: BufferId,
126 /// The range of the underlying buffer that this hunk corresponds to.
127 pub buffer_range: Range<text::Anchor>,
128 /// The excerpt that contains the diff hunk.
129 pub excerpt_id: ExcerptId,
130 /// The range within the buffer's diff base that this hunk corresponds to.
131 pub diff_base_byte_range: Range<usize>,
132}
133
134impl MultiBufferDiffHunk {
135 pub fn status(&self) -> DiffHunkStatus {
136 if self.buffer_range.start == self.buffer_range.end {
137 DiffHunkStatus::Removed
138 } else if self.diff_base_byte_range.is_empty() {
139 DiffHunkStatus::Added
140 } else {
141 DiffHunkStatus::Modified
142 }
143 }
144}
145
146#[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Hash, Debug)]
147pub struct PathKey(String);
148
149impl PathKey {
150 pub fn namespaced(namespace: &str, path: &Path) -> Self {
151 Self(format!("{}/{}", namespace, path.to_string_lossy()))
152 }
153}
154
155pub type MultiBufferPoint = Point;
156type ExcerptOffset = TypedOffset<Excerpt>;
157type ExcerptPoint = TypedPoint<Excerpt>;
158
159#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq, Hash, serde::Deserialize)]
160#[serde(transparent)]
161pub struct MultiBufferRow(pub u32);
162
163impl MultiBufferRow {
164 pub const MIN: Self = Self(0);
165 pub const MAX: Self = Self(u32::MAX);
166}
167
168impl std::ops::Add<usize> for MultiBufferRow {
169 type Output = Self;
170
171 fn add(self, rhs: usize) -> Self::Output {
172 MultiBufferRow(self.0 + rhs as u32)
173 }
174}
175
176#[derive(Clone)]
177struct History {
178 next_transaction_id: TransactionId,
179 undo_stack: Vec<Transaction>,
180 redo_stack: Vec<Transaction>,
181 transaction_depth: usize,
182 group_interval: Duration,
183}
184
185#[derive(Clone)]
186struct Transaction {
187 id: TransactionId,
188 buffer_transactions: HashMap<BufferId, text::TransactionId>,
189 first_edit_at: Instant,
190 last_edit_at: Instant,
191 suppress_grouping: bool,
192}
193
194pub trait ToOffset: 'static + fmt::Debug {
195 fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
196}
197
198pub trait ToOffsetUtf16: 'static + fmt::Debug {
199 fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16;
200}
201
202pub trait ToPoint: 'static + fmt::Debug {
203 fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point;
204}
205
206pub trait ToPointUtf16: 'static + fmt::Debug {
207 fn to_point_utf16(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16;
208}
209
210struct BufferState {
211 buffer: Entity<Buffer>,
212 last_version: clock::Global,
213 last_non_text_state_update_count: usize,
214 excerpts: Vec<Locator>,
215 _subscriptions: [gpui::Subscription; 2],
216}
217
218struct ChangeSetState {
219 change_set: Entity<BufferChangeSet>,
220 _subscription: gpui::Subscription,
221}
222
223/// The contents of a [`MultiBuffer`] at a single point in time.
224#[derive(Clone, Default)]
225pub struct MultiBufferSnapshot {
226 singleton: bool,
227 excerpts: SumTree<Excerpt>,
228 excerpt_ids: SumTree<ExcerptIdMapping>,
229 diffs: TreeMap<BufferId, DiffSnapshot>,
230 pub diff_transforms: SumTree<DiffTransform>,
231 trailing_excerpt_update_count: usize,
232 non_text_state_update_count: usize,
233 edit_count: usize,
234 is_dirty: bool,
235 has_deleted_file: bool,
236 has_conflict: bool,
237 show_headers: bool,
238}
239
240#[derive(Debug, Clone)]
241pub enum DiffTransform {
242 BufferContent {
243 summary: TextSummary,
244 inserted_hunk_anchor: Option<(ExcerptId, text::Anchor)>,
245 },
246 DeletedHunk {
247 summary: TextSummary,
248 buffer_id: BufferId,
249 hunk_anchor: (ExcerptId, text::Anchor),
250 base_text_byte_range: Range<usize>,
251 has_trailing_newline: bool,
252 },
253}
254
255#[derive(Clone)]
256struct DiffSnapshot {
257 diff: git::diff::BufferDiff,
258 base_text: language::BufferSnapshot,
259}
260
261#[derive(Clone)]
262pub struct ExcerptInfo {
263 pub id: ExcerptId,
264 pub buffer: BufferSnapshot,
265 pub buffer_id: BufferId,
266 pub range: ExcerptRange<text::Anchor>,
267 pub end_row: MultiBufferRow,
268}
269
270impl std::fmt::Debug for ExcerptInfo {
271 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
272 f.debug_struct(type_name::<Self>())
273 .field("id", &self.id)
274 .field("buffer_id", &self.buffer_id)
275 .field("path", &self.buffer.file().map(|f| f.path()))
276 .field("range", &self.range)
277 .finish()
278 }
279}
280
281/// A boundary between `Excerpt`s in a [`MultiBuffer`]
282#[derive(Debug)]
283pub struct ExcerptBoundary {
284 pub prev: Option<ExcerptInfo>,
285 pub next: Option<ExcerptInfo>,
286 /// The row in the `MultiBuffer` where the boundary is located
287 pub row: MultiBufferRow,
288}
289
290impl ExcerptBoundary {
291 pub fn starts_new_buffer(&self) -> bool {
292 match (self.prev.as_ref(), self.next.as_ref()) {
293 (None, _) => true,
294 (Some(_), None) => false,
295 (Some(prev), Some(next)) => prev.buffer_id != next.buffer_id,
296 }
297 }
298}
299
300#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
301pub struct RowInfo {
302 pub buffer_id: Option<BufferId>,
303 pub buffer_row: Option<u32>,
304 pub multibuffer_row: Option<MultiBufferRow>,
305 pub diff_status: Option<git::diff::DiffHunkStatus>,
306}
307
308/// A slice into a [`Buffer`] that is being edited in a [`MultiBuffer`].
309#[derive(Clone)]
310struct Excerpt {
311 /// The unique identifier for this excerpt
312 id: ExcerptId,
313 /// The location of the excerpt in the [`MultiBuffer`]
314 locator: Locator,
315 /// The buffer being excerpted
316 buffer_id: BufferId,
317 /// A snapshot of the buffer being excerpted
318 buffer: BufferSnapshot,
319 /// The range of the buffer to be shown in the excerpt
320 range: ExcerptRange<text::Anchor>,
321 /// The last row in the excerpted slice of the buffer
322 max_buffer_row: BufferRow,
323 /// A summary of the text in the excerpt
324 text_summary: TextSummary,
325 has_trailing_newline: bool,
326}
327
328/// A public view into an `Excerpt` in a [`MultiBuffer`].
329///
330/// Contains methods for getting the [`Buffer`] of the excerpt,
331/// as well as mapping offsets to/from buffer and multibuffer coordinates.
332#[derive(Clone)]
333pub struct MultiBufferExcerpt<'a> {
334 excerpt: &'a Excerpt,
335 diff_transforms:
336 sum_tree::Cursor<'a, DiffTransform, (OutputDimension<usize>, ExcerptDimension<usize>)>,
337 offset: usize,
338 excerpt_offset: ExcerptDimension<usize>,
339 buffer_offset: usize,
340}
341
342#[derive(Clone, Debug)]
343struct ExcerptIdMapping {
344 id: ExcerptId,
345 locator: Locator,
346}
347
348/// A range of text from a single [`Buffer`], to be shown as an `Excerpt`.
349/// These ranges are relative to the buffer itself
350#[derive(Clone, Debug, Eq, PartialEq, Hash)]
351pub struct ExcerptRange<T> {
352 /// The full range of text to be shown in the excerpt.
353 pub context: Range<T>,
354 /// The primary range of text to be highlighted in the excerpt.
355 /// In a multi-buffer search, this would be the text that matched the search
356 pub primary: Option<Range<T>>,
357}
358
359#[derive(Clone, Debug, Default)]
360pub struct ExcerptSummary {
361 excerpt_id: ExcerptId,
362 /// The location of the last [`Excerpt`] being summarized
363 excerpt_locator: Locator,
364 widest_line_number: u32,
365 text: TextSummary,
366}
367
368#[derive(Debug, Clone)]
369pub struct DiffTransformSummary {
370 input: TextSummary,
371 output: TextSummary,
372}
373
374#[derive(Clone)]
375pub struct MultiBufferRows<'a> {
376 point: Point,
377 is_empty: bool,
378 cursor: MultiBufferCursor<'a, Point>,
379}
380
381pub struct MultiBufferChunks<'a> {
382 excerpts: Cursor<'a, Excerpt, ExcerptOffset>,
383 diff_transforms: Cursor<'a, DiffTransform, (usize, ExcerptOffset)>,
384 diffs: &'a TreeMap<BufferId, DiffSnapshot>,
385 diff_base_chunks: Option<(BufferId, BufferChunks<'a>)>,
386 buffer_chunk: Option<Chunk<'a>>,
387 range: Range<usize>,
388 excerpt_offset_range: Range<ExcerptOffset>,
389 excerpt_chunks: Option<ExcerptChunks<'a>>,
390 language_aware: bool,
391}
392
393pub struct ReversedMultiBufferChunks<'a> {
394 cursor: MultiBufferCursor<'a, usize>,
395 current_chunks: Option<rope::Chunks<'a>>,
396 start: usize,
397 offset: usize,
398}
399
400pub struct MultiBufferBytes<'a> {
401 range: Range<usize>,
402 cursor: MultiBufferCursor<'a, usize>,
403 excerpt_bytes: Option<text::Bytes<'a>>,
404 has_trailing_newline: bool,
405 chunk: &'a [u8],
406}
407
408pub struct ReversedMultiBufferBytes<'a> {
409 range: Range<usize>,
410 chunks: ReversedMultiBufferChunks<'a>,
411 chunk: &'a [u8],
412}
413
414#[derive(Clone)]
415struct MultiBufferCursor<'a, D: TextDimension> {
416 excerpts: Cursor<'a, Excerpt, ExcerptDimension<D>>,
417 diff_transforms: Cursor<'a, DiffTransform, (OutputDimension<D>, ExcerptDimension<D>)>,
418 diffs: &'a TreeMap<BufferId, DiffSnapshot>,
419 cached_region: Option<MultiBufferRegion<'a, D>>,
420}
421
422#[derive(Clone)]
423struct MultiBufferRegion<'a, D: TextDimension> {
424 buffer: &'a BufferSnapshot,
425 is_main_buffer: bool,
426 is_inserted_hunk: bool,
427 excerpt: &'a Excerpt,
428 buffer_range: Range<D>,
429 range: Range<D>,
430 has_trailing_newline: bool,
431}
432
433struct ExcerptChunks<'a> {
434 excerpt_id: ExcerptId,
435 content_chunks: BufferChunks<'a>,
436 footer_height: usize,
437}
438
439#[derive(Debug)]
440struct BufferEdit {
441 range: Range<usize>,
442 new_text: Arc<str>,
443 is_insertion: bool,
444 original_indent_column: u32,
445 excerpt_id: ExcerptId,
446}
447
448#[derive(Clone, Copy, Debug, PartialEq)]
449enum DiffChangeKind {
450 BufferEdited,
451 DiffUpdated { base_changed: bool },
452 ExpandOrCollapseHunks { expand: bool },
453}
454
455#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
456pub enum ExpandExcerptDirection {
457 Up,
458 Down,
459 UpAndDown,
460}
461
462impl ExpandExcerptDirection {
463 pub fn should_expand_up(&self) -> bool {
464 match self {
465 ExpandExcerptDirection::Up => true,
466 ExpandExcerptDirection::Down => false,
467 ExpandExcerptDirection::UpAndDown => true,
468 }
469 }
470
471 pub fn should_expand_down(&self) -> bool {
472 match self {
473 ExpandExcerptDirection::Up => false,
474 ExpandExcerptDirection::Down => true,
475 ExpandExcerptDirection::UpAndDown => true,
476 }
477 }
478}
479
480#[derive(Clone, Debug, PartialEq)]
481pub struct IndentGuide {
482 pub buffer_id: BufferId,
483 pub start_row: MultiBufferRow,
484 pub end_row: MultiBufferRow,
485 pub depth: u32,
486 pub tab_size: u32,
487 pub settings: IndentGuideSettings,
488}
489
490impl IndentGuide {
491 pub fn indent_level(&self) -> u32 {
492 self.depth * self.tab_size
493 }
494}
495
496impl MultiBuffer {
497 pub fn new(capability: Capability) -> Self {
498 Self {
499 snapshot: RefCell::new(MultiBufferSnapshot {
500 show_headers: true,
501 ..MultiBufferSnapshot::default()
502 }),
503 buffers: RefCell::default(),
504 diff_bases: HashMap::default(),
505 all_diff_hunks_expanded: false,
506 subscriptions: Topic::default(),
507 singleton: false,
508 capability,
509 title: None,
510 buffers_by_path: Default::default(),
511 history: History {
512 next_transaction_id: clock::Lamport::default(),
513 undo_stack: Vec::new(),
514 redo_stack: Vec::new(),
515 transaction_depth: 0,
516 group_interval: Duration::from_millis(300),
517 },
518 }
519 }
520
521 pub fn without_headers(capability: Capability) -> Self {
522 Self {
523 snapshot: Default::default(),
524 buffers: Default::default(),
525 buffers_by_path: Default::default(),
526 diff_bases: HashMap::default(),
527 all_diff_hunks_expanded: false,
528 subscriptions: Default::default(),
529 singleton: false,
530 capability,
531 history: History {
532 next_transaction_id: Default::default(),
533 undo_stack: Default::default(),
534 redo_stack: Default::default(),
535 transaction_depth: 0,
536 group_interval: Duration::from_millis(300),
537 },
538 title: Default::default(),
539 }
540 }
541
542 pub fn clone(&self, new_cx: &mut Context<Self>) -> Self {
543 let mut buffers = HashMap::default();
544 for (buffer_id, buffer_state) in self.buffers.borrow().iter() {
545 buffers.insert(
546 *buffer_id,
547 BufferState {
548 buffer: buffer_state.buffer.clone(),
549 last_version: buffer_state.last_version.clone(),
550 last_non_text_state_update_count: buffer_state.last_non_text_state_update_count,
551 excerpts: buffer_state.excerpts.clone(),
552 _subscriptions: [
553 new_cx.observe(&buffer_state.buffer, |_, _, cx| cx.notify()),
554 new_cx.subscribe(&buffer_state.buffer, Self::on_buffer_event),
555 ],
556 },
557 );
558 }
559 let mut diff_bases = HashMap::default();
560 for (buffer_id, change_set_state) in self.diff_bases.iter() {
561 diff_bases.insert(
562 *buffer_id,
563 ChangeSetState {
564 _subscription: new_cx.subscribe(
565 &change_set_state.change_set,
566 |this, change_set, event, cx| match event {
567 BufferChangeSetEvent::DiffChanged { changed_range } => {
568 this.buffer_diff_changed(change_set, changed_range.clone(), cx)
569 }
570 },
571 ),
572 change_set: change_set_state.change_set.clone(),
573 },
574 );
575 }
576 Self {
577 snapshot: RefCell::new(self.snapshot.borrow().clone()),
578 buffers: RefCell::new(buffers),
579 buffers_by_path: Default::default(),
580 diff_bases,
581 all_diff_hunks_expanded: self.all_diff_hunks_expanded,
582 subscriptions: Default::default(),
583 singleton: self.singleton,
584 capability: self.capability,
585 history: self.history.clone(),
586 title: self.title.clone(),
587 }
588 }
589
590 pub fn with_title(mut self, title: String) -> Self {
591 self.title = Some(title);
592 self
593 }
594
595 pub fn read_only(&self) -> bool {
596 self.capability == Capability::ReadOnly
597 }
598
599 pub fn singleton(buffer: Entity<Buffer>, cx: &mut Context<Self>) -> Self {
600 let mut this = Self::new(buffer.read(cx).capability());
601 this.singleton = true;
602 this.push_excerpts(
603 buffer,
604 [ExcerptRange {
605 context: text::Anchor::MIN..text::Anchor::MAX,
606 primary: None,
607 }],
608 cx,
609 );
610 this.snapshot.borrow_mut().singleton = true;
611 this
612 }
613
614 /// Returns an up-to-date snapshot of the MultiBuffer.
615 pub fn snapshot(&self, cx: &App) -> MultiBufferSnapshot {
616 self.sync(cx);
617 self.snapshot.borrow().clone()
618 }
619
620 pub fn read(&self, cx: &App) -> Ref<MultiBufferSnapshot> {
621 self.sync(cx);
622 self.snapshot.borrow()
623 }
624
625 pub fn as_singleton(&self) -> Option<Entity<Buffer>> {
626 if self.singleton {
627 return Some(
628 self.buffers
629 .borrow()
630 .values()
631 .next()
632 .unwrap()
633 .buffer
634 .clone(),
635 );
636 } else {
637 None
638 }
639 }
640
641 pub fn is_singleton(&self) -> bool {
642 self.singleton
643 }
644
645 pub fn subscribe(&mut self) -> Subscription {
646 self.subscriptions.subscribe()
647 }
648
649 pub fn is_dirty(&self, cx: &App) -> bool {
650 self.read(cx).is_dirty()
651 }
652
653 pub fn has_deleted_file(&self, cx: &App) -> bool {
654 self.read(cx).has_deleted_file()
655 }
656
657 pub fn has_conflict(&self, cx: &App) -> bool {
658 self.read(cx).has_conflict()
659 }
660
661 // The `is_empty` signature doesn't match what clippy expects
662 #[allow(clippy::len_without_is_empty)]
663 pub fn len(&self, cx: &App) -> usize {
664 self.read(cx).len()
665 }
666
667 pub fn is_empty(&self) -> bool {
668 self.buffers.borrow().is_empty()
669 }
670
671 pub fn symbols_containing<T: ToOffset>(
672 &self,
673 offset: T,
674 theme: Option<&SyntaxTheme>,
675 cx: &App,
676 ) -> Option<(BufferId, Vec<OutlineItem<Anchor>>)> {
677 self.read(cx).symbols_containing(offset, theme)
678 }
679
680 pub fn edit<I, S, T>(
681 &self,
682 edits: I,
683 autoindent_mode: Option<AutoindentMode>,
684 cx: &mut Context<Self>,
685 ) where
686 I: IntoIterator<Item = (Range<S>, T)>,
687 S: ToOffset,
688 T: Into<Arc<str>>,
689 {
690 let snapshot = self.read(cx);
691 let edits = edits
692 .into_iter()
693 .map(|(range, new_text)| {
694 let mut range = range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot);
695 if range.start > range.end {
696 mem::swap(&mut range.start, &mut range.end);
697 }
698 (range, new_text.into())
699 })
700 .collect::<Vec<_>>();
701
702 return edit_internal(self, snapshot, edits, autoindent_mode, cx);
703
704 // Non-generic part of edit, hoisted out to avoid blowing up LLVM IR.
705 fn edit_internal(
706 this: &MultiBuffer,
707 snapshot: Ref<MultiBufferSnapshot>,
708 edits: Vec<(Range<usize>, Arc<str>)>,
709 mut autoindent_mode: Option<AutoindentMode>,
710 cx: &mut Context<MultiBuffer>,
711 ) {
712 if this.read_only() || this.buffers.borrow().is_empty() {
713 return;
714 }
715
716 let original_indent_columns = match &mut autoindent_mode {
717 Some(AutoindentMode::Block {
718 original_indent_columns,
719 }) => mem::take(original_indent_columns),
720 _ => Default::default(),
721 };
722
723 let (buffer_edits, edited_excerpt_ids) =
724 this.convert_edits_to_buffer_edits(edits, &snapshot, &original_indent_columns);
725 drop(snapshot);
726
727 for (buffer_id, mut edits) in buffer_edits {
728 edits.sort_by_key(|edit| edit.range.start);
729 this.buffers.borrow()[&buffer_id]
730 .buffer
731 .update(cx, |buffer, cx| {
732 let mut edits = edits.into_iter().peekable();
733 let mut insertions = Vec::new();
734 let mut original_indent_columns = Vec::new();
735 let mut deletions = Vec::new();
736 let empty_str: Arc<str> = Arc::default();
737 while let Some(BufferEdit {
738 mut range,
739 mut new_text,
740 mut is_insertion,
741 original_indent_column,
742 excerpt_id,
743 }) = edits.next()
744 {
745 while let Some(BufferEdit {
746 range: next_range,
747 is_insertion: next_is_insertion,
748 new_text: next_new_text,
749 excerpt_id: next_excerpt_id,
750 ..
751 }) = edits.peek()
752 {
753 if range.end >= next_range.start {
754 range.end = cmp::max(next_range.end, range.end);
755 is_insertion |= *next_is_insertion;
756 if excerpt_id == *next_excerpt_id {
757 new_text = format!("{new_text}{next_new_text}").into();
758 }
759 edits.next();
760 } else {
761 break;
762 }
763 }
764
765 if is_insertion {
766 original_indent_columns.push(original_indent_column);
767 insertions.push((
768 buffer.anchor_before(range.start)
769 ..buffer.anchor_before(range.end),
770 new_text.clone(),
771 ));
772 } else if !range.is_empty() {
773 deletions.push((
774 buffer.anchor_before(range.start)
775 ..buffer.anchor_before(range.end),
776 empty_str.clone(),
777 ));
778 }
779 }
780
781 let deletion_autoindent_mode =
782 if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
783 Some(AutoindentMode::Block {
784 original_indent_columns: Default::default(),
785 })
786 } else {
787 autoindent_mode.clone()
788 };
789 let insertion_autoindent_mode =
790 if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
791 Some(AutoindentMode::Block {
792 original_indent_columns,
793 })
794 } else {
795 autoindent_mode.clone()
796 };
797
798 buffer.edit(deletions, deletion_autoindent_mode, cx);
799 buffer.edit(insertions, insertion_autoindent_mode, cx);
800 })
801 }
802
803 cx.emit(Event::ExcerptsEdited {
804 ids: edited_excerpt_ids,
805 });
806 }
807 }
808
809 fn convert_edits_to_buffer_edits(
810 &self,
811 edits: Vec<(Range<usize>, Arc<str>)>,
812 snapshot: &MultiBufferSnapshot,
813 original_indent_columns: &[u32],
814 ) -> (HashMap<BufferId, Vec<BufferEdit>>, Vec<ExcerptId>) {
815 let mut buffer_edits: HashMap<BufferId, Vec<BufferEdit>> = Default::default();
816 let mut edited_excerpt_ids = Vec::new();
817 let mut cursor = snapshot.cursor::<usize>();
818 for (ix, (range, new_text)) in edits.into_iter().enumerate() {
819 let original_indent_column = original_indent_columns.get(ix).copied().unwrap_or(0);
820
821 cursor.seek(&range.start);
822 let mut start_region = cursor.region().expect("start offset out of bounds");
823 if !start_region.is_main_buffer {
824 cursor.next();
825 if let Some(region) = cursor.region() {
826 start_region = region;
827 } else {
828 continue;
829 }
830 }
831
832 if range.end < start_region.range.start {
833 continue;
834 }
835
836 if range.end > start_region.range.end {
837 cursor.seek_forward(&range.end);
838 }
839 let mut end_region = cursor.region().expect("end offset out of bounds");
840 if !end_region.is_main_buffer {
841 cursor.prev();
842 if let Some(region) = cursor.region() {
843 end_region = region;
844 } else {
845 continue;
846 }
847 }
848
849 if range.start > end_region.range.end {
850 continue;
851 }
852
853 let start_overshoot = range.start.saturating_sub(start_region.range.start);
854 let end_overshoot = range.end.saturating_sub(end_region.range.start);
855 let buffer_start = (start_region.buffer_range.start + start_overshoot)
856 .min(start_region.buffer_range.end);
857 let buffer_end =
858 (end_region.buffer_range.start + end_overshoot).min(end_region.buffer_range.end);
859
860 if start_region.excerpt.id == end_region.excerpt.id {
861 if start_region.is_main_buffer {
862 edited_excerpt_ids.push(start_region.excerpt.id);
863 buffer_edits
864 .entry(start_region.buffer.remote_id())
865 .or_default()
866 .push(BufferEdit {
867 range: buffer_start..buffer_end,
868 new_text,
869 is_insertion: true,
870 original_indent_column,
871 excerpt_id: start_region.excerpt.id,
872 });
873 }
874 } else {
875 let start_excerpt_range = buffer_start..start_region.buffer_range.end;
876 let end_excerpt_range = end_region.buffer_range.start..buffer_end;
877 if start_region.is_main_buffer {
878 edited_excerpt_ids.push(start_region.excerpt.id);
879 buffer_edits
880 .entry(start_region.buffer.remote_id())
881 .or_default()
882 .push(BufferEdit {
883 range: start_excerpt_range,
884 new_text: new_text.clone(),
885 is_insertion: true,
886 original_indent_column,
887 excerpt_id: start_region.excerpt.id,
888 });
889 }
890 if end_region.is_main_buffer {
891 edited_excerpt_ids.push(end_region.excerpt.id);
892 buffer_edits
893 .entry(end_region.buffer.remote_id())
894 .or_default()
895 .push(BufferEdit {
896 range: end_excerpt_range,
897 new_text: new_text.clone(),
898 is_insertion: false,
899 original_indent_column,
900 excerpt_id: end_region.excerpt.id,
901 });
902 }
903
904 cursor.seek(&range.start);
905 cursor.next_excerpt();
906 while let Some(region) = cursor.region() {
907 if region.excerpt.id == end_region.excerpt.id {
908 break;
909 }
910 if region.is_main_buffer {
911 edited_excerpt_ids.push(region.excerpt.id);
912 buffer_edits
913 .entry(region.buffer.remote_id())
914 .or_default()
915 .push(BufferEdit {
916 range: region.buffer_range,
917 new_text: new_text.clone(),
918 is_insertion: false,
919 original_indent_column,
920 excerpt_id: region.excerpt.id,
921 });
922 }
923 cursor.next_excerpt();
924 }
925 }
926 }
927 (buffer_edits, edited_excerpt_ids)
928 }
929
930 pub fn autoindent_ranges<I, S>(&self, ranges: I, cx: &mut Context<Self>)
931 where
932 I: IntoIterator<Item = Range<S>>,
933 S: ToOffset,
934 {
935 let snapshot = self.read(cx);
936 let empty = Arc::<str>::from("");
937 let edits = ranges
938 .into_iter()
939 .map(|range| {
940 let mut range = range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot);
941 if range.start > range.end {
942 mem::swap(&mut range.start, &mut range.end);
943 }
944 (range, empty.clone())
945 })
946 .collect::<Vec<_>>();
947
948 return autoindent_ranges_internal(self, snapshot, edits, cx);
949
950 fn autoindent_ranges_internal(
951 this: &MultiBuffer,
952 snapshot: Ref<MultiBufferSnapshot>,
953 edits: Vec<(Range<usize>, Arc<str>)>,
954 cx: &mut Context<MultiBuffer>,
955 ) {
956 if this.read_only() || this.buffers.borrow().is_empty() {
957 return;
958 }
959
960 let (buffer_edits, edited_excerpt_ids) =
961 this.convert_edits_to_buffer_edits(edits, &snapshot, &[]);
962 drop(snapshot);
963
964 for (buffer_id, mut edits) in buffer_edits {
965 edits.sort_unstable_by_key(|edit| edit.range.start);
966
967 let mut ranges: Vec<Range<usize>> = Vec::new();
968 for edit in edits {
969 if let Some(last_range) = ranges.last_mut() {
970 if edit.range.start <= last_range.end {
971 last_range.end = last_range.end.max(edit.range.end);
972 continue;
973 }
974 }
975 ranges.push(edit.range);
976 }
977
978 this.buffers.borrow()[&buffer_id]
979 .buffer
980 .update(cx, |buffer, cx| {
981 buffer.autoindent_ranges(ranges, cx);
982 })
983 }
984
985 cx.emit(Event::ExcerptsEdited {
986 ids: edited_excerpt_ids,
987 });
988 }
989 }
990
991 // Inserts newlines at the given position to create an empty line, returning the start of the new line.
992 // You can also request the insertion of empty lines above and below the line starting at the returned point.
993 // Panics if the given position is invalid.
994 pub fn insert_empty_line(
995 &mut self,
996 position: impl ToPoint,
997 space_above: bool,
998 space_below: bool,
999 cx: &mut Context<Self>,
1000 ) -> Point {
1001 let multibuffer_point = position.to_point(&self.read(cx));
1002 let (buffer, buffer_point, _) = self.point_to_buffer_point(multibuffer_point, cx).unwrap();
1003 self.start_transaction(cx);
1004 let empty_line_start = buffer.update(cx, |buffer, cx| {
1005 buffer.insert_empty_line(buffer_point, space_above, space_below, cx)
1006 });
1007 self.end_transaction(cx);
1008 multibuffer_point + (empty_line_start - buffer_point)
1009 }
1010
1011 pub fn start_transaction(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {
1012 self.start_transaction_at(Instant::now(), cx)
1013 }
1014
1015 pub fn start_transaction_at(
1016 &mut self,
1017 now: Instant,
1018 cx: &mut Context<Self>,
1019 ) -> Option<TransactionId> {
1020 if let Some(buffer) = self.as_singleton() {
1021 return buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
1022 }
1023
1024 for BufferState { buffer, .. } in self.buffers.borrow().values() {
1025 buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
1026 }
1027 self.history.start_transaction(now)
1028 }
1029
1030 pub fn end_transaction(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {
1031 self.end_transaction_at(Instant::now(), cx)
1032 }
1033
1034 pub fn end_transaction_at(
1035 &mut self,
1036 now: Instant,
1037 cx: &mut Context<Self>,
1038 ) -> Option<TransactionId> {
1039 if let Some(buffer) = self.as_singleton() {
1040 return buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx));
1041 }
1042
1043 let mut buffer_transactions = HashMap::default();
1044 for BufferState { buffer, .. } in self.buffers.borrow().values() {
1045 if let Some(transaction_id) =
1046 buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
1047 {
1048 buffer_transactions.insert(buffer.read(cx).remote_id(), transaction_id);
1049 }
1050 }
1051
1052 if self.history.end_transaction(now, buffer_transactions) {
1053 let transaction_id = self.history.group().unwrap();
1054 Some(transaction_id)
1055 } else {
1056 None
1057 }
1058 }
1059
1060 pub fn edited_ranges_for_transaction<D>(
1061 &self,
1062 transaction_id: TransactionId,
1063 cx: &App,
1064 ) -> Vec<Range<D>>
1065 where
1066 D: TextDimension + Ord + Sub<D, Output = D>,
1067 {
1068 let Some(transaction) = self.history.transaction(transaction_id) else {
1069 return Vec::new();
1070 };
1071
1072 let mut ranges = Vec::new();
1073 let snapshot = self.read(cx);
1074 let buffers = self.buffers.borrow();
1075 let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>(&());
1076
1077 for (buffer_id, buffer_transaction) in &transaction.buffer_transactions {
1078 let Some(buffer_state) = buffers.get(buffer_id) else {
1079 continue;
1080 };
1081
1082 let buffer = buffer_state.buffer.read(cx);
1083 for range in buffer.edited_ranges_for_transaction_id::<D>(*buffer_transaction) {
1084 for excerpt_id in &buffer_state.excerpts {
1085 cursor.seek(excerpt_id, Bias::Left, &());
1086 if let Some(excerpt) = cursor.item() {
1087 if excerpt.locator == *excerpt_id {
1088 let excerpt_buffer_start =
1089 excerpt.range.context.start.summary::<D>(buffer);
1090 let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(buffer);
1091 let excerpt_range = excerpt_buffer_start..excerpt_buffer_end;
1092 if excerpt_range.contains(&range.start)
1093 && excerpt_range.contains(&range.end)
1094 {
1095 let excerpt_start = D::from_text_summary(&cursor.start().text);
1096
1097 let mut start = excerpt_start;
1098 start.add_assign(&(range.start - excerpt_buffer_start));
1099 let mut end = excerpt_start;
1100 end.add_assign(&(range.end - excerpt_buffer_start));
1101
1102 ranges.push(start..end);
1103 break;
1104 }
1105 }
1106 }
1107 }
1108 }
1109 }
1110
1111 ranges.sort_by_key(|range| range.start);
1112 ranges
1113 }
1114
1115 pub fn merge_transactions(
1116 &mut self,
1117 transaction: TransactionId,
1118 destination: TransactionId,
1119 cx: &mut Context<Self>,
1120 ) {
1121 if let Some(buffer) = self.as_singleton() {
1122 buffer.update(cx, |buffer, _| {
1123 buffer.merge_transactions(transaction, destination)
1124 });
1125 } else if let Some(transaction) = self.history.forget(transaction) {
1126 if let Some(destination) = self.history.transaction_mut(destination) {
1127 for (buffer_id, buffer_transaction_id) in transaction.buffer_transactions {
1128 if let Some(destination_buffer_transaction_id) =
1129 destination.buffer_transactions.get(&buffer_id)
1130 {
1131 if let Some(state) = self.buffers.borrow().get(&buffer_id) {
1132 state.buffer.update(cx, |buffer, _| {
1133 buffer.merge_transactions(
1134 buffer_transaction_id,
1135 *destination_buffer_transaction_id,
1136 )
1137 });
1138 }
1139 } else {
1140 destination
1141 .buffer_transactions
1142 .insert(buffer_id, buffer_transaction_id);
1143 }
1144 }
1145 }
1146 }
1147 }
1148
1149 pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
1150 self.history.finalize_last_transaction();
1151 for BufferState { buffer, .. } in self.buffers.borrow().values() {
1152 buffer.update(cx, |buffer, _| {
1153 buffer.finalize_last_transaction();
1154 });
1155 }
1156 }
1157
1158 pub fn push_transaction<'a, T>(&mut self, buffer_transactions: T, cx: &Context<Self>)
1159 where
1160 T: IntoIterator<Item = (&'a Entity<Buffer>, &'a language::Transaction)>,
1161 {
1162 self.history
1163 .push_transaction(buffer_transactions, Instant::now(), cx);
1164 self.history.finalize_last_transaction();
1165 }
1166
1167 pub fn group_until_transaction(
1168 &mut self,
1169 transaction_id: TransactionId,
1170 cx: &mut Context<Self>,
1171 ) {
1172 if let Some(buffer) = self.as_singleton() {
1173 buffer.update(cx, |buffer, _| {
1174 buffer.group_until_transaction(transaction_id)
1175 });
1176 } else {
1177 self.history.group_until(transaction_id);
1178 }
1179 }
1180
1181 pub fn set_active_selections(
1182 &self,
1183 selections: &[Selection<Anchor>],
1184 line_mode: bool,
1185 cursor_shape: CursorShape,
1186 cx: &mut Context<Self>,
1187 ) {
1188 let mut selections_by_buffer: HashMap<BufferId, Vec<Selection<text::Anchor>>> =
1189 Default::default();
1190 let snapshot = self.read(cx);
1191 let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>(&());
1192 for selection in selections {
1193 let start_locator = snapshot.excerpt_locator_for_id(selection.start.excerpt_id);
1194 let end_locator = snapshot.excerpt_locator_for_id(selection.end.excerpt_id);
1195
1196 cursor.seek(&Some(start_locator), Bias::Left, &());
1197 while let Some(excerpt) = cursor.item() {
1198 if excerpt.locator > *end_locator {
1199 break;
1200 }
1201
1202 let mut start = excerpt.range.context.start;
1203 let mut end = excerpt.range.context.end;
1204 if excerpt.id == selection.start.excerpt_id {
1205 start = selection.start.text_anchor;
1206 }
1207 if excerpt.id == selection.end.excerpt_id {
1208 end = selection.end.text_anchor;
1209 }
1210 selections_by_buffer
1211 .entry(excerpt.buffer_id)
1212 .or_default()
1213 .push(Selection {
1214 id: selection.id,
1215 start,
1216 end,
1217 reversed: selection.reversed,
1218 goal: selection.goal,
1219 });
1220
1221 cursor.next(&());
1222 }
1223 }
1224
1225 for (buffer_id, buffer_state) in self.buffers.borrow().iter() {
1226 if !selections_by_buffer.contains_key(buffer_id) {
1227 buffer_state
1228 .buffer
1229 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
1230 }
1231 }
1232
1233 for (buffer_id, mut selections) in selections_by_buffer {
1234 self.buffers.borrow()[&buffer_id]
1235 .buffer
1236 .update(cx, |buffer, cx| {
1237 selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer));
1238 let mut selections = selections.into_iter().peekable();
1239 let merged_selections = Arc::from_iter(iter::from_fn(|| {
1240 let mut selection = selections.next()?;
1241 while let Some(next_selection) = selections.peek() {
1242 if selection.end.cmp(&next_selection.start, buffer).is_ge() {
1243 let next_selection = selections.next().unwrap();
1244 if next_selection.end.cmp(&selection.end, buffer).is_ge() {
1245 selection.end = next_selection.end;
1246 }
1247 } else {
1248 break;
1249 }
1250 }
1251 Some(selection)
1252 }));
1253 buffer.set_active_selections(merged_selections, line_mode, cursor_shape, cx);
1254 });
1255 }
1256 }
1257
1258 pub fn remove_active_selections(&self, cx: &mut Context<Self>) {
1259 for buffer in self.buffers.borrow().values() {
1260 buffer
1261 .buffer
1262 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
1263 }
1264 }
1265
1266 pub fn undo(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {
1267 let mut transaction_id = None;
1268 if let Some(buffer) = self.as_singleton() {
1269 transaction_id = buffer.update(cx, |buffer, cx| buffer.undo(cx));
1270 } else {
1271 while let Some(transaction) = self.history.pop_undo() {
1272 let mut undone = false;
1273 for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions {
1274 if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
1275 undone |= buffer.update(cx, |buffer, cx| {
1276 let undo_to = *buffer_transaction_id;
1277 if let Some(entry) = buffer.peek_undo_stack() {
1278 *buffer_transaction_id = entry.transaction_id();
1279 }
1280 buffer.undo_to_transaction(undo_to, cx)
1281 });
1282 }
1283 }
1284
1285 if undone {
1286 transaction_id = Some(transaction.id);
1287 break;
1288 }
1289 }
1290 }
1291
1292 if let Some(transaction_id) = transaction_id {
1293 cx.emit(Event::TransactionUndone { transaction_id });
1294 }
1295
1296 transaction_id
1297 }
1298
1299 pub fn redo(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {
1300 if let Some(buffer) = self.as_singleton() {
1301 return buffer.update(cx, |buffer, cx| buffer.redo(cx));
1302 }
1303
1304 while let Some(transaction) = self.history.pop_redo() {
1305 let mut redone = false;
1306 for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions {
1307 if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
1308 redone |= buffer.update(cx, |buffer, cx| {
1309 let redo_to = *buffer_transaction_id;
1310 if let Some(entry) = buffer.peek_redo_stack() {
1311 *buffer_transaction_id = entry.transaction_id();
1312 }
1313 buffer.redo_to_transaction(redo_to, cx)
1314 });
1315 }
1316 }
1317
1318 if redone {
1319 return Some(transaction.id);
1320 }
1321 }
1322
1323 None
1324 }
1325
1326 pub fn undo_transaction(&mut self, transaction_id: TransactionId, cx: &mut Context<Self>) {
1327 if let Some(buffer) = self.as_singleton() {
1328 buffer.update(cx, |buffer, cx| buffer.undo_transaction(transaction_id, cx));
1329 } else if let Some(transaction) = self.history.remove_from_undo(transaction_id) {
1330 for (buffer_id, transaction_id) in &transaction.buffer_transactions {
1331 if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
1332 buffer.update(cx, |buffer, cx| {
1333 buffer.undo_transaction(*transaction_id, cx)
1334 });
1335 }
1336 }
1337 }
1338 }
1339
1340 pub fn forget_transaction(&mut self, transaction_id: TransactionId, cx: &mut Context<Self>) {
1341 if let Some(buffer) = self.as_singleton() {
1342 buffer.update(cx, |buffer, _| {
1343 buffer.forget_transaction(transaction_id);
1344 });
1345 } else if let Some(transaction) = self.history.forget(transaction_id) {
1346 for (buffer_id, buffer_transaction_id) in transaction.buffer_transactions {
1347 if let Some(state) = self.buffers.borrow_mut().get_mut(&buffer_id) {
1348 state.buffer.update(cx, |buffer, _| {
1349 buffer.forget_transaction(buffer_transaction_id);
1350 });
1351 }
1352 }
1353 }
1354 }
1355
1356 pub fn push_excerpts<O>(
1357 &mut self,
1358 buffer: Entity<Buffer>,
1359 ranges: impl IntoIterator<Item = ExcerptRange<O>>,
1360 cx: &mut Context<Self>,
1361 ) -> Vec<ExcerptId>
1362 where
1363 O: text::ToOffset,
1364 {
1365 self.insert_excerpts_after(ExcerptId::max(), buffer, ranges, cx)
1366 }
1367
1368 pub fn push_excerpts_with_context_lines<O>(
1369 &mut self,
1370 buffer: Entity<Buffer>,
1371 ranges: Vec<Range<O>>,
1372 context_line_count: u32,
1373 cx: &mut Context<Self>,
1374 ) -> Vec<Range<Anchor>>
1375 where
1376 O: text::ToPoint + text::ToOffset,
1377 {
1378 let buffer_id = buffer.read(cx).remote_id();
1379 let buffer_snapshot = buffer.read(cx).snapshot();
1380 let (excerpt_ranges, range_counts) =
1381 build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
1382
1383 let excerpt_ids = self.push_excerpts(buffer, excerpt_ranges, cx);
1384
1385 let mut anchor_ranges = Vec::new();
1386 let mut ranges = ranges.into_iter();
1387 for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.into_iter()) {
1388 anchor_ranges.extend(ranges.by_ref().take(range_count).map(|range| {
1389 let start = Anchor {
1390 buffer_id: Some(buffer_id),
1391 excerpt_id,
1392 text_anchor: buffer_snapshot.anchor_after(range.start),
1393 diff_base_anchor: None,
1394 };
1395 let end = Anchor {
1396 buffer_id: Some(buffer_id),
1397 excerpt_id,
1398 text_anchor: buffer_snapshot.anchor_after(range.end),
1399 diff_base_anchor: None,
1400 };
1401 start..end
1402 }))
1403 }
1404 anchor_ranges
1405 }
1406
1407 pub fn location_for_path(&self, path: &PathKey, cx: &App) -> Option<Anchor> {
1408 let excerpt_id = self.buffers_by_path.get(path)?.first()?;
1409 let snapshot = self.snapshot(cx);
1410 let excerpt = snapshot.excerpt(*excerpt_id)?;
1411 Some(Anchor::in_buffer(
1412 *excerpt_id,
1413 excerpt.buffer_id,
1414 excerpt.range.context.start,
1415 ))
1416 }
1417
1418 pub fn set_excerpts_for_path(
1419 &mut self,
1420 path: PathKey,
1421 buffer: Entity<Buffer>,
1422 ranges: Vec<Range<Point>>,
1423 context_line_count: u32,
1424 cx: &mut Context<Self>,
1425 ) {
1426 let buffer_snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
1427
1428 let mut insert_after = self
1429 .buffers_by_path
1430 .range(..path.clone())
1431 .next_back()
1432 .map(|(_, value)| *value.last().unwrap())
1433 .unwrap_or(ExcerptId::min());
1434 let existing = self.buffers_by_path.get(&path).cloned().unwrap_or_default();
1435
1436 let (new, _) = build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
1437
1438 let mut new_iter = new.into_iter().peekable();
1439 let mut existing_iter = existing.into_iter().peekable();
1440
1441 let mut new_excerpt_ids = Vec::new();
1442 let mut to_remove = Vec::new();
1443 let mut to_insert = Vec::new();
1444 let snapshot = self.snapshot(cx);
1445
1446 let mut excerpts_cursor = snapshot.excerpts.cursor::<Option<&Locator>>(&());
1447 excerpts_cursor.next(&());
1448
1449 loop {
1450 let (new, existing) = match (new_iter.peek(), existing_iter.peek()) {
1451 (Some(new), Some(existing)) => (new, existing),
1452 (None, None) => break,
1453 (None, Some(_)) => {
1454 to_remove.push(existing_iter.next().unwrap());
1455 continue;
1456 }
1457 (Some(_), None) => {
1458 to_insert.push(new_iter.next().unwrap());
1459 continue;
1460 }
1461 };
1462 let locator = snapshot.excerpt_locator_for_id(*existing);
1463 excerpts_cursor.seek_forward(&Some(locator), Bias::Left, &());
1464 let existing_excerpt = excerpts_cursor.item().unwrap();
1465 if existing_excerpt.buffer_id != buffer_snapshot.remote_id() {
1466 to_remove.push(existing_iter.next().unwrap());
1467 to_insert.push(new_iter.next().unwrap());
1468 continue;
1469 }
1470
1471 let existing_start = existing_excerpt
1472 .range
1473 .context
1474 .start
1475 .to_point(&buffer_snapshot);
1476 let existing_end = existing_excerpt
1477 .range
1478 .context
1479 .end
1480 .to_point(&buffer_snapshot);
1481
1482 if existing_end < new.context.start {
1483 to_remove.push(existing_iter.next().unwrap());
1484 continue;
1485 } else if existing_start > new.context.end {
1486 to_insert.push(new_iter.next().unwrap());
1487 continue;
1488 }
1489
1490 // maybe merge overlapping excerpts?
1491 // it's hard to distinguish between a manually expanded excerpt, and one that
1492 // got smaller because of a missing diff.
1493 if existing_start == new.context.start && existing_end == new.context.end {
1494 new_excerpt_ids.append(&mut self.insert_excerpts_after(
1495 insert_after,
1496 buffer.clone(),
1497 mem::take(&mut to_insert),
1498 cx,
1499 ));
1500 insert_after = existing_iter.next().unwrap();
1501 new_excerpt_ids.push(insert_after);
1502 new_iter.next();
1503 } else {
1504 to_remove.push(existing_iter.next().unwrap());
1505 to_insert.push(new_iter.next().unwrap());
1506 }
1507 }
1508
1509 new_excerpt_ids.append(&mut self.insert_excerpts_after(
1510 insert_after,
1511 buffer,
1512 to_insert,
1513 cx,
1514 ));
1515 self.remove_excerpts(to_remove, cx);
1516 if new_excerpt_ids.is_empty() {
1517 self.buffers_by_path.remove(&path);
1518 } else {
1519 self.buffers_by_path.insert(path, new_excerpt_ids);
1520 }
1521 }
1522
1523 pub fn paths(&self) -> impl Iterator<Item = PathKey> + '_ {
1524 self.buffers_by_path.keys().cloned()
1525 }
1526
1527 pub fn remove_excerpts_for_path(&mut self, path: PathKey, cx: &mut Context<Self>) {
1528 if let Some(to_remove) = self.buffers_by_path.remove(&path) {
1529 self.remove_excerpts(to_remove, cx)
1530 }
1531 }
1532
1533 pub fn push_multiple_excerpts_with_context_lines(
1534 &self,
1535 buffers_with_ranges: Vec<(Entity<Buffer>, Vec<Range<text::Anchor>>)>,
1536 context_line_count: u32,
1537 cx: &mut Context<Self>,
1538 ) -> Task<Vec<Range<Anchor>>> {
1539 use futures::StreamExt;
1540
1541 let (excerpt_ranges_tx, mut excerpt_ranges_rx) = mpsc::channel(256);
1542
1543 let mut buffer_ids = Vec::with_capacity(buffers_with_ranges.len());
1544
1545 for (buffer, ranges) in buffers_with_ranges {
1546 let (buffer_id, buffer_snapshot) =
1547 buffer.update(cx, |buffer, _| (buffer.remote_id(), buffer.snapshot()));
1548
1549 buffer_ids.push(buffer_id);
1550
1551 cx.background_executor()
1552 .spawn({
1553 let mut excerpt_ranges_tx = excerpt_ranges_tx.clone();
1554
1555 async move {
1556 let (excerpt_ranges, counts) =
1557 build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
1558 excerpt_ranges_tx
1559 .send((buffer_id, buffer.clone(), ranges, excerpt_ranges, counts))
1560 .await
1561 .ok();
1562 }
1563 })
1564 .detach()
1565 }
1566
1567 cx.spawn(move |this, mut cx| async move {
1568 let mut results_by_buffer_id = HashMap::default();
1569 while let Some((buffer_id, buffer, ranges, excerpt_ranges, range_counts)) =
1570 excerpt_ranges_rx.next().await
1571 {
1572 results_by_buffer_id
1573 .insert(buffer_id, (buffer, ranges, excerpt_ranges, range_counts));
1574 }
1575
1576 let mut multi_buffer_ranges = Vec::default();
1577 'outer: for buffer_id in buffer_ids {
1578 let Some((buffer, ranges, excerpt_ranges, range_counts)) =
1579 results_by_buffer_id.remove(&buffer_id)
1580 else {
1581 continue;
1582 };
1583
1584 let mut ranges = ranges.into_iter();
1585 let mut range_counts = range_counts.into_iter();
1586 for excerpt_ranges in excerpt_ranges.chunks(100) {
1587 let excerpt_ids = match this.update(&mut cx, |this, cx| {
1588 this.push_excerpts(buffer.clone(), excerpt_ranges.iter().cloned(), cx)
1589 }) {
1590 Ok(excerpt_ids) => excerpt_ids,
1591 Err(_) => continue 'outer,
1592 };
1593
1594 for (excerpt_id, range_count) in
1595 excerpt_ids.into_iter().zip(range_counts.by_ref())
1596 {
1597 for range in ranges.by_ref().take(range_count) {
1598 let start = Anchor {
1599 buffer_id: Some(buffer_id),
1600 excerpt_id,
1601 text_anchor: range.start,
1602 diff_base_anchor: None,
1603 };
1604 let end = Anchor {
1605 buffer_id: Some(buffer_id),
1606 excerpt_id,
1607 text_anchor: range.end,
1608 diff_base_anchor: None,
1609 };
1610 multi_buffer_ranges.push(start..end);
1611 }
1612 }
1613 }
1614 }
1615
1616 multi_buffer_ranges
1617 })
1618 }
1619
1620 pub fn insert_excerpts_after<O>(
1621 &mut self,
1622 prev_excerpt_id: ExcerptId,
1623 buffer: Entity<Buffer>,
1624 ranges: impl IntoIterator<Item = ExcerptRange<O>>,
1625 cx: &mut Context<Self>,
1626 ) -> Vec<ExcerptId>
1627 where
1628 O: text::ToOffset,
1629 {
1630 let mut ids = Vec::new();
1631 let mut next_excerpt_id =
1632 if let Some(last_entry) = self.snapshot.borrow().excerpt_ids.last() {
1633 last_entry.id.0 + 1
1634 } else {
1635 1
1636 };
1637 self.insert_excerpts_with_ids_after(
1638 prev_excerpt_id,
1639 buffer,
1640 ranges.into_iter().map(|range| {
1641 let id = ExcerptId(post_inc(&mut next_excerpt_id));
1642 ids.push(id);
1643 (id, range)
1644 }),
1645 cx,
1646 );
1647 ids
1648 }
1649
1650 pub fn insert_excerpts_with_ids_after<O>(
1651 &mut self,
1652 prev_excerpt_id: ExcerptId,
1653 buffer: Entity<Buffer>,
1654 ranges: impl IntoIterator<Item = (ExcerptId, ExcerptRange<O>)>,
1655 cx: &mut Context<Self>,
1656 ) where
1657 O: text::ToOffset,
1658 {
1659 assert_eq!(self.history.transaction_depth, 0);
1660 let mut ranges = ranges.into_iter().peekable();
1661 if ranges.peek().is_none() {
1662 return Default::default();
1663 }
1664
1665 self.sync(cx);
1666
1667 let buffer_id = buffer.read(cx).remote_id();
1668 let buffer_snapshot = buffer.read(cx).snapshot();
1669
1670 let mut buffers = self.buffers.borrow_mut();
1671 let buffer_state = buffers.entry(buffer_id).or_insert_with(|| BufferState {
1672 last_version: buffer_snapshot.version().clone(),
1673 last_non_text_state_update_count: buffer_snapshot.non_text_state_update_count(),
1674 excerpts: Default::default(),
1675 _subscriptions: [
1676 cx.observe(&buffer, |_, _, cx| cx.notify()),
1677 cx.subscribe(&buffer, Self::on_buffer_event),
1678 ],
1679 buffer: buffer.clone(),
1680 });
1681
1682 let mut snapshot = self.snapshot.borrow_mut();
1683
1684 let mut prev_locator = snapshot.excerpt_locator_for_id(prev_excerpt_id).clone();
1685 let mut new_excerpt_ids = mem::take(&mut snapshot.excerpt_ids);
1686 let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>(&());
1687 let mut new_excerpts = cursor.slice(&prev_locator, Bias::Right, &());
1688 prev_locator = cursor.start().unwrap_or(Locator::min_ref()).clone();
1689
1690 let edit_start = ExcerptOffset::new(new_excerpts.summary().text.len);
1691 new_excerpts.update_last(
1692 |excerpt| {
1693 excerpt.has_trailing_newline = true;
1694 },
1695 &(),
1696 );
1697
1698 let next_locator = if let Some(excerpt) = cursor.item() {
1699 excerpt.locator.clone()
1700 } else {
1701 Locator::max()
1702 };
1703
1704 let mut excerpts = Vec::new();
1705 while let Some((id, range)) = ranges.next() {
1706 let locator = Locator::between(&prev_locator, &next_locator);
1707 if let Err(ix) = buffer_state.excerpts.binary_search(&locator) {
1708 buffer_state.excerpts.insert(ix, locator.clone());
1709 }
1710 let range = ExcerptRange {
1711 context: buffer_snapshot.anchor_before(&range.context.start)
1712 ..buffer_snapshot.anchor_after(&range.context.end),
1713 primary: range.primary.map(|primary| {
1714 buffer_snapshot.anchor_before(&primary.start)
1715 ..buffer_snapshot.anchor_after(&primary.end)
1716 }),
1717 };
1718 excerpts.push((id, range.clone()));
1719 let excerpt = Excerpt::new(
1720 id,
1721 locator.clone(),
1722 buffer_id,
1723 buffer_snapshot.clone(),
1724 range,
1725 ranges.peek().is_some() || cursor.item().is_some(),
1726 );
1727 new_excerpts.push(excerpt, &());
1728 prev_locator = locator.clone();
1729
1730 if let Some(last_mapping_entry) = new_excerpt_ids.last() {
1731 assert!(id > last_mapping_entry.id, "excerpt ids must be increasing");
1732 }
1733 new_excerpt_ids.push(ExcerptIdMapping { id, locator }, &());
1734 }
1735
1736 let edit_end = ExcerptOffset::new(new_excerpts.summary().text.len);
1737
1738 let suffix = cursor.suffix(&());
1739 let changed_trailing_excerpt = suffix.is_empty();
1740 new_excerpts.append(suffix, &());
1741 drop(cursor);
1742 snapshot.excerpts = new_excerpts;
1743 snapshot.excerpt_ids = new_excerpt_ids;
1744 if changed_trailing_excerpt {
1745 snapshot.trailing_excerpt_update_count += 1;
1746 }
1747
1748 self.sync_diff_transforms(
1749 &mut snapshot,
1750 vec![Edit {
1751 old: edit_start..edit_start,
1752 new: edit_start..edit_end,
1753 }],
1754 DiffChangeKind::BufferEdited,
1755 );
1756 cx.emit(Event::Edited {
1757 singleton_buffer_edited: false,
1758 edited_buffer: None,
1759 });
1760 cx.emit(Event::ExcerptsAdded {
1761 buffer,
1762 predecessor: prev_excerpt_id,
1763 excerpts,
1764 });
1765 cx.notify();
1766 }
1767
1768 pub fn clear(&mut self, cx: &mut Context<Self>) {
1769 self.sync(cx);
1770 let ids = self.excerpt_ids();
1771 self.buffers.borrow_mut().clear();
1772 let mut snapshot = self.snapshot.borrow_mut();
1773 let start = ExcerptOffset::new(0);
1774 let prev_len = ExcerptOffset::new(snapshot.excerpts.summary().text.len);
1775 snapshot.excerpts = Default::default();
1776 snapshot.trailing_excerpt_update_count += 1;
1777 snapshot.is_dirty = false;
1778 snapshot.has_deleted_file = false;
1779 snapshot.has_conflict = false;
1780
1781 self.sync_diff_transforms(
1782 &mut snapshot,
1783 vec![Edit {
1784 old: start..prev_len,
1785 new: start..start,
1786 }],
1787 DiffChangeKind::BufferEdited,
1788 );
1789 cx.emit(Event::Edited {
1790 singleton_buffer_edited: false,
1791 edited_buffer: None,
1792 });
1793 cx.emit(Event::ExcerptsRemoved { ids });
1794 cx.notify();
1795 }
1796
1797 pub fn excerpts_for_buffer(
1798 &self,
1799 buffer_id: BufferId,
1800 cx: &App,
1801 ) -> Vec<(ExcerptId, ExcerptRange<text::Anchor>)> {
1802 let mut excerpts = Vec::new();
1803 let snapshot = self.read(cx);
1804 let buffers = self.buffers.borrow();
1805 let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>(&());
1806 for locator in buffers
1807 .get(&buffer_id)
1808 .map(|state| &state.excerpts)
1809 .into_iter()
1810 .flatten()
1811 {
1812 cursor.seek_forward(&Some(locator), Bias::Left, &());
1813 if let Some(excerpt) = cursor.item() {
1814 if excerpt.locator == *locator {
1815 excerpts.push((excerpt.id, excerpt.range.clone()));
1816 }
1817 }
1818 }
1819
1820 excerpts
1821 }
1822
1823 pub fn excerpt_ranges_for_buffer(&self, buffer_id: BufferId, cx: &App) -> Vec<Range<Point>> {
1824 let snapshot = self.read(cx);
1825 let buffers = self.buffers.borrow();
1826 let mut excerpts = snapshot
1827 .excerpts
1828 .cursor::<(Option<&Locator>, ExcerptDimension<Point>)>(&());
1829 let mut diff_transforms = snapshot
1830 .diff_transforms
1831 .cursor::<(ExcerptDimension<Point>, OutputDimension<Point>)>(&());
1832 diff_transforms.next(&());
1833 let locators = buffers
1834 .get(&buffer_id)
1835 .into_iter()
1836 .flat_map(|state| &state.excerpts);
1837 let mut result = Vec::new();
1838 for locator in locators {
1839 excerpts.seek_forward(&Some(locator), Bias::Left, &());
1840 if let Some(excerpt) = excerpts.item() {
1841 if excerpt.locator == *locator {
1842 let excerpt_start = excerpts.start().1.clone();
1843 let excerpt_end =
1844 ExcerptDimension(excerpt_start.0 + excerpt.text_summary.lines);
1845
1846 diff_transforms.seek_forward(&excerpt_start, Bias::Left, &());
1847 let overshoot = excerpt_start.0 - diff_transforms.start().0 .0;
1848 let start = diff_transforms.start().1 .0 + overshoot;
1849
1850 diff_transforms.seek_forward(&excerpt_end, Bias::Right, &());
1851 let overshoot = excerpt_end.0 - diff_transforms.start().0 .0;
1852 let end = diff_transforms.start().1 .0 + overshoot;
1853
1854 result.push(start..end)
1855 }
1856 }
1857 }
1858 result
1859 }
1860
1861 pub fn excerpt_buffer_ids(&self) -> Vec<BufferId> {
1862 self.snapshot
1863 .borrow()
1864 .excerpts
1865 .iter()
1866 .map(|entry| entry.buffer_id)
1867 .collect()
1868 }
1869
1870 pub fn excerpt_ids(&self) -> Vec<ExcerptId> {
1871 self.snapshot
1872 .borrow()
1873 .excerpts
1874 .iter()
1875 .map(|entry| entry.id)
1876 .collect()
1877 }
1878
1879 pub fn excerpt_containing(
1880 &self,
1881 position: impl ToOffset,
1882 cx: &App,
1883 ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
1884 let snapshot = self.read(cx);
1885 let offset = position.to_offset(&snapshot);
1886
1887 let mut cursor = snapshot.cursor::<usize>();
1888 cursor.seek(&offset);
1889 cursor
1890 .excerpt()
1891 .or_else(|| snapshot.excerpts.last())
1892 .map(|excerpt| {
1893 (
1894 excerpt.id,
1895 self.buffers
1896 .borrow()
1897 .get(&excerpt.buffer_id)
1898 .unwrap()
1899 .buffer
1900 .clone(),
1901 excerpt.range.context.clone(),
1902 )
1903 })
1904 }
1905
1906 // If point is at the end of the buffer, the last excerpt is returned
1907 pub fn point_to_buffer_offset<T: ToOffset>(
1908 &self,
1909 point: T,
1910 cx: &App,
1911 ) -> Option<(Entity<Buffer>, usize)> {
1912 let snapshot = self.read(cx);
1913 let (buffer, offset) = snapshot.point_to_buffer_offset(point)?;
1914 Some((
1915 self.buffers
1916 .borrow()
1917 .get(&buffer.remote_id())?
1918 .buffer
1919 .clone(),
1920 offset,
1921 ))
1922 }
1923
1924 // If point is at the end of the buffer, the last excerpt is returned
1925 pub fn point_to_buffer_point<T: ToPoint>(
1926 &self,
1927 point: T,
1928 cx: &App,
1929 ) -> Option<(Entity<Buffer>, Point, ExcerptId)> {
1930 let snapshot = self.read(cx);
1931 let point = point.to_point(&snapshot);
1932 let mut cursor = snapshot.cursor::<Point>();
1933 cursor.seek(&point);
1934
1935 cursor.region().and_then(|region| {
1936 if !region.is_main_buffer {
1937 return None;
1938 }
1939
1940 let overshoot = point - region.range.start;
1941 let buffer_point = region.buffer_range.start + overshoot;
1942 let buffer = self.buffers.borrow()[®ion.buffer.remote_id()]
1943 .buffer
1944 .clone();
1945 Some((buffer, buffer_point, region.excerpt.id))
1946 })
1947 }
1948
1949 pub fn buffer_point_to_anchor(
1950 &self,
1951 buffer: &Entity<Buffer>,
1952 point: Point,
1953 cx: &App,
1954 ) -> Option<Anchor> {
1955 let mut found = None;
1956 let snapshot = buffer.read(cx).snapshot();
1957 for (excerpt_id, range) in self.excerpts_for_buffer(snapshot.remote_id(), cx) {
1958 let start = range.context.start.to_point(&snapshot);
1959 let end = range.context.end.to_point(&snapshot);
1960 if start <= point && point < end {
1961 found = Some((snapshot.clip_point(point, Bias::Left), excerpt_id));
1962 break;
1963 }
1964 if point < start {
1965 found = Some((start, excerpt_id));
1966 }
1967 if point > end {
1968 found = Some((end, excerpt_id));
1969 }
1970 }
1971
1972 found.map(|(point, excerpt_id)| {
1973 let text_anchor = snapshot.anchor_after(point);
1974 Anchor::in_buffer(excerpt_id, snapshot.remote_id(), text_anchor)
1975 })
1976 }
1977
1978 pub fn remove_excerpts(
1979 &mut self,
1980 excerpt_ids: impl IntoIterator<Item = ExcerptId>,
1981 cx: &mut Context<Self>,
1982 ) {
1983 self.sync(cx);
1984 let ids = excerpt_ids.into_iter().collect::<Vec<_>>();
1985 if ids.is_empty() {
1986 return;
1987 }
1988
1989 let mut buffers = self.buffers.borrow_mut();
1990 let mut snapshot = self.snapshot.borrow_mut();
1991 let mut new_excerpts = SumTree::default();
1992 let mut cursor = snapshot
1993 .excerpts
1994 .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
1995 let mut edits = Vec::new();
1996 let mut excerpt_ids = ids.iter().copied().peekable();
1997
1998 while let Some(excerpt_id) = excerpt_ids.next() {
1999 // Seek to the next excerpt to remove, preserving any preceding excerpts.
2000 let locator = snapshot.excerpt_locator_for_id(excerpt_id);
2001 new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &());
2002
2003 if let Some(mut excerpt) = cursor.item() {
2004 if excerpt.id != excerpt_id {
2005 continue;
2006 }
2007 let mut old_start = cursor.start().1;
2008
2009 // Skip over the removed excerpt.
2010 'remove_excerpts: loop {
2011 if let Some(buffer_state) = buffers.get_mut(&excerpt.buffer_id) {
2012 buffer_state.excerpts.retain(|l| l != &excerpt.locator);
2013 if buffer_state.excerpts.is_empty() {
2014 buffers.remove(&excerpt.buffer_id);
2015 }
2016 }
2017 cursor.next(&());
2018
2019 // Skip over any subsequent excerpts that are also removed.
2020 if let Some(&next_excerpt_id) = excerpt_ids.peek() {
2021 let next_locator = snapshot.excerpt_locator_for_id(next_excerpt_id);
2022 if let Some(next_excerpt) = cursor.item() {
2023 if next_excerpt.locator == *next_locator {
2024 excerpt_ids.next();
2025 excerpt = next_excerpt;
2026 continue 'remove_excerpts;
2027 }
2028 }
2029 }
2030
2031 break;
2032 }
2033
2034 // When removing the last excerpt, remove the trailing newline from
2035 // the previous excerpt.
2036 if cursor.item().is_none() && old_start.value > 0 {
2037 old_start.value -= 1;
2038 new_excerpts.update_last(|e| e.has_trailing_newline = false, &());
2039 }
2040
2041 // Push an edit for the removal of this run of excerpts.
2042 let old_end = cursor.start().1;
2043 let new_start = ExcerptOffset::new(new_excerpts.summary().text.len);
2044 edits.push(Edit {
2045 old: old_start..old_end,
2046 new: new_start..new_start,
2047 });
2048 }
2049 }
2050 let suffix = cursor.suffix(&());
2051 let changed_trailing_excerpt = suffix.is_empty();
2052 new_excerpts.append(suffix, &());
2053 drop(cursor);
2054 snapshot.excerpts = new_excerpts;
2055
2056 if changed_trailing_excerpt {
2057 snapshot.trailing_excerpt_update_count += 1;
2058 }
2059
2060 self.sync_diff_transforms(&mut snapshot, edits, DiffChangeKind::BufferEdited);
2061 cx.emit(Event::Edited {
2062 singleton_buffer_edited: false,
2063 edited_buffer: None,
2064 });
2065 cx.emit(Event::ExcerptsRemoved { ids });
2066 cx.notify();
2067 }
2068
2069 pub fn wait_for_anchors<'a>(
2070 &self,
2071 anchors: impl 'a + Iterator<Item = Anchor>,
2072 cx: &mut Context<Self>,
2073 ) -> impl 'static + Future<Output = Result<()>> {
2074 let borrow = self.buffers.borrow();
2075 let mut error = None;
2076 let mut futures = Vec::new();
2077 for anchor in anchors {
2078 if let Some(buffer_id) = anchor.buffer_id {
2079 if let Some(buffer) = borrow.get(&buffer_id) {
2080 buffer.buffer.update(cx, |buffer, _| {
2081 futures.push(buffer.wait_for_anchors([anchor.text_anchor]))
2082 });
2083 } else {
2084 error = Some(anyhow!(
2085 "buffer {buffer_id} is not part of this multi-buffer"
2086 ));
2087 break;
2088 }
2089 }
2090 }
2091 async move {
2092 if let Some(error) = error {
2093 Err(error)?;
2094 }
2095 for future in futures {
2096 future.await?;
2097 }
2098 Ok(())
2099 }
2100 }
2101
2102 pub fn text_anchor_for_position<T: ToOffset>(
2103 &self,
2104 position: T,
2105 cx: &App,
2106 ) -> Option<(Entity<Buffer>, language::Anchor)> {
2107 let snapshot = self.read(cx);
2108 let anchor = snapshot.anchor_before(position);
2109 let buffer = self
2110 .buffers
2111 .borrow()
2112 .get(&anchor.buffer_id?)?
2113 .buffer
2114 .clone();
2115 Some((buffer, anchor.text_anchor))
2116 }
2117
2118 fn on_buffer_event(
2119 &mut self,
2120 buffer: Entity<Buffer>,
2121 event: &language::BufferEvent,
2122 cx: &mut Context<Self>,
2123 ) {
2124 cx.emit(match event {
2125 language::BufferEvent::Edited => Event::Edited {
2126 singleton_buffer_edited: true,
2127 edited_buffer: Some(buffer.clone()),
2128 },
2129 language::BufferEvent::DirtyChanged => Event::DirtyChanged,
2130 language::BufferEvent::Saved => Event::Saved,
2131 language::BufferEvent::FileHandleChanged => Event::FileHandleChanged,
2132 language::BufferEvent::Reloaded => Event::Reloaded,
2133 language::BufferEvent::ReloadNeeded => Event::ReloadNeeded,
2134 language::BufferEvent::LanguageChanged => {
2135 Event::LanguageChanged(buffer.read(cx).remote_id())
2136 }
2137 language::BufferEvent::Reparsed => Event::Reparsed(buffer.read(cx).remote_id()),
2138 language::BufferEvent::DiagnosticsUpdated => Event::DiagnosticsUpdated,
2139 language::BufferEvent::Closed => Event::Closed,
2140 language::BufferEvent::Discarded => Event::Discarded,
2141 language::BufferEvent::CapabilityChanged => {
2142 self.capability = buffer.read(cx).capability();
2143 Event::CapabilityChanged
2144 }
2145 language::BufferEvent::Operation { .. } => return,
2146 });
2147 }
2148
2149 fn buffer_diff_changed(
2150 &mut self,
2151 change_set: Entity<BufferChangeSet>,
2152 range: Range<text::Anchor>,
2153 cx: &mut Context<Self>,
2154 ) {
2155 let change_set = change_set.read(cx);
2156 let buffer_id = change_set.buffer_id;
2157 let diff = change_set.diff_to_buffer.clone();
2158 let base_text = change_set.base_text.clone();
2159 self.sync(cx);
2160 let mut snapshot = self.snapshot.borrow_mut();
2161 let base_text_changed = snapshot
2162 .diffs
2163 .get(&buffer_id)
2164 .map_or(true, |diff_snapshot| {
2165 change_set.base_text.as_ref().map_or(true, |base_text| {
2166 base_text.remote_id() != diff_snapshot.base_text.remote_id()
2167 })
2168 });
2169
2170 if let Some(base_text) = base_text {
2171 snapshot.diffs.insert(
2172 buffer_id,
2173 DiffSnapshot {
2174 diff: diff.clone(),
2175 base_text,
2176 },
2177 );
2178 } else {
2179 snapshot.diffs.remove(&buffer_id);
2180 }
2181 let buffers = self.buffers.borrow();
2182 let Some(buffer_state) = buffers.get(&buffer_id) else {
2183 return;
2184 };
2185
2186 let diff_change_range = range.to_offset(buffer_state.buffer.read(cx));
2187
2188 let mut excerpt_edits = Vec::new();
2189 for locator in &buffer_state.excerpts {
2190 let mut cursor = snapshot
2191 .excerpts
2192 .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
2193 cursor.seek_forward(&Some(locator), Bias::Left, &());
2194 if let Some(excerpt) = cursor.item() {
2195 if excerpt.locator == *locator {
2196 let excerpt_buffer_range = excerpt.range.context.to_offset(&excerpt.buffer);
2197 if diff_change_range.end < excerpt_buffer_range.start
2198 || diff_change_range.start > excerpt_buffer_range.end
2199 {
2200 continue;
2201 }
2202 let excerpt_start = cursor.start().1;
2203 let excerpt_len = ExcerptOffset::new(excerpt.text_summary.len);
2204 let diff_change_start_in_excerpt = ExcerptOffset::new(
2205 diff_change_range
2206 .start
2207 .saturating_sub(excerpt_buffer_range.start),
2208 );
2209 let diff_change_end_in_excerpt = ExcerptOffset::new(
2210 diff_change_range
2211 .end
2212 .saturating_sub(excerpt_buffer_range.start),
2213 );
2214 let edit_start = excerpt_start + diff_change_start_in_excerpt.min(excerpt_len);
2215 let edit_end = excerpt_start + diff_change_end_in_excerpt.min(excerpt_len);
2216 excerpt_edits.push(Edit {
2217 old: edit_start..edit_end,
2218 new: edit_start..edit_end,
2219 });
2220 }
2221 }
2222 }
2223
2224 self.sync_diff_transforms(
2225 &mut snapshot,
2226 excerpt_edits,
2227 DiffChangeKind::DiffUpdated {
2228 base_changed: base_text_changed,
2229 },
2230 );
2231 cx.emit(Event::Edited {
2232 singleton_buffer_edited: false,
2233 edited_buffer: None,
2234 });
2235 }
2236
2237 pub fn all_buffers(&self) -> HashSet<Entity<Buffer>> {
2238 self.buffers
2239 .borrow()
2240 .values()
2241 .map(|state| state.buffer.clone())
2242 .collect()
2243 }
2244
2245 pub fn buffer(&self, buffer_id: BufferId) -> Option<Entity<Buffer>> {
2246 self.buffers
2247 .borrow()
2248 .get(&buffer_id)
2249 .map(|state| state.buffer.clone())
2250 }
2251
2252 pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
2253 self.point_to_buffer_offset(point, cx)
2254 .and_then(|(buffer, offset)| buffer.read(cx).language_at(offset))
2255 }
2256
2257 pub fn settings_at<'a, T: ToOffset>(&self, point: T, cx: &'a App) -> Cow<'a, LanguageSettings> {
2258 let mut language = None;
2259 let mut file = None;
2260 if let Some((buffer, offset)) = self.point_to_buffer_offset(point, cx) {
2261 let buffer = buffer.read(cx);
2262 language = buffer.language_at(offset);
2263 file = buffer.file();
2264 }
2265 language_settings(language.map(|l| l.name()), file, cx)
2266 }
2267
2268 pub fn for_each_buffer(&self, mut f: impl FnMut(&Entity<Buffer>)) {
2269 self.buffers
2270 .borrow()
2271 .values()
2272 .for_each(|state| f(&state.buffer))
2273 }
2274
2275 pub fn title<'a>(&'a self, cx: &'a App) -> Cow<'a, str> {
2276 if let Some(title) = self.title.as_ref() {
2277 return title.into();
2278 }
2279
2280 if let Some(buffer) = self.as_singleton() {
2281 if let Some(file) = buffer.read(cx).file() {
2282 return file.file_name(cx).to_string_lossy();
2283 }
2284 }
2285
2286 "untitled".into()
2287 }
2288
2289 pub fn set_title(&mut self, title: String, cx: &mut Context<Self>) {
2290 self.title = Some(title);
2291 cx.notify();
2292 }
2293
2294 /// Preserve preview tabs containing this multibuffer until additional edits occur.
2295 pub fn refresh_preview(&self, cx: &mut Context<Self>) {
2296 for buffer_state in self.buffers.borrow().values() {
2297 buffer_state
2298 .buffer
2299 .update(cx, |buffer, _cx| buffer.refresh_preview());
2300 }
2301 }
2302
2303 /// Whether we should preserve the preview status of a tab containing this multi-buffer.
2304 pub fn preserve_preview(&self, cx: &App) -> bool {
2305 self.buffers
2306 .borrow()
2307 .values()
2308 .all(|state| state.buffer.read(cx).preserve_preview())
2309 }
2310
2311 #[cfg(any(test, feature = "test-support"))]
2312 pub fn is_parsing(&self, cx: &App) -> bool {
2313 self.as_singleton().unwrap().read(cx).is_parsing()
2314 }
2315
2316 pub fn add_change_set(&mut self, change_set: Entity<BufferChangeSet>, cx: &mut Context<Self>) {
2317 let buffer_id = change_set.read(cx).buffer_id;
2318 self.buffer_diff_changed(change_set.clone(), text::Anchor::MIN..text::Anchor::MAX, cx);
2319 self.diff_bases.insert(
2320 buffer_id,
2321 ChangeSetState {
2322 _subscription: cx.subscribe(
2323 &change_set,
2324 |this, change_set, event, cx| match event {
2325 BufferChangeSetEvent::DiffChanged { changed_range } => {
2326 this.buffer_diff_changed(change_set, changed_range.clone(), cx);
2327 }
2328 },
2329 ),
2330 change_set,
2331 },
2332 );
2333 }
2334
2335 pub fn change_set_for(&self, buffer_id: BufferId) -> Option<Entity<BufferChangeSet>> {
2336 self.diff_bases
2337 .get(&buffer_id)
2338 .map(|state| state.change_set.clone())
2339 }
2340
2341 pub fn expand_diff_hunks(&mut self, ranges: Vec<Range<Anchor>>, cx: &mut Context<Self>) {
2342 self.expand_or_collapse_diff_hunks(ranges, true, cx);
2343 }
2344
2345 pub fn collapse_diff_hunks(&mut self, ranges: Vec<Range<Anchor>>, cx: &mut Context<Self>) {
2346 self.expand_or_collapse_diff_hunks(ranges, false, cx);
2347 }
2348
2349 pub fn set_all_diff_hunks_expanded(&mut self, cx: &mut Context<Self>) {
2350 self.all_diff_hunks_expanded = true;
2351 self.expand_or_collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], true, cx);
2352 }
2353
2354 pub fn all_diff_hunks_expanded(&mut self) -> bool {
2355 self.all_diff_hunks_expanded
2356 }
2357
2358 pub fn has_multiple_hunks(&self, cx: &App) -> bool {
2359 self.read(cx)
2360 .diff_hunks_in_range(Anchor::min()..Anchor::max())
2361 .nth(1)
2362 .is_some()
2363 }
2364
2365 pub fn has_expanded_diff_hunks_in_ranges(&self, ranges: &[Range<Anchor>], cx: &App) -> bool {
2366 let snapshot = self.read(cx);
2367 let mut cursor = snapshot.diff_transforms.cursor::<usize>(&());
2368 for range in ranges {
2369 let range = range.to_point(&snapshot);
2370 let start = snapshot.point_to_offset(Point::new(range.start.row, 0));
2371 let end = snapshot.point_to_offset(Point::new(range.end.row + 1, 0));
2372 let start = start.saturating_sub(1);
2373 let end = snapshot.len().min(end + 1);
2374 cursor.seek(&start, Bias::Right, &());
2375 while let Some(item) = cursor.item() {
2376 if *cursor.start() >= end {
2377 break;
2378 }
2379 if item.hunk_anchor().is_some() {
2380 return true;
2381 }
2382 cursor.next(&());
2383 }
2384 }
2385 false
2386 }
2387
2388 fn expand_or_collapse_diff_hunks(
2389 &mut self,
2390 ranges: Vec<Range<Anchor>>,
2391 expand: bool,
2392 cx: &mut Context<Self>,
2393 ) {
2394 self.sync(cx);
2395 let mut snapshot = self.snapshot.borrow_mut();
2396 let mut excerpt_edits = Vec::new();
2397 for range in ranges.iter() {
2398 let end_excerpt_id = range.end.excerpt_id;
2399 let range = range.to_point(&snapshot);
2400 let mut peek_end = range.end;
2401 if range.end.row < snapshot.max_row().0 {
2402 peek_end = Point::new(range.end.row + 1, 0);
2403 };
2404
2405 for diff_hunk in snapshot.diff_hunks_in_range(range.start..peek_end) {
2406 if diff_hunk.excerpt_id.cmp(&end_excerpt_id, &snapshot).is_gt() {
2407 continue;
2408 }
2409 let start = Anchor::in_buffer(
2410 diff_hunk.excerpt_id,
2411 diff_hunk.buffer_id,
2412 diff_hunk.buffer_range.start,
2413 );
2414 let end = Anchor::in_buffer(
2415 diff_hunk.excerpt_id,
2416 diff_hunk.buffer_id,
2417 diff_hunk.buffer_range.end,
2418 );
2419 let start = snapshot.excerpt_offset_for_anchor(&start);
2420 let end = snapshot.excerpt_offset_for_anchor(&end);
2421 excerpt_edits.push(text::Edit {
2422 old: start..end,
2423 new: start..end,
2424 });
2425 }
2426 }
2427
2428 self.sync_diff_transforms(
2429 &mut snapshot,
2430 excerpt_edits,
2431 DiffChangeKind::ExpandOrCollapseHunks { expand },
2432 );
2433 cx.emit(Event::DiffHunksToggled);
2434 cx.emit(Event::Edited {
2435 singleton_buffer_edited: false,
2436 edited_buffer: None,
2437 });
2438 }
2439
2440 pub fn resize_excerpt(
2441 &mut self,
2442 id: ExcerptId,
2443 range: Range<text::Anchor>,
2444 cx: &mut Context<Self>,
2445 ) {
2446 self.sync(cx);
2447
2448 let mut snapshot = self.snapshot.borrow_mut();
2449 let locator = snapshot.excerpt_locator_for_id(id);
2450 let mut new_excerpts = SumTree::default();
2451 let mut cursor = snapshot
2452 .excerpts
2453 .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
2454 let mut edits = Vec::<Edit<ExcerptOffset>>::new();
2455
2456 let prefix = cursor.slice(&Some(locator), Bias::Left, &());
2457 new_excerpts.append(prefix, &());
2458
2459 let mut excerpt = cursor.item().unwrap().clone();
2460 let old_text_len = ExcerptOffset::new(excerpt.text_summary.len);
2461
2462 excerpt.range.context.start = range.start;
2463 excerpt.range.context.end = range.end;
2464 excerpt.max_buffer_row = range.end.to_point(&excerpt.buffer).row;
2465
2466 excerpt.text_summary = excerpt
2467 .buffer
2468 .text_summary_for_range(excerpt.range.context.clone());
2469
2470 let new_start_offset = ExcerptOffset::new(new_excerpts.summary().text.len);
2471 let old_start_offset = cursor.start().1;
2472 let new_text_len = ExcerptOffset::new(excerpt.text_summary.len);
2473 let edit = Edit {
2474 old: old_start_offset..old_start_offset + old_text_len,
2475 new: new_start_offset..new_start_offset + new_text_len,
2476 };
2477
2478 if let Some(last_edit) = edits.last_mut() {
2479 if last_edit.old.end == edit.old.start {
2480 last_edit.old.end = edit.old.end;
2481 last_edit.new.end = edit.new.end;
2482 } else {
2483 edits.push(edit);
2484 }
2485 } else {
2486 edits.push(edit);
2487 }
2488
2489 new_excerpts.push(excerpt, &());
2490
2491 cursor.next(&());
2492
2493 new_excerpts.append(cursor.suffix(&()), &());
2494
2495 drop(cursor);
2496 snapshot.excerpts = new_excerpts;
2497
2498 self.sync_diff_transforms(&mut snapshot, edits, DiffChangeKind::BufferEdited);
2499 cx.emit(Event::Edited {
2500 singleton_buffer_edited: false,
2501 edited_buffer: None,
2502 });
2503 cx.emit(Event::ExcerptsExpanded { ids: vec![id] });
2504 cx.notify();
2505 }
2506
2507 pub fn expand_excerpts(
2508 &mut self,
2509 ids: impl IntoIterator<Item = ExcerptId>,
2510 line_count: u32,
2511 direction: ExpandExcerptDirection,
2512 cx: &mut Context<Self>,
2513 ) {
2514 if line_count == 0 {
2515 return;
2516 }
2517 self.sync(cx);
2518 let mut snapshot = self.snapshot.borrow_mut();
2519
2520 let ids = ids.into_iter().collect::<Vec<_>>();
2521 let locators = snapshot.excerpt_locators_for_ids(ids.iter().copied());
2522 let mut new_excerpts = SumTree::default();
2523 let mut cursor = snapshot
2524 .excerpts
2525 .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
2526 let mut edits = Vec::<Edit<ExcerptOffset>>::new();
2527
2528 for locator in &locators {
2529 let prefix = cursor.slice(&Some(locator), Bias::Left, &());
2530 new_excerpts.append(prefix, &());
2531
2532 let mut excerpt = cursor.item().unwrap().clone();
2533 let old_text_len = ExcerptOffset::new(excerpt.text_summary.len);
2534
2535 let up_line_count = if direction.should_expand_up() {
2536 line_count
2537 } else {
2538 0
2539 };
2540
2541 let start_row = excerpt
2542 .range
2543 .context
2544 .start
2545 .to_point(&excerpt.buffer)
2546 .row
2547 .saturating_sub(up_line_count);
2548 let start_point = Point::new(start_row, 0);
2549 excerpt.range.context.start = excerpt.buffer.anchor_before(start_point);
2550
2551 let down_line_count = if direction.should_expand_down() {
2552 line_count
2553 } else {
2554 0
2555 };
2556
2557 let mut end_point = excerpt.buffer.clip_point(
2558 excerpt.range.context.end.to_point(&excerpt.buffer)
2559 + Point::new(down_line_count, 0),
2560 Bias::Left,
2561 );
2562 end_point.column = excerpt.buffer.line_len(end_point.row);
2563 excerpt.range.context.end = excerpt.buffer.anchor_after(end_point);
2564 excerpt.max_buffer_row = end_point.row;
2565
2566 excerpt.text_summary = excerpt
2567 .buffer
2568 .text_summary_for_range(excerpt.range.context.clone());
2569
2570 let new_start_offset = ExcerptOffset::new(new_excerpts.summary().text.len);
2571 let old_start_offset = cursor.start().1;
2572 let new_text_len = ExcerptOffset::new(excerpt.text_summary.len);
2573 let edit = Edit {
2574 old: old_start_offset..old_start_offset + old_text_len,
2575 new: new_start_offset..new_start_offset + new_text_len,
2576 };
2577
2578 if let Some(last_edit) = edits.last_mut() {
2579 if last_edit.old.end == edit.old.start {
2580 last_edit.old.end = edit.old.end;
2581 last_edit.new.end = edit.new.end;
2582 } else {
2583 edits.push(edit);
2584 }
2585 } else {
2586 edits.push(edit);
2587 }
2588
2589 new_excerpts.push(excerpt, &());
2590
2591 cursor.next(&());
2592 }
2593
2594 new_excerpts.append(cursor.suffix(&()), &());
2595
2596 drop(cursor);
2597 snapshot.excerpts = new_excerpts;
2598
2599 self.sync_diff_transforms(&mut snapshot, edits, DiffChangeKind::BufferEdited);
2600 cx.emit(Event::Edited {
2601 singleton_buffer_edited: false,
2602 edited_buffer: None,
2603 });
2604 cx.emit(Event::ExcerptsExpanded { ids });
2605 cx.notify();
2606 }
2607
2608 fn sync(&self, cx: &App) {
2609 let mut snapshot = self.snapshot.borrow_mut();
2610 let mut excerpts_to_edit = Vec::new();
2611 let mut non_text_state_updated = false;
2612 let mut is_dirty = false;
2613 let mut has_deleted_file = false;
2614 let mut has_conflict = false;
2615 let mut edited = false;
2616 let mut buffers = self.buffers.borrow_mut();
2617 for buffer_state in buffers.values_mut() {
2618 let buffer = buffer_state.buffer.read(cx);
2619 let version = buffer.version();
2620 let non_text_state_update_count = buffer.non_text_state_update_count();
2621
2622 let buffer_edited = version.changed_since(&buffer_state.last_version);
2623 let buffer_non_text_state_updated =
2624 non_text_state_update_count > buffer_state.last_non_text_state_update_count;
2625 if buffer_edited || buffer_non_text_state_updated {
2626 buffer_state.last_version = version;
2627 buffer_state.last_non_text_state_update_count = non_text_state_update_count;
2628 excerpts_to_edit.extend(
2629 buffer_state
2630 .excerpts
2631 .iter()
2632 .map(|locator| (locator, buffer_state.buffer.clone(), buffer_edited)),
2633 );
2634 }
2635
2636 edited |= buffer_edited;
2637 non_text_state_updated |= buffer_non_text_state_updated;
2638 is_dirty |= buffer.is_dirty();
2639 has_deleted_file |= buffer
2640 .file()
2641 .map_or(false, |file| file.disk_state() == DiskState::Deleted);
2642 has_conflict |= buffer.has_conflict();
2643 }
2644 if edited {
2645 snapshot.edit_count += 1;
2646 }
2647 if non_text_state_updated {
2648 snapshot.non_text_state_update_count += 1;
2649 }
2650 snapshot.is_dirty = is_dirty;
2651 snapshot.has_deleted_file = has_deleted_file;
2652 snapshot.has_conflict = has_conflict;
2653
2654 excerpts_to_edit.sort_unstable_by_key(|(locator, _, _)| *locator);
2655
2656 let mut edits = Vec::new();
2657 let mut new_excerpts = SumTree::default();
2658 let mut cursor = snapshot
2659 .excerpts
2660 .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
2661
2662 for (locator, buffer, buffer_edited) in excerpts_to_edit {
2663 new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &());
2664 let old_excerpt = cursor.item().unwrap();
2665 let buffer = buffer.read(cx);
2666 let buffer_id = buffer.remote_id();
2667
2668 let mut new_excerpt;
2669 if buffer_edited {
2670 edits.extend(
2671 buffer
2672 .edits_since_in_range::<usize>(
2673 old_excerpt.buffer.version(),
2674 old_excerpt.range.context.clone(),
2675 )
2676 .map(|edit| {
2677 let excerpt_old_start = cursor.start().1;
2678 let excerpt_new_start =
2679 ExcerptOffset::new(new_excerpts.summary().text.len);
2680 let old_start = excerpt_old_start + ExcerptOffset::new(edit.old.start);
2681 let old_end = excerpt_old_start + ExcerptOffset::new(edit.old.end);
2682 let new_start = excerpt_new_start + ExcerptOffset::new(edit.new.start);
2683 let new_end = excerpt_new_start + ExcerptOffset::new(edit.new.end);
2684 Edit {
2685 old: old_start..old_end,
2686 new: new_start..new_end,
2687 }
2688 }),
2689 );
2690
2691 new_excerpt = Excerpt::new(
2692 old_excerpt.id,
2693 locator.clone(),
2694 buffer_id,
2695 buffer.snapshot(),
2696 old_excerpt.range.clone(),
2697 old_excerpt.has_trailing_newline,
2698 );
2699 } else {
2700 new_excerpt = old_excerpt.clone();
2701 new_excerpt.buffer = buffer.snapshot();
2702 }
2703
2704 new_excerpts.push(new_excerpt, &());
2705 cursor.next(&());
2706 }
2707 new_excerpts.append(cursor.suffix(&()), &());
2708
2709 drop(cursor);
2710 snapshot.excerpts = new_excerpts;
2711
2712 self.sync_diff_transforms(&mut snapshot, edits, DiffChangeKind::BufferEdited);
2713 }
2714
2715 fn sync_diff_transforms(
2716 &self,
2717 snapshot: &mut MultiBufferSnapshot,
2718 excerpt_edits: Vec<text::Edit<ExcerptOffset>>,
2719 change_kind: DiffChangeKind,
2720 ) {
2721 if excerpt_edits.is_empty() {
2722 return;
2723 }
2724
2725 let mut excerpts = snapshot.excerpts.cursor::<ExcerptOffset>(&());
2726 let mut old_diff_transforms = snapshot
2727 .diff_transforms
2728 .cursor::<(ExcerptOffset, usize)>(&());
2729 let mut new_diff_transforms = SumTree::default();
2730 let mut old_expanded_hunks = HashSet::default();
2731 let mut output_edits = Vec::new();
2732 let mut output_delta = 0_isize;
2733 let mut at_transform_boundary = true;
2734 let mut end_of_current_insert = None;
2735
2736 let mut excerpt_edits = excerpt_edits.into_iter().peekable();
2737 while let Some(edit) = excerpt_edits.next() {
2738 excerpts.seek_forward(&edit.new.start, Bias::Right, &());
2739 if excerpts.item().is_none() && *excerpts.start() == edit.new.start {
2740 excerpts.prev(&());
2741 }
2742
2743 // Keep any transforms that are before the edit.
2744 if at_transform_boundary {
2745 at_transform_boundary = false;
2746 let transforms_before_edit =
2747 old_diff_transforms.slice(&edit.old.start, Bias::Left, &());
2748 self.append_diff_transforms(&mut new_diff_transforms, transforms_before_edit);
2749 if let Some(transform) = old_diff_transforms.item() {
2750 if old_diff_transforms.end(&()).0 == edit.old.start
2751 && old_diff_transforms.start().0 < edit.old.start
2752 {
2753 self.push_diff_transform(&mut new_diff_transforms, transform.clone());
2754 old_diff_transforms.next(&());
2755 }
2756 }
2757 }
2758
2759 // Compute the start of the edit in output coordinates.
2760 let edit_start_overshoot = (edit.old.start - old_diff_transforms.start().0).value;
2761 let edit_old_start = old_diff_transforms.start().1 + edit_start_overshoot;
2762 let edit_new_start = (edit_old_start as isize + output_delta) as usize;
2763
2764 let changed_diff_hunks = self.recompute_diff_transforms_for_edit(
2765 &edit,
2766 &mut excerpts,
2767 &mut old_diff_transforms,
2768 &mut new_diff_transforms,
2769 &mut end_of_current_insert,
2770 &mut old_expanded_hunks,
2771 &snapshot,
2772 change_kind,
2773 );
2774
2775 // Compute the end of the edit in output coordinates.
2776 let edit_old_end_overshoot = edit.old.end - old_diff_transforms.start().0;
2777 let edit_new_end_overshoot = edit.new.end - new_diff_transforms.summary().excerpt_len();
2778 let edit_old_end = old_diff_transforms.start().1 + edit_old_end_overshoot.value;
2779 let edit_new_end =
2780 new_diff_transforms.summary().output.len + edit_new_end_overshoot.value;
2781 let output_edit = Edit {
2782 old: edit_old_start..edit_old_end,
2783 new: edit_new_start..edit_new_end,
2784 };
2785
2786 output_delta += (output_edit.new.end - output_edit.new.start) as isize;
2787 output_delta -= (output_edit.old.end - output_edit.old.start) as isize;
2788 if changed_diff_hunks || matches!(change_kind, DiffChangeKind::BufferEdited) {
2789 output_edits.push(output_edit);
2790 }
2791
2792 // If this is the last edit that intersects the current diff transform,
2793 // then recreate the content up to the end of this transform, to prepare
2794 // for reusing additional slices of the old transforms.
2795 if excerpt_edits.peek().map_or(true, |next_edit| {
2796 next_edit.old.start >= old_diff_transforms.end(&()).0
2797 }) {
2798 let keep_next_old_transform = (old_diff_transforms.start().0 >= edit.old.end)
2799 && match old_diff_transforms.item() {
2800 Some(DiffTransform::BufferContent {
2801 inserted_hunk_anchor: Some(hunk_anchor),
2802 ..
2803 }) => excerpts
2804 .item()
2805 .is_some_and(|excerpt| hunk_anchor.1.is_valid(&excerpt.buffer)),
2806 _ => true,
2807 };
2808
2809 let mut excerpt_offset = edit.new.end;
2810 if !keep_next_old_transform {
2811 excerpt_offset += old_diff_transforms.end(&()).0 - edit.old.end;
2812 old_diff_transforms.next(&());
2813 }
2814
2815 old_expanded_hunks.clear();
2816 self.push_buffer_content_transform(
2817 &snapshot,
2818 &mut new_diff_transforms,
2819 excerpt_offset,
2820 end_of_current_insert,
2821 );
2822 at_transform_boundary = true;
2823 }
2824 }
2825
2826 // Keep any transforms that are after the last edit.
2827 self.append_diff_transforms(&mut new_diff_transforms, old_diff_transforms.suffix(&()));
2828
2829 // Ensure there's always at least one buffer content transform.
2830 if new_diff_transforms.is_empty() {
2831 new_diff_transforms.push(
2832 DiffTransform::BufferContent {
2833 summary: Default::default(),
2834 inserted_hunk_anchor: None,
2835 },
2836 &(),
2837 );
2838 }
2839
2840 self.subscriptions.publish(output_edits);
2841 drop(old_diff_transforms);
2842 drop(excerpts);
2843 snapshot.diff_transforms = new_diff_transforms;
2844 snapshot.edit_count += 1;
2845
2846 #[cfg(any(test, feature = "test-support"))]
2847 snapshot.check_invariants();
2848 }
2849
2850 #[allow(clippy::too_many_arguments)]
2851 fn recompute_diff_transforms_for_edit(
2852 &self,
2853 edit: &Edit<TypedOffset<Excerpt>>,
2854 excerpts: &mut Cursor<Excerpt, TypedOffset<Excerpt>>,
2855 old_diff_transforms: &mut Cursor<DiffTransform, (TypedOffset<Excerpt>, usize)>,
2856 new_diff_transforms: &mut SumTree<DiffTransform>,
2857 end_of_current_insert: &mut Option<(TypedOffset<Excerpt>, ExcerptId, text::Anchor)>,
2858 old_expanded_hunks: &mut HashSet<(ExcerptId, text::Anchor)>,
2859 snapshot: &MultiBufferSnapshot,
2860 change_kind: DiffChangeKind,
2861 ) -> bool {
2862 log::trace!(
2863 "recomputing diff transform for edit {:?} => {:?}",
2864 edit.old.start.value..edit.old.end.value,
2865 edit.new.start.value..edit.new.end.value
2866 );
2867
2868 // Record which hunks were previously expanded.
2869 while let Some(item) = old_diff_transforms.item() {
2870 if let Some(hunk_anchor) = item.hunk_anchor() {
2871 log::trace!(
2872 "previously expanded hunk at {}",
2873 old_diff_transforms.start().0
2874 );
2875 old_expanded_hunks.insert(hunk_anchor);
2876 }
2877 if old_diff_transforms.end(&()).0 > edit.old.end {
2878 break;
2879 }
2880 old_diff_transforms.next(&());
2881 }
2882
2883 // Avoid querying diff hunks if there's no possibility of hunks being expanded.
2884 if old_expanded_hunks.is_empty()
2885 && change_kind == DiffChangeKind::BufferEdited
2886 && !self.all_diff_hunks_expanded
2887 {
2888 return false;
2889 }
2890
2891 // Visit each excerpt that intersects the edit.
2892 let mut did_expand_hunks = false;
2893 while let Some(excerpt) = excerpts.item() {
2894 // Recompute the expanded hunks in the portion of the excerpt that
2895 // intersects the edit.
2896 if let Some(diff_state) = snapshot.diffs.get(&excerpt.buffer_id) {
2897 let diff = &diff_state.diff;
2898 let base_text = &diff_state.base_text;
2899 let buffer = &excerpt.buffer;
2900 let excerpt_start = *excerpts.start();
2901 let excerpt_end = excerpt_start + ExcerptOffset::new(excerpt.text_summary.len);
2902 let excerpt_buffer_start = excerpt.range.context.start.to_offset(buffer);
2903 let excerpt_buffer_end = excerpt_buffer_start + excerpt.text_summary.len;
2904 let edit_buffer_start =
2905 excerpt_buffer_start + edit.new.start.value.saturating_sub(excerpt_start.value);
2906 let edit_buffer_end =
2907 excerpt_buffer_start + edit.new.end.value.saturating_sub(excerpt_start.value);
2908 let edit_buffer_end = edit_buffer_end.min(excerpt_buffer_end);
2909 let edit_anchor_range =
2910 buffer.anchor_before(edit_buffer_start)..buffer.anchor_after(edit_buffer_end);
2911
2912 for hunk in diff.hunks_intersecting_range(edit_anchor_range, buffer) {
2913 let hunk_buffer_range = hunk.buffer_range.to_offset(buffer);
2914
2915 let hunk_anchor = (excerpt.id, hunk.buffer_range.start);
2916 if hunk_buffer_range.start < excerpt_buffer_start {
2917 log::trace!("skipping hunk that starts before excerpt");
2918 continue;
2919 }
2920
2921 let hunk_excerpt_start = excerpt_start
2922 + ExcerptOffset::new(
2923 hunk_buffer_range.start.saturating_sub(excerpt_buffer_start),
2924 );
2925 let hunk_excerpt_end = excerpt_end.min(
2926 excerpt_start
2927 + ExcerptOffset::new(hunk_buffer_range.end - excerpt_buffer_start),
2928 );
2929
2930 self.push_buffer_content_transform(
2931 snapshot,
2932 new_diff_transforms,
2933 hunk_excerpt_start,
2934 *end_of_current_insert,
2935 );
2936
2937 // For every existing hunk, determine if it was previously expanded
2938 // and if it should currently be expanded.
2939 let was_previously_expanded = old_expanded_hunks.contains(&hunk_anchor);
2940 let should_expand_hunk = match &change_kind {
2941 DiffChangeKind::DiffUpdated { base_changed: true } => {
2942 self.all_diff_hunks_expanded
2943 }
2944 DiffChangeKind::ExpandOrCollapseHunks { expand } => {
2945 let intersects = hunk_buffer_range.is_empty()
2946 || hunk_buffer_range.end > edit_buffer_start;
2947 if *expand {
2948 intersects
2949 || was_previously_expanded
2950 || self.all_diff_hunks_expanded
2951 } else {
2952 !intersects
2953 && (was_previously_expanded || self.all_diff_hunks_expanded)
2954 }
2955 }
2956 _ => was_previously_expanded || self.all_diff_hunks_expanded,
2957 };
2958
2959 if should_expand_hunk {
2960 did_expand_hunks = true;
2961 log::trace!(
2962 "expanding hunk {:?}, excerpt:{:?}",
2963 hunk_excerpt_start.value..hunk_excerpt_end.value,
2964 excerpt.id
2965 );
2966
2967 if !hunk.diff_base_byte_range.is_empty()
2968 && hunk_buffer_range.start >= edit_buffer_start
2969 && hunk_buffer_range.start <= excerpt_buffer_end
2970 {
2971 let mut text_cursor =
2972 base_text.as_rope().cursor(hunk.diff_base_byte_range.start);
2973 let mut base_text_summary =
2974 text_cursor.summary::<TextSummary>(hunk.diff_base_byte_range.end);
2975
2976 let mut has_trailing_newline = false;
2977 if base_text_summary.last_line_chars > 0 {
2978 base_text_summary += TextSummary::newline();
2979 has_trailing_newline = true;
2980 }
2981
2982 new_diff_transforms.push(
2983 DiffTransform::DeletedHunk {
2984 base_text_byte_range: hunk.diff_base_byte_range.clone(),
2985 summary: base_text_summary,
2986 buffer_id: excerpt.buffer_id,
2987 hunk_anchor,
2988 has_trailing_newline,
2989 },
2990 &(),
2991 );
2992 }
2993
2994 if !hunk_buffer_range.is_empty() {
2995 *end_of_current_insert = Some((
2996 hunk_excerpt_end.min(excerpt_end),
2997 hunk_anchor.0,
2998 hunk_anchor.1,
2999 ));
3000 }
3001 }
3002 }
3003 }
3004
3005 if excerpts.end(&()) <= edit.new.end {
3006 excerpts.next(&());
3007 } else {
3008 break;
3009 }
3010 }
3011
3012 did_expand_hunks || !old_expanded_hunks.is_empty()
3013 }
3014
3015 fn append_diff_transforms(
3016 &self,
3017 new_transforms: &mut SumTree<DiffTransform>,
3018 subtree: SumTree<DiffTransform>,
3019 ) {
3020 if let Some(DiffTransform::BufferContent {
3021 inserted_hunk_anchor,
3022 summary,
3023 }) = subtree.first()
3024 {
3025 if self.extend_last_buffer_content_transform(
3026 new_transforms,
3027 *inserted_hunk_anchor,
3028 *summary,
3029 ) {
3030 let mut cursor = subtree.cursor::<()>(&());
3031 cursor.next(&());
3032 cursor.next(&());
3033 new_transforms.append(cursor.suffix(&()), &());
3034 return;
3035 }
3036 }
3037 new_transforms.append(subtree, &());
3038 }
3039
3040 fn push_diff_transform(
3041 &self,
3042 new_transforms: &mut SumTree<DiffTransform>,
3043 transform: DiffTransform,
3044 ) {
3045 if let DiffTransform::BufferContent {
3046 inserted_hunk_anchor,
3047 summary,
3048 } = transform
3049 {
3050 if self.extend_last_buffer_content_transform(
3051 new_transforms,
3052 inserted_hunk_anchor,
3053 summary,
3054 ) {
3055 return;
3056 }
3057 }
3058 new_transforms.push(transform, &());
3059 }
3060
3061 fn push_buffer_content_transform(
3062 &self,
3063 old_snapshot: &MultiBufferSnapshot,
3064 new_transforms: &mut SumTree<DiffTransform>,
3065 end_offset: ExcerptOffset,
3066 current_inserted_hunk: Option<(ExcerptOffset, ExcerptId, text::Anchor)>,
3067 ) {
3068 let inserted_region =
3069 current_inserted_hunk.map(|(insertion_end_offset, excerpt_id, anchor)| {
3070 (
3071 end_offset.min(insertion_end_offset),
3072 Some((excerpt_id, anchor)),
3073 )
3074 });
3075 let unchanged_region = [(end_offset, None)];
3076
3077 for (end_offset, inserted_hunk_anchor) in
3078 inserted_region.into_iter().chain(unchanged_region)
3079 {
3080 let start_offset = new_transforms.summary().excerpt_len();
3081 if end_offset <= start_offset {
3082 continue;
3083 }
3084 let summary_to_add = old_snapshot
3085 .text_summary_for_excerpt_offset_range::<TextSummary>(start_offset..end_offset);
3086
3087 if !self.extend_last_buffer_content_transform(
3088 new_transforms,
3089 inserted_hunk_anchor,
3090 summary_to_add,
3091 ) {
3092 new_transforms.push(
3093 DiffTransform::BufferContent {
3094 summary: summary_to_add,
3095 inserted_hunk_anchor,
3096 },
3097 &(),
3098 )
3099 }
3100 }
3101 }
3102
3103 fn extend_last_buffer_content_transform(
3104 &self,
3105 new_transforms: &mut SumTree<DiffTransform>,
3106 new_inserted_hunk_anchor: Option<(ExcerptId, text::Anchor)>,
3107 summary_to_add: TextSummary,
3108 ) -> bool {
3109 let mut did_extend = false;
3110 new_transforms.update_last(
3111 |last_transform| {
3112 if let DiffTransform::BufferContent {
3113 summary,
3114 inserted_hunk_anchor,
3115 } = last_transform
3116 {
3117 if *inserted_hunk_anchor == new_inserted_hunk_anchor {
3118 *summary += summary_to_add;
3119 did_extend = true;
3120 }
3121 }
3122 },
3123 &(),
3124 );
3125 did_extend
3126 }
3127}
3128
3129#[cfg(any(test, feature = "test-support"))]
3130impl MultiBuffer {
3131 pub fn build_simple(text: &str, cx: &mut gpui::App) -> Entity<Self> {
3132 let buffer = cx.new(|cx| Buffer::local(text, cx));
3133 cx.new(|cx| Self::singleton(buffer, cx))
3134 }
3135
3136 pub fn build_multi<const COUNT: usize>(
3137 excerpts: [(&str, Vec<Range<Point>>); COUNT],
3138 cx: &mut gpui::App,
3139 ) -> Entity<Self> {
3140 let multi = cx.new(|_| Self::new(Capability::ReadWrite));
3141 for (text, ranges) in excerpts {
3142 let buffer = cx.new(|cx| Buffer::local(text, cx));
3143 let excerpt_ranges = ranges.into_iter().map(|range| ExcerptRange {
3144 context: range,
3145 primary: None,
3146 });
3147 multi.update(cx, |multi, cx| {
3148 multi.push_excerpts(buffer, excerpt_ranges, cx)
3149 });
3150 }
3151
3152 multi
3153 }
3154
3155 pub fn build_from_buffer(buffer: Entity<Buffer>, cx: &mut gpui::App) -> Entity<Self> {
3156 cx.new(|cx| Self::singleton(buffer, cx))
3157 }
3158
3159 pub fn build_random(rng: &mut impl rand::Rng, cx: &mut gpui::App) -> Entity<Self> {
3160 cx.new(|cx| {
3161 let mut multibuffer = MultiBuffer::new(Capability::ReadWrite);
3162 let mutation_count = rng.gen_range(1..=5);
3163 multibuffer.randomly_edit_excerpts(rng, mutation_count, cx);
3164 multibuffer
3165 })
3166 }
3167
3168 pub fn randomly_edit(
3169 &mut self,
3170 rng: &mut impl rand::Rng,
3171 edit_count: usize,
3172 cx: &mut Context<Self>,
3173 ) {
3174 use util::RandomCharIter;
3175
3176 let snapshot = self.read(cx);
3177 let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
3178 let mut last_end = None;
3179 for _ in 0..edit_count {
3180 if last_end.map_or(false, |last_end| last_end >= snapshot.len()) {
3181 break;
3182 }
3183
3184 let new_start = last_end.map_or(0, |last_end| last_end + 1);
3185 let end = snapshot.clip_offset(rng.gen_range(new_start..=snapshot.len()), Bias::Right);
3186 let start = snapshot.clip_offset(rng.gen_range(new_start..=end), Bias::Right);
3187 last_end = Some(end);
3188
3189 let mut range = start..end;
3190 if rng.gen_bool(0.2) {
3191 mem::swap(&mut range.start, &mut range.end);
3192 }
3193
3194 let new_text_len = rng.gen_range(0..10);
3195 let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
3196
3197 edits.push((range, new_text.into()));
3198 }
3199 log::info!("mutating multi-buffer with {:?}", edits);
3200 drop(snapshot);
3201
3202 self.edit(edits, None, cx);
3203 }
3204
3205 pub fn randomly_edit_excerpts(
3206 &mut self,
3207 rng: &mut impl rand::Rng,
3208 mutation_count: usize,
3209 cx: &mut Context<Self>,
3210 ) {
3211 use rand::prelude::*;
3212 use std::env;
3213 use util::RandomCharIter;
3214
3215 let max_excerpts = env::var("MAX_EXCERPTS")
3216 .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))
3217 .unwrap_or(5);
3218
3219 let mut buffers = Vec::new();
3220 for _ in 0..mutation_count {
3221 if rng.gen_bool(0.05) {
3222 log::info!("Clearing multi-buffer");
3223 self.clear(cx);
3224 continue;
3225 } else if rng.gen_bool(0.1) && !self.excerpt_ids().is_empty() {
3226 let ids = self.excerpt_ids();
3227 let mut excerpts = HashSet::default();
3228 for _ in 0..rng.gen_range(0..ids.len()) {
3229 excerpts.extend(ids.choose(rng).copied());
3230 }
3231
3232 let line_count = rng.gen_range(0..5);
3233
3234 log::info!("Expanding excerpts {excerpts:?} by {line_count} lines");
3235
3236 self.expand_excerpts(
3237 excerpts.iter().cloned(),
3238 line_count,
3239 ExpandExcerptDirection::UpAndDown,
3240 cx,
3241 );
3242 continue;
3243 }
3244
3245 let excerpt_ids = self.excerpt_ids();
3246 if excerpt_ids.is_empty() || (rng.gen() && excerpt_ids.len() < max_excerpts) {
3247 let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() {
3248 let text = RandomCharIter::new(&mut *rng).take(10).collect::<String>();
3249 buffers.push(cx.new(|cx| Buffer::local(text, cx)));
3250 let buffer = buffers.last().unwrap().read(cx);
3251 log::info!(
3252 "Creating new buffer {} with text: {:?}",
3253 buffer.remote_id(),
3254 buffer.text()
3255 );
3256 buffers.last().unwrap().clone()
3257 } else {
3258 self.buffers
3259 .borrow()
3260 .values()
3261 .choose(rng)
3262 .unwrap()
3263 .buffer
3264 .clone()
3265 };
3266
3267 let buffer = buffer_handle.read(cx);
3268 let buffer_text = buffer.text();
3269 let ranges = (0..rng.gen_range(0..5))
3270 .map(|_| {
3271 let end_ix =
3272 buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
3273 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
3274 ExcerptRange {
3275 context: start_ix..end_ix,
3276 primary: None,
3277 }
3278 })
3279 .collect::<Vec<_>>();
3280 log::info!(
3281 "Inserting excerpts from buffer {} and ranges {:?}: {:?}",
3282 buffer_handle.read(cx).remote_id(),
3283 ranges.iter().map(|r| &r.context).collect::<Vec<_>>(),
3284 ranges
3285 .iter()
3286 .map(|r| &buffer_text[r.context.clone()])
3287 .collect::<Vec<_>>()
3288 );
3289
3290 let excerpt_id = self.push_excerpts(buffer_handle.clone(), ranges, cx);
3291 log::info!("Inserted with ids: {:?}", excerpt_id);
3292 } else {
3293 let remove_count = rng.gen_range(1..=excerpt_ids.len());
3294 let mut excerpts_to_remove = excerpt_ids
3295 .choose_multiple(rng, remove_count)
3296 .cloned()
3297 .collect::<Vec<_>>();
3298 let snapshot = self.snapshot.borrow();
3299 excerpts_to_remove.sort_unstable_by(|a, b| a.cmp(b, &snapshot));
3300 drop(snapshot);
3301 log::info!("Removing excerpts {:?}", excerpts_to_remove);
3302 self.remove_excerpts(excerpts_to_remove, cx);
3303 }
3304 }
3305 }
3306
3307 pub fn randomly_mutate(
3308 &mut self,
3309 rng: &mut impl rand::Rng,
3310 mutation_count: usize,
3311 cx: &mut Context<Self>,
3312 ) {
3313 use rand::prelude::*;
3314
3315 if rng.gen_bool(0.7) || self.singleton {
3316 let buffer = self
3317 .buffers
3318 .borrow()
3319 .values()
3320 .choose(rng)
3321 .map(|state| state.buffer.clone());
3322
3323 if let Some(buffer) = buffer {
3324 buffer.update(cx, |buffer, cx| {
3325 if rng.gen() {
3326 buffer.randomly_edit(rng, mutation_count, cx);
3327 } else {
3328 buffer.randomly_undo_redo(rng, cx);
3329 }
3330 });
3331 } else {
3332 self.randomly_edit(rng, mutation_count, cx);
3333 }
3334 } else {
3335 self.randomly_edit_excerpts(rng, mutation_count, cx);
3336 }
3337
3338 self.check_invariants(cx);
3339 }
3340
3341 fn check_invariants(&self, cx: &App) {
3342 self.read(cx).check_invariants();
3343 }
3344}
3345
3346impl EventEmitter<Event> for MultiBuffer {}
3347
3348impl MultiBufferSnapshot {
3349 pub fn text(&self) -> String {
3350 self.chunks(0..self.len(), false)
3351 .map(|chunk| chunk.text)
3352 .collect()
3353 }
3354
3355 pub fn reversed_chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
3356 self.reversed_chunks_in_range(0..position.to_offset(self))
3357 .flat_map(|c| c.chars().rev())
3358 }
3359
3360 fn reversed_chunks_in_range(&self, range: Range<usize>) -> ReversedMultiBufferChunks {
3361 let mut cursor = self.cursor::<usize>();
3362 cursor.seek(&range.end);
3363 let current_chunks = cursor.region().as_ref().map(|region| {
3364 let start_overshoot = range.start.saturating_sub(region.range.start);
3365 let end_overshoot = range.end - region.range.start;
3366 let end = (region.buffer_range.start + end_overshoot).min(region.buffer_range.end);
3367 let start = region.buffer_range.start + start_overshoot;
3368 region.buffer.reversed_chunks_in_range(start..end)
3369 });
3370 ReversedMultiBufferChunks {
3371 cursor,
3372 current_chunks,
3373 start: range.start,
3374 offset: range.end,
3375 }
3376 }
3377
3378 pub fn chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
3379 let offset = position.to_offset(self);
3380 self.text_for_range(offset..self.len())
3381 .flat_map(|chunk| chunk.chars())
3382 }
3383
3384 pub fn text_for_range<T: ToOffset>(&self, range: Range<T>) -> impl Iterator<Item = &str> + '_ {
3385 self.chunks(range, false).map(|chunk| chunk.text)
3386 }
3387
3388 pub fn is_line_blank(&self, row: MultiBufferRow) -> bool {
3389 self.text_for_range(Point::new(row.0, 0)..Point::new(row.0, self.line_len(row)))
3390 .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
3391 }
3392
3393 pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
3394 where
3395 T: ToOffset,
3396 {
3397 let position = position.to_offset(self);
3398 position == self.clip_offset(position, Bias::Left)
3399 && self
3400 .bytes_in_range(position..self.len())
3401 .flatten()
3402 .copied()
3403 .take(needle.len())
3404 .eq(needle.bytes())
3405 }
3406
3407 pub fn diff_hunks(&self) -> impl Iterator<Item = MultiBufferDiffHunk> + '_ {
3408 self.diff_hunks_in_range(Anchor::min()..Anchor::max())
3409 }
3410
3411 pub fn diff_hunks_in_range<T: ToPoint>(
3412 &self,
3413 range: Range<T>,
3414 ) -> impl Iterator<Item = MultiBufferDiffHunk> + '_ {
3415 let query_range = range.start.to_point(self)..range.end.to_point(self);
3416 self.lift_buffer_metadata(query_range.clone(), move |buffer, buffer_range| {
3417 let diff = self.diffs.get(&buffer.remote_id())?;
3418 let buffer_start = buffer.anchor_before(buffer_range.start);
3419 let buffer_end = buffer.anchor_after(buffer_range.end);
3420 Some(
3421 diff.diff
3422 .hunks_intersecting_range(buffer_start..buffer_end, buffer)
3423 .map(|hunk| {
3424 (
3425 Point::new(hunk.row_range.start, 0)..Point::new(hunk.row_range.end, 0),
3426 hunk,
3427 )
3428 }),
3429 )
3430 })
3431 .filter_map(move |(range, hunk, excerpt)| {
3432 if range.start != range.end
3433 && range.end == query_range.start
3434 && !hunk.row_range.is_empty()
3435 {
3436 return None;
3437 }
3438 let end_row = if range.end.column == 0 {
3439 range.end.row
3440 } else {
3441 range.end.row + 1
3442 };
3443 Some(MultiBufferDiffHunk {
3444 row_range: MultiBufferRow(range.start.row)..MultiBufferRow(end_row),
3445 buffer_id: excerpt.buffer_id,
3446 excerpt_id: excerpt.id,
3447 buffer_range: hunk.buffer_range.clone(),
3448 diff_base_byte_range: hunk.diff_base_byte_range.clone(),
3449 })
3450 })
3451 }
3452
3453 pub fn excerpt_ids_for_range<T: ToOffset>(
3454 &self,
3455 range: Range<T>,
3456 ) -> impl Iterator<Item = ExcerptId> + '_ {
3457 let range = range.start.to_offset(self)..range.end.to_offset(self);
3458 let mut cursor = self.cursor::<usize>();
3459 cursor.seek(&range.start);
3460 std::iter::from_fn(move || {
3461 let region = cursor.region()?;
3462 if region.range.start >= range.end {
3463 return None;
3464 }
3465 cursor.next_excerpt();
3466 Some(region.excerpt.id)
3467 })
3468 }
3469
3470 pub fn buffer_ids_for_range<T: ToOffset>(
3471 &self,
3472 range: Range<T>,
3473 ) -> impl Iterator<Item = BufferId> + '_ {
3474 let range = range.start.to_offset(self)..range.end.to_offset(self);
3475 let mut cursor = self.cursor::<usize>();
3476 cursor.seek(&range.start);
3477 std::iter::from_fn(move || {
3478 let region = cursor.region()?;
3479 if region.range.start >= range.end {
3480 return None;
3481 }
3482 cursor.next_excerpt();
3483 Some(region.excerpt.buffer_id)
3484 })
3485 }
3486
3487 pub fn ranges_to_buffer_ranges<T: ToOffset>(
3488 &self,
3489 ranges: impl Iterator<Item = Range<T>>,
3490 ) -> impl Iterator<Item = (&BufferSnapshot, Range<usize>, ExcerptId)> {
3491 ranges.flat_map(|range| self.range_to_buffer_ranges(range).into_iter())
3492 }
3493
3494 pub fn range_to_buffer_ranges<T: ToOffset>(
3495 &self,
3496 range: Range<T>,
3497 ) -> Vec<(&BufferSnapshot, Range<usize>, ExcerptId)> {
3498 let start = range.start.to_offset(&self);
3499 let end = range.end.to_offset(&self);
3500
3501 let mut cursor = self.cursor::<usize>();
3502 cursor.seek(&start);
3503
3504 let mut result: Vec<(&BufferSnapshot, Range<usize>, ExcerptId)> = Vec::new();
3505 while let Some(region) = cursor.region() {
3506 if region.range.start > end {
3507 break;
3508 }
3509 if region.is_main_buffer {
3510 let start_overshoot = start.saturating_sub(region.range.start);
3511 let end_overshoot = end.saturating_sub(region.range.start);
3512 let start = region
3513 .buffer_range
3514 .end
3515 .min(region.buffer_range.start + start_overshoot);
3516 let end = region
3517 .buffer_range
3518 .end
3519 .min(region.buffer_range.start + end_overshoot);
3520 if let Some(prev) = result.last_mut().filter(|(_, prev_range, excerpt_id)| {
3521 *excerpt_id == region.excerpt.id && prev_range.end == start
3522 }) {
3523 prev.1.end = end;
3524 } else {
3525 result.push((region.buffer, start..end, region.excerpt.id));
3526 }
3527 }
3528 cursor.next();
3529 }
3530 result
3531 }
3532
3533 pub fn range_to_buffer_ranges_with_deleted_hunks<T: ToOffset>(
3534 &self,
3535 range: Range<T>,
3536 ) -> impl Iterator<Item = (&BufferSnapshot, Range<usize>, ExcerptId, Option<Anchor>)> + '_ {
3537 let start = range.start.to_offset(&self);
3538 let end = range.end.to_offset(&self);
3539
3540 let mut cursor = self.cursor::<usize>();
3541 cursor.seek(&start);
3542
3543 std::iter::from_fn(move || {
3544 let region = cursor.region()?;
3545 if region.range.start > end {
3546 return None;
3547 }
3548 let start_overshoot = start.saturating_sub(region.range.start);
3549 let end_overshoot = end.saturating_sub(region.range.start);
3550 let start = region
3551 .buffer_range
3552 .end
3553 .min(region.buffer_range.start + start_overshoot);
3554 let end = region
3555 .buffer_range
3556 .end
3557 .min(region.buffer_range.start + end_overshoot);
3558
3559 let region_excerpt_id = region.excerpt.id;
3560 let deleted_hunk_anchor = if region.is_main_buffer {
3561 None
3562 } else {
3563 Some(self.anchor_before(region.range.start))
3564 };
3565 let result = (
3566 region.buffer,
3567 start..end,
3568 region_excerpt_id,
3569 deleted_hunk_anchor,
3570 );
3571 cursor.next();
3572 Some(result)
3573 })
3574 }
3575
3576 /// Retrieves buffer metadata for the given range, and converts it into multi-buffer
3577 /// coordinates.
3578 ///
3579 /// The given callback will be called for every excerpt intersecting the given range. It will
3580 /// be passed the excerpt's buffer and the buffer range that the input range intersects.
3581 /// The callback should return an iterator of metadata items from that buffer, each paired
3582 /// with a buffer range.
3583 ///
3584 /// The returned iterator yields each of these metadata items, paired with its range in
3585 /// multi-buffer coordinates.
3586 fn lift_buffer_metadata<'a, D, M, I>(
3587 &'a self,
3588 query_range: Range<D>,
3589 get_buffer_metadata: impl 'a + Fn(&'a BufferSnapshot, Range<D>) -> Option<I>,
3590 ) -> impl Iterator<Item = (Range<D>, M, &'a Excerpt)> + 'a
3591 where
3592 I: Iterator<Item = (Range<D>, M)> + 'a,
3593 D: TextDimension + Ord + Sub<D, Output = D>,
3594 {
3595 let max_position = D::from_text_summary(&self.text_summary());
3596 let mut current_excerpt_metadata: Option<(ExcerptId, I)> = None;
3597 let mut cursor = self.cursor::<D>();
3598
3599 // Find the excerpt and buffer offset where the given range ends.
3600 cursor.seek(&query_range.end);
3601 let mut range_end = None;
3602 while let Some(region) = cursor.region() {
3603 if region.is_main_buffer {
3604 let mut buffer_end = region.buffer_range.start;
3605 let overshoot = if query_range.end > region.range.start {
3606 query_range.end - region.range.start
3607 } else {
3608 D::default()
3609 };
3610 buffer_end.add_assign(&overshoot);
3611 range_end = Some((region.excerpt.id, buffer_end));
3612 break;
3613 }
3614 cursor.next();
3615 }
3616
3617 cursor.seek(&query_range.start);
3618
3619 if let Some(region) = cursor.region().filter(|region| !region.is_main_buffer) {
3620 if region.range.start > D::zero(&()) {
3621 cursor.prev()
3622 }
3623 }
3624
3625 iter::from_fn(move || loop {
3626 let excerpt = cursor.excerpt()?;
3627
3628 // If we have already retrieved metadata for this excerpt, continue to use it.
3629 let metadata_iter = if let Some((_, metadata)) = current_excerpt_metadata
3630 .as_mut()
3631 .filter(|(excerpt_id, _)| *excerpt_id == excerpt.id)
3632 {
3633 Some(metadata)
3634 }
3635 // Otherwise, compute the intersection of the input range with the excerpt's range,
3636 // and retrieve the metadata for the resulting range.
3637 else {
3638 let region = cursor.region()?;
3639 let mut buffer_start;
3640 if region.is_main_buffer {
3641 buffer_start = region.buffer_range.start;
3642 if query_range.start > region.range.start {
3643 let overshoot = query_range.start - region.range.start;
3644 buffer_start.add_assign(&overshoot);
3645 }
3646 buffer_start = buffer_start.min(region.buffer_range.end);
3647 } else {
3648 buffer_start = cursor.main_buffer_position()?;
3649 };
3650 let mut buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer);
3651 if let Some((end_excerpt_id, end_buffer_offset)) = range_end {
3652 if excerpt.id == end_excerpt_id {
3653 buffer_end = buffer_end.min(end_buffer_offset);
3654 }
3655 }
3656
3657 if let Some(iterator) =
3658 get_buffer_metadata(&excerpt.buffer, buffer_start..buffer_end)
3659 {
3660 Some(&mut current_excerpt_metadata.insert((excerpt.id, iterator)).1)
3661 } else {
3662 None
3663 }
3664 };
3665
3666 // Visit each metadata item.
3667 if let Some((metadata_buffer_range, metadata)) = metadata_iter.and_then(Iterator::next)
3668 {
3669 // Find the multibuffer regions that contain the start and end of
3670 // the metadata item's range.
3671 if metadata_buffer_range.start > D::default() {
3672 while let Some(region) = cursor.region() {
3673 if region.is_main_buffer
3674 && (region.buffer_range.end >= metadata_buffer_range.start
3675 || cursor.is_at_end_of_excerpt())
3676 {
3677 break;
3678 }
3679 cursor.next();
3680 }
3681 }
3682 let start_region = cursor.region()?;
3683 while let Some(region) = cursor.region() {
3684 if region.is_main_buffer
3685 && (region.buffer_range.end > metadata_buffer_range.end
3686 || cursor.is_at_end_of_excerpt())
3687 {
3688 break;
3689 }
3690 cursor.next();
3691 }
3692 let end_region = cursor.region();
3693
3694 // Convert the metadata item's range into multibuffer coordinates.
3695 let mut start_position = start_region.range.start;
3696 let region_buffer_start = start_region.buffer_range.start;
3697 if start_region.is_main_buffer && metadata_buffer_range.start > region_buffer_start
3698 {
3699 start_position.add_assign(&(metadata_buffer_range.start - region_buffer_start));
3700 start_position = start_position.min(start_region.range.end);
3701 }
3702
3703 let mut end_position = max_position;
3704 if let Some(end_region) = &end_region {
3705 end_position = end_region.range.start;
3706 debug_assert!(end_region.is_main_buffer);
3707 let region_buffer_start = end_region.buffer_range.start;
3708 if metadata_buffer_range.end > region_buffer_start {
3709 end_position.add_assign(&(metadata_buffer_range.end - region_buffer_start));
3710 }
3711 end_position = end_position.min(end_region.range.end);
3712 }
3713
3714 if start_position <= query_range.end && end_position >= query_range.start {
3715 return Some((start_position..end_position, metadata, excerpt));
3716 }
3717 }
3718 // When there are no more metadata items for this excerpt, move to the next excerpt.
3719 else {
3720 current_excerpt_metadata.take();
3721 cursor.next_excerpt();
3722 }
3723 })
3724 }
3725
3726 pub fn diff_hunk_before<T: ToOffset>(&self, position: T) -> Option<MultiBufferDiffHunk> {
3727 let offset = position.to_offset(self);
3728
3729 // Go to the region containing the given offset.
3730 let mut cursor = self.cursor::<DimensionPair<usize, Point>>();
3731 cursor.seek(&DimensionPair {
3732 key: offset,
3733 value: None,
3734 });
3735 let mut region = cursor.region()?;
3736 if region.range.start.key == offset || !region.is_main_buffer {
3737 cursor.prev();
3738 region = cursor.region()?;
3739 }
3740
3741 // Find the corresponding buffer offset.
3742 let overshoot = if region.is_main_buffer {
3743 offset - region.range.start.key
3744 } else {
3745 0
3746 };
3747 let mut max_buffer_offset = region
3748 .buffer
3749 .clip_offset(region.buffer_range.start.key + overshoot, Bias::Right);
3750
3751 loop {
3752 let excerpt = cursor.excerpt()?;
3753 let excerpt_end = excerpt.range.context.end.to_offset(&excerpt.buffer);
3754 let buffer_offset = excerpt_end.min(max_buffer_offset);
3755 let buffer_end = excerpt.buffer.anchor_before(buffer_offset);
3756 let buffer_end_row = buffer_end.to_point(&excerpt.buffer).row;
3757
3758 if let Some(diff_state) = self.diffs.get(&excerpt.buffer_id) {
3759 for hunk in diff_state.diff.hunks_intersecting_range_rev(
3760 excerpt.range.context.start..buffer_end,
3761 &excerpt.buffer,
3762 ) {
3763 let hunk_range = hunk.buffer_range.to_offset(&excerpt.buffer);
3764 if hunk.row_range.end >= buffer_end_row {
3765 continue;
3766 }
3767
3768 let hunk_start = Point::new(hunk.row_range.start, 0);
3769 let hunk_end = Point::new(hunk.row_range.end, 0);
3770
3771 cursor.seek_to_buffer_position_in_current_excerpt(&DimensionPair {
3772 key: hunk_range.start,
3773 value: None,
3774 });
3775
3776 let mut region = cursor.region()?;
3777 while !region.is_main_buffer || region.buffer_range.start.key >= hunk_range.end
3778 {
3779 cursor.prev();
3780 region = cursor.region()?;
3781 }
3782
3783 let overshoot = if region.is_main_buffer {
3784 hunk_start.saturating_sub(region.buffer_range.start.value.unwrap())
3785 } else {
3786 Point::zero()
3787 };
3788 let start = region.range.start.value.unwrap() + overshoot;
3789
3790 while let Some(region) = cursor.region() {
3791 if !region.is_main_buffer
3792 || region.buffer_range.end.value.unwrap() <= hunk_end
3793 {
3794 cursor.next();
3795 } else {
3796 break;
3797 }
3798 }
3799
3800 let end = if let Some(region) = cursor.region() {
3801 let overshoot = if region.is_main_buffer {
3802 hunk_end.saturating_sub(region.buffer_range.start.value.unwrap())
3803 } else {
3804 Point::zero()
3805 };
3806 region.range.start.value.unwrap() + overshoot
3807 } else {
3808 self.max_point()
3809 };
3810
3811 return Some(MultiBufferDiffHunk {
3812 row_range: MultiBufferRow(start.row)..MultiBufferRow(end.row),
3813 buffer_id: excerpt.buffer_id,
3814 excerpt_id: excerpt.id,
3815 buffer_range: hunk.buffer_range.clone(),
3816 diff_base_byte_range: hunk.diff_base_byte_range.clone(),
3817 });
3818 }
3819 }
3820
3821 cursor.prev_excerpt();
3822 max_buffer_offset = usize::MAX;
3823 }
3824 }
3825
3826 pub fn has_diff_hunks(&self) -> bool {
3827 self.diffs.values().any(|diff| !diff.diff.is_empty())
3828 }
3829
3830 pub fn surrounding_word<T: ToOffset>(
3831 &self,
3832 start: T,
3833 for_completion: bool,
3834 ) -> (Range<usize>, Option<CharKind>) {
3835 let mut start = start.to_offset(self);
3836 let mut end = start;
3837 let mut next_chars = self.chars_at(start).peekable();
3838 let mut prev_chars = self.reversed_chars_at(start).peekable();
3839
3840 let classifier = self
3841 .char_classifier_at(start)
3842 .for_completion(for_completion);
3843
3844 let word_kind = cmp::max(
3845 prev_chars.peek().copied().map(|c| classifier.kind(c)),
3846 next_chars.peek().copied().map(|c| classifier.kind(c)),
3847 );
3848
3849 for ch in prev_chars {
3850 if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
3851 start -= ch.len_utf8();
3852 } else {
3853 break;
3854 }
3855 }
3856
3857 for ch in next_chars {
3858 if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
3859 end += ch.len_utf8();
3860 } else {
3861 break;
3862 }
3863 }
3864
3865 (start..end, word_kind)
3866 }
3867
3868 pub fn is_singleton(&self) -> bool {
3869 self.singleton
3870 }
3871
3872 pub fn as_singleton(&self) -> Option<(&ExcerptId, BufferId, &BufferSnapshot)> {
3873 if self.singleton {
3874 self.excerpts
3875 .iter()
3876 .next()
3877 .map(|e| (&e.id, e.buffer_id, &e.buffer))
3878 } else {
3879 None
3880 }
3881 }
3882
3883 pub fn len(&self) -> usize {
3884 self.diff_transforms.summary().output.len
3885 }
3886
3887 pub fn is_empty(&self) -> bool {
3888 self.excerpts.summary().text.len == 0
3889 }
3890
3891 pub fn widest_line_number(&self) -> u32 {
3892 self.excerpts.summary().widest_line_number + 1
3893 }
3894
3895 pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> MultiBufferBytes {
3896 let range = range.start.to_offset(self)..range.end.to_offset(self);
3897 let mut excerpts = self.cursor::<usize>();
3898 excerpts.seek(&range.start);
3899
3900 let mut chunk;
3901 let mut has_trailing_newline;
3902 let excerpt_bytes;
3903 if let Some(region) = excerpts.region() {
3904 let mut bytes = region.buffer.bytes_in_range(
3905 region.buffer_range.start + range.start - region.range.start
3906 ..(region.buffer_range.start + range.end - region.range.start)
3907 .min(region.buffer_range.end),
3908 );
3909 chunk = bytes.next().unwrap_or(&[][..]);
3910 excerpt_bytes = Some(bytes);
3911 has_trailing_newline = region.has_trailing_newline && range.end >= region.range.end;
3912 if chunk.is_empty() && has_trailing_newline {
3913 chunk = b"\n";
3914 has_trailing_newline = false;
3915 }
3916 } else {
3917 chunk = &[][..];
3918 excerpt_bytes = None;
3919 has_trailing_newline = false;
3920 };
3921
3922 MultiBufferBytes {
3923 range,
3924 cursor: excerpts,
3925 excerpt_bytes,
3926 has_trailing_newline,
3927 chunk,
3928 }
3929 }
3930
3931 pub fn reversed_bytes_in_range<T: ToOffset>(
3932 &self,
3933 range: Range<T>,
3934 ) -> ReversedMultiBufferBytes {
3935 let range = range.start.to_offset(self)..range.end.to_offset(self);
3936 let mut chunks = self.reversed_chunks_in_range(range.clone());
3937 let chunk = chunks.next().map_or(&[][..], |c| c.as_bytes());
3938 ReversedMultiBufferBytes {
3939 range,
3940 chunks,
3941 chunk,
3942 }
3943 }
3944
3945 pub fn row_infos(&self, start_row: MultiBufferRow) -> MultiBufferRows {
3946 let mut cursor = self.cursor::<Point>();
3947 cursor.seek(&Point::new(start_row.0, 0));
3948 let mut result = MultiBufferRows {
3949 point: Point::new(0, 0),
3950 is_empty: self.excerpts.is_empty(),
3951 cursor,
3952 };
3953 result.seek(start_row);
3954 result
3955 }
3956
3957 pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> MultiBufferChunks {
3958 let mut chunks = MultiBufferChunks {
3959 excerpt_offset_range: ExcerptOffset::new(0)..ExcerptOffset::new(0),
3960 range: 0..0,
3961 excerpts: self.excerpts.cursor(&()),
3962 diff_transforms: self.diff_transforms.cursor(&()),
3963 diffs: &self.diffs,
3964 diff_base_chunks: None,
3965 excerpt_chunks: None,
3966 buffer_chunk: None,
3967 language_aware,
3968 };
3969 let range = range.start.to_offset(self)..range.end.to_offset(self);
3970 chunks.seek(range);
3971 chunks
3972 }
3973
3974 pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
3975 self.clip_dimension(offset, bias, text::BufferSnapshot::clip_offset)
3976 }
3977
3978 pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
3979 self.clip_dimension(point, bias, text::BufferSnapshot::clip_point)
3980 }
3981
3982 pub fn clip_offset_utf16(&self, offset: OffsetUtf16, bias: Bias) -> OffsetUtf16 {
3983 self.clip_dimension(offset, bias, text::BufferSnapshot::clip_offset_utf16)
3984 }
3985
3986 pub fn clip_point_utf16(&self, point: Unclipped<PointUtf16>, bias: Bias) -> PointUtf16 {
3987 self.clip_dimension(point.0, bias, |buffer, point, bias| {
3988 buffer.clip_point_utf16(Unclipped(point), bias)
3989 })
3990 }
3991
3992 pub fn offset_to_point(&self, offset: usize) -> Point {
3993 self.convert_dimension(offset, text::BufferSnapshot::offset_to_point)
3994 }
3995
3996 pub fn offset_to_point_utf16(&self, offset: usize) -> PointUtf16 {
3997 self.convert_dimension(offset, text::BufferSnapshot::offset_to_point_utf16)
3998 }
3999
4000 pub fn point_to_point_utf16(&self, point: Point) -> PointUtf16 {
4001 self.convert_dimension(point, text::BufferSnapshot::point_to_point_utf16)
4002 }
4003
4004 pub fn point_to_offset(&self, point: Point) -> usize {
4005 self.convert_dimension(point, text::BufferSnapshot::point_to_offset)
4006 }
4007
4008 pub fn offset_utf16_to_offset(&self, offset: OffsetUtf16) -> usize {
4009 self.convert_dimension(offset, text::BufferSnapshot::offset_utf16_to_offset)
4010 }
4011
4012 pub fn offset_to_offset_utf16(&self, offset: usize) -> OffsetUtf16 {
4013 self.convert_dimension(offset, text::BufferSnapshot::offset_to_offset_utf16)
4014 }
4015
4016 pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
4017 self.convert_dimension(point, text::BufferSnapshot::point_utf16_to_offset)
4018 }
4019
4020 fn clip_dimension<D>(
4021 &self,
4022 position: D,
4023 bias: Bias,
4024 clip_buffer_position: fn(&text::BufferSnapshot, D, Bias) -> D,
4025 ) -> D
4026 where
4027 D: TextDimension + Ord + Sub<D, Output = D>,
4028 {
4029 let mut cursor = self.cursor();
4030 cursor.seek(&position);
4031 if let Some(region) = cursor.region() {
4032 if position >= region.range.end {
4033 return region.range.end;
4034 }
4035 let overshoot = position - region.range.start;
4036 let mut buffer_position = region.buffer_range.start;
4037 buffer_position.add_assign(&overshoot);
4038 let clipped_buffer_position =
4039 clip_buffer_position(®ion.buffer, buffer_position, bias);
4040 let mut position = region.range.start;
4041 position.add_assign(&(clipped_buffer_position - region.buffer_range.start));
4042 position
4043 } else {
4044 D::from_text_summary(&self.text_summary())
4045 }
4046 }
4047
4048 fn convert_dimension<D1, D2>(
4049 &self,
4050 key: D1,
4051 convert_buffer_dimension: fn(&text::BufferSnapshot, D1) -> D2,
4052 ) -> D2
4053 where
4054 D1: TextDimension + Ord + Sub<D1, Output = D1>,
4055 D2: TextDimension + Ord + Sub<D2, Output = D2>,
4056 {
4057 let mut cursor = self.cursor::<DimensionPair<D1, D2>>();
4058 cursor.seek(&DimensionPair { key, value: None });
4059 if let Some(region) = cursor.region() {
4060 if key >= region.range.end.key {
4061 return region.range.end.value.unwrap();
4062 }
4063 let start_key = region.range.start.key;
4064 let start_value = region.range.start.value.unwrap();
4065 let buffer_start_key = region.buffer_range.start.key;
4066 let buffer_start_value = region.buffer_range.start.value.unwrap();
4067 let mut buffer_key = buffer_start_key;
4068 buffer_key.add_assign(&(key - start_key));
4069 let buffer_value = convert_buffer_dimension(®ion.buffer, buffer_key);
4070 let mut result = start_value;
4071 result.add_assign(&(buffer_value - buffer_start_value));
4072 result
4073 } else {
4074 D2::from_text_summary(&self.text_summary())
4075 }
4076 }
4077
4078 pub fn point_to_buffer_offset<T: ToOffset>(
4079 &self,
4080 point: T,
4081 ) -> Option<(&BufferSnapshot, usize)> {
4082 let offset = point.to_offset(self);
4083 let mut cursor = self.cursor::<usize>();
4084 cursor.seek(&offset);
4085 let region = cursor.region()?;
4086 let overshoot = offset - region.range.start;
4087 let buffer_offset = region.buffer_range.start + overshoot;
4088 Some((region.buffer, buffer_offset))
4089 }
4090
4091 pub fn point_to_buffer_point(&self, point: Point) -> Option<(&BufferSnapshot, Point, bool)> {
4092 let mut cursor = self.cursor::<Point>();
4093 cursor.seek(&point);
4094 let region = cursor.region()?;
4095 let overshoot = point - region.range.start;
4096 let buffer_offset = region.buffer_range.start + overshoot;
4097 Some((region.buffer, buffer_offset, region.is_main_buffer))
4098 }
4099
4100 pub fn suggested_indents(
4101 &self,
4102 rows: impl IntoIterator<Item = u32>,
4103 cx: &App,
4104 ) -> BTreeMap<MultiBufferRow, IndentSize> {
4105 let mut result = BTreeMap::new();
4106
4107 let mut rows_for_excerpt = Vec::new();
4108 let mut cursor = self.cursor::<Point>();
4109 let mut rows = rows.into_iter().peekable();
4110 let mut prev_row = u32::MAX;
4111 let mut prev_language_indent_size = IndentSize::default();
4112
4113 while let Some(row) = rows.next() {
4114 cursor.seek(&Point::new(row, 0));
4115 let Some(region) = cursor.region() else {
4116 continue;
4117 };
4118
4119 // Retrieve the language and indent size once for each disjoint region being indented.
4120 let single_indent_size = if row.saturating_sub(1) == prev_row {
4121 prev_language_indent_size
4122 } else {
4123 region
4124 .buffer
4125 .language_indent_size_at(Point::new(row, 0), cx)
4126 };
4127 prev_language_indent_size = single_indent_size;
4128 prev_row = row;
4129
4130 let start_buffer_row = region.buffer_range.start.row;
4131 let start_multibuffer_row = region.range.start.row;
4132 let end_multibuffer_row = region.range.end.row;
4133
4134 rows_for_excerpt.push(row);
4135 while let Some(next_row) = rows.peek().copied() {
4136 if end_multibuffer_row > next_row {
4137 rows_for_excerpt.push(next_row);
4138 rows.next();
4139 } else {
4140 break;
4141 }
4142 }
4143
4144 let buffer_rows = rows_for_excerpt
4145 .drain(..)
4146 .map(|row| start_buffer_row + row - start_multibuffer_row);
4147 let buffer_indents = region
4148 .buffer
4149 .suggested_indents(buffer_rows, single_indent_size);
4150 let multibuffer_indents = buffer_indents.into_iter().map(|(row, indent)| {
4151 (
4152 MultiBufferRow(start_multibuffer_row + row - start_buffer_row),
4153 indent,
4154 )
4155 });
4156 result.extend(multibuffer_indents);
4157 }
4158
4159 result
4160 }
4161
4162 pub fn indent_size_for_line(&self, row: MultiBufferRow) -> IndentSize {
4163 if let Some((buffer, range)) = self.buffer_line_for_row(row) {
4164 let mut size = buffer.indent_size_for_line(range.start.row);
4165 size.len = size
4166 .len
4167 .min(range.end.column)
4168 .saturating_sub(range.start.column);
4169 size
4170 } else {
4171 IndentSize::spaces(0)
4172 }
4173 }
4174
4175 pub fn line_indent_for_row(&self, row: MultiBufferRow) -> LineIndent {
4176 if let Some((buffer, range)) = self.buffer_line_for_row(row) {
4177 LineIndent::from_iter(buffer.text_for_range(range).flat_map(|s| s.chars()))
4178 } else {
4179 LineIndent::spaces(0)
4180 }
4181 }
4182
4183 pub fn indent_and_comment_for_line(&self, row: MultiBufferRow, cx: &App) -> String {
4184 let mut indent = self.indent_size_for_line(row).chars().collect::<String>();
4185
4186 if self.settings_at(0, cx).extend_comment_on_newline {
4187 if let Some(language_scope) = self.language_scope_at(Point::new(row.0, 0)) {
4188 let delimiters = language_scope.line_comment_prefixes();
4189 for delimiter in delimiters {
4190 if *self
4191 .chars_at(Point::new(row.0, indent.len() as u32))
4192 .take(delimiter.chars().count())
4193 .collect::<String>()
4194 .as_str()
4195 == **delimiter
4196 {
4197 indent.push_str(&delimiter);
4198 break;
4199 }
4200 }
4201 }
4202 }
4203
4204 indent
4205 }
4206
4207 pub fn prev_non_blank_row(&self, mut row: MultiBufferRow) -> Option<MultiBufferRow> {
4208 while row.0 > 0 {
4209 row.0 -= 1;
4210 if !self.is_line_blank(row) {
4211 return Some(row);
4212 }
4213 }
4214 None
4215 }
4216
4217 pub fn line_len(&self, row: MultiBufferRow) -> u32 {
4218 if let Some((_, range)) = self.buffer_line_for_row(row) {
4219 range.end.column - range.start.column
4220 } else {
4221 0
4222 }
4223 }
4224
4225 pub fn buffer_line_for_row(
4226 &self,
4227 row: MultiBufferRow,
4228 ) -> Option<(&BufferSnapshot, Range<Point>)> {
4229 let mut cursor = self.cursor::<Point>();
4230 let point = Point::new(row.0, 0);
4231 cursor.seek(&point);
4232 let region = cursor.region()?;
4233 let overshoot = point.min(region.range.end) - region.range.start;
4234 let buffer_point = region.buffer_range.start + overshoot;
4235 if buffer_point.row > region.buffer_range.end.row {
4236 return None;
4237 }
4238 let line_start = Point::new(buffer_point.row, 0).max(region.buffer_range.start);
4239 let line_end = Point::new(buffer_point.row, region.buffer.line_len(buffer_point.row))
4240 .min(region.buffer_range.end);
4241 Some((region.buffer, line_start..line_end))
4242 }
4243
4244 pub fn max_point(&self) -> Point {
4245 self.text_summary().lines
4246 }
4247
4248 pub fn max_row(&self) -> MultiBufferRow {
4249 MultiBufferRow(self.text_summary().lines.row)
4250 }
4251
4252 pub fn text_summary(&self) -> TextSummary {
4253 self.diff_transforms.summary().output
4254 }
4255
4256 pub fn text_summary_for_range<D, O>(&self, range: Range<O>) -> D
4257 where
4258 D: TextDimension,
4259 O: ToOffset,
4260 {
4261 let range = range.start.to_offset(self)..range.end.to_offset(self);
4262 let mut cursor = self.diff_transforms.cursor::<(usize, ExcerptOffset)>(&());
4263 cursor.seek(&range.start, Bias::Right, &());
4264
4265 let Some(first_transform) = cursor.item() else {
4266 return D::from_text_summary(&TextSummary::default());
4267 };
4268
4269 let diff_transform_start = cursor.start().0;
4270 let diff_transform_end = cursor.end(&()).0;
4271 let diff_start = range.start;
4272 let start_overshoot = diff_start - diff_transform_start;
4273 let end_overshoot = std::cmp::min(range.end, diff_transform_end) - diff_transform_start;
4274
4275 let mut result = match first_transform {
4276 DiffTransform::BufferContent { .. } => {
4277 let excerpt_start = cursor.start().1 + ExcerptOffset::new(start_overshoot);
4278 let excerpt_end = cursor.start().1 + ExcerptOffset::new(end_overshoot);
4279 self.text_summary_for_excerpt_offset_range(excerpt_start..excerpt_end)
4280 }
4281 DiffTransform::DeletedHunk {
4282 buffer_id,
4283 base_text_byte_range,
4284 has_trailing_newline,
4285 ..
4286 } => {
4287 let buffer_start = base_text_byte_range.start + start_overshoot;
4288 let mut buffer_end = base_text_byte_range.start + end_overshoot;
4289 let Some(buffer_diff) = self.diffs.get(buffer_id) else {
4290 panic!("{:?} is in non-existent deleted hunk", range.start)
4291 };
4292
4293 let include_trailing_newline =
4294 *has_trailing_newline && range.end >= diff_transform_end;
4295 if include_trailing_newline {
4296 buffer_end -= 1;
4297 }
4298
4299 let mut summary = buffer_diff
4300 .base_text
4301 .text_summary_for_range::<D, _>(buffer_start..buffer_end);
4302
4303 if include_trailing_newline {
4304 summary.add_assign(&D::from_text_summary(&TextSummary::newline()))
4305 }
4306
4307 summary
4308 }
4309 };
4310 if range.end < diff_transform_end {
4311 return result;
4312 }
4313
4314 cursor.next(&());
4315 result.add_assign(&D::from_text_summary(&cursor.summary(
4316 &range.end,
4317 Bias::Right,
4318 &(),
4319 )));
4320
4321 let Some(last_transform) = cursor.item() else {
4322 return result;
4323 };
4324
4325 let overshoot = range.end - cursor.start().0;
4326 let suffix = match last_transform {
4327 DiffTransform::BufferContent { .. } => {
4328 let end = cursor.start().1 + ExcerptOffset::new(overshoot);
4329 self.text_summary_for_excerpt_offset_range::<D>(cursor.start().1..end)
4330 }
4331 DiffTransform::DeletedHunk {
4332 base_text_byte_range,
4333 buffer_id,
4334 has_trailing_newline,
4335 ..
4336 } => {
4337 let buffer_end = base_text_byte_range.start + overshoot;
4338 let Some(buffer_diff) = self.diffs.get(buffer_id) else {
4339 panic!("{:?} is in non-extant deleted hunk", range.end)
4340 };
4341
4342 let mut suffix = buffer_diff
4343 .base_text
4344 .text_summary_for_range::<D, _>(base_text_byte_range.start..buffer_end);
4345 if *has_trailing_newline && buffer_end == base_text_byte_range.end + 1 {
4346 suffix.add_assign(&D::from_text_summary(&TextSummary::newline()))
4347 }
4348 suffix
4349 }
4350 };
4351
4352 result.add_assign(&suffix);
4353 result
4354 }
4355
4356 fn text_summary_for_excerpt_offset_range<D>(&self, mut range: Range<ExcerptOffset>) -> D
4357 where
4358 D: TextDimension,
4359 {
4360 // let mut range = range.start..range.end;
4361 let mut summary = D::zero(&());
4362 let mut cursor = self.excerpts.cursor::<ExcerptOffset>(&());
4363 cursor.seek(&range.start, Bias::Right, &());
4364 if let Some(excerpt) = cursor.item() {
4365 let mut end_before_newline = cursor.end(&());
4366 if excerpt.has_trailing_newline {
4367 end_before_newline -= ExcerptOffset::new(1);
4368 }
4369
4370 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
4371 let start_in_excerpt = excerpt_start + (range.start - *cursor.start()).value;
4372 let end_in_excerpt =
4373 excerpt_start + (cmp::min(end_before_newline, range.end) - *cursor.start()).value;
4374 summary.add_assign(
4375 &excerpt
4376 .buffer
4377 .text_summary_for_range(start_in_excerpt..end_in_excerpt),
4378 );
4379
4380 if range.end > end_before_newline {
4381 summary.add_assign(&D::from_text_summary(&TextSummary::from("\n")));
4382 }
4383
4384 cursor.next(&());
4385 }
4386
4387 if range.end > *cursor.start() {
4388 summary.add_assign(
4389 &cursor
4390 .summary::<_, ExcerptDimension<D>>(&range.end, Bias::Right, &())
4391 .0,
4392 );
4393 if let Some(excerpt) = cursor.item() {
4394 range.end = cmp::max(*cursor.start(), range.end);
4395
4396 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
4397 let end_in_excerpt = excerpt_start + (range.end - *cursor.start()).value;
4398 summary.add_assign(
4399 &excerpt
4400 .buffer
4401 .text_summary_for_range(excerpt_start..end_in_excerpt),
4402 );
4403 }
4404 }
4405
4406 summary
4407 }
4408
4409 pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
4410 where
4411 D: TextDimension + Ord + Sub<D, Output = D>,
4412 {
4413 self.summaries_for_anchors([anchor])[0]
4414 }
4415
4416 fn resolve_summary_for_anchor<D>(
4417 &self,
4418 anchor: &Anchor,
4419 excerpt_position: D,
4420 diff_transforms: &mut Cursor<DiffTransform, (ExcerptDimension<D>, OutputDimension<D>)>,
4421 ) -> D
4422 where
4423 D: TextDimension + Ord + Sub<D, Output = D>,
4424 {
4425 loop {
4426 let transform_end_position = diff_transforms.end(&()).0 .0;
4427 let at_transform_end =
4428 excerpt_position == transform_end_position && diff_transforms.item().is_some();
4429 if at_transform_end && anchor.text_anchor.bias == Bias::Right {
4430 diff_transforms.next(&());
4431 continue;
4432 }
4433
4434 let mut position = diff_transforms.start().1 .0;
4435 match diff_transforms.item() {
4436 Some(DiffTransform::DeletedHunk {
4437 buffer_id,
4438 base_text_byte_range,
4439 ..
4440 }) => {
4441 let mut in_deleted_hunk = false;
4442 if let Some(diff_base_anchor) = &anchor.diff_base_anchor {
4443 if let Some(diff) = self.diffs.get(buffer_id) {
4444 if diff.base_text.can_resolve(&diff_base_anchor) {
4445 let base_text_offset = diff_base_anchor.to_offset(&diff.base_text);
4446 if base_text_offset >= base_text_byte_range.start
4447 && base_text_offset <= base_text_byte_range.end
4448 {
4449 let position_in_hunk =
4450 diff.base_text.text_summary_for_range::<D, _>(
4451 base_text_byte_range.start..base_text_offset,
4452 );
4453 position.add_assign(&position_in_hunk);
4454 in_deleted_hunk = true;
4455 } else if at_transform_end {
4456 diff_transforms.next(&());
4457 continue;
4458 }
4459 }
4460 }
4461 }
4462 if !in_deleted_hunk {
4463 position = diff_transforms.end(&()).1 .0;
4464 }
4465 }
4466 _ => {
4467 if at_transform_end && anchor.diff_base_anchor.is_some() {
4468 diff_transforms.next(&());
4469 continue;
4470 }
4471 let overshoot = excerpt_position - diff_transforms.start().0 .0;
4472 position.add_assign(&overshoot);
4473 }
4474 }
4475
4476 return position;
4477 }
4478 }
4479
4480 fn excerpt_offset_for_anchor(&self, anchor: &Anchor) -> ExcerptOffset {
4481 let mut cursor = self
4482 .excerpts
4483 .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
4484 let locator = self.excerpt_locator_for_id(anchor.excerpt_id);
4485
4486 cursor.seek(&Some(locator), Bias::Left, &());
4487 if cursor.item().is_none() {
4488 cursor.next(&());
4489 }
4490
4491 let mut position = cursor.start().1;
4492 if let Some(excerpt) = cursor.item() {
4493 if excerpt.id == anchor.excerpt_id {
4494 let excerpt_buffer_start = excerpt
4495 .buffer
4496 .offset_for_anchor(&excerpt.range.context.start);
4497 let excerpt_buffer_end =
4498 excerpt.buffer.offset_for_anchor(&excerpt.range.context.end);
4499 let buffer_position = cmp::min(
4500 excerpt_buffer_end,
4501 excerpt.buffer.offset_for_anchor(&anchor.text_anchor),
4502 );
4503 if buffer_position > excerpt_buffer_start {
4504 position.value += buffer_position - excerpt_buffer_start;
4505 }
4506 }
4507 }
4508 position
4509 }
4510
4511 pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
4512 where
4513 D: TextDimension + Ord + Sub<D, Output = D>,
4514 I: 'a + IntoIterator<Item = &'a Anchor>,
4515 {
4516 let mut anchors = anchors.into_iter().peekable();
4517 let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&());
4518 let mut diff_transforms_cursor = self
4519 .diff_transforms
4520 .cursor::<(ExcerptDimension<D>, OutputDimension<D>)>(&());
4521 diff_transforms_cursor.next(&());
4522
4523 let mut summaries = Vec::new();
4524 while let Some(anchor) = anchors.peek() {
4525 let excerpt_id = anchor.excerpt_id;
4526 let excerpt_anchors = iter::from_fn(|| {
4527 let anchor = anchors.peek()?;
4528 if anchor.excerpt_id == excerpt_id {
4529 Some(anchors.next().unwrap())
4530 } else {
4531 None
4532 }
4533 });
4534
4535 let locator = self.excerpt_locator_for_id(excerpt_id);
4536 cursor.seek_forward(locator, Bias::Left, &());
4537 if cursor.item().is_none() {
4538 cursor.next(&());
4539 }
4540
4541 let excerpt_start_position = D::from_text_summary(&cursor.start().text);
4542 if let Some(excerpt) = cursor.item() {
4543 if excerpt.id != excerpt_id {
4544 let position = self.resolve_summary_for_anchor(
4545 &Anchor::min(),
4546 excerpt_start_position,
4547 &mut diff_transforms_cursor,
4548 );
4549 summaries.extend(excerpt_anchors.map(|_| position));
4550 continue;
4551 }
4552 let excerpt_buffer_start =
4553 excerpt.range.context.start.summary::<D>(&excerpt.buffer);
4554 let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer);
4555 for (buffer_summary, anchor) in excerpt
4556 .buffer
4557 .summaries_for_anchors_with_payload::<D, _, _>(
4558 excerpt_anchors.map(|a| (&a.text_anchor, a)),
4559 )
4560 {
4561 let summary = cmp::min(excerpt_buffer_end, buffer_summary);
4562 let mut position = excerpt_start_position;
4563 if summary > excerpt_buffer_start {
4564 position.add_assign(&(summary - excerpt_buffer_start));
4565 }
4566
4567 if position > diff_transforms_cursor.start().0 .0 {
4568 diff_transforms_cursor.seek_forward(
4569 &ExcerptDimension(position),
4570 Bias::Left,
4571 &(),
4572 );
4573 }
4574
4575 summaries.push(self.resolve_summary_for_anchor(
4576 anchor,
4577 position,
4578 &mut diff_transforms_cursor,
4579 ));
4580 }
4581 } else {
4582 diff_transforms_cursor.seek_forward(
4583 &ExcerptDimension(excerpt_start_position),
4584 Bias::Left,
4585 &(),
4586 );
4587 let position = self.resolve_summary_for_anchor(
4588 &Anchor::max(),
4589 excerpt_start_position,
4590 &mut diff_transforms_cursor,
4591 );
4592 summaries.extend(excerpt_anchors.map(|_| position));
4593 }
4594 }
4595
4596 summaries
4597 }
4598
4599 pub fn dimensions_from_points<'a, D>(
4600 &'a self,
4601 points: impl 'a + IntoIterator<Item = Point>,
4602 ) -> impl 'a + Iterator<Item = D>
4603 where
4604 D: TextDimension + Sub<D, Output = D>,
4605 {
4606 let mut cursor = self.cursor::<DimensionPair<Point, D>>();
4607 cursor.seek(&DimensionPair {
4608 key: Point::default(),
4609 value: None,
4610 });
4611 let mut points = points.into_iter();
4612 iter::from_fn(move || {
4613 let point = points.next()?;
4614
4615 cursor.seek_forward(&DimensionPair {
4616 key: point,
4617 value: None,
4618 });
4619
4620 if let Some(region) = cursor.region() {
4621 let overshoot = point - region.range.start.key;
4622 let buffer_point = region.buffer_range.start.key + overshoot;
4623 let mut position = region.range.start.value.unwrap();
4624 position.add_assign(
4625 ®ion
4626 .buffer
4627 .text_summary_for_range(region.buffer_range.start.key..buffer_point),
4628 );
4629 return Some(position);
4630 } else {
4631 return Some(D::from_text_summary(&self.text_summary()));
4632 }
4633 })
4634 }
4635
4636 pub fn refresh_anchors<'a, I>(&'a self, anchors: I) -> Vec<(usize, Anchor, bool)>
4637 where
4638 I: 'a + IntoIterator<Item = &'a Anchor>,
4639 {
4640 let mut anchors = anchors.into_iter().enumerate().peekable();
4641 let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
4642 cursor.next(&());
4643
4644 let mut result = Vec::new();
4645
4646 while let Some((_, anchor)) = anchors.peek() {
4647 let old_excerpt_id = anchor.excerpt_id;
4648
4649 // Find the location where this anchor's excerpt should be.
4650 let old_locator = self.excerpt_locator_for_id(old_excerpt_id);
4651 cursor.seek_forward(&Some(old_locator), Bias::Left, &());
4652
4653 if cursor.item().is_none() {
4654 cursor.next(&());
4655 }
4656
4657 let next_excerpt = cursor.item();
4658 let prev_excerpt = cursor.prev_item();
4659
4660 // Process all of the anchors for this excerpt.
4661 while let Some((_, anchor)) = anchors.peek() {
4662 if anchor.excerpt_id != old_excerpt_id {
4663 break;
4664 }
4665 let (anchor_ix, anchor) = anchors.next().unwrap();
4666 let mut anchor = *anchor;
4667
4668 // Leave min and max anchors unchanged if invalid or
4669 // if the old excerpt still exists at this location
4670 let mut kept_position = next_excerpt
4671 .map_or(false, |e| e.id == old_excerpt_id && e.contains(&anchor))
4672 || old_excerpt_id == ExcerptId::max()
4673 || old_excerpt_id == ExcerptId::min();
4674
4675 // If the old excerpt no longer exists at this location, then attempt to
4676 // find an equivalent position for this anchor in an adjacent excerpt.
4677 if !kept_position {
4678 for excerpt in [next_excerpt, prev_excerpt].iter().filter_map(|e| *e) {
4679 if excerpt.contains(&anchor) {
4680 anchor.excerpt_id = excerpt.id;
4681 kept_position = true;
4682 break;
4683 }
4684 }
4685 }
4686
4687 // If there's no adjacent excerpt that contains the anchor's position,
4688 // then report that the anchor has lost its position.
4689 if !kept_position {
4690 anchor = if let Some(excerpt) = next_excerpt {
4691 let mut text_anchor = excerpt
4692 .range
4693 .context
4694 .start
4695 .bias(anchor.text_anchor.bias, &excerpt.buffer);
4696 if text_anchor
4697 .cmp(&excerpt.range.context.end, &excerpt.buffer)
4698 .is_gt()
4699 {
4700 text_anchor = excerpt.range.context.end;
4701 }
4702 Anchor {
4703 buffer_id: Some(excerpt.buffer_id),
4704 excerpt_id: excerpt.id,
4705 text_anchor,
4706 diff_base_anchor: None,
4707 }
4708 } else if let Some(excerpt) = prev_excerpt {
4709 let mut text_anchor = excerpt
4710 .range
4711 .context
4712 .end
4713 .bias(anchor.text_anchor.bias, &excerpt.buffer);
4714 if text_anchor
4715 .cmp(&excerpt.range.context.start, &excerpt.buffer)
4716 .is_lt()
4717 {
4718 text_anchor = excerpt.range.context.start;
4719 }
4720 Anchor {
4721 buffer_id: Some(excerpt.buffer_id),
4722 excerpt_id: excerpt.id,
4723 text_anchor,
4724 diff_base_anchor: None,
4725 }
4726 } else if anchor.text_anchor.bias == Bias::Left {
4727 Anchor::min()
4728 } else {
4729 Anchor::max()
4730 };
4731 }
4732
4733 result.push((anchor_ix, anchor, kept_position));
4734 }
4735 }
4736 result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self));
4737 result
4738 }
4739
4740 pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
4741 self.anchor_at(position, Bias::Left)
4742 }
4743
4744 pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
4745 self.anchor_at(position, Bias::Right)
4746 }
4747
4748 pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
4749 let offset = position.to_offset(self);
4750
4751 // Find the given position in the diff transforms. Determine the corresponding
4752 // offset in the excerpts, and whether the position is within a deleted hunk.
4753 let mut diff_transforms = self.diff_transforms.cursor::<(usize, ExcerptOffset)>(&());
4754 diff_transforms.seek(&offset, Bias::Right, &());
4755
4756 if offset == diff_transforms.start().0 && bias == Bias::Left {
4757 if let Some(prev_item) = diff_transforms.prev_item() {
4758 match prev_item {
4759 DiffTransform::DeletedHunk { .. } => {
4760 diff_transforms.prev(&());
4761 }
4762 _ => {}
4763 }
4764 }
4765 }
4766 let offset_in_transform = offset - diff_transforms.start().0;
4767 let mut excerpt_offset = diff_transforms.start().1;
4768 let mut diff_base_anchor = None;
4769 if let Some(DiffTransform::DeletedHunk {
4770 buffer_id,
4771 base_text_byte_range,
4772 has_trailing_newline,
4773 ..
4774 }) = diff_transforms.item()
4775 {
4776 let diff_base = self.diffs.get(buffer_id).expect("missing diff base");
4777 if offset_in_transform > base_text_byte_range.len() {
4778 debug_assert!(*has_trailing_newline);
4779 bias = Bias::Right;
4780 } else {
4781 diff_base_anchor = Some(
4782 diff_base
4783 .base_text
4784 .anchor_at(base_text_byte_range.start + offset_in_transform, bias),
4785 );
4786 bias = Bias::Left;
4787 }
4788 } else {
4789 excerpt_offset += ExcerptOffset::new(offset_in_transform);
4790 };
4791
4792 if let Some((excerpt_id, buffer_id, buffer)) = self.as_singleton() {
4793 return Anchor {
4794 buffer_id: Some(buffer_id),
4795 excerpt_id: *excerpt_id,
4796 text_anchor: buffer.anchor_at(excerpt_offset.value, bias),
4797 diff_base_anchor,
4798 };
4799 }
4800
4801 let mut excerpts = self
4802 .excerpts
4803 .cursor::<(ExcerptOffset, Option<ExcerptId>)>(&());
4804 excerpts.seek(&excerpt_offset, Bias::Right, &());
4805 if excerpts.item().is_none() && excerpt_offset == excerpts.start().0 && bias == Bias::Left {
4806 excerpts.prev(&());
4807 }
4808 if let Some(excerpt) = excerpts.item() {
4809 let mut overshoot = excerpt_offset.saturating_sub(excerpts.start().0).value;
4810 if excerpt.has_trailing_newline && excerpt_offset == excerpts.end(&()).0 {
4811 overshoot -= 1;
4812 bias = Bias::Right;
4813 }
4814
4815 let buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
4816 let text_anchor =
4817 excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
4818 Anchor {
4819 buffer_id: Some(excerpt.buffer_id),
4820 excerpt_id: excerpt.id,
4821 text_anchor,
4822 diff_base_anchor,
4823 }
4824 } else if excerpt_offset.is_zero() && bias == Bias::Left {
4825 Anchor::min()
4826 } else {
4827 Anchor::max()
4828 }
4829 }
4830
4831 /// Returns an anchor for the given excerpt and text anchor,
4832 /// returns None if the excerpt_id is no longer valid.
4833 pub fn anchor_in_excerpt(
4834 &self,
4835 excerpt_id: ExcerptId,
4836 text_anchor: text::Anchor,
4837 ) -> Option<Anchor> {
4838 let locator = self.excerpt_locator_for_id(excerpt_id);
4839 let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
4840 cursor.seek(locator, Bias::Left, &());
4841 if let Some(excerpt) = cursor.item() {
4842 if excerpt.id == excerpt_id {
4843 let text_anchor = excerpt.clip_anchor(text_anchor);
4844 drop(cursor);
4845 return Some(Anchor {
4846 buffer_id: Some(excerpt.buffer_id),
4847 excerpt_id,
4848 text_anchor,
4849 diff_base_anchor: None,
4850 });
4851 }
4852 }
4853 None
4854 }
4855
4856 pub fn context_range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<Range<text::Anchor>> {
4857 Some(self.excerpt(excerpt_id)?.range.context.clone())
4858 }
4859
4860 pub fn can_resolve(&self, anchor: &Anchor) -> bool {
4861 if anchor.excerpt_id == ExcerptId::min() || anchor.excerpt_id == ExcerptId::max() {
4862 true
4863 } else if let Some(excerpt) = self.excerpt(anchor.excerpt_id) {
4864 excerpt.buffer.can_resolve(&anchor.text_anchor)
4865 } else {
4866 false
4867 }
4868 }
4869
4870 pub fn excerpts(
4871 &self,
4872 ) -> impl Iterator<Item = (ExcerptId, &BufferSnapshot, ExcerptRange<text::Anchor>)> {
4873 self.excerpts
4874 .iter()
4875 .map(|excerpt| (excerpt.id, &excerpt.buffer, excerpt.range.clone()))
4876 }
4877
4878 fn cursor<D: TextDimension + Default>(&self) -> MultiBufferCursor<D> {
4879 let excerpts = self.excerpts.cursor(&());
4880 let diff_transforms = self.diff_transforms.cursor(&());
4881 MultiBufferCursor {
4882 excerpts,
4883 diff_transforms,
4884 diffs: &self.diffs,
4885 cached_region: None,
4886 }
4887 }
4888
4889 pub fn excerpt_before(&self, id: ExcerptId) -> Option<MultiBufferExcerpt<'_>> {
4890 let start_locator = self.excerpt_locator_for_id(id);
4891 let mut excerpts = self
4892 .excerpts
4893 .cursor::<(Option<&Locator>, ExcerptDimension<usize>)>(&());
4894 excerpts.seek(&Some(start_locator), Bias::Left, &());
4895 excerpts.prev(&());
4896
4897 let mut diff_transforms = self
4898 .diff_transforms
4899 .cursor::<(OutputDimension<usize>, ExcerptDimension<usize>)>(&());
4900 diff_transforms.seek(&excerpts.start().1, Bias::Left, &());
4901 if diff_transforms.end(&()).1 < excerpts.start().1 {
4902 diff_transforms.next(&());
4903 }
4904
4905 let excerpt = excerpts.item()?;
4906 Some(MultiBufferExcerpt {
4907 excerpt,
4908 offset: diff_transforms.start().0 .0,
4909 buffer_offset: excerpt.range.context.start.to_offset(&excerpt.buffer),
4910 excerpt_offset: excerpts.start().1.clone(),
4911 diff_transforms,
4912 })
4913 }
4914
4915 pub fn excerpt_boundaries_in_range<R, T>(
4916 &self,
4917 range: R,
4918 ) -> impl Iterator<Item = ExcerptBoundary> + '_
4919 where
4920 R: RangeBounds<T>,
4921 T: ToOffset,
4922 {
4923 let start_offset;
4924 let start = match range.start_bound() {
4925 Bound::Included(start) => {
4926 start_offset = start.to_offset(self);
4927 Bound::Included(start_offset)
4928 }
4929 Bound::Excluded(_) => {
4930 panic!("not supported")
4931 }
4932 Bound::Unbounded => {
4933 start_offset = 0;
4934 Bound::Unbounded
4935 }
4936 };
4937 let end = match range.end_bound() {
4938 Bound::Included(end) => Bound::Included(end.to_offset(self)),
4939 Bound::Excluded(end) => Bound::Excluded(end.to_offset(self)),
4940 Bound::Unbounded => Bound::Unbounded,
4941 };
4942 let bounds = (start, end);
4943
4944 let mut cursor = self.cursor::<DimensionPair<usize, Point>>();
4945 cursor.seek(&DimensionPair {
4946 key: start_offset,
4947 value: None,
4948 });
4949
4950 if cursor
4951 .region()
4952 .is_some_and(|region| bounds.contains(®ion.range.start.key))
4953 {
4954 cursor.prev_excerpt();
4955 } else {
4956 cursor.seek_to_start_of_current_excerpt();
4957 }
4958 let mut prev_region = cursor.region();
4959
4960 cursor.next_excerpt();
4961
4962 let mut visited_end = false;
4963 iter::from_fn(move || loop {
4964 if self.singleton {
4965 return None;
4966 }
4967
4968 let next_region = cursor.region();
4969 cursor.next_excerpt();
4970
4971 let next_region_start = if let Some(region) = &next_region {
4972 if !bounds.contains(®ion.range.start.key) {
4973 prev_region = next_region;
4974 continue;
4975 }
4976 region.range.start.value.unwrap()
4977 } else {
4978 if !bounds.contains(&self.len()) {
4979 return None;
4980 }
4981 self.max_point()
4982 };
4983 let next_region_end = if let Some(region) = cursor.region() {
4984 region.range.start.value.unwrap()
4985 } else {
4986 self.max_point()
4987 };
4988
4989 let prev = prev_region.as_ref().map(|region| ExcerptInfo {
4990 id: region.excerpt.id,
4991 buffer: region.excerpt.buffer.clone(),
4992 buffer_id: region.excerpt.buffer_id,
4993 range: region.excerpt.range.clone(),
4994 end_row: MultiBufferRow(next_region_start.row),
4995 });
4996
4997 let next = next_region.as_ref().map(|region| ExcerptInfo {
4998 id: region.excerpt.id,
4999 buffer: region.excerpt.buffer.clone(),
5000 buffer_id: region.excerpt.buffer_id,
5001 range: region.excerpt.range.clone(),
5002 end_row: if region.excerpt.has_trailing_newline {
5003 MultiBufferRow(next_region_end.row - 1)
5004 } else {
5005 MultiBufferRow(next_region_end.row)
5006 },
5007 });
5008
5009 if next.is_none() {
5010 if visited_end {
5011 return None;
5012 } else {
5013 visited_end = true;
5014 }
5015 }
5016
5017 let row = MultiBufferRow(next_region_start.row);
5018
5019 prev_region = next_region;
5020
5021 return Some(ExcerptBoundary { row, prev, next });
5022 })
5023 }
5024
5025 pub fn edit_count(&self) -> usize {
5026 self.edit_count
5027 }
5028
5029 pub fn non_text_state_update_count(&self) -> usize {
5030 self.non_text_state_update_count
5031 }
5032
5033 /// Returns the smallest enclosing bracket ranges containing the given range or
5034 /// None if no brackets contain range or the range is not contained in a single
5035 /// excerpt
5036 ///
5037 /// Can optionally pass a range_filter to filter the ranges of brackets to consider
5038 pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
5039 &self,
5040 range: Range<T>,
5041 range_filter: Option<&dyn Fn(&BufferSnapshot, Range<usize>, Range<usize>) -> bool>,
5042 ) -> Option<(Range<usize>, Range<usize>)> {
5043 let range = range.start.to_offset(self)..range.end.to_offset(self);
5044 let mut excerpt = self.excerpt_containing(range.clone())?;
5045 let buffer = excerpt.buffer();
5046 let excerpt_buffer_range = excerpt.buffer_range();
5047
5048 // Filter to ranges contained in the excerpt
5049 let range_filter = |open: Range<usize>, close: Range<usize>| -> bool {
5050 excerpt_buffer_range.contains(&open.start)
5051 && excerpt_buffer_range.contains(&close.end)
5052 && range_filter.map_or(true, |filter| filter(buffer, open, close))
5053 };
5054
5055 let (open, close) = excerpt.buffer().innermost_enclosing_bracket_ranges(
5056 excerpt.map_range_to_buffer(range),
5057 Some(&range_filter),
5058 )?;
5059
5060 Some((
5061 excerpt.map_range_from_buffer(open),
5062 excerpt.map_range_from_buffer(close),
5063 ))
5064 }
5065
5066 /// Returns enclosing bracket ranges containing the given range or returns None if the range is
5067 /// not contained in a single excerpt
5068 pub fn enclosing_bracket_ranges<T: ToOffset>(
5069 &self,
5070 range: Range<T>,
5071 ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + '_> {
5072 let range = range.start.to_offset(self)..range.end.to_offset(self);
5073 let mut excerpt = self.excerpt_containing(range.clone())?;
5074
5075 Some(
5076 excerpt
5077 .buffer()
5078 .enclosing_bracket_ranges(excerpt.map_range_to_buffer(range))
5079 .filter_map(move |(open, close)| {
5080 if excerpt.contains_buffer_range(open.start..close.end) {
5081 Some((
5082 excerpt.map_range_from_buffer(open),
5083 excerpt.map_range_from_buffer(close),
5084 ))
5085 } else {
5086 None
5087 }
5088 }),
5089 )
5090 }
5091
5092 /// Returns enclosing bracket ranges containing the given range or returns None if the range is
5093 /// not contained in a single excerpt
5094 pub fn text_object_ranges<T: ToOffset>(
5095 &self,
5096 range: Range<T>,
5097 options: TreeSitterOptions,
5098 ) -> impl Iterator<Item = (Range<usize>, TextObject)> + '_ {
5099 let range = range.start.to_offset(self)..range.end.to_offset(self);
5100 self.excerpt_containing(range.clone())
5101 .map(|mut excerpt| {
5102 excerpt
5103 .buffer()
5104 .text_object_ranges(excerpt.map_range_to_buffer(range), options)
5105 .filter_map(move |(range, text_object)| {
5106 if excerpt.contains_buffer_range(range.clone()) {
5107 Some((excerpt.map_range_from_buffer(range), text_object))
5108 } else {
5109 None
5110 }
5111 })
5112 })
5113 .into_iter()
5114 .flatten()
5115 }
5116
5117 /// Returns bracket range pairs overlapping the given `range` or returns None if the `range` is
5118 /// not contained in a single excerpt
5119 pub fn bracket_ranges<T: ToOffset>(
5120 &self,
5121 range: Range<T>,
5122 ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + '_> {
5123 let range = range.start.to_offset(self)..range.end.to_offset(self);
5124 let mut excerpt = self.excerpt_containing(range.clone())?;
5125
5126 Some(
5127 excerpt
5128 .buffer()
5129 .bracket_ranges(excerpt.map_range_to_buffer(range))
5130 .filter_map(move |(start_bracket_range, close_bracket_range)| {
5131 let buffer_range = start_bracket_range.start..close_bracket_range.end;
5132 if excerpt.contains_buffer_range(buffer_range) {
5133 Some((
5134 excerpt.map_range_from_buffer(start_bracket_range),
5135 excerpt.map_range_from_buffer(close_bracket_range),
5136 ))
5137 } else {
5138 None
5139 }
5140 }),
5141 )
5142 }
5143
5144 pub fn redacted_ranges<'a, T: ToOffset>(
5145 &'a self,
5146 range: Range<T>,
5147 redaction_enabled: impl Fn(Option<&Arc<dyn File>>) -> bool + 'a,
5148 ) -> impl Iterator<Item = Range<usize>> + 'a {
5149 let range = range.start.to_offset(self)..range.end.to_offset(self);
5150 self.lift_buffer_metadata(range, move |buffer, range| {
5151 if redaction_enabled(buffer.file()) {
5152 Some(buffer.redacted_ranges(range).map(|range| (range, ())))
5153 } else {
5154 None
5155 }
5156 })
5157 .map(|(range, _, _)| range)
5158 }
5159
5160 pub fn runnable_ranges(
5161 &self,
5162 range: Range<Anchor>,
5163 ) -> impl Iterator<Item = language::RunnableRange> + '_ {
5164 let range = range.start.to_offset(self)..range.end.to_offset(self);
5165 self.lift_buffer_metadata(range, move |buffer, range| {
5166 Some(
5167 buffer
5168 .runnable_ranges(range.clone())
5169 .filter(move |runnable| {
5170 runnable.run_range.start >= range.start
5171 && runnable.run_range.end < range.end
5172 })
5173 .map(|runnable| (runnable.run_range.clone(), runnable)),
5174 )
5175 })
5176 .map(|(run_range, runnable, _)| language::RunnableRange {
5177 run_range,
5178 ..runnable
5179 })
5180 }
5181
5182 pub fn line_indents(
5183 &self,
5184 start_row: MultiBufferRow,
5185 buffer_filter: impl Fn(&BufferSnapshot) -> bool,
5186 ) -> impl Iterator<Item = (MultiBufferRow, LineIndent, &BufferSnapshot)> {
5187 let max_point = self.max_point();
5188 let mut cursor = self.cursor::<Point>();
5189 cursor.seek(&Point::new(start_row.0, 0));
5190 iter::from_fn(move || {
5191 let mut region = cursor.region()?;
5192 while !buffer_filter(®ion.excerpt.buffer) {
5193 cursor.next();
5194 region = cursor.region()?;
5195 }
5196 let overshoot = start_row.0.saturating_sub(region.range.start.row);
5197 let buffer_start_row =
5198 (region.buffer_range.start.row + overshoot).min(region.buffer_range.end.row);
5199
5200 let buffer_end_row = if region.is_main_buffer
5201 && (region.has_trailing_newline || region.range.end == max_point)
5202 {
5203 region.buffer_range.end.row
5204 } else {
5205 region.buffer_range.end.row.saturating_sub(1)
5206 };
5207
5208 let line_indents = region
5209 .buffer
5210 .line_indents_in_row_range(buffer_start_row..buffer_end_row);
5211 cursor.next();
5212 return Some(line_indents.map(move |(buffer_row, indent)| {
5213 let row = region.range.start.row + (buffer_row - region.buffer_range.start.row);
5214 (MultiBufferRow(row), indent, ®ion.excerpt.buffer)
5215 }));
5216 })
5217 .flatten()
5218 }
5219
5220 pub fn reversed_line_indents(
5221 &self,
5222 end_row: MultiBufferRow,
5223 buffer_filter: impl Fn(&BufferSnapshot) -> bool,
5224 ) -> impl Iterator<Item = (MultiBufferRow, LineIndent, &BufferSnapshot)> {
5225 let max_point = self.max_point();
5226 let mut cursor = self.cursor::<Point>();
5227 cursor.seek(&Point::new(end_row.0, 0));
5228 iter::from_fn(move || {
5229 let mut region = cursor.region()?;
5230 while !buffer_filter(®ion.excerpt.buffer) {
5231 cursor.prev();
5232 region = cursor.region()?;
5233 }
5234
5235 let buffer_start_row = region.buffer_range.start.row;
5236 let buffer_end_row = if region.is_main_buffer
5237 && (region.has_trailing_newline || region.range.end == max_point)
5238 {
5239 region.buffer_range.end.row + 1
5240 } else {
5241 region.buffer_range.end.row
5242 };
5243
5244 let overshoot = end_row.0 - region.range.start.row;
5245 let buffer_end_row =
5246 (region.buffer_range.start.row + overshoot + 1).min(buffer_end_row);
5247
5248 let line_indents = region
5249 .buffer
5250 .reversed_line_indents_in_row_range(buffer_start_row..buffer_end_row);
5251 cursor.prev();
5252 return Some(line_indents.map(move |(buffer_row, indent)| {
5253 let row = region.range.start.row + (buffer_row - region.buffer_range.start.row);
5254 (MultiBufferRow(row), indent, ®ion.excerpt.buffer)
5255 }));
5256 })
5257 .flatten()
5258 }
5259
5260 pub async fn enclosing_indent(
5261 &self,
5262 mut target_row: MultiBufferRow,
5263 ) -> Option<(Range<MultiBufferRow>, LineIndent)> {
5264 let max_row = MultiBufferRow(self.max_point().row);
5265 if target_row >= max_row {
5266 return None;
5267 }
5268
5269 let mut target_indent = self.line_indent_for_row(target_row);
5270
5271 // If the current row is at the start of an indented block, we want to return this
5272 // block as the enclosing indent.
5273 if !target_indent.is_line_empty() && target_row < max_row {
5274 let next_line_indent = self.line_indent_for_row(MultiBufferRow(target_row.0 + 1));
5275 if !next_line_indent.is_line_empty()
5276 && target_indent.raw_len() < next_line_indent.raw_len()
5277 {
5278 target_indent = next_line_indent;
5279 target_row.0 += 1;
5280 }
5281 }
5282
5283 const SEARCH_ROW_LIMIT: u32 = 25000;
5284 const SEARCH_WHITESPACE_ROW_LIMIT: u32 = 2500;
5285 const YIELD_INTERVAL: u32 = 100;
5286
5287 let mut accessed_row_counter = 0;
5288
5289 // If there is a blank line at the current row, search for the next non indented lines
5290 if target_indent.is_line_empty() {
5291 let start = MultiBufferRow(target_row.0.saturating_sub(SEARCH_WHITESPACE_ROW_LIMIT));
5292 let end =
5293 MultiBufferRow((max_row.0 + 1).min(target_row.0 + SEARCH_WHITESPACE_ROW_LIMIT));
5294
5295 let mut non_empty_line_above = None;
5296 for (row, indent, _) in self.reversed_line_indents(target_row, |_| true) {
5297 if row < start {
5298 break;
5299 }
5300 accessed_row_counter += 1;
5301 if accessed_row_counter == YIELD_INTERVAL {
5302 accessed_row_counter = 0;
5303 yield_now().await;
5304 }
5305 if !indent.is_line_empty() {
5306 non_empty_line_above = Some((row, indent));
5307 break;
5308 }
5309 }
5310
5311 let mut non_empty_line_below = None;
5312 for (row, indent, _) in self.line_indents(target_row, |_| true) {
5313 if row > end {
5314 break;
5315 }
5316 accessed_row_counter += 1;
5317 if accessed_row_counter == YIELD_INTERVAL {
5318 accessed_row_counter = 0;
5319 yield_now().await;
5320 }
5321 if !indent.is_line_empty() {
5322 non_empty_line_below = Some((row, indent));
5323 break;
5324 }
5325 }
5326
5327 let (row, indent) = match (non_empty_line_above, non_empty_line_below) {
5328 (Some((above_row, above_indent)), Some((below_row, below_indent))) => {
5329 if above_indent.raw_len() >= below_indent.raw_len() {
5330 (above_row, above_indent)
5331 } else {
5332 (below_row, below_indent)
5333 }
5334 }
5335 (Some(above), None) => above,
5336 (None, Some(below)) => below,
5337 _ => return None,
5338 };
5339
5340 target_indent = indent;
5341 target_row = row;
5342 }
5343
5344 let start = MultiBufferRow(target_row.0.saturating_sub(SEARCH_ROW_LIMIT));
5345 let end = MultiBufferRow((max_row.0 + 1).min(target_row.0 + SEARCH_ROW_LIMIT));
5346
5347 let mut start_indent = None;
5348 for (row, indent, _) in self.reversed_line_indents(target_row, |_| true) {
5349 if row < start {
5350 break;
5351 }
5352 accessed_row_counter += 1;
5353 if accessed_row_counter == YIELD_INTERVAL {
5354 accessed_row_counter = 0;
5355 yield_now().await;
5356 }
5357 if !indent.is_line_empty() && indent.raw_len() < target_indent.raw_len() {
5358 start_indent = Some((row, indent));
5359 break;
5360 }
5361 }
5362 let (start_row, start_indent_size) = start_indent?;
5363
5364 let mut end_indent = (end, None);
5365 for (row, indent, _) in self.line_indents(target_row, |_| true) {
5366 if row > end {
5367 break;
5368 }
5369 accessed_row_counter += 1;
5370 if accessed_row_counter == YIELD_INTERVAL {
5371 accessed_row_counter = 0;
5372 yield_now().await;
5373 }
5374 if !indent.is_line_empty() && indent.raw_len() < target_indent.raw_len() {
5375 end_indent = (MultiBufferRow(row.0.saturating_sub(1)), Some(indent));
5376 break;
5377 }
5378 }
5379 let (end_row, end_indent_size) = end_indent;
5380
5381 let indent = if let Some(end_indent_size) = end_indent_size {
5382 if start_indent_size.raw_len() > end_indent_size.raw_len() {
5383 start_indent_size
5384 } else {
5385 end_indent_size
5386 }
5387 } else {
5388 start_indent_size
5389 };
5390
5391 Some((start_row..end_row, indent))
5392 }
5393
5394 pub fn indent_guides_in_range<T: ToPoint>(
5395 &self,
5396 range: Range<T>,
5397 ignore_disabled_for_language: bool,
5398 cx: &App,
5399 ) -> impl Iterator<Item = IndentGuide> {
5400 let range = range.start.to_point(self)..range.end.to_point(self);
5401 let start_row = MultiBufferRow(range.start.row);
5402 let end_row = MultiBufferRow(range.end.row);
5403
5404 let mut row_indents = self.line_indents(start_row, |buffer| {
5405 let settings =
5406 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx);
5407 settings.indent_guides.enabled || ignore_disabled_for_language
5408 });
5409
5410 let mut result = Vec::new();
5411 let mut indent_stack = SmallVec::<[IndentGuide; 8]>::new();
5412
5413 while let Some((first_row, mut line_indent, buffer)) = row_indents.next() {
5414 if first_row > end_row {
5415 break;
5416 }
5417 let current_depth = indent_stack.len() as u32;
5418
5419 let settings =
5420 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx);
5421 let tab_size = settings.tab_size.get() as u32;
5422
5423 // When encountering empty, continue until found useful line indent
5424 // then add to the indent stack with the depth found
5425 let mut found_indent = false;
5426 let mut last_row = first_row;
5427 if line_indent.is_line_empty() {
5428 while !found_indent {
5429 let Some((target_row, new_line_indent, _)) = row_indents.next() else {
5430 break;
5431 };
5432 const TRAILING_ROW_SEARCH_LIMIT: u32 = 25;
5433 if target_row > MultiBufferRow(end_row.0 + TRAILING_ROW_SEARCH_LIMIT) {
5434 break;
5435 }
5436
5437 if new_line_indent.is_line_empty() {
5438 continue;
5439 }
5440 last_row = target_row.min(end_row);
5441 line_indent = new_line_indent;
5442 found_indent = true;
5443 break;
5444 }
5445 } else {
5446 found_indent = true
5447 }
5448
5449 let depth = if found_indent {
5450 line_indent.len(tab_size) / tab_size
5451 + ((line_indent.len(tab_size) % tab_size) > 0) as u32
5452 } else {
5453 current_depth
5454 };
5455
5456 match depth.cmp(¤t_depth) {
5457 cmp::Ordering::Less => {
5458 for _ in 0..(current_depth - depth) {
5459 let mut indent = indent_stack.pop().unwrap();
5460 if last_row != first_row {
5461 // In this case, we landed on an empty row, had to seek forward,
5462 // and discovered that the indent we where on is ending.
5463 // This means that the last display row must
5464 // be on line that ends this indent range, so we
5465 // should display the range up to the first non-empty line
5466 indent.end_row = MultiBufferRow(first_row.0.saturating_sub(1));
5467 }
5468
5469 result.push(indent)
5470 }
5471 }
5472 cmp::Ordering::Greater => {
5473 for next_depth in current_depth..depth {
5474 indent_stack.push(IndentGuide {
5475 buffer_id: buffer.remote_id(),
5476 start_row: first_row,
5477 end_row: last_row,
5478 depth: next_depth,
5479 tab_size,
5480 settings: settings.indent_guides,
5481 });
5482 }
5483 }
5484 _ => {}
5485 }
5486
5487 for indent in indent_stack.iter_mut() {
5488 indent.end_row = last_row;
5489 }
5490 }
5491
5492 result.extend(indent_stack);
5493 result.into_iter()
5494 }
5495
5496 pub fn trailing_excerpt_update_count(&self) -> usize {
5497 self.trailing_excerpt_update_count
5498 }
5499
5500 pub fn file_at<T: ToOffset>(&self, point: T) -> Option<&Arc<dyn File>> {
5501 self.point_to_buffer_offset(point)
5502 .and_then(|(buffer, _)| buffer.file())
5503 }
5504
5505 pub fn language_at<T: ToOffset>(&self, point: T) -> Option<&Arc<Language>> {
5506 self.point_to_buffer_offset(point)
5507 .and_then(|(buffer, offset)| buffer.language_at(offset))
5508 }
5509
5510 pub fn settings_at<'a, T: ToOffset>(
5511 &'a self,
5512 point: T,
5513 cx: &'a App,
5514 ) -> Cow<'a, LanguageSettings> {
5515 let mut language = None;
5516 let mut file = None;
5517 if let Some((buffer, offset)) = self.point_to_buffer_offset(point) {
5518 language = buffer.language_at(offset);
5519 file = buffer.file();
5520 }
5521 language_settings(language.map(|l| l.name()), file, cx)
5522 }
5523
5524 pub fn language_scope_at<T: ToOffset>(&self, point: T) -> Option<LanguageScope> {
5525 self.point_to_buffer_offset(point)
5526 .and_then(|(buffer, offset)| buffer.language_scope_at(offset))
5527 }
5528
5529 pub fn char_classifier_at<T: ToOffset>(&self, point: T) -> CharClassifier {
5530 self.point_to_buffer_offset(point)
5531 .map(|(buffer, offset)| buffer.char_classifier_at(offset))
5532 .unwrap_or_default()
5533 }
5534
5535 pub fn language_indent_size_at<T: ToOffset>(
5536 &self,
5537 position: T,
5538 cx: &App,
5539 ) -> Option<IndentSize> {
5540 let (buffer_snapshot, offset) = self.point_to_buffer_offset(position)?;
5541 Some(buffer_snapshot.language_indent_size_at(offset, cx))
5542 }
5543
5544 pub fn is_dirty(&self) -> bool {
5545 self.is_dirty
5546 }
5547
5548 pub fn has_deleted_file(&self) -> bool {
5549 self.has_deleted_file
5550 }
5551
5552 pub fn has_conflict(&self) -> bool {
5553 self.has_conflict
5554 }
5555
5556 pub fn has_diagnostics(&self) -> bool {
5557 self.excerpts
5558 .iter()
5559 .any(|excerpt| excerpt.buffer.has_diagnostics())
5560 }
5561
5562 pub fn diagnostic_group(
5563 &self,
5564 buffer_id: BufferId,
5565 group_id: usize,
5566 ) -> impl Iterator<Item = DiagnosticEntry<Point>> + '_ {
5567 self.lift_buffer_metadata(Point::zero()..self.max_point(), move |buffer, _| {
5568 if buffer.remote_id() != buffer_id {
5569 return None;
5570 };
5571 Some(
5572 buffer
5573 .diagnostic_group(group_id)
5574 .map(move |DiagnosticEntry { diagnostic, range }| (range, diagnostic)),
5575 )
5576 })
5577 .map(|(range, diagnostic, _)| DiagnosticEntry { diagnostic, range })
5578 }
5579
5580 pub fn diagnostics_in_range<'a, T>(
5581 &'a self,
5582 range: Range<T>,
5583 ) -> impl Iterator<Item = DiagnosticEntry<T>> + 'a
5584 where
5585 T: 'a
5586 + text::ToOffset
5587 + text::FromAnchor
5588 + TextDimension
5589 + Ord
5590 + Sub<T, Output = T>
5591 + fmt::Debug,
5592 {
5593 self.lift_buffer_metadata(range, move |buffer, buffer_range| {
5594 Some(
5595 buffer
5596 .diagnostics_in_range(buffer_range.start..buffer_range.end, false)
5597 .map(|entry| (entry.range, entry.diagnostic)),
5598 )
5599 })
5600 .map(|(range, diagnostic, _)| DiagnosticEntry { diagnostic, range })
5601 }
5602
5603 pub fn syntax_ancestor<T: ToOffset>(
5604 &self,
5605 range: Range<T>,
5606 ) -> Option<(tree_sitter::Node, Range<usize>)> {
5607 let range = range.start.to_offset(self)..range.end.to_offset(self);
5608 let mut excerpt = self.excerpt_containing(range.clone())?;
5609 let node = excerpt
5610 .buffer()
5611 .syntax_ancestor(excerpt.map_range_to_buffer(range))?;
5612 Some((node, excerpt.map_range_from_buffer(node.byte_range())))
5613 }
5614
5615 pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
5616 let (excerpt_id, _, buffer) = self.as_singleton()?;
5617 let outline = buffer.outline(theme)?;
5618 Some(Outline::new(
5619 outline
5620 .items
5621 .into_iter()
5622 .flat_map(|item| {
5623 Some(OutlineItem {
5624 depth: item.depth,
5625 range: self.anchor_in_excerpt(*excerpt_id, item.range.start)?
5626 ..self.anchor_in_excerpt(*excerpt_id, item.range.end)?,
5627 text: item.text,
5628 highlight_ranges: item.highlight_ranges,
5629 name_ranges: item.name_ranges,
5630 body_range: item.body_range.and_then(|body_range| {
5631 Some(
5632 self.anchor_in_excerpt(*excerpt_id, body_range.start)?
5633 ..self.anchor_in_excerpt(*excerpt_id, body_range.end)?,
5634 )
5635 }),
5636 annotation_range: item.annotation_range.and_then(|annotation_range| {
5637 Some(
5638 self.anchor_in_excerpt(*excerpt_id, annotation_range.start)?
5639 ..self.anchor_in_excerpt(*excerpt_id, annotation_range.end)?,
5640 )
5641 }),
5642 })
5643 })
5644 .collect(),
5645 ))
5646 }
5647
5648 pub fn symbols_containing<T: ToOffset>(
5649 &self,
5650 offset: T,
5651 theme: Option<&SyntaxTheme>,
5652 ) -> Option<(BufferId, Vec<OutlineItem<Anchor>>)> {
5653 let anchor = self.anchor_before(offset);
5654 let excerpt_id = anchor.excerpt_id;
5655 let excerpt = self.excerpt(excerpt_id)?;
5656 Some((
5657 excerpt.buffer_id,
5658 excerpt
5659 .buffer
5660 .symbols_containing(anchor.text_anchor, theme)
5661 .into_iter()
5662 .flatten()
5663 .flat_map(|item| {
5664 Some(OutlineItem {
5665 depth: item.depth,
5666 range: self.anchor_in_excerpt(excerpt_id, item.range.start)?
5667 ..self.anchor_in_excerpt(excerpt_id, item.range.end)?,
5668 text: item.text,
5669 highlight_ranges: item.highlight_ranges,
5670 name_ranges: item.name_ranges,
5671 body_range: item.body_range.and_then(|body_range| {
5672 Some(
5673 self.anchor_in_excerpt(excerpt_id, body_range.start)?
5674 ..self.anchor_in_excerpt(excerpt_id, body_range.end)?,
5675 )
5676 }),
5677 annotation_range: item.annotation_range.and_then(|body_range| {
5678 Some(
5679 self.anchor_in_excerpt(excerpt_id, body_range.start)?
5680 ..self.anchor_in_excerpt(excerpt_id, body_range.end)?,
5681 )
5682 }),
5683 })
5684 })
5685 .collect(),
5686 ))
5687 }
5688
5689 fn excerpt_locator_for_id(&self, id: ExcerptId) -> &Locator {
5690 if id == ExcerptId::min() {
5691 Locator::min_ref()
5692 } else if id == ExcerptId::max() {
5693 Locator::max_ref()
5694 } else {
5695 let mut cursor = self.excerpt_ids.cursor::<ExcerptId>(&());
5696 cursor.seek(&id, Bias::Left, &());
5697 if let Some(entry) = cursor.item() {
5698 if entry.id == id {
5699 return &entry.locator;
5700 }
5701 }
5702 panic!("invalid excerpt id {:?}", id)
5703 }
5704 }
5705
5706 /// Returns the locators referenced by the given excerpt IDs, sorted by locator.
5707 fn excerpt_locators_for_ids(
5708 &self,
5709 ids: impl IntoIterator<Item = ExcerptId>,
5710 ) -> SmallVec<[Locator; 1]> {
5711 let mut sorted_ids = ids.into_iter().collect::<SmallVec<[_; 1]>>();
5712 sorted_ids.sort_unstable();
5713 let mut locators = SmallVec::new();
5714
5715 while sorted_ids.last() == Some(&ExcerptId::max()) {
5716 sorted_ids.pop();
5717 if let Some(mapping) = self.excerpt_ids.last() {
5718 locators.push(mapping.locator.clone());
5719 }
5720 }
5721
5722 let mut sorted_ids = sorted_ids.into_iter().dedup().peekable();
5723 if sorted_ids.peek() == Some(&ExcerptId::min()) {
5724 sorted_ids.next();
5725 if let Some(mapping) = self.excerpt_ids.first() {
5726 locators.push(mapping.locator.clone());
5727 }
5728 }
5729
5730 let mut cursor = self.excerpt_ids.cursor::<ExcerptId>(&());
5731 for id in sorted_ids {
5732 if cursor.seek_forward(&id, Bias::Left, &()) {
5733 locators.push(cursor.item().unwrap().locator.clone());
5734 } else {
5735 panic!("invalid excerpt id {:?}", id);
5736 }
5737 }
5738
5739 locators.sort_unstable();
5740 locators
5741 }
5742
5743 pub fn buffer_id_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<BufferId> {
5744 Some(self.excerpt(excerpt_id)?.buffer_id)
5745 }
5746
5747 pub fn buffer_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<&BufferSnapshot> {
5748 Some(&self.excerpt(excerpt_id)?.buffer)
5749 }
5750
5751 pub fn range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<Range<Point>> {
5752 let mut cursor = self
5753 .excerpts
5754 .cursor::<(Option<&Locator>, ExcerptDimension<Point>)>(&());
5755 let locator = self.excerpt_locator_for_id(excerpt_id);
5756 if cursor.seek(&Some(locator), Bias::Left, &()) {
5757 let start = cursor.start().1.clone();
5758 let end = cursor.end(&()).1;
5759 let mut diff_transforms = self
5760 .diff_transforms
5761 .cursor::<(ExcerptDimension<Point>, OutputDimension<Point>)>(&());
5762 diff_transforms.seek(&start, Bias::Left, &());
5763 let overshoot = start.0 - diff_transforms.start().0 .0;
5764 let start = diff_transforms.start().1 .0 + overshoot;
5765 diff_transforms.seek(&end, Bias::Right, &());
5766 let overshoot = end.0 - diff_transforms.start().0 .0;
5767 let end = diff_transforms.start().1 .0 + overshoot;
5768 Some(start..end)
5769 } else {
5770 None
5771 }
5772 }
5773
5774 pub fn buffer_range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<Range<text::Anchor>> {
5775 let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
5776 let locator = self.excerpt_locator_for_id(excerpt_id);
5777 if cursor.seek(&Some(locator), Bias::Left, &()) {
5778 if let Some(excerpt) = cursor.item() {
5779 return Some(excerpt.range.context.clone());
5780 }
5781 }
5782 None
5783 }
5784
5785 fn excerpt(&self, excerpt_id: ExcerptId) -> Option<&Excerpt> {
5786 let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
5787 let locator = self.excerpt_locator_for_id(excerpt_id);
5788 cursor.seek(&Some(locator), Bias::Left, &());
5789 if let Some(excerpt) = cursor.item() {
5790 if excerpt.id == excerpt_id {
5791 return Some(excerpt);
5792 }
5793 }
5794 None
5795 }
5796
5797 /// Returns the excerpt containing range and its offset start within the multibuffer or none if `range` spans multiple excerpts
5798 pub fn excerpt_containing<T: ToOffset>(&self, range: Range<T>) -> Option<MultiBufferExcerpt> {
5799 let range = range.start.to_offset(self)..range.end.to_offset(self);
5800 let mut cursor = self.cursor::<usize>();
5801 cursor.seek(&range.start);
5802
5803 let start_excerpt = cursor.excerpt()?;
5804 if range.end != range.start {
5805 cursor.seek_forward(&range.end);
5806 if cursor.excerpt()?.id != start_excerpt.id {
5807 return None;
5808 }
5809 }
5810
5811 cursor.seek_to_start_of_current_excerpt();
5812 let region = cursor.region()?;
5813 let offset = region.range.start;
5814 let buffer_offset = region.buffer_range.start;
5815 let excerpt_offset = cursor.excerpts.start().clone();
5816 Some(MultiBufferExcerpt {
5817 diff_transforms: cursor.diff_transforms,
5818 excerpt: start_excerpt,
5819 offset,
5820 buffer_offset,
5821 excerpt_offset,
5822 })
5823 }
5824
5825 pub fn selections_in_range<'a>(
5826 &'a self,
5827 range: &'a Range<Anchor>,
5828 include_local: bool,
5829 ) -> impl 'a + Iterator<Item = (ReplicaId, bool, CursorShape, Selection<Anchor>)> {
5830 let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&());
5831 let start_locator = self.excerpt_locator_for_id(range.start.excerpt_id);
5832 let end_locator = self.excerpt_locator_for_id(range.end.excerpt_id);
5833 cursor.seek(start_locator, Bias::Left, &());
5834 cursor
5835 .take_while(move |excerpt| excerpt.locator <= *end_locator)
5836 .flat_map(move |excerpt| {
5837 let mut query_range = excerpt.range.context.start..excerpt.range.context.end;
5838 if excerpt.id == range.start.excerpt_id {
5839 query_range.start = range.start.text_anchor;
5840 }
5841 if excerpt.id == range.end.excerpt_id {
5842 query_range.end = range.end.text_anchor;
5843 }
5844
5845 excerpt
5846 .buffer
5847 .selections_in_range(query_range, include_local)
5848 .flat_map(move |(replica_id, line_mode, cursor_shape, selections)| {
5849 selections.map(move |selection| {
5850 let mut start = Anchor {
5851 buffer_id: Some(excerpt.buffer_id),
5852 excerpt_id: excerpt.id,
5853 text_anchor: selection.start,
5854 diff_base_anchor: None,
5855 };
5856 let mut end = Anchor {
5857 buffer_id: Some(excerpt.buffer_id),
5858 excerpt_id: excerpt.id,
5859 text_anchor: selection.end,
5860 diff_base_anchor: None,
5861 };
5862 if range.start.cmp(&start, self).is_gt() {
5863 start = range.start;
5864 }
5865 if range.end.cmp(&end, self).is_lt() {
5866 end = range.end;
5867 }
5868
5869 (
5870 replica_id,
5871 line_mode,
5872 cursor_shape,
5873 Selection {
5874 id: selection.id,
5875 start,
5876 end,
5877 reversed: selection.reversed,
5878 goal: selection.goal,
5879 },
5880 )
5881 })
5882 })
5883 })
5884 }
5885
5886 pub fn show_headers(&self) -> bool {
5887 self.show_headers
5888 }
5889}
5890
5891#[cfg(any(test, feature = "test-support"))]
5892impl MultiBufferSnapshot {
5893 pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
5894 let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
5895 let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
5896 start..end
5897 }
5898
5899 #[cfg(any(test, feature = "test-support"))]
5900 fn check_invariants(&self) {
5901 let excerpts = self.excerpts.items(&());
5902 let excerpt_ids = self.excerpt_ids.items(&());
5903
5904 for (ix, excerpt) in excerpts.iter().enumerate() {
5905 if ix == 0 {
5906 if excerpt.locator <= Locator::min() {
5907 panic!("invalid first excerpt locator {:?}", excerpt.locator);
5908 }
5909 } else if excerpt.locator <= excerpts[ix - 1].locator {
5910 panic!("excerpts are out-of-order: {:?}", excerpts);
5911 }
5912 }
5913
5914 for (ix, entry) in excerpt_ids.iter().enumerate() {
5915 if ix == 0 {
5916 if entry.id.cmp(&ExcerptId::min(), &self).is_le() {
5917 panic!("invalid first excerpt id {:?}", entry.id);
5918 }
5919 } else if entry.id <= excerpt_ids[ix - 1].id {
5920 panic!("excerpt ids are out-of-order: {:?}", excerpt_ids);
5921 }
5922 }
5923
5924 if self.diff_transforms.summary().input != self.excerpts.summary().text {
5925 panic!(
5926 "incorrect input summary. expected {:?}, got {:?}. transforms: {:+?}",
5927 self.excerpts.summary().text.len,
5928 self.diff_transforms.summary().input,
5929 self.diff_transforms.items(&()),
5930 );
5931 }
5932
5933 let mut prev_transform: Option<&DiffTransform> = None;
5934 for item in self.diff_transforms.iter() {
5935 if let DiffTransform::BufferContent {
5936 summary,
5937 inserted_hunk_anchor,
5938 } = item
5939 {
5940 if let Some(DiffTransform::BufferContent {
5941 inserted_hunk_anchor: prev_inserted_hunk_anchor,
5942 ..
5943 }) = prev_transform
5944 {
5945 if *inserted_hunk_anchor == *prev_inserted_hunk_anchor {
5946 panic!(
5947 "multiple adjacent buffer content transforms with is_inserted_hunk = {inserted_hunk_anchor:?}. transforms: {:+?}",
5948 self.diff_transforms.items(&()));
5949 }
5950 }
5951 if summary.len == 0 && !self.is_empty() {
5952 panic!("empty buffer content transform");
5953 }
5954 }
5955 prev_transform = Some(item);
5956 }
5957 }
5958}
5959
5960impl<'a, D> MultiBufferCursor<'a, D>
5961where
5962 D: TextDimension + Ord + Sub<D, Output = D>,
5963{
5964 fn seek(&mut self, position: &D) {
5965 self.cached_region.take();
5966 self.diff_transforms
5967 .seek(&OutputDimension(*position), Bias::Right, &());
5968 if self.diff_transforms.item().is_none() && *position == self.diff_transforms.start().0 .0 {
5969 self.diff_transforms.prev(&());
5970 }
5971
5972 let mut excerpt_position = self.diff_transforms.start().1 .0;
5973 if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
5974 let overshoot = *position - self.diff_transforms.start().0 .0;
5975 excerpt_position.add_assign(&overshoot);
5976 }
5977
5978 self.excerpts
5979 .seek(&ExcerptDimension(excerpt_position), Bias::Right, &());
5980 if self.excerpts.item().is_none() && excerpt_position == self.excerpts.start().0 {
5981 self.excerpts.prev(&());
5982 }
5983 }
5984
5985 fn seek_forward(&mut self, position: &D) {
5986 self.cached_region.take();
5987 self.diff_transforms
5988 .seek_forward(&OutputDimension(*position), Bias::Right, &());
5989 if self.diff_transforms.item().is_none() && *position == self.diff_transforms.start().0 .0 {
5990 self.diff_transforms.prev(&());
5991 }
5992
5993 let overshoot = *position - self.diff_transforms.start().0 .0;
5994 let mut excerpt_position = self.diff_transforms.start().1 .0;
5995 if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
5996 excerpt_position.add_assign(&overshoot);
5997 }
5998
5999 self.excerpts
6000 .seek_forward(&ExcerptDimension(excerpt_position), Bias::Right, &());
6001 if self.excerpts.item().is_none() && excerpt_position == self.excerpts.start().0 {
6002 self.excerpts.prev(&());
6003 }
6004 }
6005
6006 fn seek_to_buffer_position_in_current_excerpt(&mut self, position: &D) {
6007 self.cached_region.take();
6008 if let Some(excerpt) = self.excerpts.item() {
6009 let excerpt_start = excerpt.range.context.start.summary::<D>(&excerpt.buffer);
6010 let position_in_excerpt = *position - excerpt_start;
6011 let mut excerpt_position = self.excerpts.start().0;
6012 excerpt_position.add_assign(&position_in_excerpt);
6013 self.diff_transforms
6014 .seek(&ExcerptDimension(excerpt_position), Bias::Left, &());
6015 if self.diff_transforms.item().is_none() {
6016 self.diff_transforms.next(&());
6017 }
6018 }
6019 }
6020
6021 fn next_excerpt(&mut self) {
6022 self.excerpts.next(&());
6023 self.seek_to_start_of_current_excerpt();
6024 }
6025
6026 fn prev_excerpt(&mut self) {
6027 self.excerpts.prev(&());
6028 self.seek_to_start_of_current_excerpt();
6029 }
6030
6031 fn seek_to_start_of_current_excerpt(&mut self) {
6032 self.cached_region.take();
6033 self.diff_transforms
6034 .seek(self.excerpts.start(), Bias::Left, &());
6035 if self.diff_transforms.end(&()).1 == *self.excerpts.start()
6036 && self.diff_transforms.start().1 < *self.excerpts.start()
6037 && self.diff_transforms.next_item().is_some()
6038 {
6039 self.diff_transforms.next(&());
6040 }
6041 }
6042
6043 fn next(&mut self) {
6044 self.cached_region.take();
6045 match self.diff_transforms.end(&()).1.cmp(&self.excerpts.end(&())) {
6046 cmp::Ordering::Less => self.diff_transforms.next(&()),
6047 cmp::Ordering::Greater => self.excerpts.next(&()),
6048 cmp::Ordering::Equal => {
6049 self.diff_transforms.next(&());
6050 if self.diff_transforms.end(&()).1 > self.excerpts.end(&())
6051 || self.diff_transforms.item().is_none()
6052 {
6053 self.excerpts.next(&());
6054 }
6055 }
6056 }
6057 }
6058
6059 fn prev(&mut self) {
6060 self.cached_region.take();
6061 match self.diff_transforms.start().1.cmp(self.excerpts.start()) {
6062 cmp::Ordering::Less => self.excerpts.prev(&()),
6063 cmp::Ordering::Greater => self.diff_transforms.prev(&()),
6064 cmp::Ordering::Equal => {
6065 self.diff_transforms.prev(&());
6066 if self.diff_transforms.start().1 < *self.excerpts.start()
6067 || self.diff_transforms.item().is_none()
6068 {
6069 self.excerpts.prev(&());
6070 }
6071 }
6072 }
6073 }
6074
6075 fn region(&mut self) -> Option<MultiBufferRegion<'a, D>> {
6076 if self.cached_region.is_none() {
6077 self.cached_region = self.build_region();
6078 }
6079 self.cached_region.clone()
6080 }
6081
6082 fn is_at_end_of_excerpt(&mut self) -> bool {
6083 if self.diff_transforms.end(&()).1 < self.excerpts.end(&()) {
6084 return false;
6085 } else if self.diff_transforms.end(&()).1 > self.excerpts.end(&())
6086 || self.diff_transforms.item().is_none()
6087 {
6088 return true;
6089 }
6090
6091 self.diff_transforms.next(&());
6092 let next_transform = self.diff_transforms.item();
6093 self.diff_transforms.prev(&());
6094
6095 next_transform.map_or(true, |next_transform| {
6096 matches!(next_transform, DiffTransform::BufferContent { .. })
6097 })
6098 }
6099
6100 fn main_buffer_position(&self) -> Option<D> {
6101 let excerpt = self.excerpts.item()?;
6102 let buffer = &excerpt.buffer;
6103 let buffer_context_start = excerpt.range.context.start.summary::<D>(buffer);
6104 let mut buffer_start = buffer_context_start;
6105 let overshoot = self.diff_transforms.end(&()).1 .0 - self.excerpts.start().0;
6106 buffer_start.add_assign(&overshoot);
6107 Some(buffer_start)
6108 }
6109
6110 fn build_region(&self) -> Option<MultiBufferRegion<'a, D>> {
6111 let excerpt = self.excerpts.item()?;
6112 match self.diff_transforms.item()? {
6113 DiffTransform::DeletedHunk {
6114 buffer_id,
6115 base_text_byte_range,
6116 has_trailing_newline,
6117 ..
6118 } => {
6119 let diff = self.diffs.get(&buffer_id)?;
6120 let buffer = &diff.base_text;
6121 let mut rope_cursor = buffer.as_rope().cursor(0);
6122 let buffer_start = rope_cursor.summary::<D>(base_text_byte_range.start);
6123 let buffer_range_len = rope_cursor.summary::<D>(base_text_byte_range.end);
6124 let mut buffer_end = buffer_start;
6125 buffer_end.add_assign(&buffer_range_len);
6126 let start = self.diff_transforms.start().0 .0;
6127 let end = self.diff_transforms.end(&()).0 .0;
6128 return Some(MultiBufferRegion {
6129 buffer,
6130 excerpt,
6131 has_trailing_newline: *has_trailing_newline,
6132 is_main_buffer: false,
6133 is_inserted_hunk: false,
6134 buffer_range: buffer_start..buffer_end,
6135 range: start..end,
6136 });
6137 }
6138 DiffTransform::BufferContent {
6139 inserted_hunk_anchor,
6140 ..
6141 } => {
6142 let buffer = &excerpt.buffer;
6143 let buffer_context_start = excerpt.range.context.start.summary::<D>(buffer);
6144
6145 let mut start = self.diff_transforms.start().0 .0;
6146 let mut buffer_start = buffer_context_start;
6147 if self.diff_transforms.start().1 < *self.excerpts.start() {
6148 let overshoot = self.excerpts.start().0 - self.diff_transforms.start().1 .0;
6149 start.add_assign(&overshoot);
6150 } else {
6151 let overshoot = self.diff_transforms.start().1 .0 - self.excerpts.start().0;
6152 buffer_start.add_assign(&overshoot);
6153 }
6154
6155 let mut end;
6156 let mut buffer_end;
6157 let has_trailing_newline;
6158 if self.diff_transforms.end(&()).1 .0 < self.excerpts.end(&()).0 {
6159 let overshoot = self.diff_transforms.end(&()).1 .0 - self.excerpts.start().0;
6160 end = self.diff_transforms.end(&()).0 .0;
6161 buffer_end = buffer_context_start;
6162 buffer_end.add_assign(&overshoot);
6163 has_trailing_newline = false;
6164 } else {
6165 let overshoot = self.excerpts.end(&()).0 - self.diff_transforms.start().1 .0;
6166 end = self.diff_transforms.start().0 .0;
6167 end.add_assign(&overshoot);
6168 buffer_end = excerpt.range.context.end.summary::<D>(buffer);
6169 has_trailing_newline = excerpt.has_trailing_newline;
6170 };
6171
6172 Some(MultiBufferRegion {
6173 buffer,
6174 excerpt,
6175 has_trailing_newline,
6176 is_main_buffer: true,
6177 is_inserted_hunk: inserted_hunk_anchor.is_some(),
6178 buffer_range: buffer_start..buffer_end,
6179 range: start..end,
6180 })
6181 }
6182 }
6183 }
6184
6185 fn excerpt(&self) -> Option<&'a Excerpt> {
6186 self.excerpts.item()
6187 }
6188}
6189
6190impl History {
6191 fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
6192 self.transaction_depth += 1;
6193 if self.transaction_depth == 1 {
6194 let id = self.next_transaction_id.tick();
6195 self.undo_stack.push(Transaction {
6196 id,
6197 buffer_transactions: Default::default(),
6198 first_edit_at: now,
6199 last_edit_at: now,
6200 suppress_grouping: false,
6201 });
6202 Some(id)
6203 } else {
6204 None
6205 }
6206 }
6207
6208 fn end_transaction(
6209 &mut self,
6210 now: Instant,
6211 buffer_transactions: HashMap<BufferId, TransactionId>,
6212 ) -> bool {
6213 assert_ne!(self.transaction_depth, 0);
6214 self.transaction_depth -= 1;
6215 if self.transaction_depth == 0 {
6216 if buffer_transactions.is_empty() {
6217 self.undo_stack.pop();
6218 false
6219 } else {
6220 self.redo_stack.clear();
6221 let transaction = self.undo_stack.last_mut().unwrap();
6222 transaction.last_edit_at = now;
6223 for (buffer_id, transaction_id) in buffer_transactions {
6224 transaction
6225 .buffer_transactions
6226 .entry(buffer_id)
6227 .or_insert(transaction_id);
6228 }
6229 true
6230 }
6231 } else {
6232 false
6233 }
6234 }
6235
6236 fn push_transaction<'a, T>(
6237 &mut self,
6238 buffer_transactions: T,
6239 now: Instant,
6240 cx: &Context<MultiBuffer>,
6241 ) where
6242 T: IntoIterator<Item = (&'a Entity<Buffer>, &'a language::Transaction)>,
6243 {
6244 assert_eq!(self.transaction_depth, 0);
6245 let transaction = Transaction {
6246 id: self.next_transaction_id.tick(),
6247 buffer_transactions: buffer_transactions
6248 .into_iter()
6249 .map(|(buffer, transaction)| (buffer.read(cx).remote_id(), transaction.id))
6250 .collect(),
6251 first_edit_at: now,
6252 last_edit_at: now,
6253 suppress_grouping: false,
6254 };
6255 if !transaction.buffer_transactions.is_empty() {
6256 self.undo_stack.push(transaction);
6257 self.redo_stack.clear();
6258 }
6259 }
6260
6261 fn finalize_last_transaction(&mut self) {
6262 if let Some(transaction) = self.undo_stack.last_mut() {
6263 transaction.suppress_grouping = true;
6264 }
6265 }
6266
6267 fn forget(&mut self, transaction_id: TransactionId) -> Option<Transaction> {
6268 if let Some(ix) = self
6269 .undo_stack
6270 .iter()
6271 .rposition(|transaction| transaction.id == transaction_id)
6272 {
6273 Some(self.undo_stack.remove(ix))
6274 } else if let Some(ix) = self
6275 .redo_stack
6276 .iter()
6277 .rposition(|transaction| transaction.id == transaction_id)
6278 {
6279 Some(self.redo_stack.remove(ix))
6280 } else {
6281 None
6282 }
6283 }
6284
6285 fn transaction(&self, transaction_id: TransactionId) -> Option<&Transaction> {
6286 self.undo_stack
6287 .iter()
6288 .find(|transaction| transaction.id == transaction_id)
6289 .or_else(|| {
6290 self.redo_stack
6291 .iter()
6292 .find(|transaction| transaction.id == transaction_id)
6293 })
6294 }
6295
6296 fn transaction_mut(&mut self, transaction_id: TransactionId) -> Option<&mut Transaction> {
6297 self.undo_stack
6298 .iter_mut()
6299 .find(|transaction| transaction.id == transaction_id)
6300 .or_else(|| {
6301 self.redo_stack
6302 .iter_mut()
6303 .find(|transaction| transaction.id == transaction_id)
6304 })
6305 }
6306
6307 fn pop_undo(&mut self) -> Option<&mut Transaction> {
6308 assert_eq!(self.transaction_depth, 0);
6309 if let Some(transaction) = self.undo_stack.pop() {
6310 self.redo_stack.push(transaction);
6311 self.redo_stack.last_mut()
6312 } else {
6313 None
6314 }
6315 }
6316
6317 fn pop_redo(&mut self) -> Option<&mut Transaction> {
6318 assert_eq!(self.transaction_depth, 0);
6319 if let Some(transaction) = self.redo_stack.pop() {
6320 self.undo_stack.push(transaction);
6321 self.undo_stack.last_mut()
6322 } else {
6323 None
6324 }
6325 }
6326
6327 fn remove_from_undo(&mut self, transaction_id: TransactionId) -> Option<&Transaction> {
6328 let ix = self
6329 .undo_stack
6330 .iter()
6331 .rposition(|transaction| transaction.id == transaction_id)?;
6332 let transaction = self.undo_stack.remove(ix);
6333 self.redo_stack.push(transaction);
6334 self.redo_stack.last()
6335 }
6336
6337 fn group(&mut self) -> Option<TransactionId> {
6338 let mut count = 0;
6339 let mut transactions = self.undo_stack.iter();
6340 if let Some(mut transaction) = transactions.next_back() {
6341 while let Some(prev_transaction) = transactions.next_back() {
6342 if !prev_transaction.suppress_grouping
6343 && transaction.first_edit_at - prev_transaction.last_edit_at
6344 <= self.group_interval
6345 {
6346 transaction = prev_transaction;
6347 count += 1;
6348 } else {
6349 break;
6350 }
6351 }
6352 }
6353 self.group_trailing(count)
6354 }
6355
6356 fn group_until(&mut self, transaction_id: TransactionId) {
6357 let mut count = 0;
6358 for transaction in self.undo_stack.iter().rev() {
6359 if transaction.id == transaction_id {
6360 self.group_trailing(count);
6361 break;
6362 } else if transaction.suppress_grouping {
6363 break;
6364 } else {
6365 count += 1;
6366 }
6367 }
6368 }
6369
6370 fn group_trailing(&mut self, n: usize) -> Option<TransactionId> {
6371 let new_len = self.undo_stack.len() - n;
6372 let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
6373 if let Some(last_transaction) = transactions_to_keep.last_mut() {
6374 if let Some(transaction) = transactions_to_merge.last() {
6375 last_transaction.last_edit_at = transaction.last_edit_at;
6376 }
6377 for to_merge in transactions_to_merge {
6378 for (buffer_id, transaction_id) in &to_merge.buffer_transactions {
6379 last_transaction
6380 .buffer_transactions
6381 .entry(*buffer_id)
6382 .or_insert(*transaction_id);
6383 }
6384 }
6385 }
6386
6387 self.undo_stack.truncate(new_len);
6388 self.undo_stack.last().map(|t| t.id)
6389 }
6390}
6391
6392impl Excerpt {
6393 fn new(
6394 id: ExcerptId,
6395 locator: Locator,
6396 buffer_id: BufferId,
6397 buffer: BufferSnapshot,
6398 range: ExcerptRange<text::Anchor>,
6399 has_trailing_newline: bool,
6400 ) -> Self {
6401 Excerpt {
6402 id,
6403 locator,
6404 max_buffer_row: range.context.end.to_point(&buffer).row,
6405 text_summary: buffer
6406 .text_summary_for_range::<TextSummary, _>(range.context.to_offset(&buffer)),
6407 buffer_id,
6408 buffer,
6409 range,
6410 has_trailing_newline,
6411 }
6412 }
6413
6414 fn chunks_in_range(&self, range: Range<usize>, language_aware: bool) -> ExcerptChunks {
6415 let content_start = self.range.context.start.to_offset(&self.buffer);
6416 let chunks_start = content_start + range.start;
6417 let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
6418
6419 let footer_height = if self.has_trailing_newline
6420 && range.start <= self.text_summary.len
6421 && range.end > self.text_summary.len
6422 {
6423 1
6424 } else {
6425 0
6426 };
6427
6428 let content_chunks = self.buffer.chunks(chunks_start..chunks_end, language_aware);
6429
6430 ExcerptChunks {
6431 excerpt_id: self.id,
6432 content_chunks,
6433 footer_height,
6434 }
6435 }
6436
6437 fn seek_chunks(&self, excerpt_chunks: &mut ExcerptChunks, range: Range<usize>) {
6438 let content_start = self.range.context.start.to_offset(&self.buffer);
6439 let chunks_start = content_start + range.start;
6440 let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
6441 excerpt_chunks.content_chunks.seek(chunks_start..chunks_end);
6442 excerpt_chunks.footer_height = if self.has_trailing_newline
6443 && range.start <= self.text_summary.len
6444 && range.end > self.text_summary.len
6445 {
6446 1
6447 } else {
6448 0
6449 };
6450 }
6451
6452 fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
6453 if text_anchor
6454 .cmp(&self.range.context.start, &self.buffer)
6455 .is_lt()
6456 {
6457 self.range.context.start
6458 } else if text_anchor
6459 .cmp(&self.range.context.end, &self.buffer)
6460 .is_gt()
6461 {
6462 self.range.context.end
6463 } else {
6464 text_anchor
6465 }
6466 }
6467
6468 fn contains(&self, anchor: &Anchor) -> bool {
6469 Some(self.buffer_id) == anchor.buffer_id
6470 && self
6471 .range
6472 .context
6473 .start
6474 .cmp(&anchor.text_anchor, &self.buffer)
6475 .is_le()
6476 && self
6477 .range
6478 .context
6479 .end
6480 .cmp(&anchor.text_anchor, &self.buffer)
6481 .is_ge()
6482 }
6483
6484 /// The [`Excerpt`]'s start offset in its [`Buffer`]
6485 fn buffer_start_offset(&self) -> usize {
6486 self.range.context.start.to_offset(&self.buffer)
6487 }
6488
6489 /// The [`Excerpt`]'s end offset in its [`Buffer`]
6490 fn buffer_end_offset(&self) -> usize {
6491 self.buffer_start_offset() + self.text_summary.len
6492 }
6493}
6494
6495impl<'a> MultiBufferExcerpt<'a> {
6496 pub fn id(&self) -> ExcerptId {
6497 self.excerpt.id
6498 }
6499
6500 pub fn buffer_id(&self) -> BufferId {
6501 self.excerpt.buffer_id
6502 }
6503
6504 pub fn start_anchor(&self) -> Anchor {
6505 Anchor {
6506 buffer_id: Some(self.excerpt.buffer_id),
6507 excerpt_id: self.excerpt.id,
6508 text_anchor: self.excerpt.range.context.start,
6509 diff_base_anchor: None,
6510 }
6511 }
6512
6513 pub fn end_anchor(&self) -> Anchor {
6514 Anchor {
6515 buffer_id: Some(self.excerpt.buffer_id),
6516 excerpt_id: self.excerpt.id,
6517 text_anchor: self.excerpt.range.context.end,
6518 diff_base_anchor: None,
6519 }
6520 }
6521
6522 pub fn buffer(&self) -> &'a BufferSnapshot {
6523 &self.excerpt.buffer
6524 }
6525
6526 pub fn buffer_range(&self) -> Range<usize> {
6527 self.buffer_offset
6528 ..self
6529 .excerpt
6530 .range
6531 .context
6532 .end
6533 .to_offset(&self.excerpt.buffer.text)
6534 }
6535
6536 pub fn start_offset(&self) -> usize {
6537 self.offset
6538 }
6539
6540 /// Maps an offset within the [`MultiBuffer`] to an offset within the [`Buffer`]
6541 pub fn map_offset_to_buffer(&mut self, offset: usize) -> usize {
6542 self.map_range_to_buffer(offset..offset).start
6543 }
6544
6545 /// Maps a range within the [`MultiBuffer`] to a range within the [`Buffer`]
6546 pub fn map_range_to_buffer(&mut self, range: Range<usize>) -> Range<usize> {
6547 self.diff_transforms
6548 .seek(&OutputDimension(range.start), Bias::Right, &());
6549 let start = self.map_offset_to_buffer_internal(range.start);
6550 let end = if range.end > range.start {
6551 self.diff_transforms
6552 .seek_forward(&OutputDimension(range.end), Bias::Right, &());
6553 self.map_offset_to_buffer_internal(range.end)
6554 } else {
6555 start
6556 };
6557 start..end
6558 }
6559
6560 fn map_offset_to_buffer_internal(&self, offset: usize) -> usize {
6561 let mut excerpt_offset = self.diff_transforms.start().1.clone();
6562 if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
6563 excerpt_offset.0 += offset - self.diff_transforms.start().0 .0;
6564 };
6565 let offset_in_excerpt = excerpt_offset.0.saturating_sub(self.excerpt_offset.0);
6566 self.buffer_offset + offset_in_excerpt
6567 }
6568
6569 /// Map an offset within the [`Buffer`] to an offset within the [`MultiBuffer`]
6570 pub fn map_offset_from_buffer(&mut self, buffer_offset: usize) -> usize {
6571 self.map_range_from_buffer(buffer_offset..buffer_offset)
6572 .start
6573 }
6574
6575 /// Map a range within the [`Buffer`] to a range within the [`MultiBuffer`]
6576 pub fn map_range_from_buffer(&mut self, buffer_range: Range<usize>) -> Range<usize> {
6577 let overshoot = buffer_range.start - self.buffer_offset;
6578 let excerpt_offset = ExcerptDimension(self.excerpt_offset.0 + overshoot);
6579 self.diff_transforms.seek(&excerpt_offset, Bias::Right, &());
6580 let overshoot = excerpt_offset.0 - self.diff_transforms.start().1 .0;
6581 let start = self.diff_transforms.start().0 .0 + overshoot;
6582
6583 let end = if buffer_range.end > buffer_range.start {
6584 let overshoot = buffer_range.end - self.buffer_offset;
6585 let excerpt_offset = ExcerptDimension(self.excerpt_offset.0 + overshoot);
6586 self.diff_transforms
6587 .seek_forward(&excerpt_offset, Bias::Right, &());
6588 let overshoot = excerpt_offset.0 - self.diff_transforms.start().1 .0;
6589 self.diff_transforms.start().0 .0 + overshoot
6590 } else {
6591 start
6592 };
6593
6594 start..end
6595 }
6596
6597 /// Returns true if the entirety of the given range is in the buffer's excerpt
6598 pub fn contains_buffer_range(&self, range: Range<usize>) -> bool {
6599 range.start >= self.excerpt.buffer_start_offset()
6600 && range.end <= self.excerpt.buffer_end_offset()
6601 }
6602
6603 pub fn max_buffer_row(&self) -> u32 {
6604 self.excerpt.max_buffer_row
6605 }
6606}
6607
6608impl ExcerptId {
6609 pub fn min() -> Self {
6610 Self(0)
6611 }
6612
6613 pub fn max() -> Self {
6614 Self(usize::MAX)
6615 }
6616
6617 pub fn to_proto(&self) -> u64 {
6618 self.0 as _
6619 }
6620
6621 pub fn from_proto(proto: u64) -> Self {
6622 Self(proto as _)
6623 }
6624
6625 pub fn cmp(&self, other: &Self, snapshot: &MultiBufferSnapshot) -> cmp::Ordering {
6626 let a = snapshot.excerpt_locator_for_id(*self);
6627 let b = snapshot.excerpt_locator_for_id(*other);
6628 a.cmp(b).then_with(|| self.0.cmp(&other.0))
6629 }
6630}
6631
6632impl From<ExcerptId> for usize {
6633 fn from(val: ExcerptId) -> Self {
6634 val.0
6635 }
6636}
6637
6638impl fmt::Debug for Excerpt {
6639 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6640 f.debug_struct("Excerpt")
6641 .field("id", &self.id)
6642 .field("locator", &self.locator)
6643 .field("buffer_id", &self.buffer_id)
6644 .field("range", &self.range)
6645 .field("text_summary", &self.text_summary)
6646 .field("has_trailing_newline", &self.has_trailing_newline)
6647 .finish()
6648 }
6649}
6650
6651impl sum_tree::Item for Excerpt {
6652 type Summary = ExcerptSummary;
6653
6654 fn summary(&self, _cx: &()) -> Self::Summary {
6655 let mut text = self.text_summary;
6656 if self.has_trailing_newline {
6657 text += TextSummary::from("\n");
6658 }
6659 ExcerptSummary {
6660 excerpt_id: self.id,
6661 excerpt_locator: self.locator.clone(),
6662 widest_line_number: self.max_buffer_row,
6663 text,
6664 }
6665 }
6666}
6667
6668impl sum_tree::Item for ExcerptIdMapping {
6669 type Summary = ExcerptId;
6670
6671 fn summary(&self, _cx: &()) -> Self::Summary {
6672 self.id
6673 }
6674}
6675
6676impl sum_tree::KeyedItem for ExcerptIdMapping {
6677 type Key = ExcerptId;
6678
6679 fn key(&self) -> Self::Key {
6680 self.id
6681 }
6682}
6683
6684impl DiffTransform {
6685 fn hunk_anchor(&self) -> Option<(ExcerptId, text::Anchor)> {
6686 match self {
6687 DiffTransform::DeletedHunk { hunk_anchor, .. } => Some(*hunk_anchor),
6688 DiffTransform::BufferContent {
6689 inserted_hunk_anchor,
6690 ..
6691 } => *inserted_hunk_anchor,
6692 }
6693 }
6694}
6695
6696impl sum_tree::Item for DiffTransform {
6697 type Summary = DiffTransformSummary;
6698
6699 fn summary(&self, _: &<Self::Summary as sum_tree::Summary>::Context) -> Self::Summary {
6700 match self {
6701 DiffTransform::BufferContent { summary, .. } => DiffTransformSummary {
6702 input: *summary,
6703 output: *summary,
6704 },
6705 DiffTransform::DeletedHunk { summary, .. } => DiffTransformSummary {
6706 input: TextSummary::default(),
6707 output: *summary,
6708 },
6709 }
6710 }
6711}
6712
6713impl DiffTransformSummary {
6714 fn excerpt_len(&self) -> ExcerptOffset {
6715 ExcerptOffset::new(self.input.len)
6716 }
6717}
6718
6719impl sum_tree::Summary for DiffTransformSummary {
6720 type Context = ();
6721
6722 fn zero(_: &Self::Context) -> Self {
6723 DiffTransformSummary {
6724 input: TextSummary::default(),
6725 output: TextSummary::default(),
6726 }
6727 }
6728
6729 fn add_summary(&mut self, summary: &Self, _: &Self::Context) {
6730 self.input += &summary.input;
6731 self.output += &summary.output;
6732 }
6733}
6734
6735impl sum_tree::Summary for ExcerptId {
6736 type Context = ();
6737
6738 fn zero(_cx: &()) -> Self {
6739 Default::default()
6740 }
6741
6742 fn add_summary(&mut self, other: &Self, _: &()) {
6743 *self = *other;
6744 }
6745}
6746
6747impl sum_tree::Summary for ExcerptSummary {
6748 type Context = ();
6749
6750 fn zero(_cx: &()) -> Self {
6751 Default::default()
6752 }
6753
6754 fn add_summary(&mut self, summary: &Self, _: &()) {
6755 debug_assert!(summary.excerpt_locator > self.excerpt_locator);
6756 self.excerpt_locator = summary.excerpt_locator.clone();
6757 self.text.add_summary(&summary.text, &());
6758 self.widest_line_number = cmp::max(self.widest_line_number, summary.widest_line_number);
6759 }
6760}
6761
6762impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for ExcerptOffset {
6763 fn zero(_cx: &()) -> Self {
6764 Default::default()
6765 }
6766
6767 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6768 self.value += summary.text.len;
6769 }
6770}
6771
6772impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for ExcerptOffset {
6773 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
6774 Ord::cmp(&self.value, &cursor_location.text.len)
6775 }
6776}
6777
6778impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, Option<&'a Locator>> for Locator {
6779 fn cmp(&self, cursor_location: &Option<&'a Locator>, _: &()) -> cmp::Ordering {
6780 Ord::cmp(&Some(self), cursor_location)
6781 }
6782}
6783
6784impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Locator {
6785 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
6786 Ord::cmp(self, &cursor_location.excerpt_locator)
6787 }
6788}
6789
6790impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for ExcerptPoint {
6791 fn zero(_cx: &()) -> Self {
6792 Default::default()
6793 }
6794
6795 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6796 self.value += summary.text.lines;
6797 }
6798}
6799
6800impl<'a, D: TextDimension + Default> sum_tree::Dimension<'a, ExcerptSummary>
6801 for ExcerptDimension<D>
6802{
6803 fn zero(_: &()) -> Self {
6804 ExcerptDimension(D::default())
6805 }
6806
6807 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6808 self.0.add_assign(&D::from_text_summary(&summary.text))
6809 }
6810}
6811
6812impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a Locator> {
6813 fn zero(_cx: &()) -> Self {
6814 Default::default()
6815 }
6816
6817 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6818 *self = Some(&summary.excerpt_locator);
6819 }
6820}
6821
6822impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<ExcerptId> {
6823 fn zero(_cx: &()) -> Self {
6824 Default::default()
6825 }
6826
6827 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6828 *self = Some(summary.excerpt_id);
6829 }
6830}
6831
6832#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
6833struct ExcerptDimension<T>(T);
6834
6835#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
6836struct OutputDimension<T>(T);
6837
6838impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for ExcerptOffset {
6839 fn zero(_: &()) -> Self {
6840 ExcerptOffset::new(0)
6841 }
6842
6843 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6844 self.value += summary.input.len;
6845 }
6846}
6847
6848impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for ExcerptPoint {
6849 fn zero(_: &()) -> Self {
6850 ExcerptPoint::new(0, 0)
6851 }
6852
6853 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6854 self.value += summary.input.lines;
6855 }
6856}
6857
6858impl<'a, D: TextDimension + Ord>
6859 sum_tree::SeekTarget<'a, DiffTransformSummary, DiffTransformSummary> for ExcerptDimension<D>
6860{
6861 fn cmp(&self, cursor_location: &DiffTransformSummary, _: &()) -> cmp::Ordering {
6862 Ord::cmp(&self.0, &D::from_text_summary(&cursor_location.input))
6863 }
6864}
6865
6866impl<'a, D: TextDimension + Ord>
6867 sum_tree::SeekTarget<'a, DiffTransformSummary, (OutputDimension<D>, ExcerptDimension<D>)>
6868 for ExcerptDimension<D>
6869{
6870 fn cmp(
6871 &self,
6872 cursor_location: &(OutputDimension<D>, ExcerptDimension<D>),
6873 _: &(),
6874 ) -> cmp::Ordering {
6875 Ord::cmp(&self.0, &cursor_location.1 .0)
6876 }
6877}
6878
6879impl<'a, D: TextDimension> sum_tree::Dimension<'a, DiffTransformSummary> for ExcerptDimension<D> {
6880 fn zero(_: &()) -> Self {
6881 ExcerptDimension(D::default())
6882 }
6883
6884 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6885 self.0.add_assign(&D::from_text_summary(&summary.input))
6886 }
6887}
6888
6889impl<'a, D: TextDimension> sum_tree::Dimension<'a, DiffTransformSummary> for OutputDimension<D> {
6890 fn zero(_: &()) -> Self {
6891 OutputDimension(D::default())
6892 }
6893
6894 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6895 self.0.add_assign(&D::from_text_summary(&summary.output))
6896 }
6897}
6898
6899impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for TextSummary {
6900 fn zero(_: &()) -> Self {
6901 TextSummary::default()
6902 }
6903
6904 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6905 *self += summary.output
6906 }
6907}
6908
6909impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for usize {
6910 fn zero(_: &()) -> Self {
6911 0
6912 }
6913
6914 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6915 *self += summary.output.len
6916 }
6917}
6918
6919impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for Point {
6920 fn zero(_: &()) -> Self {
6921 Point::new(0, 0)
6922 }
6923
6924 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6925 *self += summary.output.lines
6926 }
6927}
6928
6929impl<'a> MultiBufferRows<'a> {
6930 pub fn seek(&mut self, MultiBufferRow(row): MultiBufferRow) {
6931 self.point = Point::new(row, 0);
6932 self.cursor.seek(&self.point);
6933 }
6934}
6935
6936impl<'a> Iterator for MultiBufferRows<'a> {
6937 type Item = RowInfo;
6938
6939 fn next(&mut self) -> Option<Self::Item> {
6940 if self.is_empty && self.point.row == 0 {
6941 self.point += Point::new(1, 0);
6942 return Some(RowInfo {
6943 buffer_id: None,
6944 buffer_row: Some(0),
6945 multibuffer_row: Some(MultiBufferRow(0)),
6946 diff_status: None,
6947 });
6948 }
6949
6950 let mut region = self.cursor.region()?;
6951 while self.point >= region.range.end {
6952 self.cursor.next();
6953 if let Some(next_region) = self.cursor.region() {
6954 region = next_region;
6955 } else {
6956 if self.point == self.cursor.diff_transforms.end(&()).0 .0 {
6957 let multibuffer_row = MultiBufferRow(self.point.row);
6958 self.point += Point::new(1, 0);
6959 let last_excerpt = self
6960 .cursor
6961 .excerpts
6962 .item()
6963 .or(self.cursor.excerpts.prev_item())?;
6964 let last_row = last_excerpt
6965 .range
6966 .context
6967 .end
6968 .to_point(&last_excerpt.buffer)
6969 .row;
6970 return Some(RowInfo {
6971 buffer_id: Some(last_excerpt.buffer_id),
6972 buffer_row: Some(last_row),
6973 multibuffer_row: Some(multibuffer_row),
6974 diff_status: None,
6975 });
6976 } else {
6977 return None;
6978 }
6979 };
6980 }
6981
6982 let overshoot = self.point - region.range.start;
6983 let buffer_point = region.buffer_range.start + overshoot;
6984 let result = Some(RowInfo {
6985 buffer_id: Some(region.buffer.remote_id()),
6986 buffer_row: Some(buffer_point.row),
6987 multibuffer_row: Some(MultiBufferRow(self.point.row)),
6988 diff_status: if region.is_inserted_hunk && self.point < region.range.end {
6989 Some(DiffHunkStatus::Added)
6990 } else if !region.is_main_buffer {
6991 Some(DiffHunkStatus::Removed)
6992 } else {
6993 None
6994 },
6995 });
6996 self.point += Point::new(1, 0);
6997 result
6998 }
6999}
7000
7001impl<'a> MultiBufferChunks<'a> {
7002 pub fn offset(&self) -> usize {
7003 self.range.start
7004 }
7005
7006 pub fn seek(&mut self, range: Range<usize>) {
7007 self.diff_transforms.seek(&range.end, Bias::Right, &());
7008 let mut excerpt_end = self.diff_transforms.start().1;
7009 if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
7010 let overshoot = range.end - self.diff_transforms.start().0;
7011 excerpt_end.value += overshoot;
7012 }
7013
7014 self.diff_transforms.seek(&range.start, Bias::Right, &());
7015 let mut excerpt_start = self.diff_transforms.start().1;
7016 if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
7017 let overshoot = range.start - self.diff_transforms.start().0;
7018 excerpt_start.value += overshoot;
7019 }
7020
7021 self.seek_to_excerpt_offset_range(excerpt_start..excerpt_end);
7022 self.buffer_chunk.take();
7023 self.range = range;
7024 }
7025
7026 fn seek_to_excerpt_offset_range(&mut self, new_range: Range<ExcerptOffset>) {
7027 self.excerpt_offset_range = new_range.clone();
7028 self.excerpts.seek(&new_range.start, Bias::Right, &());
7029 if let Some(excerpt) = self.excerpts.item() {
7030 let excerpt_start = *self.excerpts.start();
7031 if let Some(excerpt_chunks) = self
7032 .excerpt_chunks
7033 .as_mut()
7034 .filter(|chunks| excerpt.id == chunks.excerpt_id)
7035 {
7036 excerpt.seek_chunks(
7037 excerpt_chunks,
7038 (self.excerpt_offset_range.start - excerpt_start).value
7039 ..(self.excerpt_offset_range.end - excerpt_start).value,
7040 );
7041 } else {
7042 self.excerpt_chunks = Some(excerpt.chunks_in_range(
7043 (self.excerpt_offset_range.start - excerpt_start).value
7044 ..(self.excerpt_offset_range.end - excerpt_start).value,
7045 self.language_aware,
7046 ));
7047 }
7048 } else {
7049 self.excerpt_chunks = None;
7050 }
7051 }
7052
7053 fn next_excerpt_chunk(&mut self) -> Option<Chunk<'a>> {
7054 loop {
7055 if self.excerpt_offset_range.is_empty() {
7056 return None;
7057 } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
7058 self.excerpt_offset_range.start.value += chunk.text.len();
7059 return Some(chunk);
7060 } else {
7061 self.excerpts.next(&());
7062 let excerpt = self.excerpts.item()?;
7063 self.excerpt_chunks = Some(excerpt.chunks_in_range(
7064 0..(self.excerpt_offset_range.end - *self.excerpts.start()).value,
7065 self.language_aware,
7066 ));
7067 }
7068 }
7069 }
7070}
7071
7072impl<'a> Iterator for ReversedMultiBufferChunks<'a> {
7073 type Item = &'a str;
7074
7075 fn next(&mut self) -> Option<Self::Item> {
7076 let mut region = self.cursor.region()?;
7077 if self.offset == region.range.start {
7078 self.cursor.prev();
7079 region = self.cursor.region()?;
7080 let start_overshoot = self.start.saturating_sub(region.range.start);
7081 self.current_chunks = Some(region.buffer.reversed_chunks_in_range(
7082 region.buffer_range.start + start_overshoot..region.buffer_range.end,
7083 ));
7084 }
7085
7086 if self.offset == region.range.end && region.has_trailing_newline {
7087 self.offset -= 1;
7088 Some("\n")
7089 } else {
7090 let chunk = self.current_chunks.as_mut().unwrap().next().unwrap();
7091 self.offset -= chunk.len();
7092 Some(chunk)
7093 }
7094 }
7095}
7096
7097impl<'a> Iterator for MultiBufferChunks<'a> {
7098 type Item = Chunk<'a>;
7099
7100 fn next(&mut self) -> Option<Chunk<'a>> {
7101 if self.range.start >= self.range.end {
7102 return None;
7103 }
7104 if self.range.start == self.diff_transforms.end(&()).0 {
7105 self.diff_transforms.next(&());
7106 }
7107
7108 let diff_transform_start = self.diff_transforms.start().0;
7109 let diff_transform_end = self.diff_transforms.end(&()).0;
7110 debug_assert!(self.range.start < diff_transform_end);
7111
7112 let diff_transform = self.diff_transforms.item()?;
7113 match diff_transform {
7114 DiffTransform::BufferContent { .. } => {
7115 let chunk = if let Some(chunk) = &mut self.buffer_chunk {
7116 chunk
7117 } else {
7118 let chunk = self.next_excerpt_chunk().unwrap();
7119 self.buffer_chunk.insert(chunk)
7120 };
7121
7122 let chunk_end = self.range.start + chunk.text.len();
7123 let diff_transform_end = diff_transform_end.min(self.range.end);
7124
7125 if diff_transform_end < chunk_end {
7126 let (before, after) =
7127 chunk.text.split_at(diff_transform_end - self.range.start);
7128 self.range.start = diff_transform_end;
7129 chunk.text = after;
7130 Some(Chunk {
7131 text: before,
7132 ..chunk.clone()
7133 })
7134 } else {
7135 self.range.start = chunk_end;
7136 self.buffer_chunk.take()
7137 }
7138 }
7139 DiffTransform::DeletedHunk {
7140 buffer_id,
7141 base_text_byte_range,
7142 has_trailing_newline,
7143 ..
7144 } => {
7145 let base_text_start =
7146 base_text_byte_range.start + self.range.start - diff_transform_start;
7147 let base_text_end =
7148 base_text_byte_range.start + self.range.end - diff_transform_start;
7149 let base_text_end = base_text_end.min(base_text_byte_range.end);
7150
7151 let mut chunks = if let Some((_, mut chunks)) = self
7152 .diff_base_chunks
7153 .take()
7154 .filter(|(id, _)| id == buffer_id)
7155 {
7156 if chunks.range().start != base_text_start || chunks.range().end < base_text_end
7157 {
7158 chunks.seek(base_text_start..base_text_end);
7159 }
7160 chunks
7161 } else {
7162 let base_buffer = &self.diffs.get(&buffer_id)?.base_text;
7163 base_buffer.chunks(base_text_start..base_text_end, self.language_aware)
7164 };
7165
7166 let chunk = if let Some(chunk) = chunks.next() {
7167 self.range.start += chunk.text.len();
7168 self.diff_base_chunks = Some((*buffer_id, chunks));
7169 chunk
7170 } else {
7171 debug_assert!(has_trailing_newline);
7172 self.range.start += "\n".len();
7173 Chunk {
7174 text: "\n",
7175 ..Default::default()
7176 }
7177 };
7178 Some(chunk)
7179 }
7180 }
7181 }
7182}
7183
7184impl<'a> MultiBufferBytes<'a> {
7185 fn consume(&mut self, len: usize) {
7186 self.range.start += len;
7187 self.chunk = &self.chunk[len..];
7188
7189 if !self.range.is_empty() && self.chunk.is_empty() {
7190 if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
7191 self.chunk = chunk;
7192 } else if self.has_trailing_newline {
7193 self.has_trailing_newline = false;
7194 self.chunk = b"\n";
7195 } else {
7196 self.cursor.next();
7197 if let Some(region) = self.cursor.region() {
7198 let mut excerpt_bytes = region.buffer.bytes_in_range(
7199 region.buffer_range.start
7200 ..(region.buffer_range.start + self.range.end - region.range.start)
7201 .min(region.buffer_range.end),
7202 );
7203 self.chunk = excerpt_bytes.next().unwrap_or(&[]);
7204 self.excerpt_bytes = Some(excerpt_bytes);
7205 self.has_trailing_newline =
7206 region.has_trailing_newline && self.range.end >= region.range.end;
7207 if self.chunk.is_empty() && self.has_trailing_newline {
7208 self.has_trailing_newline = false;
7209 self.chunk = b"\n";
7210 }
7211 }
7212 }
7213 }
7214 }
7215}
7216
7217impl<'a> Iterator for MultiBufferBytes<'a> {
7218 type Item = &'a [u8];
7219
7220 fn next(&mut self) -> Option<Self::Item> {
7221 let chunk = self.chunk;
7222 if chunk.is_empty() {
7223 None
7224 } else {
7225 self.consume(chunk.len());
7226 Some(chunk)
7227 }
7228 }
7229}
7230
7231impl<'a> io::Read for MultiBufferBytes<'a> {
7232 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
7233 let len = cmp::min(buf.len(), self.chunk.len());
7234 buf[..len].copy_from_slice(&self.chunk[..len]);
7235 if len > 0 {
7236 self.consume(len);
7237 }
7238 Ok(len)
7239 }
7240}
7241
7242impl<'a> io::Read for ReversedMultiBufferBytes<'a> {
7243 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
7244 let len = cmp::min(buf.len(), self.chunk.len());
7245 buf[..len].copy_from_slice(&self.chunk[..len]);
7246 buf[..len].reverse();
7247 if len > 0 {
7248 self.range.end -= len;
7249 self.chunk = &self.chunk[..self.chunk.len() - len];
7250 if !self.range.is_empty() && self.chunk.is_empty() {
7251 if let Some(chunk) = self.chunks.next() {
7252 self.chunk = chunk.as_bytes();
7253 }
7254 }
7255 }
7256 Ok(len)
7257 }
7258}
7259
7260impl<'a> Iterator for ExcerptChunks<'a> {
7261 type Item = Chunk<'a>;
7262
7263 fn next(&mut self) -> Option<Self::Item> {
7264 if let Some(chunk) = self.content_chunks.next() {
7265 return Some(chunk);
7266 }
7267
7268 if self.footer_height > 0 {
7269 let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
7270 self.footer_height = 0;
7271 return Some(Chunk {
7272 text,
7273 ..Default::default()
7274 });
7275 }
7276
7277 None
7278 }
7279}
7280
7281impl ToOffset for Point {
7282 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
7283 snapshot.point_to_offset(*self)
7284 }
7285}
7286
7287impl ToOffset for usize {
7288 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
7289 assert!(*self <= snapshot.len(), "offset is out of range");
7290 *self
7291 }
7292}
7293
7294impl ToOffset for OffsetUtf16 {
7295 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
7296 snapshot.offset_utf16_to_offset(*self)
7297 }
7298}
7299
7300impl ToOffset for PointUtf16 {
7301 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
7302 snapshot.point_utf16_to_offset(*self)
7303 }
7304}
7305
7306impl ToOffsetUtf16 for OffsetUtf16 {
7307 fn to_offset_utf16(&self, _snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
7308 *self
7309 }
7310}
7311
7312impl ToOffsetUtf16 for usize {
7313 fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
7314 snapshot.offset_to_offset_utf16(*self)
7315 }
7316}
7317
7318impl ToPoint for usize {
7319 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
7320 snapshot.offset_to_point(*self)
7321 }
7322}
7323
7324impl ToPoint for Point {
7325 fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
7326 *self
7327 }
7328}
7329
7330impl ToPointUtf16 for usize {
7331 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
7332 snapshot.offset_to_point_utf16(*self)
7333 }
7334}
7335
7336impl ToPointUtf16 for Point {
7337 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
7338 snapshot.point_to_point_utf16(*self)
7339 }
7340}
7341
7342impl ToPointUtf16 for PointUtf16 {
7343 fn to_point_utf16<'a>(&self, _: &MultiBufferSnapshot) -> PointUtf16 {
7344 *self
7345 }
7346}
7347
7348impl From<ExcerptId> for EntityId {
7349 fn from(id: ExcerptId) -> Self {
7350 EntityId::from(id.0 as u64)
7351 }
7352}
7353
7354pub fn build_excerpt_ranges<T>(
7355 buffer: &BufferSnapshot,
7356 ranges: &[Range<T>],
7357 context_line_count: u32,
7358) -> (Vec<ExcerptRange<Point>>, Vec<usize>)
7359where
7360 T: text::ToPoint,
7361{
7362 let max_point = buffer.max_point();
7363 let mut range_counts = Vec::new();
7364 let mut excerpt_ranges = Vec::new();
7365 let mut range_iter = ranges
7366 .iter()
7367 .map(|range| range.start.to_point(buffer)..range.end.to_point(buffer))
7368 .peekable();
7369 while let Some(range) = range_iter.next() {
7370 let excerpt_start = Point::new(range.start.row.saturating_sub(context_line_count), 0);
7371 let row = (range.end.row + context_line_count).min(max_point.row);
7372 let mut excerpt_end = Point::new(row, buffer.line_len(row));
7373
7374 let mut ranges_in_excerpt = 1;
7375
7376 while let Some(next_range) = range_iter.peek() {
7377 if next_range.start.row <= excerpt_end.row + context_line_count {
7378 let row = (next_range.end.row + context_line_count).min(max_point.row);
7379 excerpt_end = Point::new(row, buffer.line_len(row));
7380
7381 ranges_in_excerpt += 1;
7382 range_iter.next();
7383 } else {
7384 break;
7385 }
7386 }
7387
7388 excerpt_ranges.push(ExcerptRange {
7389 context: excerpt_start..excerpt_end,
7390 primary: Some(range),
7391 });
7392 range_counts.push(ranges_in_excerpt);
7393 }
7394
7395 (excerpt_ranges, range_counts)
7396}