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