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