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