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