1mod anchor;
2
3pub use anchor::{Anchor, AnchorRangeExt};
4use anyhow::Result;
5use clock::ReplicaId;
6use collections::{HashMap, HashSet};
7use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
8use language::{
9 Buffer, BufferChunks, BufferSnapshot, Chunk, DiagnosticEntry, Event, File, Language, Selection,
10 ToOffset as _, ToPoint as _, TransactionId,
11};
12use std::{
13 cell::{Ref, RefCell},
14 cmp, fmt, io,
15 iter::{self, FromIterator},
16 ops::{Range, Sub},
17 str,
18 sync::Arc,
19 time::{Duration, Instant},
20};
21use sum_tree::{Bias, Cursor, SumTree};
22use text::{
23 locator::Locator,
24 rope::TextDimension,
25 subscription::{Subscription, Topic},
26 AnchorRangeExt as _, Edit, Point, PointUtf16, TextSummary,
27};
28use theme::SyntaxTheme;
29use util::post_inc;
30
31const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize];
32
33pub type ExcerptId = Locator;
34
35pub struct MultiBuffer {
36 snapshot: RefCell<MultiBufferSnapshot>,
37 buffers: RefCell<HashMap<usize, BufferState>>,
38 subscriptions: Topic,
39 singleton: bool,
40 replica_id: ReplicaId,
41 history: History,
42}
43
44struct History {
45 next_transaction_id: usize,
46 undo_stack: Vec<Transaction>,
47 redo_stack: Vec<Transaction>,
48 transaction_depth: usize,
49 group_interval: Duration,
50}
51
52struct Transaction {
53 id: usize,
54 buffer_transactions: HashSet<(usize, text::TransactionId)>,
55 first_edit_at: Instant,
56 last_edit_at: Instant,
57}
58
59pub trait ToOffset: 'static + fmt::Debug {
60 fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
61}
62
63pub trait ToPoint: 'static + fmt::Debug {
64 fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point;
65}
66
67pub trait FromAnchor: 'static {
68 fn from_anchor(anchor: &Anchor, snapshot: &MultiBufferSnapshot) -> Self;
69}
70
71struct BufferState {
72 buffer: ModelHandle<Buffer>,
73 last_version: clock::Global,
74 last_parse_count: usize,
75 last_diagnostics_update_count: usize,
76 excerpts: Vec<ExcerptId>,
77 _subscriptions: [gpui::Subscription; 2],
78}
79
80#[derive(Clone, Default)]
81pub struct MultiBufferSnapshot {
82 excerpts: SumTree<Excerpt>,
83 parse_count: usize,
84 diagnostics_update_count: usize,
85 is_dirty: bool,
86 has_conflict: bool,
87}
88
89pub struct ExcerptProperties<'a, T> {
90 pub buffer: &'a ModelHandle<Buffer>,
91 pub range: Range<T>,
92}
93
94#[derive(Clone)]
95struct Excerpt {
96 id: ExcerptId,
97 buffer_id: usize,
98 buffer: BufferSnapshot,
99 range: Range<text::Anchor>,
100 max_buffer_row: u32,
101 text_summary: TextSummary,
102 has_trailing_newline: bool,
103}
104
105#[derive(Clone, Debug, Default)]
106struct ExcerptSummary {
107 excerpt_id: ExcerptId,
108 max_buffer_row: u32,
109 text: TextSummary,
110}
111
112pub struct MultiBufferRows<'a> {
113 buffer_row_range: Range<u32>,
114 excerpts: Cursor<'a, Excerpt, Point>,
115}
116
117pub struct MultiBufferChunks<'a> {
118 range: Range<usize>,
119 excerpts: Cursor<'a, Excerpt, usize>,
120 excerpt_chunks: Option<ExcerptChunks<'a>>,
121 theme: Option<&'a SyntaxTheme>,
122}
123
124pub struct MultiBufferBytes<'a> {
125 range: Range<usize>,
126 excerpts: Cursor<'a, Excerpt, usize>,
127 excerpt_bytes: Option<ExcerptBytes<'a>>,
128 chunk: &'a [u8],
129}
130
131struct ExcerptChunks<'a> {
132 content_chunks: BufferChunks<'a>,
133 footer_height: usize,
134}
135
136struct ExcerptBytes<'a> {
137 content_bytes: language::rope::Bytes<'a>,
138 footer_height: usize,
139}
140
141impl MultiBuffer {
142 pub fn new(replica_id: ReplicaId) -> Self {
143 Self {
144 snapshot: Default::default(),
145 buffers: Default::default(),
146 subscriptions: Default::default(),
147 singleton: false,
148 replica_id,
149 history: History {
150 next_transaction_id: Default::default(),
151 undo_stack: Default::default(),
152 redo_stack: Default::default(),
153 transaction_depth: 0,
154 group_interval: Duration::from_millis(300),
155 },
156 }
157 }
158
159 pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
160 let mut this = Self::new(buffer.read(cx).replica_id());
161 this.singleton = true;
162 this.push_excerpt(
163 ExcerptProperties {
164 buffer: &buffer,
165 range: text::Anchor::min()..text::Anchor::max(),
166 },
167 cx,
168 );
169 this
170 }
171
172 #[cfg(any(test, feature = "test-support"))]
173 pub fn build_simple(text: &str, cx: &mut gpui::MutableAppContext) -> ModelHandle<Self> {
174 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
175 cx.add_model(|cx| Self::singleton(buffer, cx))
176 }
177
178 #[cfg(any(test, feature = "test-support"))]
179 pub fn build_random(
180 mut rng: &mut impl rand::Rng,
181 cx: &mut gpui::MutableAppContext,
182 ) -> ModelHandle<Self> {
183 use rand::prelude::*;
184 use std::env;
185 use text::RandomCharIter;
186
187 let max_excerpts = env::var("MAX_EXCERPTS")
188 .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))
189 .unwrap_or(5);
190 let excerpts = rng.gen_range(1..=max_excerpts);
191
192 cx.add_model(|cx| {
193 let mut multibuffer = MultiBuffer::new(0);
194 let mut buffers = Vec::new();
195 for _ in 0..excerpts {
196 let buffer_handle = if rng.gen() || buffers.is_empty() {
197 let text = RandomCharIter::new(&mut rng).take(10).collect::<String>();
198 buffers.push(cx.add_model(|cx| Buffer::new(0, text, cx)));
199 let buffer = buffers.last().unwrap();
200 log::info!(
201 "Creating new buffer {} with text: {:?}",
202 buffer.id(),
203 buffer.read(cx).text()
204 );
205 buffers.last().unwrap()
206 } else {
207 buffers.choose(rng).unwrap()
208 };
209
210 let buffer = buffer_handle.read(cx);
211 let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
212 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
213 let header_height = rng.gen_range(0..=5);
214 log::info!(
215 "Inserting excerpt from buffer {} with header height {} and range {:?}: {:?}",
216 buffer_handle.id(),
217 header_height,
218 start_ix..end_ix,
219 &buffer.text()[start_ix..end_ix]
220 );
221
222 multibuffer.push_excerpt(
223 ExcerptProperties {
224 buffer: buffer_handle,
225 range: start_ix..end_ix,
226 },
227 cx,
228 );
229 }
230 multibuffer
231 })
232 }
233
234 pub fn replica_id(&self) -> ReplicaId {
235 self.replica_id
236 }
237
238 pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot {
239 self.sync(cx);
240 self.snapshot.borrow().clone()
241 }
242
243 pub fn read(&self, cx: &AppContext) -> Ref<MultiBufferSnapshot> {
244 self.sync(cx);
245 self.snapshot.borrow()
246 }
247
248 pub fn as_singleton(&self) -> Option<ModelHandle<Buffer>> {
249 if self.singleton {
250 return Some(
251 self.buffers
252 .borrow()
253 .values()
254 .next()
255 .unwrap()
256 .buffer
257 .clone(),
258 );
259 } else {
260 None
261 }
262 }
263
264 pub fn subscribe(&mut self) -> Subscription {
265 self.subscriptions.subscribe()
266 }
267
268 pub fn edit<I, S, T>(&mut self, ranges: I, new_text: T, cx: &mut ModelContext<Self>)
269 where
270 I: IntoIterator<Item = Range<S>>,
271 S: ToOffset,
272 T: Into<String>,
273 {
274 self.edit_internal(ranges, new_text, false, cx)
275 }
276
277 pub fn edit_with_autoindent<I, S, T>(
278 &mut self,
279 ranges: I,
280 new_text: T,
281 cx: &mut ModelContext<Self>,
282 ) where
283 I: IntoIterator<Item = Range<S>>,
284 S: ToOffset,
285 T: Into<String>,
286 {
287 self.edit_internal(ranges, new_text, true, cx)
288 }
289
290 pub fn edit_internal<I, S, T>(
291 &mut self,
292 ranges_iter: I,
293 new_text: T,
294 autoindent: bool,
295 cx: &mut ModelContext<Self>,
296 ) where
297 I: IntoIterator<Item = Range<S>>,
298 S: ToOffset,
299 T: Into<String>,
300 {
301 if let Some(buffer) = self.as_singleton() {
302 let snapshot = self.read(cx);
303 let ranges = ranges_iter
304 .into_iter()
305 .map(|range| range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot));
306 return buffer.update(cx, |buffer, cx| {
307 if autoindent {
308 buffer.edit_with_autoindent(ranges, new_text, cx)
309 } else {
310 buffer.edit(ranges, new_text, cx)
311 }
312 });
313 }
314
315 let snapshot = self.read(cx);
316 let mut buffer_edits: HashMap<usize, Vec<(Range<usize>, bool)>> = Default::default();
317 let mut cursor = snapshot.excerpts.cursor::<usize>();
318 for range in ranges_iter {
319 let start = range.start.to_offset(&snapshot);
320 let end = range.end.to_offset(&snapshot);
321 cursor.seek(&start, Bias::Right, &());
322 if cursor.item().is_none() && start == *cursor.start() {
323 cursor.prev(&());
324 }
325 let start_excerpt = cursor.item().expect("start offset out of bounds");
326 let start_overshoot = start - cursor.start();
327 let buffer_start =
328 start_excerpt.range.start.to_offset(&start_excerpt.buffer) + start_overshoot;
329
330 cursor.seek(&end, Bias::Right, &());
331 if cursor.item().is_none() && end == *cursor.start() {
332 cursor.prev(&());
333 }
334 let end_excerpt = cursor.item().expect("end offset out of bounds");
335 let end_overshoot = end - cursor.start();
336 let buffer_end = end_excerpt.range.start.to_offset(&end_excerpt.buffer) + end_overshoot;
337
338 if start_excerpt.id == end_excerpt.id {
339 buffer_edits
340 .entry(start_excerpt.buffer_id)
341 .or_insert(Vec::new())
342 .push((buffer_start..buffer_end, true));
343 } else {
344 let start_excerpt_range =
345 buffer_start..start_excerpt.range.end.to_offset(&start_excerpt.buffer);
346 let end_excerpt_range =
347 end_excerpt.range.start.to_offset(&end_excerpt.buffer)..buffer_end;
348 buffer_edits
349 .entry(start_excerpt.buffer_id)
350 .or_insert(Vec::new())
351 .push((start_excerpt_range, true));
352 buffer_edits
353 .entry(end_excerpt.buffer_id)
354 .or_insert(Vec::new())
355 .push((end_excerpt_range, false));
356
357 cursor.seek(&start, Bias::Right, &());
358 cursor.next(&());
359 while let Some(excerpt) = cursor.item() {
360 if excerpt.id == end_excerpt.id {
361 break;
362 }
363 buffer_edits
364 .entry(excerpt.buffer_id)
365 .or_insert(Vec::new())
366 .push((excerpt.range.to_offset(&excerpt.buffer), false));
367 cursor.next(&());
368 }
369 }
370 }
371
372 let new_text = new_text.into();
373 for (buffer_id, mut edits) in buffer_edits {
374 edits.sort_unstable_by_key(|(range, _)| range.start);
375 self.buffers.borrow()[&buffer_id]
376 .buffer
377 .update(cx, |buffer, cx| {
378 let mut edits = edits.into_iter().peekable();
379 let mut insertions = Vec::new();
380 let mut deletions = Vec::new();
381 while let Some((mut range, mut is_insertion)) = edits.next() {
382 while let Some((next_range, next_is_insertion)) = edits.peek() {
383 if range.end >= next_range.start {
384 range.end = cmp::max(next_range.end, range.end);
385 is_insertion |= *next_is_insertion;
386 edits.next();
387 } else {
388 break;
389 }
390 }
391
392 if is_insertion {
393 insertions.push(
394 buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
395 );
396 } else if !range.is_empty() {
397 deletions.push(
398 buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
399 );
400 }
401 }
402
403 if autoindent {
404 buffer.edit_with_autoindent(deletions, "", cx);
405 buffer.edit_with_autoindent(insertions, new_text.clone(), cx);
406 } else {
407 buffer.edit(deletions, "", cx);
408 buffer.edit(insertions, new_text.clone(), cx);
409 }
410 })
411 }
412 }
413
414 pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
415 self.start_transaction_at(Instant::now(), cx)
416 }
417
418 pub(crate) fn start_transaction_at(
419 &mut self,
420 now: Instant,
421 cx: &mut ModelContext<Self>,
422 ) -> Option<TransactionId> {
423 if let Some(buffer) = self.as_singleton() {
424 return buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
425 }
426
427 for BufferState { buffer, .. } in self.buffers.borrow().values() {
428 buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
429 }
430 self.history.start_transaction(now)
431 }
432
433 pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
434 self.end_transaction_at(Instant::now(), cx)
435 }
436
437 pub(crate) fn end_transaction_at(
438 &mut self,
439 now: Instant,
440 cx: &mut ModelContext<Self>,
441 ) -> Option<TransactionId> {
442 if let Some(buffer) = self.as_singleton() {
443 return buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx));
444 }
445
446 let mut buffer_transactions = HashSet::default();
447 for BufferState { buffer, .. } in self.buffers.borrow().values() {
448 if let Some(transaction_id) =
449 buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
450 {
451 buffer_transactions.insert((buffer.id(), transaction_id));
452 }
453 }
454
455 if self.history.end_transaction(now, buffer_transactions) {
456 let transaction_id = self.history.group().unwrap();
457 Some(transaction_id)
458 } else {
459 None
460 }
461 }
462
463 pub fn set_active_selections(
464 &mut self,
465 selections: &[Selection<Anchor>],
466 cx: &mut ModelContext<Self>,
467 ) {
468 let mut selections_by_buffer: HashMap<usize, Vec<Selection<text::Anchor>>> =
469 Default::default();
470 let snapshot = self.read(cx);
471 let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();
472 for selection in selections {
473 cursor.seek(&Some(&selection.start.excerpt_id), Bias::Left, &());
474 while let Some(excerpt) = cursor.item() {
475 if excerpt.id > selection.end.excerpt_id {
476 break;
477 }
478
479 let mut start = excerpt.range.start.clone();
480 let mut end = excerpt.range.end.clone();
481 if excerpt.id == selection.start.excerpt_id {
482 start = selection.start.text_anchor.clone();
483 }
484 if excerpt.id == selection.end.excerpt_id {
485 end = selection.end.text_anchor.clone();
486 }
487 selections_by_buffer
488 .entry(excerpt.buffer_id)
489 .or_default()
490 .push(Selection {
491 id: selection.id,
492 start,
493 end,
494 reversed: selection.reversed,
495 goal: selection.goal,
496 });
497
498 cursor.next(&());
499 }
500 }
501
502 for (buffer_id, mut selections) in selections_by_buffer {
503 self.buffers.borrow()[&buffer_id]
504 .buffer
505 .update(cx, |buffer, cx| {
506 selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap());
507 let mut selections = selections.into_iter().peekable();
508 let merged_selections = Arc::from_iter(iter::from_fn(|| {
509 let mut selection = selections.next()?;
510 while let Some(next_selection) = selections.peek() {
511 if selection
512 .end
513 .cmp(&next_selection.start, buffer)
514 .unwrap()
515 .is_ge()
516 {
517 let next_selection = selections.next().unwrap();
518 if next_selection
519 .end
520 .cmp(&selection.end, buffer)
521 .unwrap()
522 .is_ge()
523 {
524 selection.end = next_selection.end;
525 }
526 } else {
527 break;
528 }
529 }
530 Some(selection)
531 }));
532 buffer.set_active_selections(merged_selections, cx);
533 });
534 }
535 }
536
537 pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
538 for buffer in self.buffers.borrow().values() {
539 buffer
540 .buffer
541 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
542 }
543 }
544
545 pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
546 if let Some(buffer) = self.as_singleton() {
547 return buffer.update(cx, |buffer, cx| buffer.undo(cx));
548 }
549
550 while let Some(transaction) = self.history.pop_undo() {
551 let mut undone = false;
552 for (buffer_id, buffer_transaction_id) in &transaction.buffer_transactions {
553 if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(&buffer_id) {
554 undone |= buffer.update(cx, |buf, cx| {
555 buf.undo_transaction(*buffer_transaction_id, cx)
556 });
557 }
558 }
559
560 if undone {
561 return Some(transaction.id);
562 }
563 }
564
565 None
566 }
567
568 pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
569 if let Some(buffer) = self.as_singleton() {
570 return buffer.update(cx, |buffer, cx| buffer.redo(cx));
571 }
572
573 while let Some(transaction) = self.history.pop_redo() {
574 let mut redone = false;
575 for (buffer_id, buffer_transaction_id) in &transaction.buffer_transactions {
576 if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(&buffer_id) {
577 redone |= buffer.update(cx, |buf, cx| {
578 buf.redo_transaction(*buffer_transaction_id, cx)
579 });
580 }
581 }
582
583 if redone {
584 return Some(transaction.id);
585 }
586 }
587
588 None
589 }
590
591 pub fn push_excerpt<O>(
592 &mut self,
593 props: ExcerptProperties<O>,
594 cx: &mut ModelContext<Self>,
595 ) -> ExcerptId
596 where
597 O: text::ToOffset,
598 {
599 assert_eq!(self.history.transaction_depth, 0);
600 self.sync(cx);
601
602 let buffer_snapshot = props.buffer.read(cx).snapshot();
603 let range = buffer_snapshot.anchor_before(&props.range.start)
604 ..buffer_snapshot.anchor_after(&props.range.end);
605 let mut snapshot = self.snapshot.borrow_mut();
606 let mut prev_id = None;
607 let edit_start = snapshot.excerpts.summary().text.bytes;
608 snapshot.excerpts.update_last(
609 |excerpt| {
610 excerpt.has_trailing_newline = true;
611 prev_id = Some(excerpt.id.clone());
612 },
613 &(),
614 );
615
616 let id = ExcerptId::between(&prev_id.unwrap_or(ExcerptId::min()), &ExcerptId::max());
617 self.buffers
618 .borrow_mut()
619 .entry(props.buffer.id())
620 .or_insert_with(|| BufferState {
621 last_version: buffer_snapshot.version().clone(),
622 last_parse_count: buffer_snapshot.parse_count(),
623 last_diagnostics_update_count: buffer_snapshot.diagnostics_update_count(),
624 excerpts: Default::default(),
625 _subscriptions: [
626 cx.observe(&props.buffer, |_, _, cx| cx.notify()),
627 cx.subscribe(&props.buffer, Self::on_buffer_event),
628 ],
629 buffer: props.buffer.clone(),
630 })
631 .excerpts
632 .push(id.clone());
633 let excerpt = Excerpt::new(id.clone(), props.buffer.id(), buffer_snapshot, range, false);
634 snapshot.excerpts.push(excerpt, &());
635 self.subscriptions.publish_mut([Edit {
636 old: edit_start..edit_start,
637 new: edit_start..snapshot.excerpts.summary().text.bytes,
638 }]);
639
640 cx.notify();
641 id
642 }
643
644 pub fn excerpt_ids_for_buffer(&self, buffer: &ModelHandle<Buffer>) -> Vec<ExcerptId> {
645 self.buffers
646 .borrow()
647 .get(&buffer.id())
648 .map_or(Vec::new(), |state| state.excerpts.clone())
649 }
650
651 pub fn remove_excerpts<'a>(
652 &mut self,
653 excerpt_ids: impl IntoIterator<Item = &'a ExcerptId>,
654 cx: &mut ModelContext<Self>,
655 ) {
656 let mut buffers = self.buffers.borrow_mut();
657 let mut snapshot = self.snapshot.borrow_mut();
658 let mut new_excerpts = SumTree::new();
659 let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>();
660 let mut edits = Vec::new();
661 for excerpt_id in excerpt_ids {
662 new_excerpts.push_tree(cursor.slice(&Some(excerpt_id), Bias::Left, &()), &());
663 if let Some(excerpt) = cursor.item() {
664 if excerpt.id == *excerpt_id {
665 let mut old_start = cursor.start().1;
666 let old_end = cursor.end(&()).1;
667 cursor.next(&());
668
669 if let Some(buffer_state) = buffers.get_mut(&excerpt.buffer_id) {
670 buffer_state.excerpts.retain(|id| id != excerpt_id);
671 }
672
673 // When removing the last excerpt, remove the trailing newline from
674 // the previous excerpt.
675 if cursor.item().is_none() && old_start > 0 {
676 old_start -= 1;
677 new_excerpts.update_last(|e| e.has_trailing_newline = false, &());
678 }
679
680 let new_start = new_excerpts.summary().text.bytes;
681 edits.push(Edit {
682 old: old_start..old_end,
683 new: new_start..new_start,
684 });
685 }
686 }
687 }
688 new_excerpts.push_tree(cursor.suffix(&()), &());
689 drop(cursor);
690 snapshot.excerpts = new_excerpts;
691 self.subscriptions.publish_mut(edits);
692 cx.notify();
693 }
694
695 fn on_buffer_event(
696 &mut self,
697 _: ModelHandle<Buffer>,
698 event: &Event,
699 cx: &mut ModelContext<Self>,
700 ) {
701 cx.emit(event.clone());
702 }
703
704 pub fn save(&mut self, cx: &mut ModelContext<Self>) -> Result<Task<Result<()>>> {
705 let mut save_tasks = Vec::new();
706 for BufferState { buffer, .. } in self.buffers.borrow().values() {
707 save_tasks.push(buffer.update(cx, |buffer, cx| buffer.save(cx))?);
708 }
709
710 Ok(cx.spawn(|_, _| async move {
711 for save in save_tasks {
712 save.await?;
713 }
714 Ok(())
715 }))
716 }
717
718 pub fn language<'a>(&self, cx: &'a AppContext) -> Option<&'a Arc<Language>> {
719 self.buffers
720 .borrow()
721 .values()
722 .next()
723 .and_then(|state| state.buffer.read(cx).language())
724 }
725
726 pub fn file<'a>(&self, cx: &'a AppContext) -> Option<&'a dyn File> {
727 self.as_singleton()?.read(cx).file()
728 }
729
730 #[cfg(test)]
731 pub fn is_parsing(&self, cx: &AppContext) -> bool {
732 self.as_singleton().unwrap().read(cx).is_parsing()
733 }
734
735 fn sync(&self, cx: &AppContext) {
736 let mut snapshot = self.snapshot.borrow_mut();
737 let mut excerpts_to_edit = Vec::new();
738 let mut reparsed = false;
739 let mut diagnostics_updated = false;
740 let mut is_dirty = false;
741 let mut has_conflict = false;
742 let mut buffers = self.buffers.borrow_mut();
743 for buffer_state in buffers.values_mut() {
744 let buffer = buffer_state.buffer.read(cx);
745 let version = buffer.version();
746 let parse_count = buffer.parse_count();
747 let diagnostics_update_count = buffer.diagnostics_update_count();
748
749 let buffer_edited = version.gt(&buffer_state.last_version);
750 let buffer_reparsed = parse_count > buffer_state.last_parse_count;
751 let buffer_diagnostics_updated =
752 diagnostics_update_count > buffer_state.last_diagnostics_update_count;
753 if buffer_edited || buffer_reparsed || buffer_diagnostics_updated {
754 buffer_state.last_version = version;
755 buffer_state.last_parse_count = parse_count;
756 buffer_state.last_diagnostics_update_count = diagnostics_update_count;
757 excerpts_to_edit.extend(
758 buffer_state
759 .excerpts
760 .iter()
761 .map(|excerpt_id| (excerpt_id, buffer_state.buffer.clone(), buffer_edited)),
762 );
763 }
764
765 reparsed |= buffer_reparsed;
766 diagnostics_updated |= buffer_diagnostics_updated;
767 is_dirty |= buffer.is_dirty();
768 has_conflict |= buffer.has_conflict();
769 }
770 if reparsed {
771 snapshot.parse_count += 1;
772 }
773 if diagnostics_updated {
774 snapshot.diagnostics_update_count += 1;
775 }
776 snapshot.is_dirty = is_dirty;
777 snapshot.has_conflict = has_conflict;
778
779 excerpts_to_edit.sort_unstable_by_key(|(excerpt_id, _, _)| *excerpt_id);
780
781 let mut edits = Vec::new();
782 let mut new_excerpts = SumTree::new();
783 let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>();
784
785 for (id, buffer, buffer_edited) in excerpts_to_edit {
786 new_excerpts.push_tree(cursor.slice(&Some(id), Bias::Left, &()), &());
787 let old_excerpt = cursor.item().unwrap();
788 let buffer_id = buffer.id();
789 let buffer = buffer.read(cx);
790
791 let mut new_excerpt;
792 if buffer_edited {
793 edits.extend(
794 buffer
795 .edits_since_in_range::<usize>(
796 old_excerpt.buffer.version(),
797 old_excerpt.range.clone(),
798 )
799 .map(|mut edit| {
800 let excerpt_old_start = cursor.start().1;
801 let excerpt_new_start = new_excerpts.summary().text.bytes;
802 edit.old.start += excerpt_old_start;
803 edit.old.end += excerpt_old_start;
804 edit.new.start += excerpt_new_start;
805 edit.new.end += excerpt_new_start;
806 edit
807 }),
808 );
809
810 new_excerpt = Excerpt::new(
811 id.clone(),
812 buffer_id,
813 buffer.snapshot(),
814 old_excerpt.range.clone(),
815 old_excerpt.has_trailing_newline,
816 );
817 } else {
818 new_excerpt = old_excerpt.clone();
819 new_excerpt.buffer = buffer.snapshot();
820 }
821
822 new_excerpts.push(new_excerpt, &());
823 cursor.next(&());
824 }
825 new_excerpts.push_tree(cursor.suffix(&()), &());
826
827 drop(cursor);
828 snapshot.excerpts = new_excerpts;
829
830 self.subscriptions.publish(edits);
831 }
832}
833
834#[cfg(any(test, feature = "test-support"))]
835impl MultiBuffer {
836 pub fn randomly_edit(
837 &mut self,
838 rng: &mut impl rand::Rng,
839 count: usize,
840 cx: &mut ModelContext<Self>,
841 ) {
842 use text::RandomCharIter;
843
844 let snapshot = self.read(cx);
845 let mut old_ranges: Vec<Range<usize>> = Vec::new();
846 for _ in 0..count {
847 let last_end = old_ranges.last().map_or(0, |last_range| last_range.end + 1);
848 if last_end > snapshot.len() {
849 break;
850 }
851 let end_ix = snapshot.clip_offset(rng.gen_range(0..=last_end), Bias::Right);
852 let start_ix = snapshot.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
853 old_ranges.push(start_ix..end_ix);
854 }
855 let new_text_len = rng.gen_range(0..10);
856 let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
857 log::info!("mutating multi-buffer at {:?}: {:?}", old_ranges, new_text);
858 drop(snapshot);
859
860 self.edit(old_ranges.iter().cloned(), new_text.as_str(), cx);
861 }
862}
863
864impl Entity for MultiBuffer {
865 type Event = language::Event;
866}
867
868impl MultiBufferSnapshot {
869 pub fn text(&self) -> String {
870 self.chunks(0..self.len(), None)
871 .map(|chunk| chunk.text)
872 .collect()
873 }
874
875 pub fn reversed_chars_at<'a, T: ToOffset>(
876 &'a self,
877 position: T,
878 ) -> impl Iterator<Item = char> + 'a {
879 let mut offset = position.to_offset(self);
880 let mut cursor = self.excerpts.cursor::<usize>();
881 cursor.seek(&offset, Bias::Left, &());
882 let mut excerpt_chunks = cursor.item().map(|excerpt| {
883 let end_before_footer = cursor.start() + excerpt.text_summary.bytes;
884 let start = excerpt.range.start.to_offset(&excerpt.buffer);
885 let end = start + (cmp::min(offset, end_before_footer) - cursor.start());
886 excerpt.buffer.reversed_chunks_in_range(start..end)
887 });
888 iter::from_fn(move || {
889 if offset == *cursor.start() {
890 cursor.prev(&());
891 let excerpt = cursor.item()?;
892 excerpt_chunks = Some(
893 excerpt
894 .buffer
895 .reversed_chunks_in_range(excerpt.range.clone()),
896 );
897 }
898
899 let excerpt = cursor.item().unwrap();
900 if offset == cursor.end(&()) && excerpt.has_trailing_newline {
901 offset -= 1;
902 Some("\n")
903 } else {
904 let chunk = excerpt_chunks.as_mut().unwrap().next().unwrap();
905 offset -= chunk.len();
906 Some(chunk)
907 }
908 })
909 .flat_map(|c| c.chars().rev())
910 }
911
912 pub fn chars_at<'a, T: ToOffset>(&'a self, position: T) -> impl Iterator<Item = char> + 'a {
913 let offset = position.to_offset(self);
914 self.text_for_range(offset..self.len())
915 .flat_map(|chunk| chunk.chars())
916 }
917
918 pub fn text_for_range<'a, T: ToOffset>(
919 &'a self,
920 range: Range<T>,
921 ) -> impl Iterator<Item = &'a str> {
922 self.chunks(range, None).map(|chunk| chunk.text)
923 }
924
925 pub fn is_line_blank(&self, row: u32) -> bool {
926 self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row)))
927 .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
928 }
929
930 pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
931 where
932 T: ToOffset,
933 {
934 let position = position.to_offset(self);
935 position == self.clip_offset(position, Bias::Left)
936 && self
937 .bytes_in_range(position..self.len())
938 .flatten()
939 .copied()
940 .take(needle.len())
941 .eq(needle.bytes())
942 }
943
944 fn as_singleton(&self) -> Option<&BufferSnapshot> {
945 let mut excerpts = self.excerpts.iter();
946 let buffer = excerpts.next().map(|excerpt| &excerpt.buffer);
947 if excerpts.next().is_none() {
948 buffer
949 } else {
950 None
951 }
952 }
953
954 pub fn len(&self) -> usize {
955 self.excerpts.summary().text.bytes
956 }
957
958 pub fn max_buffer_row(&self) -> u32 {
959 self.excerpts.summary().max_buffer_row
960 }
961
962 pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
963 let mut cursor = self.excerpts.cursor::<usize>();
964 cursor.seek(&offset, Bias::Right, &());
965 let overshoot = if let Some(excerpt) = cursor.item() {
966 let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
967 let buffer_offset = excerpt
968 .buffer
969 .clip_offset(excerpt_start + (offset - cursor.start()), bias);
970 buffer_offset.saturating_sub(excerpt_start)
971 } else {
972 0
973 };
974 cursor.start() + overshoot
975 }
976
977 pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
978 let mut cursor = self.excerpts.cursor::<Point>();
979 cursor.seek(&point, Bias::Right, &());
980 let overshoot = if let Some(excerpt) = cursor.item() {
981 let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
982 let buffer_point = excerpt
983 .buffer
984 .clip_point(excerpt_start + (point - cursor.start()), bias);
985 buffer_point.saturating_sub(excerpt_start)
986 } else {
987 Point::zero()
988 };
989 *cursor.start() + overshoot
990 }
991
992 pub fn clip_point_utf16(&self, point: PointUtf16, bias: Bias) -> PointUtf16 {
993 let mut cursor = self.excerpts.cursor::<PointUtf16>();
994 cursor.seek(&point, Bias::Right, &());
995 let overshoot = if let Some(excerpt) = cursor.item() {
996 let excerpt_start = excerpt
997 .buffer
998 .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
999 let buffer_point = excerpt
1000 .buffer
1001 .clip_point_utf16(excerpt_start + (point - cursor.start()), bias);
1002 buffer_point.saturating_sub(excerpt_start)
1003 } else {
1004 PointUtf16::zero()
1005 };
1006 *cursor.start() + overshoot
1007 }
1008
1009 pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> MultiBufferBytes<'a> {
1010 let range = range.start.to_offset(self)..range.end.to_offset(self);
1011 let mut excerpts = self.excerpts.cursor::<usize>();
1012 excerpts.seek(&range.start, Bias::Right, &());
1013
1014 let mut chunk = &[][..];
1015 let excerpt_bytes = if let Some(excerpt) = excerpts.item() {
1016 let mut excerpt_bytes = excerpt
1017 .bytes_in_range(range.start - excerpts.start()..range.end - excerpts.start());
1018 chunk = excerpt_bytes.next().unwrap_or(&[][..]);
1019 Some(excerpt_bytes)
1020 } else {
1021 None
1022 };
1023
1024 MultiBufferBytes {
1025 range,
1026 excerpts,
1027 excerpt_bytes,
1028 chunk,
1029 }
1030 }
1031
1032 pub fn buffer_rows<'a>(&'a self, start_row: u32) -> MultiBufferRows<'a> {
1033 let mut result = MultiBufferRows {
1034 buffer_row_range: 0..0,
1035 excerpts: self.excerpts.cursor(),
1036 };
1037 result.seek(start_row);
1038 result
1039 }
1040
1041 pub fn chunks<'a, T: ToOffset>(
1042 &'a self,
1043 range: Range<T>,
1044 theme: Option<&'a SyntaxTheme>,
1045 ) -> MultiBufferChunks<'a> {
1046 let range = range.start.to_offset(self)..range.end.to_offset(self);
1047 let mut chunks = MultiBufferChunks {
1048 range: range.clone(),
1049 excerpts: self.excerpts.cursor(),
1050 excerpt_chunks: None,
1051 theme,
1052 };
1053 chunks.seek(range.start);
1054 chunks
1055 }
1056
1057 pub fn offset_to_point(&self, offset: usize) -> Point {
1058 let mut cursor = self.excerpts.cursor::<(usize, Point)>();
1059 cursor.seek(&offset, Bias::Right, &());
1060 if let Some(excerpt) = cursor.item() {
1061 let (start_offset, start_point) = cursor.start();
1062 let overshoot = offset - start_offset;
1063 let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1064 let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
1065 let buffer_point = excerpt
1066 .buffer
1067 .offset_to_point(excerpt_start_offset + overshoot);
1068 *start_point + (buffer_point - excerpt_start_point)
1069 } else {
1070 self.excerpts.summary().text.lines
1071 }
1072 }
1073
1074 pub fn point_to_offset(&self, point: Point) -> usize {
1075 let mut cursor = self.excerpts.cursor::<(Point, usize)>();
1076 cursor.seek(&point, Bias::Right, &());
1077 if let Some(excerpt) = cursor.item() {
1078 let (start_point, start_offset) = cursor.start();
1079 let overshoot = point - start_point;
1080 let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1081 let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
1082 let buffer_offset = excerpt
1083 .buffer
1084 .point_to_offset(excerpt_start_point + overshoot);
1085 *start_offset + buffer_offset - excerpt_start_offset
1086 } else {
1087 self.excerpts.summary().text.bytes
1088 }
1089 }
1090
1091 pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
1092 let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>();
1093 cursor.seek(&point, Bias::Right, &());
1094 if let Some(excerpt) = cursor.item() {
1095 let (start_point, start_offset) = cursor.start();
1096 let overshoot = point - start_point;
1097 let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1098 let excerpt_start_point = excerpt
1099 .buffer
1100 .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
1101 let buffer_offset = excerpt
1102 .buffer
1103 .point_utf16_to_offset(excerpt_start_point + overshoot);
1104 *start_offset + (buffer_offset - excerpt_start_offset)
1105 } else {
1106 self.excerpts.summary().text.bytes
1107 }
1108 }
1109
1110 pub fn indent_column_for_line(&self, row: u32) -> u32 {
1111 if let Some((buffer, range)) = self.buffer_line_for_row(row) {
1112 buffer
1113 .indent_column_for_line(range.start.row)
1114 .min(range.end.column)
1115 .saturating_sub(range.start.column)
1116 } else {
1117 0
1118 }
1119 }
1120
1121 pub fn line_len(&self, row: u32) -> u32 {
1122 if let Some((_, range)) = self.buffer_line_for_row(row) {
1123 range.end.column - range.start.column
1124 } else {
1125 0
1126 }
1127 }
1128
1129 fn buffer_line_for_row(&self, row: u32) -> Option<(&BufferSnapshot, Range<Point>)> {
1130 let mut cursor = self.excerpts.cursor::<Point>();
1131 cursor.seek(&Point::new(row, 0), Bias::Right, &());
1132 if let Some(excerpt) = cursor.item() {
1133 let overshoot = row - cursor.start().row;
1134 let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
1135 let excerpt_end = excerpt.range.end.to_point(&excerpt.buffer);
1136 let buffer_row = excerpt_start.row + overshoot;
1137 let line_start = Point::new(buffer_row, 0);
1138 let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
1139 return Some((
1140 &excerpt.buffer,
1141 line_start.max(excerpt_start)..line_end.min(excerpt_end),
1142 ));
1143 }
1144 None
1145 }
1146
1147 pub fn max_point(&self) -> Point {
1148 self.text_summary().lines
1149 }
1150
1151 pub fn text_summary(&self) -> TextSummary {
1152 self.excerpts.summary().text
1153 }
1154
1155 pub fn text_summary_for_range<'a, D, O>(&'a self, range: Range<O>) -> D
1156 where
1157 D: TextDimension,
1158 O: ToOffset,
1159 {
1160 let mut summary = D::default();
1161 let mut range = range.start.to_offset(self)..range.end.to_offset(self);
1162 let mut cursor = self.excerpts.cursor::<usize>();
1163 cursor.seek(&range.start, Bias::Right, &());
1164 if let Some(excerpt) = cursor.item() {
1165 let mut end_before_newline = cursor.end(&());
1166 if excerpt.has_trailing_newline {
1167 end_before_newline -= 1;
1168 }
1169
1170 let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1171 let start_in_excerpt = excerpt_start + (range.start - cursor.start());
1172 let end_in_excerpt =
1173 excerpt_start + (cmp::min(end_before_newline, range.end) - cursor.start());
1174 summary.add_assign(
1175 &excerpt
1176 .buffer
1177 .text_summary_for_range(start_in_excerpt..end_in_excerpt),
1178 );
1179
1180 if range.end > end_before_newline {
1181 summary.add_assign(&D::from_text_summary(&TextSummary {
1182 bytes: 1,
1183 lines: Point::new(1 as u32, 0),
1184 lines_utf16: PointUtf16::new(1 as u32, 0),
1185 first_line_chars: 0,
1186 last_line_chars: 0,
1187 longest_row: 0,
1188 longest_row_chars: 0,
1189 }));
1190 }
1191
1192 cursor.next(&());
1193 }
1194
1195 if range.end > *cursor.start() {
1196 summary.add_assign(&D::from_text_summary(&cursor.summary::<_, TextSummary>(
1197 &range.end,
1198 Bias::Right,
1199 &(),
1200 )));
1201 if let Some(excerpt) = cursor.item() {
1202 range.end = cmp::max(*cursor.start(), range.end);
1203
1204 let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1205 let end_in_excerpt = excerpt_start + (range.end - cursor.start());
1206 summary.add_assign(
1207 &excerpt
1208 .buffer
1209 .text_summary_for_range(excerpt_start..end_in_excerpt),
1210 );
1211 }
1212 }
1213
1214 summary
1215 }
1216
1217 pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
1218 where
1219 D: TextDimension + Ord + Sub<D, Output = D>,
1220 {
1221 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1222 cursor.seek(&Some(&anchor.excerpt_id), Bias::Left, &());
1223 if cursor.item().is_none() {
1224 cursor.next(&());
1225 }
1226
1227 let mut position = D::from_text_summary(&cursor.start().text);
1228 if let Some(excerpt) = cursor.item() {
1229 if excerpt.id == anchor.excerpt_id {
1230 let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
1231 let buffer_position = anchor.text_anchor.summary::<D>(&excerpt.buffer);
1232 if buffer_position > excerpt_buffer_start {
1233 position.add_assign(&(buffer_position - excerpt_buffer_start));
1234 }
1235 }
1236 }
1237 position
1238 }
1239
1240 pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
1241 where
1242 D: TextDimension + Ord + Sub<D, Output = D>,
1243 I: 'a + IntoIterator<Item = &'a Anchor>,
1244 {
1245 let mut anchors = anchors.into_iter().peekable();
1246 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1247 let mut summaries = Vec::new();
1248 while let Some(anchor) = anchors.peek() {
1249 let excerpt_id = &anchor.excerpt_id;
1250 let excerpt_anchors = iter::from_fn(|| {
1251 let anchor = anchors.peek()?;
1252 if anchor.excerpt_id == *excerpt_id {
1253 Some(&anchors.next().unwrap().text_anchor)
1254 } else {
1255 None
1256 }
1257 });
1258
1259 cursor.seek_forward(&Some(excerpt_id), Bias::Left, &());
1260 if cursor.item().is_none() {
1261 cursor.next(&());
1262 }
1263
1264 let position = D::from_text_summary(&cursor.start().text);
1265 if let Some(excerpt) = cursor.item() {
1266 if excerpt.id == *excerpt_id {
1267 let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
1268 summaries.extend(
1269 excerpt
1270 .buffer
1271 .summaries_for_anchors::<D, _>(excerpt_anchors)
1272 .map(move |summary| {
1273 let mut position = position.clone();
1274 let excerpt_buffer_start = excerpt_buffer_start.clone();
1275 if summary > excerpt_buffer_start {
1276 position.add_assign(&(summary - excerpt_buffer_start));
1277 }
1278 position
1279 }),
1280 );
1281 continue;
1282 }
1283 }
1284
1285 summaries.extend(excerpt_anchors.map(|_| position.clone()));
1286 }
1287
1288 summaries
1289 }
1290
1291 pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
1292 self.anchor_at(position, Bias::Left)
1293 }
1294
1295 pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
1296 self.anchor_at(position, Bias::Right)
1297 }
1298
1299 pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
1300 let offset = position.to_offset(self);
1301 let mut cursor = self.excerpts.cursor::<(usize, Option<&ExcerptId>)>();
1302 cursor.seek(&offset, Bias::Right, &());
1303 if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left {
1304 cursor.prev(&());
1305 }
1306 if let Some(excerpt) = cursor.item() {
1307 let mut overshoot = offset.saturating_sub(cursor.start().0);
1308 if excerpt.has_trailing_newline && offset == cursor.end(&()).0 {
1309 overshoot -= 1;
1310 bias = Bias::Right;
1311 }
1312
1313 let buffer_start = excerpt.range.start.to_offset(&excerpt.buffer);
1314 let text_anchor =
1315 excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
1316 Anchor {
1317 excerpt_id: excerpt.id.clone(),
1318 text_anchor,
1319 }
1320 } else if offset == 0 && bias == Bias::Left {
1321 Anchor::min()
1322 } else {
1323 Anchor::max()
1324 }
1325 }
1326
1327 pub fn anchor_in_excerpt(&self, excerpt_id: ExcerptId, text_anchor: text::Anchor) -> Anchor {
1328 let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1329 cursor.seek(&Some(&excerpt_id), Bias::Left, &());
1330 if let Some(excerpt) = cursor.item() {
1331 if excerpt.id == excerpt_id {
1332 let text_anchor = excerpt.clip_anchor(text_anchor);
1333 drop(cursor);
1334 return Anchor {
1335 excerpt_id,
1336 text_anchor,
1337 };
1338 }
1339 }
1340 panic!("excerpt not found");
1341 }
1342
1343 pub fn parse_count(&self) -> usize {
1344 self.parse_count
1345 }
1346
1347 pub fn enclosing_bracket_ranges<T: ToOffset>(
1348 &self,
1349 range: Range<T>,
1350 ) -> Option<(Range<usize>, Range<usize>)> {
1351 let range = range.start.to_offset(self)..range.end.to_offset(self);
1352
1353 let mut cursor = self.excerpts.cursor::<usize>();
1354 cursor.seek(&range.start, Bias::Right, &());
1355 let start_excerpt = cursor.item();
1356
1357 cursor.seek(&range.end, Bias::Right, &());
1358 let end_excerpt = cursor.item();
1359
1360 start_excerpt
1361 .zip(end_excerpt)
1362 .and_then(|(start_excerpt, end_excerpt)| {
1363 if start_excerpt.id != end_excerpt.id {
1364 return None;
1365 }
1366
1367 let excerpt_buffer_start =
1368 start_excerpt.range.start.to_offset(&start_excerpt.buffer);
1369 let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
1370
1371 let start_in_buffer =
1372 excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
1373 let end_in_buffer =
1374 excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
1375 let (mut start_bracket_range, mut end_bracket_range) = start_excerpt
1376 .buffer
1377 .enclosing_bracket_ranges(start_in_buffer..end_in_buffer)?;
1378
1379 if start_bracket_range.start >= excerpt_buffer_start
1380 && end_bracket_range.end < excerpt_buffer_end
1381 {
1382 start_bracket_range.start =
1383 cursor.start() + (start_bracket_range.start - excerpt_buffer_start);
1384 start_bracket_range.end =
1385 cursor.start() + (start_bracket_range.end - excerpt_buffer_start);
1386 end_bracket_range.start =
1387 cursor.start() + (end_bracket_range.start - excerpt_buffer_start);
1388 end_bracket_range.end =
1389 cursor.start() + (end_bracket_range.end - excerpt_buffer_start);
1390 Some((start_bracket_range, end_bracket_range))
1391 } else {
1392 None
1393 }
1394 })
1395 }
1396
1397 pub fn diagnostics_update_count(&self) -> usize {
1398 self.diagnostics_update_count
1399 }
1400
1401 pub fn language(&self) -> Option<&Arc<Language>> {
1402 self.excerpts
1403 .iter()
1404 .next()
1405 .and_then(|excerpt| excerpt.buffer.language())
1406 }
1407
1408 pub fn is_dirty(&self) -> bool {
1409 self.is_dirty
1410 }
1411
1412 pub fn has_conflict(&self) -> bool {
1413 self.has_conflict
1414 }
1415
1416 pub fn diagnostic_group<'a, O>(
1417 &'a self,
1418 group_id: usize,
1419 ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
1420 where
1421 O: text::FromAnchor + 'a,
1422 {
1423 self.as_singleton()
1424 .into_iter()
1425 .flat_map(move |buffer| buffer.diagnostic_group(group_id))
1426 }
1427
1428 pub fn diagnostics_in_range<'a, T, O>(
1429 &'a self,
1430 range: Range<T>,
1431 ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
1432 where
1433 T: 'a + ToOffset,
1434 O: 'a + text::FromAnchor,
1435 {
1436 self.as_singleton().into_iter().flat_map(move |buffer| {
1437 buffer.diagnostics_in_range(range.start.to_offset(self)..range.end.to_offset(self))
1438 })
1439 }
1440
1441 pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
1442 let range = range.start.to_offset(self)..range.end.to_offset(self);
1443
1444 let mut cursor = self.excerpts.cursor::<usize>();
1445 cursor.seek(&range.start, Bias::Right, &());
1446 let start_excerpt = cursor.item();
1447
1448 cursor.seek(&range.end, Bias::Right, &());
1449 let end_excerpt = cursor.item();
1450
1451 start_excerpt
1452 .zip(end_excerpt)
1453 .and_then(|(start_excerpt, end_excerpt)| {
1454 if start_excerpt.id != end_excerpt.id {
1455 return None;
1456 }
1457
1458 let excerpt_buffer_start =
1459 start_excerpt.range.start.to_offset(&start_excerpt.buffer);
1460 let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
1461
1462 let start_in_buffer =
1463 excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
1464 let end_in_buffer =
1465 excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
1466 let mut ancestor_buffer_range = start_excerpt
1467 .buffer
1468 .range_for_syntax_ancestor(start_in_buffer..end_in_buffer)?;
1469 ancestor_buffer_range.start =
1470 cmp::max(ancestor_buffer_range.start, excerpt_buffer_start);
1471 ancestor_buffer_range.end = cmp::min(ancestor_buffer_range.end, excerpt_buffer_end);
1472
1473 let start = cursor.start() + (ancestor_buffer_range.start - excerpt_buffer_start);
1474 let end = cursor.start() + (ancestor_buffer_range.end - excerpt_buffer_start);
1475 Some(start..end)
1476 })
1477 }
1478
1479 fn buffer_snapshot_for_excerpt<'a>(
1480 &'a self,
1481 excerpt_id: &'a ExcerptId,
1482 ) -> Option<&'a BufferSnapshot> {
1483 let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1484 cursor.seek(&Some(excerpt_id), Bias::Left, &());
1485 if let Some(excerpt) = cursor.item() {
1486 if excerpt.id == *excerpt_id {
1487 return Some(&excerpt.buffer);
1488 }
1489 }
1490 None
1491 }
1492
1493 pub fn remote_selections_in_range<'a>(
1494 &'a self,
1495 range: &'a Range<Anchor>,
1496 ) -> impl 'a + Iterator<Item = (ReplicaId, Selection<Anchor>)> {
1497 let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1498 cursor.seek(&Some(&range.start.excerpt_id), Bias::Left, &());
1499 cursor
1500 .take_while(move |excerpt| excerpt.id <= range.end.excerpt_id)
1501 .flat_map(move |excerpt| {
1502 let mut query_range = excerpt.range.start.clone()..excerpt.range.end.clone();
1503 if excerpt.id == range.start.excerpt_id {
1504 query_range.start = range.start.text_anchor.clone();
1505 }
1506 if excerpt.id == range.end.excerpt_id {
1507 query_range.end = range.end.text_anchor.clone();
1508 }
1509
1510 excerpt
1511 .buffer
1512 .remote_selections_in_range(query_range)
1513 .flat_map(move |(replica_id, selections)| {
1514 selections.map(move |selection| {
1515 let mut start = Anchor {
1516 excerpt_id: excerpt.id.clone(),
1517 text_anchor: selection.start.clone(),
1518 };
1519 let mut end = Anchor {
1520 excerpt_id: excerpt.id.clone(),
1521 text_anchor: selection.end.clone(),
1522 };
1523 if range.start.cmp(&start, self).unwrap().is_gt() {
1524 start = range.start.clone();
1525 }
1526 if range.end.cmp(&end, self).unwrap().is_lt() {
1527 end = range.end.clone();
1528 }
1529
1530 (
1531 replica_id,
1532 Selection {
1533 id: selection.id,
1534 start,
1535 end,
1536 reversed: selection.reversed,
1537 goal: selection.goal,
1538 },
1539 )
1540 })
1541 })
1542 })
1543 }
1544}
1545
1546impl History {
1547 fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
1548 self.transaction_depth += 1;
1549 if self.transaction_depth == 1 {
1550 let id = post_inc(&mut self.next_transaction_id);
1551 self.undo_stack.push(Transaction {
1552 id,
1553 buffer_transactions: Default::default(),
1554 first_edit_at: now,
1555 last_edit_at: now,
1556 });
1557 Some(id)
1558 } else {
1559 None
1560 }
1561 }
1562
1563 fn end_transaction(
1564 &mut self,
1565 now: Instant,
1566 buffer_transactions: HashSet<(usize, TransactionId)>,
1567 ) -> bool {
1568 assert_ne!(self.transaction_depth, 0);
1569 self.transaction_depth -= 1;
1570 if self.transaction_depth == 0 {
1571 if buffer_transactions.is_empty() {
1572 self.undo_stack.pop();
1573 false
1574 } else {
1575 let transaction = self.undo_stack.last_mut().unwrap();
1576 transaction.last_edit_at = now;
1577 transaction.buffer_transactions.extend(buffer_transactions);
1578 true
1579 }
1580 } else {
1581 false
1582 }
1583 }
1584
1585 fn pop_undo(&mut self) -> Option<&Transaction> {
1586 assert_eq!(self.transaction_depth, 0);
1587 if let Some(transaction) = self.undo_stack.pop() {
1588 self.redo_stack.push(transaction);
1589 self.redo_stack.last()
1590 } else {
1591 None
1592 }
1593 }
1594
1595 fn pop_redo(&mut self) -> Option<&Transaction> {
1596 assert_eq!(self.transaction_depth, 0);
1597 if let Some(transaction) = self.redo_stack.pop() {
1598 self.undo_stack.push(transaction);
1599 self.undo_stack.last()
1600 } else {
1601 None
1602 }
1603 }
1604
1605 fn group(&mut self) -> Option<TransactionId> {
1606 let mut new_len = self.undo_stack.len();
1607 let mut transactions = self.undo_stack.iter_mut();
1608
1609 if let Some(mut transaction) = transactions.next_back() {
1610 while let Some(prev_transaction) = transactions.next_back() {
1611 if transaction.first_edit_at - prev_transaction.last_edit_at <= self.group_interval
1612 {
1613 transaction = prev_transaction;
1614 new_len -= 1;
1615 } else {
1616 break;
1617 }
1618 }
1619 }
1620
1621 let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
1622 if let Some(last_transaction) = transactions_to_keep.last_mut() {
1623 if let Some(transaction) = transactions_to_merge.last() {
1624 last_transaction.last_edit_at = transaction.last_edit_at;
1625 }
1626 }
1627
1628 self.undo_stack.truncate(new_len);
1629 self.undo_stack.last().map(|t| t.id)
1630 }
1631}
1632
1633impl Excerpt {
1634 fn new(
1635 id: ExcerptId,
1636 buffer_id: usize,
1637 buffer: BufferSnapshot,
1638 range: Range<text::Anchor>,
1639 has_trailing_newline: bool,
1640 ) -> Self {
1641 Excerpt {
1642 id,
1643 max_buffer_row: range.end.to_point(&buffer).row,
1644 text_summary: buffer.text_summary_for_range::<TextSummary, _>(range.to_offset(&buffer)),
1645 buffer_id,
1646 buffer,
1647 range,
1648 has_trailing_newline,
1649 }
1650 }
1651
1652 fn chunks_in_range<'a>(
1653 &'a self,
1654 range: Range<usize>,
1655 theme: Option<&'a SyntaxTheme>,
1656 ) -> ExcerptChunks<'a> {
1657 let content_start = self.range.start.to_offset(&self.buffer);
1658 let chunks_start = content_start + range.start;
1659 let chunks_end = content_start + cmp::min(range.end, self.text_summary.bytes);
1660
1661 let footer_height = if self.has_trailing_newline
1662 && range.start <= self.text_summary.bytes
1663 && range.end > self.text_summary.bytes
1664 {
1665 1
1666 } else {
1667 0
1668 };
1669
1670 let content_chunks = self.buffer.chunks(chunks_start..chunks_end, theme);
1671
1672 ExcerptChunks {
1673 content_chunks,
1674 footer_height,
1675 }
1676 }
1677
1678 fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
1679 let content_start = self.range.start.to_offset(&self.buffer);
1680 let bytes_start = content_start + range.start;
1681 let bytes_end = content_start + cmp::min(range.end, self.text_summary.bytes);
1682 let footer_height = if self.has_trailing_newline
1683 && range.start <= self.text_summary.bytes
1684 && range.end > self.text_summary.bytes
1685 {
1686 1
1687 } else {
1688 0
1689 };
1690 let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
1691
1692 ExcerptBytes {
1693 content_bytes,
1694 footer_height,
1695 }
1696 }
1697
1698 fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
1699 if text_anchor
1700 .cmp(&self.range.start, &self.buffer)
1701 .unwrap()
1702 .is_lt()
1703 {
1704 self.range.start.clone()
1705 } else if text_anchor
1706 .cmp(&self.range.end, &self.buffer)
1707 .unwrap()
1708 .is_gt()
1709 {
1710 self.range.end.clone()
1711 } else {
1712 text_anchor
1713 }
1714 }
1715}
1716
1717impl fmt::Debug for Excerpt {
1718 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1719 f.debug_struct("Excerpt")
1720 .field("id", &self.id)
1721 .field("buffer_id", &self.buffer_id)
1722 .field("range", &self.range)
1723 .field("text_summary", &self.text_summary)
1724 .field("has_trailing_newline", &self.has_trailing_newline)
1725 .finish()
1726 }
1727}
1728
1729impl sum_tree::Item for Excerpt {
1730 type Summary = ExcerptSummary;
1731
1732 fn summary(&self) -> Self::Summary {
1733 let mut text = self.text_summary.clone();
1734 if self.has_trailing_newline {
1735 text += TextSummary::from("\n");
1736 }
1737 ExcerptSummary {
1738 excerpt_id: self.id.clone(),
1739 max_buffer_row: self.max_buffer_row,
1740 text,
1741 }
1742 }
1743}
1744
1745impl sum_tree::Summary for ExcerptSummary {
1746 type Context = ();
1747
1748 fn add_summary(&mut self, summary: &Self, _: &()) {
1749 debug_assert!(summary.excerpt_id > self.excerpt_id);
1750 self.excerpt_id = summary.excerpt_id.clone();
1751 self.text.add_summary(&summary.text, &());
1752 self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row);
1753 }
1754}
1755
1756impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
1757 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1758 *self += &summary.text;
1759 }
1760}
1761
1762impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
1763 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1764 *self += summary.text.bytes;
1765 }
1766}
1767
1768impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
1769 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
1770 Ord::cmp(self, &cursor_location.text.bytes)
1771 }
1772}
1773
1774impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Option<&'a ExcerptId> {
1775 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
1776 Ord::cmp(self, &Some(&cursor_location.excerpt_id))
1777 }
1778}
1779
1780impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
1781 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1782 *self += summary.text.lines;
1783 }
1784}
1785
1786impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
1787 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1788 *self += summary.text.lines_utf16
1789 }
1790}
1791
1792impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a ExcerptId> {
1793 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1794 *self = Some(&summary.excerpt_id);
1795 }
1796}
1797
1798impl<'a> MultiBufferRows<'a> {
1799 pub fn seek(&mut self, row: u32) {
1800 self.buffer_row_range = 0..0;
1801
1802 self.excerpts
1803 .seek_forward(&Point::new(row, 0), Bias::Right, &());
1804 if self.excerpts.item().is_none() {
1805 self.excerpts.prev(&());
1806
1807 if self.excerpts.item().is_none() && row == 0 {
1808 self.buffer_row_range = 0..1;
1809 return;
1810 }
1811 }
1812
1813 if let Some(excerpt) = self.excerpts.item() {
1814 let overshoot = row - self.excerpts.start().row;
1815 let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer).row;
1816 self.buffer_row_range.start = excerpt_start + overshoot;
1817 self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
1818 }
1819 }
1820}
1821
1822impl<'a> Iterator for MultiBufferRows<'a> {
1823 type Item = Option<u32>;
1824
1825 fn next(&mut self) -> Option<Self::Item> {
1826 loop {
1827 if !self.buffer_row_range.is_empty() {
1828 let row = Some(self.buffer_row_range.start);
1829 self.buffer_row_range.start += 1;
1830 return Some(row);
1831 }
1832 self.excerpts.item()?;
1833 self.excerpts.next(&());
1834 let excerpt = self.excerpts.item()?;
1835 self.buffer_row_range.start = excerpt.range.start.to_point(&excerpt.buffer).row;
1836 self.buffer_row_range.end =
1837 self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
1838 }
1839 }
1840}
1841
1842impl<'a> MultiBufferChunks<'a> {
1843 pub fn offset(&self) -> usize {
1844 self.range.start
1845 }
1846
1847 pub fn seek(&mut self, offset: usize) {
1848 self.range.start = offset;
1849 self.excerpts.seek(&offset, Bias::Right, &());
1850 if let Some(excerpt) = self.excerpts.item() {
1851 self.excerpt_chunks = Some(excerpt.chunks_in_range(
1852 self.range.start - self.excerpts.start()..self.range.end - self.excerpts.start(),
1853 self.theme,
1854 ));
1855 } else {
1856 self.excerpt_chunks = None;
1857 }
1858 }
1859}
1860
1861impl<'a> Iterator for MultiBufferChunks<'a> {
1862 type Item = Chunk<'a>;
1863
1864 fn next(&mut self) -> Option<Self::Item> {
1865 if self.range.is_empty() {
1866 None
1867 } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
1868 self.range.start += chunk.text.len();
1869 Some(chunk)
1870 } else {
1871 self.excerpts.next(&());
1872 let excerpt = self.excerpts.item()?;
1873 self.excerpt_chunks = Some(
1874 excerpt.chunks_in_range(0..self.range.end - self.excerpts.start(), self.theme),
1875 );
1876 self.next()
1877 }
1878 }
1879}
1880
1881impl<'a> MultiBufferBytes<'a> {
1882 fn consume(&mut self, len: usize) {
1883 self.range.start += len;
1884 self.chunk = &self.chunk[len..];
1885
1886 if !self.range.is_empty() && self.chunk.is_empty() {
1887 if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
1888 self.chunk = chunk;
1889 } else {
1890 self.excerpts.next(&());
1891 if let Some(excerpt) = self.excerpts.item() {
1892 let mut excerpt_bytes =
1893 excerpt.bytes_in_range(0..self.range.end - self.excerpts.start());
1894 self.chunk = excerpt_bytes.next().unwrap();
1895 self.excerpt_bytes = Some(excerpt_bytes);
1896 }
1897 }
1898 }
1899 }
1900}
1901
1902impl<'a> Iterator for MultiBufferBytes<'a> {
1903 type Item = &'a [u8];
1904
1905 fn next(&mut self) -> Option<Self::Item> {
1906 let chunk = self.chunk;
1907 if chunk.is_empty() {
1908 None
1909 } else {
1910 self.consume(chunk.len());
1911 Some(chunk)
1912 }
1913 }
1914}
1915
1916impl<'a> io::Read for MultiBufferBytes<'a> {
1917 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1918 let len = cmp::min(buf.len(), self.chunk.len());
1919 buf[..len].copy_from_slice(&self.chunk[..len]);
1920 if len > 0 {
1921 self.consume(len);
1922 }
1923 Ok(len)
1924 }
1925}
1926
1927impl<'a> Iterator for ExcerptBytes<'a> {
1928 type Item = &'a [u8];
1929
1930 fn next(&mut self) -> Option<Self::Item> {
1931 if let Some(chunk) = self.content_bytes.next() {
1932 if !chunk.is_empty() {
1933 return Some(chunk);
1934 }
1935 }
1936
1937 if self.footer_height > 0 {
1938 let result = &NEWLINES[..self.footer_height];
1939 self.footer_height = 0;
1940 return Some(result);
1941 }
1942
1943 None
1944 }
1945}
1946
1947impl<'a> Iterator for ExcerptChunks<'a> {
1948 type Item = Chunk<'a>;
1949
1950 fn next(&mut self) -> Option<Self::Item> {
1951 if let Some(chunk) = self.content_chunks.next() {
1952 return Some(chunk);
1953 }
1954
1955 if self.footer_height > 0 {
1956 let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
1957 self.footer_height = 0;
1958 return Some(Chunk {
1959 text,
1960 ..Default::default()
1961 });
1962 }
1963
1964 None
1965 }
1966}
1967
1968impl ToOffset for Point {
1969 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
1970 snapshot.point_to_offset(*self)
1971 }
1972}
1973
1974impl ToOffset for PointUtf16 {
1975 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
1976 snapshot.point_utf16_to_offset(*self)
1977 }
1978}
1979
1980impl ToOffset for usize {
1981 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
1982 assert!(*self <= snapshot.len(), "offset is out of range");
1983 *self
1984 }
1985}
1986
1987impl ToPoint for usize {
1988 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
1989 snapshot.offset_to_point(*self)
1990 }
1991}
1992
1993impl ToPoint for Point {
1994 fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
1995 *self
1996 }
1997}
1998
1999#[cfg(test)]
2000mod tests {
2001 use super::*;
2002 use gpui::MutableAppContext;
2003 use language::{Buffer, Rope};
2004 use rand::prelude::*;
2005 use std::env;
2006 use text::{Point, RandomCharIter};
2007 use util::test::sample_text;
2008
2009 #[gpui::test]
2010 fn test_singleton_multibuffer(cx: &mut MutableAppContext) {
2011 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
2012 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
2013
2014 let snapshot = multibuffer.read(cx).snapshot(cx);
2015 assert_eq!(snapshot.text(), buffer.read(cx).text());
2016
2017 assert_eq!(
2018 snapshot.buffer_rows(0).collect::<Vec<_>>(),
2019 (0..buffer.read(cx).row_count())
2020 .map(Some)
2021 .collect::<Vec<_>>()
2022 );
2023
2024 buffer.update(cx, |buffer, cx| buffer.edit([1..3], "XXX\n", cx));
2025 let snapshot = multibuffer.read(cx).snapshot(cx);
2026
2027 assert_eq!(snapshot.text(), buffer.read(cx).text());
2028 assert_eq!(
2029 snapshot.buffer_rows(0).collect::<Vec<_>>(),
2030 (0..buffer.read(cx).row_count())
2031 .map(Some)
2032 .collect::<Vec<_>>()
2033 );
2034 }
2035
2036 #[gpui::test]
2037 fn test_excerpt_buffer(cx: &mut MutableAppContext) {
2038 let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
2039 let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
2040 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2041
2042 let subscription = multibuffer.update(cx, |multibuffer, cx| {
2043 let subscription = multibuffer.subscribe();
2044 multibuffer.push_excerpt(
2045 ExcerptProperties {
2046 buffer: &buffer_1,
2047 range: Point::new(1, 2)..Point::new(2, 5),
2048 },
2049 cx,
2050 );
2051 assert_eq!(
2052 subscription.consume().into_inner(),
2053 [Edit {
2054 old: 0..0,
2055 new: 0..10
2056 }]
2057 );
2058
2059 multibuffer.push_excerpt(
2060 ExcerptProperties {
2061 buffer: &buffer_1,
2062 range: Point::new(3, 3)..Point::new(4, 4),
2063 },
2064 cx,
2065 );
2066 multibuffer.push_excerpt(
2067 ExcerptProperties {
2068 buffer: &buffer_2,
2069 range: Point::new(3, 1)..Point::new(3, 3),
2070 },
2071 cx,
2072 );
2073 assert_eq!(
2074 subscription.consume().into_inner(),
2075 [Edit {
2076 old: 10..10,
2077 new: 10..22
2078 }]
2079 );
2080
2081 subscription
2082 });
2083
2084 let snapshot = multibuffer.read(cx).snapshot(cx);
2085 assert_eq!(
2086 snapshot.text(),
2087 concat!(
2088 "bbbb\n", // Preserve newlines
2089 "ccccc\n", //
2090 "ddd\n", //
2091 "eeee\n", //
2092 "jj" //
2093 )
2094 );
2095 assert_eq!(
2096 snapshot.buffer_rows(0).collect::<Vec<_>>(),
2097 [Some(1), Some(2), Some(3), Some(4), Some(3)]
2098 );
2099 assert_eq!(
2100 snapshot.buffer_rows(2).collect::<Vec<_>>(),
2101 [Some(3), Some(4), Some(3)]
2102 );
2103 assert_eq!(snapshot.buffer_rows(4).collect::<Vec<_>>(), [Some(3)]);
2104 assert_eq!(snapshot.buffer_rows(5).collect::<Vec<_>>(), []);
2105
2106 buffer_1.update(cx, |buffer, cx| {
2107 buffer.edit(
2108 [
2109 Point::new(0, 0)..Point::new(0, 0),
2110 Point::new(2, 1)..Point::new(2, 3),
2111 ],
2112 "\n",
2113 cx,
2114 );
2115 });
2116
2117 let snapshot = multibuffer.read(cx).snapshot(cx);
2118 assert_eq!(
2119 snapshot.text(),
2120 concat!(
2121 "bbbb\n", // Preserve newlines
2122 "c\n", //
2123 "cc\n", //
2124 "ddd\n", //
2125 "eeee\n", //
2126 "jj" //
2127 )
2128 );
2129
2130 assert_eq!(
2131 subscription.consume().into_inner(),
2132 [Edit {
2133 old: 6..8,
2134 new: 6..7
2135 }]
2136 );
2137
2138 let snapshot = multibuffer.read(cx).snapshot(cx);
2139 assert_eq!(
2140 snapshot.clip_point(Point::new(0, 5), Bias::Left),
2141 Point::new(0, 4)
2142 );
2143 assert_eq!(
2144 snapshot.clip_point(Point::new(0, 5), Bias::Right),
2145 Point::new(0, 4)
2146 );
2147 assert_eq!(
2148 snapshot.clip_point(Point::new(5, 1), Bias::Right),
2149 Point::new(5, 1)
2150 );
2151 assert_eq!(
2152 snapshot.clip_point(Point::new(5, 2), Bias::Right),
2153 Point::new(5, 2)
2154 );
2155 assert_eq!(
2156 snapshot.clip_point(Point::new(5, 3), Bias::Right),
2157 Point::new(5, 2)
2158 );
2159
2160 let snapshot = multibuffer.update(cx, |multibuffer, cx| {
2161 let buffer_2_excerpt_id = multibuffer.excerpt_ids_for_buffer(&buffer_2)[0].clone();
2162 multibuffer.remove_excerpts(&[buffer_2_excerpt_id], cx);
2163 multibuffer.snapshot(cx)
2164 });
2165
2166 assert_eq!(
2167 snapshot.text(),
2168 concat!(
2169 "bbbb\n", // Preserve newlines
2170 "c\n", //
2171 "cc\n", //
2172 "ddd\n", //
2173 "eeee", //
2174 )
2175 );
2176 }
2177
2178 #[gpui::test]
2179 fn test_empty_excerpt_buffer(cx: &mut MutableAppContext) {
2180 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2181
2182 let snapshot = multibuffer.read(cx).snapshot(cx);
2183 assert_eq!(snapshot.text(), "");
2184 assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), &[Some(0)]);
2185 assert_eq!(snapshot.buffer_rows(1).collect::<Vec<_>>(), &[]);
2186 }
2187
2188 #[gpui::test]
2189 fn test_singleton_multibuffer_anchors(cx: &mut MutableAppContext) {
2190 let buffer = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
2191 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
2192 let old_snapshot = multibuffer.read(cx).snapshot(cx);
2193 buffer.update(cx, |buffer, cx| {
2194 buffer.edit([0..0], "X", cx);
2195 buffer.edit([5..5], "Y", cx);
2196 });
2197 let new_snapshot = multibuffer.read(cx).snapshot(cx);
2198
2199 assert_eq!(old_snapshot.text(), "abcd");
2200 assert_eq!(new_snapshot.text(), "XabcdY");
2201
2202 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
2203 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
2204 assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
2205 assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
2206 }
2207
2208 #[gpui::test]
2209 fn test_multibuffer_anchors(cx: &mut MutableAppContext) {
2210 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
2211 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
2212 let multibuffer = cx.add_model(|cx| {
2213 let mut multibuffer = MultiBuffer::new(0);
2214 multibuffer.push_excerpt(
2215 ExcerptProperties {
2216 buffer: &buffer_1,
2217 range: 0..4,
2218 },
2219 cx,
2220 );
2221 multibuffer.push_excerpt(
2222 ExcerptProperties {
2223 buffer: &buffer_2,
2224 range: 0..5,
2225 },
2226 cx,
2227 );
2228 multibuffer
2229 });
2230 let old_snapshot = multibuffer.read(cx).snapshot(cx);
2231
2232 assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
2233 assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
2234 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
2235 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
2236 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
2237 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
2238
2239 buffer_1.update(cx, |buffer, cx| {
2240 buffer.edit([0..0], "W", cx);
2241 buffer.edit([5..5], "X", cx);
2242 });
2243 buffer_2.update(cx, |buffer, cx| {
2244 buffer.edit([0..0], "Y", cx);
2245 buffer.edit([6..0], "Z", cx);
2246 });
2247 let new_snapshot = multibuffer.read(cx).snapshot(cx);
2248
2249 assert_eq!(old_snapshot.text(), "abcd\nefghi");
2250 assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
2251
2252 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
2253 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
2254 assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
2255 assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
2256 assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
2257 assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
2258 assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
2259 assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
2260 assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
2261 assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
2262 }
2263
2264 #[gpui::test(iterations = 100)]
2265 fn test_random_excerpts(cx: &mut MutableAppContext, mut rng: StdRng) {
2266 let operations = env::var("OPERATIONS")
2267 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2268 .unwrap_or(10);
2269
2270 let mut buffers: Vec<ModelHandle<Buffer>> = Vec::new();
2271 let list = cx.add_model(|_| MultiBuffer::new(0));
2272 let mut excerpt_ids = Vec::new();
2273 let mut expected_excerpts = Vec::<(ModelHandle<Buffer>, Range<text::Anchor>)>::new();
2274 let mut old_versions = Vec::new();
2275
2276 for _ in 0..operations {
2277 match rng.gen_range(0..100) {
2278 0..=19 if !buffers.is_empty() => {
2279 let buffer = buffers.choose(&mut rng).unwrap();
2280 buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
2281 }
2282 20..=29 if !expected_excerpts.is_empty() => {
2283 let ix = rng.gen_range(0..expected_excerpts.len());
2284 let id = excerpt_ids.remove(ix);
2285 let (buffer, range) = expected_excerpts.remove(ix);
2286 let buffer = buffer.read(cx);
2287 log::info!(
2288 "Removing excerpt {}: {:?}",
2289 ix,
2290 buffer
2291 .text_for_range(range.to_offset(&buffer))
2292 .collect::<String>(),
2293 );
2294 list.update(cx, |list, cx| list.remove_excerpts(&[id], cx));
2295 }
2296 _ => {
2297 let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
2298 let base_text = RandomCharIter::new(&mut rng).take(10).collect::<String>();
2299 buffers.push(cx.add_model(|cx| Buffer::new(0, base_text, cx)));
2300 buffers.last().unwrap()
2301 } else {
2302 buffers.choose(&mut rng).unwrap()
2303 };
2304
2305 let buffer = buffer_handle.read(cx);
2306 let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
2307 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
2308 let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
2309 log::info!(
2310 "Pushing excerpt for buffer {}: {:?}[{:?}] = {:?}",
2311 buffer_handle.id(),
2312 buffer.text(),
2313 start_ix..end_ix,
2314 &buffer.text()[start_ix..end_ix]
2315 );
2316
2317 let excerpt_id = list.update(cx, |list, cx| {
2318 list.push_excerpt(
2319 ExcerptProperties {
2320 buffer: &buffer_handle,
2321 range: start_ix..end_ix,
2322 },
2323 cx,
2324 )
2325 });
2326 excerpt_ids.push(excerpt_id);
2327 expected_excerpts.push((buffer_handle.clone(), anchor_range));
2328 }
2329 }
2330
2331 if rng.gen_bool(0.3) {
2332 list.update(cx, |list, cx| {
2333 old_versions.push((list.snapshot(cx), list.subscribe()));
2334 })
2335 }
2336
2337 let snapshot = list.read(cx).snapshot(cx);
2338
2339 let mut excerpt_starts = Vec::new();
2340 let mut expected_text = String::new();
2341 let mut expected_buffer_rows = Vec::new();
2342 for (buffer, range) in &expected_excerpts {
2343 let buffer = buffer.read(cx);
2344 let buffer_range = range.to_offset(buffer);
2345
2346 excerpt_starts.push(TextSummary::from(expected_text.as_str()));
2347 expected_text.extend(buffer.text_for_range(buffer_range.clone()));
2348 expected_text.push('\n');
2349
2350 let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
2351 ..=buffer.offset_to_point(buffer_range.end).row;
2352 for row in buffer_row_range {
2353 expected_buffer_rows.push(Some(row));
2354 }
2355 }
2356 // Remove final trailing newline.
2357 if !expected_excerpts.is_empty() {
2358 expected_text.pop();
2359 }
2360
2361 // Always report one buffer row
2362 if expected_buffer_rows.is_empty() {
2363 expected_buffer_rows.push(Some(0));
2364 }
2365
2366 assert_eq!(snapshot.text(), expected_text);
2367 log::info!("MultiBuffer text: {:?}", expected_text);
2368
2369 assert_eq!(
2370 snapshot.buffer_rows(0).collect::<Vec<_>>(),
2371 expected_buffer_rows,
2372 );
2373
2374 for _ in 0..5 {
2375 let start_row = rng.gen_range(0..=expected_buffer_rows.len());
2376 assert_eq!(
2377 snapshot.buffer_rows(start_row as u32).collect::<Vec<_>>(),
2378 &expected_buffer_rows[start_row..],
2379 "buffer_rows({})",
2380 start_row
2381 );
2382 }
2383
2384 assert_eq!(
2385 snapshot.max_buffer_row(),
2386 expected_buffer_rows
2387 .into_iter()
2388 .filter_map(|r| r)
2389 .max()
2390 .unwrap()
2391 );
2392
2393 let mut excerpt_starts = excerpt_starts.into_iter();
2394 for (buffer, range) in &expected_excerpts {
2395 let buffer_id = buffer.id();
2396 let buffer = buffer.read(cx);
2397 let buffer_range = range.to_offset(buffer);
2398 let buffer_start_point = buffer.offset_to_point(buffer_range.start);
2399 let buffer_start_point_utf16 =
2400 buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
2401
2402 let excerpt_start = excerpt_starts.next().unwrap();
2403 let mut offset = excerpt_start.bytes;
2404 let mut buffer_offset = buffer_range.start;
2405 let mut point = excerpt_start.lines;
2406 let mut buffer_point = buffer_start_point;
2407 let mut point_utf16 = excerpt_start.lines_utf16;
2408 let mut buffer_point_utf16 = buffer_start_point_utf16;
2409 for ch in buffer
2410 .snapshot()
2411 .chunks(buffer_range.clone(), None)
2412 .flat_map(|c| c.text.chars())
2413 {
2414 for _ in 0..ch.len_utf8() {
2415 let left_offset = snapshot.clip_offset(offset, Bias::Left);
2416 let right_offset = snapshot.clip_offset(offset, Bias::Right);
2417 let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
2418 let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
2419 assert_eq!(
2420 left_offset,
2421 excerpt_start.bytes + (buffer_left_offset - buffer_range.start),
2422 "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
2423 offset,
2424 buffer_id,
2425 buffer_offset,
2426 );
2427 assert_eq!(
2428 right_offset,
2429 excerpt_start.bytes + (buffer_right_offset - buffer_range.start),
2430 "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
2431 offset,
2432 buffer_id,
2433 buffer_offset,
2434 );
2435
2436 let left_point = snapshot.clip_point(point, Bias::Left);
2437 let right_point = snapshot.clip_point(point, Bias::Right);
2438 let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
2439 let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
2440 assert_eq!(
2441 left_point,
2442 excerpt_start.lines + (buffer_left_point - buffer_start_point),
2443 "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
2444 point,
2445 buffer_id,
2446 buffer_point,
2447 );
2448 assert_eq!(
2449 right_point,
2450 excerpt_start.lines + (buffer_right_point - buffer_start_point),
2451 "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
2452 point,
2453 buffer_id,
2454 buffer_point,
2455 );
2456
2457 assert_eq!(
2458 snapshot.point_to_offset(left_point),
2459 left_offset,
2460 "point_to_offset({:?})",
2461 left_point,
2462 );
2463 assert_eq!(
2464 snapshot.offset_to_point(left_offset),
2465 left_point,
2466 "offset_to_point({:?})",
2467 left_offset,
2468 );
2469
2470 offset += 1;
2471 buffer_offset += 1;
2472 if ch == '\n' {
2473 point += Point::new(1, 0);
2474 buffer_point += Point::new(1, 0);
2475 } else {
2476 point += Point::new(0, 1);
2477 buffer_point += Point::new(0, 1);
2478 }
2479 }
2480
2481 for _ in 0..ch.len_utf16() {
2482 let left_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Left);
2483 let right_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Right);
2484 let buffer_left_point_utf16 =
2485 buffer.clip_point_utf16(buffer_point_utf16, Bias::Left);
2486 let buffer_right_point_utf16 =
2487 buffer.clip_point_utf16(buffer_point_utf16, Bias::Right);
2488 assert_eq!(
2489 left_point_utf16,
2490 excerpt_start.lines_utf16
2491 + (buffer_left_point_utf16 - buffer_start_point_utf16),
2492 "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
2493 point_utf16,
2494 buffer_id,
2495 buffer_point_utf16,
2496 );
2497 assert_eq!(
2498 right_point_utf16,
2499 excerpt_start.lines_utf16
2500 + (buffer_right_point_utf16 - buffer_start_point_utf16),
2501 "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
2502 point_utf16,
2503 buffer_id,
2504 buffer_point_utf16,
2505 );
2506
2507 if ch == '\n' {
2508 point_utf16 += PointUtf16::new(1, 0);
2509 buffer_point_utf16 += PointUtf16::new(1, 0);
2510 } else {
2511 point_utf16 += PointUtf16::new(0, 1);
2512 buffer_point_utf16 += PointUtf16::new(0, 1);
2513 }
2514 }
2515 }
2516 }
2517
2518 for (row, line) in expected_text.split('\n').enumerate() {
2519 assert_eq!(
2520 snapshot.line_len(row as u32),
2521 line.len() as u32,
2522 "line_len({}).",
2523 row
2524 );
2525 }
2526
2527 let text_rope = Rope::from(expected_text.as_str());
2528 for _ in 0..10 {
2529 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
2530 let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
2531
2532 assert_eq!(
2533 snapshot
2534 .text_for_range(start_ix..end_ix)
2535 .collect::<String>(),
2536 &expected_text[start_ix..end_ix],
2537 "incorrect text for range {:?}",
2538 start_ix..end_ix
2539 );
2540
2541 let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
2542 assert_eq!(
2543 snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
2544 expected_summary,
2545 "incorrect summary for range {:?}",
2546 start_ix..end_ix
2547 );
2548 }
2549
2550 for _ in 0..10 {
2551 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
2552 assert_eq!(
2553 snapshot.reversed_chars_at(end_ix).collect::<String>(),
2554 expected_text[..end_ix].chars().rev().collect::<String>(),
2555 );
2556 }
2557
2558 for _ in 0..10 {
2559 let end_ix = rng.gen_range(0..=text_rope.len());
2560 let start_ix = rng.gen_range(0..=end_ix);
2561 assert_eq!(
2562 snapshot
2563 .bytes_in_range(start_ix..end_ix)
2564 .flatten()
2565 .copied()
2566 .collect::<Vec<_>>(),
2567 expected_text.as_bytes()[start_ix..end_ix].to_vec(),
2568 "bytes_in_range({:?})",
2569 start_ix..end_ix,
2570 );
2571 }
2572 }
2573
2574 let snapshot = list.read(cx).snapshot(cx);
2575 for (old_snapshot, subscription) in old_versions {
2576 let edits = subscription.consume().into_inner();
2577
2578 log::info!(
2579 "applying subscription edits to old text: {:?}: {:?}",
2580 old_snapshot.text(),
2581 edits,
2582 );
2583
2584 let mut text = old_snapshot.text();
2585 for edit in edits {
2586 let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
2587 text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
2588 }
2589 assert_eq!(text.to_string(), snapshot.text());
2590 }
2591 }
2592
2593 #[gpui::test]
2594 fn test_history(cx: &mut MutableAppContext) {
2595 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "1234", cx));
2596 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "5678", cx));
2597 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2598 let group_interval = multibuffer.read(cx).history.group_interval;
2599 multibuffer.update(cx, |multibuffer, cx| {
2600 multibuffer.push_excerpt(
2601 ExcerptProperties {
2602 buffer: &buffer_1,
2603 range: 0..buffer_1.read(cx).len(),
2604 },
2605 cx,
2606 );
2607 multibuffer.push_excerpt(
2608 ExcerptProperties {
2609 buffer: &buffer_2,
2610 range: 0..buffer_2.read(cx).len(),
2611 },
2612 cx,
2613 );
2614 });
2615
2616 let mut now = Instant::now();
2617
2618 multibuffer.update(cx, |multibuffer, cx| {
2619 multibuffer.start_transaction_at(now, cx);
2620 multibuffer.edit(
2621 [
2622 Point::new(0, 0)..Point::new(0, 0),
2623 Point::new(1, 0)..Point::new(1, 0),
2624 ],
2625 "A",
2626 cx,
2627 );
2628 multibuffer.edit(
2629 [
2630 Point::new(0, 1)..Point::new(0, 1),
2631 Point::new(1, 1)..Point::new(1, 1),
2632 ],
2633 "B",
2634 cx,
2635 );
2636 multibuffer.end_transaction_at(now, cx);
2637 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2638
2639 now += 2 * group_interval;
2640 multibuffer.start_transaction_at(now, cx);
2641 multibuffer.edit([2..2], "C", cx);
2642 multibuffer.end_transaction_at(now, cx);
2643 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2644
2645 multibuffer.undo(cx);
2646 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2647
2648 multibuffer.undo(cx);
2649 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
2650
2651 multibuffer.redo(cx);
2652 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2653
2654 multibuffer.redo(cx);
2655 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2656
2657 buffer_1.update(cx, |buffer_1, cx| buffer_1.undo(cx));
2658 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2659
2660 multibuffer.undo(cx);
2661 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
2662
2663 multibuffer.redo(cx);
2664 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2665
2666 multibuffer.redo(cx);
2667 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2668
2669 multibuffer.undo(cx);
2670 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2671
2672 buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
2673 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2674
2675 multibuffer.undo(cx);
2676 assert_eq!(multibuffer.read(cx).text(), "C1234\n5678");
2677 });
2678 }
2679}