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