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