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