1mod anchor;
2
3pub use anchor::{Anchor, AnchorRangeExt, Offset};
4use anyhow::{anyhow, Result};
5use clock::ReplicaId;
6use collections::{BTreeMap, Bound, HashMap, HashSet};
7use futures::{channel::mpsc, SinkExt};
8use git::diff::DiffHunk;
9use gpui::{AppContext, EventEmitter, Model, ModelContext};
10use language::{
11 char_kind,
12 language_settings::{language_settings, LanguageSettings},
13 AutoindentMode, Buffer, BufferChunks, BufferSnapshot, Capability, CharKind, Chunk, CursorShape,
14 DiagnosticEntry, File, IndentSize, Language, LanguageScope, OffsetRangeExt, OffsetUtf16,
15 Outline, OutlineItem, Point, PointUtf16, Selection, TextDimension, ToOffset as _,
16 ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _, TransactionId, Unclipped,
17};
18use std::{
19 borrow::Cow,
20 cell::{Ref, RefCell},
21 cmp, fmt,
22 future::Future,
23 io,
24 iter::{self, FromIterator},
25 mem,
26 ops::{Range, RangeBounds, Sub},
27 str,
28 sync::Arc,
29 time::{Duration, Instant},
30};
31use sum_tree::{Bias, Cursor, SumTree};
32use text::{
33 locator::Locator,
34 subscription::{Subscription, Topic},
35 BufferId, Edit, TextSummary,
36};
37use theme::SyntaxTheme;
38
39use util::post_inc;
40
41#[cfg(any(test, feature = "test-support"))]
42use gpui::Context;
43
44const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];
45
46#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
47pub struct ExcerptId(usize);
48
49/// One or more [`Buffers`](Buffer) being edited in a single view.
50///
51/// See <https://zed.dev/features#multi-buffers>
52pub struct MultiBuffer {
53 /// A snapshot of the [`Excerpt`]s in the MultiBuffer.
54 /// Use [`MultiBuffer::snapshot`] to get a up-to-date snapshot.
55 snapshot: RefCell<MultiBufferSnapshot>,
56 /// Contains the state of the buffers being edited
57 buffers: RefCell<HashMap<BufferId, BufferState>>,
58 subscriptions: Topic,
59 /// If true, the multi-buffer only contains a single [`Buffer`] and a single [`Excerpt`]
60 singleton: bool,
61 replica_id: ReplicaId,
62 history: History,
63 title: Option<String>,
64 capability: Capability,
65}
66
67#[derive(Clone, Debug, PartialEq, Eq)]
68pub enum Event {
69 ExcerptsAdded {
70 buffer: Model<Buffer>,
71 predecessor: ExcerptId,
72 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
73 },
74 ExcerptsRemoved {
75 ids: Vec<ExcerptId>,
76 },
77 ExcerptsEdited {
78 ids: Vec<ExcerptId>,
79 },
80 Edited {
81 singleton_buffer_edited: bool,
82 },
83 TransactionUndone {
84 transaction_id: TransactionId,
85 },
86 Reloaded,
87 DiffBaseChanged,
88 LanguageChanged,
89 CapabilityChanged,
90 Reparsed,
91 Saved,
92 FileHandleChanged,
93 Closed,
94 DirtyChanged,
95 DiagnosticsUpdated,
96}
97
98#[derive(Clone)]
99struct History {
100 next_transaction_id: TransactionId,
101 undo_stack: Vec<Transaction>,
102 redo_stack: Vec<Transaction>,
103 transaction_depth: usize,
104 group_interval: Duration,
105}
106
107#[derive(Clone)]
108struct Transaction {
109 id: TransactionId,
110 buffer_transactions: HashMap<BufferId, text::TransactionId>,
111 first_edit_at: Instant,
112 last_edit_at: Instant,
113 suppress_grouping: bool,
114}
115
116pub trait ToOffset: 'static + fmt::Debug {
117 fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
118}
119
120pub trait ToOffsetUtf16: 'static + fmt::Debug {
121 fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16;
122}
123
124pub trait ToPoint: 'static + fmt::Debug {
125 fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point;
126}
127
128pub trait ToPointUtf16: 'static + fmt::Debug {
129 fn to_point_utf16(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16;
130}
131
132struct BufferState {
133 buffer: Model<Buffer>,
134 last_version: clock::Global,
135 last_parse_count: usize,
136 last_selections_update_count: usize,
137 last_diagnostics_update_count: usize,
138 last_file_update_count: usize,
139 last_git_diff_update_count: usize,
140 excerpts: Vec<Locator>,
141 _subscriptions: [gpui::Subscription; 2],
142}
143
144/// The contents of a [`MultiBuffer`] at a single point in time.
145#[derive(Clone, Default)]
146pub struct MultiBufferSnapshot {
147 singleton: bool,
148 excerpts: SumTree<Excerpt>,
149 excerpt_ids: SumTree<ExcerptIdMapping>,
150 parse_count: usize,
151 diagnostics_update_count: usize,
152 trailing_excerpt_update_count: usize,
153 git_diff_update_count: usize,
154 edit_count: usize,
155 is_dirty: bool,
156 has_conflict: bool,
157}
158
159/// A boundary between [`Excerpt`]s in a [`MultiBuffer`]
160pub struct ExcerptBoundary {
161 pub id: ExcerptId,
162 /// The row in the `MultiBuffer` where the boundary is located
163 pub row: u32,
164 pub buffer: BufferSnapshot,
165 pub range: ExcerptRange<text::Anchor>,
166 /// It's possible to have multiple excerpts in the same buffer,
167 /// and they are rendered together without a new File header.
168 ///
169 /// This flag indicates that the excerpt is the first one in the buffer.
170 pub starts_new_buffer: bool,
171}
172
173/// A slice into a [`Buffer`] that is being edited in a [`MultiBuffer`].
174#[derive(Clone)]
175struct Excerpt {
176 /// The unique identifier for this excerpt
177 id: ExcerptId,
178 /// The location of the excerpt in the [`MultiBuffer`]
179 locator: Locator,
180 /// The buffer being excerpted
181 buffer_id: BufferId,
182 /// A snapshot of the buffer being excerpted
183 buffer: BufferSnapshot,
184 /// The range of the buffer to be shown in the excerpt
185 range: ExcerptRange<text::Anchor>,
186 /// The last row in the excerpted slice of the buffer
187 max_buffer_row: u32,
188 /// A summary of the text in the excerpt
189 text_summary: TextSummary,
190 has_trailing_newline: bool,
191}
192
193/// A public view into an [`Excerpt`] in a [`MultiBuffer`].
194///
195/// Contains methods for getting the [`Buffer`] of the excerpt,
196/// as well as mapping offsets to/from buffer and multibuffer coordinates.
197#[derive(Clone)]
198pub struct MultiBufferExcerpt<'a> {
199 excerpt: &'a Excerpt,
200 excerpt_offset: usize,
201}
202
203#[derive(Clone, Debug)]
204struct ExcerptIdMapping {
205 id: ExcerptId,
206 locator: Locator,
207}
208
209/// A range of text from a single [`Buffer`], to be shown as an [`Excerpt`].
210/// These ranges are relative to the buffer itself
211#[derive(Clone, Debug, Eq, PartialEq)]
212pub struct ExcerptRange<T> {
213 /// The full range of text to be shown in the excerpt.
214 pub context: Range<T>,
215 /// The primary range of text to be highlighted in the excerpt.
216 /// In a multi-buffer search, this would be the text that matched the search
217 pub primary: Option<Range<T>>,
218}
219
220#[derive(Clone, Debug, Default)]
221struct ExcerptSummary {
222 excerpt_id: ExcerptId,
223 /// The location of the last [`Excerpt`] being summarized
224 excerpt_locator: Locator,
225 /// The maximum row of the [`Excerpt`]s being summarized
226 max_buffer_row: u32,
227 text: TextSummary,
228}
229
230#[derive(Clone)]
231pub struct MultiBufferRows<'a> {
232 buffer_row_range: Range<u32>,
233 excerpts: Cursor<'a, Excerpt, Point>,
234}
235
236pub struct MultiBufferChunks<'a> {
237 range: Range<usize>,
238 excerpts: Cursor<'a, Excerpt, usize>,
239 excerpt_chunks: Option<ExcerptChunks<'a>>,
240 language_aware: bool,
241}
242
243pub struct MultiBufferBytes<'a> {
244 range: Range<usize>,
245 excerpts: Cursor<'a, Excerpt, usize>,
246 excerpt_bytes: Option<ExcerptBytes<'a>>,
247 chunk: &'a [u8],
248}
249
250pub struct ReversedMultiBufferBytes<'a> {
251 range: Range<usize>,
252 excerpts: Cursor<'a, Excerpt, usize>,
253 excerpt_bytes: Option<ExcerptBytes<'a>>,
254 chunk: &'a [u8],
255}
256
257struct ExcerptChunks<'a> {
258 content_chunks: BufferChunks<'a>,
259 footer_height: usize,
260}
261
262struct ExcerptBytes<'a> {
263 content_bytes: text::Bytes<'a>,
264 padding_height: usize,
265 reversed: bool,
266}
267
268impl MultiBuffer {
269 pub fn new(replica_id: ReplicaId, capability: Capability) -> Self {
270 Self {
271 snapshot: Default::default(),
272 buffers: Default::default(),
273 subscriptions: Default::default(),
274 singleton: false,
275 capability,
276 replica_id,
277 history: History {
278 next_transaction_id: Default::default(),
279 undo_stack: Default::default(),
280 redo_stack: Default::default(),
281 transaction_depth: 0,
282 group_interval: Duration::from_millis(300),
283 },
284 title: Default::default(),
285 }
286 }
287
288 pub fn clone(&self, new_cx: &mut ModelContext<Self>) -> Self {
289 let mut buffers = HashMap::default();
290 for (buffer_id, buffer_state) in self.buffers.borrow().iter() {
291 buffers.insert(
292 *buffer_id,
293 BufferState {
294 buffer: buffer_state.buffer.clone(),
295 last_version: buffer_state.last_version.clone(),
296 last_parse_count: buffer_state.last_parse_count,
297 last_selections_update_count: buffer_state.last_selections_update_count,
298 last_diagnostics_update_count: buffer_state.last_diagnostics_update_count,
299 last_file_update_count: buffer_state.last_file_update_count,
300 last_git_diff_update_count: buffer_state.last_git_diff_update_count,
301 excerpts: buffer_state.excerpts.clone(),
302 _subscriptions: [
303 new_cx.observe(&buffer_state.buffer, |_, _, cx| cx.notify()),
304 new_cx.subscribe(&buffer_state.buffer, Self::on_buffer_event),
305 ],
306 },
307 );
308 }
309 Self {
310 snapshot: RefCell::new(self.snapshot.borrow().clone()),
311 buffers: RefCell::new(buffers),
312 subscriptions: Default::default(),
313 singleton: self.singleton,
314 capability: self.capability,
315 replica_id: self.replica_id,
316 history: self.history.clone(),
317 title: self.title.clone(),
318 }
319 }
320
321 pub fn with_title(mut self, title: String) -> Self {
322 self.title = Some(title);
323 self
324 }
325
326 pub fn read_only(&self) -> bool {
327 self.capability == Capability::ReadOnly
328 }
329
330 pub fn singleton(buffer: Model<Buffer>, cx: &mut ModelContext<Self>) -> Self {
331 let mut this = Self::new(buffer.read(cx).replica_id(), buffer.read(cx).capability());
332 this.singleton = true;
333 this.push_excerpts(
334 buffer,
335 [ExcerptRange {
336 context: text::Anchor::MIN..text::Anchor::MAX,
337 primary: None,
338 }],
339 cx,
340 );
341 this.snapshot.borrow_mut().singleton = true;
342 this
343 }
344
345 pub fn replica_id(&self) -> ReplicaId {
346 self.replica_id
347 }
348
349 /// Returns an up-to-date snapshot of the MultiBuffer.
350 pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot {
351 self.sync(cx);
352 self.snapshot.borrow().clone()
353 }
354
355 pub fn read(&self, cx: &AppContext) -> Ref<MultiBufferSnapshot> {
356 self.sync(cx);
357 self.snapshot.borrow()
358 }
359
360 pub fn as_singleton(&self) -> Option<Model<Buffer>> {
361 if self.singleton {
362 return Some(
363 self.buffers
364 .borrow()
365 .values()
366 .next()
367 .unwrap()
368 .buffer
369 .clone(),
370 );
371 } else {
372 None
373 }
374 }
375
376 pub fn is_singleton(&self) -> bool {
377 self.singleton
378 }
379
380 pub fn subscribe(&mut self) -> Subscription {
381 self.subscriptions.subscribe()
382 }
383
384 pub fn is_dirty(&self, cx: &AppContext) -> bool {
385 self.read(cx).is_dirty()
386 }
387
388 pub fn has_conflict(&self, cx: &AppContext) -> bool {
389 self.read(cx).has_conflict()
390 }
391
392 // The `is_empty` signature doesn't match what clippy expects
393 #[allow(clippy::len_without_is_empty)]
394 pub fn len(&self, cx: &AppContext) -> usize {
395 self.read(cx).len()
396 }
397
398 pub fn is_empty(&self, cx: &AppContext) -> bool {
399 self.len(cx) != 0
400 }
401
402 pub fn symbols_containing<T: ToOffset>(
403 &self,
404 offset: T,
405 theme: Option<&SyntaxTheme>,
406 cx: &AppContext,
407 ) -> Option<(BufferId, Vec<OutlineItem<Anchor>>)> {
408 self.read(cx).symbols_containing(offset, theme)
409 }
410
411 pub fn edit<I, S, T>(
412 &mut self,
413 edits: I,
414 mut autoindent_mode: Option<AutoindentMode>,
415 cx: &mut ModelContext<Self>,
416 ) where
417 I: IntoIterator<Item = (Range<S>, T)>,
418 S: ToOffset,
419 T: Into<Arc<str>>,
420 {
421 if self.read_only() {
422 return;
423 }
424 if self.buffers.borrow().is_empty() {
425 return;
426 }
427
428 let snapshot = self.read(cx);
429 let edits = edits.into_iter().map(|(range, new_text)| {
430 let mut range = range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot);
431 if range.start > range.end {
432 mem::swap(&mut range.start, &mut range.end);
433 }
434 (range, new_text)
435 });
436
437 if let Some(buffer) = self.as_singleton() {
438 return buffer.update(cx, |buffer, cx| {
439 buffer.edit(edits, autoindent_mode, cx);
440 });
441 }
442
443 let original_indent_columns = match &mut autoindent_mode {
444 Some(AutoindentMode::Block {
445 original_indent_columns,
446 }) => mem::take(original_indent_columns),
447 _ => Default::default(),
448 };
449
450 struct BufferEdit {
451 range: Range<usize>,
452 new_text: Arc<str>,
453 is_insertion: bool,
454 original_indent_column: u32,
455 }
456 let mut buffer_edits: HashMap<BufferId, Vec<BufferEdit>> = Default::default();
457 let mut edited_excerpt_ids = Vec::new();
458 let mut cursor = snapshot.excerpts.cursor::<usize>();
459 for (ix, (range, new_text)) in edits.enumerate() {
460 let new_text: Arc<str> = new_text.into();
461 let original_indent_column = original_indent_columns.get(ix).copied().unwrap_or(0);
462 cursor.seek(&range.start, Bias::Right, &());
463 if cursor.item().is_none() && range.start == *cursor.start() {
464 cursor.prev(&());
465 }
466 let start_excerpt = cursor.item().expect("start offset out of bounds");
467 let start_overshoot = range.start - cursor.start();
468 let buffer_start = start_excerpt
469 .range
470 .context
471 .start
472 .to_offset(&start_excerpt.buffer)
473 + start_overshoot;
474 edited_excerpt_ids.push(start_excerpt.id);
475
476 cursor.seek(&range.end, Bias::Right, &());
477 if cursor.item().is_none() && range.end == *cursor.start() {
478 cursor.prev(&());
479 }
480 let end_excerpt = cursor.item().expect("end offset out of bounds");
481 let end_overshoot = range.end - cursor.start();
482 let buffer_end = end_excerpt
483 .range
484 .context
485 .start
486 .to_offset(&end_excerpt.buffer)
487 + end_overshoot;
488
489 if start_excerpt.id == end_excerpt.id {
490 buffer_edits
491 .entry(start_excerpt.buffer_id)
492 .or_insert(Vec::new())
493 .push(BufferEdit {
494 range: buffer_start..buffer_end,
495 new_text,
496 is_insertion: true,
497 original_indent_column,
498 });
499 } else {
500 edited_excerpt_ids.push(end_excerpt.id);
501 let start_excerpt_range = buffer_start
502 ..start_excerpt
503 .range
504 .context
505 .end
506 .to_offset(&start_excerpt.buffer);
507 let end_excerpt_range = end_excerpt
508 .range
509 .context
510 .start
511 .to_offset(&end_excerpt.buffer)
512 ..buffer_end;
513 buffer_edits
514 .entry(start_excerpt.buffer_id)
515 .or_insert(Vec::new())
516 .push(BufferEdit {
517 range: start_excerpt_range,
518 new_text: new_text.clone(),
519 is_insertion: true,
520 original_indent_column,
521 });
522 buffer_edits
523 .entry(end_excerpt.buffer_id)
524 .or_insert(Vec::new())
525 .push(BufferEdit {
526 range: end_excerpt_range,
527 new_text: new_text.clone(),
528 is_insertion: false,
529 original_indent_column,
530 });
531
532 cursor.seek(&range.start, Bias::Right, &());
533 cursor.next(&());
534 while let Some(excerpt) = cursor.item() {
535 if excerpt.id == end_excerpt.id {
536 break;
537 }
538 buffer_edits
539 .entry(excerpt.buffer_id)
540 .or_insert(Vec::new())
541 .push(BufferEdit {
542 range: excerpt.range.context.to_offset(&excerpt.buffer),
543 new_text: new_text.clone(),
544 is_insertion: false,
545 original_indent_column,
546 });
547 edited_excerpt_ids.push(excerpt.id);
548 cursor.next(&());
549 }
550 }
551 }
552
553 drop(cursor);
554 drop(snapshot);
555 // Non-generic part of edit, hoisted out to avoid blowing up LLVM IR.
556 fn tail(
557 this: &mut MultiBuffer,
558 buffer_edits: HashMap<BufferId, Vec<BufferEdit>>,
559 autoindent_mode: Option<AutoindentMode>,
560 edited_excerpt_ids: Vec<ExcerptId>,
561 cx: &mut ModelContext<MultiBuffer>,
562 ) {
563 for (buffer_id, mut edits) in buffer_edits {
564 edits.sort_unstable_by_key(|edit| edit.range.start);
565 this.buffers.borrow()[&buffer_id]
566 .buffer
567 .update(cx, |buffer, cx| {
568 let mut edits = edits.into_iter().peekable();
569 let mut insertions = Vec::new();
570 let mut original_indent_columns = Vec::new();
571 let mut deletions = Vec::new();
572 let empty_str: Arc<str> = "".into();
573 while let Some(BufferEdit {
574 mut range,
575 new_text,
576 mut is_insertion,
577 original_indent_column,
578 }) = edits.next()
579 {
580 while let Some(BufferEdit {
581 range: next_range,
582 is_insertion: next_is_insertion,
583 ..
584 }) = edits.peek()
585 {
586 if range.end >= next_range.start {
587 range.end = cmp::max(next_range.end, range.end);
588 is_insertion |= *next_is_insertion;
589 edits.next();
590 } else {
591 break;
592 }
593 }
594
595 if is_insertion {
596 original_indent_columns.push(original_indent_column);
597 insertions.push((
598 buffer.anchor_before(range.start)
599 ..buffer.anchor_before(range.end),
600 new_text.clone(),
601 ));
602 } else if !range.is_empty() {
603 deletions.push((
604 buffer.anchor_before(range.start)
605 ..buffer.anchor_before(range.end),
606 empty_str.clone(),
607 ));
608 }
609 }
610
611 let deletion_autoindent_mode =
612 if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
613 Some(AutoindentMode::Block {
614 original_indent_columns: Default::default(),
615 })
616 } else {
617 None
618 };
619 let insertion_autoindent_mode =
620 if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
621 Some(AutoindentMode::Block {
622 original_indent_columns,
623 })
624 } else {
625 None
626 };
627
628 buffer.edit(deletions, deletion_autoindent_mode, cx);
629 buffer.edit(insertions, insertion_autoindent_mode, cx);
630 })
631 }
632
633 cx.emit(Event::ExcerptsEdited {
634 ids: edited_excerpt_ids,
635 });
636 }
637 tail(self, buffer_edits, autoindent_mode, edited_excerpt_ids, cx);
638 }
639
640 pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
641 self.start_transaction_at(Instant::now(), cx)
642 }
643
644 pub fn start_transaction_at(
645 &mut self,
646 now: Instant,
647 cx: &mut ModelContext<Self>,
648 ) -> Option<TransactionId> {
649 if let Some(buffer) = self.as_singleton() {
650 return buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
651 }
652
653 for BufferState { buffer, .. } in self.buffers.borrow().values() {
654 buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
655 }
656 self.history.start_transaction(now)
657 }
658
659 pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
660 self.end_transaction_at(Instant::now(), cx)
661 }
662
663 pub fn end_transaction_at(
664 &mut self,
665 now: Instant,
666 cx: &mut ModelContext<Self>,
667 ) -> Option<TransactionId> {
668 if let Some(buffer) = self.as_singleton() {
669 return buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx));
670 }
671
672 let mut buffer_transactions = HashMap::default();
673 for BufferState { buffer, .. } in self.buffers.borrow().values() {
674 if let Some(transaction_id) =
675 buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
676 {
677 buffer_transactions.insert(buffer.read(cx).remote_id(), transaction_id);
678 }
679 }
680
681 if self.history.end_transaction(now, buffer_transactions) {
682 let transaction_id = self.history.group().unwrap();
683 Some(transaction_id)
684 } else {
685 None
686 }
687 }
688
689 pub fn merge_transactions(
690 &mut self,
691 transaction: TransactionId,
692 destination: TransactionId,
693 cx: &mut ModelContext<Self>,
694 ) {
695 if let Some(buffer) = self.as_singleton() {
696 buffer.update(cx, |buffer, _| {
697 buffer.merge_transactions(transaction, destination)
698 });
699 } else {
700 if let Some(transaction) = self.history.forget(transaction) {
701 if let Some(destination) = self.history.transaction_mut(destination) {
702 for (buffer_id, buffer_transaction_id) in transaction.buffer_transactions {
703 if let Some(destination_buffer_transaction_id) =
704 destination.buffer_transactions.get(&buffer_id)
705 {
706 if let Some(state) = self.buffers.borrow().get(&buffer_id) {
707 state.buffer.update(cx, |buffer, _| {
708 buffer.merge_transactions(
709 buffer_transaction_id,
710 *destination_buffer_transaction_id,
711 )
712 });
713 }
714 } else {
715 destination
716 .buffer_transactions
717 .insert(buffer_id, buffer_transaction_id);
718 }
719 }
720 }
721 }
722 }
723 }
724
725 pub fn finalize_last_transaction(&mut self, cx: &mut ModelContext<Self>) {
726 self.history.finalize_last_transaction();
727 for BufferState { buffer, .. } in self.buffers.borrow().values() {
728 buffer.update(cx, |buffer, _| {
729 buffer.finalize_last_transaction();
730 });
731 }
732 }
733
734 pub fn push_transaction<'a, T>(&mut self, buffer_transactions: T, cx: &mut ModelContext<Self>)
735 where
736 T: IntoIterator<Item = (&'a Model<Buffer>, &'a language::Transaction)>,
737 {
738 self.history
739 .push_transaction(buffer_transactions, Instant::now(), cx);
740 self.history.finalize_last_transaction();
741 }
742
743 pub fn group_until_transaction(
744 &mut self,
745 transaction_id: TransactionId,
746 cx: &mut ModelContext<Self>,
747 ) {
748 if let Some(buffer) = self.as_singleton() {
749 buffer.update(cx, |buffer, _| {
750 buffer.group_until_transaction(transaction_id)
751 });
752 } else {
753 self.history.group_until(transaction_id);
754 }
755 }
756
757 pub fn set_active_selections(
758 &mut self,
759 selections: &[Selection<Anchor>],
760 line_mode: bool,
761 cursor_shape: CursorShape,
762 cx: &mut ModelContext<Self>,
763 ) {
764 let mut selections_by_buffer: HashMap<BufferId, Vec<Selection<text::Anchor>>> =
765 Default::default();
766 let snapshot = self.read(cx);
767 let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>();
768 for selection in selections {
769 let start_locator = snapshot.excerpt_locator_for_id(selection.start.excerpt_id);
770 let end_locator = snapshot.excerpt_locator_for_id(selection.end.excerpt_id);
771
772 cursor.seek(&Some(start_locator), Bias::Left, &());
773 while let Some(excerpt) = cursor.item() {
774 if excerpt.locator > *end_locator {
775 break;
776 }
777
778 let mut start = excerpt.range.context.start;
779 let mut end = excerpt.range.context.end;
780 if excerpt.id == selection.start.excerpt_id {
781 start = selection.start.text_anchor;
782 }
783 if excerpt.id == selection.end.excerpt_id {
784 end = selection.end.text_anchor;
785 }
786 selections_by_buffer
787 .entry(excerpt.buffer_id)
788 .or_default()
789 .push(Selection {
790 id: selection.id,
791 start,
792 end,
793 reversed: selection.reversed,
794 goal: selection.goal,
795 });
796
797 cursor.next(&());
798 }
799 }
800
801 for (buffer_id, buffer_state) in self.buffers.borrow().iter() {
802 if !selections_by_buffer.contains_key(buffer_id) {
803 buffer_state
804 .buffer
805 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
806 }
807 }
808
809 for (buffer_id, mut selections) in selections_by_buffer {
810 self.buffers.borrow()[&buffer_id]
811 .buffer
812 .update(cx, |buffer, cx| {
813 selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer));
814 let mut selections = selections.into_iter().peekable();
815 let merged_selections = Arc::from_iter(iter::from_fn(|| {
816 let mut selection = selections.next()?;
817 while let Some(next_selection) = selections.peek() {
818 if selection.end.cmp(&next_selection.start, buffer).is_ge() {
819 let next_selection = selections.next().unwrap();
820 if next_selection.end.cmp(&selection.end, buffer).is_ge() {
821 selection.end = next_selection.end;
822 }
823 } else {
824 break;
825 }
826 }
827 Some(selection)
828 }));
829 buffer.set_active_selections(merged_selections, line_mode, cursor_shape, cx);
830 });
831 }
832 }
833
834 pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
835 for buffer in self.buffers.borrow().values() {
836 buffer
837 .buffer
838 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
839 }
840 }
841
842 pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
843 let mut transaction_id = None;
844 if let Some(buffer) = self.as_singleton() {
845 transaction_id = buffer.update(cx, |buffer, cx| buffer.undo(cx));
846 } else {
847 while let Some(transaction) = self.history.pop_undo() {
848 let mut undone = false;
849 for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions {
850 if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
851 undone |= buffer.update(cx, |buffer, cx| {
852 let undo_to = *buffer_transaction_id;
853 if let Some(entry) = buffer.peek_undo_stack() {
854 *buffer_transaction_id = entry.transaction_id();
855 }
856 buffer.undo_to_transaction(undo_to, cx)
857 });
858 }
859 }
860
861 if undone {
862 transaction_id = Some(transaction.id);
863 break;
864 }
865 }
866 }
867
868 if let Some(transaction_id) = transaction_id {
869 cx.emit(Event::TransactionUndone { transaction_id });
870 }
871
872 transaction_id
873 }
874
875 pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
876 if let Some(buffer) = self.as_singleton() {
877 return buffer.update(cx, |buffer, cx| buffer.redo(cx));
878 }
879
880 while let Some(transaction) = self.history.pop_redo() {
881 let mut redone = false;
882 for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions {
883 if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
884 redone |= buffer.update(cx, |buffer, cx| {
885 let redo_to = *buffer_transaction_id;
886 if let Some(entry) = buffer.peek_redo_stack() {
887 *buffer_transaction_id = entry.transaction_id();
888 }
889 buffer.redo_to_transaction(redo_to, cx)
890 });
891 }
892 }
893
894 if redone {
895 return Some(transaction.id);
896 }
897 }
898
899 None
900 }
901
902 pub fn undo_transaction(&mut self, transaction_id: TransactionId, cx: &mut ModelContext<Self>) {
903 if let Some(buffer) = self.as_singleton() {
904 buffer.update(cx, |buffer, cx| buffer.undo_transaction(transaction_id, cx));
905 } else if let Some(transaction) = self.history.remove_from_undo(transaction_id) {
906 for (buffer_id, transaction_id) in &transaction.buffer_transactions {
907 if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
908 buffer.update(cx, |buffer, cx| {
909 buffer.undo_transaction(*transaction_id, cx)
910 });
911 }
912 }
913 }
914 }
915
916 pub fn stream_excerpts_with_context_lines(
917 &mut self,
918 buffer: Model<Buffer>,
919 ranges: Vec<Range<text::Anchor>>,
920 context_line_count: u32,
921 cx: &mut ModelContext<Self>,
922 ) -> mpsc::Receiver<Range<Anchor>> {
923 let (buffer_id, buffer_snapshot) =
924 buffer.update(cx, |buffer, _| (buffer.remote_id(), buffer.snapshot()));
925
926 let (mut tx, rx) = mpsc::channel(256);
927 cx.spawn(move |this, mut cx| async move {
928 let mut excerpt_ranges = Vec::new();
929 let mut range_counts = Vec::new();
930 cx.background_executor()
931 .scoped(|scope| {
932 scope.spawn(async {
933 let (ranges, counts) =
934 build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
935 excerpt_ranges = ranges;
936 range_counts = counts;
937 });
938 })
939 .await;
940
941 let mut ranges = ranges.into_iter();
942 let mut range_counts = range_counts.into_iter();
943 for excerpt_ranges in excerpt_ranges.chunks(100) {
944 let excerpt_ids = match this.update(&mut cx, |this, cx| {
945 this.push_excerpts(buffer.clone(), excerpt_ranges.iter().cloned(), cx)
946 }) {
947 Ok(excerpt_ids) => excerpt_ids,
948 Err(_) => return,
949 };
950
951 for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.by_ref())
952 {
953 for range in ranges.by_ref().take(range_count) {
954 let start = Anchor {
955 buffer_id: Some(buffer_id),
956 excerpt_id: excerpt_id,
957 text_anchor: range.start,
958 };
959 let end = Anchor {
960 buffer_id: Some(buffer_id),
961 excerpt_id: excerpt_id,
962 text_anchor: range.end,
963 };
964 if tx.send(start..end).await.is_err() {
965 break;
966 }
967 }
968 }
969 }
970 })
971 .detach();
972
973 rx
974 }
975
976 pub fn push_excerpts<O>(
977 &mut self,
978 buffer: Model<Buffer>,
979 ranges: impl IntoIterator<Item = ExcerptRange<O>>,
980 cx: &mut ModelContext<Self>,
981 ) -> Vec<ExcerptId>
982 where
983 O: text::ToOffset,
984 {
985 self.insert_excerpts_after(ExcerptId::max(), buffer, ranges, cx)
986 }
987
988 pub fn push_excerpts_with_context_lines<O>(
989 &mut self,
990 buffer: Model<Buffer>,
991 ranges: Vec<Range<O>>,
992 context_line_count: u32,
993 cx: &mut ModelContext<Self>,
994 ) -> Vec<Range<Anchor>>
995 where
996 O: text::ToPoint + text::ToOffset,
997 {
998 let buffer_id = buffer.read(cx).remote_id();
999 let buffer_snapshot = buffer.read(cx).snapshot();
1000 let (excerpt_ranges, range_counts) =
1001 build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
1002
1003 let excerpt_ids = self.push_excerpts(buffer, excerpt_ranges, cx);
1004
1005 let mut anchor_ranges = Vec::new();
1006 let mut ranges = ranges.into_iter();
1007 for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.into_iter()) {
1008 anchor_ranges.extend(ranges.by_ref().take(range_count).map(|range| {
1009 let start = Anchor {
1010 buffer_id: Some(buffer_id),
1011 excerpt_id: excerpt_id,
1012 text_anchor: buffer_snapshot.anchor_after(range.start),
1013 };
1014 let end = Anchor {
1015 buffer_id: Some(buffer_id),
1016 excerpt_id: excerpt_id,
1017 text_anchor: buffer_snapshot.anchor_after(range.end),
1018 };
1019 start..end
1020 }))
1021 }
1022 anchor_ranges
1023 }
1024
1025 pub fn insert_excerpts_after<O>(
1026 &mut self,
1027 prev_excerpt_id: ExcerptId,
1028 buffer: Model<Buffer>,
1029 ranges: impl IntoIterator<Item = ExcerptRange<O>>,
1030 cx: &mut ModelContext<Self>,
1031 ) -> Vec<ExcerptId>
1032 where
1033 O: text::ToOffset,
1034 {
1035 let mut ids = Vec::new();
1036 let mut next_excerpt_id =
1037 if let Some(last_entry) = self.snapshot.borrow().excerpt_ids.last() {
1038 last_entry.id.0 + 1
1039 } else {
1040 1
1041 };
1042 self.insert_excerpts_with_ids_after(
1043 prev_excerpt_id,
1044 buffer,
1045 ranges.into_iter().map(|range| {
1046 let id = ExcerptId(post_inc(&mut next_excerpt_id));
1047 ids.push(id);
1048 (id, range)
1049 }),
1050 cx,
1051 );
1052 ids
1053 }
1054
1055 pub fn insert_excerpts_with_ids_after<O>(
1056 &mut self,
1057 prev_excerpt_id: ExcerptId,
1058 buffer: Model<Buffer>,
1059 ranges: impl IntoIterator<Item = (ExcerptId, ExcerptRange<O>)>,
1060 cx: &mut ModelContext<Self>,
1061 ) where
1062 O: text::ToOffset,
1063 {
1064 assert_eq!(self.history.transaction_depth, 0);
1065 let mut ranges = ranges.into_iter().peekable();
1066 if ranges.peek().is_none() {
1067 return Default::default();
1068 }
1069
1070 self.sync(cx);
1071
1072 let buffer_id = buffer.read(cx).remote_id();
1073 let buffer_snapshot = buffer.read(cx).snapshot();
1074
1075 let mut buffers = self.buffers.borrow_mut();
1076 let buffer_state = buffers.entry(buffer_id).or_insert_with(|| BufferState {
1077 last_version: buffer_snapshot.version().clone(),
1078 last_parse_count: buffer_snapshot.parse_count(),
1079 last_selections_update_count: buffer_snapshot.selections_update_count(),
1080 last_diagnostics_update_count: buffer_snapshot.diagnostics_update_count(),
1081 last_file_update_count: buffer_snapshot.file_update_count(),
1082 last_git_diff_update_count: buffer_snapshot.git_diff_update_count(),
1083 excerpts: Default::default(),
1084 _subscriptions: [
1085 cx.observe(&buffer, |_, _, cx| cx.notify()),
1086 cx.subscribe(&buffer, Self::on_buffer_event),
1087 ],
1088 buffer: buffer.clone(),
1089 });
1090
1091 let mut snapshot = self.snapshot.borrow_mut();
1092
1093 let mut prev_locator = snapshot.excerpt_locator_for_id(prev_excerpt_id).clone();
1094 let mut new_excerpt_ids = mem::take(&mut snapshot.excerpt_ids);
1095 let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>();
1096 let mut new_excerpts = cursor.slice(&prev_locator, Bias::Right, &());
1097 prev_locator = cursor.start().unwrap_or(Locator::min_ref()).clone();
1098
1099 let edit_start = new_excerpts.summary().text.len;
1100 new_excerpts.update_last(
1101 |excerpt| {
1102 excerpt.has_trailing_newline = true;
1103 },
1104 &(),
1105 );
1106
1107 let next_locator = if let Some(excerpt) = cursor.item() {
1108 excerpt.locator.clone()
1109 } else {
1110 Locator::max()
1111 };
1112
1113 let mut excerpts = Vec::new();
1114 while let Some((id, range)) = ranges.next() {
1115 let locator = Locator::between(&prev_locator, &next_locator);
1116 if let Err(ix) = buffer_state.excerpts.binary_search(&locator) {
1117 buffer_state.excerpts.insert(ix, locator.clone());
1118 }
1119 let range = ExcerptRange {
1120 context: buffer_snapshot.anchor_before(&range.context.start)
1121 ..buffer_snapshot.anchor_after(&range.context.end),
1122 primary: range.primary.map(|primary| {
1123 buffer_snapshot.anchor_before(&primary.start)
1124 ..buffer_snapshot.anchor_after(&primary.end)
1125 }),
1126 };
1127 excerpts.push((id, range.clone()));
1128 let excerpt = Excerpt::new(
1129 id,
1130 locator.clone(),
1131 buffer_id,
1132 buffer_snapshot.clone(),
1133 range,
1134 ranges.peek().is_some() || cursor.item().is_some(),
1135 );
1136 new_excerpts.push(excerpt, &());
1137 prev_locator = locator.clone();
1138
1139 if let Some(last_mapping_entry) = new_excerpt_ids.last() {
1140 assert!(id > last_mapping_entry.id, "excerpt ids must be increasing");
1141 }
1142 new_excerpt_ids.push(ExcerptIdMapping { id, locator }, &());
1143 }
1144
1145 let edit_end = new_excerpts.summary().text.len;
1146
1147 let suffix = cursor.suffix(&());
1148 let changed_trailing_excerpt = suffix.is_empty();
1149 new_excerpts.append(suffix, &());
1150 drop(cursor);
1151 snapshot.excerpts = new_excerpts;
1152 snapshot.excerpt_ids = new_excerpt_ids;
1153 if changed_trailing_excerpt {
1154 snapshot.trailing_excerpt_update_count += 1;
1155 }
1156
1157 self.subscriptions.publish_mut([Edit {
1158 old: edit_start..edit_start,
1159 new: edit_start..edit_end,
1160 }]);
1161 cx.emit(Event::Edited {
1162 singleton_buffer_edited: false,
1163 });
1164 cx.emit(Event::ExcerptsAdded {
1165 buffer,
1166 predecessor: prev_excerpt_id,
1167 excerpts,
1168 });
1169 cx.notify();
1170 }
1171
1172 pub fn clear(&mut self, cx: &mut ModelContext<Self>) {
1173 self.sync(cx);
1174 let ids = self.excerpt_ids();
1175 self.buffers.borrow_mut().clear();
1176 let mut snapshot = self.snapshot.borrow_mut();
1177 let prev_len = snapshot.len();
1178 snapshot.excerpts = Default::default();
1179 snapshot.trailing_excerpt_update_count += 1;
1180 snapshot.is_dirty = false;
1181 snapshot.has_conflict = false;
1182
1183 self.subscriptions.publish_mut([Edit {
1184 old: 0..prev_len,
1185 new: 0..0,
1186 }]);
1187 cx.emit(Event::Edited {
1188 singleton_buffer_edited: false,
1189 });
1190 cx.emit(Event::ExcerptsRemoved { ids });
1191 cx.notify();
1192 }
1193
1194 pub fn excerpts_for_buffer(
1195 &self,
1196 buffer: &Model<Buffer>,
1197 cx: &AppContext,
1198 ) -> Vec<(ExcerptId, ExcerptRange<text::Anchor>)> {
1199 let mut excerpts = Vec::new();
1200 let snapshot = self.read(cx);
1201 let buffers = self.buffers.borrow();
1202 let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>();
1203 for locator in buffers
1204 .get(&buffer.read(cx).remote_id())
1205 .map(|state| &state.excerpts)
1206 .into_iter()
1207 .flatten()
1208 {
1209 cursor.seek_forward(&Some(locator), Bias::Left, &());
1210 if let Some(excerpt) = cursor.item() {
1211 if excerpt.locator == *locator {
1212 excerpts.push((excerpt.id, excerpt.range.clone()));
1213 }
1214 }
1215 }
1216
1217 excerpts
1218 }
1219
1220 pub fn excerpt_ids(&self) -> Vec<ExcerptId> {
1221 self.snapshot
1222 .borrow()
1223 .excerpts
1224 .iter()
1225 .map(|entry| entry.id)
1226 .collect()
1227 }
1228
1229 pub fn excerpt_containing(
1230 &self,
1231 position: impl ToOffset,
1232 cx: &AppContext,
1233 ) -> Option<(ExcerptId, Model<Buffer>, Range<text::Anchor>)> {
1234 let snapshot = self.read(cx);
1235 let position = position.to_offset(&snapshot);
1236
1237 let mut cursor = snapshot.excerpts.cursor::<usize>();
1238 cursor.seek(&position, Bias::Right, &());
1239 cursor
1240 .item()
1241 .or_else(|| snapshot.excerpts.last())
1242 .map(|excerpt| {
1243 (
1244 excerpt.id,
1245 self.buffers
1246 .borrow()
1247 .get(&excerpt.buffer_id)
1248 .unwrap()
1249 .buffer
1250 .clone(),
1251 excerpt.range.context.clone(),
1252 )
1253 })
1254 }
1255
1256 // If point is at the end of the buffer, the last excerpt is returned
1257 pub fn point_to_buffer_offset<T: ToOffset>(
1258 &self,
1259 point: T,
1260 cx: &AppContext,
1261 ) -> Option<(Model<Buffer>, usize, ExcerptId)> {
1262 let snapshot = self.read(cx);
1263 let offset = point.to_offset(&snapshot);
1264 let mut cursor = snapshot.excerpts.cursor::<usize>();
1265 cursor.seek(&offset, Bias::Right, &());
1266 if cursor.item().is_none() {
1267 cursor.prev(&());
1268 }
1269
1270 cursor.item().map(|excerpt| {
1271 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
1272 let buffer_point = excerpt_start + offset - *cursor.start();
1273 let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone();
1274
1275 (buffer, buffer_point, excerpt.id)
1276 })
1277 }
1278
1279 pub fn range_to_buffer_ranges<T: ToOffset>(
1280 &self,
1281 range: Range<T>,
1282 cx: &AppContext,
1283 ) -> Vec<(Model<Buffer>, Range<usize>, ExcerptId)> {
1284 let snapshot = self.read(cx);
1285 let start = range.start.to_offset(&snapshot);
1286 let end = range.end.to_offset(&snapshot);
1287
1288 let mut result = Vec::new();
1289 let mut cursor = snapshot.excerpts.cursor::<usize>();
1290 cursor.seek(&start, Bias::Right, &());
1291 if cursor.item().is_none() {
1292 cursor.prev(&());
1293 }
1294
1295 while let Some(excerpt) = cursor.item() {
1296 if *cursor.start() > end {
1297 break;
1298 }
1299
1300 let mut end_before_newline = cursor.end(&());
1301 if excerpt.has_trailing_newline {
1302 end_before_newline -= 1;
1303 }
1304 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
1305 let start = excerpt_start + (cmp::max(start, *cursor.start()) - *cursor.start());
1306 let end = excerpt_start + (cmp::min(end, end_before_newline) - *cursor.start());
1307 let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone();
1308 result.push((buffer, start..end, excerpt.id));
1309 cursor.next(&());
1310 }
1311
1312 result
1313 }
1314
1315 pub fn remove_excerpts(
1316 &mut self,
1317 excerpt_ids: impl IntoIterator<Item = ExcerptId>,
1318 cx: &mut ModelContext<Self>,
1319 ) {
1320 self.sync(cx);
1321 let ids = excerpt_ids.into_iter().collect::<Vec<_>>();
1322 if ids.is_empty() {
1323 return;
1324 }
1325
1326 let mut buffers = self.buffers.borrow_mut();
1327 let mut snapshot = self.snapshot.borrow_mut();
1328 let mut new_excerpts = SumTree::new();
1329 let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>();
1330 let mut edits = Vec::new();
1331 let mut excerpt_ids = ids.iter().copied().peekable();
1332
1333 while let Some(excerpt_id) = excerpt_ids.next() {
1334 // Seek to the next excerpt to remove, preserving any preceding excerpts.
1335 let locator = snapshot.excerpt_locator_for_id(excerpt_id);
1336 new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &());
1337
1338 if let Some(mut excerpt) = cursor.item() {
1339 if excerpt.id != excerpt_id {
1340 continue;
1341 }
1342 let mut old_start = cursor.start().1;
1343
1344 // Skip over the removed excerpt.
1345 'remove_excerpts: loop {
1346 if let Some(buffer_state) = buffers.get_mut(&excerpt.buffer_id) {
1347 buffer_state.excerpts.retain(|l| l != &excerpt.locator);
1348 if buffer_state.excerpts.is_empty() {
1349 buffers.remove(&excerpt.buffer_id);
1350 }
1351 }
1352 cursor.next(&());
1353
1354 // Skip over any subsequent excerpts that are also removed.
1355 if let Some(&next_excerpt_id) = excerpt_ids.peek() {
1356 let next_locator = snapshot.excerpt_locator_for_id(next_excerpt_id);
1357 if let Some(next_excerpt) = cursor.item() {
1358 if next_excerpt.locator == *next_locator {
1359 excerpt_ids.next();
1360 excerpt = next_excerpt;
1361 continue 'remove_excerpts;
1362 }
1363 }
1364 }
1365
1366 break;
1367 }
1368
1369 // When removing the last excerpt, remove the trailing newline from
1370 // the previous excerpt.
1371 if cursor.item().is_none() && old_start > 0 {
1372 old_start -= 1;
1373 new_excerpts.update_last(|e| e.has_trailing_newline = false, &());
1374 }
1375
1376 // Push an edit for the removal of this run of excerpts.
1377 let old_end = cursor.start().1;
1378 let new_start = new_excerpts.summary().text.len;
1379 edits.push(Edit {
1380 old: old_start..old_end,
1381 new: new_start..new_start,
1382 });
1383 }
1384 }
1385 let suffix = cursor.suffix(&());
1386 let changed_trailing_excerpt = suffix.is_empty();
1387 new_excerpts.append(suffix, &());
1388 drop(cursor);
1389 snapshot.excerpts = new_excerpts;
1390
1391 if changed_trailing_excerpt {
1392 snapshot.trailing_excerpt_update_count += 1;
1393 }
1394
1395 self.subscriptions.publish_mut(edits);
1396 cx.emit(Event::Edited {
1397 singleton_buffer_edited: false,
1398 });
1399 cx.emit(Event::ExcerptsRemoved { ids });
1400 cx.notify();
1401 }
1402
1403 pub fn wait_for_anchors<'a>(
1404 &self,
1405 anchors: impl 'a + Iterator<Item = Anchor>,
1406 cx: &mut ModelContext<Self>,
1407 ) -> impl 'static + Future<Output = Result<()>> {
1408 let borrow = self.buffers.borrow();
1409 let mut error = None;
1410 let mut futures = Vec::new();
1411 for anchor in anchors {
1412 if let Some(buffer_id) = anchor.buffer_id {
1413 if let Some(buffer) = borrow.get(&buffer_id) {
1414 buffer.buffer.update(cx, |buffer, _| {
1415 futures.push(buffer.wait_for_anchors([anchor.text_anchor]))
1416 });
1417 } else {
1418 error = Some(anyhow!(
1419 "buffer {buffer_id} is not part of this multi-buffer"
1420 ));
1421 break;
1422 }
1423 }
1424 }
1425 async move {
1426 if let Some(error) = error {
1427 Err(error)?;
1428 }
1429 for future in futures {
1430 future.await?;
1431 }
1432 Ok(())
1433 }
1434 }
1435
1436 pub fn text_anchor_for_position<T: ToOffset>(
1437 &self,
1438 position: T,
1439 cx: &AppContext,
1440 ) -> Option<(Model<Buffer>, language::Anchor)> {
1441 let snapshot = self.read(cx);
1442 let anchor = snapshot.anchor_before(position);
1443 let buffer = self
1444 .buffers
1445 .borrow()
1446 .get(&anchor.buffer_id?)?
1447 .buffer
1448 .clone();
1449 Some((buffer, anchor.text_anchor))
1450 }
1451
1452 fn on_buffer_event(
1453 &mut self,
1454 buffer: Model<Buffer>,
1455 event: &language::Event,
1456 cx: &mut ModelContext<Self>,
1457 ) {
1458 cx.emit(match event {
1459 language::Event::Edited => Event::Edited {
1460 singleton_buffer_edited: true,
1461 },
1462 language::Event::DirtyChanged => Event::DirtyChanged,
1463 language::Event::Saved => Event::Saved,
1464 language::Event::FileHandleChanged => Event::FileHandleChanged,
1465 language::Event::Reloaded => Event::Reloaded,
1466 language::Event::DiffBaseChanged => Event::DiffBaseChanged,
1467 language::Event::LanguageChanged => Event::LanguageChanged,
1468 language::Event::Reparsed => Event::Reparsed,
1469 language::Event::DiagnosticsUpdated => Event::DiagnosticsUpdated,
1470 language::Event::Closed => Event::Closed,
1471 language::Event::CapabilityChanged => {
1472 self.capability = buffer.read(cx).capability();
1473 Event::CapabilityChanged
1474 }
1475
1476 //
1477 language::Event::Operation(_) => return,
1478 });
1479 }
1480
1481 pub fn all_buffers(&self) -> HashSet<Model<Buffer>> {
1482 self.buffers
1483 .borrow()
1484 .values()
1485 .map(|state| state.buffer.clone())
1486 .collect()
1487 }
1488
1489 pub fn buffer(&self, buffer_id: BufferId) -> Option<Model<Buffer>> {
1490 self.buffers
1491 .borrow()
1492 .get(&buffer_id)
1493 .map(|state| state.buffer.clone())
1494 }
1495
1496 pub fn is_completion_trigger(&self, position: Anchor, text: &str, cx: &AppContext) -> bool {
1497 let mut chars = text.chars();
1498 let char = if let Some(char) = chars.next() {
1499 char
1500 } else {
1501 return false;
1502 };
1503 if chars.next().is_some() {
1504 return false;
1505 }
1506
1507 let snapshot = self.snapshot(cx);
1508 let position = position.to_offset(&snapshot);
1509 let scope = snapshot.language_scope_at(position);
1510 if char_kind(&scope, char) == CharKind::Word {
1511 return true;
1512 }
1513
1514 let anchor = snapshot.anchor_before(position);
1515 anchor
1516 .buffer_id
1517 .and_then(|buffer_id| {
1518 let buffer = self.buffers.borrow().get(&buffer_id)?.buffer.clone();
1519 Some(
1520 buffer
1521 .read(cx)
1522 .completion_triggers()
1523 .iter()
1524 .any(|string| string == text),
1525 )
1526 })
1527 .unwrap_or(false)
1528 }
1529
1530 pub fn language_at<T: ToOffset>(&self, point: T, cx: &AppContext) -> Option<Arc<Language>> {
1531 self.point_to_buffer_offset(point, cx)
1532 .and_then(|(buffer, offset, _)| buffer.read(cx).language_at(offset))
1533 }
1534
1535 pub fn settings_at<'a, T: ToOffset>(
1536 &self,
1537 point: T,
1538 cx: &'a AppContext,
1539 ) -> &'a LanguageSettings {
1540 let mut language = None;
1541 let mut file = None;
1542 if let Some((buffer, offset, _)) = self.point_to_buffer_offset(point, cx) {
1543 let buffer = buffer.read(cx);
1544 language = buffer.language_at(offset);
1545 file = buffer.file();
1546 }
1547 language_settings(language.as_ref(), file, cx)
1548 }
1549
1550 pub fn for_each_buffer(&self, mut f: impl FnMut(&Model<Buffer>)) {
1551 self.buffers
1552 .borrow()
1553 .values()
1554 .for_each(|state| f(&state.buffer))
1555 }
1556
1557 pub fn title<'a>(&'a self, cx: &'a AppContext) -> Cow<'a, str> {
1558 if let Some(title) = self.title.as_ref() {
1559 return title.into();
1560 }
1561
1562 if let Some(buffer) = self.as_singleton() {
1563 if let Some(file) = buffer.read(cx).file() {
1564 return file.file_name(cx).to_string_lossy();
1565 }
1566 }
1567
1568 "untitled".into()
1569 }
1570
1571 #[cfg(any(test, feature = "test-support"))]
1572 pub fn is_parsing(&self, cx: &AppContext) -> bool {
1573 self.as_singleton().unwrap().read(cx).is_parsing()
1574 }
1575
1576 fn sync(&self, cx: &AppContext) {
1577 let mut snapshot = self.snapshot.borrow_mut();
1578 let mut excerpts_to_edit = Vec::new();
1579 let mut reparsed = false;
1580 let mut diagnostics_updated = false;
1581 let mut git_diff_updated = false;
1582 let mut is_dirty = false;
1583 let mut has_conflict = false;
1584 let mut edited = false;
1585 let mut buffers = self.buffers.borrow_mut();
1586 for buffer_state in buffers.values_mut() {
1587 let buffer = buffer_state.buffer.read(cx);
1588 let version = buffer.version();
1589 let parse_count = buffer.parse_count();
1590 let selections_update_count = buffer.selections_update_count();
1591 let diagnostics_update_count = buffer.diagnostics_update_count();
1592 let file_update_count = buffer.file_update_count();
1593 let git_diff_update_count = buffer.git_diff_update_count();
1594
1595 let buffer_edited = version.changed_since(&buffer_state.last_version);
1596 let buffer_reparsed = parse_count > buffer_state.last_parse_count;
1597 let buffer_selections_updated =
1598 selections_update_count > buffer_state.last_selections_update_count;
1599 let buffer_diagnostics_updated =
1600 diagnostics_update_count > buffer_state.last_diagnostics_update_count;
1601 let buffer_file_updated = file_update_count > buffer_state.last_file_update_count;
1602 let buffer_git_diff_updated =
1603 git_diff_update_count > buffer_state.last_git_diff_update_count;
1604 if buffer_edited
1605 || buffer_reparsed
1606 || buffer_selections_updated
1607 || buffer_diagnostics_updated
1608 || buffer_file_updated
1609 || buffer_git_diff_updated
1610 {
1611 buffer_state.last_version = version;
1612 buffer_state.last_parse_count = parse_count;
1613 buffer_state.last_selections_update_count = selections_update_count;
1614 buffer_state.last_diagnostics_update_count = diagnostics_update_count;
1615 buffer_state.last_file_update_count = file_update_count;
1616 buffer_state.last_git_diff_update_count = git_diff_update_count;
1617 excerpts_to_edit.extend(
1618 buffer_state
1619 .excerpts
1620 .iter()
1621 .map(|locator| (locator, buffer_state.buffer.clone(), buffer_edited)),
1622 );
1623 }
1624
1625 edited |= buffer_edited;
1626 reparsed |= buffer_reparsed;
1627 diagnostics_updated |= buffer_diagnostics_updated;
1628 git_diff_updated |= buffer_git_diff_updated;
1629 is_dirty |= buffer.is_dirty();
1630 has_conflict |= buffer.has_conflict();
1631 }
1632 if edited {
1633 snapshot.edit_count += 1;
1634 }
1635 if reparsed {
1636 snapshot.parse_count += 1;
1637 }
1638 if diagnostics_updated {
1639 snapshot.diagnostics_update_count += 1;
1640 }
1641 if git_diff_updated {
1642 snapshot.git_diff_update_count += 1;
1643 }
1644 snapshot.is_dirty = is_dirty;
1645 snapshot.has_conflict = has_conflict;
1646
1647 excerpts_to_edit.sort_unstable_by_key(|(locator, _, _)| *locator);
1648
1649 let mut edits = Vec::new();
1650 let mut new_excerpts = SumTree::new();
1651 let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>();
1652
1653 for (locator, buffer, buffer_edited) in excerpts_to_edit {
1654 new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &());
1655 let old_excerpt = cursor.item().unwrap();
1656 let buffer = buffer.read(cx);
1657 let buffer_id = buffer.remote_id();
1658
1659 let mut new_excerpt;
1660 if buffer_edited {
1661 edits.extend(
1662 buffer
1663 .edits_since_in_range::<usize>(
1664 old_excerpt.buffer.version(),
1665 old_excerpt.range.context.clone(),
1666 )
1667 .map(|mut edit| {
1668 let excerpt_old_start = cursor.start().1;
1669 let excerpt_new_start = new_excerpts.summary().text.len;
1670 edit.old.start += excerpt_old_start;
1671 edit.old.end += excerpt_old_start;
1672 edit.new.start += excerpt_new_start;
1673 edit.new.end += excerpt_new_start;
1674 edit
1675 }),
1676 );
1677
1678 new_excerpt = Excerpt::new(
1679 old_excerpt.id,
1680 locator.clone(),
1681 buffer_id,
1682 buffer.snapshot(),
1683 old_excerpt.range.clone(),
1684 old_excerpt.has_trailing_newline,
1685 );
1686 } else {
1687 new_excerpt = old_excerpt.clone();
1688 new_excerpt.buffer = buffer.snapshot();
1689 }
1690
1691 new_excerpts.push(new_excerpt, &());
1692 cursor.next(&());
1693 }
1694 new_excerpts.append(cursor.suffix(&()), &());
1695
1696 drop(cursor);
1697 snapshot.excerpts = new_excerpts;
1698
1699 self.subscriptions.publish(edits);
1700 }
1701}
1702
1703#[cfg(any(test, feature = "test-support"))]
1704impl MultiBuffer {
1705 pub fn build_simple(text: &str, cx: &mut gpui::AppContext) -> Model<Self> {
1706 let buffer = cx.new_model(|cx| Buffer::local(text, cx));
1707 cx.new_model(|cx| Self::singleton(buffer, cx))
1708 }
1709
1710 pub fn build_multi<const COUNT: usize>(
1711 excerpts: [(&str, Vec<Range<Point>>); COUNT],
1712 cx: &mut gpui::AppContext,
1713 ) -> Model<Self> {
1714 let multi = cx.new_model(|_| Self::new(0, Capability::ReadWrite));
1715 for (text, ranges) in excerpts {
1716 let buffer = cx.new_model(|cx| Buffer::local(text, cx));
1717 let excerpt_ranges = ranges.into_iter().map(|range| ExcerptRange {
1718 context: range,
1719 primary: None,
1720 });
1721 multi.update(cx, |multi, cx| {
1722 multi.push_excerpts(buffer, excerpt_ranges, cx)
1723 });
1724 }
1725
1726 multi
1727 }
1728
1729 pub fn build_from_buffer(buffer: Model<Buffer>, cx: &mut gpui::AppContext) -> Model<Self> {
1730 cx.new_model(|cx| Self::singleton(buffer, cx))
1731 }
1732
1733 pub fn build_random(rng: &mut impl rand::Rng, cx: &mut gpui::AppContext) -> Model<Self> {
1734 cx.new_model(|cx| {
1735 let mut multibuffer = MultiBuffer::new(0, Capability::ReadWrite);
1736 let mutation_count = rng.gen_range(1..=5);
1737 multibuffer.randomly_edit_excerpts(rng, mutation_count, cx);
1738 multibuffer
1739 })
1740 }
1741
1742 pub fn randomly_edit(
1743 &mut self,
1744 rng: &mut impl rand::Rng,
1745 edit_count: usize,
1746 cx: &mut ModelContext<Self>,
1747 ) {
1748 use util::RandomCharIter;
1749
1750 let snapshot = self.read(cx);
1751 let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
1752 let mut last_end = None;
1753 for _ in 0..edit_count {
1754 if last_end.map_or(false, |last_end| last_end >= snapshot.len()) {
1755 break;
1756 }
1757
1758 let new_start = last_end.map_or(0, |last_end| last_end + 1);
1759 let end = snapshot.clip_offset(rng.gen_range(new_start..=snapshot.len()), Bias::Right);
1760 let start = snapshot.clip_offset(rng.gen_range(new_start..=end), Bias::Right);
1761 last_end = Some(end);
1762
1763 let mut range = start..end;
1764 if rng.gen_bool(0.2) {
1765 mem::swap(&mut range.start, &mut range.end);
1766 }
1767
1768 let new_text_len = rng.gen_range(0..10);
1769 let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
1770
1771 edits.push((range, new_text.into()));
1772 }
1773 log::info!("mutating multi-buffer with {:?}", edits);
1774 drop(snapshot);
1775
1776 self.edit(edits, None, cx);
1777 }
1778
1779 pub fn randomly_edit_excerpts(
1780 &mut self,
1781 rng: &mut impl rand::Rng,
1782 mutation_count: usize,
1783 cx: &mut ModelContext<Self>,
1784 ) {
1785 use rand::prelude::*;
1786 use std::env;
1787 use util::RandomCharIter;
1788
1789 let max_excerpts = env::var("MAX_EXCERPTS")
1790 .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))
1791 .unwrap_or(5);
1792
1793 let mut buffers = Vec::new();
1794 for _ in 0..mutation_count {
1795 if rng.gen_bool(0.05) {
1796 log::info!("Clearing multi-buffer");
1797 self.clear(cx);
1798 continue;
1799 }
1800
1801 let excerpt_ids = self.excerpt_ids();
1802 if excerpt_ids.is_empty() || (rng.gen() && excerpt_ids.len() < max_excerpts) {
1803 let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() {
1804 let text = RandomCharIter::new(&mut *rng).take(10).collect::<String>();
1805 buffers.push(cx.new_model(|cx| Buffer::local(text, cx)));
1806 let buffer = buffers.last().unwrap().read(cx);
1807 log::info!(
1808 "Creating new buffer {} with text: {:?}",
1809 buffer.remote_id(),
1810 buffer.text()
1811 );
1812 buffers.last().unwrap().clone()
1813 } else {
1814 self.buffers
1815 .borrow()
1816 .values()
1817 .choose(rng)
1818 .unwrap()
1819 .buffer
1820 .clone()
1821 };
1822
1823 let buffer = buffer_handle.read(cx);
1824 let buffer_text = buffer.text();
1825 let ranges = (0..rng.gen_range(0..5))
1826 .map(|_| {
1827 let end_ix =
1828 buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
1829 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
1830 ExcerptRange {
1831 context: start_ix..end_ix,
1832 primary: None,
1833 }
1834 })
1835 .collect::<Vec<_>>();
1836 log::info!(
1837 "Inserting excerpts from buffer {} and ranges {:?}: {:?}",
1838 buffer_handle.read(cx).remote_id(),
1839 ranges.iter().map(|r| &r.context).collect::<Vec<_>>(),
1840 ranges
1841 .iter()
1842 .map(|r| &buffer_text[r.context.clone()])
1843 .collect::<Vec<_>>()
1844 );
1845
1846 let excerpt_id = self.push_excerpts(buffer_handle.clone(), ranges, cx);
1847 log::info!("Inserted with ids: {:?}", excerpt_id);
1848 } else {
1849 let remove_count = rng.gen_range(1..=excerpt_ids.len());
1850 let mut excerpts_to_remove = excerpt_ids
1851 .choose_multiple(rng, remove_count)
1852 .cloned()
1853 .collect::<Vec<_>>();
1854 let snapshot = self.snapshot.borrow();
1855 excerpts_to_remove.sort_unstable_by(|a, b| a.cmp(b, &snapshot));
1856 drop(snapshot);
1857 log::info!("Removing excerpts {:?}", excerpts_to_remove);
1858 self.remove_excerpts(excerpts_to_remove, cx);
1859 }
1860 }
1861 }
1862
1863 pub fn randomly_mutate(
1864 &mut self,
1865 rng: &mut impl rand::Rng,
1866 mutation_count: usize,
1867 cx: &mut ModelContext<Self>,
1868 ) {
1869 use rand::prelude::*;
1870
1871 if rng.gen_bool(0.7) || self.singleton {
1872 let buffer = self
1873 .buffers
1874 .borrow()
1875 .values()
1876 .choose(rng)
1877 .map(|state| state.buffer.clone());
1878
1879 if let Some(buffer) = buffer {
1880 buffer.update(cx, |buffer, cx| {
1881 if rng.gen() {
1882 buffer.randomly_edit(rng, mutation_count, cx);
1883 } else {
1884 buffer.randomly_undo_redo(rng, cx);
1885 }
1886 });
1887 } else {
1888 self.randomly_edit(rng, mutation_count, cx);
1889 }
1890 } else {
1891 self.randomly_edit_excerpts(rng, mutation_count, cx);
1892 }
1893
1894 self.check_invariants(cx);
1895 }
1896
1897 fn check_invariants(&self, cx: &mut ModelContext<Self>) {
1898 let snapshot = self.read(cx);
1899 let excerpts = snapshot.excerpts.items(&());
1900 let excerpt_ids = snapshot.excerpt_ids.items(&());
1901
1902 for (ix, excerpt) in excerpts.iter().enumerate() {
1903 if ix == 0 {
1904 if excerpt.locator <= Locator::min() {
1905 panic!("invalid first excerpt locator {:?}", excerpt.locator);
1906 }
1907 } else {
1908 if excerpt.locator <= excerpts[ix - 1].locator {
1909 panic!("excerpts are out-of-order: {:?}", excerpts);
1910 }
1911 }
1912 }
1913
1914 for (ix, entry) in excerpt_ids.iter().enumerate() {
1915 if ix == 0 {
1916 if entry.id.cmp(&ExcerptId::min(), &snapshot).is_le() {
1917 panic!("invalid first excerpt id {:?}", entry.id);
1918 }
1919 } else {
1920 if entry.id <= excerpt_ids[ix - 1].id {
1921 panic!("excerpt ids are out-of-order: {:?}", excerpt_ids);
1922 }
1923 }
1924 }
1925 }
1926}
1927
1928impl EventEmitter<Event> for MultiBuffer {}
1929
1930impl MultiBufferSnapshot {
1931 pub fn text(&self) -> String {
1932 self.chunks(0..self.len(), false)
1933 .map(|chunk| chunk.text)
1934 .collect()
1935 }
1936
1937 pub fn reversed_chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
1938 let mut offset = position.to_offset(self);
1939 let mut cursor = self.excerpts.cursor::<usize>();
1940 cursor.seek(&offset, Bias::Left, &());
1941 let mut excerpt_chunks = cursor.item().map(|excerpt| {
1942 let end_before_footer = cursor.start() + excerpt.text_summary.len;
1943 let start = excerpt.range.context.start.to_offset(&excerpt.buffer);
1944 let end = start + (cmp::min(offset, end_before_footer) - cursor.start());
1945 excerpt.buffer.reversed_chunks_in_range(start..end)
1946 });
1947 iter::from_fn(move || {
1948 if offset == *cursor.start() {
1949 cursor.prev(&());
1950 let excerpt = cursor.item()?;
1951 excerpt_chunks = Some(
1952 excerpt
1953 .buffer
1954 .reversed_chunks_in_range(excerpt.range.context.clone()),
1955 );
1956 }
1957
1958 let excerpt = cursor.item().unwrap();
1959 if offset == cursor.end(&()) && excerpt.has_trailing_newline {
1960 offset -= 1;
1961 Some("\n")
1962 } else {
1963 let chunk = excerpt_chunks.as_mut().unwrap().next().unwrap();
1964 offset -= chunk.len();
1965 Some(chunk)
1966 }
1967 })
1968 .flat_map(|c| c.chars().rev())
1969 }
1970
1971 pub fn chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
1972 let offset = position.to_offset(self);
1973 self.text_for_range(offset..self.len())
1974 .flat_map(|chunk| chunk.chars())
1975 }
1976
1977 pub fn text_for_range<T: ToOffset>(&self, range: Range<T>) -> impl Iterator<Item = &str> + '_ {
1978 self.chunks(range, false).map(|chunk| chunk.text)
1979 }
1980
1981 pub fn is_line_blank(&self, row: u32) -> bool {
1982 self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row)))
1983 .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
1984 }
1985
1986 pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
1987 where
1988 T: ToOffset,
1989 {
1990 let position = position.to_offset(self);
1991 position == self.clip_offset(position, Bias::Left)
1992 && self
1993 .bytes_in_range(position..self.len())
1994 .flatten()
1995 .copied()
1996 .take(needle.len())
1997 .eq(needle.bytes())
1998 }
1999
2000 pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) {
2001 let mut start = start.to_offset(self);
2002 let mut end = start;
2003 let mut next_chars = self.chars_at(start).peekable();
2004 let mut prev_chars = self.reversed_chars_at(start).peekable();
2005
2006 let scope = self.language_scope_at(start);
2007 let kind = |c| char_kind(&scope, c);
2008 let word_kind = cmp::max(
2009 prev_chars.peek().copied().map(kind),
2010 next_chars.peek().copied().map(kind),
2011 );
2012
2013 for ch in prev_chars {
2014 if Some(kind(ch)) == word_kind && ch != '\n' {
2015 start -= ch.len_utf8();
2016 } else {
2017 break;
2018 }
2019 }
2020
2021 for ch in next_chars {
2022 if Some(kind(ch)) == word_kind && ch != '\n' {
2023 end += ch.len_utf8();
2024 } else {
2025 break;
2026 }
2027 }
2028
2029 (start..end, word_kind)
2030 }
2031
2032 pub fn as_singleton(&self) -> Option<(&ExcerptId, BufferId, &BufferSnapshot)> {
2033 if self.singleton {
2034 self.excerpts
2035 .iter()
2036 .next()
2037 .map(|e| (&e.id, e.buffer_id, &e.buffer))
2038 } else {
2039 None
2040 }
2041 }
2042
2043 pub fn len(&self) -> usize {
2044 self.excerpts.summary().text.len
2045 }
2046
2047 pub fn is_empty(&self) -> bool {
2048 self.excerpts.summary().text.len == 0
2049 }
2050
2051 pub fn max_buffer_row(&self) -> u32 {
2052 self.excerpts.summary().max_buffer_row
2053 }
2054
2055 pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
2056 if let Some((_, _, buffer)) = self.as_singleton() {
2057 return buffer.clip_offset(offset, bias);
2058 }
2059
2060 let mut cursor = self.excerpts.cursor::<usize>();
2061 cursor.seek(&offset, Bias::Right, &());
2062 let overshoot = if let Some(excerpt) = cursor.item() {
2063 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2064 let buffer_offset = excerpt
2065 .buffer
2066 .clip_offset(excerpt_start + (offset - cursor.start()), bias);
2067 buffer_offset.saturating_sub(excerpt_start)
2068 } else {
2069 0
2070 };
2071 cursor.start() + overshoot
2072 }
2073
2074 pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
2075 if let Some((_, _, buffer)) = self.as_singleton() {
2076 return buffer.clip_point(point, bias);
2077 }
2078
2079 let mut cursor = self.excerpts.cursor::<Point>();
2080 cursor.seek(&point, Bias::Right, &());
2081 let overshoot = if let Some(excerpt) = cursor.item() {
2082 let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
2083 let buffer_point = excerpt
2084 .buffer
2085 .clip_point(excerpt_start + (point - cursor.start()), bias);
2086 buffer_point.saturating_sub(excerpt_start)
2087 } else {
2088 Point::zero()
2089 };
2090 *cursor.start() + overshoot
2091 }
2092
2093 pub fn clip_offset_utf16(&self, offset: OffsetUtf16, bias: Bias) -> OffsetUtf16 {
2094 if let Some((_, _, buffer)) = self.as_singleton() {
2095 return buffer.clip_offset_utf16(offset, bias);
2096 }
2097
2098 let mut cursor = self.excerpts.cursor::<OffsetUtf16>();
2099 cursor.seek(&offset, Bias::Right, &());
2100 let overshoot = if let Some(excerpt) = cursor.item() {
2101 let excerpt_start = excerpt.range.context.start.to_offset_utf16(&excerpt.buffer);
2102 let buffer_offset = excerpt
2103 .buffer
2104 .clip_offset_utf16(excerpt_start + (offset - cursor.start()), bias);
2105 OffsetUtf16(buffer_offset.0.saturating_sub(excerpt_start.0))
2106 } else {
2107 OffsetUtf16(0)
2108 };
2109 *cursor.start() + overshoot
2110 }
2111
2112 pub fn clip_point_utf16(&self, point: Unclipped<PointUtf16>, bias: Bias) -> PointUtf16 {
2113 if let Some((_, _, buffer)) = self.as_singleton() {
2114 return buffer.clip_point_utf16(point, bias);
2115 }
2116
2117 let mut cursor = self.excerpts.cursor::<PointUtf16>();
2118 cursor.seek(&point.0, Bias::Right, &());
2119 let overshoot = if let Some(excerpt) = cursor.item() {
2120 let excerpt_start = excerpt
2121 .buffer
2122 .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
2123 let buffer_point = excerpt
2124 .buffer
2125 .clip_point_utf16(Unclipped(excerpt_start + (point.0 - cursor.start())), bias);
2126 buffer_point.saturating_sub(excerpt_start)
2127 } else {
2128 PointUtf16::zero()
2129 };
2130 *cursor.start() + overshoot
2131 }
2132
2133 pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> MultiBufferBytes {
2134 let range = range.start.to_offset(self)..range.end.to_offset(self);
2135 let mut excerpts = self.excerpts.cursor::<usize>();
2136 excerpts.seek(&range.start, Bias::Right, &());
2137
2138 let mut chunk = &[][..];
2139 let excerpt_bytes = if let Some(excerpt) = excerpts.item() {
2140 let mut excerpt_bytes = excerpt
2141 .bytes_in_range(range.start - excerpts.start()..range.end - excerpts.start());
2142 chunk = excerpt_bytes.next().unwrap_or(&[][..]);
2143 Some(excerpt_bytes)
2144 } else {
2145 None
2146 };
2147 MultiBufferBytes {
2148 range,
2149 excerpts,
2150 excerpt_bytes,
2151 chunk,
2152 }
2153 }
2154
2155 pub fn reversed_bytes_in_range<T: ToOffset>(
2156 &self,
2157 range: Range<T>,
2158 ) -> ReversedMultiBufferBytes {
2159 let range = range.start.to_offset(self)..range.end.to_offset(self);
2160 let mut excerpts = self.excerpts.cursor::<usize>();
2161 excerpts.seek(&range.end, Bias::Left, &());
2162
2163 let mut chunk = &[][..];
2164 let excerpt_bytes = if let Some(excerpt) = excerpts.item() {
2165 let mut excerpt_bytes = excerpt.reversed_bytes_in_range(
2166 range.start.saturating_sub(*excerpts.start())..range.end - *excerpts.start(),
2167 );
2168 chunk = excerpt_bytes.next().unwrap_or(&[][..]);
2169 Some(excerpt_bytes)
2170 } else {
2171 None
2172 };
2173
2174 ReversedMultiBufferBytes {
2175 range,
2176 excerpts,
2177 excerpt_bytes,
2178 chunk,
2179 }
2180 }
2181
2182 pub fn buffer_rows(&self, start_row: u32) -> MultiBufferRows {
2183 let mut result = MultiBufferRows {
2184 buffer_row_range: 0..0,
2185 excerpts: self.excerpts.cursor(),
2186 };
2187 result.seek(start_row);
2188 result
2189 }
2190
2191 pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> MultiBufferChunks {
2192 let range = range.start.to_offset(self)..range.end.to_offset(self);
2193 let mut chunks = MultiBufferChunks {
2194 range: range.clone(),
2195 excerpts: self.excerpts.cursor(),
2196 excerpt_chunks: None,
2197 language_aware,
2198 };
2199 chunks.seek(range.start);
2200 chunks
2201 }
2202
2203 pub fn offset_to_point(&self, offset: usize) -> Point {
2204 if let Some((_, _, buffer)) = self.as_singleton() {
2205 return buffer.offset_to_point(offset);
2206 }
2207
2208 let mut cursor = self.excerpts.cursor::<(usize, Point)>();
2209 cursor.seek(&offset, Bias::Right, &());
2210 if let Some(excerpt) = cursor.item() {
2211 let (start_offset, start_point) = cursor.start();
2212 let overshoot = offset - start_offset;
2213 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2214 let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
2215 let buffer_point = excerpt
2216 .buffer
2217 .offset_to_point(excerpt_start_offset + overshoot);
2218 *start_point + (buffer_point - excerpt_start_point)
2219 } else {
2220 self.excerpts.summary().text.lines
2221 }
2222 }
2223
2224 pub fn offset_to_point_utf16(&self, offset: usize) -> PointUtf16 {
2225 if let Some((_, _, buffer)) = self.as_singleton() {
2226 return buffer.offset_to_point_utf16(offset);
2227 }
2228
2229 let mut cursor = self.excerpts.cursor::<(usize, PointUtf16)>();
2230 cursor.seek(&offset, Bias::Right, &());
2231 if let Some(excerpt) = cursor.item() {
2232 let (start_offset, start_point) = cursor.start();
2233 let overshoot = offset - start_offset;
2234 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2235 let excerpt_start_point = excerpt.range.context.start.to_point_utf16(&excerpt.buffer);
2236 let buffer_point = excerpt
2237 .buffer
2238 .offset_to_point_utf16(excerpt_start_offset + overshoot);
2239 *start_point + (buffer_point - excerpt_start_point)
2240 } else {
2241 self.excerpts.summary().text.lines_utf16()
2242 }
2243 }
2244
2245 pub fn point_to_point_utf16(&self, point: Point) -> PointUtf16 {
2246 if let Some((_, _, buffer)) = self.as_singleton() {
2247 return buffer.point_to_point_utf16(point);
2248 }
2249
2250 let mut cursor = self.excerpts.cursor::<(Point, PointUtf16)>();
2251 cursor.seek(&point, Bias::Right, &());
2252 if let Some(excerpt) = cursor.item() {
2253 let (start_offset, start_point) = cursor.start();
2254 let overshoot = point - start_offset;
2255 let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
2256 let excerpt_start_point_utf16 =
2257 excerpt.range.context.start.to_point_utf16(&excerpt.buffer);
2258 let buffer_point = excerpt
2259 .buffer
2260 .point_to_point_utf16(excerpt_start_point + overshoot);
2261 *start_point + (buffer_point - excerpt_start_point_utf16)
2262 } else {
2263 self.excerpts.summary().text.lines_utf16()
2264 }
2265 }
2266
2267 pub fn point_to_offset(&self, point: Point) -> usize {
2268 if let Some((_, _, buffer)) = self.as_singleton() {
2269 return buffer.point_to_offset(point);
2270 }
2271
2272 let mut cursor = self.excerpts.cursor::<(Point, usize)>();
2273 cursor.seek(&point, Bias::Right, &());
2274 if let Some(excerpt) = cursor.item() {
2275 let (start_point, start_offset) = cursor.start();
2276 let overshoot = point - start_point;
2277 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2278 let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
2279 let buffer_offset = excerpt
2280 .buffer
2281 .point_to_offset(excerpt_start_point + overshoot);
2282 *start_offset + buffer_offset - excerpt_start_offset
2283 } else {
2284 self.excerpts.summary().text.len
2285 }
2286 }
2287
2288 pub fn offset_utf16_to_offset(&self, offset_utf16: OffsetUtf16) -> usize {
2289 if let Some((_, _, buffer)) = self.as_singleton() {
2290 return buffer.offset_utf16_to_offset(offset_utf16);
2291 }
2292
2293 let mut cursor = self.excerpts.cursor::<(OffsetUtf16, usize)>();
2294 cursor.seek(&offset_utf16, Bias::Right, &());
2295 if let Some(excerpt) = cursor.item() {
2296 let (start_offset_utf16, start_offset) = cursor.start();
2297 let overshoot = offset_utf16 - start_offset_utf16;
2298 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2299 let excerpt_start_offset_utf16 =
2300 excerpt.buffer.offset_to_offset_utf16(excerpt_start_offset);
2301 let buffer_offset = excerpt
2302 .buffer
2303 .offset_utf16_to_offset(excerpt_start_offset_utf16 + overshoot);
2304 *start_offset + (buffer_offset - excerpt_start_offset)
2305 } else {
2306 self.excerpts.summary().text.len
2307 }
2308 }
2309
2310 pub fn offset_to_offset_utf16(&self, offset: usize) -> OffsetUtf16 {
2311 if let Some((_, _, buffer)) = self.as_singleton() {
2312 return buffer.offset_to_offset_utf16(offset);
2313 }
2314
2315 let mut cursor = self.excerpts.cursor::<(usize, OffsetUtf16)>();
2316 cursor.seek(&offset, Bias::Right, &());
2317 if let Some(excerpt) = cursor.item() {
2318 let (start_offset, start_offset_utf16) = cursor.start();
2319 let overshoot = offset - start_offset;
2320 let excerpt_start_offset_utf16 =
2321 excerpt.range.context.start.to_offset_utf16(&excerpt.buffer);
2322 let excerpt_start_offset = excerpt
2323 .buffer
2324 .offset_utf16_to_offset(excerpt_start_offset_utf16);
2325 let buffer_offset_utf16 = excerpt
2326 .buffer
2327 .offset_to_offset_utf16(excerpt_start_offset + overshoot);
2328 *start_offset_utf16 + (buffer_offset_utf16 - excerpt_start_offset_utf16)
2329 } else {
2330 self.excerpts.summary().text.len_utf16
2331 }
2332 }
2333
2334 pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
2335 if let Some((_, _, buffer)) = self.as_singleton() {
2336 return buffer.point_utf16_to_offset(point);
2337 }
2338
2339 let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>();
2340 cursor.seek(&point, Bias::Right, &());
2341 if let Some(excerpt) = cursor.item() {
2342 let (start_point, start_offset) = cursor.start();
2343 let overshoot = point - start_point;
2344 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2345 let excerpt_start_point = excerpt
2346 .buffer
2347 .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
2348 let buffer_offset = excerpt
2349 .buffer
2350 .point_utf16_to_offset(excerpt_start_point + overshoot);
2351 *start_offset + (buffer_offset - excerpt_start_offset)
2352 } else {
2353 self.excerpts.summary().text.len
2354 }
2355 }
2356
2357 pub fn point_to_buffer_offset<T: ToOffset>(
2358 &self,
2359 point: T,
2360 ) -> Option<(&BufferSnapshot, usize)> {
2361 let offset = point.to_offset(self);
2362 let mut cursor = self.excerpts.cursor::<usize>();
2363 cursor.seek(&offset, Bias::Right, &());
2364 if cursor.item().is_none() {
2365 cursor.prev(&());
2366 }
2367
2368 cursor.item().map(|excerpt| {
2369 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2370 let buffer_point = excerpt_start + offset - *cursor.start();
2371 (&excerpt.buffer, buffer_point)
2372 })
2373 }
2374
2375 pub fn suggested_indents(
2376 &self,
2377 rows: impl IntoIterator<Item = u32>,
2378 cx: &AppContext,
2379 ) -> BTreeMap<u32, IndentSize> {
2380 let mut result = BTreeMap::new();
2381
2382 let mut rows_for_excerpt = Vec::new();
2383 let mut cursor = self.excerpts.cursor::<Point>();
2384 let mut rows = rows.into_iter().peekable();
2385 let mut prev_row = u32::MAX;
2386 let mut prev_language_indent_size = IndentSize::default();
2387
2388 while let Some(row) = rows.next() {
2389 cursor.seek(&Point::new(row, 0), Bias::Right, &());
2390 let excerpt = match cursor.item() {
2391 Some(excerpt) => excerpt,
2392 _ => continue,
2393 };
2394
2395 // Retrieve the language and indent size once for each disjoint region being indented.
2396 let single_indent_size = if row.saturating_sub(1) == prev_row {
2397 prev_language_indent_size
2398 } else {
2399 excerpt
2400 .buffer
2401 .language_indent_size_at(Point::new(row, 0), cx)
2402 };
2403 prev_language_indent_size = single_indent_size;
2404 prev_row = row;
2405
2406 let start_buffer_row = excerpt.range.context.start.to_point(&excerpt.buffer).row;
2407 let start_multibuffer_row = cursor.start().row;
2408
2409 rows_for_excerpt.push(row);
2410 while let Some(next_row) = rows.peek().copied() {
2411 if cursor.end(&()).row > next_row {
2412 rows_for_excerpt.push(next_row);
2413 rows.next();
2414 } else {
2415 break;
2416 }
2417 }
2418
2419 let buffer_rows = rows_for_excerpt
2420 .drain(..)
2421 .map(|row| start_buffer_row + row - start_multibuffer_row);
2422 let buffer_indents = excerpt
2423 .buffer
2424 .suggested_indents(buffer_rows, single_indent_size);
2425 let multibuffer_indents = buffer_indents
2426 .into_iter()
2427 .map(|(row, indent)| (start_multibuffer_row + row - start_buffer_row, indent));
2428 result.extend(multibuffer_indents);
2429 }
2430
2431 result
2432 }
2433
2434 pub fn indent_size_for_line(&self, row: u32) -> IndentSize {
2435 if let Some((buffer, range)) = self.buffer_line_for_row(row) {
2436 let mut size = buffer.indent_size_for_line(range.start.row);
2437 size.len = size
2438 .len
2439 .min(range.end.column)
2440 .saturating_sub(range.start.column);
2441 size
2442 } else {
2443 IndentSize::spaces(0)
2444 }
2445 }
2446
2447 pub fn prev_non_blank_row(&self, mut row: u32) -> Option<u32> {
2448 while row > 0 {
2449 row -= 1;
2450 if !self.is_line_blank(row) {
2451 return Some(row);
2452 }
2453 }
2454 None
2455 }
2456
2457 pub fn line_len(&self, row: u32) -> u32 {
2458 if let Some((_, range)) = self.buffer_line_for_row(row) {
2459 range.end.column - range.start.column
2460 } else {
2461 0
2462 }
2463 }
2464
2465 pub fn buffer_line_for_row(&self, row: u32) -> Option<(&BufferSnapshot, Range<Point>)> {
2466 let mut cursor = self.excerpts.cursor::<Point>();
2467 let point = Point::new(row, 0);
2468 cursor.seek(&point, Bias::Right, &());
2469 if cursor.item().is_none() && *cursor.start() == point {
2470 cursor.prev(&());
2471 }
2472 if let Some(excerpt) = cursor.item() {
2473 let overshoot = row - cursor.start().row;
2474 let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
2475 let excerpt_end = excerpt.range.context.end.to_point(&excerpt.buffer);
2476 let buffer_row = excerpt_start.row + overshoot;
2477 let line_start = Point::new(buffer_row, 0);
2478 let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
2479 return Some((
2480 &excerpt.buffer,
2481 line_start.max(excerpt_start)..line_end.min(excerpt_end),
2482 ));
2483 }
2484 None
2485 }
2486
2487 pub fn max_point(&self) -> Point {
2488 self.text_summary().lines
2489 }
2490
2491 pub fn text_summary(&self) -> TextSummary {
2492 self.excerpts.summary().text.clone()
2493 }
2494
2495 pub fn text_summary_for_range<D, O>(&self, range: Range<O>) -> D
2496 where
2497 D: TextDimension,
2498 O: ToOffset,
2499 {
2500 let mut summary = D::default();
2501 let mut range = range.start.to_offset(self)..range.end.to_offset(self);
2502 let mut cursor = self.excerpts.cursor::<usize>();
2503 cursor.seek(&range.start, Bias::Right, &());
2504 if let Some(excerpt) = cursor.item() {
2505 let mut end_before_newline = cursor.end(&());
2506 if excerpt.has_trailing_newline {
2507 end_before_newline -= 1;
2508 }
2509
2510 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2511 let start_in_excerpt = excerpt_start + (range.start - cursor.start());
2512 let end_in_excerpt =
2513 excerpt_start + (cmp::min(end_before_newline, range.end) - cursor.start());
2514 summary.add_assign(
2515 &excerpt
2516 .buffer
2517 .text_summary_for_range(start_in_excerpt..end_in_excerpt),
2518 );
2519
2520 if range.end > end_before_newline {
2521 summary.add_assign(&D::from_text_summary(&TextSummary::from("\n")));
2522 }
2523
2524 cursor.next(&());
2525 }
2526
2527 if range.end > *cursor.start() {
2528 summary.add_assign(&D::from_text_summary(&cursor.summary::<_, TextSummary>(
2529 &range.end,
2530 Bias::Right,
2531 &(),
2532 )));
2533 if let Some(excerpt) = cursor.item() {
2534 range.end = cmp::max(*cursor.start(), range.end);
2535
2536 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2537 let end_in_excerpt = excerpt_start + (range.end - cursor.start());
2538 summary.add_assign(
2539 &excerpt
2540 .buffer
2541 .text_summary_for_range(excerpt_start..end_in_excerpt),
2542 );
2543 }
2544 }
2545
2546 summary
2547 }
2548
2549 pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
2550 where
2551 D: TextDimension + Ord + Sub<D, Output = D>,
2552 {
2553 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
2554 let locator = self.excerpt_locator_for_id(anchor.excerpt_id);
2555
2556 cursor.seek(locator, Bias::Left, &());
2557 if cursor.item().is_none() {
2558 cursor.next(&());
2559 }
2560
2561 let mut position = D::from_text_summary(&cursor.start().text);
2562 if let Some(excerpt) = cursor.item() {
2563 if excerpt.id == anchor.excerpt_id {
2564 let excerpt_buffer_start =
2565 excerpt.range.context.start.summary::<D>(&excerpt.buffer);
2566 let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer);
2567 let buffer_position = cmp::min(
2568 excerpt_buffer_end,
2569 anchor.text_anchor.summary::<D>(&excerpt.buffer),
2570 );
2571 if buffer_position > excerpt_buffer_start {
2572 position.add_assign(&(buffer_position - excerpt_buffer_start));
2573 }
2574 }
2575 }
2576 position
2577 }
2578
2579 pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
2580 where
2581 D: TextDimension + Ord + Sub<D, Output = D>,
2582 I: 'a + IntoIterator<Item = &'a Anchor>,
2583 {
2584 if let Some((_, _, buffer)) = self.as_singleton() {
2585 return buffer
2586 .summaries_for_anchors(anchors.into_iter().map(|a| &a.text_anchor))
2587 .collect();
2588 }
2589
2590 let mut anchors = anchors.into_iter().peekable();
2591 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
2592 let mut summaries = Vec::new();
2593 while let Some(anchor) = anchors.peek() {
2594 let excerpt_id = anchor.excerpt_id;
2595 let excerpt_anchors = iter::from_fn(|| {
2596 let anchor = anchors.peek()?;
2597 if anchor.excerpt_id == excerpt_id {
2598 Some(&anchors.next().unwrap().text_anchor)
2599 } else {
2600 None
2601 }
2602 });
2603
2604 let locator = self.excerpt_locator_for_id(excerpt_id);
2605 cursor.seek_forward(locator, Bias::Left, &());
2606 if cursor.item().is_none() {
2607 cursor.next(&());
2608 }
2609
2610 let position = D::from_text_summary(&cursor.start().text);
2611 if let Some(excerpt) = cursor.item() {
2612 if excerpt.id == excerpt_id {
2613 let excerpt_buffer_start =
2614 excerpt.range.context.start.summary::<D>(&excerpt.buffer);
2615 let excerpt_buffer_end =
2616 excerpt.range.context.end.summary::<D>(&excerpt.buffer);
2617 summaries.extend(
2618 excerpt
2619 .buffer
2620 .summaries_for_anchors::<D, _>(excerpt_anchors)
2621 .map(move |summary| {
2622 let summary = cmp::min(excerpt_buffer_end.clone(), summary);
2623 let mut position = position.clone();
2624 let excerpt_buffer_start = excerpt_buffer_start.clone();
2625 if summary > excerpt_buffer_start {
2626 position.add_assign(&(summary - excerpt_buffer_start));
2627 }
2628 position
2629 }),
2630 );
2631 continue;
2632 }
2633 }
2634
2635 summaries.extend(excerpt_anchors.map(|_| position.clone()));
2636 }
2637
2638 summaries
2639 }
2640
2641 pub fn refresh_anchors<'a, I>(&'a self, anchors: I) -> Vec<(usize, Anchor, bool)>
2642 where
2643 I: 'a + IntoIterator<Item = &'a Anchor>,
2644 {
2645 let mut anchors = anchors.into_iter().enumerate().peekable();
2646 let mut cursor = self.excerpts.cursor::<Option<&Locator>>();
2647 cursor.next(&());
2648
2649 let mut result = Vec::new();
2650
2651 while let Some((_, anchor)) = anchors.peek() {
2652 let old_excerpt_id = anchor.excerpt_id;
2653
2654 // Find the location where this anchor's excerpt should be.
2655 let old_locator = self.excerpt_locator_for_id(old_excerpt_id);
2656 cursor.seek_forward(&Some(old_locator), Bias::Left, &());
2657
2658 if cursor.item().is_none() {
2659 cursor.next(&());
2660 }
2661
2662 let next_excerpt = cursor.item();
2663 let prev_excerpt = cursor.prev_item();
2664
2665 // Process all of the anchors for this excerpt.
2666 while let Some((_, anchor)) = anchors.peek() {
2667 if anchor.excerpt_id != old_excerpt_id {
2668 break;
2669 }
2670 let (anchor_ix, anchor) = anchors.next().unwrap();
2671 let mut anchor = *anchor;
2672
2673 // Leave min and max anchors unchanged if invalid or
2674 // if the old excerpt still exists at this location
2675 let mut kept_position = next_excerpt
2676 .map_or(false, |e| e.id == old_excerpt_id && e.contains(&anchor))
2677 || old_excerpt_id == ExcerptId::max()
2678 || old_excerpt_id == ExcerptId::min();
2679
2680 // If the old excerpt no longer exists at this location, then attempt to
2681 // find an equivalent position for this anchor in an adjacent excerpt.
2682 if !kept_position {
2683 for excerpt in [next_excerpt, prev_excerpt].iter().filter_map(|e| *e) {
2684 if excerpt.contains(&anchor) {
2685 anchor.excerpt_id = excerpt.id;
2686 kept_position = true;
2687 break;
2688 }
2689 }
2690 }
2691
2692 // If there's no adjacent excerpt that contains the anchor's position,
2693 // then report that the anchor has lost its position.
2694 if !kept_position {
2695 anchor = if let Some(excerpt) = next_excerpt {
2696 let mut text_anchor = excerpt
2697 .range
2698 .context
2699 .start
2700 .bias(anchor.text_anchor.bias, &excerpt.buffer);
2701 if text_anchor
2702 .cmp(&excerpt.range.context.end, &excerpt.buffer)
2703 .is_gt()
2704 {
2705 text_anchor = excerpt.range.context.end;
2706 }
2707 Anchor {
2708 buffer_id: Some(excerpt.buffer_id),
2709 excerpt_id: excerpt.id,
2710 text_anchor,
2711 }
2712 } else if let Some(excerpt) = prev_excerpt {
2713 let mut text_anchor = excerpt
2714 .range
2715 .context
2716 .end
2717 .bias(anchor.text_anchor.bias, &excerpt.buffer);
2718 if text_anchor
2719 .cmp(&excerpt.range.context.start, &excerpt.buffer)
2720 .is_lt()
2721 {
2722 text_anchor = excerpt.range.context.start;
2723 }
2724 Anchor {
2725 buffer_id: Some(excerpt.buffer_id),
2726 excerpt_id: excerpt.id,
2727 text_anchor,
2728 }
2729 } else if anchor.text_anchor.bias == Bias::Left {
2730 Anchor::min()
2731 } else {
2732 Anchor::max()
2733 };
2734 }
2735
2736 result.push((anchor_ix, anchor, kept_position));
2737 }
2738 }
2739 result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self));
2740 result
2741 }
2742
2743 pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
2744 self.anchor_at(position, Bias::Left)
2745 }
2746
2747 pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
2748 self.anchor_at(position, Bias::Right)
2749 }
2750
2751 pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
2752 let offset = position.to_offset(self);
2753 if let Some((excerpt_id, buffer_id, buffer)) = self.as_singleton() {
2754 return Anchor {
2755 buffer_id: Some(buffer_id),
2756 excerpt_id: *excerpt_id,
2757 text_anchor: buffer.anchor_at(offset, bias),
2758 };
2759 }
2760
2761 let mut cursor = self.excerpts.cursor::<(usize, Option<ExcerptId>)>();
2762 cursor.seek(&offset, Bias::Right, &());
2763 if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left {
2764 cursor.prev(&());
2765 }
2766 if let Some(excerpt) = cursor.item() {
2767 let mut overshoot = offset.saturating_sub(cursor.start().0);
2768 if excerpt.has_trailing_newline && offset == cursor.end(&()).0 {
2769 overshoot -= 1;
2770 bias = Bias::Right;
2771 }
2772
2773 let buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2774 let text_anchor =
2775 excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
2776 Anchor {
2777 buffer_id: Some(excerpt.buffer_id),
2778 excerpt_id: excerpt.id,
2779 text_anchor,
2780 }
2781 } else if offset == 0 && bias == Bias::Left {
2782 Anchor::min()
2783 } else {
2784 Anchor::max()
2785 }
2786 }
2787
2788 /// Returns an anchor for the given excerpt and text anchor,
2789 /// returns None if the excerpt_id is no longer valid.
2790 pub fn anchor_in_excerpt(
2791 &self,
2792 excerpt_id: ExcerptId,
2793 text_anchor: text::Anchor,
2794 ) -> Option<Anchor> {
2795 let locator = self.excerpt_locator_for_id(excerpt_id);
2796 let mut cursor = self.excerpts.cursor::<Option<&Locator>>();
2797 cursor.seek(locator, Bias::Left, &());
2798 if let Some(excerpt) = cursor.item() {
2799 if excerpt.id == excerpt_id {
2800 let text_anchor = excerpt.clip_anchor(text_anchor);
2801 drop(cursor);
2802 return Some(Anchor {
2803 buffer_id: Some(excerpt.buffer_id),
2804 excerpt_id,
2805 text_anchor,
2806 });
2807 }
2808 }
2809 None
2810 }
2811
2812 pub fn can_resolve(&self, anchor: &Anchor) -> bool {
2813 if anchor.excerpt_id == ExcerptId::min() || anchor.excerpt_id == ExcerptId::max() {
2814 true
2815 } else if let Some(excerpt) = self.excerpt(anchor.excerpt_id) {
2816 excerpt.buffer.can_resolve(&anchor.text_anchor)
2817 } else {
2818 false
2819 }
2820 }
2821
2822 pub fn excerpts(
2823 &self,
2824 ) -> impl Iterator<Item = (ExcerptId, &BufferSnapshot, ExcerptRange<text::Anchor>)> {
2825 self.excerpts
2826 .iter()
2827 .map(|excerpt| (excerpt.id, &excerpt.buffer, excerpt.range.clone()))
2828 }
2829
2830 fn excerpts_for_range<T: ToOffset>(
2831 &self,
2832 range: Range<T>,
2833 ) -> impl Iterator<Item = (&Excerpt, usize)> + '_ {
2834 let range = range.start.to_offset(self)..range.end.to_offset(self);
2835
2836 let mut cursor = self.excerpts.cursor::<usize>();
2837 cursor.seek(&range.start, Bias::Right, &());
2838 cursor.prev(&());
2839
2840 iter::from_fn(move || {
2841 cursor.next(&());
2842 if cursor.start() < &range.end {
2843 cursor.item().map(|item| (item, *cursor.start()))
2844 } else {
2845 None
2846 }
2847 })
2848 }
2849
2850 pub fn excerpt_boundaries_in_range<R, T>(
2851 &self,
2852 range: R,
2853 ) -> impl Iterator<Item = ExcerptBoundary> + '_
2854 where
2855 R: RangeBounds<T>,
2856 T: ToOffset,
2857 {
2858 let start_offset;
2859 let start = match range.start_bound() {
2860 Bound::Included(start) => {
2861 start_offset = start.to_offset(self);
2862 Bound::Included(start_offset)
2863 }
2864 Bound::Excluded(start) => {
2865 start_offset = start.to_offset(self);
2866 Bound::Excluded(start_offset)
2867 }
2868 Bound::Unbounded => {
2869 start_offset = 0;
2870 Bound::Unbounded
2871 }
2872 };
2873 let end = match range.end_bound() {
2874 Bound::Included(end) => Bound::Included(end.to_offset(self)),
2875 Bound::Excluded(end) => Bound::Excluded(end.to_offset(self)),
2876 Bound::Unbounded => Bound::Unbounded,
2877 };
2878 let bounds = (start, end);
2879
2880 let mut cursor = self.excerpts.cursor::<(usize, Point)>();
2881 cursor.seek(&start_offset, Bias::Right, &());
2882 if cursor.item().is_none() {
2883 cursor.prev(&());
2884 }
2885 if !bounds.contains(&cursor.start().0) {
2886 cursor.next(&());
2887 }
2888
2889 let mut prev_buffer_id = cursor.prev_item().map(|excerpt| excerpt.buffer_id);
2890 std::iter::from_fn(move || {
2891 if self.singleton {
2892 None
2893 } else if bounds.contains(&cursor.start().0) {
2894 let excerpt = cursor.item()?;
2895 let starts_new_buffer = Some(excerpt.buffer_id) != prev_buffer_id;
2896 let boundary = ExcerptBoundary {
2897 id: excerpt.id,
2898 row: cursor.start().1.row,
2899 buffer: excerpt.buffer.clone(),
2900 range: excerpt.range.clone(),
2901 starts_new_buffer,
2902 };
2903
2904 prev_buffer_id = Some(excerpt.buffer_id);
2905 cursor.next(&());
2906 Some(boundary)
2907 } else {
2908 None
2909 }
2910 })
2911 }
2912
2913 pub fn edit_count(&self) -> usize {
2914 self.edit_count
2915 }
2916
2917 pub fn parse_count(&self) -> usize {
2918 self.parse_count
2919 }
2920
2921 /// Returns the smallest enclosing bracket ranges containing the given range or
2922 /// None if no brackets contain range or the range is not contained in a single
2923 /// excerpt
2924 ///
2925 /// Can optionally pass a range_filter to filter the ranges of brackets to consider
2926 pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
2927 &self,
2928 range: Range<T>,
2929 range_filter: Option<&dyn Fn(Range<usize>, Range<usize>) -> bool>,
2930 ) -> Option<(Range<usize>, Range<usize>)> {
2931 let range = range.start.to_offset(self)..range.end.to_offset(self);
2932 let excerpt = self.excerpt_containing(range.clone())?;
2933
2934 // Filter to ranges contained in the excerpt
2935 let range_filter = |open: Range<usize>, close: Range<usize>| -> bool {
2936 excerpt.contains_buffer_range(open.start..close.end)
2937 && range_filter.map_or(true, |filter| {
2938 filter(
2939 excerpt.map_range_from_buffer(open),
2940 excerpt.map_range_from_buffer(close),
2941 )
2942 })
2943 };
2944
2945 let (open, close) = excerpt.buffer().innermost_enclosing_bracket_ranges(
2946 excerpt.map_range_to_buffer(range),
2947 Some(&range_filter),
2948 )?;
2949
2950 Some((
2951 excerpt.map_range_from_buffer(open),
2952 excerpt.map_range_from_buffer(close),
2953 ))
2954 }
2955
2956 /// Returns enclosing bracket ranges containing the given range or returns None if the range is
2957 /// not contained in a single excerpt
2958 pub fn enclosing_bracket_ranges<T: ToOffset>(
2959 &self,
2960 range: Range<T>,
2961 ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + '_> {
2962 let range = range.start.to_offset(self)..range.end.to_offset(self);
2963 let excerpt = self.excerpt_containing(range.clone())?;
2964
2965 Some(
2966 excerpt
2967 .buffer()
2968 .enclosing_bracket_ranges(excerpt.map_range_to_buffer(range))
2969 .filter_map(move |(open, close)| {
2970 if excerpt.contains_buffer_range(open.start..close.end) {
2971 Some((
2972 excerpt.map_range_from_buffer(open),
2973 excerpt.map_range_from_buffer(close),
2974 ))
2975 } else {
2976 None
2977 }
2978 }),
2979 )
2980 }
2981
2982 /// Returns bracket range pairs overlapping the given `range` or returns None if the `range` is
2983 /// not contained in a single excerpt
2984 pub fn bracket_ranges<T: ToOffset>(
2985 &self,
2986 range: Range<T>,
2987 ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + '_> {
2988 let range = range.start.to_offset(self)..range.end.to_offset(self);
2989 let excerpt = self.excerpt_containing(range.clone())?;
2990
2991 Some(
2992 excerpt
2993 .buffer()
2994 .bracket_ranges(excerpt.map_range_to_buffer(range))
2995 .filter_map(move |(start_bracket_range, close_bracket_range)| {
2996 let buffer_range = start_bracket_range.start..close_bracket_range.end;
2997 if excerpt.contains_buffer_range(buffer_range) {
2998 Some((
2999 excerpt.map_range_from_buffer(start_bracket_range),
3000 excerpt.map_range_from_buffer(close_bracket_range),
3001 ))
3002 } else {
3003 None
3004 }
3005 }),
3006 )
3007 }
3008
3009 pub fn redacted_ranges<'a, T: ToOffset>(
3010 &'a self,
3011 range: Range<T>,
3012 redaction_enabled: impl Fn(Option<&Arc<dyn File>>) -> bool + 'a,
3013 ) -> impl Iterator<Item = Range<usize>> + 'a {
3014 let range = range.start.to_offset(self)..range.end.to_offset(self);
3015 self.excerpts_for_range(range.clone())
3016 .filter_map(move |(excerpt, excerpt_offset)| {
3017 redaction_enabled(excerpt.buffer.file()).then(move || {
3018 let excerpt_buffer_start =
3019 excerpt.range.context.start.to_offset(&excerpt.buffer);
3020
3021 excerpt
3022 .buffer
3023 .redacted_ranges(excerpt.range.context.clone())
3024 .map(move |mut redacted_range| {
3025 // Re-base onto the excerpts coordinates in the multibuffer
3026 redacted_range.start =
3027 excerpt_offset + (redacted_range.start - excerpt_buffer_start);
3028 redacted_range.end =
3029 excerpt_offset + (redacted_range.end - excerpt_buffer_start);
3030
3031 redacted_range
3032 })
3033 .skip_while(move |redacted_range| redacted_range.end < range.start)
3034 .take_while(move |redacted_range| redacted_range.start < range.end)
3035 })
3036 })
3037 .flatten()
3038 }
3039
3040 pub fn diagnostics_update_count(&self) -> usize {
3041 self.diagnostics_update_count
3042 }
3043
3044 pub fn git_diff_update_count(&self) -> usize {
3045 self.git_diff_update_count
3046 }
3047
3048 pub fn trailing_excerpt_update_count(&self) -> usize {
3049 self.trailing_excerpt_update_count
3050 }
3051
3052 pub fn file_at<T: ToOffset>(&self, point: T) -> Option<&Arc<dyn File>> {
3053 self.point_to_buffer_offset(point)
3054 .and_then(|(buffer, _)| buffer.file())
3055 }
3056
3057 pub fn language_at<T: ToOffset>(&self, point: T) -> Option<&Arc<Language>> {
3058 self.point_to_buffer_offset(point)
3059 .and_then(|(buffer, offset)| buffer.language_at(offset))
3060 }
3061
3062 pub fn settings_at<'a, T: ToOffset>(
3063 &'a self,
3064 point: T,
3065 cx: &'a AppContext,
3066 ) -> &'a LanguageSettings {
3067 let mut language = None;
3068 let mut file = None;
3069 if let Some((buffer, offset)) = self.point_to_buffer_offset(point) {
3070 language = buffer.language_at(offset);
3071 file = buffer.file();
3072 }
3073 language_settings(language, file, cx)
3074 }
3075
3076 pub fn language_scope_at<T: ToOffset>(&self, point: T) -> Option<LanguageScope> {
3077 self.point_to_buffer_offset(point)
3078 .and_then(|(buffer, offset)| buffer.language_scope_at(offset))
3079 }
3080
3081 pub fn language_indent_size_at<T: ToOffset>(
3082 &self,
3083 position: T,
3084 cx: &AppContext,
3085 ) -> Option<IndentSize> {
3086 let (buffer_snapshot, offset) = self.point_to_buffer_offset(position)?;
3087 Some(buffer_snapshot.language_indent_size_at(offset, cx))
3088 }
3089
3090 pub fn is_dirty(&self) -> bool {
3091 self.is_dirty
3092 }
3093
3094 pub fn has_conflict(&self) -> bool {
3095 self.has_conflict
3096 }
3097
3098 pub fn has_diagnostics(&self) -> bool {
3099 self.excerpts
3100 .iter()
3101 .any(|excerpt| excerpt.buffer.has_diagnostics())
3102 }
3103
3104 pub fn diagnostic_group<'a, O>(
3105 &'a self,
3106 group_id: usize,
3107 ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
3108 where
3109 O: text::FromAnchor + 'a,
3110 {
3111 self.as_singleton()
3112 .into_iter()
3113 .flat_map(move |(_, _, buffer)| buffer.diagnostic_group(group_id))
3114 }
3115
3116 pub fn diagnostics_in_range<'a, T, O>(
3117 &'a self,
3118 range: Range<T>,
3119 reversed: bool,
3120 ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
3121 where
3122 T: 'a + ToOffset,
3123 O: 'a + text::FromAnchor + Ord,
3124 {
3125 self.as_singleton()
3126 .into_iter()
3127 .flat_map(move |(_, _, buffer)| {
3128 buffer.diagnostics_in_range(
3129 range.start.to_offset(self)..range.end.to_offset(self),
3130 reversed,
3131 )
3132 })
3133 }
3134
3135 pub fn has_git_diffs(&self) -> bool {
3136 for excerpt in self.excerpts.iter() {
3137 if excerpt.buffer.has_git_diff() {
3138 return true;
3139 }
3140 }
3141 false
3142 }
3143
3144 pub fn git_diff_hunks_in_range_rev(
3145 &self,
3146 row_range: Range<u32>,
3147 ) -> impl Iterator<Item = DiffHunk<u32>> + '_ {
3148 let mut cursor = self.excerpts.cursor::<Point>();
3149
3150 cursor.seek(&Point::new(row_range.end, 0), Bias::Left, &());
3151 if cursor.item().is_none() {
3152 cursor.prev(&());
3153 }
3154
3155 std::iter::from_fn(move || {
3156 let excerpt = cursor.item()?;
3157 let multibuffer_start = *cursor.start();
3158 let multibuffer_end = multibuffer_start + excerpt.text_summary.lines;
3159 if multibuffer_start.row >= row_range.end {
3160 return None;
3161 }
3162
3163 let mut buffer_start = excerpt.range.context.start;
3164 let mut buffer_end = excerpt.range.context.end;
3165 let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
3166 let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
3167
3168 if row_range.start > multibuffer_start.row {
3169 let buffer_start_point =
3170 excerpt_start_point + Point::new(row_range.start - multibuffer_start.row, 0);
3171 buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
3172 }
3173
3174 if row_range.end < multibuffer_end.row {
3175 let buffer_end_point =
3176 excerpt_start_point + Point::new(row_range.end - multibuffer_start.row, 0);
3177 buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
3178 }
3179
3180 let buffer_hunks = excerpt
3181 .buffer
3182 .git_diff_hunks_intersecting_range_rev(buffer_start..buffer_end)
3183 .map(move |hunk| {
3184 let start = multibuffer_start.row
3185 + hunk
3186 .associated_range
3187 .start
3188 .saturating_sub(excerpt_start_point.row);
3189 let end = multibuffer_start.row
3190 + hunk
3191 .associated_range
3192 .end
3193 .min(excerpt_end_point.row + 1)
3194 .saturating_sub(excerpt_start_point.row);
3195
3196 DiffHunk {
3197 associated_range: start..end,
3198 diff_base_byte_range: hunk.diff_base_byte_range.clone(),
3199 buffer_range: hunk.buffer_range.clone(),
3200 buffer_id: hunk.buffer_id,
3201 }
3202 });
3203
3204 cursor.prev(&());
3205
3206 Some(buffer_hunks)
3207 })
3208 .flatten()
3209 }
3210
3211 pub fn git_diff_hunks_in_range(
3212 &self,
3213 row_range: Range<u32>,
3214 ) -> impl Iterator<Item = DiffHunk<u32>> + '_ {
3215 let mut cursor = self.excerpts.cursor::<Point>();
3216
3217 cursor.seek(&Point::new(row_range.start, 0), Bias::Left, &());
3218
3219 std::iter::from_fn(move || {
3220 let excerpt = cursor.item()?;
3221 let multibuffer_start = *cursor.start();
3222 let multibuffer_end = multibuffer_start + excerpt.text_summary.lines;
3223 let mut buffer_start = excerpt.range.context.start;
3224 let mut buffer_end = excerpt.range.context.end;
3225
3226 let excerpt_rows = match multibuffer_start.row.cmp(&row_range.end) {
3227 cmp::Ordering::Less => {
3228 let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
3229 let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
3230
3231 if row_range.start > multibuffer_start.row {
3232 let buffer_start_point = excerpt_start_point
3233 + Point::new(row_range.start - multibuffer_start.row, 0);
3234 buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
3235 }
3236
3237 if row_range.end < multibuffer_end.row {
3238 let buffer_end_point = excerpt_start_point
3239 + Point::new(row_range.end - multibuffer_start.row, 0);
3240 buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
3241 }
3242 excerpt_start_point.row..excerpt_end_point.row
3243 }
3244 cmp::Ordering::Equal if row_range.end == 0 => {
3245 buffer_end = buffer_start;
3246 0..0
3247 }
3248 cmp::Ordering::Greater | cmp::Ordering::Equal => return None,
3249 };
3250
3251 let buffer_hunks = excerpt
3252 .buffer
3253 .git_diff_hunks_intersecting_range(buffer_start..buffer_end)
3254 .map(move |hunk| {
3255 let buffer_range = if excerpt_rows.start == 0 && excerpt_rows.end == 0 {
3256 0..1
3257 } else {
3258 let start = multibuffer_start.row
3259 + hunk
3260 .associated_range
3261 .start
3262 .saturating_sub(excerpt_rows.start);
3263 let end = multibuffer_start.row
3264 + hunk
3265 .associated_range
3266 .end
3267 .min(excerpt_rows.end + 1)
3268 .saturating_sub(excerpt_rows.start);
3269 start..end
3270 };
3271 DiffHunk {
3272 associated_range: buffer_range,
3273 diff_base_byte_range: hunk.diff_base_byte_range.clone(),
3274 buffer_range: hunk.buffer_range.clone(),
3275 buffer_id: hunk.buffer_id,
3276 }
3277 });
3278
3279 cursor.next(&());
3280
3281 Some(buffer_hunks)
3282 })
3283 .flatten()
3284 }
3285
3286 pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
3287 let range = range.start.to_offset(self)..range.end.to_offset(self);
3288 let excerpt = self.excerpt_containing(range.clone())?;
3289
3290 let ancestor_buffer_range = excerpt
3291 .buffer()
3292 .range_for_syntax_ancestor(excerpt.map_range_to_buffer(range))?;
3293
3294 Some(excerpt.map_range_from_buffer(ancestor_buffer_range))
3295 }
3296
3297 pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
3298 let (excerpt_id, _, buffer) = self.as_singleton()?;
3299 let outline = buffer.outline(theme)?;
3300 Some(Outline::new(
3301 outline
3302 .items
3303 .into_iter()
3304 .flat_map(|item| {
3305 Some(OutlineItem {
3306 depth: item.depth,
3307 range: self.anchor_in_excerpt(*excerpt_id, item.range.start)?
3308 ..self.anchor_in_excerpt(*excerpt_id, item.range.end)?,
3309 text: item.text,
3310 highlight_ranges: item.highlight_ranges,
3311 name_ranges: item.name_ranges,
3312 })
3313 })
3314 .collect(),
3315 ))
3316 }
3317
3318 pub fn symbols_containing<T: ToOffset>(
3319 &self,
3320 offset: T,
3321 theme: Option<&SyntaxTheme>,
3322 ) -> Option<(BufferId, Vec<OutlineItem<Anchor>>)> {
3323 let anchor = self.anchor_before(offset);
3324 let excerpt_id = anchor.excerpt_id;
3325 let excerpt = self.excerpt(excerpt_id)?;
3326 Some((
3327 excerpt.buffer_id,
3328 excerpt
3329 .buffer
3330 .symbols_containing(anchor.text_anchor, theme)
3331 .into_iter()
3332 .flatten()
3333 .flat_map(|item| {
3334 Some(OutlineItem {
3335 depth: item.depth,
3336 range: self.anchor_in_excerpt(excerpt_id, item.range.start)?
3337 ..self.anchor_in_excerpt(excerpt_id, item.range.end)?,
3338 text: item.text,
3339 highlight_ranges: item.highlight_ranges,
3340 name_ranges: item.name_ranges,
3341 })
3342 })
3343 .collect(),
3344 ))
3345 }
3346
3347 fn excerpt_locator_for_id(&self, id: ExcerptId) -> &Locator {
3348 if id == ExcerptId::min() {
3349 Locator::min_ref()
3350 } else if id == ExcerptId::max() {
3351 Locator::max_ref()
3352 } else {
3353 let mut cursor = self.excerpt_ids.cursor::<ExcerptId>();
3354 cursor.seek(&id, Bias::Left, &());
3355 if let Some(entry) = cursor.item() {
3356 if entry.id == id {
3357 return &entry.locator;
3358 }
3359 }
3360 panic!("invalid excerpt id {:?}", id)
3361 }
3362 }
3363
3364 pub fn buffer_id_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<BufferId> {
3365 Some(self.excerpt(excerpt_id)?.buffer_id)
3366 }
3367
3368 pub fn buffer_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<&BufferSnapshot> {
3369 Some(&self.excerpt(excerpt_id)?.buffer)
3370 }
3371
3372 fn excerpt(&self, excerpt_id: ExcerptId) -> Option<&Excerpt> {
3373 let mut cursor = self.excerpts.cursor::<Option<&Locator>>();
3374 let locator = self.excerpt_locator_for_id(excerpt_id);
3375 cursor.seek(&Some(locator), Bias::Left, &());
3376 if let Some(excerpt) = cursor.item() {
3377 if excerpt.id == excerpt_id {
3378 return Some(excerpt);
3379 }
3380 }
3381 None
3382 }
3383
3384 /// Returns the excerpt containing range and its offset start within the multibuffer or none if `range` spans multiple excerpts
3385 pub fn excerpt_containing<T: ToOffset>(&self, range: Range<T>) -> Option<MultiBufferExcerpt> {
3386 let range = range.start.to_offset(self)..range.end.to_offset(self);
3387
3388 let mut cursor = self.excerpts.cursor::<usize>();
3389 cursor.seek(&range.start, Bias::Right, &());
3390 let start_excerpt = cursor.item()?;
3391
3392 if range.start == range.end {
3393 return Some(MultiBufferExcerpt::new(start_excerpt, *cursor.start()));
3394 }
3395
3396 cursor.seek(&range.end, Bias::Right, &());
3397 let end_excerpt = cursor.item()?;
3398
3399 if start_excerpt.id == end_excerpt.id {
3400 Some(MultiBufferExcerpt::new(start_excerpt, *cursor.start()))
3401 } else {
3402 None
3403 }
3404 }
3405
3406 pub fn remote_selections_in_range<'a>(
3407 &'a self,
3408 range: &'a Range<Anchor>,
3409 ) -> impl 'a + Iterator<Item = (ReplicaId, bool, CursorShape, Selection<Anchor>)> {
3410 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
3411 let start_locator = self.excerpt_locator_for_id(range.start.excerpt_id);
3412 let end_locator = self.excerpt_locator_for_id(range.end.excerpt_id);
3413 cursor.seek(start_locator, Bias::Left, &());
3414 cursor
3415 .take_while(move |excerpt| excerpt.locator <= *end_locator)
3416 .flat_map(move |excerpt| {
3417 let mut query_range = excerpt.range.context.start..excerpt.range.context.end;
3418 if excerpt.id == range.start.excerpt_id {
3419 query_range.start = range.start.text_anchor;
3420 }
3421 if excerpt.id == range.end.excerpt_id {
3422 query_range.end = range.end.text_anchor;
3423 }
3424
3425 excerpt
3426 .buffer
3427 .remote_selections_in_range(query_range)
3428 .flat_map(move |(replica_id, line_mode, cursor_shape, selections)| {
3429 selections.map(move |selection| {
3430 let mut start = Anchor {
3431 buffer_id: Some(excerpt.buffer_id),
3432 excerpt_id: excerpt.id,
3433 text_anchor: selection.start,
3434 };
3435 let mut end = Anchor {
3436 buffer_id: Some(excerpt.buffer_id),
3437 excerpt_id: excerpt.id,
3438 text_anchor: selection.end,
3439 };
3440 if range.start.cmp(&start, self).is_gt() {
3441 start = range.start;
3442 }
3443 if range.end.cmp(&end, self).is_lt() {
3444 end = range.end;
3445 }
3446
3447 (
3448 replica_id,
3449 line_mode,
3450 cursor_shape,
3451 Selection {
3452 id: selection.id,
3453 start,
3454 end,
3455 reversed: selection.reversed,
3456 goal: selection.goal,
3457 },
3458 )
3459 })
3460 })
3461 })
3462 }
3463}
3464
3465#[cfg(any(test, feature = "test-support"))]
3466impl MultiBufferSnapshot {
3467 pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
3468 let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
3469 let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
3470 start..end
3471 }
3472}
3473
3474impl History {
3475 fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
3476 self.transaction_depth += 1;
3477 if self.transaction_depth == 1 {
3478 let id = self.next_transaction_id.tick();
3479 self.undo_stack.push(Transaction {
3480 id,
3481 buffer_transactions: Default::default(),
3482 first_edit_at: now,
3483 last_edit_at: now,
3484 suppress_grouping: false,
3485 });
3486 Some(id)
3487 } else {
3488 None
3489 }
3490 }
3491
3492 fn end_transaction(
3493 &mut self,
3494 now: Instant,
3495 buffer_transactions: HashMap<BufferId, TransactionId>,
3496 ) -> bool {
3497 assert_ne!(self.transaction_depth, 0);
3498 self.transaction_depth -= 1;
3499 if self.transaction_depth == 0 {
3500 if buffer_transactions.is_empty() {
3501 self.undo_stack.pop();
3502 false
3503 } else {
3504 self.redo_stack.clear();
3505 let transaction = self.undo_stack.last_mut().unwrap();
3506 transaction.last_edit_at = now;
3507 for (buffer_id, transaction_id) in buffer_transactions {
3508 transaction
3509 .buffer_transactions
3510 .entry(buffer_id)
3511 .or_insert(transaction_id);
3512 }
3513 true
3514 }
3515 } else {
3516 false
3517 }
3518 }
3519
3520 fn push_transaction<'a, T>(
3521 &mut self,
3522 buffer_transactions: T,
3523 now: Instant,
3524 cx: &mut ModelContext<MultiBuffer>,
3525 ) where
3526 T: IntoIterator<Item = (&'a Model<Buffer>, &'a language::Transaction)>,
3527 {
3528 assert_eq!(self.transaction_depth, 0);
3529 let transaction = Transaction {
3530 id: self.next_transaction_id.tick(),
3531 buffer_transactions: buffer_transactions
3532 .into_iter()
3533 .map(|(buffer, transaction)| (buffer.read(cx).remote_id(), transaction.id))
3534 .collect(),
3535 first_edit_at: now,
3536 last_edit_at: now,
3537 suppress_grouping: false,
3538 };
3539 if !transaction.buffer_transactions.is_empty() {
3540 self.undo_stack.push(transaction);
3541 self.redo_stack.clear();
3542 }
3543 }
3544
3545 fn finalize_last_transaction(&mut self) {
3546 if let Some(transaction) = self.undo_stack.last_mut() {
3547 transaction.suppress_grouping = true;
3548 }
3549 }
3550
3551 fn forget(&mut self, transaction_id: TransactionId) -> Option<Transaction> {
3552 if let Some(ix) = self
3553 .undo_stack
3554 .iter()
3555 .rposition(|transaction| transaction.id == transaction_id)
3556 {
3557 Some(self.undo_stack.remove(ix))
3558 } else if let Some(ix) = self
3559 .redo_stack
3560 .iter()
3561 .rposition(|transaction| transaction.id == transaction_id)
3562 {
3563 Some(self.redo_stack.remove(ix))
3564 } else {
3565 None
3566 }
3567 }
3568
3569 fn transaction_mut(&mut self, transaction_id: TransactionId) -> Option<&mut Transaction> {
3570 self.undo_stack
3571 .iter_mut()
3572 .find(|transaction| transaction.id == transaction_id)
3573 .or_else(|| {
3574 self.redo_stack
3575 .iter_mut()
3576 .find(|transaction| transaction.id == transaction_id)
3577 })
3578 }
3579
3580 fn pop_undo(&mut self) -> Option<&mut Transaction> {
3581 assert_eq!(self.transaction_depth, 0);
3582 if let Some(transaction) = self.undo_stack.pop() {
3583 self.redo_stack.push(transaction);
3584 self.redo_stack.last_mut()
3585 } else {
3586 None
3587 }
3588 }
3589
3590 fn pop_redo(&mut self) -> Option<&mut Transaction> {
3591 assert_eq!(self.transaction_depth, 0);
3592 if let Some(transaction) = self.redo_stack.pop() {
3593 self.undo_stack.push(transaction);
3594 self.undo_stack.last_mut()
3595 } else {
3596 None
3597 }
3598 }
3599
3600 fn remove_from_undo(&mut self, transaction_id: TransactionId) -> Option<&Transaction> {
3601 let ix = self
3602 .undo_stack
3603 .iter()
3604 .rposition(|transaction| transaction.id == transaction_id)?;
3605 let transaction = self.undo_stack.remove(ix);
3606 self.redo_stack.push(transaction);
3607 self.redo_stack.last()
3608 }
3609
3610 fn group(&mut self) -> Option<TransactionId> {
3611 let mut count = 0;
3612 let mut transactions = self.undo_stack.iter();
3613 if let Some(mut transaction) = transactions.next_back() {
3614 while let Some(prev_transaction) = transactions.next_back() {
3615 if !prev_transaction.suppress_grouping
3616 && transaction.first_edit_at - prev_transaction.last_edit_at
3617 <= self.group_interval
3618 {
3619 transaction = prev_transaction;
3620 count += 1;
3621 } else {
3622 break;
3623 }
3624 }
3625 }
3626 self.group_trailing(count)
3627 }
3628
3629 fn group_until(&mut self, transaction_id: TransactionId) {
3630 let mut count = 0;
3631 for transaction in self.undo_stack.iter().rev() {
3632 if transaction.id == transaction_id {
3633 self.group_trailing(count);
3634 break;
3635 } else if transaction.suppress_grouping {
3636 break;
3637 } else {
3638 count += 1;
3639 }
3640 }
3641 }
3642
3643 fn group_trailing(&mut self, n: usize) -> Option<TransactionId> {
3644 let new_len = self.undo_stack.len() - n;
3645 let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
3646 if let Some(last_transaction) = transactions_to_keep.last_mut() {
3647 if let Some(transaction) = transactions_to_merge.last() {
3648 last_transaction.last_edit_at = transaction.last_edit_at;
3649 }
3650 for to_merge in transactions_to_merge {
3651 for (buffer_id, transaction_id) in &to_merge.buffer_transactions {
3652 last_transaction
3653 .buffer_transactions
3654 .entry(*buffer_id)
3655 .or_insert(*transaction_id);
3656 }
3657 }
3658 }
3659
3660 self.undo_stack.truncate(new_len);
3661 self.undo_stack.last().map(|t| t.id)
3662 }
3663}
3664
3665impl Excerpt {
3666 fn new(
3667 id: ExcerptId,
3668 locator: Locator,
3669 buffer_id: BufferId,
3670 buffer: BufferSnapshot,
3671 range: ExcerptRange<text::Anchor>,
3672 has_trailing_newline: bool,
3673 ) -> Self {
3674 Excerpt {
3675 id,
3676 locator,
3677 max_buffer_row: range.context.end.to_point(&buffer).row,
3678 text_summary: buffer
3679 .text_summary_for_range::<TextSummary, _>(range.context.to_offset(&buffer)),
3680 buffer_id,
3681 buffer,
3682 range,
3683 has_trailing_newline,
3684 }
3685 }
3686
3687 fn chunks_in_range(&self, range: Range<usize>, language_aware: bool) -> ExcerptChunks {
3688 let content_start = self.range.context.start.to_offset(&self.buffer);
3689 let chunks_start = content_start + range.start;
3690 let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
3691
3692 let footer_height = if self.has_trailing_newline
3693 && range.start <= self.text_summary.len
3694 && range.end > self.text_summary.len
3695 {
3696 1
3697 } else {
3698 0
3699 };
3700
3701 let content_chunks = self.buffer.chunks(chunks_start..chunks_end, language_aware);
3702
3703 ExcerptChunks {
3704 content_chunks,
3705 footer_height,
3706 }
3707 }
3708
3709 fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
3710 let content_start = self.range.context.start.to_offset(&self.buffer);
3711 let bytes_start = content_start + range.start;
3712 let bytes_end = content_start + cmp::min(range.end, self.text_summary.len);
3713 let footer_height = if self.has_trailing_newline
3714 && range.start <= self.text_summary.len
3715 && range.end > self.text_summary.len
3716 {
3717 1
3718 } else {
3719 0
3720 };
3721 let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
3722
3723 ExcerptBytes {
3724 content_bytes,
3725 padding_height: footer_height,
3726 reversed: false,
3727 }
3728 }
3729
3730 fn reversed_bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
3731 let content_start = self.range.context.start.to_offset(&self.buffer);
3732 let bytes_start = content_start + range.start;
3733 let bytes_end = content_start + cmp::min(range.end, self.text_summary.len);
3734 let footer_height = if self.has_trailing_newline
3735 && range.start <= self.text_summary.len
3736 && range.end > self.text_summary.len
3737 {
3738 1
3739 } else {
3740 0
3741 };
3742 let content_bytes = self.buffer.reversed_bytes_in_range(bytes_start..bytes_end);
3743
3744 ExcerptBytes {
3745 content_bytes,
3746 padding_height: footer_height,
3747 reversed: true,
3748 }
3749 }
3750
3751 fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
3752 if text_anchor
3753 .cmp(&self.range.context.start, &self.buffer)
3754 .is_lt()
3755 {
3756 self.range.context.start
3757 } else if text_anchor
3758 .cmp(&self.range.context.end, &self.buffer)
3759 .is_gt()
3760 {
3761 self.range.context.end
3762 } else {
3763 text_anchor
3764 }
3765 }
3766
3767 fn contains(&self, anchor: &Anchor) -> bool {
3768 Some(self.buffer_id) == anchor.buffer_id
3769 && self
3770 .range
3771 .context
3772 .start
3773 .cmp(&anchor.text_anchor, &self.buffer)
3774 .is_le()
3775 && self
3776 .range
3777 .context
3778 .end
3779 .cmp(&anchor.text_anchor, &self.buffer)
3780 .is_ge()
3781 }
3782
3783 /// The [`Excerpt`]'s start offset in its [`Buffer`]
3784 fn buffer_start_offset(&self) -> usize {
3785 self.range.context.start.to_offset(&self.buffer)
3786 }
3787
3788 /// The [`Excerpt`]'s end offset in its [`Buffer`]
3789 fn buffer_end_offset(&self) -> usize {
3790 self.buffer_start_offset() + self.text_summary.len
3791 }
3792}
3793
3794impl<'a> MultiBufferExcerpt<'a> {
3795 fn new(excerpt: &'a Excerpt, excerpt_offset: usize) -> Self {
3796 MultiBufferExcerpt {
3797 excerpt,
3798 excerpt_offset,
3799 }
3800 }
3801
3802 pub fn buffer(&self) -> &'a BufferSnapshot {
3803 &self.excerpt.buffer
3804 }
3805
3806 /// Maps an offset within the [`MultiBuffer`] to an offset within the [`Buffer`]
3807 pub fn map_offset_to_buffer(&self, offset: usize) -> usize {
3808 self.excerpt.buffer_start_offset() + offset.saturating_sub(self.excerpt_offset)
3809 }
3810
3811 /// Maps a range within the [`MultiBuffer`] to a range within the [`Buffer`]
3812 pub fn map_range_to_buffer(&self, range: Range<usize>) -> Range<usize> {
3813 self.map_offset_to_buffer(range.start)..self.map_offset_to_buffer(range.end)
3814 }
3815
3816 /// Map an offset within the [`Buffer`] to an offset within the [`MultiBuffer`]
3817 pub fn map_offset_from_buffer(&self, buffer_offset: usize) -> usize {
3818 let mut buffer_offset_in_excerpt =
3819 buffer_offset.saturating_sub(self.excerpt.buffer_start_offset());
3820 buffer_offset_in_excerpt =
3821 cmp::min(buffer_offset_in_excerpt, self.excerpt.text_summary.len);
3822
3823 self.excerpt_offset + buffer_offset_in_excerpt
3824 }
3825
3826 /// Map a range within the [`Buffer`] to a range within the [`MultiBuffer`]
3827 pub fn map_range_from_buffer(&self, buffer_range: Range<usize>) -> Range<usize> {
3828 self.map_offset_from_buffer(buffer_range.start)
3829 ..self.map_offset_from_buffer(buffer_range.end)
3830 }
3831
3832 /// Returns true if the entirety of the given range is in the buffer's excerpt
3833 pub fn contains_buffer_range(&self, range: Range<usize>) -> bool {
3834 range.start >= self.excerpt.buffer_start_offset()
3835 && range.end <= self.excerpt.buffer_end_offset()
3836 }
3837}
3838
3839impl ExcerptId {
3840 pub fn min() -> Self {
3841 Self(0)
3842 }
3843
3844 pub fn max() -> Self {
3845 Self(usize::MAX)
3846 }
3847
3848 pub fn to_proto(&self) -> u64 {
3849 self.0 as _
3850 }
3851
3852 pub fn from_proto(proto: u64) -> Self {
3853 Self(proto as _)
3854 }
3855
3856 pub fn cmp(&self, other: &Self, snapshot: &MultiBufferSnapshot) -> cmp::Ordering {
3857 let a = snapshot.excerpt_locator_for_id(*self);
3858 let b = snapshot.excerpt_locator_for_id(*other);
3859 a.cmp(b).then_with(|| self.0.cmp(&other.0))
3860 }
3861}
3862
3863impl Into<usize> for ExcerptId {
3864 fn into(self) -> usize {
3865 self.0
3866 }
3867}
3868
3869impl fmt::Debug for Excerpt {
3870 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3871 f.debug_struct("Excerpt")
3872 .field("id", &self.id)
3873 .field("locator", &self.locator)
3874 .field("buffer_id", &self.buffer_id)
3875 .field("range", &self.range)
3876 .field("text_summary", &self.text_summary)
3877 .field("has_trailing_newline", &self.has_trailing_newline)
3878 .finish()
3879 }
3880}
3881
3882impl sum_tree::Item for Excerpt {
3883 type Summary = ExcerptSummary;
3884
3885 fn summary(&self) -> Self::Summary {
3886 let mut text = self.text_summary.clone();
3887 if self.has_trailing_newline {
3888 text += TextSummary::from("\n");
3889 }
3890 ExcerptSummary {
3891 excerpt_id: self.id,
3892 excerpt_locator: self.locator.clone(),
3893 max_buffer_row: self.max_buffer_row,
3894 text,
3895 }
3896 }
3897}
3898
3899impl sum_tree::Item for ExcerptIdMapping {
3900 type Summary = ExcerptId;
3901
3902 fn summary(&self) -> Self::Summary {
3903 self.id
3904 }
3905}
3906
3907impl sum_tree::KeyedItem for ExcerptIdMapping {
3908 type Key = ExcerptId;
3909
3910 fn key(&self) -> Self::Key {
3911 self.id
3912 }
3913}
3914
3915impl sum_tree::Summary for ExcerptId {
3916 type Context = ();
3917
3918 fn add_summary(&mut self, other: &Self, _: &()) {
3919 *self = *other;
3920 }
3921}
3922
3923impl sum_tree::Summary for ExcerptSummary {
3924 type Context = ();
3925
3926 fn add_summary(&mut self, summary: &Self, _: &()) {
3927 debug_assert!(summary.excerpt_locator > self.excerpt_locator);
3928 self.excerpt_locator = summary.excerpt_locator.clone();
3929 self.text.add_summary(&summary.text, &());
3930 self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row);
3931 }
3932}
3933
3934impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
3935 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3936 *self += &summary.text;
3937 }
3938}
3939
3940impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
3941 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3942 *self += summary.text.len;
3943 }
3944}
3945
3946impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
3947 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
3948 Ord::cmp(self, &cursor_location.text.len)
3949 }
3950}
3951
3952impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, Option<&'a Locator>> for Locator {
3953 fn cmp(&self, cursor_location: &Option<&'a Locator>, _: &()) -> cmp::Ordering {
3954 Ord::cmp(&Some(self), cursor_location)
3955 }
3956}
3957
3958impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Locator {
3959 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
3960 Ord::cmp(self, &cursor_location.excerpt_locator)
3961 }
3962}
3963
3964impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for OffsetUtf16 {
3965 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3966 *self += summary.text.len_utf16;
3967 }
3968}
3969
3970impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
3971 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3972 *self += summary.text.lines;
3973 }
3974}
3975
3976impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
3977 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3978 *self += summary.text.lines_utf16()
3979 }
3980}
3981
3982impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a Locator> {
3983 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3984 *self = Some(&summary.excerpt_locator);
3985 }
3986}
3987
3988impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<ExcerptId> {
3989 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3990 *self = Some(summary.excerpt_id);
3991 }
3992}
3993
3994impl<'a> MultiBufferRows<'a> {
3995 pub fn seek(&mut self, row: u32) {
3996 self.buffer_row_range = 0..0;
3997
3998 self.excerpts
3999 .seek_forward(&Point::new(row, 0), Bias::Right, &());
4000 if self.excerpts.item().is_none() {
4001 self.excerpts.prev(&());
4002
4003 if self.excerpts.item().is_none() && row == 0 {
4004 self.buffer_row_range = 0..1;
4005 return;
4006 }
4007 }
4008
4009 if let Some(excerpt) = self.excerpts.item() {
4010 let overshoot = row - self.excerpts.start().row;
4011 let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
4012 self.buffer_row_range.start = excerpt_start + overshoot;
4013 self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
4014 }
4015 }
4016}
4017
4018impl<'a> Iterator for MultiBufferRows<'a> {
4019 type Item = Option<u32>;
4020
4021 fn next(&mut self) -> Option<Self::Item> {
4022 loop {
4023 if !self.buffer_row_range.is_empty() {
4024 let row = Some(self.buffer_row_range.start);
4025 self.buffer_row_range.start += 1;
4026 return Some(row);
4027 }
4028 self.excerpts.item()?;
4029 self.excerpts.next(&());
4030 let excerpt = self.excerpts.item()?;
4031 self.buffer_row_range.start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
4032 self.buffer_row_range.end =
4033 self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
4034 }
4035 }
4036}
4037
4038impl<'a> MultiBufferChunks<'a> {
4039 pub fn offset(&self) -> usize {
4040 self.range.start
4041 }
4042
4043 pub fn seek(&mut self, offset: usize) {
4044 self.range.start = offset;
4045 self.excerpts.seek(&offset, Bias::Right, &());
4046 if let Some(excerpt) = self.excerpts.item() {
4047 self.excerpt_chunks = Some(excerpt.chunks_in_range(
4048 self.range.start - self.excerpts.start()..self.range.end - self.excerpts.start(),
4049 self.language_aware,
4050 ));
4051 } else {
4052 self.excerpt_chunks = None;
4053 }
4054 }
4055}
4056
4057impl<'a> Iterator for MultiBufferChunks<'a> {
4058 type Item = Chunk<'a>;
4059
4060 fn next(&mut self) -> Option<Self::Item> {
4061 if self.range.is_empty() {
4062 None
4063 } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
4064 self.range.start += chunk.text.len();
4065 Some(chunk)
4066 } else {
4067 self.excerpts.next(&());
4068 let excerpt = self.excerpts.item()?;
4069 self.excerpt_chunks = Some(excerpt.chunks_in_range(
4070 0..self.range.end - self.excerpts.start(),
4071 self.language_aware,
4072 ));
4073 self.next()
4074 }
4075 }
4076}
4077
4078impl<'a> MultiBufferBytes<'a> {
4079 fn consume(&mut self, len: usize) {
4080 self.range.start += len;
4081 self.chunk = &self.chunk[len..];
4082
4083 if !self.range.is_empty() && self.chunk.is_empty() {
4084 if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
4085 self.chunk = chunk;
4086 } else {
4087 self.excerpts.next(&());
4088 if let Some(excerpt) = self.excerpts.item() {
4089 let mut excerpt_bytes =
4090 excerpt.bytes_in_range(0..self.range.end - self.excerpts.start());
4091 self.chunk = excerpt_bytes.next().unwrap();
4092 self.excerpt_bytes = Some(excerpt_bytes);
4093 }
4094 }
4095 }
4096 }
4097}
4098
4099impl<'a> Iterator for MultiBufferBytes<'a> {
4100 type Item = &'a [u8];
4101
4102 fn next(&mut self) -> Option<Self::Item> {
4103 let chunk = self.chunk;
4104 if chunk.is_empty() {
4105 None
4106 } else {
4107 self.consume(chunk.len());
4108 Some(chunk)
4109 }
4110 }
4111}
4112
4113impl<'a> io::Read for MultiBufferBytes<'a> {
4114 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
4115 let len = cmp::min(buf.len(), self.chunk.len());
4116 buf[..len].copy_from_slice(&self.chunk[..len]);
4117 if len > 0 {
4118 self.consume(len);
4119 }
4120 Ok(len)
4121 }
4122}
4123
4124impl<'a> ReversedMultiBufferBytes<'a> {
4125 fn consume(&mut self, len: usize) {
4126 self.range.end -= len;
4127 self.chunk = &self.chunk[..self.chunk.len() - len];
4128
4129 if !self.range.is_empty() && self.chunk.is_empty() {
4130 if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
4131 self.chunk = chunk;
4132 } else {
4133 self.excerpts.prev(&());
4134 if let Some(excerpt) = self.excerpts.item() {
4135 let mut excerpt_bytes = excerpt.reversed_bytes_in_range(
4136 self.range.start.saturating_sub(*self.excerpts.start())..usize::MAX,
4137 );
4138 self.chunk = excerpt_bytes.next().unwrap();
4139 self.excerpt_bytes = Some(excerpt_bytes);
4140 }
4141 }
4142 } else {
4143 }
4144 }
4145}
4146
4147impl<'a> io::Read for ReversedMultiBufferBytes<'a> {
4148 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
4149 let len = cmp::min(buf.len(), self.chunk.len());
4150 buf[..len].copy_from_slice(&self.chunk[..len]);
4151 buf[..len].reverse();
4152 if len > 0 {
4153 self.consume(len);
4154 }
4155 Ok(len)
4156 }
4157}
4158impl<'a> Iterator for ExcerptBytes<'a> {
4159 type Item = &'a [u8];
4160
4161 fn next(&mut self) -> Option<Self::Item> {
4162 if self.reversed && self.padding_height > 0 {
4163 let result = &NEWLINES[..self.padding_height];
4164 self.padding_height = 0;
4165 return Some(result);
4166 }
4167
4168 if let Some(chunk) = self.content_bytes.next() {
4169 if !chunk.is_empty() {
4170 return Some(chunk);
4171 }
4172 }
4173
4174 if self.padding_height > 0 {
4175 let result = &NEWLINES[..self.padding_height];
4176 self.padding_height = 0;
4177 return Some(result);
4178 }
4179
4180 None
4181 }
4182}
4183
4184impl<'a> Iterator for ExcerptChunks<'a> {
4185 type Item = Chunk<'a>;
4186
4187 fn next(&mut self) -> Option<Self::Item> {
4188 if let Some(chunk) = self.content_chunks.next() {
4189 return Some(chunk);
4190 }
4191
4192 if self.footer_height > 0 {
4193 let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
4194 self.footer_height = 0;
4195 return Some(Chunk {
4196 text,
4197 ..Default::default()
4198 });
4199 }
4200
4201 None
4202 }
4203}
4204
4205impl ToOffset for Point {
4206 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
4207 snapshot.point_to_offset(*self)
4208 }
4209}
4210
4211impl ToOffset for usize {
4212 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
4213 assert!(*self <= snapshot.len(), "offset is out of range");
4214 *self
4215 }
4216}
4217
4218impl ToOffset for OffsetUtf16 {
4219 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
4220 snapshot.offset_utf16_to_offset(*self)
4221 }
4222}
4223
4224impl ToOffset for PointUtf16 {
4225 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
4226 snapshot.point_utf16_to_offset(*self)
4227 }
4228}
4229
4230impl ToOffsetUtf16 for OffsetUtf16 {
4231 fn to_offset_utf16(&self, _snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
4232 *self
4233 }
4234}
4235
4236impl ToOffsetUtf16 for usize {
4237 fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
4238 snapshot.offset_to_offset_utf16(*self)
4239 }
4240}
4241
4242impl ToPoint for usize {
4243 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
4244 snapshot.offset_to_point(*self)
4245 }
4246}
4247
4248impl ToPoint for Point {
4249 fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
4250 *self
4251 }
4252}
4253
4254impl ToPointUtf16 for usize {
4255 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
4256 snapshot.offset_to_point_utf16(*self)
4257 }
4258}
4259
4260impl ToPointUtf16 for Point {
4261 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
4262 snapshot.point_to_point_utf16(*self)
4263 }
4264}
4265
4266impl ToPointUtf16 for PointUtf16 {
4267 fn to_point_utf16<'a>(&self, _: &MultiBufferSnapshot) -> PointUtf16 {
4268 *self
4269 }
4270}
4271
4272fn build_excerpt_ranges<T>(
4273 buffer: &BufferSnapshot,
4274 ranges: &[Range<T>],
4275 context_line_count: u32,
4276) -> (Vec<ExcerptRange<Point>>, Vec<usize>)
4277where
4278 T: text::ToPoint,
4279{
4280 let max_point = buffer.max_point();
4281 let mut range_counts = Vec::new();
4282 let mut excerpt_ranges = Vec::new();
4283 let mut range_iter = ranges
4284 .iter()
4285 .map(|range| range.start.to_point(buffer)..range.end.to_point(buffer))
4286 .peekable();
4287 while let Some(range) = range_iter.next() {
4288 let excerpt_start = Point::new(range.start.row.saturating_sub(context_line_count), 0);
4289 let mut excerpt_end = Point::new(range.end.row + context_line_count, 0).min(max_point);
4290
4291 let mut ranges_in_excerpt = 1;
4292
4293 while let Some(next_range) = range_iter.peek() {
4294 if next_range.start.row <= excerpt_end.row + context_line_count {
4295 excerpt_end =
4296 Point::new(next_range.end.row + 1 + context_line_count, 0).min(max_point);
4297 ranges_in_excerpt += 1;
4298 range_iter.next();
4299 } else {
4300 break;
4301 }
4302 }
4303
4304 excerpt_ranges.push(ExcerptRange {
4305 context: excerpt_start..excerpt_end,
4306 primary: Some(range),
4307 });
4308 range_counts.push(ranges_in_excerpt);
4309 }
4310
4311 (excerpt_ranges, range_counts)
4312}
4313
4314#[cfg(test)]
4315mod tests {
4316 use super::*;
4317 use futures::StreamExt;
4318 use gpui::{AppContext, Context, TestAppContext};
4319 use language::{Buffer, Rope};
4320 use parking_lot::RwLock;
4321 use rand::prelude::*;
4322 use settings::SettingsStore;
4323 use std::env;
4324 use util::test::sample_text;
4325
4326 #[gpui::test]
4327 fn test_singleton(cx: &mut AppContext) {
4328 let buffer = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
4329 let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
4330
4331 let snapshot = multibuffer.read(cx).snapshot(cx);
4332 assert_eq!(snapshot.text(), buffer.read(cx).text());
4333
4334 assert_eq!(
4335 snapshot.buffer_rows(0).collect::<Vec<_>>(),
4336 (0..buffer.read(cx).row_count())
4337 .map(Some)
4338 .collect::<Vec<_>>()
4339 );
4340
4341 buffer.update(cx, |buffer, cx| buffer.edit([(1..3, "XXX\n")], None, cx));
4342 let snapshot = multibuffer.read(cx).snapshot(cx);
4343
4344 assert_eq!(snapshot.text(), buffer.read(cx).text());
4345 assert_eq!(
4346 snapshot.buffer_rows(0).collect::<Vec<_>>(),
4347 (0..buffer.read(cx).row_count())
4348 .map(Some)
4349 .collect::<Vec<_>>()
4350 );
4351 }
4352
4353 #[gpui::test]
4354 fn test_remote(cx: &mut AppContext) {
4355 let host_buffer = cx.new_model(|cx| Buffer::local("a", cx));
4356 let guest_buffer = cx.new_model(|cx| {
4357 let state = host_buffer.read(cx).to_proto();
4358 let ops = cx
4359 .background_executor()
4360 .block(host_buffer.read(cx).serialize_ops(None, cx));
4361 let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
4362 buffer
4363 .apply_ops(
4364 ops.into_iter()
4365 .map(|op| language::proto::deserialize_operation(op).unwrap()),
4366 cx,
4367 )
4368 .unwrap();
4369 buffer
4370 });
4371 let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(guest_buffer.clone(), cx));
4372 let snapshot = multibuffer.read(cx).snapshot(cx);
4373 assert_eq!(snapshot.text(), "a");
4374
4375 guest_buffer.update(cx, |buffer, cx| buffer.edit([(1..1, "b")], None, cx));
4376 let snapshot = multibuffer.read(cx).snapshot(cx);
4377 assert_eq!(snapshot.text(), "ab");
4378
4379 guest_buffer.update(cx, |buffer, cx| buffer.edit([(2..2, "c")], None, cx));
4380 let snapshot = multibuffer.read(cx).snapshot(cx);
4381 assert_eq!(snapshot.text(), "abc");
4382 }
4383
4384 #[gpui::test]
4385 fn test_excerpt_boundaries_and_clipping(cx: &mut AppContext) {
4386 let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
4387 let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx));
4388 let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
4389
4390 let events = Arc::new(RwLock::new(Vec::<Event>::new()));
4391 multibuffer.update(cx, |_, cx| {
4392 let events = events.clone();
4393 cx.subscribe(&multibuffer, move |_, _, event, _| {
4394 if let Event::Edited { .. } = event {
4395 events.write().push(event.clone())
4396 }
4397 })
4398 .detach();
4399 });
4400
4401 let subscription = multibuffer.update(cx, |multibuffer, cx| {
4402 let subscription = multibuffer.subscribe();
4403 multibuffer.push_excerpts(
4404 buffer_1.clone(),
4405 [ExcerptRange {
4406 context: Point::new(1, 2)..Point::new(2, 5),
4407 primary: None,
4408 }],
4409 cx,
4410 );
4411 assert_eq!(
4412 subscription.consume().into_inner(),
4413 [Edit {
4414 old: 0..0,
4415 new: 0..10
4416 }]
4417 );
4418
4419 multibuffer.push_excerpts(
4420 buffer_1.clone(),
4421 [ExcerptRange {
4422 context: Point::new(3, 3)..Point::new(4, 4),
4423 primary: None,
4424 }],
4425 cx,
4426 );
4427 multibuffer.push_excerpts(
4428 buffer_2.clone(),
4429 [ExcerptRange {
4430 context: Point::new(3, 1)..Point::new(3, 3),
4431 primary: None,
4432 }],
4433 cx,
4434 );
4435 assert_eq!(
4436 subscription.consume().into_inner(),
4437 [Edit {
4438 old: 10..10,
4439 new: 10..22
4440 }]
4441 );
4442
4443 subscription
4444 });
4445
4446 // Adding excerpts emits an edited event.
4447 assert_eq!(
4448 events.read().as_slice(),
4449 &[
4450 Event::Edited {
4451 singleton_buffer_edited: false
4452 },
4453 Event::Edited {
4454 singleton_buffer_edited: false
4455 },
4456 Event::Edited {
4457 singleton_buffer_edited: false
4458 }
4459 ]
4460 );
4461
4462 let snapshot = multibuffer.read(cx).snapshot(cx);
4463 assert_eq!(
4464 snapshot.text(),
4465 concat!(
4466 "bbbb\n", // Preserve newlines
4467 "ccccc\n", //
4468 "ddd\n", //
4469 "eeee\n", //
4470 "jj" //
4471 )
4472 );
4473 assert_eq!(
4474 snapshot.buffer_rows(0).collect::<Vec<_>>(),
4475 [Some(1), Some(2), Some(3), Some(4), Some(3)]
4476 );
4477 assert_eq!(
4478 snapshot.buffer_rows(2).collect::<Vec<_>>(),
4479 [Some(3), Some(4), Some(3)]
4480 );
4481 assert_eq!(snapshot.buffer_rows(4).collect::<Vec<_>>(), [Some(3)]);
4482 assert_eq!(snapshot.buffer_rows(5).collect::<Vec<_>>(), []);
4483
4484 assert_eq!(
4485 boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot),
4486 &[
4487 (0, "bbbb\nccccc".to_string(), true),
4488 (2, "ddd\neeee".to_string(), false),
4489 (4, "jj".to_string(), true),
4490 ]
4491 );
4492 assert_eq!(
4493 boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot),
4494 &[(0, "bbbb\nccccc".to_string(), true)]
4495 );
4496 assert_eq!(
4497 boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot),
4498 &[]
4499 );
4500 assert_eq!(
4501 boundaries_in_range(Point::new(1, 0)..Point::new(2, 0), &snapshot),
4502 &[]
4503 );
4504 assert_eq!(
4505 boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
4506 &[(2, "ddd\neeee".to_string(), false)]
4507 );
4508 assert_eq!(
4509 boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
4510 &[(2, "ddd\neeee".to_string(), false)]
4511 );
4512 assert_eq!(
4513 boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot),
4514 &[(2, "ddd\neeee".to_string(), false)]
4515 );
4516 assert_eq!(
4517 boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot),
4518 &[(4, "jj".to_string(), true)]
4519 );
4520 assert_eq!(
4521 boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot),
4522 &[]
4523 );
4524
4525 buffer_1.update(cx, |buffer, cx| {
4526 let text = "\n";
4527 buffer.edit(
4528 [
4529 (Point::new(0, 0)..Point::new(0, 0), text),
4530 (Point::new(2, 1)..Point::new(2, 3), text),
4531 ],
4532 None,
4533 cx,
4534 );
4535 });
4536
4537 let snapshot = multibuffer.read(cx).snapshot(cx);
4538 assert_eq!(
4539 snapshot.text(),
4540 concat!(
4541 "bbbb\n", // Preserve newlines
4542 "c\n", //
4543 "cc\n", //
4544 "ddd\n", //
4545 "eeee\n", //
4546 "jj" //
4547 )
4548 );
4549
4550 assert_eq!(
4551 subscription.consume().into_inner(),
4552 [Edit {
4553 old: 6..8,
4554 new: 6..7
4555 }]
4556 );
4557
4558 let snapshot = multibuffer.read(cx).snapshot(cx);
4559 assert_eq!(
4560 snapshot.clip_point(Point::new(0, 5), Bias::Left),
4561 Point::new(0, 4)
4562 );
4563 assert_eq!(
4564 snapshot.clip_point(Point::new(0, 5), Bias::Right),
4565 Point::new(0, 4)
4566 );
4567 assert_eq!(
4568 snapshot.clip_point(Point::new(5, 1), Bias::Right),
4569 Point::new(5, 1)
4570 );
4571 assert_eq!(
4572 snapshot.clip_point(Point::new(5, 2), Bias::Right),
4573 Point::new(5, 2)
4574 );
4575 assert_eq!(
4576 snapshot.clip_point(Point::new(5, 3), Bias::Right),
4577 Point::new(5, 2)
4578 );
4579
4580 let snapshot = multibuffer.update(cx, |multibuffer, cx| {
4581 let (buffer_2_excerpt_id, _) =
4582 multibuffer.excerpts_for_buffer(&buffer_2, cx)[0].clone();
4583 multibuffer.remove_excerpts([buffer_2_excerpt_id], cx);
4584 multibuffer.snapshot(cx)
4585 });
4586
4587 assert_eq!(
4588 snapshot.text(),
4589 concat!(
4590 "bbbb\n", // Preserve newlines
4591 "c\n", //
4592 "cc\n", //
4593 "ddd\n", //
4594 "eeee", //
4595 )
4596 );
4597
4598 fn boundaries_in_range(
4599 range: Range<Point>,
4600 snapshot: &MultiBufferSnapshot,
4601 ) -> Vec<(u32, String, bool)> {
4602 snapshot
4603 .excerpt_boundaries_in_range(range)
4604 .map(|boundary| {
4605 (
4606 boundary.row,
4607 boundary
4608 .buffer
4609 .text_for_range(boundary.range.context)
4610 .collect::<String>(),
4611 boundary.starts_new_buffer,
4612 )
4613 })
4614 .collect::<Vec<_>>()
4615 }
4616 }
4617
4618 #[gpui::test]
4619 fn test_excerpt_events(cx: &mut AppContext) {
4620 let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(10, 3, 'a'), cx));
4621 let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(10, 3, 'm'), cx));
4622
4623 let leader_multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
4624 let follower_multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
4625 let follower_edit_event_count = Arc::new(RwLock::new(0));
4626
4627 follower_multibuffer.update(cx, |_, cx| {
4628 let follower_edit_event_count = follower_edit_event_count.clone();
4629 cx.subscribe(
4630 &leader_multibuffer,
4631 move |follower, _, event, cx| match event.clone() {
4632 Event::ExcerptsAdded {
4633 buffer,
4634 predecessor,
4635 excerpts,
4636 } => follower.insert_excerpts_with_ids_after(predecessor, buffer, excerpts, cx),
4637 Event::ExcerptsRemoved { ids } => follower.remove_excerpts(ids, cx),
4638 Event::Edited { .. } => {
4639 *follower_edit_event_count.write() += 1;
4640 }
4641 _ => {}
4642 },
4643 )
4644 .detach();
4645 });
4646
4647 leader_multibuffer.update(cx, |leader, cx| {
4648 leader.push_excerpts(
4649 buffer_1.clone(),
4650 [
4651 ExcerptRange {
4652 context: 0..8,
4653 primary: None,
4654 },
4655 ExcerptRange {
4656 context: 12..16,
4657 primary: None,
4658 },
4659 ],
4660 cx,
4661 );
4662 leader.insert_excerpts_after(
4663 leader.excerpt_ids()[0],
4664 buffer_2.clone(),
4665 [
4666 ExcerptRange {
4667 context: 0..5,
4668 primary: None,
4669 },
4670 ExcerptRange {
4671 context: 10..15,
4672 primary: None,
4673 },
4674 ],
4675 cx,
4676 )
4677 });
4678 assert_eq!(
4679 leader_multibuffer.read(cx).snapshot(cx).text(),
4680 follower_multibuffer.read(cx).snapshot(cx).text(),
4681 );
4682 assert_eq!(*follower_edit_event_count.read(), 2);
4683
4684 leader_multibuffer.update(cx, |leader, cx| {
4685 let excerpt_ids = leader.excerpt_ids();
4686 leader.remove_excerpts([excerpt_ids[1], excerpt_ids[3]], cx);
4687 });
4688 assert_eq!(
4689 leader_multibuffer.read(cx).snapshot(cx).text(),
4690 follower_multibuffer.read(cx).snapshot(cx).text(),
4691 );
4692 assert_eq!(*follower_edit_event_count.read(), 3);
4693
4694 // Removing an empty set of excerpts is a noop.
4695 leader_multibuffer.update(cx, |leader, cx| {
4696 leader.remove_excerpts([], cx);
4697 });
4698 assert_eq!(
4699 leader_multibuffer.read(cx).snapshot(cx).text(),
4700 follower_multibuffer.read(cx).snapshot(cx).text(),
4701 );
4702 assert_eq!(*follower_edit_event_count.read(), 3);
4703
4704 // Adding an empty set of excerpts is a noop.
4705 leader_multibuffer.update(cx, |leader, cx| {
4706 leader.push_excerpts::<usize>(buffer_2.clone(), [], cx);
4707 });
4708 assert_eq!(
4709 leader_multibuffer.read(cx).snapshot(cx).text(),
4710 follower_multibuffer.read(cx).snapshot(cx).text(),
4711 );
4712 assert_eq!(*follower_edit_event_count.read(), 3);
4713
4714 leader_multibuffer.update(cx, |leader, cx| {
4715 leader.clear(cx);
4716 });
4717 assert_eq!(
4718 leader_multibuffer.read(cx).snapshot(cx).text(),
4719 follower_multibuffer.read(cx).snapshot(cx).text(),
4720 );
4721 assert_eq!(*follower_edit_event_count.read(), 4);
4722 }
4723
4724 #[gpui::test]
4725 fn test_push_excerpts_with_context_lines(cx: &mut AppContext) {
4726 let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
4727 let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
4728 let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
4729 multibuffer.push_excerpts_with_context_lines(
4730 buffer.clone(),
4731 vec![
4732 Point::new(3, 2)..Point::new(4, 2),
4733 Point::new(7, 1)..Point::new(7, 3),
4734 Point::new(15, 0)..Point::new(15, 0),
4735 ],
4736 2,
4737 cx,
4738 )
4739 });
4740
4741 let snapshot = multibuffer.read(cx).snapshot(cx);
4742 assert_eq!(
4743 snapshot.text(),
4744 "bbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\n\nnnn\nooo\nppp\nqqq\n"
4745 );
4746
4747 assert_eq!(
4748 anchor_ranges
4749 .iter()
4750 .map(|range| range.to_point(&snapshot))
4751 .collect::<Vec<_>>(),
4752 vec![
4753 Point::new(2, 2)..Point::new(3, 2),
4754 Point::new(6, 1)..Point::new(6, 3),
4755 Point::new(12, 0)..Point::new(12, 0)
4756 ]
4757 );
4758 }
4759
4760 #[gpui::test]
4761 async fn test_stream_excerpts_with_context_lines(cx: &mut TestAppContext) {
4762 let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
4763 let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
4764 let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
4765 let snapshot = buffer.read(cx);
4766 let ranges = vec![
4767 snapshot.anchor_before(Point::new(3, 2))..snapshot.anchor_before(Point::new(4, 2)),
4768 snapshot.anchor_before(Point::new(7, 1))..snapshot.anchor_before(Point::new(7, 3)),
4769 snapshot.anchor_before(Point::new(15, 0))
4770 ..snapshot.anchor_before(Point::new(15, 0)),
4771 ];
4772 multibuffer.stream_excerpts_with_context_lines(buffer.clone(), ranges, 2, cx)
4773 });
4774
4775 let anchor_ranges = anchor_ranges.collect::<Vec<_>>().await;
4776
4777 let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx));
4778 assert_eq!(
4779 snapshot.text(),
4780 "bbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\n\nnnn\nooo\nppp\nqqq\n"
4781 );
4782
4783 assert_eq!(
4784 anchor_ranges
4785 .iter()
4786 .map(|range| range.to_point(&snapshot))
4787 .collect::<Vec<_>>(),
4788 vec![
4789 Point::new(2, 2)..Point::new(3, 2),
4790 Point::new(6, 1)..Point::new(6, 3),
4791 Point::new(12, 0)..Point::new(12, 0)
4792 ]
4793 );
4794 }
4795
4796 #[gpui::test]
4797 fn test_empty_multibuffer(cx: &mut AppContext) {
4798 let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
4799
4800 let snapshot = multibuffer.read(cx).snapshot(cx);
4801 assert_eq!(snapshot.text(), "");
4802 assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), &[Some(0)]);
4803 assert_eq!(snapshot.buffer_rows(1).collect::<Vec<_>>(), &[]);
4804 }
4805
4806 #[gpui::test]
4807 fn test_singleton_multibuffer_anchors(cx: &mut AppContext) {
4808 let buffer = cx.new_model(|cx| Buffer::local("abcd", cx));
4809 let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
4810 let old_snapshot = multibuffer.read(cx).snapshot(cx);
4811 buffer.update(cx, |buffer, cx| {
4812 buffer.edit([(0..0, "X")], None, cx);
4813 buffer.edit([(5..5, "Y")], None, cx);
4814 });
4815 let new_snapshot = multibuffer.read(cx).snapshot(cx);
4816
4817 assert_eq!(old_snapshot.text(), "abcd");
4818 assert_eq!(new_snapshot.text(), "XabcdY");
4819
4820 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
4821 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
4822 assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
4823 assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
4824 }
4825
4826 #[gpui::test]
4827 fn test_multibuffer_anchors(cx: &mut AppContext) {
4828 let buffer_1 = cx.new_model(|cx| Buffer::local("abcd", cx));
4829 let buffer_2 = cx.new_model(|cx| Buffer::local("efghi", cx));
4830 let multibuffer = cx.new_model(|cx| {
4831 let mut multibuffer = MultiBuffer::new(0, Capability::ReadWrite);
4832 multibuffer.push_excerpts(
4833 buffer_1.clone(),
4834 [ExcerptRange {
4835 context: 0..4,
4836 primary: None,
4837 }],
4838 cx,
4839 );
4840 multibuffer.push_excerpts(
4841 buffer_2.clone(),
4842 [ExcerptRange {
4843 context: 0..5,
4844 primary: None,
4845 }],
4846 cx,
4847 );
4848 multibuffer
4849 });
4850 let old_snapshot = multibuffer.read(cx).snapshot(cx);
4851
4852 assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
4853 assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
4854 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
4855 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
4856 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
4857 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
4858
4859 buffer_1.update(cx, |buffer, cx| {
4860 buffer.edit([(0..0, "W")], None, cx);
4861 buffer.edit([(5..5, "X")], None, cx);
4862 });
4863 buffer_2.update(cx, |buffer, cx| {
4864 buffer.edit([(0..0, "Y")], None, cx);
4865 buffer.edit([(6..6, "Z")], None, cx);
4866 });
4867 let new_snapshot = multibuffer.read(cx).snapshot(cx);
4868
4869 assert_eq!(old_snapshot.text(), "abcd\nefghi");
4870 assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
4871
4872 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
4873 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
4874 assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
4875 assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
4876 assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
4877 assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
4878 assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
4879 assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
4880 assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
4881 assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
4882 }
4883
4884 #[gpui::test]
4885 fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut AppContext) {
4886 let buffer_1 = cx.new_model(|cx| Buffer::local("abcd", cx));
4887 let buffer_2 = cx.new_model(|cx| Buffer::local("ABCDEFGHIJKLMNOP", cx));
4888 let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
4889
4890 // Create an insertion id in buffer 1 that doesn't exist in buffer 2.
4891 // Add an excerpt from buffer 1 that spans this new insertion.
4892 buffer_1.update(cx, |buffer, cx| buffer.edit([(4..4, "123")], None, cx));
4893 let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| {
4894 multibuffer
4895 .push_excerpts(
4896 buffer_1.clone(),
4897 [ExcerptRange {
4898 context: 0..7,
4899 primary: None,
4900 }],
4901 cx,
4902 )
4903 .pop()
4904 .unwrap()
4905 });
4906
4907 let snapshot_1 = multibuffer.read(cx).snapshot(cx);
4908 assert_eq!(snapshot_1.text(), "abcd123");
4909
4910 // Replace the buffer 1 excerpt with new excerpts from buffer 2.
4911 let (excerpt_id_2, excerpt_id_3) = multibuffer.update(cx, |multibuffer, cx| {
4912 multibuffer.remove_excerpts([excerpt_id_1], cx);
4913 let mut ids = multibuffer
4914 .push_excerpts(
4915 buffer_2.clone(),
4916 [
4917 ExcerptRange {
4918 context: 0..4,
4919 primary: None,
4920 },
4921 ExcerptRange {
4922 context: 6..10,
4923 primary: None,
4924 },
4925 ExcerptRange {
4926 context: 12..16,
4927 primary: None,
4928 },
4929 ],
4930 cx,
4931 )
4932 .into_iter();
4933 (ids.next().unwrap(), ids.next().unwrap())
4934 });
4935 let snapshot_2 = multibuffer.read(cx).snapshot(cx);
4936 assert_eq!(snapshot_2.text(), "ABCD\nGHIJ\nMNOP");
4937
4938 // The old excerpt id doesn't get reused.
4939 assert_ne!(excerpt_id_2, excerpt_id_1);
4940
4941 // Resolve some anchors from the previous snapshot in the new snapshot.
4942 // The current excerpts are from a different buffer, so we don't attempt to
4943 // resolve the old text anchor in the new buffer.
4944 assert_eq!(
4945 snapshot_2.summary_for_anchor::<usize>(&snapshot_1.anchor_before(2)),
4946 0
4947 );
4948 assert_eq!(
4949 snapshot_2.summaries_for_anchors::<usize, _>(&[
4950 snapshot_1.anchor_before(2),
4951 snapshot_1.anchor_after(3)
4952 ]),
4953 vec![0, 0]
4954 );
4955
4956 // Refresh anchors from the old snapshot. The return value indicates that both
4957 // anchors lost their original excerpt.
4958 let refresh =
4959 snapshot_2.refresh_anchors(&[snapshot_1.anchor_before(2), snapshot_1.anchor_after(3)]);
4960 assert_eq!(
4961 refresh,
4962 &[
4963 (0, snapshot_2.anchor_before(0), false),
4964 (1, snapshot_2.anchor_after(0), false),
4965 ]
4966 );
4967
4968 // Replace the middle excerpt with a smaller excerpt in buffer 2,
4969 // that intersects the old excerpt.
4970 let excerpt_id_5 = multibuffer.update(cx, |multibuffer, cx| {
4971 multibuffer.remove_excerpts([excerpt_id_3], cx);
4972 multibuffer
4973 .insert_excerpts_after(
4974 excerpt_id_2,
4975 buffer_2.clone(),
4976 [ExcerptRange {
4977 context: 5..8,
4978 primary: None,
4979 }],
4980 cx,
4981 )
4982 .pop()
4983 .unwrap()
4984 });
4985
4986 let snapshot_3 = multibuffer.read(cx).snapshot(cx);
4987 assert_eq!(snapshot_3.text(), "ABCD\nFGH\nMNOP");
4988 assert_ne!(excerpt_id_5, excerpt_id_3);
4989
4990 // Resolve some anchors from the previous snapshot in the new snapshot.
4991 // The third anchor can't be resolved, since its excerpt has been removed,
4992 // so it resolves to the same position as its predecessor.
4993 let anchors = [
4994 snapshot_2.anchor_before(0),
4995 snapshot_2.anchor_after(2),
4996 snapshot_2.anchor_after(6),
4997 snapshot_2.anchor_after(14),
4998 ];
4999 assert_eq!(
5000 snapshot_3.summaries_for_anchors::<usize, _>(&anchors),
5001 &[0, 2, 9, 13]
5002 );
5003
5004 let new_anchors = snapshot_3.refresh_anchors(&anchors);
5005 assert_eq!(
5006 new_anchors.iter().map(|a| (a.0, a.2)).collect::<Vec<_>>(),
5007 &[(0, true), (1, true), (2, true), (3, true)]
5008 );
5009 assert_eq!(
5010 snapshot_3.summaries_for_anchors::<usize, _>(new_anchors.iter().map(|a| &a.1)),
5011 &[0, 2, 7, 13]
5012 );
5013 }
5014
5015 #[gpui::test(iterations = 100)]
5016 fn test_random_multibuffer(cx: &mut AppContext, mut rng: StdRng) {
5017 let operations = env::var("OPERATIONS")
5018 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
5019 .unwrap_or(10);
5020
5021 let mut buffers: Vec<Model<Buffer>> = Vec::new();
5022 let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
5023 let mut excerpt_ids = Vec::<ExcerptId>::new();
5024 let mut expected_excerpts = Vec::<(Model<Buffer>, Range<text::Anchor>)>::new();
5025 let mut anchors = Vec::new();
5026 let mut old_versions = Vec::new();
5027
5028 for _ in 0..operations {
5029 match rng.gen_range(0..100) {
5030 0..=19 if !buffers.is_empty() => {
5031 let buffer = buffers.choose(&mut rng).unwrap();
5032 buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
5033 }
5034 20..=29 if !expected_excerpts.is_empty() => {
5035 let mut ids_to_remove = vec![];
5036 for _ in 0..rng.gen_range(1..=3) {
5037 if expected_excerpts.is_empty() {
5038 break;
5039 }
5040
5041 let ix = rng.gen_range(0..expected_excerpts.len());
5042 ids_to_remove.push(excerpt_ids.remove(ix));
5043 let (buffer, range) = expected_excerpts.remove(ix);
5044 let buffer = buffer.read(cx);
5045 log::info!(
5046 "Removing excerpt {}: {:?}",
5047 ix,
5048 buffer
5049 .text_for_range(range.to_offset(buffer))
5050 .collect::<String>(),
5051 );
5052 }
5053 let snapshot = multibuffer.read(cx).read(cx);
5054 ids_to_remove.sort_unstable_by(|a, b| a.cmp(&b, &snapshot));
5055 drop(snapshot);
5056 multibuffer.update(cx, |multibuffer, cx| {
5057 multibuffer.remove_excerpts(ids_to_remove, cx)
5058 });
5059 }
5060 30..=39 if !expected_excerpts.is_empty() => {
5061 let multibuffer = multibuffer.read(cx).read(cx);
5062 let offset =
5063 multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left);
5064 let bias = if rng.gen() { Bias::Left } else { Bias::Right };
5065 log::info!("Creating anchor at {} with bias {:?}", offset, bias);
5066 anchors.push(multibuffer.anchor_at(offset, bias));
5067 anchors.sort_by(|a, b| a.cmp(b, &multibuffer));
5068 }
5069 40..=44 if !anchors.is_empty() => {
5070 let multibuffer = multibuffer.read(cx).read(cx);
5071 let prev_len = anchors.len();
5072 anchors = multibuffer
5073 .refresh_anchors(&anchors)
5074 .into_iter()
5075 .map(|a| a.1)
5076 .collect();
5077
5078 // Ensure the newly-refreshed anchors point to a valid excerpt and don't
5079 // overshoot its boundaries.
5080 assert_eq!(anchors.len(), prev_len);
5081 for anchor in &anchors {
5082 if anchor.excerpt_id == ExcerptId::min()
5083 || anchor.excerpt_id == ExcerptId::max()
5084 {
5085 continue;
5086 }
5087
5088 let excerpt = multibuffer.excerpt(anchor.excerpt_id).unwrap();
5089 assert_eq!(excerpt.id, anchor.excerpt_id);
5090 assert!(excerpt.contains(anchor));
5091 }
5092 }
5093 _ => {
5094 let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
5095 let base_text = util::RandomCharIter::new(&mut rng)
5096 .take(10)
5097 .collect::<String>();
5098 buffers.push(cx.new_model(|cx| Buffer::local(base_text, cx)));
5099 buffers.last().unwrap()
5100 } else {
5101 buffers.choose(&mut rng).unwrap()
5102 };
5103
5104 let buffer = buffer_handle.read(cx);
5105 let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
5106 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
5107 let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
5108 let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len());
5109 let prev_excerpt_id = excerpt_ids
5110 .get(prev_excerpt_ix)
5111 .cloned()
5112 .unwrap_or_else(ExcerptId::max);
5113 let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len());
5114
5115 log::info!(
5116 "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}",
5117 excerpt_ix,
5118 expected_excerpts.len(),
5119 buffer_handle.read(cx).remote_id(),
5120 buffer.text(),
5121 start_ix..end_ix,
5122 &buffer.text()[start_ix..end_ix]
5123 );
5124
5125 let excerpt_id = multibuffer.update(cx, |multibuffer, cx| {
5126 multibuffer
5127 .insert_excerpts_after(
5128 prev_excerpt_id,
5129 buffer_handle.clone(),
5130 [ExcerptRange {
5131 context: start_ix..end_ix,
5132 primary: None,
5133 }],
5134 cx,
5135 )
5136 .pop()
5137 .unwrap()
5138 });
5139
5140 excerpt_ids.insert(excerpt_ix, excerpt_id);
5141 expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range));
5142 }
5143 }
5144
5145 if rng.gen_bool(0.3) {
5146 multibuffer.update(cx, |multibuffer, cx| {
5147 old_versions.push((multibuffer.snapshot(cx), multibuffer.subscribe()));
5148 })
5149 }
5150
5151 let snapshot = multibuffer.read(cx).snapshot(cx);
5152
5153 let mut excerpt_starts = Vec::new();
5154 let mut expected_text = String::new();
5155 let mut expected_buffer_rows = Vec::new();
5156 for (buffer, range) in &expected_excerpts {
5157 let buffer = buffer.read(cx);
5158 let buffer_range = range.to_offset(buffer);
5159
5160 excerpt_starts.push(TextSummary::from(expected_text.as_str()));
5161 expected_text.extend(buffer.text_for_range(buffer_range.clone()));
5162 expected_text.push('\n');
5163
5164 let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
5165 ..=buffer.offset_to_point(buffer_range.end).row;
5166 for row in buffer_row_range {
5167 expected_buffer_rows.push(Some(row));
5168 }
5169 }
5170 // Remove final trailing newline.
5171 if !expected_excerpts.is_empty() {
5172 expected_text.pop();
5173 }
5174
5175 // Always report one buffer row
5176 if expected_buffer_rows.is_empty() {
5177 expected_buffer_rows.push(Some(0));
5178 }
5179
5180 assert_eq!(snapshot.text(), expected_text);
5181 log::info!("MultiBuffer text: {:?}", expected_text);
5182
5183 assert_eq!(
5184 snapshot.buffer_rows(0).collect::<Vec<_>>(),
5185 expected_buffer_rows,
5186 );
5187
5188 for _ in 0..5 {
5189 let start_row = rng.gen_range(0..=expected_buffer_rows.len());
5190 assert_eq!(
5191 snapshot.buffer_rows(start_row as u32).collect::<Vec<_>>(),
5192 &expected_buffer_rows[start_row..],
5193 "buffer_rows({})",
5194 start_row
5195 );
5196 }
5197
5198 assert_eq!(
5199 snapshot.max_buffer_row(),
5200 expected_buffer_rows.into_iter().flatten().max().unwrap()
5201 );
5202
5203 let mut excerpt_starts = excerpt_starts.into_iter();
5204 for (buffer, range) in &expected_excerpts {
5205 let buffer = buffer.read(cx);
5206 let buffer_id = buffer.remote_id();
5207 let buffer_range = range.to_offset(buffer);
5208 let buffer_start_point = buffer.offset_to_point(buffer_range.start);
5209 let buffer_start_point_utf16 =
5210 buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
5211
5212 let excerpt_start = excerpt_starts.next().unwrap();
5213 let mut offset = excerpt_start.len;
5214 let mut buffer_offset = buffer_range.start;
5215 let mut point = excerpt_start.lines;
5216 let mut buffer_point = buffer_start_point;
5217 let mut point_utf16 = excerpt_start.lines_utf16();
5218 let mut buffer_point_utf16 = buffer_start_point_utf16;
5219 for ch in buffer
5220 .snapshot()
5221 .chunks(buffer_range.clone(), false)
5222 .flat_map(|c| c.text.chars())
5223 {
5224 for _ in 0..ch.len_utf8() {
5225 let left_offset = snapshot.clip_offset(offset, Bias::Left);
5226 let right_offset = snapshot.clip_offset(offset, Bias::Right);
5227 let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
5228 let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
5229 assert_eq!(
5230 left_offset,
5231 excerpt_start.len + (buffer_left_offset - buffer_range.start),
5232 "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
5233 offset,
5234 buffer_id,
5235 buffer_offset,
5236 );
5237 assert_eq!(
5238 right_offset,
5239 excerpt_start.len + (buffer_right_offset - buffer_range.start),
5240 "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
5241 offset,
5242 buffer_id,
5243 buffer_offset,
5244 );
5245
5246 let left_point = snapshot.clip_point(point, Bias::Left);
5247 let right_point = snapshot.clip_point(point, Bias::Right);
5248 let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
5249 let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
5250 assert_eq!(
5251 left_point,
5252 excerpt_start.lines + (buffer_left_point - buffer_start_point),
5253 "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
5254 point,
5255 buffer_id,
5256 buffer_point,
5257 );
5258 assert_eq!(
5259 right_point,
5260 excerpt_start.lines + (buffer_right_point - buffer_start_point),
5261 "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
5262 point,
5263 buffer_id,
5264 buffer_point,
5265 );
5266
5267 assert_eq!(
5268 snapshot.point_to_offset(left_point),
5269 left_offset,
5270 "point_to_offset({:?})",
5271 left_point,
5272 );
5273 assert_eq!(
5274 snapshot.offset_to_point(left_offset),
5275 left_point,
5276 "offset_to_point({:?})",
5277 left_offset,
5278 );
5279
5280 offset += 1;
5281 buffer_offset += 1;
5282 if ch == '\n' {
5283 point += Point::new(1, 0);
5284 buffer_point += Point::new(1, 0);
5285 } else {
5286 point += Point::new(0, 1);
5287 buffer_point += Point::new(0, 1);
5288 }
5289 }
5290
5291 for _ in 0..ch.len_utf16() {
5292 let left_point_utf16 =
5293 snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Left);
5294 let right_point_utf16 =
5295 snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Right);
5296 let buffer_left_point_utf16 =
5297 buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Left);
5298 let buffer_right_point_utf16 =
5299 buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Right);
5300 assert_eq!(
5301 left_point_utf16,
5302 excerpt_start.lines_utf16()
5303 + (buffer_left_point_utf16 - buffer_start_point_utf16),
5304 "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
5305 point_utf16,
5306 buffer_id,
5307 buffer_point_utf16,
5308 );
5309 assert_eq!(
5310 right_point_utf16,
5311 excerpt_start.lines_utf16()
5312 + (buffer_right_point_utf16 - buffer_start_point_utf16),
5313 "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
5314 point_utf16,
5315 buffer_id,
5316 buffer_point_utf16,
5317 );
5318
5319 if ch == '\n' {
5320 point_utf16 += PointUtf16::new(1, 0);
5321 buffer_point_utf16 += PointUtf16::new(1, 0);
5322 } else {
5323 point_utf16 += PointUtf16::new(0, 1);
5324 buffer_point_utf16 += PointUtf16::new(0, 1);
5325 }
5326 }
5327 }
5328 }
5329
5330 for (row, line) in expected_text.split('\n').enumerate() {
5331 assert_eq!(
5332 snapshot.line_len(row as u32),
5333 line.len() as u32,
5334 "line_len({}).",
5335 row
5336 );
5337 }
5338
5339 let text_rope = Rope::from(expected_text.as_str());
5340 for _ in 0..10 {
5341 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
5342 let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
5343
5344 let text_for_range = snapshot
5345 .text_for_range(start_ix..end_ix)
5346 .collect::<String>();
5347 assert_eq!(
5348 text_for_range,
5349 &expected_text[start_ix..end_ix],
5350 "incorrect text for range {:?}",
5351 start_ix..end_ix
5352 );
5353
5354 let excerpted_buffer_ranges = multibuffer
5355 .read(cx)
5356 .range_to_buffer_ranges(start_ix..end_ix, cx);
5357 let excerpted_buffers_text = excerpted_buffer_ranges
5358 .iter()
5359 .map(|(buffer, buffer_range, _)| {
5360 buffer
5361 .read(cx)
5362 .text_for_range(buffer_range.clone())
5363 .collect::<String>()
5364 })
5365 .collect::<Vec<_>>()
5366 .join("\n");
5367 assert_eq!(excerpted_buffers_text, text_for_range);
5368 if !expected_excerpts.is_empty() {
5369 assert!(!excerpted_buffer_ranges.is_empty());
5370 }
5371
5372 let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
5373 assert_eq!(
5374 snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
5375 expected_summary,
5376 "incorrect summary for range {:?}",
5377 start_ix..end_ix
5378 );
5379 }
5380
5381 // Anchor resolution
5382 let summaries = snapshot.summaries_for_anchors::<usize, _>(&anchors);
5383 assert_eq!(anchors.len(), summaries.len());
5384 for (anchor, resolved_offset) in anchors.iter().zip(summaries) {
5385 assert!(resolved_offset <= snapshot.len());
5386 assert_eq!(
5387 snapshot.summary_for_anchor::<usize>(anchor),
5388 resolved_offset
5389 );
5390 }
5391
5392 for _ in 0..10 {
5393 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
5394 assert_eq!(
5395 snapshot.reversed_chars_at(end_ix).collect::<String>(),
5396 expected_text[..end_ix].chars().rev().collect::<String>(),
5397 );
5398 }
5399
5400 for _ in 0..10 {
5401 let end_ix = rng.gen_range(0..=text_rope.len());
5402 let start_ix = rng.gen_range(0..=end_ix);
5403 assert_eq!(
5404 snapshot
5405 .bytes_in_range(start_ix..end_ix)
5406 .flatten()
5407 .copied()
5408 .collect::<Vec<_>>(),
5409 expected_text.as_bytes()[start_ix..end_ix].to_vec(),
5410 "bytes_in_range({:?})",
5411 start_ix..end_ix,
5412 );
5413 }
5414 }
5415
5416 let snapshot = multibuffer.read(cx).snapshot(cx);
5417 for (old_snapshot, subscription) in old_versions {
5418 let edits = subscription.consume().into_inner();
5419
5420 log::info!(
5421 "applying subscription edits to old text: {:?}: {:?}",
5422 old_snapshot.text(),
5423 edits,
5424 );
5425
5426 let mut text = old_snapshot.text();
5427 for edit in edits {
5428 let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
5429 text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
5430 }
5431 assert_eq!(text.to_string(), snapshot.text());
5432 }
5433 }
5434
5435 #[gpui::test]
5436 fn test_history(cx: &mut AppContext) {
5437 let test_settings = SettingsStore::test(cx);
5438 cx.set_global(test_settings);
5439
5440 let buffer_1 = cx.new_model(|cx| Buffer::local("1234", cx));
5441 let buffer_2 = cx.new_model(|cx| Buffer::local("5678", cx));
5442 let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
5443 let group_interval = multibuffer.read(cx).history.group_interval;
5444 multibuffer.update(cx, |multibuffer, cx| {
5445 multibuffer.push_excerpts(
5446 buffer_1.clone(),
5447 [ExcerptRange {
5448 context: 0..buffer_1.read(cx).len(),
5449 primary: None,
5450 }],
5451 cx,
5452 );
5453 multibuffer.push_excerpts(
5454 buffer_2.clone(),
5455 [ExcerptRange {
5456 context: 0..buffer_2.read(cx).len(),
5457 primary: None,
5458 }],
5459 cx,
5460 );
5461 });
5462
5463 let mut now = Instant::now();
5464
5465 multibuffer.update(cx, |multibuffer, cx| {
5466 let transaction_1 = multibuffer.start_transaction_at(now, cx).unwrap();
5467 multibuffer.edit(
5468 [
5469 (Point::new(0, 0)..Point::new(0, 0), "A"),
5470 (Point::new(1, 0)..Point::new(1, 0), "A"),
5471 ],
5472 None,
5473 cx,
5474 );
5475 multibuffer.edit(
5476 [
5477 (Point::new(0, 1)..Point::new(0, 1), "B"),
5478 (Point::new(1, 1)..Point::new(1, 1), "B"),
5479 ],
5480 None,
5481 cx,
5482 );
5483 multibuffer.end_transaction_at(now, cx);
5484 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5485
5486 // Edit buffer 1 through the multibuffer
5487 now += 2 * group_interval;
5488 multibuffer.start_transaction_at(now, cx);
5489 multibuffer.edit([(2..2, "C")], None, cx);
5490 multibuffer.end_transaction_at(now, cx);
5491 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
5492
5493 // Edit buffer 1 independently
5494 buffer_1.update(cx, |buffer_1, cx| {
5495 buffer_1.start_transaction_at(now);
5496 buffer_1.edit([(3..3, "D")], None, cx);
5497 buffer_1.end_transaction_at(now, cx);
5498
5499 now += 2 * group_interval;
5500 buffer_1.start_transaction_at(now);
5501 buffer_1.edit([(4..4, "E")], None, cx);
5502 buffer_1.end_transaction_at(now, cx);
5503 });
5504 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
5505
5506 // An undo in the multibuffer undoes the multibuffer transaction
5507 // and also any individual buffer edits that have occurred since
5508 // that transaction.
5509 multibuffer.undo(cx);
5510 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5511
5512 multibuffer.undo(cx);
5513 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5514
5515 multibuffer.redo(cx);
5516 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5517
5518 multibuffer.redo(cx);
5519 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
5520
5521 // Undo buffer 2 independently.
5522 buffer_2.update(cx, |buffer_2, cx| buffer_2.undo(cx));
5523 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\n5678");
5524
5525 // An undo in the multibuffer undoes the components of the
5526 // the last multibuffer transaction that are not already undone.
5527 multibuffer.undo(cx);
5528 assert_eq!(multibuffer.read(cx).text(), "AB1234\n5678");
5529
5530 multibuffer.undo(cx);
5531 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5532
5533 multibuffer.redo(cx);
5534 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5535
5536 buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
5537 assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
5538
5539 // Redo stack gets cleared after an edit.
5540 now += 2 * group_interval;
5541 multibuffer.start_transaction_at(now, cx);
5542 multibuffer.edit([(0..0, "X")], None, cx);
5543 multibuffer.end_transaction_at(now, cx);
5544 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5545 multibuffer.redo(cx);
5546 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5547 multibuffer.undo(cx);
5548 assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
5549 multibuffer.undo(cx);
5550 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5551
5552 // Transactions can be grouped manually.
5553 multibuffer.redo(cx);
5554 multibuffer.redo(cx);
5555 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5556 multibuffer.group_until_transaction(transaction_1, cx);
5557 multibuffer.undo(cx);
5558 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5559 multibuffer.redo(cx);
5560 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5561 });
5562 }
5563}