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