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