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