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(
2380 &mut self,
2381 ranges: Vec<Range<Anchor>>,
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 in ranges.iter() {
2389 let end_excerpt_id = range.end.excerpt_id;
2390 let range = range.to_point(&snapshot);
2391 let mut peek_end = range.end;
2392 if range.end.row < snapshot.max_row().0 {
2393 peek_end = Point::new(range.end.row + 1, 0);
2394 };
2395
2396 for diff_hunk in snapshot.diff_hunks_in_range(range.start..peek_end) {
2397 if diff_hunk.excerpt_id.cmp(&end_excerpt_id, &snapshot).is_gt() {
2398 continue;
2399 }
2400 let start = Anchor::in_buffer(
2401 diff_hunk.excerpt_id,
2402 diff_hunk.buffer_id,
2403 diff_hunk.buffer_range.start,
2404 );
2405 let end = Anchor::in_buffer(
2406 diff_hunk.excerpt_id,
2407 diff_hunk.buffer_id,
2408 diff_hunk.buffer_range.end,
2409 );
2410 let start = snapshot.excerpt_offset_for_anchor(&start);
2411 let end = snapshot.excerpt_offset_for_anchor(&end);
2412 excerpt_edits.push(text::Edit {
2413 old: start..end,
2414 new: start..end,
2415 });
2416 }
2417 }
2418
2419 self.sync_diff_transforms(
2420 &mut snapshot,
2421 excerpt_edits,
2422 DiffChangeKind::ExpandOrCollapseHunks { expand },
2423 );
2424 cx.emit(Event::DiffHunksToggled);
2425 cx.emit(Event::Edited {
2426 singleton_buffer_edited: false,
2427 edited_buffer: None,
2428 });
2429 }
2430
2431 pub fn resize_excerpt(
2432 &mut self,
2433 id: ExcerptId,
2434 range: Range<text::Anchor>,
2435 cx: &mut Context<Self>,
2436 ) {
2437 self.sync(cx);
2438
2439 let mut snapshot = self.snapshot.borrow_mut();
2440 let locator = snapshot.excerpt_locator_for_id(id);
2441 let mut new_excerpts = SumTree::default();
2442 let mut cursor = snapshot
2443 .excerpts
2444 .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
2445 let mut edits = Vec::<Edit<ExcerptOffset>>::new();
2446
2447 let prefix = cursor.slice(&Some(locator), Bias::Left, &());
2448 new_excerpts.append(prefix, &());
2449
2450 let mut excerpt = cursor.item().unwrap().clone();
2451 let old_text_len = ExcerptOffset::new(excerpt.text_summary.len);
2452
2453 excerpt.range.context.start = range.start;
2454 excerpt.range.context.end = range.end;
2455 excerpt.max_buffer_row = range.end.to_point(&excerpt.buffer).row;
2456
2457 excerpt.text_summary = excerpt
2458 .buffer
2459 .text_summary_for_range(excerpt.range.context.clone());
2460
2461 let new_start_offset = ExcerptOffset::new(new_excerpts.summary().text.len);
2462 let old_start_offset = cursor.start().1;
2463 let new_text_len = ExcerptOffset::new(excerpt.text_summary.len);
2464 let edit = Edit {
2465 old: old_start_offset..old_start_offset + old_text_len,
2466 new: new_start_offset..new_start_offset + new_text_len,
2467 };
2468
2469 if let Some(last_edit) = edits.last_mut() {
2470 if last_edit.old.end == edit.old.start {
2471 last_edit.old.end = edit.old.end;
2472 last_edit.new.end = edit.new.end;
2473 } else {
2474 edits.push(edit);
2475 }
2476 } else {
2477 edits.push(edit);
2478 }
2479
2480 new_excerpts.push(excerpt, &());
2481
2482 cursor.next(&());
2483
2484 new_excerpts.append(cursor.suffix(&()), &());
2485
2486 drop(cursor);
2487 snapshot.excerpts = new_excerpts;
2488
2489 self.sync_diff_transforms(&mut snapshot, edits, DiffChangeKind::BufferEdited);
2490 cx.emit(Event::Edited {
2491 singleton_buffer_edited: false,
2492 edited_buffer: None,
2493 });
2494 cx.emit(Event::ExcerptsExpanded { ids: vec![id] });
2495 cx.notify();
2496 }
2497
2498 pub fn expand_excerpts(
2499 &mut self,
2500 ids: impl IntoIterator<Item = ExcerptId>,
2501 line_count: u32,
2502 direction: ExpandExcerptDirection,
2503 cx: &mut Context<Self>,
2504 ) {
2505 if line_count == 0 {
2506 return;
2507 }
2508 self.sync(cx);
2509 let mut snapshot = self.snapshot.borrow_mut();
2510
2511 let ids = ids.into_iter().collect::<Vec<_>>();
2512 let locators = snapshot.excerpt_locators_for_ids(ids.iter().copied());
2513 let mut new_excerpts = SumTree::default();
2514 let mut cursor = snapshot
2515 .excerpts
2516 .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
2517 let mut edits = Vec::<Edit<ExcerptOffset>>::new();
2518
2519 for locator in &locators {
2520 let prefix = cursor.slice(&Some(locator), Bias::Left, &());
2521 new_excerpts.append(prefix, &());
2522
2523 let mut excerpt = cursor.item().unwrap().clone();
2524 let old_text_len = ExcerptOffset::new(excerpt.text_summary.len);
2525
2526 let up_line_count = if direction.should_expand_up() {
2527 line_count
2528 } else {
2529 0
2530 };
2531
2532 let start_row = excerpt
2533 .range
2534 .context
2535 .start
2536 .to_point(&excerpt.buffer)
2537 .row
2538 .saturating_sub(up_line_count);
2539 let start_point = Point::new(start_row, 0);
2540 excerpt.range.context.start = excerpt.buffer.anchor_before(start_point);
2541
2542 let down_line_count = if direction.should_expand_down() {
2543 line_count
2544 } else {
2545 0
2546 };
2547
2548 let mut end_point = excerpt.buffer.clip_point(
2549 excerpt.range.context.end.to_point(&excerpt.buffer)
2550 + Point::new(down_line_count, 0),
2551 Bias::Left,
2552 );
2553 end_point.column = excerpt.buffer.line_len(end_point.row);
2554 excerpt.range.context.end = excerpt.buffer.anchor_after(end_point);
2555 excerpt.max_buffer_row = end_point.row;
2556
2557 excerpt.text_summary = excerpt
2558 .buffer
2559 .text_summary_for_range(excerpt.range.context.clone());
2560
2561 let new_start_offset = ExcerptOffset::new(new_excerpts.summary().text.len);
2562 let old_start_offset = cursor.start().1;
2563 let new_text_len = ExcerptOffset::new(excerpt.text_summary.len);
2564 let edit = Edit {
2565 old: old_start_offset..old_start_offset + old_text_len,
2566 new: new_start_offset..new_start_offset + new_text_len,
2567 };
2568
2569 if let Some(last_edit) = edits.last_mut() {
2570 if last_edit.old.end == edit.old.start {
2571 last_edit.old.end = edit.old.end;
2572 last_edit.new.end = edit.new.end;
2573 } else {
2574 edits.push(edit);
2575 }
2576 } else {
2577 edits.push(edit);
2578 }
2579
2580 new_excerpts.push(excerpt, &());
2581
2582 cursor.next(&());
2583 }
2584
2585 new_excerpts.append(cursor.suffix(&()), &());
2586
2587 drop(cursor);
2588 snapshot.excerpts = new_excerpts;
2589
2590 self.sync_diff_transforms(&mut snapshot, edits, DiffChangeKind::BufferEdited);
2591 cx.emit(Event::Edited {
2592 singleton_buffer_edited: false,
2593 edited_buffer: None,
2594 });
2595 cx.emit(Event::ExcerptsExpanded { ids });
2596 cx.notify();
2597 }
2598
2599 fn sync(&self, cx: &App) {
2600 let mut snapshot = self.snapshot.borrow_mut();
2601 let mut excerpts_to_edit = Vec::new();
2602 let mut non_text_state_updated = false;
2603 let mut is_dirty = false;
2604 let mut has_deleted_file = false;
2605 let mut has_conflict = false;
2606 let mut edited = false;
2607 let mut buffers = self.buffers.borrow_mut();
2608 for buffer_state in buffers.values_mut() {
2609 let buffer = buffer_state.buffer.read(cx);
2610 let version = buffer.version();
2611 let non_text_state_update_count = buffer.non_text_state_update_count();
2612
2613 let buffer_edited = version.changed_since(&buffer_state.last_version);
2614 let buffer_non_text_state_updated =
2615 non_text_state_update_count > buffer_state.last_non_text_state_update_count;
2616 if buffer_edited || buffer_non_text_state_updated {
2617 buffer_state.last_version = version;
2618 buffer_state.last_non_text_state_update_count = non_text_state_update_count;
2619 excerpts_to_edit.extend(
2620 buffer_state
2621 .excerpts
2622 .iter()
2623 .map(|locator| (locator, buffer_state.buffer.clone(), buffer_edited)),
2624 );
2625 }
2626
2627 edited |= buffer_edited;
2628 non_text_state_updated |= buffer_non_text_state_updated;
2629 is_dirty |= buffer.is_dirty();
2630 has_deleted_file |= buffer
2631 .file()
2632 .map_or(false, |file| file.disk_state() == DiskState::Deleted);
2633 has_conflict |= buffer.has_conflict();
2634 }
2635 if edited {
2636 snapshot.edit_count += 1;
2637 }
2638 if non_text_state_updated {
2639 snapshot.non_text_state_update_count += 1;
2640 }
2641 snapshot.is_dirty = is_dirty;
2642 snapshot.has_deleted_file = has_deleted_file;
2643 snapshot.has_conflict = has_conflict;
2644
2645 excerpts_to_edit.sort_unstable_by_key(|(locator, _, _)| *locator);
2646
2647 let mut edits = Vec::new();
2648 let mut new_excerpts = SumTree::default();
2649 let mut cursor = snapshot
2650 .excerpts
2651 .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
2652
2653 for (locator, buffer, buffer_edited) in excerpts_to_edit {
2654 new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &());
2655 let old_excerpt = cursor.item().unwrap();
2656 let buffer = buffer.read(cx);
2657 let buffer_id = buffer.remote_id();
2658
2659 let mut new_excerpt;
2660 if buffer_edited {
2661 edits.extend(
2662 buffer
2663 .edits_since_in_range::<usize>(
2664 old_excerpt.buffer.version(),
2665 old_excerpt.range.context.clone(),
2666 )
2667 .map(|edit| {
2668 let excerpt_old_start = cursor.start().1;
2669 let excerpt_new_start =
2670 ExcerptOffset::new(new_excerpts.summary().text.len);
2671 let old_start = excerpt_old_start + ExcerptOffset::new(edit.old.start);
2672 let old_end = excerpt_old_start + ExcerptOffset::new(edit.old.end);
2673 let new_start = excerpt_new_start + ExcerptOffset::new(edit.new.start);
2674 let new_end = excerpt_new_start + ExcerptOffset::new(edit.new.end);
2675 Edit {
2676 old: old_start..old_end,
2677 new: new_start..new_end,
2678 }
2679 }),
2680 );
2681
2682 new_excerpt = Excerpt::new(
2683 old_excerpt.id,
2684 locator.clone(),
2685 buffer_id,
2686 buffer.snapshot(),
2687 old_excerpt.range.clone(),
2688 old_excerpt.has_trailing_newline,
2689 );
2690 } else {
2691 new_excerpt = old_excerpt.clone();
2692 new_excerpt.buffer = buffer.snapshot();
2693 }
2694
2695 new_excerpts.push(new_excerpt, &());
2696 cursor.next(&());
2697 }
2698 new_excerpts.append(cursor.suffix(&()), &());
2699
2700 drop(cursor);
2701 snapshot.excerpts = new_excerpts;
2702
2703 self.sync_diff_transforms(&mut snapshot, edits, DiffChangeKind::BufferEdited);
2704 }
2705
2706 fn sync_diff_transforms(
2707 &self,
2708 snapshot: &mut MultiBufferSnapshot,
2709 excerpt_edits: Vec<text::Edit<ExcerptOffset>>,
2710 change_kind: DiffChangeKind,
2711 ) {
2712 if excerpt_edits.is_empty() {
2713 return;
2714 }
2715
2716 let mut excerpts = snapshot.excerpts.cursor::<ExcerptOffset>(&());
2717 let mut old_diff_transforms = snapshot
2718 .diff_transforms
2719 .cursor::<(ExcerptOffset, usize)>(&());
2720 let mut new_diff_transforms = SumTree::default();
2721 let mut old_expanded_hunks = HashSet::default();
2722 let mut output_edits = Vec::new();
2723 let mut output_delta = 0_isize;
2724 let mut at_transform_boundary = true;
2725 let mut end_of_current_insert = None;
2726
2727 let mut excerpt_edits = excerpt_edits.into_iter().peekable();
2728 while let Some(edit) = excerpt_edits.next() {
2729 excerpts.seek_forward(&edit.new.start, Bias::Right, &());
2730 if excerpts.item().is_none() && *excerpts.start() == edit.new.start {
2731 excerpts.prev(&());
2732 }
2733
2734 // Keep any transforms that are before the edit.
2735 if at_transform_boundary {
2736 at_transform_boundary = false;
2737 let transforms_before_edit =
2738 old_diff_transforms.slice(&edit.old.start, Bias::Left, &());
2739 self.append_diff_transforms(&mut new_diff_transforms, transforms_before_edit);
2740 if let Some(transform) = old_diff_transforms.item() {
2741 if old_diff_transforms.end(&()).0 == edit.old.start
2742 && old_diff_transforms.start().0 < edit.old.start
2743 {
2744 self.push_diff_transform(&mut new_diff_transforms, transform.clone());
2745 old_diff_transforms.next(&());
2746 }
2747 }
2748 }
2749
2750 // Compute the start of the edit in output coordinates.
2751 let edit_start_overshoot = (edit.old.start - old_diff_transforms.start().0).value;
2752 let edit_old_start = old_diff_transforms.start().1 + edit_start_overshoot;
2753 let edit_new_start = (edit_old_start as isize + output_delta) as usize;
2754
2755 let changed_diff_hunks = self.recompute_diff_transforms_for_edit(
2756 &edit,
2757 &mut excerpts,
2758 &mut old_diff_transforms,
2759 &mut new_diff_transforms,
2760 &mut end_of_current_insert,
2761 &mut old_expanded_hunks,
2762 &snapshot,
2763 change_kind,
2764 );
2765
2766 // Compute the end of the edit in output coordinates.
2767 let edit_old_end_overshoot = edit.old.end - old_diff_transforms.start().0;
2768 let edit_new_end_overshoot = edit.new.end - new_diff_transforms.summary().excerpt_len();
2769 let edit_old_end = old_diff_transforms.start().1 + edit_old_end_overshoot.value;
2770 let edit_new_end =
2771 new_diff_transforms.summary().output.len + edit_new_end_overshoot.value;
2772 let output_edit = Edit {
2773 old: edit_old_start..edit_old_end,
2774 new: edit_new_start..edit_new_end,
2775 };
2776
2777 output_delta += (output_edit.new.end - output_edit.new.start) as isize;
2778 output_delta -= (output_edit.old.end - output_edit.old.start) as isize;
2779 if changed_diff_hunks || matches!(change_kind, DiffChangeKind::BufferEdited) {
2780 output_edits.push(output_edit);
2781 }
2782
2783 // If this is the last edit that intersects the current diff transform,
2784 // then recreate the content up to the end of this transform, to prepare
2785 // for reusing additional slices of the old transforms.
2786 if excerpt_edits.peek().map_or(true, |next_edit| {
2787 next_edit.old.start >= old_diff_transforms.end(&()).0
2788 }) {
2789 let keep_next_old_transform = (old_diff_transforms.start().0 >= edit.old.end)
2790 && match old_diff_transforms.item() {
2791 Some(DiffTransform::BufferContent {
2792 inserted_hunk_anchor: Some(hunk_anchor),
2793 ..
2794 }) => excerpts
2795 .item()
2796 .is_some_and(|excerpt| hunk_anchor.1.is_valid(&excerpt.buffer)),
2797 _ => true,
2798 };
2799
2800 let mut excerpt_offset = edit.new.end;
2801 if !keep_next_old_transform {
2802 excerpt_offset += old_diff_transforms.end(&()).0 - edit.old.end;
2803 old_diff_transforms.next(&());
2804 }
2805
2806 old_expanded_hunks.clear();
2807 self.push_buffer_content_transform(
2808 &snapshot,
2809 &mut new_diff_transforms,
2810 excerpt_offset,
2811 end_of_current_insert,
2812 );
2813 at_transform_boundary = true;
2814 }
2815 }
2816
2817 // Keep any transforms that are after the last edit.
2818 self.append_diff_transforms(&mut new_diff_transforms, old_diff_transforms.suffix(&()));
2819
2820 // Ensure there's always at least one buffer content transform.
2821 if new_diff_transforms.is_empty() {
2822 new_diff_transforms.push(
2823 DiffTransform::BufferContent {
2824 summary: Default::default(),
2825 inserted_hunk_anchor: None,
2826 },
2827 &(),
2828 );
2829 }
2830
2831 self.subscriptions.publish(output_edits);
2832 drop(old_diff_transforms);
2833 drop(excerpts);
2834 snapshot.diff_transforms = new_diff_transforms;
2835 snapshot.edit_count += 1;
2836
2837 #[cfg(any(test, feature = "test-support"))]
2838 snapshot.check_invariants();
2839 }
2840
2841 #[allow(clippy::too_many_arguments)]
2842 fn recompute_diff_transforms_for_edit(
2843 &self,
2844 edit: &Edit<TypedOffset<Excerpt>>,
2845 excerpts: &mut Cursor<Excerpt, TypedOffset<Excerpt>>,
2846 old_diff_transforms: &mut Cursor<DiffTransform, (TypedOffset<Excerpt>, usize)>,
2847 new_diff_transforms: &mut SumTree<DiffTransform>,
2848 end_of_current_insert: &mut Option<(TypedOffset<Excerpt>, ExcerptId, text::Anchor)>,
2849 old_expanded_hunks: &mut HashSet<(ExcerptId, text::Anchor)>,
2850 snapshot: &MultiBufferSnapshot,
2851 change_kind: DiffChangeKind,
2852 ) -> bool {
2853 log::trace!(
2854 "recomputing diff transform for edit {:?} => {:?}",
2855 edit.old.start.value..edit.old.end.value,
2856 edit.new.start.value..edit.new.end.value
2857 );
2858
2859 // Record which hunks were previously expanded.
2860 while let Some(item) = old_diff_transforms.item() {
2861 if let Some(hunk_anchor) = item.hunk_anchor() {
2862 log::trace!(
2863 "previously expanded hunk at {}",
2864 old_diff_transforms.start().0
2865 );
2866 old_expanded_hunks.insert(hunk_anchor);
2867 }
2868 if old_diff_transforms.end(&()).0 > edit.old.end {
2869 break;
2870 }
2871 old_diff_transforms.next(&());
2872 }
2873
2874 // Avoid querying diff hunks if there's no possibility of hunks being expanded.
2875 if old_expanded_hunks.is_empty()
2876 && change_kind == DiffChangeKind::BufferEdited
2877 && !self.all_diff_hunks_expanded
2878 {
2879 return false;
2880 }
2881
2882 // Visit each excerpt that intersects the edit.
2883 let mut did_expand_hunks = false;
2884 while let Some(excerpt) = excerpts.item() {
2885 // Recompute the expanded hunks in the portion of the excerpt that
2886 // intersects the edit.
2887 if let Some((diff, base_text)) = snapshot
2888 .diffs
2889 .get(&excerpt.buffer_id)
2890 .and_then(|diff| Some((diff, diff.base_text.as_ref()?)))
2891 {
2892 let buffer = &excerpt.buffer;
2893 let excerpt_start = *excerpts.start();
2894 let excerpt_end = excerpt_start + ExcerptOffset::new(excerpt.text_summary.len);
2895 let excerpt_buffer_start = excerpt.range.context.start.to_offset(buffer);
2896 let excerpt_buffer_end = excerpt_buffer_start + excerpt.text_summary.len;
2897 let edit_buffer_start =
2898 excerpt_buffer_start + edit.new.start.value.saturating_sub(excerpt_start.value);
2899 let edit_buffer_end =
2900 excerpt_buffer_start + edit.new.end.value.saturating_sub(excerpt_start.value);
2901 let edit_buffer_end = edit_buffer_end.min(excerpt_buffer_end);
2902 let edit_anchor_range =
2903 buffer.anchor_before(edit_buffer_start)..buffer.anchor_after(edit_buffer_end);
2904
2905 for hunk in diff.hunks_intersecting_range(edit_anchor_range, buffer) {
2906 let hunk_buffer_range = hunk.buffer_range.to_offset(buffer);
2907
2908 let hunk_anchor = (excerpt.id, hunk.buffer_range.start);
2909 if hunk_buffer_range.start < excerpt_buffer_start {
2910 log::trace!("skipping hunk that starts before excerpt");
2911 continue;
2912 }
2913
2914 let hunk_excerpt_start = excerpt_start
2915 + ExcerptOffset::new(
2916 hunk_buffer_range.start.saturating_sub(excerpt_buffer_start),
2917 );
2918 let hunk_excerpt_end = excerpt_end.min(
2919 excerpt_start
2920 + ExcerptOffset::new(hunk_buffer_range.end - excerpt_buffer_start),
2921 );
2922
2923 self.push_buffer_content_transform(
2924 snapshot,
2925 new_diff_transforms,
2926 hunk_excerpt_start,
2927 *end_of_current_insert,
2928 );
2929
2930 // For every existing hunk, determine if it was previously expanded
2931 // and if it should currently be expanded.
2932 let was_previously_expanded = old_expanded_hunks.contains(&hunk_anchor);
2933 let should_expand_hunk = match &change_kind {
2934 DiffChangeKind::DiffUpdated { base_changed: true } => {
2935 self.all_diff_hunks_expanded
2936 }
2937 DiffChangeKind::ExpandOrCollapseHunks { expand } => {
2938 let intersects = hunk_buffer_range.is_empty()
2939 || hunk_buffer_range.end > edit_buffer_start;
2940 if *expand {
2941 intersects
2942 || was_previously_expanded
2943 || self.all_diff_hunks_expanded
2944 } else {
2945 !intersects
2946 && (was_previously_expanded || self.all_diff_hunks_expanded)
2947 }
2948 }
2949 _ => was_previously_expanded || self.all_diff_hunks_expanded,
2950 };
2951
2952 if should_expand_hunk {
2953 did_expand_hunks = true;
2954 log::trace!(
2955 "expanding hunk {:?}, excerpt:{:?}",
2956 hunk_excerpt_start.value..hunk_excerpt_end.value,
2957 excerpt.id
2958 );
2959
2960 if !hunk.diff_base_byte_range.is_empty()
2961 && hunk_buffer_range.start >= edit_buffer_start
2962 && hunk_buffer_range.start <= excerpt_buffer_end
2963 {
2964 let mut text_cursor =
2965 base_text.as_rope().cursor(hunk.diff_base_byte_range.start);
2966 let mut base_text_summary =
2967 text_cursor.summary::<TextSummary>(hunk.diff_base_byte_range.end);
2968
2969 let mut has_trailing_newline = false;
2970 if base_text_summary.last_line_chars > 0 {
2971 base_text_summary += TextSummary::newline();
2972 has_trailing_newline = true;
2973 }
2974
2975 new_diff_transforms.push(
2976 DiffTransform::DeletedHunk {
2977 base_text_byte_range: hunk.diff_base_byte_range.clone(),
2978 summary: base_text_summary,
2979 buffer_id: excerpt.buffer_id,
2980 hunk_anchor,
2981 has_trailing_newline,
2982 },
2983 &(),
2984 );
2985 }
2986
2987 if !hunk_buffer_range.is_empty() {
2988 *end_of_current_insert = Some((
2989 hunk_excerpt_end.min(excerpt_end),
2990 hunk_anchor.0,
2991 hunk_anchor.1,
2992 ));
2993 }
2994 }
2995 }
2996 }
2997
2998 if excerpts.end(&()) <= edit.new.end {
2999 excerpts.next(&());
3000 } else {
3001 break;
3002 }
3003 }
3004
3005 did_expand_hunks || !old_expanded_hunks.is_empty()
3006 }
3007
3008 fn append_diff_transforms(
3009 &self,
3010 new_transforms: &mut SumTree<DiffTransform>,
3011 subtree: SumTree<DiffTransform>,
3012 ) {
3013 if let Some(DiffTransform::BufferContent {
3014 inserted_hunk_anchor,
3015 summary,
3016 }) = subtree.first()
3017 {
3018 if self.extend_last_buffer_content_transform(
3019 new_transforms,
3020 *inserted_hunk_anchor,
3021 *summary,
3022 ) {
3023 let mut cursor = subtree.cursor::<()>(&());
3024 cursor.next(&());
3025 cursor.next(&());
3026 new_transforms.append(cursor.suffix(&()), &());
3027 return;
3028 }
3029 }
3030 new_transforms.append(subtree, &());
3031 }
3032
3033 fn push_diff_transform(
3034 &self,
3035 new_transforms: &mut SumTree<DiffTransform>,
3036 transform: DiffTransform,
3037 ) {
3038 if let DiffTransform::BufferContent {
3039 inserted_hunk_anchor,
3040 summary,
3041 } = transform
3042 {
3043 if self.extend_last_buffer_content_transform(
3044 new_transforms,
3045 inserted_hunk_anchor,
3046 summary,
3047 ) {
3048 return;
3049 }
3050 }
3051 new_transforms.push(transform, &());
3052 }
3053
3054 fn push_buffer_content_transform(
3055 &self,
3056 old_snapshot: &MultiBufferSnapshot,
3057 new_transforms: &mut SumTree<DiffTransform>,
3058 end_offset: ExcerptOffset,
3059 current_inserted_hunk: Option<(ExcerptOffset, ExcerptId, text::Anchor)>,
3060 ) {
3061 let inserted_region =
3062 current_inserted_hunk.map(|(insertion_end_offset, excerpt_id, anchor)| {
3063 (
3064 end_offset.min(insertion_end_offset),
3065 Some((excerpt_id, anchor)),
3066 )
3067 });
3068 let unchanged_region = [(end_offset, None)];
3069
3070 for (end_offset, inserted_hunk_anchor) in
3071 inserted_region.into_iter().chain(unchanged_region)
3072 {
3073 let start_offset = new_transforms.summary().excerpt_len();
3074 if end_offset <= start_offset {
3075 continue;
3076 }
3077 let summary_to_add = old_snapshot
3078 .text_summary_for_excerpt_offset_range::<TextSummary>(start_offset..end_offset);
3079
3080 if !self.extend_last_buffer_content_transform(
3081 new_transforms,
3082 inserted_hunk_anchor,
3083 summary_to_add,
3084 ) {
3085 new_transforms.push(
3086 DiffTransform::BufferContent {
3087 summary: summary_to_add,
3088 inserted_hunk_anchor,
3089 },
3090 &(),
3091 )
3092 }
3093 }
3094 }
3095
3096 fn extend_last_buffer_content_transform(
3097 &self,
3098 new_transforms: &mut SumTree<DiffTransform>,
3099 new_inserted_hunk_anchor: Option<(ExcerptId, text::Anchor)>,
3100 summary_to_add: TextSummary,
3101 ) -> bool {
3102 let mut did_extend = false;
3103 new_transforms.update_last(
3104 |last_transform| {
3105 if let DiffTransform::BufferContent {
3106 summary,
3107 inserted_hunk_anchor,
3108 } = last_transform
3109 {
3110 if *inserted_hunk_anchor == new_inserted_hunk_anchor {
3111 *summary += summary_to_add;
3112 did_extend = true;
3113 }
3114 }
3115 },
3116 &(),
3117 );
3118 did_extend
3119 }
3120}
3121
3122#[cfg(any(test, feature = "test-support"))]
3123impl MultiBuffer {
3124 pub fn build_simple(text: &str, cx: &mut gpui::App) -> Entity<Self> {
3125 let buffer = cx.new(|cx| Buffer::local(text, cx));
3126 cx.new(|cx| Self::singleton(buffer, cx))
3127 }
3128
3129 pub fn build_multi<const COUNT: usize>(
3130 excerpts: [(&str, Vec<Range<Point>>); COUNT],
3131 cx: &mut gpui::App,
3132 ) -> Entity<Self> {
3133 let multi = cx.new(|_| Self::new(Capability::ReadWrite));
3134 for (text, ranges) in excerpts {
3135 let buffer = cx.new(|cx| Buffer::local(text, cx));
3136 let excerpt_ranges = ranges.into_iter().map(|range| ExcerptRange {
3137 context: range,
3138 primary: None,
3139 });
3140 multi.update(cx, |multi, cx| {
3141 multi.push_excerpts(buffer, excerpt_ranges, cx)
3142 });
3143 }
3144
3145 multi
3146 }
3147
3148 pub fn build_from_buffer(buffer: Entity<Buffer>, cx: &mut gpui::App) -> Entity<Self> {
3149 cx.new(|cx| Self::singleton(buffer, cx))
3150 }
3151
3152 pub fn build_random(rng: &mut impl rand::Rng, cx: &mut gpui::App) -> Entity<Self> {
3153 cx.new(|cx| {
3154 let mut multibuffer = MultiBuffer::new(Capability::ReadWrite);
3155 let mutation_count = rng.gen_range(1..=5);
3156 multibuffer.randomly_edit_excerpts(rng, mutation_count, cx);
3157 multibuffer
3158 })
3159 }
3160
3161 pub fn randomly_edit(
3162 &mut self,
3163 rng: &mut impl rand::Rng,
3164 edit_count: usize,
3165 cx: &mut Context<Self>,
3166 ) {
3167 use util::RandomCharIter;
3168
3169 let snapshot = self.read(cx);
3170 let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
3171 let mut last_end = None;
3172 for _ in 0..edit_count {
3173 if last_end.map_or(false, |last_end| last_end >= snapshot.len()) {
3174 break;
3175 }
3176
3177 let new_start = last_end.map_or(0, |last_end| last_end + 1);
3178 let end = snapshot.clip_offset(rng.gen_range(new_start..=snapshot.len()), Bias::Right);
3179 let start = snapshot.clip_offset(rng.gen_range(new_start..=end), Bias::Right);
3180 last_end = Some(end);
3181
3182 let mut range = start..end;
3183 if rng.gen_bool(0.2) {
3184 mem::swap(&mut range.start, &mut range.end);
3185 }
3186
3187 let new_text_len = rng.gen_range(0..10);
3188 let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
3189
3190 edits.push((range, new_text.into()));
3191 }
3192 log::info!("mutating multi-buffer with {:?}", edits);
3193 drop(snapshot);
3194
3195 self.edit(edits, None, cx);
3196 }
3197
3198 pub fn randomly_edit_excerpts(
3199 &mut self,
3200 rng: &mut impl rand::Rng,
3201 mutation_count: usize,
3202 cx: &mut Context<Self>,
3203 ) {
3204 use rand::prelude::*;
3205 use std::env;
3206 use util::RandomCharIter;
3207
3208 let max_excerpts = env::var("MAX_EXCERPTS")
3209 .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))
3210 .unwrap_or(5);
3211
3212 let mut buffers = Vec::new();
3213 for _ in 0..mutation_count {
3214 if rng.gen_bool(0.05) {
3215 log::info!("Clearing multi-buffer");
3216 self.clear(cx);
3217 continue;
3218 } else if rng.gen_bool(0.1) && !self.excerpt_ids().is_empty() {
3219 let ids = self.excerpt_ids();
3220 let mut excerpts = HashSet::default();
3221 for _ in 0..rng.gen_range(0..ids.len()) {
3222 excerpts.extend(ids.choose(rng).copied());
3223 }
3224
3225 let line_count = rng.gen_range(0..5);
3226
3227 log::info!("Expanding excerpts {excerpts:?} by {line_count} lines");
3228
3229 self.expand_excerpts(
3230 excerpts.iter().cloned(),
3231 line_count,
3232 ExpandExcerptDirection::UpAndDown,
3233 cx,
3234 );
3235 continue;
3236 }
3237
3238 let excerpt_ids = self.excerpt_ids();
3239 if excerpt_ids.is_empty() || (rng.gen() && excerpt_ids.len() < max_excerpts) {
3240 let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() {
3241 let text = RandomCharIter::new(&mut *rng).take(10).collect::<String>();
3242 buffers.push(cx.new(|cx| Buffer::local(text, cx)));
3243 let buffer = buffers.last().unwrap().read(cx);
3244 log::info!(
3245 "Creating new buffer {} with text: {:?}",
3246 buffer.remote_id(),
3247 buffer.text()
3248 );
3249 buffers.last().unwrap().clone()
3250 } else {
3251 self.buffers
3252 .borrow()
3253 .values()
3254 .choose(rng)
3255 .unwrap()
3256 .buffer
3257 .clone()
3258 };
3259
3260 let buffer = buffer_handle.read(cx);
3261 let buffer_text = buffer.text();
3262 let ranges = (0..rng.gen_range(0..5))
3263 .map(|_| {
3264 let end_ix =
3265 buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
3266 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
3267 ExcerptRange {
3268 context: start_ix..end_ix,
3269 primary: None,
3270 }
3271 })
3272 .collect::<Vec<_>>();
3273 log::info!(
3274 "Inserting excerpts from buffer {} and ranges {:?}: {:?}",
3275 buffer_handle.read(cx).remote_id(),
3276 ranges.iter().map(|r| &r.context).collect::<Vec<_>>(),
3277 ranges
3278 .iter()
3279 .map(|r| &buffer_text[r.context.clone()])
3280 .collect::<Vec<_>>()
3281 );
3282
3283 let excerpt_id = self.push_excerpts(buffer_handle.clone(), ranges, cx);
3284 log::info!("Inserted with ids: {:?}", excerpt_id);
3285 } else {
3286 let remove_count = rng.gen_range(1..=excerpt_ids.len());
3287 let mut excerpts_to_remove = excerpt_ids
3288 .choose_multiple(rng, remove_count)
3289 .cloned()
3290 .collect::<Vec<_>>();
3291 let snapshot = self.snapshot.borrow();
3292 excerpts_to_remove.sort_unstable_by(|a, b| a.cmp(b, &snapshot));
3293 drop(snapshot);
3294 log::info!("Removing excerpts {:?}", excerpts_to_remove);
3295 self.remove_excerpts(excerpts_to_remove, cx);
3296 }
3297 }
3298 }
3299
3300 pub fn randomly_mutate(
3301 &mut self,
3302 rng: &mut impl rand::Rng,
3303 mutation_count: usize,
3304 cx: &mut Context<Self>,
3305 ) {
3306 use rand::prelude::*;
3307
3308 if rng.gen_bool(0.7) || self.singleton {
3309 let buffer = self
3310 .buffers
3311 .borrow()
3312 .values()
3313 .choose(rng)
3314 .map(|state| state.buffer.clone());
3315
3316 if let Some(buffer) = buffer {
3317 buffer.update(cx, |buffer, cx| {
3318 if rng.gen() {
3319 buffer.randomly_edit(rng, mutation_count, cx);
3320 } else {
3321 buffer.randomly_undo_redo(rng, cx);
3322 }
3323 });
3324 } else {
3325 self.randomly_edit(rng, mutation_count, cx);
3326 }
3327 } else {
3328 self.randomly_edit_excerpts(rng, mutation_count, cx);
3329 }
3330
3331 self.check_invariants(cx);
3332 }
3333
3334 fn check_invariants(&self, cx: &App) {
3335 self.read(cx).check_invariants();
3336 }
3337}
3338
3339impl EventEmitter<Event> for MultiBuffer {}
3340
3341impl MultiBufferSnapshot {
3342 pub fn text(&self) -> String {
3343 self.chunks(0..self.len(), false)
3344 .map(|chunk| chunk.text)
3345 .collect()
3346 }
3347
3348 pub fn reversed_chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
3349 self.reversed_chunks_in_range(0..position.to_offset(self))
3350 .flat_map(|c| c.chars().rev())
3351 }
3352
3353 fn reversed_chunks_in_range(&self, range: Range<usize>) -> ReversedMultiBufferChunks {
3354 let mut cursor = self.cursor::<usize>();
3355 cursor.seek(&range.end);
3356 let current_chunks = cursor.region().as_ref().map(|region| {
3357 let start_overshoot = range.start.saturating_sub(region.range.start);
3358 let end_overshoot = range.end - region.range.start;
3359 let end = (region.buffer_range.start + end_overshoot).min(region.buffer_range.end);
3360 let start = region.buffer_range.start + start_overshoot;
3361 region.buffer.reversed_chunks_in_range(start..end)
3362 });
3363 ReversedMultiBufferChunks {
3364 cursor,
3365 current_chunks,
3366 start: range.start,
3367 offset: range.end,
3368 }
3369 }
3370
3371 pub fn chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
3372 let offset = position.to_offset(self);
3373 self.text_for_range(offset..self.len())
3374 .flat_map(|chunk| chunk.chars())
3375 }
3376
3377 pub fn text_for_range<T: ToOffset>(&self, range: Range<T>) -> impl Iterator<Item = &str> + '_ {
3378 self.chunks(range, false).map(|chunk| chunk.text)
3379 }
3380
3381 pub fn is_line_blank(&self, row: MultiBufferRow) -> bool {
3382 self.text_for_range(Point::new(row.0, 0)..Point::new(row.0, self.line_len(row)))
3383 .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
3384 }
3385
3386 pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
3387 where
3388 T: ToOffset,
3389 {
3390 let position = position.to_offset(self);
3391 position == self.clip_offset(position, Bias::Left)
3392 && self
3393 .bytes_in_range(position..self.len())
3394 .flatten()
3395 .copied()
3396 .take(needle.len())
3397 .eq(needle.bytes())
3398 }
3399
3400 pub fn diff_hunks(&self) -> impl Iterator<Item = MultiBufferDiffHunk> + '_ {
3401 self.diff_hunks_in_range(Anchor::min()..Anchor::max())
3402 }
3403
3404 pub fn diff_hunks_in_range<T: ToPoint>(
3405 &self,
3406 range: Range<T>,
3407 ) -> impl Iterator<Item = MultiBufferDiffHunk> + '_ {
3408 let query_range = range.start.to_point(self)..range.end.to_point(self);
3409 self.lift_buffer_metadata(query_range.clone(), move |buffer, buffer_range| {
3410 let diff = self.diffs.get(&buffer.remote_id())?;
3411 let buffer_start = buffer.anchor_before(buffer_range.start);
3412 let buffer_end = buffer.anchor_after(buffer_range.end);
3413 Some(
3414 diff.hunks_intersecting_range(buffer_start..buffer_end, buffer)
3415 .map(|hunk| {
3416 (
3417 Point::new(hunk.row_range.start, 0)..Point::new(hunk.row_range.end, 0),
3418 hunk,
3419 )
3420 }),
3421 )
3422 })
3423 .filter_map(move |(range, hunk, excerpt)| {
3424 if range.start != range.end
3425 && range.end == query_range.start
3426 && !hunk.row_range.is_empty()
3427 {
3428 return None;
3429 }
3430 let end_row = if range.end.column == 0 {
3431 range.end.row
3432 } else {
3433 range.end.row + 1
3434 };
3435 Some(MultiBufferDiffHunk {
3436 row_range: MultiBufferRow(range.start.row)..MultiBufferRow(end_row),
3437 buffer_id: excerpt.buffer_id,
3438 excerpt_id: excerpt.id,
3439 buffer_range: hunk.buffer_range.clone(),
3440 diff_base_byte_range: hunk.diff_base_byte_range.clone(),
3441 })
3442 })
3443 }
3444
3445 pub fn excerpt_ids_for_range<T: ToOffset>(
3446 &self,
3447 range: Range<T>,
3448 ) -> impl Iterator<Item = ExcerptId> + '_ {
3449 let range = range.start.to_offset(self)..range.end.to_offset(self);
3450 let mut cursor = self.cursor::<usize>();
3451 cursor.seek(&range.start);
3452 std::iter::from_fn(move || {
3453 let region = cursor.region()?;
3454 if region.range.start >= range.end {
3455 return None;
3456 }
3457 cursor.next_excerpt();
3458 Some(region.excerpt.id)
3459 })
3460 }
3461
3462 pub fn buffer_ids_for_range<T: ToOffset>(
3463 &self,
3464 range: Range<T>,
3465 ) -> impl Iterator<Item = BufferId> + '_ {
3466 let range = range.start.to_offset(self)..range.end.to_offset(self);
3467 let mut cursor = self.cursor::<usize>();
3468 cursor.seek(&range.start);
3469 std::iter::from_fn(move || {
3470 let region = cursor.region()?;
3471 if region.range.start >= range.end {
3472 return None;
3473 }
3474 cursor.next_excerpt();
3475 Some(region.excerpt.buffer_id)
3476 })
3477 }
3478
3479 pub fn ranges_to_buffer_ranges<T: ToOffset>(
3480 &self,
3481 ranges: impl Iterator<Item = Range<T>>,
3482 ) -> impl Iterator<Item = (&BufferSnapshot, Range<usize>, ExcerptId)> {
3483 ranges.flat_map(|range| self.range_to_buffer_ranges(range).into_iter())
3484 }
3485
3486 pub fn range_to_buffer_ranges<T: ToOffset>(
3487 &self,
3488 range: Range<T>,
3489 ) -> Vec<(&BufferSnapshot, Range<usize>, ExcerptId)> {
3490 let start = range.start.to_offset(&self);
3491 let end = range.end.to_offset(&self);
3492
3493 let mut cursor = self.cursor::<usize>();
3494 cursor.seek(&start);
3495
3496 let mut result: Vec<(&BufferSnapshot, Range<usize>, ExcerptId)> = Vec::new();
3497 while let Some(region) = cursor.region() {
3498 if region.range.start > end {
3499 break;
3500 }
3501 if region.is_main_buffer {
3502 let start_overshoot = start.saturating_sub(region.range.start);
3503 let end_overshoot = end.saturating_sub(region.range.start);
3504 let start = region
3505 .buffer_range
3506 .end
3507 .min(region.buffer_range.start + start_overshoot);
3508 let end = region
3509 .buffer_range
3510 .end
3511 .min(region.buffer_range.start + end_overshoot);
3512 if let Some(prev) = result.last_mut().filter(|(_, prev_range, excerpt_id)| {
3513 *excerpt_id == region.excerpt.id && prev_range.end == start
3514 }) {
3515 prev.1.end = end;
3516 } else {
3517 result.push((region.buffer, start..end, region.excerpt.id));
3518 }
3519 }
3520 cursor.next();
3521 }
3522 result
3523 }
3524
3525 pub fn range_to_buffer_ranges_with_deleted_hunks<T: ToOffset>(
3526 &self,
3527 range: Range<T>,
3528 ) -> impl Iterator<Item = (&BufferSnapshot, Range<usize>, ExcerptId, Option<Anchor>)> + '_ {
3529 let start = range.start.to_offset(&self);
3530 let end = range.end.to_offset(&self);
3531
3532 let mut cursor = self.cursor::<usize>();
3533 cursor.seek(&start);
3534
3535 std::iter::from_fn(move || {
3536 let region = cursor.region()?;
3537 if region.range.start > end {
3538 return None;
3539 }
3540 let start_overshoot = start.saturating_sub(region.range.start);
3541 let end_overshoot = end.saturating_sub(region.range.start);
3542 let start = region
3543 .buffer_range
3544 .end
3545 .min(region.buffer_range.start + start_overshoot);
3546 let end = region
3547 .buffer_range
3548 .end
3549 .min(region.buffer_range.start + end_overshoot);
3550
3551 let region_excerpt_id = region.excerpt.id;
3552 let deleted_hunk_anchor = if region.is_main_buffer {
3553 None
3554 } else {
3555 Some(self.anchor_before(region.range.start))
3556 };
3557 let result = (
3558 region.buffer,
3559 start..end,
3560 region_excerpt_id,
3561 deleted_hunk_anchor,
3562 );
3563 cursor.next();
3564 Some(result)
3565 })
3566 }
3567
3568 /// Retrieves buffer metadata for the given range, and converts it into multi-buffer
3569 /// coordinates.
3570 ///
3571 /// The given callback will be called for every excerpt intersecting the given range. It will
3572 /// be passed the excerpt's buffer and the buffer range that the input range intersects.
3573 /// The callback should return an iterator of metadata items from that buffer, each paired
3574 /// with a buffer range.
3575 ///
3576 /// The returned iterator yields each of these metadata items, paired with its range in
3577 /// multi-buffer coordinates.
3578 fn lift_buffer_metadata<'a, D, M, I>(
3579 &'a self,
3580 query_range: Range<D>,
3581 get_buffer_metadata: impl 'a + Fn(&'a BufferSnapshot, Range<D>) -> Option<I>,
3582 ) -> impl Iterator<Item = (Range<D>, M, &'a Excerpt)> + 'a
3583 where
3584 I: Iterator<Item = (Range<D>, M)> + 'a,
3585 D: TextDimension + Ord + Sub<D, Output = D>,
3586 {
3587 let max_position = D::from_text_summary(&self.text_summary());
3588 let mut current_excerpt_metadata: Option<(ExcerptId, I)> = None;
3589 let mut cursor = self.cursor::<D>();
3590
3591 // Find the excerpt and buffer offset where the given range ends.
3592 cursor.seek(&query_range.end);
3593 let mut range_end = None;
3594 while let Some(region) = cursor.region() {
3595 if region.is_main_buffer {
3596 let mut buffer_end = region.buffer_range.start;
3597 let overshoot = if query_range.end > region.range.start {
3598 query_range.end - region.range.start
3599 } else {
3600 D::default()
3601 };
3602 buffer_end.add_assign(&overshoot);
3603 range_end = Some((region.excerpt.id, buffer_end));
3604 break;
3605 }
3606 cursor.next();
3607 }
3608
3609 cursor.seek(&query_range.start);
3610
3611 if let Some(region) = cursor.region().filter(|region| !region.is_main_buffer) {
3612 if region.range.start > D::zero(&()) {
3613 cursor.prev()
3614 }
3615 }
3616
3617 iter::from_fn(move || loop {
3618 let excerpt = cursor.excerpt()?;
3619
3620 // If we have already retrieved metadata for this excerpt, continue to use it.
3621 let metadata_iter = if let Some((_, metadata)) = current_excerpt_metadata
3622 .as_mut()
3623 .filter(|(excerpt_id, _)| *excerpt_id == excerpt.id)
3624 {
3625 Some(metadata)
3626 }
3627 // Otherwise, compute the intersection of the input range with the excerpt's range,
3628 // and retrieve the metadata for the resulting range.
3629 else {
3630 let region = cursor.region()?;
3631 let mut buffer_start;
3632 if region.is_main_buffer {
3633 buffer_start = region.buffer_range.start;
3634 if query_range.start > region.range.start {
3635 let overshoot = query_range.start - region.range.start;
3636 buffer_start.add_assign(&overshoot);
3637 }
3638 buffer_start = buffer_start.min(region.buffer_range.end);
3639 } else {
3640 buffer_start = cursor.main_buffer_position()?;
3641 };
3642 let mut buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer);
3643 if let Some((end_excerpt_id, end_buffer_offset)) = range_end {
3644 if excerpt.id == end_excerpt_id {
3645 buffer_end = buffer_end.min(end_buffer_offset);
3646 }
3647 }
3648
3649 if let Some(iterator) =
3650 get_buffer_metadata(&excerpt.buffer, buffer_start..buffer_end)
3651 {
3652 Some(&mut current_excerpt_metadata.insert((excerpt.id, iterator)).1)
3653 } else {
3654 None
3655 }
3656 };
3657
3658 // Visit each metadata item.
3659 if let Some((metadata_buffer_range, metadata)) = metadata_iter.and_then(Iterator::next)
3660 {
3661 // Find the multibuffer regions that contain the start and end of
3662 // the metadata item's range.
3663 if metadata_buffer_range.start > D::default() {
3664 while let Some(region) = cursor.region() {
3665 if region.is_main_buffer
3666 && (region.buffer_range.end >= metadata_buffer_range.start
3667 || cursor.is_at_end_of_excerpt())
3668 {
3669 break;
3670 }
3671 cursor.next();
3672 }
3673 }
3674 let start_region = cursor.region()?;
3675 while let Some(region) = cursor.region() {
3676 if region.is_main_buffer
3677 && (region.buffer_range.end > metadata_buffer_range.end
3678 || cursor.is_at_end_of_excerpt())
3679 {
3680 break;
3681 }
3682 cursor.next();
3683 }
3684 let end_region = cursor.region();
3685
3686 // Convert the metadata item's range into multibuffer coordinates.
3687 let mut start_position = start_region.range.start;
3688 let region_buffer_start = start_region.buffer_range.start;
3689 if start_region.is_main_buffer && metadata_buffer_range.start > region_buffer_start
3690 {
3691 start_position.add_assign(&(metadata_buffer_range.start - region_buffer_start));
3692 start_position = start_position.min(start_region.range.end);
3693 }
3694
3695 let mut end_position = max_position;
3696 if let Some(end_region) = &end_region {
3697 end_position = end_region.range.start;
3698 debug_assert!(end_region.is_main_buffer);
3699 let region_buffer_start = end_region.buffer_range.start;
3700 if metadata_buffer_range.end > region_buffer_start {
3701 end_position.add_assign(&(metadata_buffer_range.end - region_buffer_start));
3702 }
3703 end_position = end_position.min(end_region.range.end);
3704 }
3705
3706 if start_position <= query_range.end && end_position >= query_range.start {
3707 return Some((start_position..end_position, metadata, excerpt));
3708 }
3709 }
3710 // When there are no more metadata items for this excerpt, move to the next excerpt.
3711 else {
3712 current_excerpt_metadata.take();
3713 cursor.next_excerpt();
3714 }
3715 })
3716 }
3717
3718 pub fn diff_hunk_before<T: ToOffset>(&self, position: T) -> Option<MultiBufferDiffHunk> {
3719 let offset = position.to_offset(self);
3720
3721 // Go to the region containing the given offset.
3722 let mut cursor = self.cursor::<DimensionPair<usize, Point>>();
3723 cursor.seek(&DimensionPair {
3724 key: offset,
3725 value: None,
3726 });
3727 let mut region = cursor.region()?;
3728 if region.range.start.key == offset || !region.is_main_buffer {
3729 cursor.prev();
3730 region = cursor.region()?;
3731 }
3732
3733 // Find the corresponding buffer offset.
3734 let overshoot = if region.is_main_buffer {
3735 offset - region.range.start.key
3736 } else {
3737 0
3738 };
3739 let mut max_buffer_offset = region
3740 .buffer
3741 .clip_offset(region.buffer_range.start.key + overshoot, Bias::Right);
3742
3743 loop {
3744 let excerpt = cursor.excerpt()?;
3745 let excerpt_end = excerpt.range.context.end.to_offset(&excerpt.buffer);
3746 let buffer_offset = excerpt_end.min(max_buffer_offset);
3747 let buffer_end = excerpt.buffer.anchor_before(buffer_offset);
3748 let buffer_end_row = buffer_end.to_point(&excerpt.buffer).row;
3749
3750 if let Some(diff) = self.diffs.get(&excerpt.buffer_id) {
3751 for hunk in diff.hunks_intersecting_range_rev(
3752 excerpt.range.context.start..buffer_end,
3753 &excerpt.buffer,
3754 ) {
3755 let hunk_range = hunk.buffer_range.to_offset(&excerpt.buffer);
3756 if hunk.row_range.end >= buffer_end_row {
3757 continue;
3758 }
3759
3760 let hunk_start = Point::new(hunk.row_range.start, 0);
3761 let hunk_end = Point::new(hunk.row_range.end, 0);
3762
3763 cursor.seek_to_buffer_position_in_current_excerpt(&DimensionPair {
3764 key: hunk_range.start,
3765 value: None,
3766 });
3767
3768 let mut region = cursor.region()?;
3769 while !region.is_main_buffer || region.buffer_range.start.key >= hunk_range.end
3770 {
3771 cursor.prev();
3772 region = cursor.region()?;
3773 }
3774
3775 let overshoot = if region.is_main_buffer {
3776 hunk_start.saturating_sub(region.buffer_range.start.value.unwrap())
3777 } else {
3778 Point::zero()
3779 };
3780 let start = region.range.start.value.unwrap() + overshoot;
3781
3782 while let Some(region) = cursor.region() {
3783 if !region.is_main_buffer
3784 || region.buffer_range.end.value.unwrap() <= hunk_end
3785 {
3786 cursor.next();
3787 } else {
3788 break;
3789 }
3790 }
3791
3792 let end = if let Some(region) = cursor.region() {
3793 let overshoot = if region.is_main_buffer {
3794 hunk_end.saturating_sub(region.buffer_range.start.value.unwrap())
3795 } else {
3796 Point::zero()
3797 };
3798 region.range.start.value.unwrap() + overshoot
3799 } else {
3800 self.max_point()
3801 };
3802
3803 return Some(MultiBufferDiffHunk {
3804 row_range: MultiBufferRow(start.row)..MultiBufferRow(end.row),
3805 buffer_id: excerpt.buffer_id,
3806 excerpt_id: excerpt.id,
3807 buffer_range: hunk.buffer_range.clone(),
3808 diff_base_byte_range: hunk.diff_base_byte_range.clone(),
3809 });
3810 }
3811 }
3812
3813 cursor.prev_excerpt();
3814 max_buffer_offset = usize::MAX;
3815 }
3816 }
3817
3818 pub fn has_diff_hunks(&self) -> bool {
3819 self.diffs.values().any(|diff| !diff.is_empty())
3820 }
3821
3822 pub fn surrounding_word<T: ToOffset>(
3823 &self,
3824 start: T,
3825 for_completion: bool,
3826 ) -> (Range<usize>, Option<CharKind>) {
3827 let mut start = start.to_offset(self);
3828 let mut end = start;
3829 let mut next_chars = self.chars_at(start).peekable();
3830 let mut prev_chars = self.reversed_chars_at(start).peekable();
3831
3832 let classifier = self
3833 .char_classifier_at(start)
3834 .for_completion(for_completion);
3835
3836 let word_kind = cmp::max(
3837 prev_chars.peek().copied().map(|c| classifier.kind(c)),
3838 next_chars.peek().copied().map(|c| classifier.kind(c)),
3839 );
3840
3841 for ch in prev_chars {
3842 if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
3843 start -= ch.len_utf8();
3844 } else {
3845 break;
3846 }
3847 }
3848
3849 for ch in next_chars {
3850 if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
3851 end += ch.len_utf8();
3852 } else {
3853 break;
3854 }
3855 }
3856
3857 (start..end, word_kind)
3858 }
3859
3860 pub fn is_singleton(&self) -> bool {
3861 self.singleton
3862 }
3863
3864 pub fn as_singleton(&self) -> Option<(&ExcerptId, BufferId, &BufferSnapshot)> {
3865 if self.singleton {
3866 self.excerpts
3867 .iter()
3868 .next()
3869 .map(|e| (&e.id, e.buffer_id, &e.buffer))
3870 } else {
3871 None
3872 }
3873 }
3874
3875 pub fn len(&self) -> usize {
3876 self.diff_transforms.summary().output.len
3877 }
3878
3879 pub fn is_empty(&self) -> bool {
3880 self.excerpts.summary().text.len == 0
3881 }
3882
3883 pub fn widest_line_number(&self) -> u32 {
3884 self.excerpts.summary().widest_line_number + 1
3885 }
3886
3887 pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> MultiBufferBytes {
3888 let range = range.start.to_offset(self)..range.end.to_offset(self);
3889 let mut excerpts = self.cursor::<usize>();
3890 excerpts.seek(&range.start);
3891
3892 let mut chunk;
3893 let mut has_trailing_newline;
3894 let excerpt_bytes;
3895 if let Some(region) = excerpts.region() {
3896 let mut bytes = region.buffer.bytes_in_range(
3897 region.buffer_range.start + range.start - region.range.start
3898 ..(region.buffer_range.start + range.end - region.range.start)
3899 .min(region.buffer_range.end),
3900 );
3901 chunk = bytes.next().unwrap_or(&[][..]);
3902 excerpt_bytes = Some(bytes);
3903 has_trailing_newline = region.has_trailing_newline && range.end >= region.range.end;
3904 if chunk.is_empty() && has_trailing_newline {
3905 chunk = b"\n";
3906 has_trailing_newline = false;
3907 }
3908 } else {
3909 chunk = &[][..];
3910 excerpt_bytes = None;
3911 has_trailing_newline = false;
3912 };
3913
3914 MultiBufferBytes {
3915 range,
3916 cursor: excerpts,
3917 excerpt_bytes,
3918 has_trailing_newline,
3919 chunk,
3920 }
3921 }
3922
3923 pub fn reversed_bytes_in_range<T: ToOffset>(
3924 &self,
3925 range: Range<T>,
3926 ) -> ReversedMultiBufferBytes {
3927 let range = range.start.to_offset(self)..range.end.to_offset(self);
3928 let mut chunks = self.reversed_chunks_in_range(range.clone());
3929 let chunk = chunks.next().map_or(&[][..], |c| c.as_bytes());
3930 ReversedMultiBufferBytes {
3931 range,
3932 chunks,
3933 chunk,
3934 }
3935 }
3936
3937 pub fn row_infos(&self, start_row: MultiBufferRow) -> MultiBufferRows {
3938 let mut cursor = self.cursor::<Point>();
3939 cursor.seek(&Point::new(start_row.0, 0));
3940 let mut result = MultiBufferRows {
3941 point: Point::new(0, 0),
3942 is_empty: self.excerpts.is_empty(),
3943 cursor,
3944 };
3945 result.seek(start_row);
3946 result
3947 }
3948
3949 pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> MultiBufferChunks {
3950 let mut chunks = MultiBufferChunks {
3951 excerpt_offset_range: ExcerptOffset::new(0)..ExcerptOffset::new(0),
3952 range: 0..0,
3953 excerpts: self.excerpts.cursor(&()),
3954 diff_transforms: self.diff_transforms.cursor(&()),
3955 diffs: &self.diffs,
3956 diff_base_chunks: None,
3957 excerpt_chunks: None,
3958 buffer_chunk: None,
3959 language_aware,
3960 };
3961 let range = range.start.to_offset(self)..range.end.to_offset(self);
3962 chunks.seek(range);
3963 chunks
3964 }
3965
3966 pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
3967 self.clip_dimension(offset, bias, text::BufferSnapshot::clip_offset)
3968 }
3969
3970 pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
3971 self.clip_dimension(point, bias, text::BufferSnapshot::clip_point)
3972 }
3973
3974 pub fn clip_offset_utf16(&self, offset: OffsetUtf16, bias: Bias) -> OffsetUtf16 {
3975 self.clip_dimension(offset, bias, text::BufferSnapshot::clip_offset_utf16)
3976 }
3977
3978 pub fn clip_point_utf16(&self, point: Unclipped<PointUtf16>, bias: Bias) -> PointUtf16 {
3979 self.clip_dimension(point.0, bias, |buffer, point, bias| {
3980 buffer.clip_point_utf16(Unclipped(point), bias)
3981 })
3982 }
3983
3984 pub fn offset_to_point(&self, offset: usize) -> Point {
3985 self.convert_dimension(offset, text::BufferSnapshot::offset_to_point)
3986 }
3987
3988 pub fn offset_to_point_utf16(&self, offset: usize) -> PointUtf16 {
3989 self.convert_dimension(offset, text::BufferSnapshot::offset_to_point_utf16)
3990 }
3991
3992 pub fn point_to_point_utf16(&self, point: Point) -> PointUtf16 {
3993 self.convert_dimension(point, text::BufferSnapshot::point_to_point_utf16)
3994 }
3995
3996 pub fn point_to_offset(&self, point: Point) -> usize {
3997 self.convert_dimension(point, text::BufferSnapshot::point_to_offset)
3998 }
3999
4000 pub fn offset_utf16_to_offset(&self, offset: OffsetUtf16) -> usize {
4001 self.convert_dimension(offset, text::BufferSnapshot::offset_utf16_to_offset)
4002 }
4003
4004 pub fn offset_to_offset_utf16(&self, offset: usize) -> OffsetUtf16 {
4005 self.convert_dimension(offset, text::BufferSnapshot::offset_to_offset_utf16)
4006 }
4007
4008 pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
4009 self.convert_dimension(point, text::BufferSnapshot::point_utf16_to_offset)
4010 }
4011
4012 fn clip_dimension<D>(
4013 &self,
4014 position: D,
4015 bias: Bias,
4016 clip_buffer_position: fn(&text::BufferSnapshot, D, Bias) -> D,
4017 ) -> D
4018 where
4019 D: TextDimension + Ord + Sub<D, Output = D>,
4020 {
4021 let mut cursor = self.cursor();
4022 cursor.seek(&position);
4023 if let Some(region) = cursor.region() {
4024 if position >= region.range.end {
4025 return region.range.end;
4026 }
4027 let overshoot = position - region.range.start;
4028 let mut buffer_position = region.buffer_range.start;
4029 buffer_position.add_assign(&overshoot);
4030 let clipped_buffer_position =
4031 clip_buffer_position(®ion.buffer, buffer_position, bias);
4032 let mut position = region.range.start;
4033 position.add_assign(&(clipped_buffer_position - region.buffer_range.start));
4034 position
4035 } else {
4036 D::from_text_summary(&self.text_summary())
4037 }
4038 }
4039
4040 fn convert_dimension<D1, D2>(
4041 &self,
4042 key: D1,
4043 convert_buffer_dimension: fn(&text::BufferSnapshot, D1) -> D2,
4044 ) -> D2
4045 where
4046 D1: TextDimension + Ord + Sub<D1, Output = D1>,
4047 D2: TextDimension + Ord + Sub<D2, Output = D2>,
4048 {
4049 let mut cursor = self.cursor::<DimensionPair<D1, D2>>();
4050 cursor.seek(&DimensionPair { key, value: None });
4051 if let Some(region) = cursor.region() {
4052 if key >= region.range.end.key {
4053 return region.range.end.value.unwrap();
4054 }
4055 let start_key = region.range.start.key;
4056 let start_value = region.range.start.value.unwrap();
4057 let buffer_start_key = region.buffer_range.start.key;
4058 let buffer_start_value = region.buffer_range.start.value.unwrap();
4059 let mut buffer_key = buffer_start_key;
4060 buffer_key.add_assign(&(key - start_key));
4061 let buffer_value = convert_buffer_dimension(®ion.buffer, buffer_key);
4062 let mut result = start_value;
4063 result.add_assign(&(buffer_value - buffer_start_value));
4064 result
4065 } else {
4066 D2::from_text_summary(&self.text_summary())
4067 }
4068 }
4069
4070 pub fn point_to_buffer_offset<T: ToOffset>(
4071 &self,
4072 point: T,
4073 ) -> Option<(&BufferSnapshot, usize)> {
4074 let offset = point.to_offset(self);
4075 let mut cursor = self.cursor::<usize>();
4076 cursor.seek(&offset);
4077 let region = cursor.region()?;
4078 let overshoot = offset - region.range.start;
4079 let buffer_offset = region.buffer_range.start + overshoot;
4080 Some((region.buffer, buffer_offset))
4081 }
4082
4083 pub fn point_to_buffer_point(&self, point: Point) -> Option<(&BufferSnapshot, Point, bool)> {
4084 let mut cursor = self.cursor::<Point>();
4085 cursor.seek(&point);
4086 let region = cursor.region()?;
4087 let overshoot = point - region.range.start;
4088 let buffer_offset = region.buffer_range.start + overshoot;
4089 Some((region.buffer, buffer_offset, region.is_main_buffer))
4090 }
4091
4092 pub fn suggested_indents(
4093 &self,
4094 rows: impl IntoIterator<Item = u32>,
4095 cx: &App,
4096 ) -> BTreeMap<MultiBufferRow, IndentSize> {
4097 let mut result = BTreeMap::new();
4098
4099 let mut rows_for_excerpt = Vec::new();
4100 let mut cursor = self.cursor::<Point>();
4101 let mut rows = rows.into_iter().peekable();
4102 let mut prev_row = u32::MAX;
4103 let mut prev_language_indent_size = IndentSize::default();
4104
4105 while let Some(row) = rows.next() {
4106 cursor.seek(&Point::new(row, 0));
4107 let Some(region) = cursor.region() else {
4108 continue;
4109 };
4110
4111 // Retrieve the language and indent size once for each disjoint region being indented.
4112 let single_indent_size = if row.saturating_sub(1) == prev_row {
4113 prev_language_indent_size
4114 } else {
4115 region
4116 .buffer
4117 .language_indent_size_at(Point::new(row, 0), cx)
4118 };
4119 prev_language_indent_size = single_indent_size;
4120 prev_row = row;
4121
4122 let start_buffer_row = region.buffer_range.start.row;
4123 let start_multibuffer_row = region.range.start.row;
4124 let end_multibuffer_row = region.range.end.row;
4125
4126 rows_for_excerpt.push(row);
4127 while let Some(next_row) = rows.peek().copied() {
4128 if end_multibuffer_row > next_row {
4129 rows_for_excerpt.push(next_row);
4130 rows.next();
4131 } else {
4132 break;
4133 }
4134 }
4135
4136 let buffer_rows = rows_for_excerpt
4137 .drain(..)
4138 .map(|row| start_buffer_row + row - start_multibuffer_row);
4139 let buffer_indents = region
4140 .buffer
4141 .suggested_indents(buffer_rows, single_indent_size);
4142 let multibuffer_indents = buffer_indents.into_iter().map(|(row, indent)| {
4143 (
4144 MultiBufferRow(start_multibuffer_row + row - start_buffer_row),
4145 indent,
4146 )
4147 });
4148 result.extend(multibuffer_indents);
4149 }
4150
4151 result
4152 }
4153
4154 pub fn indent_size_for_line(&self, row: MultiBufferRow) -> IndentSize {
4155 if let Some((buffer, range)) = self.buffer_line_for_row(row) {
4156 let mut size = buffer.indent_size_for_line(range.start.row);
4157 size.len = size
4158 .len
4159 .min(range.end.column)
4160 .saturating_sub(range.start.column);
4161 size
4162 } else {
4163 IndentSize::spaces(0)
4164 }
4165 }
4166
4167 pub fn line_indent_for_row(&self, row: MultiBufferRow) -> LineIndent {
4168 if let Some((buffer, range)) = self.buffer_line_for_row(row) {
4169 LineIndent::from_iter(buffer.text_for_range(range).flat_map(|s| s.chars()))
4170 } else {
4171 LineIndent::spaces(0)
4172 }
4173 }
4174
4175 pub fn indent_and_comment_for_line(&self, row: MultiBufferRow, cx: &App) -> String {
4176 let mut indent = self.indent_size_for_line(row).chars().collect::<String>();
4177
4178 if self.settings_at(0, cx).extend_comment_on_newline {
4179 if let Some(language_scope) = self.language_scope_at(Point::new(row.0, 0)) {
4180 let delimiters = language_scope.line_comment_prefixes();
4181 for delimiter in delimiters {
4182 if *self
4183 .chars_at(Point::new(row.0, indent.len() as u32))
4184 .take(delimiter.chars().count())
4185 .collect::<String>()
4186 .as_str()
4187 == **delimiter
4188 {
4189 indent.push_str(&delimiter);
4190 break;
4191 }
4192 }
4193 }
4194 }
4195
4196 indent
4197 }
4198
4199 pub fn prev_non_blank_row(&self, mut row: MultiBufferRow) -> Option<MultiBufferRow> {
4200 while row.0 > 0 {
4201 row.0 -= 1;
4202 if !self.is_line_blank(row) {
4203 return Some(row);
4204 }
4205 }
4206 None
4207 }
4208
4209 pub fn line_len(&self, row: MultiBufferRow) -> u32 {
4210 if let Some((_, range)) = self.buffer_line_for_row(row) {
4211 range.end.column - range.start.column
4212 } else {
4213 0
4214 }
4215 }
4216
4217 pub fn buffer_line_for_row(
4218 &self,
4219 row: MultiBufferRow,
4220 ) -> Option<(&BufferSnapshot, Range<Point>)> {
4221 let mut cursor = self.cursor::<Point>();
4222 let point = Point::new(row.0, 0);
4223 cursor.seek(&point);
4224 let region = cursor.region()?;
4225 let overshoot = point.min(region.range.end) - region.range.start;
4226 let buffer_point = region.buffer_range.start + overshoot;
4227 if buffer_point.row > region.buffer_range.end.row {
4228 return None;
4229 }
4230 let line_start = Point::new(buffer_point.row, 0).max(region.buffer_range.start);
4231 let line_end = Point::new(buffer_point.row, region.buffer.line_len(buffer_point.row))
4232 .min(region.buffer_range.end);
4233 Some((region.buffer, line_start..line_end))
4234 }
4235
4236 pub fn max_point(&self) -> Point {
4237 self.text_summary().lines
4238 }
4239
4240 pub fn max_row(&self) -> MultiBufferRow {
4241 MultiBufferRow(self.text_summary().lines.row)
4242 }
4243
4244 pub fn text_summary(&self) -> TextSummary {
4245 self.diff_transforms.summary().output
4246 }
4247
4248 pub fn text_summary_for_range<D, O>(&self, range: Range<O>) -> D
4249 where
4250 D: TextDimension,
4251 O: ToOffset,
4252 {
4253 let range = range.start.to_offset(self)..range.end.to_offset(self);
4254 let mut cursor = self.diff_transforms.cursor::<(usize, ExcerptOffset)>(&());
4255 cursor.seek(&range.start, Bias::Right, &());
4256
4257 let Some(first_transform) = cursor.item() else {
4258 return D::from_text_summary(&TextSummary::default());
4259 };
4260
4261 let diff_transform_start = cursor.start().0;
4262 let diff_transform_end = cursor.end(&()).0;
4263 let diff_start = range.start;
4264 let start_overshoot = diff_start - diff_transform_start;
4265 let end_overshoot = std::cmp::min(range.end, diff_transform_end) - diff_transform_start;
4266
4267 let mut result = match first_transform {
4268 DiffTransform::BufferContent { .. } => {
4269 let excerpt_start = cursor.start().1 + ExcerptOffset::new(start_overshoot);
4270 let excerpt_end = cursor.start().1 + ExcerptOffset::new(end_overshoot);
4271 self.text_summary_for_excerpt_offset_range(excerpt_start..excerpt_end)
4272 }
4273 DiffTransform::DeletedHunk {
4274 buffer_id,
4275 base_text_byte_range,
4276 has_trailing_newline,
4277 ..
4278 } => {
4279 let buffer_start = base_text_byte_range.start + start_overshoot;
4280 let mut buffer_end = base_text_byte_range.start + end_overshoot;
4281 let Some(base_text) = self
4282 .diffs
4283 .get(buffer_id)
4284 .and_then(|diff| diff.base_text.as_ref())
4285 else {
4286 panic!("{:?} is in non-existent deleted hunk", range.start)
4287 };
4288
4289 let include_trailing_newline =
4290 *has_trailing_newline && range.end >= diff_transform_end;
4291 if include_trailing_newline {
4292 buffer_end -= 1;
4293 }
4294
4295 let mut summary =
4296 base_text.text_summary_for_range::<D, _>(buffer_start..buffer_end);
4297
4298 if include_trailing_newline {
4299 summary.add_assign(&D::from_text_summary(&TextSummary::newline()))
4300 }
4301
4302 summary
4303 }
4304 };
4305 if range.end < diff_transform_end {
4306 return result;
4307 }
4308
4309 cursor.next(&());
4310 result.add_assign(&D::from_text_summary(&cursor.summary(
4311 &range.end,
4312 Bias::Right,
4313 &(),
4314 )));
4315
4316 let Some(last_transform) = cursor.item() else {
4317 return result;
4318 };
4319
4320 let overshoot = range.end - cursor.start().0;
4321 let suffix = match last_transform {
4322 DiffTransform::BufferContent { .. } => {
4323 let end = cursor.start().1 + ExcerptOffset::new(overshoot);
4324 self.text_summary_for_excerpt_offset_range::<D>(cursor.start().1..end)
4325 }
4326 DiffTransform::DeletedHunk {
4327 base_text_byte_range,
4328 buffer_id,
4329 has_trailing_newline,
4330 ..
4331 } => {
4332 let buffer_end = base_text_byte_range.start + overshoot;
4333 let Some(base_text) = self
4334 .diffs
4335 .get(buffer_id)
4336 .and_then(|diff| diff.base_text.as_ref())
4337 else {
4338 panic!("{:?} is in non-existent deleted hunk", range.end)
4339 };
4340
4341 let mut suffix = base_text
4342 .text_summary_for_range::<D, _>(base_text_byte_range.start..buffer_end);
4343 if *has_trailing_newline && buffer_end == base_text_byte_range.end + 1 {
4344 suffix.add_assign(&D::from_text_summary(&TextSummary::newline()))
4345 }
4346 suffix
4347 }
4348 };
4349
4350 result.add_assign(&suffix);
4351 result
4352 }
4353
4354 fn text_summary_for_excerpt_offset_range<D>(&self, mut range: Range<ExcerptOffset>) -> D
4355 where
4356 D: TextDimension,
4357 {
4358 // let mut range = range.start..range.end;
4359 let mut summary = D::zero(&());
4360 let mut cursor = self.excerpts.cursor::<ExcerptOffset>(&());
4361 cursor.seek(&range.start, Bias::Right, &());
4362 if let Some(excerpt) = cursor.item() {
4363 let mut end_before_newline = cursor.end(&());
4364 if excerpt.has_trailing_newline {
4365 end_before_newline -= ExcerptOffset::new(1);
4366 }
4367
4368 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
4369 let start_in_excerpt = excerpt_start + (range.start - *cursor.start()).value;
4370 let end_in_excerpt =
4371 excerpt_start + (cmp::min(end_before_newline, range.end) - *cursor.start()).value;
4372 summary.add_assign(
4373 &excerpt
4374 .buffer
4375 .text_summary_for_range(start_in_excerpt..end_in_excerpt),
4376 );
4377
4378 if range.end > end_before_newline {
4379 summary.add_assign(&D::from_text_summary(&TextSummary::from("\n")));
4380 }
4381
4382 cursor.next(&());
4383 }
4384
4385 if range.end > *cursor.start() {
4386 summary.add_assign(
4387 &cursor
4388 .summary::<_, ExcerptDimension<D>>(&range.end, Bias::Right, &())
4389 .0,
4390 );
4391 if let Some(excerpt) = cursor.item() {
4392 range.end = cmp::max(*cursor.start(), range.end);
4393
4394 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
4395 let end_in_excerpt = excerpt_start + (range.end - *cursor.start()).value;
4396 summary.add_assign(
4397 &excerpt
4398 .buffer
4399 .text_summary_for_range(excerpt_start..end_in_excerpt),
4400 );
4401 }
4402 }
4403
4404 summary
4405 }
4406
4407 pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
4408 where
4409 D: TextDimension + Ord + Sub<D, Output = D>,
4410 {
4411 self.summaries_for_anchors([anchor])[0]
4412 }
4413
4414 fn resolve_summary_for_anchor<D>(
4415 &self,
4416 anchor: &Anchor,
4417 excerpt_position: D,
4418 diff_transforms: &mut Cursor<DiffTransform, (ExcerptDimension<D>, OutputDimension<D>)>,
4419 ) -> D
4420 where
4421 D: TextDimension + Ord + Sub<D, Output = D>,
4422 {
4423 loop {
4424 let transform_end_position = diff_transforms.end(&()).0 .0;
4425 let at_transform_end =
4426 excerpt_position == transform_end_position && diff_transforms.item().is_some();
4427 if at_transform_end && anchor.text_anchor.bias == Bias::Right {
4428 diff_transforms.next(&());
4429 continue;
4430 }
4431
4432 let mut position = diff_transforms.start().1 .0;
4433 match diff_transforms.item() {
4434 Some(DiffTransform::DeletedHunk {
4435 buffer_id,
4436 base_text_byte_range,
4437 ..
4438 }) => {
4439 let mut in_deleted_hunk = false;
4440 if let Some(diff_base_anchor) = &anchor.diff_base_anchor {
4441 if let Some(base_text) = self
4442 .diffs
4443 .get(buffer_id)
4444 .and_then(|diff| diff.base_text.as_ref())
4445 {
4446 if base_text.can_resolve(&diff_base_anchor) {
4447 let base_text_offset = diff_base_anchor.to_offset(&base_text);
4448 if base_text_offset >= base_text_byte_range.start
4449 && base_text_offset <= base_text_byte_range.end
4450 {
4451 let position_in_hunk = base_text
4452 .text_summary_for_range::<D, _>(
4453 base_text_byte_range.start..base_text_offset,
4454 );
4455 position.add_assign(&position_in_hunk);
4456 in_deleted_hunk = true;
4457 } else if at_transform_end {
4458 diff_transforms.next(&());
4459 continue;
4460 }
4461 }
4462 }
4463 }
4464 if !in_deleted_hunk {
4465 position = diff_transforms.end(&()).1 .0;
4466 }
4467 }
4468 _ => {
4469 if at_transform_end && anchor.diff_base_anchor.is_some() {
4470 diff_transforms.next(&());
4471 continue;
4472 }
4473 let overshoot = excerpt_position - diff_transforms.start().0 .0;
4474 position.add_assign(&overshoot);
4475 }
4476 }
4477
4478 return position;
4479 }
4480 }
4481
4482 fn excerpt_offset_for_anchor(&self, anchor: &Anchor) -> ExcerptOffset {
4483 let mut cursor = self
4484 .excerpts
4485 .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
4486 let locator = self.excerpt_locator_for_id(anchor.excerpt_id);
4487
4488 cursor.seek(&Some(locator), Bias::Left, &());
4489 if cursor.item().is_none() {
4490 cursor.next(&());
4491 }
4492
4493 let mut position = cursor.start().1;
4494 if let Some(excerpt) = cursor.item() {
4495 if excerpt.id == anchor.excerpt_id {
4496 let excerpt_buffer_start = excerpt
4497 .buffer
4498 .offset_for_anchor(&excerpt.range.context.start);
4499 let excerpt_buffer_end =
4500 excerpt.buffer.offset_for_anchor(&excerpt.range.context.end);
4501 let buffer_position = cmp::min(
4502 excerpt_buffer_end,
4503 excerpt.buffer.offset_for_anchor(&anchor.text_anchor),
4504 );
4505 if buffer_position > excerpt_buffer_start {
4506 position.value += buffer_position - excerpt_buffer_start;
4507 }
4508 }
4509 }
4510 position
4511 }
4512
4513 pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
4514 where
4515 D: TextDimension + Ord + Sub<D, Output = D>,
4516 I: 'a + IntoIterator<Item = &'a Anchor>,
4517 {
4518 let mut anchors = anchors.into_iter().peekable();
4519 let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&());
4520 let mut diff_transforms_cursor = self
4521 .diff_transforms
4522 .cursor::<(ExcerptDimension<D>, OutputDimension<D>)>(&());
4523 diff_transforms_cursor.next(&());
4524
4525 let mut summaries = Vec::new();
4526 while let Some(anchor) = anchors.peek() {
4527 let excerpt_id = anchor.excerpt_id;
4528 let excerpt_anchors = iter::from_fn(|| {
4529 let anchor = anchors.peek()?;
4530 if anchor.excerpt_id == excerpt_id {
4531 Some(anchors.next().unwrap())
4532 } else {
4533 None
4534 }
4535 });
4536
4537 let locator = self.excerpt_locator_for_id(excerpt_id);
4538 cursor.seek_forward(locator, Bias::Left, &());
4539 if cursor.item().is_none() {
4540 cursor.next(&());
4541 }
4542
4543 let excerpt_start_position = D::from_text_summary(&cursor.start().text);
4544 if let Some(excerpt) = cursor.item() {
4545 if excerpt.id != excerpt_id {
4546 let position = self.resolve_summary_for_anchor(
4547 &Anchor::min(),
4548 excerpt_start_position,
4549 &mut diff_transforms_cursor,
4550 );
4551 summaries.extend(excerpt_anchors.map(|_| position));
4552 continue;
4553 }
4554 let excerpt_buffer_start =
4555 excerpt.range.context.start.summary::<D>(&excerpt.buffer);
4556 let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer);
4557 for (buffer_summary, anchor) in excerpt
4558 .buffer
4559 .summaries_for_anchors_with_payload::<D, _, _>(
4560 excerpt_anchors.map(|a| (&a.text_anchor, a)),
4561 )
4562 {
4563 let summary = cmp::min(excerpt_buffer_end, buffer_summary);
4564 let mut position = excerpt_start_position;
4565 if summary > excerpt_buffer_start {
4566 position.add_assign(&(summary - excerpt_buffer_start));
4567 }
4568
4569 if position > diff_transforms_cursor.start().0 .0 {
4570 diff_transforms_cursor.seek_forward(
4571 &ExcerptDimension(position),
4572 Bias::Left,
4573 &(),
4574 );
4575 }
4576
4577 summaries.push(self.resolve_summary_for_anchor(
4578 anchor,
4579 position,
4580 &mut diff_transforms_cursor,
4581 ));
4582 }
4583 } else {
4584 diff_transforms_cursor.seek_forward(
4585 &ExcerptDimension(excerpt_start_position),
4586 Bias::Left,
4587 &(),
4588 );
4589 let position = self.resolve_summary_for_anchor(
4590 &Anchor::max(),
4591 excerpt_start_position,
4592 &mut diff_transforms_cursor,
4593 );
4594 summaries.extend(excerpt_anchors.map(|_| position));
4595 }
4596 }
4597
4598 summaries
4599 }
4600
4601 pub fn dimensions_from_points<'a, D>(
4602 &'a self,
4603 points: impl 'a + IntoIterator<Item = Point>,
4604 ) -> impl 'a + Iterator<Item = D>
4605 where
4606 D: TextDimension + Sub<D, Output = D>,
4607 {
4608 let mut cursor = self.cursor::<DimensionPair<Point, D>>();
4609 cursor.seek(&DimensionPair {
4610 key: Point::default(),
4611 value: None,
4612 });
4613 let mut points = points.into_iter();
4614 iter::from_fn(move || {
4615 let point = points.next()?;
4616
4617 cursor.seek_forward(&DimensionPair {
4618 key: point,
4619 value: None,
4620 });
4621
4622 if let Some(region) = cursor.region() {
4623 let overshoot = point - region.range.start.key;
4624 let buffer_point = region.buffer_range.start.key + overshoot;
4625 let mut position = region.range.start.value.unwrap();
4626 position.add_assign(
4627 ®ion
4628 .buffer
4629 .text_summary_for_range(region.buffer_range.start.key..buffer_point),
4630 );
4631 return Some(position);
4632 } else {
4633 return Some(D::from_text_summary(&self.text_summary()));
4634 }
4635 })
4636 }
4637
4638 pub fn refresh_anchors<'a, I>(&'a self, anchors: I) -> Vec<(usize, Anchor, bool)>
4639 where
4640 I: 'a + IntoIterator<Item = &'a Anchor>,
4641 {
4642 let mut anchors = anchors.into_iter().enumerate().peekable();
4643 let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
4644 cursor.next(&());
4645
4646 let mut result = Vec::new();
4647
4648 while let Some((_, anchor)) = anchors.peek() {
4649 let old_excerpt_id = anchor.excerpt_id;
4650
4651 // Find the location where this anchor's excerpt should be.
4652 let old_locator = self.excerpt_locator_for_id(old_excerpt_id);
4653 cursor.seek_forward(&Some(old_locator), Bias::Left, &());
4654
4655 if cursor.item().is_none() {
4656 cursor.next(&());
4657 }
4658
4659 let next_excerpt = cursor.item();
4660 let prev_excerpt = cursor.prev_item();
4661
4662 // Process all of the anchors for this excerpt.
4663 while let Some((_, anchor)) = anchors.peek() {
4664 if anchor.excerpt_id != old_excerpt_id {
4665 break;
4666 }
4667 let (anchor_ix, anchor) = anchors.next().unwrap();
4668 let mut anchor = *anchor;
4669
4670 // Leave min and max anchors unchanged if invalid or
4671 // if the old excerpt still exists at this location
4672 let mut kept_position = next_excerpt
4673 .map_or(false, |e| e.id == old_excerpt_id && e.contains(&anchor))
4674 || old_excerpt_id == ExcerptId::max()
4675 || old_excerpt_id == ExcerptId::min();
4676
4677 // If the old excerpt no longer exists at this location, then attempt to
4678 // find an equivalent position for this anchor in an adjacent excerpt.
4679 if !kept_position {
4680 for excerpt in [next_excerpt, prev_excerpt].iter().filter_map(|e| *e) {
4681 if excerpt.contains(&anchor) {
4682 anchor.excerpt_id = excerpt.id;
4683 kept_position = true;
4684 break;
4685 }
4686 }
4687 }
4688
4689 // If there's no adjacent excerpt that contains the anchor's position,
4690 // then report that the anchor has lost its position.
4691 if !kept_position {
4692 anchor = if let Some(excerpt) = next_excerpt {
4693 let mut text_anchor = excerpt
4694 .range
4695 .context
4696 .start
4697 .bias(anchor.text_anchor.bias, &excerpt.buffer);
4698 if text_anchor
4699 .cmp(&excerpt.range.context.end, &excerpt.buffer)
4700 .is_gt()
4701 {
4702 text_anchor = excerpt.range.context.end;
4703 }
4704 Anchor {
4705 buffer_id: Some(excerpt.buffer_id),
4706 excerpt_id: excerpt.id,
4707 text_anchor,
4708 diff_base_anchor: None,
4709 }
4710 } else if let Some(excerpt) = prev_excerpt {
4711 let mut text_anchor = excerpt
4712 .range
4713 .context
4714 .end
4715 .bias(anchor.text_anchor.bias, &excerpt.buffer);
4716 if text_anchor
4717 .cmp(&excerpt.range.context.start, &excerpt.buffer)
4718 .is_lt()
4719 {
4720 text_anchor = excerpt.range.context.start;
4721 }
4722 Anchor {
4723 buffer_id: Some(excerpt.buffer_id),
4724 excerpt_id: excerpt.id,
4725 text_anchor,
4726 diff_base_anchor: None,
4727 }
4728 } else if anchor.text_anchor.bias == Bias::Left {
4729 Anchor::min()
4730 } else {
4731 Anchor::max()
4732 };
4733 }
4734
4735 result.push((anchor_ix, anchor, kept_position));
4736 }
4737 }
4738 result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self));
4739 result
4740 }
4741
4742 pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
4743 self.anchor_at(position, Bias::Left)
4744 }
4745
4746 pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
4747 self.anchor_at(position, Bias::Right)
4748 }
4749
4750 pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
4751 let offset = position.to_offset(self);
4752
4753 // Find the given position in the diff transforms. Determine the corresponding
4754 // offset in the excerpts, and whether the position is within a deleted hunk.
4755 let mut diff_transforms = self.diff_transforms.cursor::<(usize, ExcerptOffset)>(&());
4756 diff_transforms.seek(&offset, Bias::Right, &());
4757
4758 if offset == diff_transforms.start().0 && bias == Bias::Left {
4759 if let Some(prev_item) = diff_transforms.prev_item() {
4760 match prev_item {
4761 DiffTransform::DeletedHunk { .. } => {
4762 diff_transforms.prev(&());
4763 }
4764 _ => {}
4765 }
4766 }
4767 }
4768 let offset_in_transform = offset - diff_transforms.start().0;
4769 let mut excerpt_offset = diff_transforms.start().1;
4770 let mut diff_base_anchor = None;
4771 if let Some(DiffTransform::DeletedHunk {
4772 buffer_id,
4773 base_text_byte_range,
4774 has_trailing_newline,
4775 ..
4776 }) = diff_transforms.item()
4777 {
4778 let base_text = self
4779 .diffs
4780 .get(buffer_id)
4781 .and_then(|diff| diff.base_text.as_ref())
4782 .expect("missing diff base");
4783 if offset_in_transform > base_text_byte_range.len() {
4784 debug_assert!(*has_trailing_newline);
4785 bias = Bias::Right;
4786 } else {
4787 diff_base_anchor = Some(
4788 base_text.anchor_at(base_text_byte_range.start + offset_in_transform, bias),
4789 );
4790 bias = Bias::Left;
4791 }
4792 } else {
4793 excerpt_offset += ExcerptOffset::new(offset_in_transform);
4794 };
4795
4796 if let Some((excerpt_id, buffer_id, buffer)) = self.as_singleton() {
4797 return Anchor {
4798 buffer_id: Some(buffer_id),
4799 excerpt_id: *excerpt_id,
4800 text_anchor: buffer.anchor_at(excerpt_offset.value, bias),
4801 diff_base_anchor,
4802 };
4803 }
4804
4805 let mut excerpts = self
4806 .excerpts
4807 .cursor::<(ExcerptOffset, Option<ExcerptId>)>(&());
4808 excerpts.seek(&excerpt_offset, Bias::Right, &());
4809 if excerpts.item().is_none() && excerpt_offset == excerpts.start().0 && bias == Bias::Left {
4810 excerpts.prev(&());
4811 }
4812 if let Some(excerpt) = excerpts.item() {
4813 let mut overshoot = excerpt_offset.saturating_sub(excerpts.start().0).value;
4814 if excerpt.has_trailing_newline && excerpt_offset == excerpts.end(&()).0 {
4815 overshoot -= 1;
4816 bias = Bias::Right;
4817 }
4818
4819 let buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
4820 let text_anchor =
4821 excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
4822 Anchor {
4823 buffer_id: Some(excerpt.buffer_id),
4824 excerpt_id: excerpt.id,
4825 text_anchor,
4826 diff_base_anchor,
4827 }
4828 } else if excerpt_offset.is_zero() && bias == Bias::Left {
4829 Anchor::min()
4830 } else {
4831 Anchor::max()
4832 }
4833 }
4834
4835 /// Returns an anchor for the given excerpt and text anchor,
4836 /// returns None if the excerpt_id is no longer valid.
4837 pub fn anchor_in_excerpt(
4838 &self,
4839 excerpt_id: ExcerptId,
4840 text_anchor: text::Anchor,
4841 ) -> Option<Anchor> {
4842 let locator = self.excerpt_locator_for_id(excerpt_id);
4843 let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
4844 cursor.seek(locator, Bias::Left, &());
4845 if let Some(excerpt) = cursor.item() {
4846 if excerpt.id == excerpt_id {
4847 let text_anchor = excerpt.clip_anchor(text_anchor);
4848 drop(cursor);
4849 return Some(Anchor {
4850 buffer_id: Some(excerpt.buffer_id),
4851 excerpt_id,
4852 text_anchor,
4853 diff_base_anchor: None,
4854 });
4855 }
4856 }
4857 None
4858 }
4859
4860 pub fn context_range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<Range<text::Anchor>> {
4861 Some(self.excerpt(excerpt_id)?.range.context.clone())
4862 }
4863
4864 pub fn can_resolve(&self, anchor: &Anchor) -> bool {
4865 if anchor.excerpt_id == ExcerptId::min() || anchor.excerpt_id == ExcerptId::max() {
4866 true
4867 } else if let Some(excerpt) = self.excerpt(anchor.excerpt_id) {
4868 excerpt.buffer.can_resolve(&anchor.text_anchor)
4869 } else {
4870 false
4871 }
4872 }
4873
4874 pub fn excerpts(
4875 &self,
4876 ) -> impl Iterator<Item = (ExcerptId, &BufferSnapshot, ExcerptRange<text::Anchor>)> {
4877 self.excerpts
4878 .iter()
4879 .map(|excerpt| (excerpt.id, &excerpt.buffer, excerpt.range.clone()))
4880 }
4881
4882 fn cursor<D: TextDimension + Default>(&self) -> MultiBufferCursor<D> {
4883 let excerpts = self.excerpts.cursor(&());
4884 let diff_transforms = self.diff_transforms.cursor(&());
4885 MultiBufferCursor {
4886 excerpts,
4887 diff_transforms,
4888 diffs: &self.diffs,
4889 cached_region: None,
4890 }
4891 }
4892
4893 pub fn excerpt_before(&self, id: ExcerptId) -> Option<MultiBufferExcerpt<'_>> {
4894 let start_locator = self.excerpt_locator_for_id(id);
4895 let mut excerpts = self
4896 .excerpts
4897 .cursor::<(Option<&Locator>, ExcerptDimension<usize>)>(&());
4898 excerpts.seek(&Some(start_locator), Bias::Left, &());
4899 excerpts.prev(&());
4900
4901 let mut diff_transforms = self
4902 .diff_transforms
4903 .cursor::<(OutputDimension<usize>, ExcerptDimension<usize>)>(&());
4904 diff_transforms.seek(&excerpts.start().1, Bias::Left, &());
4905 if diff_transforms.end(&()).1 < excerpts.start().1 {
4906 diff_transforms.next(&());
4907 }
4908
4909 let excerpt = excerpts.item()?;
4910 Some(MultiBufferExcerpt {
4911 excerpt,
4912 offset: diff_transforms.start().0 .0,
4913 buffer_offset: excerpt.range.context.start.to_offset(&excerpt.buffer),
4914 excerpt_offset: excerpts.start().1.clone(),
4915 diff_transforms,
4916 })
4917 }
4918
4919 pub fn excerpt_boundaries_in_range<R, T>(
4920 &self,
4921 range: R,
4922 ) -> impl Iterator<Item = ExcerptBoundary> + '_
4923 where
4924 R: RangeBounds<T>,
4925 T: ToOffset,
4926 {
4927 let start_offset;
4928 let start = match range.start_bound() {
4929 Bound::Included(start) => {
4930 start_offset = start.to_offset(self);
4931 Bound::Included(start_offset)
4932 }
4933 Bound::Excluded(_) => {
4934 panic!("not supported")
4935 }
4936 Bound::Unbounded => {
4937 start_offset = 0;
4938 Bound::Unbounded
4939 }
4940 };
4941 let end = match range.end_bound() {
4942 Bound::Included(end) => Bound::Included(end.to_offset(self)),
4943 Bound::Excluded(end) => Bound::Excluded(end.to_offset(self)),
4944 Bound::Unbounded => Bound::Unbounded,
4945 };
4946 let bounds = (start, end);
4947
4948 let mut cursor = self.cursor::<DimensionPair<usize, Point>>();
4949 cursor.seek(&DimensionPair {
4950 key: start_offset,
4951 value: None,
4952 });
4953
4954 if cursor
4955 .region()
4956 .is_some_and(|region| bounds.contains(®ion.range.start.key))
4957 {
4958 cursor.prev_excerpt();
4959 } else {
4960 cursor.seek_to_start_of_current_excerpt();
4961 }
4962 let mut prev_region = cursor.region();
4963
4964 cursor.next_excerpt();
4965
4966 let mut visited_end = false;
4967 iter::from_fn(move || loop {
4968 if self.singleton {
4969 return None;
4970 }
4971
4972 let next_region = cursor.region();
4973 cursor.next_excerpt();
4974
4975 let next_region_start = if let Some(region) = &next_region {
4976 if !bounds.contains(®ion.range.start.key) {
4977 prev_region = next_region;
4978 continue;
4979 }
4980 region.range.start.value.unwrap()
4981 } else {
4982 if !bounds.contains(&self.len()) {
4983 return None;
4984 }
4985 self.max_point()
4986 };
4987 let next_region_end = if let Some(region) = cursor.region() {
4988 region.range.start.value.unwrap()
4989 } else {
4990 self.max_point()
4991 };
4992
4993 let prev = prev_region.as_ref().map(|region| ExcerptInfo {
4994 id: region.excerpt.id,
4995 buffer: region.excerpt.buffer.clone(),
4996 buffer_id: region.excerpt.buffer_id,
4997 range: region.excerpt.range.clone(),
4998 end_row: MultiBufferRow(next_region_start.row),
4999 });
5000
5001 let next = next_region.as_ref().map(|region| ExcerptInfo {
5002 id: region.excerpt.id,
5003 buffer: region.excerpt.buffer.clone(),
5004 buffer_id: region.excerpt.buffer_id,
5005 range: region.excerpt.range.clone(),
5006 end_row: if region.excerpt.has_trailing_newline {
5007 MultiBufferRow(next_region_end.row - 1)
5008 } else {
5009 MultiBufferRow(next_region_end.row)
5010 },
5011 });
5012
5013 if next.is_none() {
5014 if visited_end {
5015 return None;
5016 } else {
5017 visited_end = true;
5018 }
5019 }
5020
5021 let row = MultiBufferRow(next_region_start.row);
5022
5023 prev_region = next_region;
5024
5025 return Some(ExcerptBoundary { row, prev, next });
5026 })
5027 }
5028
5029 pub fn edit_count(&self) -> usize {
5030 self.edit_count
5031 }
5032
5033 pub fn non_text_state_update_count(&self) -> usize {
5034 self.non_text_state_update_count
5035 }
5036
5037 /// Returns the smallest enclosing bracket ranges containing the given range or
5038 /// None if no brackets contain range or the range is not contained in a single
5039 /// excerpt
5040 ///
5041 /// Can optionally pass a range_filter to filter the ranges of brackets to consider
5042 pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
5043 &self,
5044 range: Range<T>,
5045 range_filter: Option<&dyn Fn(&BufferSnapshot, Range<usize>, Range<usize>) -> bool>,
5046 ) -> Option<(Range<usize>, Range<usize>)> {
5047 let range = range.start.to_offset(self)..range.end.to_offset(self);
5048 let mut excerpt = self.excerpt_containing(range.clone())?;
5049 let buffer = excerpt.buffer();
5050 let excerpt_buffer_range = excerpt.buffer_range();
5051
5052 // Filter to ranges contained in the excerpt
5053 let range_filter = |open: Range<usize>, close: Range<usize>| -> bool {
5054 excerpt_buffer_range.contains(&open.start)
5055 && excerpt_buffer_range.contains(&close.end)
5056 && range_filter.map_or(true, |filter| filter(buffer, open, close))
5057 };
5058
5059 let (open, close) = excerpt.buffer().innermost_enclosing_bracket_ranges(
5060 excerpt.map_range_to_buffer(range),
5061 Some(&range_filter),
5062 )?;
5063
5064 Some((
5065 excerpt.map_range_from_buffer(open),
5066 excerpt.map_range_from_buffer(close),
5067 ))
5068 }
5069
5070 /// Returns enclosing bracket ranges containing the given range or returns None if the range is
5071 /// not contained in a single excerpt
5072 pub fn enclosing_bracket_ranges<T: ToOffset>(
5073 &self,
5074 range: Range<T>,
5075 ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + '_> {
5076 let range = range.start.to_offset(self)..range.end.to_offset(self);
5077 let mut excerpt = self.excerpt_containing(range.clone())?;
5078
5079 Some(
5080 excerpt
5081 .buffer()
5082 .enclosing_bracket_ranges(excerpt.map_range_to_buffer(range))
5083 .filter_map(move |(open, close)| {
5084 if excerpt.contains_buffer_range(open.start..close.end) {
5085 Some((
5086 excerpt.map_range_from_buffer(open),
5087 excerpt.map_range_from_buffer(close),
5088 ))
5089 } else {
5090 None
5091 }
5092 }),
5093 )
5094 }
5095
5096 /// Returns enclosing bracket ranges containing the given range or returns None if the range is
5097 /// not contained in a single excerpt
5098 pub fn text_object_ranges<T: ToOffset>(
5099 &self,
5100 range: Range<T>,
5101 options: TreeSitterOptions,
5102 ) -> impl Iterator<Item = (Range<usize>, TextObject)> + '_ {
5103 let range = range.start.to_offset(self)..range.end.to_offset(self);
5104 self.excerpt_containing(range.clone())
5105 .map(|mut excerpt| {
5106 excerpt
5107 .buffer()
5108 .text_object_ranges(excerpt.map_range_to_buffer(range), options)
5109 .filter_map(move |(range, text_object)| {
5110 if excerpt.contains_buffer_range(range.clone()) {
5111 Some((excerpt.map_range_from_buffer(range), text_object))
5112 } else {
5113 None
5114 }
5115 })
5116 })
5117 .into_iter()
5118 .flatten()
5119 }
5120
5121 /// Returns bracket range pairs overlapping the given `range` or returns None if the `range` is
5122 /// not contained in a single excerpt
5123 pub fn bracket_ranges<T: ToOffset>(
5124 &self,
5125 range: Range<T>,
5126 ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + '_> {
5127 let range = range.start.to_offset(self)..range.end.to_offset(self);
5128 let mut excerpt = self.excerpt_containing(range.clone())?;
5129
5130 Some(
5131 excerpt
5132 .buffer()
5133 .bracket_ranges(excerpt.map_range_to_buffer(range))
5134 .filter_map(move |(start_bracket_range, close_bracket_range)| {
5135 let buffer_range = start_bracket_range.start..close_bracket_range.end;
5136 if excerpt.contains_buffer_range(buffer_range) {
5137 Some((
5138 excerpt.map_range_from_buffer(start_bracket_range),
5139 excerpt.map_range_from_buffer(close_bracket_range),
5140 ))
5141 } else {
5142 None
5143 }
5144 }),
5145 )
5146 }
5147
5148 pub fn redacted_ranges<'a, T: ToOffset>(
5149 &'a self,
5150 range: Range<T>,
5151 redaction_enabled: impl Fn(Option<&Arc<dyn File>>) -> bool + 'a,
5152 ) -> impl Iterator<Item = Range<usize>> + 'a {
5153 let range = range.start.to_offset(self)..range.end.to_offset(self);
5154 self.lift_buffer_metadata(range, move |buffer, range| {
5155 if redaction_enabled(buffer.file()) {
5156 Some(buffer.redacted_ranges(range).map(|range| (range, ())))
5157 } else {
5158 None
5159 }
5160 })
5161 .map(|(range, _, _)| range)
5162 }
5163
5164 pub fn runnable_ranges(
5165 &self,
5166 range: Range<Anchor>,
5167 ) -> impl Iterator<Item = language::RunnableRange> + '_ {
5168 let range = range.start.to_offset(self)..range.end.to_offset(self);
5169 self.lift_buffer_metadata(range, move |buffer, range| {
5170 Some(
5171 buffer
5172 .runnable_ranges(range.clone())
5173 .filter(move |runnable| {
5174 runnable.run_range.start >= range.start
5175 && runnable.run_range.end < range.end
5176 })
5177 .map(|runnable| (runnable.run_range.clone(), runnable)),
5178 )
5179 })
5180 .map(|(run_range, runnable, _)| language::RunnableRange {
5181 run_range,
5182 ..runnable
5183 })
5184 }
5185
5186 pub fn line_indents(
5187 &self,
5188 start_row: MultiBufferRow,
5189 buffer_filter: impl Fn(&BufferSnapshot) -> bool,
5190 ) -> impl Iterator<Item = (MultiBufferRow, LineIndent, &BufferSnapshot)> {
5191 let max_point = self.max_point();
5192 let mut cursor = self.cursor::<Point>();
5193 cursor.seek(&Point::new(start_row.0, 0));
5194 iter::from_fn(move || {
5195 let mut region = cursor.region()?;
5196 while !buffer_filter(®ion.excerpt.buffer) {
5197 cursor.next();
5198 region = cursor.region()?;
5199 }
5200 let overshoot = start_row.0.saturating_sub(region.range.start.row);
5201 let buffer_start_row =
5202 (region.buffer_range.start.row + overshoot).min(region.buffer_range.end.row);
5203
5204 let buffer_end_row = if region.is_main_buffer
5205 && (region.has_trailing_newline || region.range.end == max_point)
5206 {
5207 region.buffer_range.end.row
5208 } else {
5209 region.buffer_range.end.row.saturating_sub(1)
5210 };
5211
5212 let line_indents = region
5213 .buffer
5214 .line_indents_in_row_range(buffer_start_row..buffer_end_row);
5215 cursor.next();
5216 return Some(line_indents.map(move |(buffer_row, indent)| {
5217 let row = region.range.start.row + (buffer_row - region.buffer_range.start.row);
5218 (MultiBufferRow(row), indent, ®ion.excerpt.buffer)
5219 }));
5220 })
5221 .flatten()
5222 }
5223
5224 pub fn reversed_line_indents(
5225 &self,
5226 end_row: MultiBufferRow,
5227 buffer_filter: impl Fn(&BufferSnapshot) -> bool,
5228 ) -> impl Iterator<Item = (MultiBufferRow, LineIndent, &BufferSnapshot)> {
5229 let max_point = self.max_point();
5230 let mut cursor = self.cursor::<Point>();
5231 cursor.seek(&Point::new(end_row.0, 0));
5232 iter::from_fn(move || {
5233 let mut region = cursor.region()?;
5234 while !buffer_filter(®ion.excerpt.buffer) {
5235 cursor.prev();
5236 region = cursor.region()?;
5237 }
5238
5239 let buffer_start_row = region.buffer_range.start.row;
5240 let buffer_end_row = if region.is_main_buffer
5241 && (region.has_trailing_newline || region.range.end == max_point)
5242 {
5243 region.buffer_range.end.row + 1
5244 } else {
5245 region.buffer_range.end.row
5246 };
5247
5248 let overshoot = end_row.0 - region.range.start.row;
5249 let buffer_end_row =
5250 (region.buffer_range.start.row + overshoot + 1).min(buffer_end_row);
5251
5252 let line_indents = region
5253 .buffer
5254 .reversed_line_indents_in_row_range(buffer_start_row..buffer_end_row);
5255 cursor.prev();
5256 return Some(line_indents.map(move |(buffer_row, indent)| {
5257 let row = region.range.start.row + (buffer_row - region.buffer_range.start.row);
5258 (MultiBufferRow(row), indent, ®ion.excerpt.buffer)
5259 }));
5260 })
5261 .flatten()
5262 }
5263
5264 pub async fn enclosing_indent(
5265 &self,
5266 mut target_row: MultiBufferRow,
5267 ) -> Option<(Range<MultiBufferRow>, LineIndent)> {
5268 let max_row = MultiBufferRow(self.max_point().row);
5269 if target_row >= max_row {
5270 return None;
5271 }
5272
5273 let mut target_indent = self.line_indent_for_row(target_row);
5274
5275 // If the current row is at the start of an indented block, we want to return this
5276 // block as the enclosing indent.
5277 if !target_indent.is_line_empty() && target_row < max_row {
5278 let next_line_indent = self.line_indent_for_row(MultiBufferRow(target_row.0 + 1));
5279 if !next_line_indent.is_line_empty()
5280 && target_indent.raw_len() < next_line_indent.raw_len()
5281 {
5282 target_indent = next_line_indent;
5283 target_row.0 += 1;
5284 }
5285 }
5286
5287 const SEARCH_ROW_LIMIT: u32 = 25000;
5288 const SEARCH_WHITESPACE_ROW_LIMIT: u32 = 2500;
5289 const YIELD_INTERVAL: u32 = 100;
5290
5291 let mut accessed_row_counter = 0;
5292
5293 // If there is a blank line at the current row, search for the next non indented lines
5294 if target_indent.is_line_empty() {
5295 let start = MultiBufferRow(target_row.0.saturating_sub(SEARCH_WHITESPACE_ROW_LIMIT));
5296 let end =
5297 MultiBufferRow((max_row.0 + 1).min(target_row.0 + SEARCH_WHITESPACE_ROW_LIMIT));
5298
5299 let mut non_empty_line_above = None;
5300 for (row, indent, _) in self.reversed_line_indents(target_row, |_| true) {
5301 if row < start {
5302 break;
5303 }
5304 accessed_row_counter += 1;
5305 if accessed_row_counter == YIELD_INTERVAL {
5306 accessed_row_counter = 0;
5307 yield_now().await;
5308 }
5309 if !indent.is_line_empty() {
5310 non_empty_line_above = Some((row, indent));
5311 break;
5312 }
5313 }
5314
5315 let mut non_empty_line_below = None;
5316 for (row, indent, _) in self.line_indents(target_row, |_| true) {
5317 if row > end {
5318 break;
5319 }
5320 accessed_row_counter += 1;
5321 if accessed_row_counter == YIELD_INTERVAL {
5322 accessed_row_counter = 0;
5323 yield_now().await;
5324 }
5325 if !indent.is_line_empty() {
5326 non_empty_line_below = Some((row, indent));
5327 break;
5328 }
5329 }
5330
5331 let (row, indent) = match (non_empty_line_above, non_empty_line_below) {
5332 (Some((above_row, above_indent)), Some((below_row, below_indent))) => {
5333 if above_indent.raw_len() >= below_indent.raw_len() {
5334 (above_row, above_indent)
5335 } else {
5336 (below_row, below_indent)
5337 }
5338 }
5339 (Some(above), None) => above,
5340 (None, Some(below)) => below,
5341 _ => return None,
5342 };
5343
5344 target_indent = indent;
5345 target_row = row;
5346 }
5347
5348 let start = MultiBufferRow(target_row.0.saturating_sub(SEARCH_ROW_LIMIT));
5349 let end = MultiBufferRow((max_row.0 + 1).min(target_row.0 + SEARCH_ROW_LIMIT));
5350
5351 let mut start_indent = None;
5352 for (row, indent, _) in self.reversed_line_indents(target_row, |_| true) {
5353 if row < start {
5354 break;
5355 }
5356 accessed_row_counter += 1;
5357 if accessed_row_counter == YIELD_INTERVAL {
5358 accessed_row_counter = 0;
5359 yield_now().await;
5360 }
5361 if !indent.is_line_empty() && indent.raw_len() < target_indent.raw_len() {
5362 start_indent = Some((row, indent));
5363 break;
5364 }
5365 }
5366 let (start_row, start_indent_size) = start_indent?;
5367
5368 let mut end_indent = (end, None);
5369 for (row, indent, _) in self.line_indents(target_row, |_| true) {
5370 if row > end {
5371 break;
5372 }
5373 accessed_row_counter += 1;
5374 if accessed_row_counter == YIELD_INTERVAL {
5375 accessed_row_counter = 0;
5376 yield_now().await;
5377 }
5378 if !indent.is_line_empty() && indent.raw_len() < target_indent.raw_len() {
5379 end_indent = (MultiBufferRow(row.0.saturating_sub(1)), Some(indent));
5380 break;
5381 }
5382 }
5383 let (end_row, end_indent_size) = end_indent;
5384
5385 let indent = if let Some(end_indent_size) = end_indent_size {
5386 if start_indent_size.raw_len() > end_indent_size.raw_len() {
5387 start_indent_size
5388 } else {
5389 end_indent_size
5390 }
5391 } else {
5392 start_indent_size
5393 };
5394
5395 Some((start_row..end_row, indent))
5396 }
5397
5398 pub fn indent_guides_in_range<T: ToPoint>(
5399 &self,
5400 range: Range<T>,
5401 ignore_disabled_for_language: bool,
5402 cx: &App,
5403 ) -> impl Iterator<Item = IndentGuide> {
5404 let range = range.start.to_point(self)..range.end.to_point(self);
5405 let start_row = MultiBufferRow(range.start.row);
5406 let end_row = MultiBufferRow(range.end.row);
5407
5408 let mut row_indents = self.line_indents(start_row, |buffer| {
5409 let settings =
5410 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx);
5411 settings.indent_guides.enabled || ignore_disabled_for_language
5412 });
5413
5414 let mut result = Vec::new();
5415 let mut indent_stack = SmallVec::<[IndentGuide; 8]>::new();
5416
5417 while let Some((first_row, mut line_indent, buffer)) = row_indents.next() {
5418 if first_row > end_row {
5419 break;
5420 }
5421 let current_depth = indent_stack.len() as u32;
5422
5423 let settings =
5424 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx);
5425 let tab_size = settings.tab_size.get() as u32;
5426
5427 // When encountering empty, continue until found useful line indent
5428 // then add to the indent stack with the depth found
5429 let mut found_indent = false;
5430 let mut last_row = first_row;
5431 if line_indent.is_line_empty() {
5432 while !found_indent {
5433 let Some((target_row, new_line_indent, _)) = row_indents.next() else {
5434 break;
5435 };
5436 const TRAILING_ROW_SEARCH_LIMIT: u32 = 25;
5437 if target_row > MultiBufferRow(end_row.0 + TRAILING_ROW_SEARCH_LIMIT) {
5438 break;
5439 }
5440
5441 if new_line_indent.is_line_empty() {
5442 continue;
5443 }
5444 last_row = target_row.min(end_row);
5445 line_indent = new_line_indent;
5446 found_indent = true;
5447 break;
5448 }
5449 } else {
5450 found_indent = true
5451 }
5452
5453 let depth = if found_indent {
5454 line_indent.len(tab_size) / tab_size
5455 + ((line_indent.len(tab_size) % tab_size) > 0) as u32
5456 } else {
5457 current_depth
5458 };
5459
5460 match depth.cmp(¤t_depth) {
5461 cmp::Ordering::Less => {
5462 for _ in 0..(current_depth - depth) {
5463 let mut indent = indent_stack.pop().unwrap();
5464 if last_row != first_row {
5465 // In this case, we landed on an empty row, had to seek forward,
5466 // and discovered that the indent we where on is ending.
5467 // This means that the last display row must
5468 // be on line that ends this indent range, so we
5469 // should display the range up to the first non-empty line
5470 indent.end_row = MultiBufferRow(first_row.0.saturating_sub(1));
5471 }
5472
5473 result.push(indent)
5474 }
5475 }
5476 cmp::Ordering::Greater => {
5477 for next_depth in current_depth..depth {
5478 indent_stack.push(IndentGuide {
5479 buffer_id: buffer.remote_id(),
5480 start_row: first_row,
5481 end_row: last_row,
5482 depth: next_depth,
5483 tab_size,
5484 settings: settings.indent_guides,
5485 });
5486 }
5487 }
5488 _ => {}
5489 }
5490
5491 for indent in indent_stack.iter_mut() {
5492 indent.end_row = last_row;
5493 }
5494 }
5495
5496 result.extend(indent_stack);
5497 result.into_iter()
5498 }
5499
5500 pub fn trailing_excerpt_update_count(&self) -> usize {
5501 self.trailing_excerpt_update_count
5502 }
5503
5504 pub fn file_at<T: ToOffset>(&self, point: T) -> Option<&Arc<dyn File>> {
5505 self.point_to_buffer_offset(point)
5506 .and_then(|(buffer, _)| buffer.file())
5507 }
5508
5509 pub fn language_at<T: ToOffset>(&self, point: T) -> Option<&Arc<Language>> {
5510 self.point_to_buffer_offset(point)
5511 .and_then(|(buffer, offset)| buffer.language_at(offset))
5512 }
5513
5514 pub fn settings_at<'a, T: ToOffset>(
5515 &'a self,
5516 point: T,
5517 cx: &'a App,
5518 ) -> Cow<'a, LanguageSettings> {
5519 let mut language = None;
5520 let mut file = None;
5521 if let Some((buffer, offset)) = self.point_to_buffer_offset(point) {
5522 language = buffer.language_at(offset);
5523 file = buffer.file();
5524 }
5525 language_settings(language.map(|l| l.name()), file, cx)
5526 }
5527
5528 pub fn language_scope_at<T: ToOffset>(&self, point: T) -> Option<LanguageScope> {
5529 self.point_to_buffer_offset(point)
5530 .and_then(|(buffer, offset)| buffer.language_scope_at(offset))
5531 }
5532
5533 pub fn char_classifier_at<T: ToOffset>(&self, point: T) -> CharClassifier {
5534 self.point_to_buffer_offset(point)
5535 .map(|(buffer, offset)| buffer.char_classifier_at(offset))
5536 .unwrap_or_default()
5537 }
5538
5539 pub fn language_indent_size_at<T: ToOffset>(
5540 &self,
5541 position: T,
5542 cx: &App,
5543 ) -> Option<IndentSize> {
5544 let (buffer_snapshot, offset) = self.point_to_buffer_offset(position)?;
5545 Some(buffer_snapshot.language_indent_size_at(offset, cx))
5546 }
5547
5548 pub fn is_dirty(&self) -> bool {
5549 self.is_dirty
5550 }
5551
5552 pub fn has_deleted_file(&self) -> bool {
5553 self.has_deleted_file
5554 }
5555
5556 pub fn has_conflict(&self) -> bool {
5557 self.has_conflict
5558 }
5559
5560 pub fn has_diagnostics(&self) -> bool {
5561 self.excerpts
5562 .iter()
5563 .any(|excerpt| excerpt.buffer.has_diagnostics())
5564 }
5565
5566 pub fn diagnostic_group(
5567 &self,
5568 buffer_id: BufferId,
5569 group_id: usize,
5570 ) -> impl Iterator<Item = DiagnosticEntry<Point>> + '_ {
5571 self.lift_buffer_metadata(Point::zero()..self.max_point(), move |buffer, _| {
5572 if buffer.remote_id() != buffer_id {
5573 return None;
5574 };
5575 Some(
5576 buffer
5577 .diagnostic_group(group_id)
5578 .map(move |DiagnosticEntry { diagnostic, range }| (range, diagnostic)),
5579 )
5580 })
5581 .map(|(range, diagnostic, _)| DiagnosticEntry { diagnostic, range })
5582 }
5583
5584 pub fn diagnostics_in_range<'a, T>(
5585 &'a self,
5586 range: Range<T>,
5587 ) -> impl Iterator<Item = DiagnosticEntry<T>> + 'a
5588 where
5589 T: 'a
5590 + text::ToOffset
5591 + text::FromAnchor
5592 + TextDimension
5593 + Ord
5594 + Sub<T, Output = T>
5595 + fmt::Debug,
5596 {
5597 self.lift_buffer_metadata(range, move |buffer, buffer_range| {
5598 Some(
5599 buffer
5600 .diagnostics_in_range(buffer_range.start..buffer_range.end, false)
5601 .map(|entry| (entry.range, entry.diagnostic)),
5602 )
5603 })
5604 .map(|(range, diagnostic, _)| DiagnosticEntry { diagnostic, range })
5605 }
5606
5607 pub fn syntax_ancestor<T: ToOffset>(
5608 &self,
5609 range: Range<T>,
5610 ) -> Option<(tree_sitter::Node, Range<usize>)> {
5611 let range = range.start.to_offset(self)..range.end.to_offset(self);
5612 let mut excerpt = self.excerpt_containing(range.clone())?;
5613 let node = excerpt
5614 .buffer()
5615 .syntax_ancestor(excerpt.map_range_to_buffer(range))?;
5616 Some((node, excerpt.map_range_from_buffer(node.byte_range())))
5617 }
5618
5619 pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
5620 let (excerpt_id, _, buffer) = self.as_singleton()?;
5621 let outline = buffer.outline(theme)?;
5622 Some(Outline::new(
5623 outline
5624 .items
5625 .into_iter()
5626 .flat_map(|item| {
5627 Some(OutlineItem {
5628 depth: item.depth,
5629 range: self.anchor_in_excerpt(*excerpt_id, item.range.start)?
5630 ..self.anchor_in_excerpt(*excerpt_id, item.range.end)?,
5631 text: item.text,
5632 highlight_ranges: item.highlight_ranges,
5633 name_ranges: item.name_ranges,
5634 body_range: item.body_range.and_then(|body_range| {
5635 Some(
5636 self.anchor_in_excerpt(*excerpt_id, body_range.start)?
5637 ..self.anchor_in_excerpt(*excerpt_id, body_range.end)?,
5638 )
5639 }),
5640 annotation_range: item.annotation_range.and_then(|annotation_range| {
5641 Some(
5642 self.anchor_in_excerpt(*excerpt_id, annotation_range.start)?
5643 ..self.anchor_in_excerpt(*excerpt_id, annotation_range.end)?,
5644 )
5645 }),
5646 })
5647 })
5648 .collect(),
5649 ))
5650 }
5651
5652 pub fn symbols_containing<T: ToOffset>(
5653 &self,
5654 offset: T,
5655 theme: Option<&SyntaxTheme>,
5656 ) -> Option<(BufferId, Vec<OutlineItem<Anchor>>)> {
5657 let anchor = self.anchor_before(offset);
5658 let excerpt_id = anchor.excerpt_id;
5659 let excerpt = self.excerpt(excerpt_id)?;
5660 Some((
5661 excerpt.buffer_id,
5662 excerpt
5663 .buffer
5664 .symbols_containing(anchor.text_anchor, theme)
5665 .into_iter()
5666 .flatten()
5667 .flat_map(|item| {
5668 Some(OutlineItem {
5669 depth: item.depth,
5670 range: self.anchor_in_excerpt(excerpt_id, item.range.start)?
5671 ..self.anchor_in_excerpt(excerpt_id, item.range.end)?,
5672 text: item.text,
5673 highlight_ranges: item.highlight_ranges,
5674 name_ranges: item.name_ranges,
5675 body_range: item.body_range.and_then(|body_range| {
5676 Some(
5677 self.anchor_in_excerpt(excerpt_id, body_range.start)?
5678 ..self.anchor_in_excerpt(excerpt_id, body_range.end)?,
5679 )
5680 }),
5681 annotation_range: item.annotation_range.and_then(|body_range| {
5682 Some(
5683 self.anchor_in_excerpt(excerpt_id, body_range.start)?
5684 ..self.anchor_in_excerpt(excerpt_id, body_range.end)?,
5685 )
5686 }),
5687 })
5688 })
5689 .collect(),
5690 ))
5691 }
5692
5693 fn excerpt_locator_for_id(&self, id: ExcerptId) -> &Locator {
5694 if id == ExcerptId::min() {
5695 Locator::min_ref()
5696 } else if id == ExcerptId::max() {
5697 Locator::max_ref()
5698 } else {
5699 let mut cursor = self.excerpt_ids.cursor::<ExcerptId>(&());
5700 cursor.seek(&id, Bias::Left, &());
5701 if let Some(entry) = cursor.item() {
5702 if entry.id == id {
5703 return &entry.locator;
5704 }
5705 }
5706 panic!("invalid excerpt id {:?}", id)
5707 }
5708 }
5709
5710 /// Returns the locators referenced by the given excerpt IDs, sorted by locator.
5711 fn excerpt_locators_for_ids(
5712 &self,
5713 ids: impl IntoIterator<Item = ExcerptId>,
5714 ) -> SmallVec<[Locator; 1]> {
5715 let mut sorted_ids = ids.into_iter().collect::<SmallVec<[_; 1]>>();
5716 sorted_ids.sort_unstable();
5717 let mut locators = SmallVec::new();
5718
5719 while sorted_ids.last() == Some(&ExcerptId::max()) {
5720 sorted_ids.pop();
5721 if let Some(mapping) = self.excerpt_ids.last() {
5722 locators.push(mapping.locator.clone());
5723 }
5724 }
5725
5726 let mut sorted_ids = sorted_ids.into_iter().dedup().peekable();
5727 if sorted_ids.peek() == Some(&ExcerptId::min()) {
5728 sorted_ids.next();
5729 if let Some(mapping) = self.excerpt_ids.first() {
5730 locators.push(mapping.locator.clone());
5731 }
5732 }
5733
5734 let mut cursor = self.excerpt_ids.cursor::<ExcerptId>(&());
5735 for id in sorted_ids {
5736 if cursor.seek_forward(&id, Bias::Left, &()) {
5737 locators.push(cursor.item().unwrap().locator.clone());
5738 } else {
5739 panic!("invalid excerpt id {:?}", id);
5740 }
5741 }
5742
5743 locators.sort_unstable();
5744 locators
5745 }
5746
5747 pub fn buffer_id_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<BufferId> {
5748 Some(self.excerpt(excerpt_id)?.buffer_id)
5749 }
5750
5751 pub fn buffer_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<&BufferSnapshot> {
5752 Some(&self.excerpt(excerpt_id)?.buffer)
5753 }
5754
5755 pub fn range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<Range<Point>> {
5756 let mut cursor = self
5757 .excerpts
5758 .cursor::<(Option<&Locator>, ExcerptDimension<Point>)>(&());
5759 let locator = self.excerpt_locator_for_id(excerpt_id);
5760 if cursor.seek(&Some(locator), Bias::Left, &()) {
5761 let start = cursor.start().1.clone();
5762 let end = cursor.end(&()).1;
5763 let mut diff_transforms = self
5764 .diff_transforms
5765 .cursor::<(ExcerptDimension<Point>, OutputDimension<Point>)>(&());
5766 diff_transforms.seek(&start, Bias::Left, &());
5767 let overshoot = start.0 - diff_transforms.start().0 .0;
5768 let start = diff_transforms.start().1 .0 + overshoot;
5769 diff_transforms.seek(&end, Bias::Right, &());
5770 let overshoot = end.0 - diff_transforms.start().0 .0;
5771 let end = diff_transforms.start().1 .0 + overshoot;
5772 Some(start..end)
5773 } else {
5774 None
5775 }
5776 }
5777
5778 pub fn buffer_range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<Range<text::Anchor>> {
5779 let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
5780 let locator = self.excerpt_locator_for_id(excerpt_id);
5781 if cursor.seek(&Some(locator), Bias::Left, &()) {
5782 if let Some(excerpt) = cursor.item() {
5783 return Some(excerpt.range.context.clone());
5784 }
5785 }
5786 None
5787 }
5788
5789 fn excerpt(&self, excerpt_id: ExcerptId) -> Option<&Excerpt> {
5790 let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
5791 let locator = self.excerpt_locator_for_id(excerpt_id);
5792 cursor.seek(&Some(locator), Bias::Left, &());
5793 if let Some(excerpt) = cursor.item() {
5794 if excerpt.id == excerpt_id {
5795 return Some(excerpt);
5796 }
5797 }
5798 None
5799 }
5800
5801 /// Returns the excerpt containing range and its offset start within the multibuffer or none if `range` spans multiple excerpts
5802 pub fn excerpt_containing<T: ToOffset>(&self, range: Range<T>) -> Option<MultiBufferExcerpt> {
5803 let range = range.start.to_offset(self)..range.end.to_offset(self);
5804 let mut cursor = self.cursor::<usize>();
5805 cursor.seek(&range.start);
5806
5807 let start_excerpt = cursor.excerpt()?;
5808 if range.end != range.start {
5809 cursor.seek_forward(&range.end);
5810 if cursor.excerpt()?.id != start_excerpt.id {
5811 return None;
5812 }
5813 }
5814
5815 cursor.seek_to_start_of_current_excerpt();
5816 let region = cursor.region()?;
5817 let offset = region.range.start;
5818 let buffer_offset = region.buffer_range.start;
5819 let excerpt_offset = cursor.excerpts.start().clone();
5820 Some(MultiBufferExcerpt {
5821 diff_transforms: cursor.diff_transforms,
5822 excerpt: start_excerpt,
5823 offset,
5824 buffer_offset,
5825 excerpt_offset,
5826 })
5827 }
5828
5829 pub fn selections_in_range<'a>(
5830 &'a self,
5831 range: &'a Range<Anchor>,
5832 include_local: bool,
5833 ) -> impl 'a + Iterator<Item = (ReplicaId, bool, CursorShape, Selection<Anchor>)> {
5834 let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&());
5835 let start_locator = self.excerpt_locator_for_id(range.start.excerpt_id);
5836 let end_locator = self.excerpt_locator_for_id(range.end.excerpt_id);
5837 cursor.seek(start_locator, Bias::Left, &());
5838 cursor
5839 .take_while(move |excerpt| excerpt.locator <= *end_locator)
5840 .flat_map(move |excerpt| {
5841 let mut query_range = excerpt.range.context.start..excerpt.range.context.end;
5842 if excerpt.id == range.start.excerpt_id {
5843 query_range.start = range.start.text_anchor;
5844 }
5845 if excerpt.id == range.end.excerpt_id {
5846 query_range.end = range.end.text_anchor;
5847 }
5848
5849 excerpt
5850 .buffer
5851 .selections_in_range(query_range, include_local)
5852 .flat_map(move |(replica_id, line_mode, cursor_shape, selections)| {
5853 selections.map(move |selection| {
5854 let mut start = Anchor {
5855 buffer_id: Some(excerpt.buffer_id),
5856 excerpt_id: excerpt.id,
5857 text_anchor: selection.start,
5858 diff_base_anchor: None,
5859 };
5860 let mut end = Anchor {
5861 buffer_id: Some(excerpt.buffer_id),
5862 excerpt_id: excerpt.id,
5863 text_anchor: selection.end,
5864 diff_base_anchor: None,
5865 };
5866 if range.start.cmp(&start, self).is_gt() {
5867 start = range.start;
5868 }
5869 if range.end.cmp(&end, self).is_lt() {
5870 end = range.end;
5871 }
5872
5873 (
5874 replica_id,
5875 line_mode,
5876 cursor_shape,
5877 Selection {
5878 id: selection.id,
5879 start,
5880 end,
5881 reversed: selection.reversed,
5882 goal: selection.goal,
5883 },
5884 )
5885 })
5886 })
5887 })
5888 }
5889
5890 pub fn show_headers(&self) -> bool {
5891 self.show_headers
5892 }
5893}
5894
5895#[cfg(any(test, feature = "test-support"))]
5896impl MultiBufferSnapshot {
5897 pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
5898 let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
5899 let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
5900 start..end
5901 }
5902
5903 #[cfg(any(test, feature = "test-support"))]
5904 fn check_invariants(&self) {
5905 let excerpts = self.excerpts.items(&());
5906 let excerpt_ids = self.excerpt_ids.items(&());
5907
5908 for (ix, excerpt) in excerpts.iter().enumerate() {
5909 if ix == 0 {
5910 if excerpt.locator <= Locator::min() {
5911 panic!("invalid first excerpt locator {:?}", excerpt.locator);
5912 }
5913 } else if excerpt.locator <= excerpts[ix - 1].locator {
5914 panic!("excerpts are out-of-order: {:?}", excerpts);
5915 }
5916 }
5917
5918 for (ix, entry) in excerpt_ids.iter().enumerate() {
5919 if ix == 0 {
5920 if entry.id.cmp(&ExcerptId::min(), &self).is_le() {
5921 panic!("invalid first excerpt id {:?}", entry.id);
5922 }
5923 } else if entry.id <= excerpt_ids[ix - 1].id {
5924 panic!("excerpt ids are out-of-order: {:?}", excerpt_ids);
5925 }
5926 }
5927
5928 if self.diff_transforms.summary().input != self.excerpts.summary().text {
5929 panic!(
5930 "incorrect input summary. expected {:?}, got {:?}. transforms: {:+?}",
5931 self.excerpts.summary().text.len,
5932 self.diff_transforms.summary().input,
5933 self.diff_transforms.items(&()),
5934 );
5935 }
5936
5937 let mut prev_transform: Option<&DiffTransform> = None;
5938 for item in self.diff_transforms.iter() {
5939 if let DiffTransform::BufferContent {
5940 summary,
5941 inserted_hunk_anchor,
5942 } = item
5943 {
5944 if let Some(DiffTransform::BufferContent {
5945 inserted_hunk_anchor: prev_inserted_hunk_anchor,
5946 ..
5947 }) = prev_transform
5948 {
5949 if *inserted_hunk_anchor == *prev_inserted_hunk_anchor {
5950 panic!(
5951 "multiple adjacent buffer content transforms with is_inserted_hunk = {inserted_hunk_anchor:?}. transforms: {:+?}",
5952 self.diff_transforms.items(&()));
5953 }
5954 }
5955 if summary.len == 0 && !self.is_empty() {
5956 panic!("empty buffer content transform");
5957 }
5958 }
5959 prev_transform = Some(item);
5960 }
5961 }
5962}
5963
5964impl<'a, D> MultiBufferCursor<'a, D>
5965where
5966 D: TextDimension + Ord + Sub<D, Output = D>,
5967{
5968 fn seek(&mut self, position: &D) {
5969 self.cached_region.take();
5970 self.diff_transforms
5971 .seek(&OutputDimension(*position), Bias::Right, &());
5972 if self.diff_transforms.item().is_none() && *position == self.diff_transforms.start().0 .0 {
5973 self.diff_transforms.prev(&());
5974 }
5975
5976 let mut excerpt_position = self.diff_transforms.start().1 .0;
5977 if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
5978 let overshoot = *position - self.diff_transforms.start().0 .0;
5979 excerpt_position.add_assign(&overshoot);
5980 }
5981
5982 self.excerpts
5983 .seek(&ExcerptDimension(excerpt_position), Bias::Right, &());
5984 if self.excerpts.item().is_none() && excerpt_position == self.excerpts.start().0 {
5985 self.excerpts.prev(&());
5986 }
5987 }
5988
5989 fn seek_forward(&mut self, position: &D) {
5990 self.cached_region.take();
5991 self.diff_transforms
5992 .seek_forward(&OutputDimension(*position), Bias::Right, &());
5993 if self.diff_transforms.item().is_none() && *position == self.diff_transforms.start().0 .0 {
5994 self.diff_transforms.prev(&());
5995 }
5996
5997 let overshoot = *position - self.diff_transforms.start().0 .0;
5998 let mut excerpt_position = self.diff_transforms.start().1 .0;
5999 if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
6000 excerpt_position.add_assign(&overshoot);
6001 }
6002
6003 self.excerpts
6004 .seek_forward(&ExcerptDimension(excerpt_position), Bias::Right, &());
6005 if self.excerpts.item().is_none() && excerpt_position == self.excerpts.start().0 {
6006 self.excerpts.prev(&());
6007 }
6008 }
6009
6010 fn seek_to_buffer_position_in_current_excerpt(&mut self, position: &D) {
6011 self.cached_region.take();
6012 if let Some(excerpt) = self.excerpts.item() {
6013 let excerpt_start = excerpt.range.context.start.summary::<D>(&excerpt.buffer);
6014 let position_in_excerpt = *position - excerpt_start;
6015 let mut excerpt_position = self.excerpts.start().0;
6016 excerpt_position.add_assign(&position_in_excerpt);
6017 self.diff_transforms
6018 .seek(&ExcerptDimension(excerpt_position), Bias::Left, &());
6019 if self.diff_transforms.item().is_none() {
6020 self.diff_transforms.next(&());
6021 }
6022 }
6023 }
6024
6025 fn next_excerpt(&mut self) {
6026 self.excerpts.next(&());
6027 self.seek_to_start_of_current_excerpt();
6028 }
6029
6030 fn prev_excerpt(&mut self) {
6031 self.excerpts.prev(&());
6032 self.seek_to_start_of_current_excerpt();
6033 }
6034
6035 fn seek_to_start_of_current_excerpt(&mut self) {
6036 self.cached_region.take();
6037 self.diff_transforms
6038 .seek(self.excerpts.start(), Bias::Left, &());
6039 if self.diff_transforms.end(&()).1 == *self.excerpts.start()
6040 && self.diff_transforms.start().1 < *self.excerpts.start()
6041 && self.diff_transforms.next_item().is_some()
6042 {
6043 self.diff_transforms.next(&());
6044 }
6045 }
6046
6047 fn next(&mut self) {
6048 self.cached_region.take();
6049 match self.diff_transforms.end(&()).1.cmp(&self.excerpts.end(&())) {
6050 cmp::Ordering::Less => self.diff_transforms.next(&()),
6051 cmp::Ordering::Greater => self.excerpts.next(&()),
6052 cmp::Ordering::Equal => {
6053 self.diff_transforms.next(&());
6054 if self.diff_transforms.end(&()).1 > self.excerpts.end(&())
6055 || self.diff_transforms.item().is_none()
6056 {
6057 self.excerpts.next(&());
6058 }
6059 }
6060 }
6061 }
6062
6063 fn prev(&mut self) {
6064 self.cached_region.take();
6065 match self.diff_transforms.start().1.cmp(self.excerpts.start()) {
6066 cmp::Ordering::Less => self.excerpts.prev(&()),
6067 cmp::Ordering::Greater => self.diff_transforms.prev(&()),
6068 cmp::Ordering::Equal => {
6069 self.diff_transforms.prev(&());
6070 if self.diff_transforms.start().1 < *self.excerpts.start()
6071 || self.diff_transforms.item().is_none()
6072 {
6073 self.excerpts.prev(&());
6074 }
6075 }
6076 }
6077 }
6078
6079 fn region(&mut self) -> Option<MultiBufferRegion<'a, D>> {
6080 if self.cached_region.is_none() {
6081 self.cached_region = self.build_region();
6082 }
6083 self.cached_region.clone()
6084 }
6085
6086 fn is_at_end_of_excerpt(&mut self) -> bool {
6087 if self.diff_transforms.end(&()).1 < self.excerpts.end(&()) {
6088 return false;
6089 } else if self.diff_transforms.end(&()).1 > self.excerpts.end(&())
6090 || self.diff_transforms.item().is_none()
6091 {
6092 return true;
6093 }
6094
6095 self.diff_transforms.next(&());
6096 let next_transform = self.diff_transforms.item();
6097 self.diff_transforms.prev(&());
6098
6099 next_transform.map_or(true, |next_transform| {
6100 matches!(next_transform, DiffTransform::BufferContent { .. })
6101 })
6102 }
6103
6104 fn main_buffer_position(&self) -> Option<D> {
6105 let excerpt = self.excerpts.item()?;
6106 let buffer = &excerpt.buffer;
6107 let buffer_context_start = excerpt.range.context.start.summary::<D>(buffer);
6108 let mut buffer_start = buffer_context_start;
6109 let overshoot = self.diff_transforms.end(&()).1 .0 - self.excerpts.start().0;
6110 buffer_start.add_assign(&overshoot);
6111 Some(buffer_start)
6112 }
6113
6114 fn build_region(&self) -> Option<MultiBufferRegion<'a, D>> {
6115 let excerpt = self.excerpts.item()?;
6116 match self.diff_transforms.item()? {
6117 DiffTransform::DeletedHunk {
6118 buffer_id,
6119 base_text_byte_range,
6120 has_trailing_newline,
6121 ..
6122 } => {
6123 let diff = self.diffs.get(&buffer_id)?;
6124 let buffer = diff.base_text.as_ref()?;
6125 let mut rope_cursor = buffer.as_rope().cursor(0);
6126 let buffer_start = rope_cursor.summary::<D>(base_text_byte_range.start);
6127 let buffer_range_len = rope_cursor.summary::<D>(base_text_byte_range.end);
6128 let mut buffer_end = buffer_start;
6129 buffer_end.add_assign(&buffer_range_len);
6130 let start = self.diff_transforms.start().0 .0;
6131 let end = self.diff_transforms.end(&()).0 .0;
6132 return Some(MultiBufferRegion {
6133 buffer,
6134 excerpt,
6135 has_trailing_newline: *has_trailing_newline,
6136 is_main_buffer: false,
6137 is_inserted_hunk: false,
6138 buffer_range: buffer_start..buffer_end,
6139 range: start..end,
6140 });
6141 }
6142 DiffTransform::BufferContent {
6143 inserted_hunk_anchor,
6144 ..
6145 } => {
6146 let buffer = &excerpt.buffer;
6147 let buffer_context_start = excerpt.range.context.start.summary::<D>(buffer);
6148
6149 let mut start = self.diff_transforms.start().0 .0;
6150 let mut buffer_start = buffer_context_start;
6151 if self.diff_transforms.start().1 < *self.excerpts.start() {
6152 let overshoot = self.excerpts.start().0 - self.diff_transforms.start().1 .0;
6153 start.add_assign(&overshoot);
6154 } else {
6155 let overshoot = self.diff_transforms.start().1 .0 - self.excerpts.start().0;
6156 buffer_start.add_assign(&overshoot);
6157 }
6158
6159 let mut end;
6160 let mut buffer_end;
6161 let has_trailing_newline;
6162 if self.diff_transforms.end(&()).1 .0 < self.excerpts.end(&()).0 {
6163 let overshoot = self.diff_transforms.end(&()).1 .0 - self.excerpts.start().0;
6164 end = self.diff_transforms.end(&()).0 .0;
6165 buffer_end = buffer_context_start;
6166 buffer_end.add_assign(&overshoot);
6167 has_trailing_newline = false;
6168 } else {
6169 let overshoot = self.excerpts.end(&()).0 - self.diff_transforms.start().1 .0;
6170 end = self.diff_transforms.start().0 .0;
6171 end.add_assign(&overshoot);
6172 buffer_end = excerpt.range.context.end.summary::<D>(buffer);
6173 has_trailing_newline = excerpt.has_trailing_newline;
6174 };
6175
6176 Some(MultiBufferRegion {
6177 buffer,
6178 excerpt,
6179 has_trailing_newline,
6180 is_main_buffer: true,
6181 is_inserted_hunk: inserted_hunk_anchor.is_some(),
6182 buffer_range: buffer_start..buffer_end,
6183 range: start..end,
6184 })
6185 }
6186 }
6187 }
6188
6189 fn excerpt(&self) -> Option<&'a Excerpt> {
6190 self.excerpts.item()
6191 }
6192}
6193
6194impl History {
6195 fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
6196 self.transaction_depth += 1;
6197 if self.transaction_depth == 1 {
6198 let id = self.next_transaction_id.tick();
6199 self.undo_stack.push(Transaction {
6200 id,
6201 buffer_transactions: Default::default(),
6202 first_edit_at: now,
6203 last_edit_at: now,
6204 suppress_grouping: false,
6205 });
6206 Some(id)
6207 } else {
6208 None
6209 }
6210 }
6211
6212 fn end_transaction(
6213 &mut self,
6214 now: Instant,
6215 buffer_transactions: HashMap<BufferId, TransactionId>,
6216 ) -> bool {
6217 assert_ne!(self.transaction_depth, 0);
6218 self.transaction_depth -= 1;
6219 if self.transaction_depth == 0 {
6220 if buffer_transactions.is_empty() {
6221 self.undo_stack.pop();
6222 false
6223 } else {
6224 self.redo_stack.clear();
6225 let transaction = self.undo_stack.last_mut().unwrap();
6226 transaction.last_edit_at = now;
6227 for (buffer_id, transaction_id) in buffer_transactions {
6228 transaction
6229 .buffer_transactions
6230 .entry(buffer_id)
6231 .or_insert(transaction_id);
6232 }
6233 true
6234 }
6235 } else {
6236 false
6237 }
6238 }
6239
6240 fn push_transaction<'a, T>(
6241 &mut self,
6242 buffer_transactions: T,
6243 now: Instant,
6244 cx: &Context<MultiBuffer>,
6245 ) where
6246 T: IntoIterator<Item = (&'a Entity<Buffer>, &'a language::Transaction)>,
6247 {
6248 assert_eq!(self.transaction_depth, 0);
6249 let transaction = Transaction {
6250 id: self.next_transaction_id.tick(),
6251 buffer_transactions: buffer_transactions
6252 .into_iter()
6253 .map(|(buffer, transaction)| (buffer.read(cx).remote_id(), transaction.id))
6254 .collect(),
6255 first_edit_at: now,
6256 last_edit_at: now,
6257 suppress_grouping: false,
6258 };
6259 if !transaction.buffer_transactions.is_empty() {
6260 self.undo_stack.push(transaction);
6261 self.redo_stack.clear();
6262 }
6263 }
6264
6265 fn finalize_last_transaction(&mut self) {
6266 if let Some(transaction) = self.undo_stack.last_mut() {
6267 transaction.suppress_grouping = true;
6268 }
6269 }
6270
6271 fn forget(&mut self, transaction_id: TransactionId) -> Option<Transaction> {
6272 if let Some(ix) = self
6273 .undo_stack
6274 .iter()
6275 .rposition(|transaction| transaction.id == transaction_id)
6276 {
6277 Some(self.undo_stack.remove(ix))
6278 } else if let Some(ix) = self
6279 .redo_stack
6280 .iter()
6281 .rposition(|transaction| transaction.id == transaction_id)
6282 {
6283 Some(self.redo_stack.remove(ix))
6284 } else {
6285 None
6286 }
6287 }
6288
6289 fn transaction(&self, transaction_id: TransactionId) -> Option<&Transaction> {
6290 self.undo_stack
6291 .iter()
6292 .find(|transaction| transaction.id == transaction_id)
6293 .or_else(|| {
6294 self.redo_stack
6295 .iter()
6296 .find(|transaction| transaction.id == transaction_id)
6297 })
6298 }
6299
6300 fn transaction_mut(&mut self, transaction_id: TransactionId) -> Option<&mut Transaction> {
6301 self.undo_stack
6302 .iter_mut()
6303 .find(|transaction| transaction.id == transaction_id)
6304 .or_else(|| {
6305 self.redo_stack
6306 .iter_mut()
6307 .find(|transaction| transaction.id == transaction_id)
6308 })
6309 }
6310
6311 fn pop_undo(&mut self) -> Option<&mut Transaction> {
6312 assert_eq!(self.transaction_depth, 0);
6313 if let Some(transaction) = self.undo_stack.pop() {
6314 self.redo_stack.push(transaction);
6315 self.redo_stack.last_mut()
6316 } else {
6317 None
6318 }
6319 }
6320
6321 fn pop_redo(&mut self) -> Option<&mut Transaction> {
6322 assert_eq!(self.transaction_depth, 0);
6323 if let Some(transaction) = self.redo_stack.pop() {
6324 self.undo_stack.push(transaction);
6325 self.undo_stack.last_mut()
6326 } else {
6327 None
6328 }
6329 }
6330
6331 fn remove_from_undo(&mut self, transaction_id: TransactionId) -> Option<&Transaction> {
6332 let ix = self
6333 .undo_stack
6334 .iter()
6335 .rposition(|transaction| transaction.id == transaction_id)?;
6336 let transaction = self.undo_stack.remove(ix);
6337 self.redo_stack.push(transaction);
6338 self.redo_stack.last()
6339 }
6340
6341 fn group(&mut self) -> Option<TransactionId> {
6342 let mut count = 0;
6343 let mut transactions = self.undo_stack.iter();
6344 if let Some(mut transaction) = transactions.next_back() {
6345 while let Some(prev_transaction) = transactions.next_back() {
6346 if !prev_transaction.suppress_grouping
6347 && transaction.first_edit_at - prev_transaction.last_edit_at
6348 <= self.group_interval
6349 {
6350 transaction = prev_transaction;
6351 count += 1;
6352 } else {
6353 break;
6354 }
6355 }
6356 }
6357 self.group_trailing(count)
6358 }
6359
6360 fn group_until(&mut self, transaction_id: TransactionId) {
6361 let mut count = 0;
6362 for transaction in self.undo_stack.iter().rev() {
6363 if transaction.id == transaction_id {
6364 self.group_trailing(count);
6365 break;
6366 } else if transaction.suppress_grouping {
6367 break;
6368 } else {
6369 count += 1;
6370 }
6371 }
6372 }
6373
6374 fn group_trailing(&mut self, n: usize) -> Option<TransactionId> {
6375 let new_len = self.undo_stack.len() - n;
6376 let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
6377 if let Some(last_transaction) = transactions_to_keep.last_mut() {
6378 if let Some(transaction) = transactions_to_merge.last() {
6379 last_transaction.last_edit_at = transaction.last_edit_at;
6380 }
6381 for to_merge in transactions_to_merge {
6382 for (buffer_id, transaction_id) in &to_merge.buffer_transactions {
6383 last_transaction
6384 .buffer_transactions
6385 .entry(*buffer_id)
6386 .or_insert(*transaction_id);
6387 }
6388 }
6389 }
6390
6391 self.undo_stack.truncate(new_len);
6392 self.undo_stack.last().map(|t| t.id)
6393 }
6394}
6395
6396impl Excerpt {
6397 fn new(
6398 id: ExcerptId,
6399 locator: Locator,
6400 buffer_id: BufferId,
6401 buffer: BufferSnapshot,
6402 range: ExcerptRange<text::Anchor>,
6403 has_trailing_newline: bool,
6404 ) -> Self {
6405 Excerpt {
6406 id,
6407 locator,
6408 max_buffer_row: range.context.end.to_point(&buffer).row,
6409 text_summary: buffer
6410 .text_summary_for_range::<TextSummary, _>(range.context.to_offset(&buffer)),
6411 buffer_id,
6412 buffer,
6413 range,
6414 has_trailing_newline,
6415 }
6416 }
6417
6418 fn chunks_in_range(&self, range: Range<usize>, language_aware: bool) -> ExcerptChunks {
6419 let content_start = self.range.context.start.to_offset(&self.buffer);
6420 let chunks_start = content_start + range.start;
6421 let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
6422
6423 let footer_height = if self.has_trailing_newline
6424 && range.start <= self.text_summary.len
6425 && range.end > self.text_summary.len
6426 {
6427 1
6428 } else {
6429 0
6430 };
6431
6432 let content_chunks = self.buffer.chunks(chunks_start..chunks_end, language_aware);
6433
6434 ExcerptChunks {
6435 excerpt_id: self.id,
6436 content_chunks,
6437 footer_height,
6438 }
6439 }
6440
6441 fn seek_chunks(&self, excerpt_chunks: &mut ExcerptChunks, range: Range<usize>) {
6442 let content_start = self.range.context.start.to_offset(&self.buffer);
6443 let chunks_start = content_start + range.start;
6444 let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
6445 excerpt_chunks.content_chunks.seek(chunks_start..chunks_end);
6446 excerpt_chunks.footer_height = if self.has_trailing_newline
6447 && range.start <= self.text_summary.len
6448 && range.end > self.text_summary.len
6449 {
6450 1
6451 } else {
6452 0
6453 };
6454 }
6455
6456 fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
6457 if text_anchor
6458 .cmp(&self.range.context.start, &self.buffer)
6459 .is_lt()
6460 {
6461 self.range.context.start
6462 } else if text_anchor
6463 .cmp(&self.range.context.end, &self.buffer)
6464 .is_gt()
6465 {
6466 self.range.context.end
6467 } else {
6468 text_anchor
6469 }
6470 }
6471
6472 fn contains(&self, anchor: &Anchor) -> bool {
6473 Some(self.buffer_id) == anchor.buffer_id
6474 && self
6475 .range
6476 .context
6477 .start
6478 .cmp(&anchor.text_anchor, &self.buffer)
6479 .is_le()
6480 && self
6481 .range
6482 .context
6483 .end
6484 .cmp(&anchor.text_anchor, &self.buffer)
6485 .is_ge()
6486 }
6487
6488 /// The [`Excerpt`]'s start offset in its [`Buffer`]
6489 fn buffer_start_offset(&self) -> usize {
6490 self.range.context.start.to_offset(&self.buffer)
6491 }
6492
6493 /// The [`Excerpt`]'s end offset in its [`Buffer`]
6494 fn buffer_end_offset(&self) -> usize {
6495 self.buffer_start_offset() + self.text_summary.len
6496 }
6497}
6498
6499impl<'a> MultiBufferExcerpt<'a> {
6500 pub fn id(&self) -> ExcerptId {
6501 self.excerpt.id
6502 }
6503
6504 pub fn buffer_id(&self) -> BufferId {
6505 self.excerpt.buffer_id
6506 }
6507
6508 pub fn start_anchor(&self) -> Anchor {
6509 Anchor {
6510 buffer_id: Some(self.excerpt.buffer_id),
6511 excerpt_id: self.excerpt.id,
6512 text_anchor: self.excerpt.range.context.start,
6513 diff_base_anchor: None,
6514 }
6515 }
6516
6517 pub fn end_anchor(&self) -> Anchor {
6518 Anchor {
6519 buffer_id: Some(self.excerpt.buffer_id),
6520 excerpt_id: self.excerpt.id,
6521 text_anchor: self.excerpt.range.context.end,
6522 diff_base_anchor: None,
6523 }
6524 }
6525
6526 pub fn buffer(&self) -> &'a BufferSnapshot {
6527 &self.excerpt.buffer
6528 }
6529
6530 pub fn buffer_range(&self) -> Range<usize> {
6531 self.buffer_offset
6532 ..self
6533 .excerpt
6534 .range
6535 .context
6536 .end
6537 .to_offset(&self.excerpt.buffer.text)
6538 }
6539
6540 pub fn start_offset(&self) -> usize {
6541 self.offset
6542 }
6543
6544 /// Maps an offset within the [`MultiBuffer`] to an offset within the [`Buffer`]
6545 pub fn map_offset_to_buffer(&mut self, offset: usize) -> usize {
6546 self.map_range_to_buffer(offset..offset).start
6547 }
6548
6549 /// Maps a range within the [`MultiBuffer`] to a range within the [`Buffer`]
6550 pub fn map_range_to_buffer(&mut self, range: Range<usize>) -> Range<usize> {
6551 self.diff_transforms
6552 .seek(&OutputDimension(range.start), Bias::Right, &());
6553 let start = self.map_offset_to_buffer_internal(range.start);
6554 let end = if range.end > range.start {
6555 self.diff_transforms
6556 .seek_forward(&OutputDimension(range.end), Bias::Right, &());
6557 self.map_offset_to_buffer_internal(range.end)
6558 } else {
6559 start
6560 };
6561 start..end
6562 }
6563
6564 fn map_offset_to_buffer_internal(&self, offset: usize) -> usize {
6565 let mut excerpt_offset = self.diff_transforms.start().1.clone();
6566 if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
6567 excerpt_offset.0 += offset - self.diff_transforms.start().0 .0;
6568 };
6569 let offset_in_excerpt = excerpt_offset.0.saturating_sub(self.excerpt_offset.0);
6570 self.buffer_offset + offset_in_excerpt
6571 }
6572
6573 /// Map an offset within the [`Buffer`] to an offset within the [`MultiBuffer`]
6574 pub fn map_offset_from_buffer(&mut self, buffer_offset: usize) -> usize {
6575 self.map_range_from_buffer(buffer_offset..buffer_offset)
6576 .start
6577 }
6578
6579 /// Map a range within the [`Buffer`] to a range within the [`MultiBuffer`]
6580 pub fn map_range_from_buffer(&mut self, buffer_range: Range<usize>) -> Range<usize> {
6581 let overshoot = buffer_range.start - self.buffer_offset;
6582 let excerpt_offset = ExcerptDimension(self.excerpt_offset.0 + overshoot);
6583 self.diff_transforms.seek(&excerpt_offset, Bias::Right, &());
6584 let overshoot = excerpt_offset.0 - self.diff_transforms.start().1 .0;
6585 let start = self.diff_transforms.start().0 .0 + overshoot;
6586
6587 let end = if buffer_range.end > buffer_range.start {
6588 let overshoot = buffer_range.end - self.buffer_offset;
6589 let excerpt_offset = ExcerptDimension(self.excerpt_offset.0 + overshoot);
6590 self.diff_transforms
6591 .seek_forward(&excerpt_offset, Bias::Right, &());
6592 let overshoot = excerpt_offset.0 - self.diff_transforms.start().1 .0;
6593 self.diff_transforms.start().0 .0 + overshoot
6594 } else {
6595 start
6596 };
6597
6598 start..end
6599 }
6600
6601 /// Returns true if the entirety of the given range is in the buffer's excerpt
6602 pub fn contains_buffer_range(&self, range: Range<usize>) -> bool {
6603 range.start >= self.excerpt.buffer_start_offset()
6604 && range.end <= self.excerpt.buffer_end_offset()
6605 }
6606
6607 pub fn max_buffer_row(&self) -> u32 {
6608 self.excerpt.max_buffer_row
6609 }
6610}
6611
6612impl ExcerptId {
6613 pub fn min() -> Self {
6614 Self(0)
6615 }
6616
6617 pub fn max() -> Self {
6618 Self(usize::MAX)
6619 }
6620
6621 pub fn to_proto(&self) -> u64 {
6622 self.0 as _
6623 }
6624
6625 pub fn from_proto(proto: u64) -> Self {
6626 Self(proto as _)
6627 }
6628
6629 pub fn cmp(&self, other: &Self, snapshot: &MultiBufferSnapshot) -> cmp::Ordering {
6630 let a = snapshot.excerpt_locator_for_id(*self);
6631 let b = snapshot.excerpt_locator_for_id(*other);
6632 a.cmp(b).then_with(|| self.0.cmp(&other.0))
6633 }
6634}
6635
6636impl From<ExcerptId> for usize {
6637 fn from(val: ExcerptId) -> Self {
6638 val.0
6639 }
6640}
6641
6642impl fmt::Debug for Excerpt {
6643 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6644 f.debug_struct("Excerpt")
6645 .field("id", &self.id)
6646 .field("locator", &self.locator)
6647 .field("buffer_id", &self.buffer_id)
6648 .field("range", &self.range)
6649 .field("text_summary", &self.text_summary)
6650 .field("has_trailing_newline", &self.has_trailing_newline)
6651 .finish()
6652 }
6653}
6654
6655impl sum_tree::Item for Excerpt {
6656 type Summary = ExcerptSummary;
6657
6658 fn summary(&self, _cx: &()) -> Self::Summary {
6659 let mut text = self.text_summary;
6660 if self.has_trailing_newline {
6661 text += TextSummary::from("\n");
6662 }
6663 ExcerptSummary {
6664 excerpt_id: self.id,
6665 excerpt_locator: self.locator.clone(),
6666 widest_line_number: self.max_buffer_row,
6667 text,
6668 }
6669 }
6670}
6671
6672impl sum_tree::Item for ExcerptIdMapping {
6673 type Summary = ExcerptId;
6674
6675 fn summary(&self, _cx: &()) -> Self::Summary {
6676 self.id
6677 }
6678}
6679
6680impl sum_tree::KeyedItem for ExcerptIdMapping {
6681 type Key = ExcerptId;
6682
6683 fn key(&self) -> Self::Key {
6684 self.id
6685 }
6686}
6687
6688impl DiffTransform {
6689 fn hunk_anchor(&self) -> Option<(ExcerptId, text::Anchor)> {
6690 match self {
6691 DiffTransform::DeletedHunk { hunk_anchor, .. } => Some(*hunk_anchor),
6692 DiffTransform::BufferContent {
6693 inserted_hunk_anchor,
6694 ..
6695 } => *inserted_hunk_anchor,
6696 }
6697 }
6698}
6699
6700impl sum_tree::Item for DiffTransform {
6701 type Summary = DiffTransformSummary;
6702
6703 fn summary(&self, _: &<Self::Summary as sum_tree::Summary>::Context) -> Self::Summary {
6704 match self {
6705 DiffTransform::BufferContent { summary, .. } => DiffTransformSummary {
6706 input: *summary,
6707 output: *summary,
6708 },
6709 DiffTransform::DeletedHunk { summary, .. } => DiffTransformSummary {
6710 input: TextSummary::default(),
6711 output: *summary,
6712 },
6713 }
6714 }
6715}
6716
6717impl DiffTransformSummary {
6718 fn excerpt_len(&self) -> ExcerptOffset {
6719 ExcerptOffset::new(self.input.len)
6720 }
6721}
6722
6723impl sum_tree::Summary for DiffTransformSummary {
6724 type Context = ();
6725
6726 fn zero(_: &Self::Context) -> Self {
6727 DiffTransformSummary {
6728 input: TextSummary::default(),
6729 output: TextSummary::default(),
6730 }
6731 }
6732
6733 fn add_summary(&mut self, summary: &Self, _: &Self::Context) {
6734 self.input += &summary.input;
6735 self.output += &summary.output;
6736 }
6737}
6738
6739impl sum_tree::Summary for ExcerptId {
6740 type Context = ();
6741
6742 fn zero(_cx: &()) -> Self {
6743 Default::default()
6744 }
6745
6746 fn add_summary(&mut self, other: &Self, _: &()) {
6747 *self = *other;
6748 }
6749}
6750
6751impl sum_tree::Summary for ExcerptSummary {
6752 type Context = ();
6753
6754 fn zero(_cx: &()) -> Self {
6755 Default::default()
6756 }
6757
6758 fn add_summary(&mut self, summary: &Self, _: &()) {
6759 debug_assert!(summary.excerpt_locator > self.excerpt_locator);
6760 self.excerpt_locator = summary.excerpt_locator.clone();
6761 self.text.add_summary(&summary.text, &());
6762 self.widest_line_number = cmp::max(self.widest_line_number, summary.widest_line_number);
6763 }
6764}
6765
6766impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for ExcerptOffset {
6767 fn zero(_cx: &()) -> Self {
6768 Default::default()
6769 }
6770
6771 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6772 self.value += summary.text.len;
6773 }
6774}
6775
6776impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for ExcerptOffset {
6777 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
6778 Ord::cmp(&self.value, &cursor_location.text.len)
6779 }
6780}
6781
6782impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, Option<&'a Locator>> for Locator {
6783 fn cmp(&self, cursor_location: &Option<&'a Locator>, _: &()) -> cmp::Ordering {
6784 Ord::cmp(&Some(self), cursor_location)
6785 }
6786}
6787
6788impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Locator {
6789 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
6790 Ord::cmp(self, &cursor_location.excerpt_locator)
6791 }
6792}
6793
6794impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for ExcerptPoint {
6795 fn zero(_cx: &()) -> Self {
6796 Default::default()
6797 }
6798
6799 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6800 self.value += summary.text.lines;
6801 }
6802}
6803
6804impl<'a, D: TextDimension + Default> sum_tree::Dimension<'a, ExcerptSummary>
6805 for ExcerptDimension<D>
6806{
6807 fn zero(_: &()) -> Self {
6808 ExcerptDimension(D::default())
6809 }
6810
6811 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6812 self.0.add_assign(&D::from_text_summary(&summary.text))
6813 }
6814}
6815
6816impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a Locator> {
6817 fn zero(_cx: &()) -> Self {
6818 Default::default()
6819 }
6820
6821 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6822 *self = Some(&summary.excerpt_locator);
6823 }
6824}
6825
6826impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<ExcerptId> {
6827 fn zero(_cx: &()) -> Self {
6828 Default::default()
6829 }
6830
6831 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6832 *self = Some(summary.excerpt_id);
6833 }
6834}
6835
6836#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
6837struct ExcerptDimension<T>(T);
6838
6839#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
6840struct OutputDimension<T>(T);
6841
6842impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for ExcerptOffset {
6843 fn zero(_: &()) -> Self {
6844 ExcerptOffset::new(0)
6845 }
6846
6847 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6848 self.value += summary.input.len;
6849 }
6850}
6851
6852impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for ExcerptPoint {
6853 fn zero(_: &()) -> Self {
6854 ExcerptPoint::new(0, 0)
6855 }
6856
6857 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6858 self.value += summary.input.lines;
6859 }
6860}
6861
6862impl<'a, D: TextDimension + Ord>
6863 sum_tree::SeekTarget<'a, DiffTransformSummary, DiffTransformSummary> for ExcerptDimension<D>
6864{
6865 fn cmp(&self, cursor_location: &DiffTransformSummary, _: &()) -> cmp::Ordering {
6866 Ord::cmp(&self.0, &D::from_text_summary(&cursor_location.input))
6867 }
6868}
6869
6870impl<'a, D: TextDimension + Ord>
6871 sum_tree::SeekTarget<'a, DiffTransformSummary, (OutputDimension<D>, ExcerptDimension<D>)>
6872 for ExcerptDimension<D>
6873{
6874 fn cmp(
6875 &self,
6876 cursor_location: &(OutputDimension<D>, ExcerptDimension<D>),
6877 _: &(),
6878 ) -> cmp::Ordering {
6879 Ord::cmp(&self.0, &cursor_location.1 .0)
6880 }
6881}
6882
6883impl<'a, D: TextDimension> sum_tree::Dimension<'a, DiffTransformSummary> for ExcerptDimension<D> {
6884 fn zero(_: &()) -> Self {
6885 ExcerptDimension(D::default())
6886 }
6887
6888 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6889 self.0.add_assign(&D::from_text_summary(&summary.input))
6890 }
6891}
6892
6893impl<'a, D: TextDimension> sum_tree::Dimension<'a, DiffTransformSummary> for OutputDimension<D> {
6894 fn zero(_: &()) -> Self {
6895 OutputDimension(D::default())
6896 }
6897
6898 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6899 self.0.add_assign(&D::from_text_summary(&summary.output))
6900 }
6901}
6902
6903impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for TextSummary {
6904 fn zero(_: &()) -> Self {
6905 TextSummary::default()
6906 }
6907
6908 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6909 *self += summary.output
6910 }
6911}
6912
6913impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for usize {
6914 fn zero(_: &()) -> Self {
6915 0
6916 }
6917
6918 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6919 *self += summary.output.len
6920 }
6921}
6922
6923impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for Point {
6924 fn zero(_: &()) -> Self {
6925 Point::new(0, 0)
6926 }
6927
6928 fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6929 *self += summary.output.lines
6930 }
6931}
6932
6933impl<'a> MultiBufferRows<'a> {
6934 pub fn seek(&mut self, MultiBufferRow(row): MultiBufferRow) {
6935 self.point = Point::new(row, 0);
6936 self.cursor.seek(&self.point);
6937 }
6938}
6939
6940impl<'a> Iterator for MultiBufferRows<'a> {
6941 type Item = RowInfo;
6942
6943 fn next(&mut self) -> Option<Self::Item> {
6944 if self.is_empty && self.point.row == 0 {
6945 self.point += Point::new(1, 0);
6946 return Some(RowInfo {
6947 buffer_id: None,
6948 buffer_row: Some(0),
6949 multibuffer_row: Some(MultiBufferRow(0)),
6950 diff_status: None,
6951 });
6952 }
6953
6954 let mut region = self.cursor.region()?;
6955 while self.point >= region.range.end {
6956 self.cursor.next();
6957 if let Some(next_region) = self.cursor.region() {
6958 region = next_region;
6959 } else {
6960 if self.point == self.cursor.diff_transforms.end(&()).0 .0 {
6961 let multibuffer_row = MultiBufferRow(self.point.row);
6962 self.point += Point::new(1, 0);
6963 let last_excerpt = self
6964 .cursor
6965 .excerpts
6966 .item()
6967 .or(self.cursor.excerpts.prev_item())?;
6968 let last_row = last_excerpt
6969 .range
6970 .context
6971 .end
6972 .to_point(&last_excerpt.buffer)
6973 .row;
6974 return Some(RowInfo {
6975 buffer_id: Some(last_excerpt.buffer_id),
6976 buffer_row: Some(last_row),
6977 multibuffer_row: Some(multibuffer_row),
6978 diff_status: None,
6979 });
6980 } else {
6981 return None;
6982 }
6983 };
6984 }
6985
6986 let overshoot = self.point - region.range.start;
6987 let buffer_point = region.buffer_range.start + overshoot;
6988 let result = Some(RowInfo {
6989 buffer_id: Some(region.buffer.remote_id()),
6990 buffer_row: Some(buffer_point.row),
6991 multibuffer_row: Some(MultiBufferRow(self.point.row)),
6992 diff_status: if region.is_inserted_hunk && self.point < region.range.end {
6993 Some(DiffHunkStatus::Added)
6994 } else if !region.is_main_buffer {
6995 Some(DiffHunkStatus::Removed)
6996 } else {
6997 None
6998 },
6999 });
7000 self.point += Point::new(1, 0);
7001 result
7002 }
7003}
7004
7005impl<'a> MultiBufferChunks<'a> {
7006 pub fn offset(&self) -> usize {
7007 self.range.start
7008 }
7009
7010 pub fn seek(&mut self, range: Range<usize>) {
7011 self.diff_transforms.seek(&range.end, Bias::Right, &());
7012 let mut excerpt_end = self.diff_transforms.start().1;
7013 if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
7014 let overshoot = range.end - self.diff_transforms.start().0;
7015 excerpt_end.value += overshoot;
7016 }
7017
7018 self.diff_transforms.seek(&range.start, Bias::Right, &());
7019 let mut excerpt_start = self.diff_transforms.start().1;
7020 if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
7021 let overshoot = range.start - self.diff_transforms.start().0;
7022 excerpt_start.value += overshoot;
7023 }
7024
7025 self.seek_to_excerpt_offset_range(excerpt_start..excerpt_end);
7026 self.buffer_chunk.take();
7027 self.range = range;
7028 }
7029
7030 fn seek_to_excerpt_offset_range(&mut self, new_range: Range<ExcerptOffset>) {
7031 self.excerpt_offset_range = new_range.clone();
7032 self.excerpts.seek(&new_range.start, Bias::Right, &());
7033 if let Some(excerpt) = self.excerpts.item() {
7034 let excerpt_start = *self.excerpts.start();
7035 if let Some(excerpt_chunks) = self
7036 .excerpt_chunks
7037 .as_mut()
7038 .filter(|chunks| excerpt.id == chunks.excerpt_id)
7039 {
7040 excerpt.seek_chunks(
7041 excerpt_chunks,
7042 (self.excerpt_offset_range.start - excerpt_start).value
7043 ..(self.excerpt_offset_range.end - excerpt_start).value,
7044 );
7045 } else {
7046 self.excerpt_chunks = Some(excerpt.chunks_in_range(
7047 (self.excerpt_offset_range.start - excerpt_start).value
7048 ..(self.excerpt_offset_range.end - excerpt_start).value,
7049 self.language_aware,
7050 ));
7051 }
7052 } else {
7053 self.excerpt_chunks = None;
7054 }
7055 }
7056
7057 fn next_excerpt_chunk(&mut self) -> Option<Chunk<'a>> {
7058 loop {
7059 if self.excerpt_offset_range.is_empty() {
7060 return None;
7061 } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
7062 self.excerpt_offset_range.start.value += chunk.text.len();
7063 return Some(chunk);
7064 } else {
7065 self.excerpts.next(&());
7066 let excerpt = self.excerpts.item()?;
7067 self.excerpt_chunks = Some(excerpt.chunks_in_range(
7068 0..(self.excerpt_offset_range.end - *self.excerpts.start()).value,
7069 self.language_aware,
7070 ));
7071 }
7072 }
7073 }
7074}
7075
7076impl<'a> Iterator for ReversedMultiBufferChunks<'a> {
7077 type Item = &'a str;
7078
7079 fn next(&mut self) -> Option<Self::Item> {
7080 let mut region = self.cursor.region()?;
7081 if self.offset == region.range.start {
7082 self.cursor.prev();
7083 region = self.cursor.region()?;
7084 let start_overshoot = self.start.saturating_sub(region.range.start);
7085 self.current_chunks = Some(region.buffer.reversed_chunks_in_range(
7086 region.buffer_range.start + start_overshoot..region.buffer_range.end,
7087 ));
7088 }
7089
7090 if self.offset == region.range.end && region.has_trailing_newline {
7091 self.offset -= 1;
7092 Some("\n")
7093 } else {
7094 let chunk = self.current_chunks.as_mut().unwrap().next().unwrap();
7095 self.offset -= chunk.len();
7096 Some(chunk)
7097 }
7098 }
7099}
7100
7101impl<'a> Iterator for MultiBufferChunks<'a> {
7102 type Item = Chunk<'a>;
7103
7104 fn next(&mut self) -> Option<Chunk<'a>> {
7105 if self.range.start >= self.range.end {
7106 return None;
7107 }
7108 if self.range.start == self.diff_transforms.end(&()).0 {
7109 self.diff_transforms.next(&());
7110 }
7111
7112 let diff_transform_start = self.diff_transforms.start().0;
7113 let diff_transform_end = self.diff_transforms.end(&()).0;
7114 debug_assert!(self.range.start < diff_transform_end);
7115
7116 let diff_transform = self.diff_transforms.item()?;
7117 match diff_transform {
7118 DiffTransform::BufferContent { .. } => {
7119 let chunk = if let Some(chunk) = &mut self.buffer_chunk {
7120 chunk
7121 } else {
7122 let chunk = self.next_excerpt_chunk().unwrap();
7123 self.buffer_chunk.insert(chunk)
7124 };
7125
7126 let chunk_end = self.range.start + chunk.text.len();
7127 let diff_transform_end = diff_transform_end.min(self.range.end);
7128
7129 if diff_transform_end < chunk_end {
7130 let (before, after) =
7131 chunk.text.split_at(diff_transform_end - self.range.start);
7132 self.range.start = diff_transform_end;
7133 chunk.text = after;
7134 Some(Chunk {
7135 text: before,
7136 ..chunk.clone()
7137 })
7138 } else {
7139 self.range.start = chunk_end;
7140 self.buffer_chunk.take()
7141 }
7142 }
7143 DiffTransform::DeletedHunk {
7144 buffer_id,
7145 base_text_byte_range,
7146 has_trailing_newline,
7147 ..
7148 } => {
7149 let base_text_start =
7150 base_text_byte_range.start + self.range.start - diff_transform_start;
7151 let base_text_end =
7152 base_text_byte_range.start + self.range.end - diff_transform_start;
7153 let base_text_end = base_text_end.min(base_text_byte_range.end);
7154
7155 let mut chunks = if let Some((_, mut chunks)) = self
7156 .diff_base_chunks
7157 .take()
7158 .filter(|(id, _)| id == buffer_id)
7159 {
7160 if chunks.range().start != base_text_start || chunks.range().end < base_text_end
7161 {
7162 chunks.seek(base_text_start..base_text_end);
7163 }
7164 chunks
7165 } else {
7166 let base_buffer = &self.diffs.get(&buffer_id)?.base_text.as_ref()?;
7167 base_buffer.chunks(base_text_start..base_text_end, self.language_aware)
7168 };
7169
7170 let chunk = if let Some(chunk) = chunks.next() {
7171 self.range.start += chunk.text.len();
7172 self.diff_base_chunks = Some((*buffer_id, chunks));
7173 chunk
7174 } else {
7175 debug_assert!(has_trailing_newline);
7176 self.range.start += "\n".len();
7177 Chunk {
7178 text: "\n",
7179 ..Default::default()
7180 }
7181 };
7182 Some(chunk)
7183 }
7184 }
7185 }
7186}
7187
7188impl<'a> MultiBufferBytes<'a> {
7189 fn consume(&mut self, len: usize) {
7190 self.range.start += len;
7191 self.chunk = &self.chunk[len..];
7192
7193 if !self.range.is_empty() && self.chunk.is_empty() {
7194 if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
7195 self.chunk = chunk;
7196 } else if self.has_trailing_newline {
7197 self.has_trailing_newline = false;
7198 self.chunk = b"\n";
7199 } else {
7200 self.cursor.next();
7201 if let Some(region) = self.cursor.region() {
7202 let mut excerpt_bytes = region.buffer.bytes_in_range(
7203 region.buffer_range.start
7204 ..(region.buffer_range.start + self.range.end - region.range.start)
7205 .min(region.buffer_range.end),
7206 );
7207 self.chunk = excerpt_bytes.next().unwrap_or(&[]);
7208 self.excerpt_bytes = Some(excerpt_bytes);
7209 self.has_trailing_newline =
7210 region.has_trailing_newline && self.range.end >= region.range.end;
7211 if self.chunk.is_empty() && self.has_trailing_newline {
7212 self.has_trailing_newline = false;
7213 self.chunk = b"\n";
7214 }
7215 }
7216 }
7217 }
7218 }
7219}
7220
7221impl<'a> Iterator for MultiBufferBytes<'a> {
7222 type Item = &'a [u8];
7223
7224 fn next(&mut self) -> Option<Self::Item> {
7225 let chunk = self.chunk;
7226 if chunk.is_empty() {
7227 None
7228 } else {
7229 self.consume(chunk.len());
7230 Some(chunk)
7231 }
7232 }
7233}
7234
7235impl<'a> io::Read for MultiBufferBytes<'a> {
7236 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
7237 let len = cmp::min(buf.len(), self.chunk.len());
7238 buf[..len].copy_from_slice(&self.chunk[..len]);
7239 if len > 0 {
7240 self.consume(len);
7241 }
7242 Ok(len)
7243 }
7244}
7245
7246impl<'a> io::Read for ReversedMultiBufferBytes<'a> {
7247 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
7248 let len = cmp::min(buf.len(), self.chunk.len());
7249 buf[..len].copy_from_slice(&self.chunk[..len]);
7250 buf[..len].reverse();
7251 if len > 0 {
7252 self.range.end -= len;
7253 self.chunk = &self.chunk[..self.chunk.len() - len];
7254 if !self.range.is_empty() && self.chunk.is_empty() {
7255 if let Some(chunk) = self.chunks.next() {
7256 self.chunk = chunk.as_bytes();
7257 }
7258 }
7259 }
7260 Ok(len)
7261 }
7262}
7263
7264impl<'a> Iterator for ExcerptChunks<'a> {
7265 type Item = Chunk<'a>;
7266
7267 fn next(&mut self) -> Option<Self::Item> {
7268 if let Some(chunk) = self.content_chunks.next() {
7269 return Some(chunk);
7270 }
7271
7272 if self.footer_height > 0 {
7273 let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
7274 self.footer_height = 0;
7275 return Some(Chunk {
7276 text,
7277 ..Default::default()
7278 });
7279 }
7280
7281 None
7282 }
7283}
7284
7285impl ToOffset for Point {
7286 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
7287 snapshot.point_to_offset(*self)
7288 }
7289}
7290
7291impl ToOffset for usize {
7292 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
7293 assert!(*self <= snapshot.len(), "offset is out of range");
7294 *self
7295 }
7296}
7297
7298impl ToOffset for OffsetUtf16 {
7299 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
7300 snapshot.offset_utf16_to_offset(*self)
7301 }
7302}
7303
7304impl ToOffset for PointUtf16 {
7305 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
7306 snapshot.point_utf16_to_offset(*self)
7307 }
7308}
7309
7310impl ToOffsetUtf16 for OffsetUtf16 {
7311 fn to_offset_utf16(&self, _snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
7312 *self
7313 }
7314}
7315
7316impl ToOffsetUtf16 for usize {
7317 fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
7318 snapshot.offset_to_offset_utf16(*self)
7319 }
7320}
7321
7322impl ToPoint for usize {
7323 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
7324 snapshot.offset_to_point(*self)
7325 }
7326}
7327
7328impl ToPoint for Point {
7329 fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
7330 *self
7331 }
7332}
7333
7334impl ToPointUtf16 for usize {
7335 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
7336 snapshot.offset_to_point_utf16(*self)
7337 }
7338}
7339
7340impl ToPointUtf16 for Point {
7341 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
7342 snapshot.point_to_point_utf16(*self)
7343 }
7344}
7345
7346impl ToPointUtf16 for PointUtf16 {
7347 fn to_point_utf16<'a>(&self, _: &MultiBufferSnapshot) -> PointUtf16 {
7348 *self
7349 }
7350}
7351
7352impl From<ExcerptId> for EntityId {
7353 fn from(id: ExcerptId) -> Self {
7354 EntityId::from(id.0 as u64)
7355 }
7356}
7357
7358pub fn build_excerpt_ranges<T>(
7359 buffer: &BufferSnapshot,
7360 ranges: &[Range<T>],
7361 context_line_count: u32,
7362) -> (Vec<ExcerptRange<Point>>, Vec<usize>)
7363where
7364 T: text::ToPoint,
7365{
7366 let max_point = buffer.max_point();
7367 let mut range_counts = Vec::new();
7368 let mut excerpt_ranges = Vec::new();
7369 let mut range_iter = ranges
7370 .iter()
7371 .map(|range| range.start.to_point(buffer)..range.end.to_point(buffer))
7372 .peekable();
7373 while let Some(range) = range_iter.next() {
7374 let excerpt_start = Point::new(range.start.row.saturating_sub(context_line_count), 0);
7375 let row = (range.end.row + context_line_count).min(max_point.row);
7376 let mut excerpt_end = Point::new(row, buffer.line_len(row));
7377
7378 let mut ranges_in_excerpt = 1;
7379
7380 while let Some(next_range) = range_iter.peek() {
7381 if next_range.start.row <= excerpt_end.row + context_line_count {
7382 let row = (next_range.end.row + context_line_count).min(max_point.row);
7383 excerpt_end = Point::new(row, buffer.line_len(row));
7384
7385 ranges_in_excerpt += 1;
7386 range_iter.next();
7387 } else {
7388 break;
7389 }
7390 }
7391
7392 excerpt_ranges.push(ExcerptRange {
7393 context: excerpt_start..excerpt_end,
7394 primary: Some(range),
7395 });
7396 range_counts.push(ranges_in_excerpt);
7397 }
7398
7399 (excerpt_ranges, range_counts)
7400}