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