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 if ids.is_empty() {
1169 return;
1170 }
1171
1172 let mut buffers = self.buffers.borrow_mut();
1173 let mut snapshot = self.snapshot.borrow_mut();
1174 let mut new_excerpts = SumTree::new();
1175 let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>();
1176 let mut edits = Vec::new();
1177 let mut excerpt_ids = ids.iter().copied().peekable();
1178
1179 while let Some(excerpt_id) = excerpt_ids.next() {
1180 // Seek to the next excerpt to remove, preserving any preceding excerpts.
1181 let locator = snapshot.excerpt_locator_for_id(excerpt_id);
1182 new_excerpts.push_tree(cursor.slice(&Some(locator), Bias::Left, &()), &());
1183
1184 if let Some(mut excerpt) = cursor.item() {
1185 if excerpt.id != excerpt_id {
1186 continue;
1187 }
1188 let mut old_start = cursor.start().1;
1189
1190 // Skip over the removed excerpt.
1191 'remove_excerpts: loop {
1192 if let Some(buffer_state) = buffers.get_mut(&excerpt.buffer_id) {
1193 buffer_state.excerpts.retain(|l| l != &excerpt.locator);
1194 if buffer_state.excerpts.is_empty() {
1195 buffers.remove(&excerpt.buffer_id);
1196 }
1197 }
1198 cursor.next(&());
1199
1200 // Skip over any subsequent excerpts that are also removed.
1201 while let Some(&next_excerpt_id) = excerpt_ids.peek() {
1202 let next_locator = snapshot.excerpt_locator_for_id(next_excerpt_id);
1203 if let Some(next_excerpt) = cursor.item() {
1204 if next_excerpt.locator == *next_locator {
1205 excerpt_ids.next();
1206 excerpt = next_excerpt;
1207 continue 'remove_excerpts;
1208 }
1209 }
1210 break;
1211 }
1212
1213 break;
1214 }
1215
1216 // When removing the last excerpt, remove the trailing newline from
1217 // the previous excerpt.
1218 if cursor.item().is_none() && old_start > 0 {
1219 old_start -= 1;
1220 new_excerpts.update_last(|e| e.has_trailing_newline = false, &());
1221 }
1222
1223 // Push an edit for the removal of this run of excerpts.
1224 let old_end = cursor.start().1;
1225 let new_start = new_excerpts.summary().text.len;
1226 edits.push(Edit {
1227 old: old_start..old_end,
1228 new: new_start..new_start,
1229 });
1230 }
1231 }
1232 let suffix = cursor.suffix(&());
1233 let changed_trailing_excerpt = suffix.is_empty();
1234 new_excerpts.push_tree(suffix, &());
1235 drop(cursor);
1236 snapshot.excerpts = new_excerpts;
1237
1238 if changed_trailing_excerpt {
1239 snapshot.trailing_excerpt_update_count += 1;
1240 }
1241
1242 self.subscriptions.publish_mut(edits);
1243 cx.emit(Event::Edited);
1244 cx.emit(Event::ExcerptsRemoved { ids });
1245 cx.notify();
1246 }
1247
1248 pub fn wait_for_anchors<'a>(
1249 &self,
1250 anchors: impl 'a + Iterator<Item = Anchor>,
1251 cx: &mut ModelContext<Self>,
1252 ) -> impl 'static + Future<Output = Result<()>> {
1253 let borrow = self.buffers.borrow();
1254 let mut error = None;
1255 let mut futures = Vec::new();
1256 for anchor in anchors {
1257 if let Some(buffer_id) = anchor.buffer_id {
1258 if let Some(buffer) = borrow.get(&buffer_id) {
1259 buffer.buffer.update(cx, |buffer, _| {
1260 futures.push(buffer.wait_for_anchors([anchor.text_anchor]))
1261 });
1262 } else {
1263 error = Some(anyhow!(
1264 "buffer {buffer_id} is not part of this multi-buffer"
1265 ));
1266 break;
1267 }
1268 }
1269 }
1270 async move {
1271 if let Some(error) = error {
1272 Err(error)?;
1273 }
1274 for future in futures {
1275 future.await?;
1276 }
1277 Ok(())
1278 }
1279 }
1280
1281 pub fn text_anchor_for_position<T: ToOffset>(
1282 &self,
1283 position: T,
1284 cx: &AppContext,
1285 ) -> Option<(ModelHandle<Buffer>, language::Anchor)> {
1286 let snapshot = self.read(cx);
1287 let anchor = snapshot.anchor_before(position);
1288 let buffer = self
1289 .buffers
1290 .borrow()
1291 .get(&anchor.buffer_id?)?
1292 .buffer
1293 .clone();
1294 Some((buffer, anchor.text_anchor))
1295 }
1296
1297 fn on_buffer_event(
1298 &mut self,
1299 _: ModelHandle<Buffer>,
1300 event: &language::Event,
1301 cx: &mut ModelContext<Self>,
1302 ) {
1303 cx.emit(match event {
1304 language::Event::Edited => Event::Edited,
1305 language::Event::DirtyChanged => Event::DirtyChanged,
1306 language::Event::Saved => Event::Saved,
1307 language::Event::FileHandleChanged => Event::FileHandleChanged,
1308 language::Event::Reloaded => Event::Reloaded,
1309 language::Event::LanguageChanged => Event::LanguageChanged,
1310 language::Event::Reparsed => Event::Reparsed,
1311 language::Event::DiagnosticsUpdated => Event::DiagnosticsUpdated,
1312 language::Event::Closed => Event::Closed,
1313
1314 //
1315 language::Event::Operation(_) => return,
1316 });
1317 }
1318
1319 pub fn all_buffers(&self) -> HashSet<ModelHandle<Buffer>> {
1320 self.buffers
1321 .borrow()
1322 .values()
1323 .map(|state| state.buffer.clone())
1324 .collect()
1325 }
1326
1327 pub fn buffer(&self, buffer_id: u64) -> Option<ModelHandle<Buffer>> {
1328 self.buffers
1329 .borrow()
1330 .get(&buffer_id)
1331 .map(|state| state.buffer.clone())
1332 }
1333
1334 pub fn is_completion_trigger<T>(&self, position: T, text: &str, cx: &AppContext) -> bool
1335 where
1336 T: ToOffset,
1337 {
1338 let mut chars = text.chars();
1339 let char = if let Some(char) = chars.next() {
1340 char
1341 } else {
1342 return false;
1343 };
1344 if chars.next().is_some() {
1345 return false;
1346 }
1347
1348 if char.is_alphanumeric() || char == '_' {
1349 return true;
1350 }
1351
1352 let snapshot = self.snapshot(cx);
1353 let anchor = snapshot.anchor_before(position);
1354 anchor
1355 .buffer_id
1356 .and_then(|buffer_id| {
1357 let buffer = self.buffers.borrow().get(&buffer_id)?.buffer.clone();
1358 Some(
1359 buffer
1360 .read(cx)
1361 .completion_triggers()
1362 .iter()
1363 .any(|string| string == text),
1364 )
1365 })
1366 .unwrap_or(false)
1367 }
1368
1369 pub fn language_at<'a, T: ToOffset>(
1370 &self,
1371 point: T,
1372 cx: &'a AppContext,
1373 ) -> Option<Arc<Language>> {
1374 self.point_to_buffer_offset(point, cx)
1375 .and_then(|(buffer, offset)| buffer.read(cx).language_at(offset))
1376 }
1377
1378 pub fn for_each_buffer(&self, mut f: impl FnMut(&ModelHandle<Buffer>)) {
1379 self.buffers
1380 .borrow()
1381 .values()
1382 .for_each(|state| f(&state.buffer))
1383 }
1384
1385 pub fn title<'a>(&'a self, cx: &'a AppContext) -> Cow<'a, str> {
1386 if let Some(title) = self.title.as_ref() {
1387 return title.into();
1388 }
1389
1390 if let Some(buffer) = self.as_singleton() {
1391 if let Some(file) = buffer.read(cx).file() {
1392 return file.file_name(cx).to_string_lossy();
1393 }
1394 }
1395
1396 "untitled".into()
1397 }
1398
1399 #[cfg(test)]
1400 pub fn is_parsing(&self, cx: &AppContext) -> bool {
1401 self.as_singleton().unwrap().read(cx).is_parsing()
1402 }
1403
1404 fn sync(&self, cx: &AppContext) {
1405 let mut snapshot = self.snapshot.borrow_mut();
1406 let mut excerpts_to_edit = Vec::new();
1407 let mut reparsed = false;
1408 let mut diagnostics_updated = false;
1409 let mut git_diff_updated = false;
1410 let mut is_dirty = false;
1411 let mut has_conflict = false;
1412 let mut edited = false;
1413 let mut buffers = self.buffers.borrow_mut();
1414 for buffer_state in buffers.values_mut() {
1415 let buffer = buffer_state.buffer.read(cx);
1416 let version = buffer.version();
1417 let parse_count = buffer.parse_count();
1418 let selections_update_count = buffer.selections_update_count();
1419 let diagnostics_update_count = buffer.diagnostics_update_count();
1420 let file_update_count = buffer.file_update_count();
1421 let git_diff_update_count = buffer.git_diff_update_count();
1422
1423 let buffer_edited = version.changed_since(&buffer_state.last_version);
1424 let buffer_reparsed = parse_count > buffer_state.last_parse_count;
1425 let buffer_selections_updated =
1426 selections_update_count > buffer_state.last_selections_update_count;
1427 let buffer_diagnostics_updated =
1428 diagnostics_update_count > buffer_state.last_diagnostics_update_count;
1429 let buffer_file_updated = file_update_count > buffer_state.last_file_update_count;
1430 let buffer_git_diff_updated =
1431 git_diff_update_count > buffer_state.last_git_diff_update_count;
1432 if buffer_edited
1433 || buffer_reparsed
1434 || buffer_selections_updated
1435 || buffer_diagnostics_updated
1436 || buffer_file_updated
1437 || buffer_git_diff_updated
1438 {
1439 buffer_state.last_version = version;
1440 buffer_state.last_parse_count = parse_count;
1441 buffer_state.last_selections_update_count = selections_update_count;
1442 buffer_state.last_diagnostics_update_count = diagnostics_update_count;
1443 buffer_state.last_file_update_count = file_update_count;
1444 buffer_state.last_git_diff_update_count = git_diff_update_count;
1445 excerpts_to_edit.extend(
1446 buffer_state
1447 .excerpts
1448 .iter()
1449 .map(|locator| (locator, buffer_state.buffer.clone(), buffer_edited)),
1450 );
1451 }
1452
1453 edited |= buffer_edited;
1454 reparsed |= buffer_reparsed;
1455 diagnostics_updated |= buffer_diagnostics_updated;
1456 git_diff_updated |= buffer_git_diff_updated;
1457 is_dirty |= buffer.is_dirty();
1458 has_conflict |= buffer.has_conflict();
1459 }
1460 if edited {
1461 snapshot.edit_count += 1;
1462 }
1463 if reparsed {
1464 snapshot.parse_count += 1;
1465 }
1466 if diagnostics_updated {
1467 snapshot.diagnostics_update_count += 1;
1468 }
1469 if git_diff_updated {
1470 snapshot.git_diff_update_count += 1;
1471 }
1472 snapshot.is_dirty = is_dirty;
1473 snapshot.has_conflict = has_conflict;
1474
1475 excerpts_to_edit.sort_unstable_by_key(|(locator, _, _)| *locator);
1476
1477 let mut edits = Vec::new();
1478 let mut new_excerpts = SumTree::new();
1479 let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>();
1480
1481 for (locator, buffer, buffer_edited) in excerpts_to_edit {
1482 new_excerpts.push_tree(cursor.slice(&Some(locator), Bias::Left, &()), &());
1483 let old_excerpt = cursor.item().unwrap();
1484 let buffer = buffer.read(cx);
1485 let buffer_id = buffer.remote_id();
1486
1487 let mut new_excerpt;
1488 if buffer_edited {
1489 edits.extend(
1490 buffer
1491 .edits_since_in_range::<usize>(
1492 old_excerpt.buffer.version(),
1493 old_excerpt.range.context.clone(),
1494 )
1495 .map(|mut edit| {
1496 let excerpt_old_start = cursor.start().1;
1497 let excerpt_new_start = new_excerpts.summary().text.len;
1498 edit.old.start += excerpt_old_start;
1499 edit.old.end += excerpt_old_start;
1500 edit.new.start += excerpt_new_start;
1501 edit.new.end += excerpt_new_start;
1502 edit
1503 }),
1504 );
1505
1506 new_excerpt = Excerpt::new(
1507 old_excerpt.id,
1508 locator.clone(),
1509 buffer_id,
1510 buffer.snapshot(),
1511 old_excerpt.range.clone(),
1512 old_excerpt.has_trailing_newline,
1513 );
1514 } else {
1515 new_excerpt = old_excerpt.clone();
1516 new_excerpt.buffer = buffer.snapshot();
1517 }
1518
1519 new_excerpts.push(new_excerpt, &());
1520 cursor.next(&());
1521 }
1522 new_excerpts.push_tree(cursor.suffix(&()), &());
1523
1524 drop(cursor);
1525 snapshot.excerpts = new_excerpts;
1526
1527 self.subscriptions.publish(edits);
1528 }
1529}
1530
1531#[cfg(any(test, feature = "test-support"))]
1532impl MultiBuffer {
1533 pub fn build_simple(text: &str, cx: &mut gpui::AppContext) -> ModelHandle<Self> {
1534 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
1535 cx.add_model(|cx| Self::singleton(buffer, cx))
1536 }
1537
1538 pub fn build_random(rng: &mut impl rand::Rng, cx: &mut gpui::AppContext) -> ModelHandle<Self> {
1539 cx.add_model(|cx| {
1540 let mut multibuffer = MultiBuffer::new(0);
1541 let mutation_count = rng.gen_range(1..=5);
1542 multibuffer.randomly_edit_excerpts(rng, mutation_count, cx);
1543 multibuffer
1544 })
1545 }
1546
1547 pub fn randomly_edit(
1548 &mut self,
1549 rng: &mut impl rand::Rng,
1550 edit_count: usize,
1551 cx: &mut ModelContext<Self>,
1552 ) {
1553 use util::RandomCharIter;
1554
1555 let snapshot = self.read(cx);
1556 let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
1557 let mut last_end = None;
1558 for _ in 0..edit_count {
1559 if last_end.map_or(false, |last_end| last_end >= snapshot.len()) {
1560 break;
1561 }
1562
1563 let new_start = last_end.map_or(0, |last_end| last_end + 1);
1564 let end = snapshot.clip_offset(rng.gen_range(new_start..=snapshot.len()), Bias::Right);
1565 let start = snapshot.clip_offset(rng.gen_range(new_start..=end), Bias::Right);
1566 last_end = Some(end);
1567
1568 let mut range = start..end;
1569 if rng.gen_bool(0.2) {
1570 mem::swap(&mut range.start, &mut range.end);
1571 }
1572
1573 let new_text_len = rng.gen_range(0..10);
1574 let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
1575
1576 edits.push((range, new_text.into()));
1577 }
1578 log::info!("mutating multi-buffer with {:?}", edits);
1579 drop(snapshot);
1580
1581 self.edit(edits, None, cx);
1582 }
1583
1584 pub fn randomly_edit_excerpts(
1585 &mut self,
1586 rng: &mut impl rand::Rng,
1587 mutation_count: usize,
1588 cx: &mut ModelContext<Self>,
1589 ) {
1590 use rand::prelude::*;
1591 use std::env;
1592 use util::RandomCharIter;
1593
1594 let max_excerpts = env::var("MAX_EXCERPTS")
1595 .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))
1596 .unwrap_or(5);
1597
1598 let mut buffers = Vec::new();
1599 for _ in 0..mutation_count {
1600 if rng.gen_bool(0.05) {
1601 log::info!("Clearing multi-buffer");
1602 self.clear(cx);
1603 continue;
1604 }
1605
1606 let excerpt_ids = self.excerpt_ids();
1607 if excerpt_ids.is_empty() || (rng.gen() && excerpt_ids.len() < max_excerpts) {
1608 let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() {
1609 let text = RandomCharIter::new(&mut *rng).take(10).collect::<String>();
1610 buffers.push(cx.add_model(|cx| Buffer::new(0, text, cx)));
1611 let buffer = buffers.last().unwrap().read(cx);
1612 log::info!(
1613 "Creating new buffer {} with text: {:?}",
1614 buffer.remote_id(),
1615 buffer.text()
1616 );
1617 buffers.last().unwrap().clone()
1618 } else {
1619 self.buffers
1620 .borrow()
1621 .values()
1622 .choose(rng)
1623 .unwrap()
1624 .buffer
1625 .clone()
1626 };
1627
1628 let buffer = buffer_handle.read(cx);
1629 let buffer_text = buffer.text();
1630 let ranges = (0..rng.gen_range(0..5))
1631 .map(|_| {
1632 let end_ix =
1633 buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
1634 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
1635 ExcerptRange {
1636 context: start_ix..end_ix,
1637 primary: None,
1638 }
1639 })
1640 .collect::<Vec<_>>();
1641 log::info!(
1642 "Inserting excerpts from buffer {} and ranges {:?}: {:?}",
1643 buffer_handle.read(cx).remote_id(),
1644 ranges.iter().map(|r| &r.context).collect::<Vec<_>>(),
1645 ranges
1646 .iter()
1647 .map(|r| &buffer_text[r.context.clone()])
1648 .collect::<Vec<_>>()
1649 );
1650
1651 let excerpt_id = self.push_excerpts(buffer_handle.clone(), ranges, cx);
1652 log::info!("Inserted with ids: {:?}", excerpt_id);
1653 } else {
1654 let remove_count = rng.gen_range(1..=excerpt_ids.len());
1655 let mut excerpts_to_remove = excerpt_ids
1656 .choose_multiple(rng, remove_count)
1657 .cloned()
1658 .collect::<Vec<_>>();
1659 let snapshot = self.snapshot.borrow();
1660 excerpts_to_remove.sort_unstable_by(|a, b| a.cmp(b, &*snapshot));
1661 drop(snapshot);
1662 log::info!("Removing excerpts {:?}", excerpts_to_remove);
1663 self.remove_excerpts(excerpts_to_remove, cx);
1664 }
1665 }
1666 }
1667
1668 pub fn randomly_mutate(
1669 &mut self,
1670 rng: &mut impl rand::Rng,
1671 mutation_count: usize,
1672 cx: &mut ModelContext<Self>,
1673 ) {
1674 use rand::prelude::*;
1675
1676 if rng.gen_bool(0.7) || self.singleton {
1677 let buffer = self
1678 .buffers
1679 .borrow()
1680 .values()
1681 .choose(rng)
1682 .map(|state| state.buffer.clone());
1683
1684 if let Some(buffer) = buffer {
1685 buffer.update(cx, |buffer, cx| {
1686 if rng.gen() {
1687 buffer.randomly_edit(rng, mutation_count, cx);
1688 } else {
1689 buffer.randomly_undo_redo(rng, cx);
1690 }
1691 });
1692 } else {
1693 self.randomly_edit(rng, mutation_count, cx);
1694 }
1695 } else {
1696 self.randomly_edit_excerpts(rng, mutation_count, cx);
1697 }
1698
1699 self.check_invariants(cx);
1700 }
1701
1702 fn check_invariants(&self, cx: &mut ModelContext<Self>) {
1703 let snapshot = self.read(cx);
1704 let excerpts = snapshot.excerpts.items(&());
1705 let excerpt_ids = snapshot.excerpt_ids.items(&());
1706
1707 for (ix, excerpt) in excerpts.iter().enumerate() {
1708 if ix == 0 {
1709 if excerpt.locator <= Locator::min() {
1710 panic!("invalid first excerpt locator {:?}", excerpt.locator);
1711 }
1712 } else {
1713 if excerpt.locator <= excerpts[ix - 1].locator {
1714 panic!("excerpts are out-of-order: {:?}", excerpts);
1715 }
1716 }
1717 }
1718
1719 for (ix, entry) in excerpt_ids.iter().enumerate() {
1720 if ix == 0 {
1721 if entry.id.cmp(&ExcerptId::min(), &*snapshot).is_le() {
1722 panic!("invalid first excerpt id {:?}", entry.id);
1723 }
1724 } else {
1725 if entry.id <= excerpt_ids[ix - 1].id {
1726 panic!("excerpt ids are out-of-order: {:?}", excerpt_ids);
1727 }
1728 }
1729 }
1730 }
1731}
1732
1733impl Entity for MultiBuffer {
1734 type Event = Event;
1735}
1736
1737impl MultiBufferSnapshot {
1738 pub fn text(&self) -> String {
1739 self.chunks(0..self.len(), false)
1740 .map(|chunk| chunk.text)
1741 .collect()
1742 }
1743
1744 pub fn reversed_chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
1745 let mut offset = position.to_offset(self);
1746 let mut cursor = self.excerpts.cursor::<usize>();
1747 cursor.seek(&offset, Bias::Left, &());
1748 let mut excerpt_chunks = cursor.item().map(|excerpt| {
1749 let end_before_footer = cursor.start() + excerpt.text_summary.len;
1750 let start = excerpt.range.context.start.to_offset(&excerpt.buffer);
1751 let end = start + (cmp::min(offset, end_before_footer) - cursor.start());
1752 excerpt.buffer.reversed_chunks_in_range(start..end)
1753 });
1754 iter::from_fn(move || {
1755 if offset == *cursor.start() {
1756 cursor.prev(&());
1757 let excerpt = cursor.item()?;
1758 excerpt_chunks = Some(
1759 excerpt
1760 .buffer
1761 .reversed_chunks_in_range(excerpt.range.context.clone()),
1762 );
1763 }
1764
1765 let excerpt = cursor.item().unwrap();
1766 if offset == cursor.end(&()) && excerpt.has_trailing_newline {
1767 offset -= 1;
1768 Some("\n")
1769 } else {
1770 let chunk = excerpt_chunks.as_mut().unwrap().next().unwrap();
1771 offset -= chunk.len();
1772 Some(chunk)
1773 }
1774 })
1775 .flat_map(|c| c.chars().rev())
1776 }
1777
1778 pub fn chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
1779 let offset = position.to_offset(self);
1780 self.text_for_range(offset..self.len())
1781 .flat_map(|chunk| chunk.chars())
1782 }
1783
1784 pub fn text_for_range<T: ToOffset>(&self, range: Range<T>) -> impl Iterator<Item = &str> + '_ {
1785 self.chunks(range, false).map(|chunk| chunk.text)
1786 }
1787
1788 pub fn is_line_blank(&self, row: u32) -> bool {
1789 self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row)))
1790 .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
1791 }
1792
1793 pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
1794 where
1795 T: ToOffset,
1796 {
1797 let position = position.to_offset(self);
1798 position == self.clip_offset(position, Bias::Left)
1799 && self
1800 .bytes_in_range(position..self.len())
1801 .flatten()
1802 .copied()
1803 .take(needle.len())
1804 .eq(needle.bytes())
1805 }
1806
1807 pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) {
1808 let mut start = start.to_offset(self);
1809 let mut end = start;
1810 let mut next_chars = self.chars_at(start).peekable();
1811 let mut prev_chars = self.reversed_chars_at(start).peekable();
1812 let word_kind = cmp::max(
1813 prev_chars.peek().copied().map(char_kind),
1814 next_chars.peek().copied().map(char_kind),
1815 );
1816
1817 for ch in prev_chars {
1818 if Some(char_kind(ch)) == word_kind && ch != '\n' {
1819 start -= ch.len_utf8();
1820 } else {
1821 break;
1822 }
1823 }
1824
1825 for ch in next_chars {
1826 if Some(char_kind(ch)) == word_kind && ch != '\n' {
1827 end += ch.len_utf8();
1828 } else {
1829 break;
1830 }
1831 }
1832
1833 (start..end, word_kind)
1834 }
1835
1836 pub fn as_singleton(&self) -> Option<(&ExcerptId, u64, &BufferSnapshot)> {
1837 if self.singleton {
1838 self.excerpts
1839 .iter()
1840 .next()
1841 .map(|e| (&e.id, e.buffer_id, &e.buffer))
1842 } else {
1843 None
1844 }
1845 }
1846
1847 pub fn len(&self) -> usize {
1848 self.excerpts.summary().text.len
1849 }
1850
1851 pub fn is_empty(&self) -> bool {
1852 self.excerpts.summary().text.len == 0
1853 }
1854
1855 pub fn max_buffer_row(&self) -> u32 {
1856 self.excerpts.summary().max_buffer_row
1857 }
1858
1859 pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
1860 if let Some((_, _, buffer)) = self.as_singleton() {
1861 return buffer.clip_offset(offset, bias);
1862 }
1863
1864 let mut cursor = self.excerpts.cursor::<usize>();
1865 cursor.seek(&offset, Bias::Right, &());
1866 let overshoot = if let Some(excerpt) = cursor.item() {
1867 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
1868 let buffer_offset = excerpt
1869 .buffer
1870 .clip_offset(excerpt_start + (offset - cursor.start()), bias);
1871 buffer_offset.saturating_sub(excerpt_start)
1872 } else {
1873 0
1874 };
1875 cursor.start() + overshoot
1876 }
1877
1878 pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
1879 if let Some((_, _, buffer)) = self.as_singleton() {
1880 return buffer.clip_point(point, bias);
1881 }
1882
1883 let mut cursor = self.excerpts.cursor::<Point>();
1884 cursor.seek(&point, Bias::Right, &());
1885 let overshoot = if let Some(excerpt) = cursor.item() {
1886 let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
1887 let buffer_point = excerpt
1888 .buffer
1889 .clip_point(excerpt_start + (point - cursor.start()), bias);
1890 buffer_point.saturating_sub(excerpt_start)
1891 } else {
1892 Point::zero()
1893 };
1894 *cursor.start() + overshoot
1895 }
1896
1897 pub fn clip_offset_utf16(&self, offset: OffsetUtf16, bias: Bias) -> OffsetUtf16 {
1898 if let Some((_, _, buffer)) = self.as_singleton() {
1899 return buffer.clip_offset_utf16(offset, bias);
1900 }
1901
1902 let mut cursor = self.excerpts.cursor::<OffsetUtf16>();
1903 cursor.seek(&offset, Bias::Right, &());
1904 let overshoot = if let Some(excerpt) = cursor.item() {
1905 let excerpt_start = excerpt.range.context.start.to_offset_utf16(&excerpt.buffer);
1906 let buffer_offset = excerpt
1907 .buffer
1908 .clip_offset_utf16(excerpt_start + (offset - cursor.start()), bias);
1909 OffsetUtf16(buffer_offset.0.saturating_sub(excerpt_start.0))
1910 } else {
1911 OffsetUtf16(0)
1912 };
1913 *cursor.start() + overshoot
1914 }
1915
1916 pub fn clip_point_utf16(&self, point: Unclipped<PointUtf16>, bias: Bias) -> PointUtf16 {
1917 if let Some((_, _, buffer)) = self.as_singleton() {
1918 return buffer.clip_point_utf16(point, bias);
1919 }
1920
1921 let mut cursor = self.excerpts.cursor::<PointUtf16>();
1922 cursor.seek(&point.0, Bias::Right, &());
1923 let overshoot = if let Some(excerpt) = cursor.item() {
1924 let excerpt_start = excerpt
1925 .buffer
1926 .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
1927 let buffer_point = excerpt
1928 .buffer
1929 .clip_point_utf16(Unclipped(excerpt_start + (point.0 - cursor.start())), bias);
1930 buffer_point.saturating_sub(excerpt_start)
1931 } else {
1932 PointUtf16::zero()
1933 };
1934 *cursor.start() + overshoot
1935 }
1936
1937 pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> MultiBufferBytes {
1938 let range = range.start.to_offset(self)..range.end.to_offset(self);
1939 let mut excerpts = self.excerpts.cursor::<usize>();
1940 excerpts.seek(&range.start, Bias::Right, &());
1941
1942 let mut chunk = &[][..];
1943 let excerpt_bytes = if let Some(excerpt) = excerpts.item() {
1944 let mut excerpt_bytes = excerpt
1945 .bytes_in_range(range.start - excerpts.start()..range.end - excerpts.start());
1946 chunk = excerpt_bytes.next().unwrap_or(&[][..]);
1947 Some(excerpt_bytes)
1948 } else {
1949 None
1950 };
1951
1952 MultiBufferBytes {
1953 range,
1954 excerpts,
1955 excerpt_bytes,
1956 chunk,
1957 }
1958 }
1959
1960 pub fn buffer_rows(&self, start_row: u32) -> MultiBufferRows {
1961 let mut result = MultiBufferRows {
1962 buffer_row_range: 0..0,
1963 excerpts: self.excerpts.cursor(),
1964 };
1965 result.seek(start_row);
1966 result
1967 }
1968
1969 pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> MultiBufferChunks {
1970 let range = range.start.to_offset(self)..range.end.to_offset(self);
1971 let mut chunks = MultiBufferChunks {
1972 range: range.clone(),
1973 excerpts: self.excerpts.cursor(),
1974 excerpt_chunks: None,
1975 language_aware,
1976 };
1977 chunks.seek(range.start);
1978 chunks
1979 }
1980
1981 pub fn offset_to_point(&self, offset: usize) -> Point {
1982 if let Some((_, _, buffer)) = self.as_singleton() {
1983 return buffer.offset_to_point(offset);
1984 }
1985
1986 let mut cursor = self.excerpts.cursor::<(usize, Point)>();
1987 cursor.seek(&offset, Bias::Right, &());
1988 if let Some(excerpt) = cursor.item() {
1989 let (start_offset, start_point) = cursor.start();
1990 let overshoot = offset - start_offset;
1991 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
1992 let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
1993 let buffer_point = excerpt
1994 .buffer
1995 .offset_to_point(excerpt_start_offset + overshoot);
1996 *start_point + (buffer_point - excerpt_start_point)
1997 } else {
1998 self.excerpts.summary().text.lines
1999 }
2000 }
2001
2002 pub fn offset_to_point_utf16(&self, offset: usize) -> PointUtf16 {
2003 if let Some((_, _, buffer)) = self.as_singleton() {
2004 return buffer.offset_to_point_utf16(offset);
2005 }
2006
2007 let mut cursor = self.excerpts.cursor::<(usize, PointUtf16)>();
2008 cursor.seek(&offset, Bias::Right, &());
2009 if let Some(excerpt) = cursor.item() {
2010 let (start_offset, start_point) = cursor.start();
2011 let overshoot = offset - start_offset;
2012 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2013 let excerpt_start_point = excerpt.range.context.start.to_point_utf16(&excerpt.buffer);
2014 let buffer_point = excerpt
2015 .buffer
2016 .offset_to_point_utf16(excerpt_start_offset + overshoot);
2017 *start_point + (buffer_point - excerpt_start_point)
2018 } else {
2019 self.excerpts.summary().text.lines_utf16()
2020 }
2021 }
2022
2023 pub fn point_to_point_utf16(&self, point: Point) -> PointUtf16 {
2024 if let Some((_, _, buffer)) = self.as_singleton() {
2025 return buffer.point_to_point_utf16(point);
2026 }
2027
2028 let mut cursor = self.excerpts.cursor::<(Point, PointUtf16)>();
2029 cursor.seek(&point, Bias::Right, &());
2030 if let Some(excerpt) = cursor.item() {
2031 let (start_offset, start_point) = cursor.start();
2032 let overshoot = point - start_offset;
2033 let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
2034 let excerpt_start_point_utf16 =
2035 excerpt.range.context.start.to_point_utf16(&excerpt.buffer);
2036 let buffer_point = excerpt
2037 .buffer
2038 .point_to_point_utf16(excerpt_start_point + overshoot);
2039 *start_point + (buffer_point - excerpt_start_point_utf16)
2040 } else {
2041 self.excerpts.summary().text.lines_utf16()
2042 }
2043 }
2044
2045 pub fn point_to_offset(&self, point: Point) -> usize {
2046 if let Some((_, _, buffer)) = self.as_singleton() {
2047 return buffer.point_to_offset(point);
2048 }
2049
2050 let mut cursor = self.excerpts.cursor::<(Point, usize)>();
2051 cursor.seek(&point, Bias::Right, &());
2052 if let Some(excerpt) = cursor.item() {
2053 let (start_point, start_offset) = cursor.start();
2054 let overshoot = point - start_point;
2055 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2056 let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
2057 let buffer_offset = excerpt
2058 .buffer
2059 .point_to_offset(excerpt_start_point + overshoot);
2060 *start_offset + buffer_offset - excerpt_start_offset
2061 } else {
2062 self.excerpts.summary().text.len
2063 }
2064 }
2065
2066 pub fn offset_utf16_to_offset(&self, offset_utf16: OffsetUtf16) -> usize {
2067 if let Some((_, _, buffer)) = self.as_singleton() {
2068 return buffer.offset_utf16_to_offset(offset_utf16);
2069 }
2070
2071 let mut cursor = self.excerpts.cursor::<(OffsetUtf16, usize)>();
2072 cursor.seek(&offset_utf16, Bias::Right, &());
2073 if let Some(excerpt) = cursor.item() {
2074 let (start_offset_utf16, start_offset) = cursor.start();
2075 let overshoot = offset_utf16 - start_offset_utf16;
2076 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2077 let excerpt_start_offset_utf16 =
2078 excerpt.buffer.offset_to_offset_utf16(excerpt_start_offset);
2079 let buffer_offset = excerpt
2080 .buffer
2081 .offset_utf16_to_offset(excerpt_start_offset_utf16 + overshoot);
2082 *start_offset + (buffer_offset - excerpt_start_offset)
2083 } else {
2084 self.excerpts.summary().text.len
2085 }
2086 }
2087
2088 pub fn offset_to_offset_utf16(&self, offset: usize) -> OffsetUtf16 {
2089 if let Some((_, _, buffer)) = self.as_singleton() {
2090 return buffer.offset_to_offset_utf16(offset);
2091 }
2092
2093 let mut cursor = self.excerpts.cursor::<(usize, OffsetUtf16)>();
2094 cursor.seek(&offset, Bias::Right, &());
2095 if let Some(excerpt) = cursor.item() {
2096 let (start_offset, start_offset_utf16) = cursor.start();
2097 let overshoot = offset - start_offset;
2098 let excerpt_start_offset_utf16 =
2099 excerpt.range.context.start.to_offset_utf16(&excerpt.buffer);
2100 let excerpt_start_offset = excerpt
2101 .buffer
2102 .offset_utf16_to_offset(excerpt_start_offset_utf16);
2103 let buffer_offset_utf16 = excerpt
2104 .buffer
2105 .offset_to_offset_utf16(excerpt_start_offset + overshoot);
2106 *start_offset_utf16 + (buffer_offset_utf16 - excerpt_start_offset_utf16)
2107 } else {
2108 self.excerpts.summary().text.len_utf16
2109 }
2110 }
2111
2112 pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
2113 if let Some((_, _, buffer)) = self.as_singleton() {
2114 return buffer.point_utf16_to_offset(point);
2115 }
2116
2117 let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>();
2118 cursor.seek(&point, Bias::Right, &());
2119 if let Some(excerpt) = cursor.item() {
2120 let (start_point, start_offset) = cursor.start();
2121 let overshoot = point - start_point;
2122 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2123 let excerpt_start_point = excerpt
2124 .buffer
2125 .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
2126 let buffer_offset = excerpt
2127 .buffer
2128 .point_utf16_to_offset(excerpt_start_point + overshoot);
2129 *start_offset + (buffer_offset - excerpt_start_offset)
2130 } else {
2131 self.excerpts.summary().text.len
2132 }
2133 }
2134
2135 pub fn point_to_buffer_offset<T: ToOffset>(
2136 &self,
2137 point: T,
2138 ) -> Option<(&BufferSnapshot, usize)> {
2139 let offset = point.to_offset(&self);
2140 let mut cursor = self.excerpts.cursor::<usize>();
2141 cursor.seek(&offset, Bias::Right, &());
2142 if cursor.item().is_none() {
2143 cursor.prev(&());
2144 }
2145
2146 cursor.item().map(|excerpt| {
2147 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2148 let buffer_point = excerpt_start + offset - *cursor.start();
2149 (&excerpt.buffer, buffer_point)
2150 })
2151 }
2152
2153 pub fn suggested_indents(
2154 &self,
2155 rows: impl IntoIterator<Item = u32>,
2156 cx: &AppContext,
2157 ) -> BTreeMap<u32, IndentSize> {
2158 let mut result = BTreeMap::new();
2159
2160 let mut rows_for_excerpt = Vec::new();
2161 let mut cursor = self.excerpts.cursor::<Point>();
2162 let mut rows = rows.into_iter().peekable();
2163 let mut prev_row = u32::MAX;
2164 let mut prev_language_indent_size = IndentSize::default();
2165
2166 while let Some(row) = rows.next() {
2167 cursor.seek(&Point::new(row, 0), Bias::Right, &());
2168 let excerpt = match cursor.item() {
2169 Some(excerpt) => excerpt,
2170 _ => continue,
2171 };
2172
2173 // Retrieve the language and indent size once for each disjoint region being indented.
2174 let single_indent_size = if row.saturating_sub(1) == prev_row {
2175 prev_language_indent_size
2176 } else {
2177 excerpt
2178 .buffer
2179 .language_indent_size_at(Point::new(row, 0), cx)
2180 };
2181 prev_language_indent_size = single_indent_size;
2182 prev_row = row;
2183
2184 let start_buffer_row = excerpt.range.context.start.to_point(&excerpt.buffer).row;
2185 let start_multibuffer_row = cursor.start().row;
2186
2187 rows_for_excerpt.push(row);
2188 while let Some(next_row) = rows.peek().copied() {
2189 if cursor.end(&()).row > next_row {
2190 rows_for_excerpt.push(next_row);
2191 rows.next();
2192 } else {
2193 break;
2194 }
2195 }
2196
2197 let buffer_rows = rows_for_excerpt
2198 .drain(..)
2199 .map(|row| start_buffer_row + row - start_multibuffer_row);
2200 let buffer_indents = excerpt
2201 .buffer
2202 .suggested_indents(buffer_rows, single_indent_size);
2203 let multibuffer_indents = buffer_indents
2204 .into_iter()
2205 .map(|(row, indent)| (start_multibuffer_row + row - start_buffer_row, indent));
2206 result.extend(multibuffer_indents);
2207 }
2208
2209 result
2210 }
2211
2212 pub fn indent_size_for_line(&self, row: u32) -> IndentSize {
2213 if let Some((buffer, range)) = self.buffer_line_for_row(row) {
2214 let mut size = buffer.indent_size_for_line(range.start.row);
2215 size.len = size
2216 .len
2217 .min(range.end.column)
2218 .saturating_sub(range.start.column);
2219 size
2220 } else {
2221 IndentSize::spaces(0)
2222 }
2223 }
2224
2225 pub fn line_len(&self, row: u32) -> u32 {
2226 if let Some((_, range)) = self.buffer_line_for_row(row) {
2227 range.end.column - range.start.column
2228 } else {
2229 0
2230 }
2231 }
2232
2233 pub fn buffer_line_for_row(&self, row: u32) -> Option<(&BufferSnapshot, Range<Point>)> {
2234 let mut cursor = self.excerpts.cursor::<Point>();
2235 let point = Point::new(row, 0);
2236 cursor.seek(&point, Bias::Right, &());
2237 if cursor.item().is_none() && *cursor.start() == point {
2238 cursor.prev(&());
2239 }
2240 if let Some(excerpt) = cursor.item() {
2241 let overshoot = row - cursor.start().row;
2242 let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
2243 let excerpt_end = excerpt.range.context.end.to_point(&excerpt.buffer);
2244 let buffer_row = excerpt_start.row + overshoot;
2245 let line_start = Point::new(buffer_row, 0);
2246 let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
2247 return Some((
2248 &excerpt.buffer,
2249 line_start.max(excerpt_start)..line_end.min(excerpt_end),
2250 ));
2251 }
2252 None
2253 }
2254
2255 pub fn max_point(&self) -> Point {
2256 self.text_summary().lines
2257 }
2258
2259 pub fn text_summary(&self) -> TextSummary {
2260 self.excerpts.summary().text.clone()
2261 }
2262
2263 pub fn text_summary_for_range<D, O>(&self, range: Range<O>) -> D
2264 where
2265 D: TextDimension,
2266 O: ToOffset,
2267 {
2268 let mut summary = D::default();
2269 let mut range = range.start.to_offset(self)..range.end.to_offset(self);
2270 let mut cursor = self.excerpts.cursor::<usize>();
2271 cursor.seek(&range.start, Bias::Right, &());
2272 if let Some(excerpt) = cursor.item() {
2273 let mut end_before_newline = cursor.end(&());
2274 if excerpt.has_trailing_newline {
2275 end_before_newline -= 1;
2276 }
2277
2278 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2279 let start_in_excerpt = excerpt_start + (range.start - cursor.start());
2280 let end_in_excerpt =
2281 excerpt_start + (cmp::min(end_before_newline, range.end) - cursor.start());
2282 summary.add_assign(
2283 &excerpt
2284 .buffer
2285 .text_summary_for_range(start_in_excerpt..end_in_excerpt),
2286 );
2287
2288 if range.end > end_before_newline {
2289 summary.add_assign(&D::from_text_summary(&TextSummary::from("\n")));
2290 }
2291
2292 cursor.next(&());
2293 }
2294
2295 if range.end > *cursor.start() {
2296 summary.add_assign(&D::from_text_summary(&cursor.summary::<_, TextSummary>(
2297 &range.end,
2298 Bias::Right,
2299 &(),
2300 )));
2301 if let Some(excerpt) = cursor.item() {
2302 range.end = cmp::max(*cursor.start(), range.end);
2303
2304 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2305 let end_in_excerpt = excerpt_start + (range.end - cursor.start());
2306 summary.add_assign(
2307 &excerpt
2308 .buffer
2309 .text_summary_for_range(excerpt_start..end_in_excerpt),
2310 );
2311 }
2312 }
2313
2314 summary
2315 }
2316
2317 pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
2318 where
2319 D: TextDimension + Ord + Sub<D, Output = D>,
2320 {
2321 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
2322 let locator = self.excerpt_locator_for_id(anchor.excerpt_id);
2323
2324 cursor.seek(locator, Bias::Left, &());
2325 if cursor.item().is_none() {
2326 cursor.next(&());
2327 }
2328
2329 let mut position = D::from_text_summary(&cursor.start().text);
2330 if let Some(excerpt) = cursor.item() {
2331 if excerpt.id == anchor.excerpt_id {
2332 let excerpt_buffer_start =
2333 excerpt.range.context.start.summary::<D>(&excerpt.buffer);
2334 let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer);
2335 let buffer_position = cmp::min(
2336 excerpt_buffer_end,
2337 anchor.text_anchor.summary::<D>(&excerpt.buffer),
2338 );
2339 if buffer_position > excerpt_buffer_start {
2340 position.add_assign(&(buffer_position - excerpt_buffer_start));
2341 }
2342 }
2343 }
2344 position
2345 }
2346
2347 pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
2348 where
2349 D: TextDimension + Ord + Sub<D, Output = D>,
2350 I: 'a + IntoIterator<Item = &'a Anchor>,
2351 {
2352 if let Some((_, _, buffer)) = self.as_singleton() {
2353 return buffer
2354 .summaries_for_anchors(anchors.into_iter().map(|a| &a.text_anchor))
2355 .collect();
2356 }
2357
2358 let mut anchors = anchors.into_iter().peekable();
2359 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
2360 let mut summaries = Vec::new();
2361 while let Some(anchor) = anchors.peek() {
2362 let excerpt_id = anchor.excerpt_id;
2363 let excerpt_anchors = iter::from_fn(|| {
2364 let anchor = anchors.peek()?;
2365 if anchor.excerpt_id == excerpt_id {
2366 Some(&anchors.next().unwrap().text_anchor)
2367 } else {
2368 None
2369 }
2370 });
2371
2372 let locator = self.excerpt_locator_for_id(excerpt_id);
2373 cursor.seek_forward(locator, Bias::Left, &());
2374 if cursor.item().is_none() {
2375 cursor.next(&());
2376 }
2377
2378 let position = D::from_text_summary(&cursor.start().text);
2379 if let Some(excerpt) = cursor.item() {
2380 if excerpt.id == excerpt_id {
2381 let excerpt_buffer_start =
2382 excerpt.range.context.start.summary::<D>(&excerpt.buffer);
2383 let excerpt_buffer_end =
2384 excerpt.range.context.end.summary::<D>(&excerpt.buffer);
2385 summaries.extend(
2386 excerpt
2387 .buffer
2388 .summaries_for_anchors::<D, _>(excerpt_anchors)
2389 .map(move |summary| {
2390 let summary = cmp::min(excerpt_buffer_end.clone(), summary);
2391 let mut position = position.clone();
2392 let excerpt_buffer_start = excerpt_buffer_start.clone();
2393 if summary > excerpt_buffer_start {
2394 position.add_assign(&(summary - excerpt_buffer_start));
2395 }
2396 position
2397 }),
2398 );
2399 continue;
2400 }
2401 }
2402
2403 summaries.extend(excerpt_anchors.map(|_| position.clone()));
2404 }
2405
2406 summaries
2407 }
2408
2409 pub fn refresh_anchors<'a, I>(&'a self, anchors: I) -> Vec<(usize, Anchor, bool)>
2410 where
2411 I: 'a + IntoIterator<Item = &'a Anchor>,
2412 {
2413 let mut anchors = anchors.into_iter().enumerate().peekable();
2414 let mut cursor = self.excerpts.cursor::<Option<&Locator>>();
2415 cursor.next(&());
2416
2417 let mut result = Vec::new();
2418
2419 while let Some((_, anchor)) = anchors.peek() {
2420 let old_excerpt_id = anchor.excerpt_id;
2421
2422 // Find the location where this anchor's excerpt should be.
2423 let old_locator = self.excerpt_locator_for_id(old_excerpt_id);
2424 cursor.seek_forward(&Some(old_locator), Bias::Left, &());
2425
2426 if cursor.item().is_none() {
2427 cursor.next(&());
2428 }
2429
2430 let next_excerpt = cursor.item();
2431 let prev_excerpt = cursor.prev_item();
2432
2433 // Process all of the anchors for this excerpt.
2434 while let Some((_, anchor)) = anchors.peek() {
2435 if anchor.excerpt_id != old_excerpt_id {
2436 break;
2437 }
2438 let (anchor_ix, anchor) = anchors.next().unwrap();
2439 let mut anchor = *anchor;
2440
2441 // Leave min and max anchors unchanged if invalid or
2442 // if the old excerpt still exists at this location
2443 let mut kept_position = next_excerpt
2444 .map_or(false, |e| e.id == old_excerpt_id && e.contains(&anchor))
2445 || old_excerpt_id == ExcerptId::max()
2446 || old_excerpt_id == ExcerptId::min();
2447
2448 // If the old excerpt no longer exists at this location, then attempt to
2449 // find an equivalent position for this anchor in an adjacent excerpt.
2450 if !kept_position {
2451 for excerpt in [next_excerpt, prev_excerpt].iter().filter_map(|e| *e) {
2452 if excerpt.contains(&anchor) {
2453 anchor.excerpt_id = excerpt.id.clone();
2454 kept_position = true;
2455 break;
2456 }
2457 }
2458 }
2459
2460 // If there's no adjacent excerpt that contains the anchor's position,
2461 // then report that the anchor has lost its position.
2462 if !kept_position {
2463 anchor = if let Some(excerpt) = next_excerpt {
2464 let mut text_anchor = excerpt
2465 .range
2466 .context
2467 .start
2468 .bias(anchor.text_anchor.bias, &excerpt.buffer);
2469 if text_anchor
2470 .cmp(&excerpt.range.context.end, &excerpt.buffer)
2471 .is_gt()
2472 {
2473 text_anchor = excerpt.range.context.end;
2474 }
2475 Anchor {
2476 buffer_id: Some(excerpt.buffer_id),
2477 excerpt_id: excerpt.id.clone(),
2478 text_anchor,
2479 }
2480 } else if let Some(excerpt) = prev_excerpt {
2481 let mut text_anchor = excerpt
2482 .range
2483 .context
2484 .end
2485 .bias(anchor.text_anchor.bias, &excerpt.buffer);
2486 if text_anchor
2487 .cmp(&excerpt.range.context.start, &excerpt.buffer)
2488 .is_lt()
2489 {
2490 text_anchor = excerpt.range.context.start;
2491 }
2492 Anchor {
2493 buffer_id: Some(excerpt.buffer_id),
2494 excerpt_id: excerpt.id.clone(),
2495 text_anchor,
2496 }
2497 } else if anchor.text_anchor.bias == Bias::Left {
2498 Anchor::min()
2499 } else {
2500 Anchor::max()
2501 };
2502 }
2503
2504 result.push((anchor_ix, anchor, kept_position));
2505 }
2506 }
2507 result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self));
2508 result
2509 }
2510
2511 pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
2512 self.anchor_at(position, Bias::Left)
2513 }
2514
2515 pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
2516 self.anchor_at(position, Bias::Right)
2517 }
2518
2519 pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
2520 let offset = position.to_offset(self);
2521 if let Some((excerpt_id, buffer_id, buffer)) = self.as_singleton() {
2522 return Anchor {
2523 buffer_id: Some(buffer_id),
2524 excerpt_id: excerpt_id.clone(),
2525 text_anchor: buffer.anchor_at(offset, bias),
2526 };
2527 }
2528
2529 let mut cursor = self.excerpts.cursor::<(usize, Option<ExcerptId>)>();
2530 cursor.seek(&offset, Bias::Right, &());
2531 if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left {
2532 cursor.prev(&());
2533 }
2534 if let Some(excerpt) = cursor.item() {
2535 let mut overshoot = offset.saturating_sub(cursor.start().0);
2536 if excerpt.has_trailing_newline && offset == cursor.end(&()).0 {
2537 overshoot -= 1;
2538 bias = Bias::Right;
2539 }
2540
2541 let buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2542 let text_anchor =
2543 excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
2544 Anchor {
2545 buffer_id: Some(excerpt.buffer_id),
2546 excerpt_id: excerpt.id.clone(),
2547 text_anchor,
2548 }
2549 } else if offset == 0 && bias == Bias::Left {
2550 Anchor::min()
2551 } else {
2552 Anchor::max()
2553 }
2554 }
2555
2556 pub fn anchor_in_excerpt(&self, excerpt_id: ExcerptId, text_anchor: text::Anchor) -> Anchor {
2557 let locator = self.excerpt_locator_for_id(excerpt_id);
2558 let mut cursor = self.excerpts.cursor::<Option<&Locator>>();
2559 cursor.seek(locator, Bias::Left, &());
2560 if let Some(excerpt) = cursor.item() {
2561 if excerpt.id == excerpt_id {
2562 let text_anchor = excerpt.clip_anchor(text_anchor);
2563 drop(cursor);
2564 return Anchor {
2565 buffer_id: Some(excerpt.buffer_id),
2566 excerpt_id,
2567 text_anchor,
2568 };
2569 }
2570 }
2571 panic!("excerpt not found");
2572 }
2573
2574 pub fn can_resolve(&self, anchor: &Anchor) -> bool {
2575 if anchor.excerpt_id == ExcerptId::min() || anchor.excerpt_id == ExcerptId::max() {
2576 true
2577 } else if let Some(excerpt) = self.excerpt(anchor.excerpt_id) {
2578 excerpt.buffer.can_resolve(&anchor.text_anchor)
2579 } else {
2580 false
2581 }
2582 }
2583
2584 pub fn excerpts(
2585 &self,
2586 ) -> impl Iterator<Item = (ExcerptId, &BufferSnapshot, ExcerptRange<text::Anchor>)> {
2587 self.excerpts
2588 .iter()
2589 .map(|excerpt| (excerpt.id, &excerpt.buffer, excerpt.range.clone()))
2590 }
2591
2592 pub fn excerpt_boundaries_in_range<R, T>(
2593 &self,
2594 range: R,
2595 ) -> impl Iterator<Item = ExcerptBoundary> + '_
2596 where
2597 R: RangeBounds<T>,
2598 T: ToOffset,
2599 {
2600 let start_offset;
2601 let start = match range.start_bound() {
2602 Bound::Included(start) => {
2603 start_offset = start.to_offset(self);
2604 Bound::Included(start_offset)
2605 }
2606 Bound::Excluded(start) => {
2607 start_offset = start.to_offset(self);
2608 Bound::Excluded(start_offset)
2609 }
2610 Bound::Unbounded => {
2611 start_offset = 0;
2612 Bound::Unbounded
2613 }
2614 };
2615 let end = match range.end_bound() {
2616 Bound::Included(end) => Bound::Included(end.to_offset(self)),
2617 Bound::Excluded(end) => Bound::Excluded(end.to_offset(self)),
2618 Bound::Unbounded => Bound::Unbounded,
2619 };
2620 let bounds = (start, end);
2621
2622 let mut cursor = self.excerpts.cursor::<(usize, Point)>();
2623 cursor.seek(&start_offset, Bias::Right, &());
2624 if cursor.item().is_none() {
2625 cursor.prev(&());
2626 }
2627 if !bounds.contains(&cursor.start().0) {
2628 cursor.next(&());
2629 }
2630
2631 let mut prev_buffer_id = cursor.prev_item().map(|excerpt| excerpt.buffer_id);
2632 std::iter::from_fn(move || {
2633 if self.singleton {
2634 None
2635 } else if bounds.contains(&cursor.start().0) {
2636 let excerpt = cursor.item()?;
2637 let starts_new_buffer = Some(excerpt.buffer_id) != prev_buffer_id;
2638 let boundary = ExcerptBoundary {
2639 id: excerpt.id.clone(),
2640 row: cursor.start().1.row,
2641 buffer: excerpt.buffer.clone(),
2642 range: excerpt.range.clone(),
2643 starts_new_buffer,
2644 };
2645
2646 prev_buffer_id = Some(excerpt.buffer_id);
2647 cursor.next(&());
2648 Some(boundary)
2649 } else {
2650 None
2651 }
2652 })
2653 }
2654
2655 pub fn edit_count(&self) -> usize {
2656 self.edit_count
2657 }
2658
2659 pub fn parse_count(&self) -> usize {
2660 self.parse_count
2661 }
2662
2663 /// Returns the smallest enclosing bracket ranges containing the given range or
2664 /// None if no brackets contain range or the range is not contained in a single
2665 /// excerpt
2666 pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
2667 &self,
2668 range: Range<T>,
2669 ) -> Option<(Range<usize>, Range<usize>)> {
2670 let range = range.start.to_offset(self)..range.end.to_offset(self);
2671
2672 // Get the ranges of the innermost pair of brackets.
2673 let mut result: Option<(Range<usize>, Range<usize>)> = None;
2674
2675 let Some(enclosing_bracket_ranges) = self.enclosing_bracket_ranges(range.clone()) else { return None; };
2676
2677 for (open, close) in enclosing_bracket_ranges {
2678 let len = close.end - open.start;
2679
2680 if let Some((existing_open, existing_close)) = &result {
2681 let existing_len = existing_close.end - existing_open.start;
2682 if len > existing_len {
2683 continue;
2684 }
2685 }
2686
2687 result = Some((open, close));
2688 }
2689
2690 result
2691 }
2692
2693 /// Returns enclosing bracket ranges containing the given range or returns None if the range is
2694 /// not contained in a single excerpt
2695 pub fn enclosing_bracket_ranges<'a, T: ToOffset>(
2696 &'a self,
2697 range: Range<T>,
2698 ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + 'a> {
2699 let range = range.start.to_offset(self)..range.end.to_offset(self);
2700
2701 self.bracket_ranges(range.clone()).map(|range_pairs| {
2702 range_pairs
2703 .filter(move |(open, close)| open.start <= range.start && close.end >= range.end)
2704 })
2705 }
2706
2707 /// Returns bracket range pairs overlapping the given `range` or returns None if the `range` is
2708 /// not contained in a single excerpt
2709 pub fn bracket_ranges<'a, T: ToOffset>(
2710 &'a self,
2711 range: Range<T>,
2712 ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + 'a> {
2713 let range = range.start.to_offset(self)..range.end.to_offset(self);
2714 let excerpt = self.excerpt_containing(range.clone());
2715 excerpt.map(|(excerpt, excerpt_offset)| {
2716 let excerpt_buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2717 let excerpt_buffer_end = excerpt_buffer_start + excerpt.text_summary.len;
2718
2719 let start_in_buffer = excerpt_buffer_start + range.start.saturating_sub(excerpt_offset);
2720 let end_in_buffer = excerpt_buffer_start + range.end.saturating_sub(excerpt_offset);
2721
2722 excerpt
2723 .buffer
2724 .bracket_ranges(start_in_buffer..end_in_buffer)
2725 .filter_map(move |(start_bracket_range, end_bracket_range)| {
2726 if start_bracket_range.start < excerpt_buffer_start
2727 || end_bracket_range.end > excerpt_buffer_end
2728 {
2729 return None;
2730 }
2731
2732 let mut start_bracket_range = start_bracket_range.clone();
2733 start_bracket_range.start =
2734 excerpt_offset + (start_bracket_range.start - excerpt_buffer_start);
2735 start_bracket_range.end =
2736 excerpt_offset + (start_bracket_range.end - excerpt_buffer_start);
2737
2738 let mut end_bracket_range = end_bracket_range.clone();
2739 end_bracket_range.start =
2740 excerpt_offset + (end_bracket_range.start - excerpt_buffer_start);
2741 end_bracket_range.end =
2742 excerpt_offset + (end_bracket_range.end - excerpt_buffer_start);
2743 Some((start_bracket_range, end_bracket_range))
2744 })
2745 })
2746 }
2747
2748 pub fn diagnostics_update_count(&self) -> usize {
2749 self.diagnostics_update_count
2750 }
2751
2752 pub fn git_diff_update_count(&self) -> usize {
2753 self.git_diff_update_count
2754 }
2755
2756 pub fn trailing_excerpt_update_count(&self) -> usize {
2757 self.trailing_excerpt_update_count
2758 }
2759
2760 pub fn file_at<'a, T: ToOffset>(&'a self, point: T) -> Option<&'a Arc<dyn File>> {
2761 self.point_to_buffer_offset(point)
2762 .and_then(|(buffer, _)| buffer.file())
2763 }
2764
2765 pub fn language_at<'a, T: ToOffset>(&'a self, point: T) -> Option<&'a Arc<Language>> {
2766 self.point_to_buffer_offset(point)
2767 .and_then(|(buffer, offset)| buffer.language_at(offset))
2768 }
2769
2770 pub fn language_scope_at<'a, T: ToOffset>(&'a self, point: T) -> Option<LanguageScope> {
2771 self.point_to_buffer_offset(point)
2772 .and_then(|(buffer, offset)| buffer.language_scope_at(offset))
2773 }
2774
2775 pub fn language_indent_size_at<T: ToOffset>(
2776 &self,
2777 position: T,
2778 cx: &AppContext,
2779 ) -> Option<IndentSize> {
2780 let (buffer_snapshot, offset) = self.point_to_buffer_offset(position)?;
2781 Some(buffer_snapshot.language_indent_size_at(offset, cx))
2782 }
2783
2784 pub fn is_dirty(&self) -> bool {
2785 self.is_dirty
2786 }
2787
2788 pub fn has_conflict(&self) -> bool {
2789 self.has_conflict
2790 }
2791
2792 pub fn diagnostic_group<'a, O>(
2793 &'a self,
2794 group_id: usize,
2795 ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
2796 where
2797 O: text::FromAnchor + 'a,
2798 {
2799 self.as_singleton()
2800 .into_iter()
2801 .flat_map(move |(_, _, buffer)| buffer.diagnostic_group(group_id))
2802 }
2803
2804 pub fn diagnostics_in_range<'a, T, O>(
2805 &'a self,
2806 range: Range<T>,
2807 reversed: bool,
2808 ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
2809 where
2810 T: 'a + ToOffset,
2811 O: 'a + text::FromAnchor + Ord,
2812 {
2813 self.as_singleton()
2814 .into_iter()
2815 .flat_map(move |(_, _, buffer)| {
2816 buffer.diagnostics_in_range(
2817 range.start.to_offset(self)..range.end.to_offset(self),
2818 reversed,
2819 )
2820 })
2821 }
2822
2823 pub fn has_git_diffs(&self) -> bool {
2824 for excerpt in self.excerpts.iter() {
2825 if !excerpt.buffer.git_diff.is_empty() {
2826 return true;
2827 }
2828 }
2829 false
2830 }
2831
2832 pub fn git_diff_hunks_in_range_rev<'a>(
2833 &'a self,
2834 row_range: Range<u32>,
2835 ) -> impl 'a + Iterator<Item = DiffHunk<u32>> {
2836 let mut cursor = self.excerpts.cursor::<Point>();
2837
2838 cursor.seek(&Point::new(row_range.end, 0), Bias::Left, &());
2839 if cursor.item().is_none() {
2840 cursor.prev(&());
2841 }
2842
2843 std::iter::from_fn(move || {
2844 let excerpt = cursor.item()?;
2845 let multibuffer_start = *cursor.start();
2846 let multibuffer_end = multibuffer_start + excerpt.text_summary.lines;
2847 if multibuffer_start.row >= row_range.end {
2848 return None;
2849 }
2850
2851 let mut buffer_start = excerpt.range.context.start;
2852 let mut buffer_end = excerpt.range.context.end;
2853 let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
2854 let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
2855
2856 if row_range.start > multibuffer_start.row {
2857 let buffer_start_point =
2858 excerpt_start_point + Point::new(row_range.start - multibuffer_start.row, 0);
2859 buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
2860 }
2861
2862 if row_range.end < multibuffer_end.row {
2863 let buffer_end_point =
2864 excerpt_start_point + Point::new(row_range.end - multibuffer_start.row, 0);
2865 buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
2866 }
2867
2868 let buffer_hunks = excerpt
2869 .buffer
2870 .git_diff_hunks_intersecting_range_rev(buffer_start..buffer_end)
2871 .filter_map(move |hunk| {
2872 let start = multibuffer_start.row
2873 + hunk
2874 .buffer_range
2875 .start
2876 .saturating_sub(excerpt_start_point.row);
2877 let end = multibuffer_start.row
2878 + hunk
2879 .buffer_range
2880 .end
2881 .min(excerpt_end_point.row + 1)
2882 .saturating_sub(excerpt_start_point.row);
2883
2884 Some(DiffHunk {
2885 buffer_range: start..end,
2886 diff_base_byte_range: hunk.diff_base_byte_range.clone(),
2887 })
2888 });
2889
2890 cursor.prev(&());
2891
2892 Some(buffer_hunks)
2893 })
2894 .flatten()
2895 }
2896
2897 pub fn git_diff_hunks_in_range<'a>(
2898 &'a self,
2899 row_range: Range<u32>,
2900 ) -> impl 'a + Iterator<Item = DiffHunk<u32>> {
2901 let mut cursor = self.excerpts.cursor::<Point>();
2902
2903 cursor.seek(&Point::new(row_range.start, 0), Bias::Right, &());
2904
2905 std::iter::from_fn(move || {
2906 let excerpt = cursor.item()?;
2907 let multibuffer_start = *cursor.start();
2908 let multibuffer_end = multibuffer_start + excerpt.text_summary.lines;
2909 if multibuffer_start.row >= row_range.end {
2910 return None;
2911 }
2912
2913 let mut buffer_start = excerpt.range.context.start;
2914 let mut buffer_end = excerpt.range.context.end;
2915 let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
2916 let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
2917
2918 if row_range.start > multibuffer_start.row {
2919 let buffer_start_point =
2920 excerpt_start_point + Point::new(row_range.start - multibuffer_start.row, 0);
2921 buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
2922 }
2923
2924 if row_range.end < multibuffer_end.row {
2925 let buffer_end_point =
2926 excerpt_start_point + Point::new(row_range.end - multibuffer_start.row, 0);
2927 buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
2928 }
2929
2930 let buffer_hunks = excerpt
2931 .buffer
2932 .git_diff_hunks_intersecting_range(buffer_start..buffer_end)
2933 .filter_map(move |hunk| {
2934 let start = multibuffer_start.row
2935 + hunk
2936 .buffer_range
2937 .start
2938 .saturating_sub(excerpt_start_point.row);
2939 let end = multibuffer_start.row
2940 + hunk
2941 .buffer_range
2942 .end
2943 .min(excerpt_end_point.row + 1)
2944 .saturating_sub(excerpt_start_point.row);
2945
2946 Some(DiffHunk {
2947 buffer_range: start..end,
2948 diff_base_byte_range: hunk.diff_base_byte_range.clone(),
2949 })
2950 });
2951
2952 cursor.next(&());
2953
2954 Some(buffer_hunks)
2955 })
2956 .flatten()
2957 }
2958
2959 pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
2960 let range = range.start.to_offset(self)..range.end.to_offset(self);
2961
2962 self.excerpt_containing(range.clone())
2963 .and_then(|(excerpt, excerpt_offset)| {
2964 let excerpt_buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2965 let excerpt_buffer_end = excerpt_buffer_start + excerpt.text_summary.len;
2966
2967 let start_in_buffer =
2968 excerpt_buffer_start + range.start.saturating_sub(excerpt_offset);
2969 let end_in_buffer = excerpt_buffer_start + range.end.saturating_sub(excerpt_offset);
2970 let mut ancestor_buffer_range = excerpt
2971 .buffer
2972 .range_for_syntax_ancestor(start_in_buffer..end_in_buffer)?;
2973 ancestor_buffer_range.start =
2974 cmp::max(ancestor_buffer_range.start, excerpt_buffer_start);
2975 ancestor_buffer_range.end = cmp::min(ancestor_buffer_range.end, excerpt_buffer_end);
2976
2977 let start = excerpt_offset + (ancestor_buffer_range.start - excerpt_buffer_start);
2978 let end = excerpt_offset + (ancestor_buffer_range.end - excerpt_buffer_start);
2979 Some(start..end)
2980 })
2981 }
2982
2983 pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
2984 let (excerpt_id, _, buffer) = self.as_singleton()?;
2985 let outline = buffer.outline(theme)?;
2986 Some(Outline::new(
2987 outline
2988 .items
2989 .into_iter()
2990 .map(|item| OutlineItem {
2991 depth: item.depth,
2992 range: self.anchor_in_excerpt(excerpt_id.clone(), item.range.start)
2993 ..self.anchor_in_excerpt(excerpt_id.clone(), item.range.end),
2994 text: item.text,
2995 highlight_ranges: item.highlight_ranges,
2996 name_ranges: item.name_ranges,
2997 })
2998 .collect(),
2999 ))
3000 }
3001
3002 pub fn symbols_containing<T: ToOffset>(
3003 &self,
3004 offset: T,
3005 theme: Option<&SyntaxTheme>,
3006 ) -> Option<(u64, Vec<OutlineItem<Anchor>>)> {
3007 let anchor = self.anchor_before(offset);
3008 let excerpt_id = anchor.excerpt_id();
3009 let excerpt = self.excerpt(excerpt_id)?;
3010 Some((
3011 excerpt.buffer_id,
3012 excerpt
3013 .buffer
3014 .symbols_containing(anchor.text_anchor, theme)
3015 .into_iter()
3016 .flatten()
3017 .map(|item| OutlineItem {
3018 depth: item.depth,
3019 range: self.anchor_in_excerpt(excerpt_id, item.range.start)
3020 ..self.anchor_in_excerpt(excerpt_id, item.range.end),
3021 text: item.text,
3022 highlight_ranges: item.highlight_ranges,
3023 name_ranges: item.name_ranges,
3024 })
3025 .collect(),
3026 ))
3027 }
3028
3029 fn excerpt_locator_for_id<'a>(&'a self, id: ExcerptId) -> &'a Locator {
3030 if id == ExcerptId::min() {
3031 Locator::min_ref()
3032 } else if id == ExcerptId::max() {
3033 Locator::max_ref()
3034 } else {
3035 let mut cursor = self.excerpt_ids.cursor::<ExcerptId>();
3036 cursor.seek(&id, Bias::Left, &());
3037 if let Some(entry) = cursor.item() {
3038 if entry.id == id {
3039 return &entry.locator;
3040 }
3041 }
3042 panic!("invalid excerpt id {:?}", id)
3043 }
3044 }
3045
3046 pub fn buffer_id_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<u64> {
3047 Some(self.excerpt(excerpt_id)?.buffer_id)
3048 }
3049
3050 pub fn buffer_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<&BufferSnapshot> {
3051 Some(&self.excerpt(excerpt_id)?.buffer)
3052 }
3053
3054 fn excerpt<'a>(&'a self, excerpt_id: ExcerptId) -> Option<&'a Excerpt> {
3055 let mut cursor = self.excerpts.cursor::<Option<&Locator>>();
3056 let locator = self.excerpt_locator_for_id(excerpt_id);
3057 cursor.seek(&Some(locator), Bias::Left, &());
3058 if let Some(excerpt) = cursor.item() {
3059 if excerpt.id == excerpt_id {
3060 return Some(excerpt);
3061 }
3062 }
3063 None
3064 }
3065
3066 /// Returns the excerpt containing range and its offset start within the multibuffer or none if `range` spans multiple excerpts
3067 fn excerpt_containing<'a, T: ToOffset>(
3068 &'a self,
3069 range: Range<T>,
3070 ) -> Option<(&'a Excerpt, usize)> {
3071 let range = range.start.to_offset(self)..range.end.to_offset(self);
3072
3073 let mut cursor = self.excerpts.cursor::<usize>();
3074 cursor.seek(&range.start, Bias::Right, &());
3075 let start_excerpt = cursor.item();
3076
3077 if range.start == range.end {
3078 return start_excerpt.map(|excerpt| (excerpt, *cursor.start()));
3079 }
3080
3081 cursor.seek(&range.end, Bias::Right, &());
3082 let end_excerpt = cursor.item();
3083
3084 start_excerpt
3085 .zip(end_excerpt)
3086 .and_then(|(start_excerpt, end_excerpt)| {
3087 if start_excerpt.id != end_excerpt.id {
3088 return None;
3089 }
3090
3091 Some((start_excerpt, *cursor.start()))
3092 })
3093 }
3094
3095 pub fn remote_selections_in_range<'a>(
3096 &'a self,
3097 range: &'a Range<Anchor>,
3098 ) -> impl 'a + Iterator<Item = (ReplicaId, bool, CursorShape, Selection<Anchor>)> {
3099 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
3100 let start_locator = self.excerpt_locator_for_id(range.start.excerpt_id);
3101 let end_locator = self.excerpt_locator_for_id(range.end.excerpt_id);
3102 cursor.seek(start_locator, Bias::Left, &());
3103 cursor
3104 .take_while(move |excerpt| excerpt.locator <= *end_locator)
3105 .flat_map(move |excerpt| {
3106 let mut query_range = excerpt.range.context.start..excerpt.range.context.end;
3107 if excerpt.id == range.start.excerpt_id {
3108 query_range.start = range.start.text_anchor;
3109 }
3110 if excerpt.id == range.end.excerpt_id {
3111 query_range.end = range.end.text_anchor;
3112 }
3113
3114 excerpt
3115 .buffer
3116 .remote_selections_in_range(query_range)
3117 .flat_map(move |(replica_id, line_mode, cursor_shape, selections)| {
3118 selections.map(move |selection| {
3119 let mut start = Anchor {
3120 buffer_id: Some(excerpt.buffer_id),
3121 excerpt_id: excerpt.id.clone(),
3122 text_anchor: selection.start,
3123 };
3124 let mut end = Anchor {
3125 buffer_id: Some(excerpt.buffer_id),
3126 excerpt_id: excerpt.id.clone(),
3127 text_anchor: selection.end,
3128 };
3129 if range.start.cmp(&start, self).is_gt() {
3130 start = range.start.clone();
3131 }
3132 if range.end.cmp(&end, self).is_lt() {
3133 end = range.end.clone();
3134 }
3135
3136 (
3137 replica_id,
3138 line_mode,
3139 cursor_shape,
3140 Selection {
3141 id: selection.id,
3142 start,
3143 end,
3144 reversed: selection.reversed,
3145 goal: selection.goal,
3146 },
3147 )
3148 })
3149 })
3150 })
3151 }
3152}
3153
3154#[cfg(any(test, feature = "test-support"))]
3155impl MultiBufferSnapshot {
3156 pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
3157 let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
3158 let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
3159 start..end
3160 }
3161}
3162
3163impl History {
3164 fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
3165 self.transaction_depth += 1;
3166 if self.transaction_depth == 1 {
3167 let id = self.next_transaction_id.tick();
3168 self.undo_stack.push(Transaction {
3169 id,
3170 buffer_transactions: Default::default(),
3171 first_edit_at: now,
3172 last_edit_at: now,
3173 suppress_grouping: false,
3174 });
3175 Some(id)
3176 } else {
3177 None
3178 }
3179 }
3180
3181 fn end_transaction(
3182 &mut self,
3183 now: Instant,
3184 buffer_transactions: HashMap<u64, TransactionId>,
3185 ) -> bool {
3186 assert_ne!(self.transaction_depth, 0);
3187 self.transaction_depth -= 1;
3188 if self.transaction_depth == 0 {
3189 if buffer_transactions.is_empty() {
3190 self.undo_stack.pop();
3191 false
3192 } else {
3193 self.redo_stack.clear();
3194 let transaction = self.undo_stack.last_mut().unwrap();
3195 transaction.last_edit_at = now;
3196 for (buffer_id, transaction_id) in buffer_transactions {
3197 transaction
3198 .buffer_transactions
3199 .entry(buffer_id)
3200 .or_insert(transaction_id);
3201 }
3202 true
3203 }
3204 } else {
3205 false
3206 }
3207 }
3208
3209 fn push_transaction<'a, T>(
3210 &mut self,
3211 buffer_transactions: T,
3212 now: Instant,
3213 cx: &mut ModelContext<MultiBuffer>,
3214 ) where
3215 T: IntoIterator<Item = (&'a ModelHandle<Buffer>, &'a language::Transaction)>,
3216 {
3217 assert_eq!(self.transaction_depth, 0);
3218 let transaction = Transaction {
3219 id: self.next_transaction_id.tick(),
3220 buffer_transactions: buffer_transactions
3221 .into_iter()
3222 .map(|(buffer, transaction)| (buffer.read(cx).remote_id(), transaction.id))
3223 .collect(),
3224 first_edit_at: now,
3225 last_edit_at: now,
3226 suppress_grouping: false,
3227 };
3228 if !transaction.buffer_transactions.is_empty() {
3229 self.undo_stack.push(transaction);
3230 self.redo_stack.clear();
3231 }
3232 }
3233
3234 fn finalize_last_transaction(&mut self) {
3235 if let Some(transaction) = self.undo_stack.last_mut() {
3236 transaction.suppress_grouping = true;
3237 }
3238 }
3239
3240 fn pop_undo(&mut self) -> Option<&mut Transaction> {
3241 assert_eq!(self.transaction_depth, 0);
3242 if let Some(transaction) = self.undo_stack.pop() {
3243 self.redo_stack.push(transaction);
3244 self.redo_stack.last_mut()
3245 } else {
3246 None
3247 }
3248 }
3249
3250 fn pop_redo(&mut self) -> Option<&mut Transaction> {
3251 assert_eq!(self.transaction_depth, 0);
3252 if let Some(transaction) = self.redo_stack.pop() {
3253 self.undo_stack.push(transaction);
3254 self.undo_stack.last_mut()
3255 } else {
3256 None
3257 }
3258 }
3259
3260 fn group(&mut self) -> Option<TransactionId> {
3261 let mut count = 0;
3262 let mut transactions = self.undo_stack.iter();
3263 if let Some(mut transaction) = transactions.next_back() {
3264 while let Some(prev_transaction) = transactions.next_back() {
3265 if !prev_transaction.suppress_grouping
3266 && transaction.first_edit_at - prev_transaction.last_edit_at
3267 <= self.group_interval
3268 {
3269 transaction = prev_transaction;
3270 count += 1;
3271 } else {
3272 break;
3273 }
3274 }
3275 }
3276 self.group_trailing(count)
3277 }
3278
3279 fn group_until(&mut self, transaction_id: TransactionId) {
3280 let mut count = 0;
3281 for transaction in self.undo_stack.iter().rev() {
3282 if transaction.id == transaction_id {
3283 self.group_trailing(count);
3284 break;
3285 } else if transaction.suppress_grouping {
3286 break;
3287 } else {
3288 count += 1;
3289 }
3290 }
3291 }
3292
3293 fn group_trailing(&mut self, n: usize) -> Option<TransactionId> {
3294 let new_len = self.undo_stack.len() - n;
3295 let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
3296 if let Some(last_transaction) = transactions_to_keep.last_mut() {
3297 if let Some(transaction) = transactions_to_merge.last() {
3298 last_transaction.last_edit_at = transaction.last_edit_at;
3299 }
3300 for to_merge in transactions_to_merge {
3301 for (buffer_id, transaction_id) in &to_merge.buffer_transactions {
3302 last_transaction
3303 .buffer_transactions
3304 .entry(*buffer_id)
3305 .or_insert(*transaction_id);
3306 }
3307 }
3308 }
3309
3310 self.undo_stack.truncate(new_len);
3311 self.undo_stack.last().map(|t| t.id)
3312 }
3313}
3314
3315impl Excerpt {
3316 fn new(
3317 id: ExcerptId,
3318 locator: Locator,
3319 buffer_id: u64,
3320 buffer: BufferSnapshot,
3321 range: ExcerptRange<text::Anchor>,
3322 has_trailing_newline: bool,
3323 ) -> Self {
3324 Excerpt {
3325 id,
3326 locator,
3327 max_buffer_row: range.context.end.to_point(&buffer).row,
3328 text_summary: buffer
3329 .text_summary_for_range::<TextSummary, _>(range.context.to_offset(&buffer)),
3330 buffer_id,
3331 buffer,
3332 range,
3333 has_trailing_newline,
3334 }
3335 }
3336
3337 fn chunks_in_range(&self, range: Range<usize>, language_aware: bool) -> ExcerptChunks {
3338 let content_start = self.range.context.start.to_offset(&self.buffer);
3339 let chunks_start = content_start + range.start;
3340 let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
3341
3342 let footer_height = if self.has_trailing_newline
3343 && range.start <= self.text_summary.len
3344 && range.end > self.text_summary.len
3345 {
3346 1
3347 } else {
3348 0
3349 };
3350
3351 let content_chunks = self.buffer.chunks(chunks_start..chunks_end, language_aware);
3352
3353 ExcerptChunks {
3354 content_chunks,
3355 footer_height,
3356 }
3357 }
3358
3359 fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
3360 let content_start = self.range.context.start.to_offset(&self.buffer);
3361 let bytes_start = content_start + range.start;
3362 let bytes_end = content_start + cmp::min(range.end, self.text_summary.len);
3363 let footer_height = if self.has_trailing_newline
3364 && range.start <= self.text_summary.len
3365 && range.end > self.text_summary.len
3366 {
3367 1
3368 } else {
3369 0
3370 };
3371 let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
3372
3373 ExcerptBytes {
3374 content_bytes,
3375 footer_height,
3376 }
3377 }
3378
3379 fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
3380 if text_anchor
3381 .cmp(&self.range.context.start, &self.buffer)
3382 .is_lt()
3383 {
3384 self.range.context.start
3385 } else if text_anchor
3386 .cmp(&self.range.context.end, &self.buffer)
3387 .is_gt()
3388 {
3389 self.range.context.end
3390 } else {
3391 text_anchor
3392 }
3393 }
3394
3395 fn contains(&self, anchor: &Anchor) -> bool {
3396 Some(self.buffer_id) == anchor.buffer_id
3397 && self
3398 .range
3399 .context
3400 .start
3401 .cmp(&anchor.text_anchor, &self.buffer)
3402 .is_le()
3403 && self
3404 .range
3405 .context
3406 .end
3407 .cmp(&anchor.text_anchor, &self.buffer)
3408 .is_ge()
3409 }
3410}
3411
3412impl ExcerptId {
3413 pub fn min() -> Self {
3414 Self(0)
3415 }
3416
3417 pub fn max() -> Self {
3418 Self(usize::MAX)
3419 }
3420
3421 pub fn to_proto(&self) -> u64 {
3422 self.0 as _
3423 }
3424
3425 pub fn from_proto(proto: u64) -> Self {
3426 Self(proto as _)
3427 }
3428
3429 pub fn cmp(&self, other: &Self, snapshot: &MultiBufferSnapshot) -> cmp::Ordering {
3430 let a = snapshot.excerpt_locator_for_id(*self);
3431 let b = snapshot.excerpt_locator_for_id(*other);
3432 a.cmp(&b).then_with(|| self.0.cmp(&other.0))
3433 }
3434}
3435
3436impl Into<usize> for ExcerptId {
3437 fn into(self) -> usize {
3438 self.0
3439 }
3440}
3441
3442impl fmt::Debug for Excerpt {
3443 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3444 f.debug_struct("Excerpt")
3445 .field("id", &self.id)
3446 .field("locator", &self.locator)
3447 .field("buffer_id", &self.buffer_id)
3448 .field("range", &self.range)
3449 .field("text_summary", &self.text_summary)
3450 .field("has_trailing_newline", &self.has_trailing_newline)
3451 .finish()
3452 }
3453}
3454
3455impl sum_tree::Item for Excerpt {
3456 type Summary = ExcerptSummary;
3457
3458 fn summary(&self) -> Self::Summary {
3459 let mut text = self.text_summary.clone();
3460 if self.has_trailing_newline {
3461 text += TextSummary::from("\n");
3462 }
3463 ExcerptSummary {
3464 excerpt_id: self.id,
3465 excerpt_locator: self.locator.clone(),
3466 max_buffer_row: self.max_buffer_row,
3467 text,
3468 }
3469 }
3470}
3471
3472impl sum_tree::Item for ExcerptIdMapping {
3473 type Summary = ExcerptId;
3474
3475 fn summary(&self) -> Self::Summary {
3476 self.id
3477 }
3478}
3479
3480impl sum_tree::KeyedItem for ExcerptIdMapping {
3481 type Key = ExcerptId;
3482
3483 fn key(&self) -> Self::Key {
3484 self.id
3485 }
3486}
3487
3488impl sum_tree::Summary for ExcerptId {
3489 type Context = ();
3490
3491 fn add_summary(&mut self, other: &Self, _: &()) {
3492 *self = *other;
3493 }
3494}
3495
3496impl sum_tree::Summary for ExcerptSummary {
3497 type Context = ();
3498
3499 fn add_summary(&mut self, summary: &Self, _: &()) {
3500 debug_assert!(summary.excerpt_locator > self.excerpt_locator);
3501 self.excerpt_locator = summary.excerpt_locator.clone();
3502 self.text.add_summary(&summary.text, &());
3503 self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row);
3504 }
3505}
3506
3507impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
3508 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3509 *self += &summary.text;
3510 }
3511}
3512
3513impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
3514 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3515 *self += summary.text.len;
3516 }
3517}
3518
3519impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
3520 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
3521 Ord::cmp(self, &cursor_location.text.len)
3522 }
3523}
3524
3525impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, Option<&'a Locator>> for Locator {
3526 fn cmp(&self, cursor_location: &Option<&'a Locator>, _: &()) -> cmp::Ordering {
3527 Ord::cmp(&Some(self), cursor_location)
3528 }
3529}
3530
3531impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Locator {
3532 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
3533 Ord::cmp(self, &cursor_location.excerpt_locator)
3534 }
3535}
3536
3537impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for OffsetUtf16 {
3538 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3539 *self += summary.text.len_utf16;
3540 }
3541}
3542
3543impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
3544 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3545 *self += summary.text.lines;
3546 }
3547}
3548
3549impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
3550 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3551 *self += summary.text.lines_utf16()
3552 }
3553}
3554
3555impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a Locator> {
3556 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3557 *self = Some(&summary.excerpt_locator);
3558 }
3559}
3560
3561impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<ExcerptId> {
3562 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3563 *self = Some(summary.excerpt_id);
3564 }
3565}
3566
3567impl<'a> MultiBufferRows<'a> {
3568 pub fn seek(&mut self, row: u32) {
3569 self.buffer_row_range = 0..0;
3570
3571 self.excerpts
3572 .seek_forward(&Point::new(row, 0), Bias::Right, &());
3573 if self.excerpts.item().is_none() {
3574 self.excerpts.prev(&());
3575
3576 if self.excerpts.item().is_none() && row == 0 {
3577 self.buffer_row_range = 0..1;
3578 return;
3579 }
3580 }
3581
3582 if let Some(excerpt) = self.excerpts.item() {
3583 let overshoot = row - self.excerpts.start().row;
3584 let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
3585 self.buffer_row_range.start = excerpt_start + overshoot;
3586 self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
3587 }
3588 }
3589}
3590
3591impl<'a> Iterator for MultiBufferRows<'a> {
3592 type Item = Option<u32>;
3593
3594 fn next(&mut self) -> Option<Self::Item> {
3595 loop {
3596 if !self.buffer_row_range.is_empty() {
3597 let row = Some(self.buffer_row_range.start);
3598 self.buffer_row_range.start += 1;
3599 return Some(row);
3600 }
3601 self.excerpts.item()?;
3602 self.excerpts.next(&());
3603 let excerpt = self.excerpts.item()?;
3604 self.buffer_row_range.start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
3605 self.buffer_row_range.end =
3606 self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
3607 }
3608 }
3609}
3610
3611impl<'a> MultiBufferChunks<'a> {
3612 pub fn offset(&self) -> usize {
3613 self.range.start
3614 }
3615
3616 pub fn seek(&mut self, offset: usize) {
3617 self.range.start = offset;
3618 self.excerpts.seek(&offset, Bias::Right, &());
3619 if let Some(excerpt) = self.excerpts.item() {
3620 self.excerpt_chunks = Some(excerpt.chunks_in_range(
3621 self.range.start - self.excerpts.start()..self.range.end - self.excerpts.start(),
3622 self.language_aware,
3623 ));
3624 } else {
3625 self.excerpt_chunks = None;
3626 }
3627 }
3628}
3629
3630impl<'a> Iterator for MultiBufferChunks<'a> {
3631 type Item = Chunk<'a>;
3632
3633 fn next(&mut self) -> Option<Self::Item> {
3634 if self.range.is_empty() {
3635 None
3636 } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
3637 self.range.start += chunk.text.len();
3638 Some(chunk)
3639 } else {
3640 self.excerpts.next(&());
3641 let excerpt = self.excerpts.item()?;
3642 self.excerpt_chunks = Some(excerpt.chunks_in_range(
3643 0..self.range.end - self.excerpts.start(),
3644 self.language_aware,
3645 ));
3646 self.next()
3647 }
3648 }
3649}
3650
3651impl<'a> MultiBufferBytes<'a> {
3652 fn consume(&mut self, len: usize) {
3653 self.range.start += len;
3654 self.chunk = &self.chunk[len..];
3655
3656 if !self.range.is_empty() && self.chunk.is_empty() {
3657 if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
3658 self.chunk = chunk;
3659 } else {
3660 self.excerpts.next(&());
3661 if let Some(excerpt) = self.excerpts.item() {
3662 let mut excerpt_bytes =
3663 excerpt.bytes_in_range(0..self.range.end - self.excerpts.start());
3664 self.chunk = excerpt_bytes.next().unwrap();
3665 self.excerpt_bytes = Some(excerpt_bytes);
3666 }
3667 }
3668 }
3669 }
3670}
3671
3672impl<'a> Iterator for MultiBufferBytes<'a> {
3673 type Item = &'a [u8];
3674
3675 fn next(&mut self) -> Option<Self::Item> {
3676 let chunk = self.chunk;
3677 if chunk.is_empty() {
3678 None
3679 } else {
3680 self.consume(chunk.len());
3681 Some(chunk)
3682 }
3683 }
3684}
3685
3686impl<'a> io::Read for MultiBufferBytes<'a> {
3687 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
3688 let len = cmp::min(buf.len(), self.chunk.len());
3689 buf[..len].copy_from_slice(&self.chunk[..len]);
3690 if len > 0 {
3691 self.consume(len);
3692 }
3693 Ok(len)
3694 }
3695}
3696
3697impl<'a> Iterator for ExcerptBytes<'a> {
3698 type Item = &'a [u8];
3699
3700 fn next(&mut self) -> Option<Self::Item> {
3701 if let Some(chunk) = self.content_bytes.next() {
3702 if !chunk.is_empty() {
3703 return Some(chunk);
3704 }
3705 }
3706
3707 if self.footer_height > 0 {
3708 let result = &NEWLINES[..self.footer_height];
3709 self.footer_height = 0;
3710 return Some(result);
3711 }
3712
3713 None
3714 }
3715}
3716
3717impl<'a> Iterator for ExcerptChunks<'a> {
3718 type Item = Chunk<'a>;
3719
3720 fn next(&mut self) -> Option<Self::Item> {
3721 if let Some(chunk) = self.content_chunks.next() {
3722 return Some(chunk);
3723 }
3724
3725 if self.footer_height > 0 {
3726 let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
3727 self.footer_height = 0;
3728 return Some(Chunk {
3729 text,
3730 ..Default::default()
3731 });
3732 }
3733
3734 None
3735 }
3736}
3737
3738impl ToOffset for Point {
3739 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3740 snapshot.point_to_offset(*self)
3741 }
3742}
3743
3744impl ToOffset for usize {
3745 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3746 assert!(*self <= snapshot.len(), "offset is out of range");
3747 *self
3748 }
3749}
3750
3751impl ToOffset for OffsetUtf16 {
3752 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3753 snapshot.offset_utf16_to_offset(*self)
3754 }
3755}
3756
3757impl ToOffset for PointUtf16 {
3758 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3759 snapshot.point_utf16_to_offset(*self)
3760 }
3761}
3762
3763impl ToOffsetUtf16 for OffsetUtf16 {
3764 fn to_offset_utf16(&self, _snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
3765 *self
3766 }
3767}
3768
3769impl ToOffsetUtf16 for usize {
3770 fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
3771 snapshot.offset_to_offset_utf16(*self)
3772 }
3773}
3774
3775impl ToPoint for usize {
3776 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
3777 snapshot.offset_to_point(*self)
3778 }
3779}
3780
3781impl ToPoint for Point {
3782 fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
3783 *self
3784 }
3785}
3786
3787impl ToPointUtf16 for usize {
3788 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
3789 snapshot.offset_to_point_utf16(*self)
3790 }
3791}
3792
3793impl ToPointUtf16 for Point {
3794 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
3795 snapshot.point_to_point_utf16(*self)
3796 }
3797}
3798
3799impl ToPointUtf16 for PointUtf16 {
3800 fn to_point_utf16<'a>(&self, _: &MultiBufferSnapshot) -> PointUtf16 {
3801 *self
3802 }
3803}
3804
3805fn build_excerpt_ranges<T>(
3806 buffer: &BufferSnapshot,
3807 ranges: &[Range<T>],
3808 context_line_count: u32,
3809) -> (Vec<ExcerptRange<Point>>, Vec<usize>)
3810where
3811 T: text::ToPoint,
3812{
3813 let max_point = buffer.max_point();
3814 let mut range_counts = Vec::new();
3815 let mut excerpt_ranges = Vec::new();
3816 let mut range_iter = ranges
3817 .iter()
3818 .map(|range| range.start.to_point(buffer)..range.end.to_point(buffer))
3819 .peekable();
3820 while let Some(range) = range_iter.next() {
3821 let excerpt_start = Point::new(range.start.row.saturating_sub(context_line_count), 0);
3822 let mut excerpt_end = Point::new(range.end.row + 1 + context_line_count, 0).min(max_point);
3823 let mut ranges_in_excerpt = 1;
3824
3825 while let Some(next_range) = range_iter.peek() {
3826 if next_range.start.row <= excerpt_end.row + context_line_count {
3827 excerpt_end =
3828 Point::new(next_range.end.row + 1 + context_line_count, 0).min(max_point);
3829 ranges_in_excerpt += 1;
3830 range_iter.next();
3831 } else {
3832 break;
3833 }
3834 }
3835
3836 excerpt_ranges.push(ExcerptRange {
3837 context: excerpt_start..excerpt_end,
3838 primary: Some(range),
3839 });
3840 range_counts.push(ranges_in_excerpt);
3841 }
3842
3843 (excerpt_ranges, range_counts)
3844}
3845
3846#[cfg(test)]
3847mod tests {
3848 use super::*;
3849 use futures::StreamExt;
3850 use gpui::{AppContext, TestAppContext};
3851 use language::{Buffer, Rope};
3852 use rand::prelude::*;
3853 use settings::Settings;
3854 use std::{env, rc::Rc};
3855 use unindent::Unindent;
3856
3857 use util::test::sample_text;
3858
3859 #[gpui::test]
3860 fn test_singleton(cx: &mut AppContext) {
3861 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
3862 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
3863
3864 let snapshot = multibuffer.read(cx).snapshot(cx);
3865 assert_eq!(snapshot.text(), buffer.read(cx).text());
3866
3867 assert_eq!(
3868 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3869 (0..buffer.read(cx).row_count())
3870 .map(Some)
3871 .collect::<Vec<_>>()
3872 );
3873
3874 buffer.update(cx, |buffer, cx| buffer.edit([(1..3, "XXX\n")], None, cx));
3875 let snapshot = multibuffer.read(cx).snapshot(cx);
3876
3877 assert_eq!(snapshot.text(), buffer.read(cx).text());
3878 assert_eq!(
3879 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3880 (0..buffer.read(cx).row_count())
3881 .map(Some)
3882 .collect::<Vec<_>>()
3883 );
3884 }
3885
3886 #[gpui::test]
3887 fn test_remote(cx: &mut AppContext) {
3888 let host_buffer = cx.add_model(|cx| Buffer::new(0, "a", cx));
3889 let guest_buffer = cx.add_model(|cx| {
3890 let state = host_buffer.read(cx).to_proto();
3891 let ops = cx
3892 .background()
3893 .block(host_buffer.read(cx).serialize_ops(None, cx));
3894 let mut buffer = Buffer::from_proto(1, state, None).unwrap();
3895 buffer
3896 .apply_ops(
3897 ops.into_iter()
3898 .map(|op| language::proto::deserialize_operation(op).unwrap()),
3899 cx,
3900 )
3901 .unwrap();
3902 buffer
3903 });
3904 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(guest_buffer.clone(), cx));
3905 let snapshot = multibuffer.read(cx).snapshot(cx);
3906 assert_eq!(snapshot.text(), "a");
3907
3908 guest_buffer.update(cx, |buffer, cx| buffer.edit([(1..1, "b")], None, cx));
3909 let snapshot = multibuffer.read(cx).snapshot(cx);
3910 assert_eq!(snapshot.text(), "ab");
3911
3912 guest_buffer.update(cx, |buffer, cx| buffer.edit([(2..2, "c")], None, cx));
3913 let snapshot = multibuffer.read(cx).snapshot(cx);
3914 assert_eq!(snapshot.text(), "abc");
3915 }
3916
3917 #[gpui::test]
3918 fn test_excerpt_boundaries_and_clipping(cx: &mut AppContext) {
3919 let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
3920 let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
3921 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3922
3923 let events = Rc::new(RefCell::new(Vec::<Event>::new()));
3924 multibuffer.update(cx, |_, cx| {
3925 let events = events.clone();
3926 cx.subscribe(&multibuffer, move |_, _, event, _| {
3927 if let Event::Edited = event {
3928 events.borrow_mut().push(event.clone())
3929 }
3930 })
3931 .detach();
3932 });
3933
3934 let subscription = multibuffer.update(cx, |multibuffer, cx| {
3935 let subscription = multibuffer.subscribe();
3936 multibuffer.push_excerpts(
3937 buffer_1.clone(),
3938 [ExcerptRange {
3939 context: Point::new(1, 2)..Point::new(2, 5),
3940 primary: None,
3941 }],
3942 cx,
3943 );
3944 assert_eq!(
3945 subscription.consume().into_inner(),
3946 [Edit {
3947 old: 0..0,
3948 new: 0..10
3949 }]
3950 );
3951
3952 multibuffer.push_excerpts(
3953 buffer_1.clone(),
3954 [ExcerptRange {
3955 context: Point::new(3, 3)..Point::new(4, 4),
3956 primary: None,
3957 }],
3958 cx,
3959 );
3960 multibuffer.push_excerpts(
3961 buffer_2.clone(),
3962 [ExcerptRange {
3963 context: Point::new(3, 1)..Point::new(3, 3),
3964 primary: None,
3965 }],
3966 cx,
3967 );
3968 assert_eq!(
3969 subscription.consume().into_inner(),
3970 [Edit {
3971 old: 10..10,
3972 new: 10..22
3973 }]
3974 );
3975
3976 subscription
3977 });
3978
3979 // Adding excerpts emits an edited event.
3980 assert_eq!(
3981 events.borrow().as_slice(),
3982 &[Event::Edited, Event::Edited, Event::Edited]
3983 );
3984
3985 let snapshot = multibuffer.read(cx).snapshot(cx);
3986 assert_eq!(
3987 snapshot.text(),
3988 concat!(
3989 "bbbb\n", // Preserve newlines
3990 "ccccc\n", //
3991 "ddd\n", //
3992 "eeee\n", //
3993 "jj" //
3994 )
3995 );
3996 assert_eq!(
3997 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3998 [Some(1), Some(2), Some(3), Some(4), Some(3)]
3999 );
4000 assert_eq!(
4001 snapshot.buffer_rows(2).collect::<Vec<_>>(),
4002 [Some(3), Some(4), Some(3)]
4003 );
4004 assert_eq!(snapshot.buffer_rows(4).collect::<Vec<_>>(), [Some(3)]);
4005 assert_eq!(snapshot.buffer_rows(5).collect::<Vec<_>>(), []);
4006
4007 assert_eq!(
4008 boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot),
4009 &[
4010 (0, "bbbb\nccccc".to_string(), true),
4011 (2, "ddd\neeee".to_string(), false),
4012 (4, "jj".to_string(), true),
4013 ]
4014 );
4015 assert_eq!(
4016 boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot),
4017 &[(0, "bbbb\nccccc".to_string(), true)]
4018 );
4019 assert_eq!(
4020 boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot),
4021 &[]
4022 );
4023 assert_eq!(
4024 boundaries_in_range(Point::new(1, 0)..Point::new(2, 0), &snapshot),
4025 &[]
4026 );
4027 assert_eq!(
4028 boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
4029 &[(2, "ddd\neeee".to_string(), false)]
4030 );
4031 assert_eq!(
4032 boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
4033 &[(2, "ddd\neeee".to_string(), false)]
4034 );
4035 assert_eq!(
4036 boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot),
4037 &[(2, "ddd\neeee".to_string(), false)]
4038 );
4039 assert_eq!(
4040 boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot),
4041 &[(4, "jj".to_string(), true)]
4042 );
4043 assert_eq!(
4044 boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot),
4045 &[]
4046 );
4047
4048 buffer_1.update(cx, |buffer, cx| {
4049 let text = "\n";
4050 buffer.edit(
4051 [
4052 (Point::new(0, 0)..Point::new(0, 0), text),
4053 (Point::new(2, 1)..Point::new(2, 3), text),
4054 ],
4055 None,
4056 cx,
4057 );
4058 });
4059
4060 let snapshot = multibuffer.read(cx).snapshot(cx);
4061 assert_eq!(
4062 snapshot.text(),
4063 concat!(
4064 "bbbb\n", // Preserve newlines
4065 "c\n", //
4066 "cc\n", //
4067 "ddd\n", //
4068 "eeee\n", //
4069 "jj" //
4070 )
4071 );
4072
4073 assert_eq!(
4074 subscription.consume().into_inner(),
4075 [Edit {
4076 old: 6..8,
4077 new: 6..7
4078 }]
4079 );
4080
4081 let snapshot = multibuffer.read(cx).snapshot(cx);
4082 assert_eq!(
4083 snapshot.clip_point(Point::new(0, 5), Bias::Left),
4084 Point::new(0, 4)
4085 );
4086 assert_eq!(
4087 snapshot.clip_point(Point::new(0, 5), Bias::Right),
4088 Point::new(0, 4)
4089 );
4090 assert_eq!(
4091 snapshot.clip_point(Point::new(5, 1), Bias::Right),
4092 Point::new(5, 1)
4093 );
4094 assert_eq!(
4095 snapshot.clip_point(Point::new(5, 2), Bias::Right),
4096 Point::new(5, 2)
4097 );
4098 assert_eq!(
4099 snapshot.clip_point(Point::new(5, 3), Bias::Right),
4100 Point::new(5, 2)
4101 );
4102
4103 let snapshot = multibuffer.update(cx, |multibuffer, cx| {
4104 let (buffer_2_excerpt_id, _) =
4105 multibuffer.excerpts_for_buffer(&buffer_2, cx)[0].clone();
4106 multibuffer.remove_excerpts([buffer_2_excerpt_id], cx);
4107 multibuffer.snapshot(cx)
4108 });
4109
4110 assert_eq!(
4111 snapshot.text(),
4112 concat!(
4113 "bbbb\n", // Preserve newlines
4114 "c\n", //
4115 "cc\n", //
4116 "ddd\n", //
4117 "eeee", //
4118 )
4119 );
4120
4121 fn boundaries_in_range(
4122 range: Range<Point>,
4123 snapshot: &MultiBufferSnapshot,
4124 ) -> Vec<(u32, String, bool)> {
4125 snapshot
4126 .excerpt_boundaries_in_range(range)
4127 .map(|boundary| {
4128 (
4129 boundary.row,
4130 boundary
4131 .buffer
4132 .text_for_range(boundary.range.context)
4133 .collect::<String>(),
4134 boundary.starts_new_buffer,
4135 )
4136 })
4137 .collect::<Vec<_>>()
4138 }
4139 }
4140
4141 #[gpui::test]
4142 fn test_excerpt_events(cx: &mut AppContext) {
4143 let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(10, 3, 'a'), cx));
4144 let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(10, 3, 'm'), cx));
4145
4146 let leader_multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4147 let follower_multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4148 let follower_edit_event_count = Rc::new(RefCell::new(0));
4149
4150 follower_multibuffer.update(cx, |_, cx| {
4151 let follower_edit_event_count = follower_edit_event_count.clone();
4152 cx.subscribe(
4153 &leader_multibuffer,
4154 move |follower, _, event, cx| match event.clone() {
4155 Event::ExcerptsAdded {
4156 buffer,
4157 predecessor,
4158 excerpts,
4159 } => follower.insert_excerpts_with_ids_after(predecessor, buffer, excerpts, cx),
4160 Event::ExcerptsRemoved { ids } => follower.remove_excerpts(ids, cx),
4161 Event::Edited => {
4162 *follower_edit_event_count.borrow_mut() += 1;
4163 }
4164 _ => {}
4165 },
4166 )
4167 .detach();
4168 });
4169
4170 leader_multibuffer.update(cx, |leader, cx| {
4171 leader.push_excerpts(
4172 buffer_1.clone(),
4173 [
4174 ExcerptRange {
4175 context: 0..8,
4176 primary: None,
4177 },
4178 ExcerptRange {
4179 context: 12..16,
4180 primary: None,
4181 },
4182 ],
4183 cx,
4184 );
4185 leader.insert_excerpts_after(
4186 leader.excerpt_ids()[0],
4187 buffer_2.clone(),
4188 [
4189 ExcerptRange {
4190 context: 0..5,
4191 primary: None,
4192 },
4193 ExcerptRange {
4194 context: 10..15,
4195 primary: None,
4196 },
4197 ],
4198 cx,
4199 )
4200 });
4201 assert_eq!(
4202 leader_multibuffer.read(cx).snapshot(cx).text(),
4203 follower_multibuffer.read(cx).snapshot(cx).text(),
4204 );
4205 assert_eq!(*follower_edit_event_count.borrow(), 2);
4206
4207 leader_multibuffer.update(cx, |leader, cx| {
4208 let excerpt_ids = leader.excerpt_ids();
4209 leader.remove_excerpts([excerpt_ids[1], excerpt_ids[3]], cx);
4210 });
4211 assert_eq!(
4212 leader_multibuffer.read(cx).snapshot(cx).text(),
4213 follower_multibuffer.read(cx).snapshot(cx).text(),
4214 );
4215 assert_eq!(*follower_edit_event_count.borrow(), 3);
4216
4217 // Removing an empty set of excerpts is a noop.
4218 leader_multibuffer.update(cx, |leader, cx| {
4219 leader.remove_excerpts([], cx);
4220 });
4221 assert_eq!(
4222 leader_multibuffer.read(cx).snapshot(cx).text(),
4223 follower_multibuffer.read(cx).snapshot(cx).text(),
4224 );
4225 assert_eq!(*follower_edit_event_count.borrow(), 3);
4226
4227 // Adding an empty set of excerpts is a noop.
4228 leader_multibuffer.update(cx, |leader, cx| {
4229 leader.push_excerpts::<usize>(buffer_2.clone(), [], cx);
4230 });
4231 assert_eq!(
4232 leader_multibuffer.read(cx).snapshot(cx).text(),
4233 follower_multibuffer.read(cx).snapshot(cx).text(),
4234 );
4235 assert_eq!(*follower_edit_event_count.borrow(), 3);
4236
4237 leader_multibuffer.update(cx, |leader, cx| {
4238 leader.clear(cx);
4239 });
4240 assert_eq!(
4241 leader_multibuffer.read(cx).snapshot(cx).text(),
4242 follower_multibuffer.read(cx).snapshot(cx).text(),
4243 );
4244 assert_eq!(*follower_edit_event_count.borrow(), 4);
4245 }
4246
4247 #[gpui::test]
4248 fn test_push_excerpts_with_context_lines(cx: &mut AppContext) {
4249 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(20, 3, 'a'), cx));
4250 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4251 let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
4252 multibuffer.push_excerpts_with_context_lines(
4253 buffer.clone(),
4254 vec![
4255 Point::new(3, 2)..Point::new(4, 2),
4256 Point::new(7, 1)..Point::new(7, 3),
4257 Point::new(15, 0)..Point::new(15, 0),
4258 ],
4259 2,
4260 cx,
4261 )
4262 });
4263
4264 let snapshot = multibuffer.read(cx).snapshot(cx);
4265 assert_eq!(
4266 snapshot.text(),
4267 "bbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\n\nnnn\nooo\nppp\nqqq\nrrr\n"
4268 );
4269
4270 assert_eq!(
4271 anchor_ranges
4272 .iter()
4273 .map(|range| range.to_point(&snapshot))
4274 .collect::<Vec<_>>(),
4275 vec![
4276 Point::new(2, 2)..Point::new(3, 2),
4277 Point::new(6, 1)..Point::new(6, 3),
4278 Point::new(12, 0)..Point::new(12, 0)
4279 ]
4280 );
4281 }
4282
4283 #[gpui::test]
4284 async fn test_stream_excerpts_with_context_lines(cx: &mut TestAppContext) {
4285 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(20, 3, 'a'), cx));
4286 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4287 let (task, anchor_ranges) = multibuffer.update(cx, |multibuffer, cx| {
4288 let snapshot = buffer.read(cx);
4289 let ranges = vec![
4290 snapshot.anchor_before(Point::new(3, 2))..snapshot.anchor_before(Point::new(4, 2)),
4291 snapshot.anchor_before(Point::new(7, 1))..snapshot.anchor_before(Point::new(7, 3)),
4292 snapshot.anchor_before(Point::new(15, 0))
4293 ..snapshot.anchor_before(Point::new(15, 0)),
4294 ];
4295 multibuffer.stream_excerpts_with_context_lines(vec![(buffer.clone(), ranges)], 2, cx)
4296 });
4297
4298 let anchor_ranges = anchor_ranges.collect::<Vec<_>>().await;
4299 // Ensure task is finished when stream completes.
4300 task.await;
4301
4302 let snapshot = multibuffer.read_with(cx, |multibuffer, cx| multibuffer.snapshot(cx));
4303 assert_eq!(
4304 snapshot.text(),
4305 "bbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\n\nnnn\nooo\nppp\nqqq\nrrr\n"
4306 );
4307
4308 assert_eq!(
4309 anchor_ranges
4310 .iter()
4311 .map(|range| range.to_point(&snapshot))
4312 .collect::<Vec<_>>(),
4313 vec![
4314 Point::new(2, 2)..Point::new(3, 2),
4315 Point::new(6, 1)..Point::new(6, 3),
4316 Point::new(12, 0)..Point::new(12, 0)
4317 ]
4318 );
4319 }
4320
4321 #[gpui::test]
4322 fn test_empty_multibuffer(cx: &mut AppContext) {
4323 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4324
4325 let snapshot = multibuffer.read(cx).snapshot(cx);
4326 assert_eq!(snapshot.text(), "");
4327 assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), &[Some(0)]);
4328 assert_eq!(snapshot.buffer_rows(1).collect::<Vec<_>>(), &[]);
4329 }
4330
4331 #[gpui::test]
4332 fn test_singleton_multibuffer_anchors(cx: &mut AppContext) {
4333 let buffer = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
4334 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
4335 let old_snapshot = multibuffer.read(cx).snapshot(cx);
4336 buffer.update(cx, |buffer, cx| {
4337 buffer.edit([(0..0, "X")], None, cx);
4338 buffer.edit([(5..5, "Y")], None, cx);
4339 });
4340 let new_snapshot = multibuffer.read(cx).snapshot(cx);
4341
4342 assert_eq!(old_snapshot.text(), "abcd");
4343 assert_eq!(new_snapshot.text(), "XabcdY");
4344
4345 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
4346 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
4347 assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
4348 assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
4349 }
4350
4351 #[gpui::test]
4352 fn test_multibuffer_anchors(cx: &mut AppContext) {
4353 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
4354 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
4355 let multibuffer = cx.add_model(|cx| {
4356 let mut multibuffer = MultiBuffer::new(0);
4357 multibuffer.push_excerpts(
4358 buffer_1.clone(),
4359 [ExcerptRange {
4360 context: 0..4,
4361 primary: None,
4362 }],
4363 cx,
4364 );
4365 multibuffer.push_excerpts(
4366 buffer_2.clone(),
4367 [ExcerptRange {
4368 context: 0..5,
4369 primary: None,
4370 }],
4371 cx,
4372 );
4373 multibuffer
4374 });
4375 let old_snapshot = multibuffer.read(cx).snapshot(cx);
4376
4377 assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
4378 assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
4379 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
4380 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
4381 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
4382 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
4383
4384 buffer_1.update(cx, |buffer, cx| {
4385 buffer.edit([(0..0, "W")], None, cx);
4386 buffer.edit([(5..5, "X")], None, cx);
4387 });
4388 buffer_2.update(cx, |buffer, cx| {
4389 buffer.edit([(0..0, "Y")], None, cx);
4390 buffer.edit([(6..6, "Z")], None, cx);
4391 });
4392 let new_snapshot = multibuffer.read(cx).snapshot(cx);
4393
4394 assert_eq!(old_snapshot.text(), "abcd\nefghi");
4395 assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
4396
4397 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
4398 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
4399 assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
4400 assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
4401 assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
4402 assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
4403 assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
4404 assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
4405 assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
4406 assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
4407 }
4408
4409 #[gpui::test]
4410 fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut AppContext) {
4411 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
4412 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "ABCDEFGHIJKLMNOP", cx));
4413 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4414
4415 // Create an insertion id in buffer 1 that doesn't exist in buffer 2.
4416 // Add an excerpt from buffer 1 that spans this new insertion.
4417 buffer_1.update(cx, |buffer, cx| buffer.edit([(4..4, "123")], None, cx));
4418 let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| {
4419 multibuffer
4420 .push_excerpts(
4421 buffer_1.clone(),
4422 [ExcerptRange {
4423 context: 0..7,
4424 primary: None,
4425 }],
4426 cx,
4427 )
4428 .pop()
4429 .unwrap()
4430 });
4431
4432 let snapshot_1 = multibuffer.read(cx).snapshot(cx);
4433 assert_eq!(snapshot_1.text(), "abcd123");
4434
4435 // Replace the buffer 1 excerpt with new excerpts from buffer 2.
4436 let (excerpt_id_2, excerpt_id_3) = multibuffer.update(cx, |multibuffer, cx| {
4437 multibuffer.remove_excerpts([excerpt_id_1], cx);
4438 let mut ids = multibuffer
4439 .push_excerpts(
4440 buffer_2.clone(),
4441 [
4442 ExcerptRange {
4443 context: 0..4,
4444 primary: None,
4445 },
4446 ExcerptRange {
4447 context: 6..10,
4448 primary: None,
4449 },
4450 ExcerptRange {
4451 context: 12..16,
4452 primary: None,
4453 },
4454 ],
4455 cx,
4456 )
4457 .into_iter();
4458 (ids.next().unwrap(), ids.next().unwrap())
4459 });
4460 let snapshot_2 = multibuffer.read(cx).snapshot(cx);
4461 assert_eq!(snapshot_2.text(), "ABCD\nGHIJ\nMNOP");
4462
4463 // The old excerpt id doesn't get reused.
4464 assert_ne!(excerpt_id_2, excerpt_id_1);
4465
4466 // Resolve some anchors from the previous snapshot in the new snapshot.
4467 // The current excerpts are from a different buffer, so we don't attempt to
4468 // resolve the old text anchor in the new buffer.
4469 assert_eq!(
4470 snapshot_2.summary_for_anchor::<usize>(&snapshot_1.anchor_before(2)),
4471 0
4472 );
4473 assert_eq!(
4474 snapshot_2.summaries_for_anchors::<usize, _>(&[
4475 snapshot_1.anchor_before(2),
4476 snapshot_1.anchor_after(3)
4477 ]),
4478 vec![0, 0]
4479 );
4480
4481 // Refresh anchors from the old snapshot. The return value indicates that both
4482 // anchors lost their original excerpt.
4483 let refresh =
4484 snapshot_2.refresh_anchors(&[snapshot_1.anchor_before(2), snapshot_1.anchor_after(3)]);
4485 assert_eq!(
4486 refresh,
4487 &[
4488 (0, snapshot_2.anchor_before(0), false),
4489 (1, snapshot_2.anchor_after(0), false),
4490 ]
4491 );
4492
4493 // Replace the middle excerpt with a smaller excerpt in buffer 2,
4494 // that intersects the old excerpt.
4495 let excerpt_id_5 = multibuffer.update(cx, |multibuffer, cx| {
4496 multibuffer.remove_excerpts([excerpt_id_3], cx);
4497 multibuffer
4498 .insert_excerpts_after(
4499 excerpt_id_2,
4500 buffer_2.clone(),
4501 [ExcerptRange {
4502 context: 5..8,
4503 primary: None,
4504 }],
4505 cx,
4506 )
4507 .pop()
4508 .unwrap()
4509 });
4510
4511 let snapshot_3 = multibuffer.read(cx).snapshot(cx);
4512 assert_eq!(snapshot_3.text(), "ABCD\nFGH\nMNOP");
4513 assert_ne!(excerpt_id_5, excerpt_id_3);
4514
4515 // Resolve some anchors from the previous snapshot in the new snapshot.
4516 // The third anchor can't be resolved, since its excerpt has been removed,
4517 // so it resolves to the same position as its predecessor.
4518 let anchors = [
4519 snapshot_2.anchor_before(0),
4520 snapshot_2.anchor_after(2),
4521 snapshot_2.anchor_after(6),
4522 snapshot_2.anchor_after(14),
4523 ];
4524 assert_eq!(
4525 snapshot_3.summaries_for_anchors::<usize, _>(&anchors),
4526 &[0, 2, 9, 13]
4527 );
4528
4529 let new_anchors = snapshot_3.refresh_anchors(&anchors);
4530 assert_eq!(
4531 new_anchors.iter().map(|a| (a.0, a.2)).collect::<Vec<_>>(),
4532 &[(0, true), (1, true), (2, true), (3, true)]
4533 );
4534 assert_eq!(
4535 snapshot_3.summaries_for_anchors::<usize, _>(new_anchors.iter().map(|a| &a.1)),
4536 &[0, 2, 7, 13]
4537 );
4538 }
4539
4540 #[gpui::test]
4541 async fn test_diff_hunks_in_range(cx: &mut TestAppContext) {
4542 use git::diff::DiffHunkStatus;
4543
4544 // buffer has two modified hunks with two rows each
4545 let buffer_1 = cx.add_model(|cx| {
4546 let mut buffer = Buffer::new(
4547 0,
4548 "
4549 1.zero
4550 1.ONE
4551 1.TWO
4552 1.three
4553 1.FOUR
4554 1.FIVE
4555 1.six
4556 "
4557 .unindent(),
4558 cx,
4559 );
4560 buffer.set_diff_base(
4561 Some(
4562 "
4563 1.zero
4564 1.one
4565 1.two
4566 1.three
4567 1.four
4568 1.five
4569 1.six
4570 "
4571 .unindent(),
4572 ),
4573 cx,
4574 );
4575 buffer
4576 });
4577
4578 // buffer has a deletion hunk and an insertion hunk
4579 let buffer_2 = cx.add_model(|cx| {
4580 let mut buffer = Buffer::new(
4581 0,
4582 "
4583 2.zero
4584 2.one
4585 2.two
4586 2.three
4587 2.four
4588 2.five
4589 2.six
4590 "
4591 .unindent(),
4592 cx,
4593 );
4594 buffer.set_diff_base(
4595 Some(
4596 "
4597 2.zero
4598 2.one
4599 2.one-and-a-half
4600 2.two
4601 2.three
4602 2.four
4603 2.six
4604 "
4605 .unindent(),
4606 ),
4607 cx,
4608 );
4609 buffer
4610 });
4611
4612 cx.foreground().run_until_parked();
4613
4614 let multibuffer = cx.add_model(|cx| {
4615 let mut multibuffer = MultiBuffer::new(0);
4616 multibuffer.push_excerpts(
4617 buffer_1.clone(),
4618 [
4619 // excerpt ends in the middle of a modified hunk
4620 ExcerptRange {
4621 context: Point::new(0, 0)..Point::new(1, 5),
4622 primary: Default::default(),
4623 },
4624 // excerpt begins in the middle of a modified hunk
4625 ExcerptRange {
4626 context: Point::new(5, 0)..Point::new(6, 5),
4627 primary: Default::default(),
4628 },
4629 ],
4630 cx,
4631 );
4632 multibuffer.push_excerpts(
4633 buffer_2.clone(),
4634 [
4635 // excerpt ends at a deletion
4636 ExcerptRange {
4637 context: Point::new(0, 0)..Point::new(1, 5),
4638 primary: Default::default(),
4639 },
4640 // excerpt starts at a deletion
4641 ExcerptRange {
4642 context: Point::new(2, 0)..Point::new(2, 5),
4643 primary: Default::default(),
4644 },
4645 // excerpt fully contains a deletion hunk
4646 ExcerptRange {
4647 context: Point::new(1, 0)..Point::new(2, 5),
4648 primary: Default::default(),
4649 },
4650 // excerpt fully contains an insertion hunk
4651 ExcerptRange {
4652 context: Point::new(4, 0)..Point::new(6, 5),
4653 primary: Default::default(),
4654 },
4655 ],
4656 cx,
4657 );
4658 multibuffer
4659 });
4660
4661 let snapshot = multibuffer.read_with(cx, |b, cx| b.snapshot(cx));
4662
4663 assert_eq!(
4664 snapshot.text(),
4665 "
4666 1.zero
4667 1.ONE
4668 1.FIVE
4669 1.six
4670 2.zero
4671 2.one
4672 2.two
4673 2.one
4674 2.two
4675 2.four
4676 2.five
4677 2.six"
4678 .unindent()
4679 );
4680
4681 let expected = [
4682 (DiffHunkStatus::Modified, 1..2),
4683 (DiffHunkStatus::Modified, 2..3),
4684 //TODO: Define better when and where removed hunks show up at range extremities
4685 (DiffHunkStatus::Removed, 6..6),
4686 (DiffHunkStatus::Removed, 8..8),
4687 (DiffHunkStatus::Added, 10..11),
4688 ];
4689
4690 assert_eq!(
4691 snapshot
4692 .git_diff_hunks_in_range(0..12)
4693 .map(|hunk| (hunk.status(), hunk.buffer_range))
4694 .collect::<Vec<_>>(),
4695 &expected,
4696 );
4697
4698 assert_eq!(
4699 snapshot
4700 .git_diff_hunks_in_range_rev(0..12)
4701 .map(|hunk| (hunk.status(), hunk.buffer_range))
4702 .collect::<Vec<_>>(),
4703 expected
4704 .iter()
4705 .rev()
4706 .cloned()
4707 .collect::<Vec<_>>()
4708 .as_slice(),
4709 );
4710 }
4711
4712 #[gpui::test(iterations = 100)]
4713 fn test_random_multibuffer(cx: &mut AppContext, mut rng: StdRng) {
4714 let operations = env::var("OPERATIONS")
4715 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
4716 .unwrap_or(10);
4717
4718 let mut buffers: Vec<ModelHandle<Buffer>> = Vec::new();
4719 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4720 let mut excerpt_ids = Vec::<ExcerptId>::new();
4721 let mut expected_excerpts = Vec::<(ModelHandle<Buffer>, Range<text::Anchor>)>::new();
4722 let mut anchors = Vec::new();
4723 let mut old_versions = Vec::new();
4724
4725 for _ in 0..operations {
4726 match rng.gen_range(0..100) {
4727 0..=19 if !buffers.is_empty() => {
4728 let buffer = buffers.choose(&mut rng).unwrap();
4729 buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
4730 }
4731 20..=29 if !expected_excerpts.is_empty() => {
4732 let mut ids_to_remove = vec![];
4733 for _ in 0..rng.gen_range(1..=3) {
4734 if expected_excerpts.is_empty() {
4735 break;
4736 }
4737
4738 let ix = rng.gen_range(0..expected_excerpts.len());
4739 ids_to_remove.push(excerpt_ids.remove(ix));
4740 let (buffer, range) = expected_excerpts.remove(ix);
4741 let buffer = buffer.read(cx);
4742 log::info!(
4743 "Removing excerpt {}: {:?}",
4744 ix,
4745 buffer
4746 .text_for_range(range.to_offset(buffer))
4747 .collect::<String>(),
4748 );
4749 }
4750 let snapshot = multibuffer.read(cx).read(cx);
4751 ids_to_remove.sort_unstable_by(|a, b| a.cmp(&b, &snapshot));
4752 drop(snapshot);
4753 multibuffer.update(cx, |multibuffer, cx| {
4754 multibuffer.remove_excerpts(ids_to_remove, cx)
4755 });
4756 }
4757 30..=39 if !expected_excerpts.is_empty() => {
4758 let multibuffer = multibuffer.read(cx).read(cx);
4759 let offset =
4760 multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left);
4761 let bias = if rng.gen() { Bias::Left } else { Bias::Right };
4762 log::info!("Creating anchor at {} with bias {:?}", offset, bias);
4763 anchors.push(multibuffer.anchor_at(offset, bias));
4764 anchors.sort_by(|a, b| a.cmp(b, &multibuffer));
4765 }
4766 40..=44 if !anchors.is_empty() => {
4767 let multibuffer = multibuffer.read(cx).read(cx);
4768 let prev_len = anchors.len();
4769 anchors = multibuffer
4770 .refresh_anchors(&anchors)
4771 .into_iter()
4772 .map(|a| a.1)
4773 .collect();
4774
4775 // Ensure the newly-refreshed anchors point to a valid excerpt and don't
4776 // overshoot its boundaries.
4777 assert_eq!(anchors.len(), prev_len);
4778 for anchor in &anchors {
4779 if anchor.excerpt_id == ExcerptId::min()
4780 || anchor.excerpt_id == ExcerptId::max()
4781 {
4782 continue;
4783 }
4784
4785 let excerpt = multibuffer.excerpt(anchor.excerpt_id).unwrap();
4786 assert_eq!(excerpt.id, anchor.excerpt_id);
4787 assert!(excerpt.contains(anchor));
4788 }
4789 }
4790 _ => {
4791 let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
4792 let base_text = util::RandomCharIter::new(&mut rng)
4793 .take(10)
4794 .collect::<String>();
4795 buffers.push(cx.add_model(|cx| Buffer::new(0, base_text, cx)));
4796 buffers.last().unwrap()
4797 } else {
4798 buffers.choose(&mut rng).unwrap()
4799 };
4800
4801 let buffer = buffer_handle.read(cx);
4802 let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
4803 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
4804 let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
4805 let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len());
4806 let prev_excerpt_id = excerpt_ids
4807 .get(prev_excerpt_ix)
4808 .cloned()
4809 .unwrap_or_else(ExcerptId::max);
4810 let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len());
4811
4812 log::info!(
4813 "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}",
4814 excerpt_ix,
4815 expected_excerpts.len(),
4816 buffer_handle.read(cx).remote_id(),
4817 buffer.text(),
4818 start_ix..end_ix,
4819 &buffer.text()[start_ix..end_ix]
4820 );
4821
4822 let excerpt_id = multibuffer.update(cx, |multibuffer, cx| {
4823 multibuffer
4824 .insert_excerpts_after(
4825 prev_excerpt_id,
4826 buffer_handle.clone(),
4827 [ExcerptRange {
4828 context: start_ix..end_ix,
4829 primary: None,
4830 }],
4831 cx,
4832 )
4833 .pop()
4834 .unwrap()
4835 });
4836
4837 excerpt_ids.insert(excerpt_ix, excerpt_id);
4838 expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range));
4839 }
4840 }
4841
4842 if rng.gen_bool(0.3) {
4843 multibuffer.update(cx, |multibuffer, cx| {
4844 old_versions.push((multibuffer.snapshot(cx), multibuffer.subscribe()));
4845 })
4846 }
4847
4848 let snapshot = multibuffer.read(cx).snapshot(cx);
4849
4850 let mut excerpt_starts = Vec::new();
4851 let mut expected_text = String::new();
4852 let mut expected_buffer_rows = Vec::new();
4853 for (buffer, range) in &expected_excerpts {
4854 let buffer = buffer.read(cx);
4855 let buffer_range = range.to_offset(buffer);
4856
4857 excerpt_starts.push(TextSummary::from(expected_text.as_str()));
4858 expected_text.extend(buffer.text_for_range(buffer_range.clone()));
4859 expected_text.push('\n');
4860
4861 let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
4862 ..=buffer.offset_to_point(buffer_range.end).row;
4863 for row in buffer_row_range {
4864 expected_buffer_rows.push(Some(row));
4865 }
4866 }
4867 // Remove final trailing newline.
4868 if !expected_excerpts.is_empty() {
4869 expected_text.pop();
4870 }
4871
4872 // Always report one buffer row
4873 if expected_buffer_rows.is_empty() {
4874 expected_buffer_rows.push(Some(0));
4875 }
4876
4877 assert_eq!(snapshot.text(), expected_text);
4878 log::info!("MultiBuffer text: {:?}", expected_text);
4879
4880 assert_eq!(
4881 snapshot.buffer_rows(0).collect::<Vec<_>>(),
4882 expected_buffer_rows,
4883 );
4884
4885 for _ in 0..5 {
4886 let start_row = rng.gen_range(0..=expected_buffer_rows.len());
4887 assert_eq!(
4888 snapshot.buffer_rows(start_row as u32).collect::<Vec<_>>(),
4889 &expected_buffer_rows[start_row..],
4890 "buffer_rows({})",
4891 start_row
4892 );
4893 }
4894
4895 assert_eq!(
4896 snapshot.max_buffer_row(),
4897 expected_buffer_rows.into_iter().flatten().max().unwrap()
4898 );
4899
4900 let mut excerpt_starts = excerpt_starts.into_iter();
4901 for (buffer, range) in &expected_excerpts {
4902 let buffer = buffer.read(cx);
4903 let buffer_id = buffer.remote_id();
4904 let buffer_range = range.to_offset(buffer);
4905 let buffer_start_point = buffer.offset_to_point(buffer_range.start);
4906 let buffer_start_point_utf16 =
4907 buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
4908
4909 let excerpt_start = excerpt_starts.next().unwrap();
4910 let mut offset = excerpt_start.len;
4911 let mut buffer_offset = buffer_range.start;
4912 let mut point = excerpt_start.lines;
4913 let mut buffer_point = buffer_start_point;
4914 let mut point_utf16 = excerpt_start.lines_utf16();
4915 let mut buffer_point_utf16 = buffer_start_point_utf16;
4916 for ch in buffer
4917 .snapshot()
4918 .chunks(buffer_range.clone(), false)
4919 .flat_map(|c| c.text.chars())
4920 {
4921 for _ in 0..ch.len_utf8() {
4922 let left_offset = snapshot.clip_offset(offset, Bias::Left);
4923 let right_offset = snapshot.clip_offset(offset, Bias::Right);
4924 let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
4925 let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
4926 assert_eq!(
4927 left_offset,
4928 excerpt_start.len + (buffer_left_offset - buffer_range.start),
4929 "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
4930 offset,
4931 buffer_id,
4932 buffer_offset,
4933 );
4934 assert_eq!(
4935 right_offset,
4936 excerpt_start.len + (buffer_right_offset - buffer_range.start),
4937 "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
4938 offset,
4939 buffer_id,
4940 buffer_offset,
4941 );
4942
4943 let left_point = snapshot.clip_point(point, Bias::Left);
4944 let right_point = snapshot.clip_point(point, Bias::Right);
4945 let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
4946 let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
4947 assert_eq!(
4948 left_point,
4949 excerpt_start.lines + (buffer_left_point - buffer_start_point),
4950 "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
4951 point,
4952 buffer_id,
4953 buffer_point,
4954 );
4955 assert_eq!(
4956 right_point,
4957 excerpt_start.lines + (buffer_right_point - buffer_start_point),
4958 "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
4959 point,
4960 buffer_id,
4961 buffer_point,
4962 );
4963
4964 assert_eq!(
4965 snapshot.point_to_offset(left_point),
4966 left_offset,
4967 "point_to_offset({:?})",
4968 left_point,
4969 );
4970 assert_eq!(
4971 snapshot.offset_to_point(left_offset),
4972 left_point,
4973 "offset_to_point({:?})",
4974 left_offset,
4975 );
4976
4977 offset += 1;
4978 buffer_offset += 1;
4979 if ch == '\n' {
4980 point += Point::new(1, 0);
4981 buffer_point += Point::new(1, 0);
4982 } else {
4983 point += Point::new(0, 1);
4984 buffer_point += Point::new(0, 1);
4985 }
4986 }
4987
4988 for _ in 0..ch.len_utf16() {
4989 let left_point_utf16 =
4990 snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Left);
4991 let right_point_utf16 =
4992 snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Right);
4993 let buffer_left_point_utf16 =
4994 buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Left);
4995 let buffer_right_point_utf16 =
4996 buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Right);
4997 assert_eq!(
4998 left_point_utf16,
4999 excerpt_start.lines_utf16()
5000 + (buffer_left_point_utf16 - buffer_start_point_utf16),
5001 "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
5002 point_utf16,
5003 buffer_id,
5004 buffer_point_utf16,
5005 );
5006 assert_eq!(
5007 right_point_utf16,
5008 excerpt_start.lines_utf16()
5009 + (buffer_right_point_utf16 - buffer_start_point_utf16),
5010 "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
5011 point_utf16,
5012 buffer_id,
5013 buffer_point_utf16,
5014 );
5015
5016 if ch == '\n' {
5017 point_utf16 += PointUtf16::new(1, 0);
5018 buffer_point_utf16 += PointUtf16::new(1, 0);
5019 } else {
5020 point_utf16 += PointUtf16::new(0, 1);
5021 buffer_point_utf16 += PointUtf16::new(0, 1);
5022 }
5023 }
5024 }
5025 }
5026
5027 for (row, line) in expected_text.split('\n').enumerate() {
5028 assert_eq!(
5029 snapshot.line_len(row as u32),
5030 line.len() as u32,
5031 "line_len({}).",
5032 row
5033 );
5034 }
5035
5036 let text_rope = Rope::from(expected_text.as_str());
5037 for _ in 0..10 {
5038 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
5039 let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
5040
5041 let text_for_range = snapshot
5042 .text_for_range(start_ix..end_ix)
5043 .collect::<String>();
5044 assert_eq!(
5045 text_for_range,
5046 &expected_text[start_ix..end_ix],
5047 "incorrect text for range {:?}",
5048 start_ix..end_ix
5049 );
5050
5051 let excerpted_buffer_ranges = multibuffer
5052 .read(cx)
5053 .range_to_buffer_ranges(start_ix..end_ix, cx);
5054 let excerpted_buffers_text = excerpted_buffer_ranges
5055 .into_iter()
5056 .map(|(buffer, buffer_range)| {
5057 buffer
5058 .read(cx)
5059 .text_for_range(buffer_range)
5060 .collect::<String>()
5061 })
5062 .collect::<Vec<_>>()
5063 .join("\n");
5064 assert_eq!(excerpted_buffers_text, text_for_range);
5065
5066 let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
5067 assert_eq!(
5068 snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
5069 expected_summary,
5070 "incorrect summary for range {:?}",
5071 start_ix..end_ix
5072 );
5073 }
5074
5075 // Anchor resolution
5076 let summaries = snapshot.summaries_for_anchors::<usize, _>(&anchors);
5077 assert_eq!(anchors.len(), summaries.len());
5078 for (anchor, resolved_offset) in anchors.iter().zip(summaries) {
5079 assert!(resolved_offset <= snapshot.len());
5080 assert_eq!(
5081 snapshot.summary_for_anchor::<usize>(anchor),
5082 resolved_offset
5083 );
5084 }
5085
5086 for _ in 0..10 {
5087 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
5088 assert_eq!(
5089 snapshot.reversed_chars_at(end_ix).collect::<String>(),
5090 expected_text[..end_ix].chars().rev().collect::<String>(),
5091 );
5092 }
5093
5094 for _ in 0..10 {
5095 let end_ix = rng.gen_range(0..=text_rope.len());
5096 let start_ix = rng.gen_range(0..=end_ix);
5097 assert_eq!(
5098 snapshot
5099 .bytes_in_range(start_ix..end_ix)
5100 .flatten()
5101 .copied()
5102 .collect::<Vec<_>>(),
5103 expected_text.as_bytes()[start_ix..end_ix].to_vec(),
5104 "bytes_in_range({:?})",
5105 start_ix..end_ix,
5106 );
5107 }
5108 }
5109
5110 let snapshot = multibuffer.read(cx).snapshot(cx);
5111 for (old_snapshot, subscription) in old_versions {
5112 let edits = subscription.consume().into_inner();
5113
5114 log::info!(
5115 "applying subscription edits to old text: {:?}: {:?}",
5116 old_snapshot.text(),
5117 edits,
5118 );
5119
5120 let mut text = old_snapshot.text();
5121 for edit in edits {
5122 let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
5123 text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
5124 }
5125 assert_eq!(text.to_string(), snapshot.text());
5126 }
5127 }
5128
5129 #[gpui::test]
5130 fn test_history(cx: &mut AppContext) {
5131 cx.set_global(Settings::test(cx));
5132 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "1234", cx));
5133 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "5678", cx));
5134 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
5135 let group_interval = multibuffer.read(cx).history.group_interval;
5136 multibuffer.update(cx, |multibuffer, cx| {
5137 multibuffer.push_excerpts(
5138 buffer_1.clone(),
5139 [ExcerptRange {
5140 context: 0..buffer_1.read(cx).len(),
5141 primary: None,
5142 }],
5143 cx,
5144 );
5145 multibuffer.push_excerpts(
5146 buffer_2.clone(),
5147 [ExcerptRange {
5148 context: 0..buffer_2.read(cx).len(),
5149 primary: None,
5150 }],
5151 cx,
5152 );
5153 });
5154
5155 let mut now = Instant::now();
5156
5157 multibuffer.update(cx, |multibuffer, cx| {
5158 let transaction_1 = multibuffer.start_transaction_at(now, cx).unwrap();
5159 multibuffer.edit(
5160 [
5161 (Point::new(0, 0)..Point::new(0, 0), "A"),
5162 (Point::new(1, 0)..Point::new(1, 0), "A"),
5163 ],
5164 None,
5165 cx,
5166 );
5167 multibuffer.edit(
5168 [
5169 (Point::new(0, 1)..Point::new(0, 1), "B"),
5170 (Point::new(1, 1)..Point::new(1, 1), "B"),
5171 ],
5172 None,
5173 cx,
5174 );
5175 multibuffer.end_transaction_at(now, cx);
5176 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5177
5178 // Edit buffer 1 through the multibuffer
5179 now += 2 * group_interval;
5180 multibuffer.start_transaction_at(now, cx);
5181 multibuffer.edit([(2..2, "C")], None, cx);
5182 multibuffer.end_transaction_at(now, cx);
5183 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
5184
5185 // Edit buffer 1 independently
5186 buffer_1.update(cx, |buffer_1, cx| {
5187 buffer_1.start_transaction_at(now);
5188 buffer_1.edit([(3..3, "D")], None, cx);
5189 buffer_1.end_transaction_at(now, cx);
5190
5191 now += 2 * group_interval;
5192 buffer_1.start_transaction_at(now);
5193 buffer_1.edit([(4..4, "E")], None, cx);
5194 buffer_1.end_transaction_at(now, cx);
5195 });
5196 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
5197
5198 // An undo in the multibuffer undoes the multibuffer transaction
5199 // and also any individual buffer edits that have occured since
5200 // that transaction.
5201 multibuffer.undo(cx);
5202 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5203
5204 multibuffer.undo(cx);
5205 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5206
5207 multibuffer.redo(cx);
5208 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5209
5210 multibuffer.redo(cx);
5211 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
5212
5213 // Undo buffer 2 independently.
5214 buffer_2.update(cx, |buffer_2, cx| buffer_2.undo(cx));
5215 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\n5678");
5216
5217 // An undo in the multibuffer undoes the components of the
5218 // the last multibuffer transaction that are not already undone.
5219 multibuffer.undo(cx);
5220 assert_eq!(multibuffer.read(cx).text(), "AB1234\n5678");
5221
5222 multibuffer.undo(cx);
5223 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5224
5225 multibuffer.redo(cx);
5226 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5227
5228 buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
5229 assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
5230
5231 // Redo stack gets cleared after an edit.
5232 now += 2 * group_interval;
5233 multibuffer.start_transaction_at(now, cx);
5234 multibuffer.edit([(0..0, "X")], None, cx);
5235 multibuffer.end_transaction_at(now, cx);
5236 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5237 multibuffer.redo(cx);
5238 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5239 multibuffer.undo(cx);
5240 assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
5241 multibuffer.undo(cx);
5242 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5243
5244 // Transactions can be grouped manually.
5245 multibuffer.redo(cx);
5246 multibuffer.redo(cx);
5247 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5248 multibuffer.group_until_transaction(transaction_1, cx);
5249 multibuffer.undo(cx);
5250 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5251 multibuffer.redo(cx);
5252 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5253 });
5254 }
5255}