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