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