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