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