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