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