1mod anchor;
2
3pub use anchor::{Anchor, AnchorRangeExt};
4use anyhow::Result;
5use clock::ReplicaId;
6use collections::{HashMap, HashSet};
7use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
8use language::{
9 Buffer, BufferChunks, BufferSnapshot, Chunk, DiagnosticEntry, Event, File, Language, Selection,
10 ToOffset as _, ToPoint as _, TransactionId,
11};
12use std::{
13 cell::{Ref, RefCell},
14 cmp, fmt, io,
15 iter::{self, FromIterator},
16 ops::{Range, Sub},
17 str,
18 sync::Arc,
19 time::{Duration, Instant},
20};
21use sum_tree::{Bias, Cursor, SumTree};
22use text::{
23 locator::Locator,
24 rope::TextDimension,
25 subscription::{Subscription, Topic},
26 AnchorRangeExt as _, Edit, Point, PointUtf16, TextSummary,
27};
28use theme::SyntaxTheme;
29use util::post_inc;
30
31const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize];
32
33pub type ExcerptId = Locator;
34
35pub struct MultiBuffer {
36 snapshot: RefCell<MultiBufferSnapshot>,
37 buffers: RefCell<HashMap<usize, BufferState>>,
38 subscriptions: Topic,
39 singleton: bool,
40 replica_id: ReplicaId,
41 history: History,
42}
43
44struct History {
45 next_transaction_id: usize,
46 undo_stack: Vec<Transaction>,
47 redo_stack: Vec<Transaction>,
48 transaction_depth: usize,
49 group_interval: Duration,
50}
51
52struct Transaction {
53 id: usize,
54 buffer_transactions: HashSet<(usize, text::TransactionId)>,
55 first_edit_at: Instant,
56 last_edit_at: Instant,
57}
58
59pub trait ToOffset: 'static + fmt::Debug {
60 fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
61}
62
63pub trait ToPoint: 'static + fmt::Debug {
64 fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point;
65}
66
67struct BufferState {
68 buffer: ModelHandle<Buffer>,
69 last_version: clock::Global,
70 last_parse_count: usize,
71 last_diagnostics_update_count: usize,
72 excerpts: Vec<ExcerptId>,
73 _subscriptions: [gpui::Subscription; 2],
74}
75
76#[derive(Clone, Default)]
77pub struct MultiBufferSnapshot {
78 excerpts: SumTree<Excerpt>,
79 parse_count: usize,
80 diagnostics_update_count: usize,
81 is_dirty: bool,
82 has_conflict: bool,
83}
84
85pub struct ExcerptProperties<'a, T> {
86 pub buffer: &'a ModelHandle<Buffer>,
87 pub range: Range<T>,
88}
89
90#[derive(Clone)]
91struct Excerpt {
92 id: ExcerptId,
93 buffer_id: usize,
94 buffer: BufferSnapshot,
95 range: Range<text::Anchor>,
96 max_buffer_row: u32,
97 text_summary: TextSummary,
98 has_trailing_newline: bool,
99}
100
101#[derive(Clone, Debug, Default)]
102struct ExcerptSummary {
103 excerpt_id: ExcerptId,
104 max_buffer_row: u32,
105 text: TextSummary,
106}
107
108pub struct MultiBufferRows<'a> {
109 buffer_row_range: Range<u32>,
110 excerpts: Cursor<'a, Excerpt, Point>,
111}
112
113pub struct MultiBufferChunks<'a> {
114 range: Range<usize>,
115 excerpts: Cursor<'a, Excerpt, usize>,
116 excerpt_chunks: Option<ExcerptChunks<'a>>,
117 theme: Option<&'a SyntaxTheme>,
118}
119
120pub struct MultiBufferBytes<'a> {
121 range: Range<usize>,
122 excerpts: Cursor<'a, Excerpt, usize>,
123 excerpt_bytes: Option<ExcerptBytes<'a>>,
124 chunk: &'a [u8],
125}
126
127struct ExcerptChunks<'a> {
128 content_chunks: BufferChunks<'a>,
129 footer_height: usize,
130}
131
132struct ExcerptBytes<'a> {
133 content_bytes: language::rope::Bytes<'a>,
134 footer_height: usize,
135}
136
137impl MultiBuffer {
138 pub fn new(replica_id: ReplicaId) -> Self {
139 Self {
140 snapshot: Default::default(),
141 buffers: Default::default(),
142 subscriptions: Default::default(),
143 singleton: false,
144 replica_id,
145 history: History {
146 next_transaction_id: Default::default(),
147 undo_stack: Default::default(),
148 redo_stack: Default::default(),
149 transaction_depth: 0,
150 group_interval: Duration::from_millis(300),
151 },
152 }
153 }
154
155 pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
156 let mut this = Self::new(buffer.read(cx).replica_id());
157 this.singleton = true;
158 this.push_excerpt(
159 ExcerptProperties {
160 buffer: &buffer,
161 range: text::Anchor::min()..text::Anchor::max(),
162 },
163 cx,
164 );
165 this
166 }
167
168 #[cfg(any(test, feature = "test-support"))]
169 pub fn build_simple(text: &str, cx: &mut gpui::MutableAppContext) -> ModelHandle<Self> {
170 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
171 cx.add_model(|cx| Self::singleton(buffer, cx))
172 }
173
174 #[cfg(any(test, feature = "test-support"))]
175 pub fn build_random(
176 mut rng: &mut impl rand::Rng,
177 cx: &mut gpui::MutableAppContext,
178 ) -> ModelHandle<Self> {
179 use rand::prelude::*;
180 use std::env;
181 use text::RandomCharIter;
182
183 let max_excerpts = env::var("MAX_EXCERPTS")
184 .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))
185 .unwrap_or(5);
186 let excerpts = rng.gen_range(1..=max_excerpts);
187
188 cx.add_model(|cx| {
189 let mut multibuffer = MultiBuffer::new(0);
190 let mut buffers = Vec::new();
191 for _ in 0..excerpts {
192 let buffer_handle = if rng.gen() || buffers.is_empty() {
193 let text = RandomCharIter::new(&mut rng).take(10).collect::<String>();
194 buffers.push(cx.add_model(|cx| Buffer::new(0, text, cx)));
195 let buffer = buffers.last().unwrap();
196 log::info!(
197 "Creating new buffer {} with text: {:?}",
198 buffer.id(),
199 buffer.read(cx).text()
200 );
201 buffers.last().unwrap()
202 } else {
203 buffers.choose(rng).unwrap()
204 };
205
206 let buffer = buffer_handle.read(cx);
207 let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
208 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
209 let header_height = rng.gen_range(0..=5);
210 log::info!(
211 "Inserting excerpt from buffer {} with header height {} and range {:?}: {:?}",
212 buffer_handle.id(),
213 header_height,
214 start_ix..end_ix,
215 &buffer.text()[start_ix..end_ix]
216 );
217
218 multibuffer.push_excerpt(
219 ExcerptProperties {
220 buffer: buffer_handle,
221 range: start_ix..end_ix,
222 },
223 cx,
224 );
225 }
226 multibuffer
227 })
228 }
229
230 pub fn replica_id(&self) -> ReplicaId {
231 self.replica_id
232 }
233
234 pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot {
235 self.sync(cx);
236 self.snapshot.borrow().clone()
237 }
238
239 pub fn read(&self, cx: &AppContext) -> Ref<MultiBufferSnapshot> {
240 self.sync(cx);
241 self.snapshot.borrow()
242 }
243
244 pub fn as_singleton(&self) -> Option<ModelHandle<Buffer>> {
245 if self.singleton {
246 return Some(
247 self.buffers
248 .borrow()
249 .values()
250 .next()
251 .unwrap()
252 .buffer
253 .clone(),
254 );
255 } else {
256 None
257 }
258 }
259
260 pub fn subscribe(&mut self) -> Subscription {
261 self.subscriptions.subscribe()
262 }
263
264 pub fn edit<I, S, T>(&mut self, ranges: I, new_text: T, cx: &mut ModelContext<Self>)
265 where
266 I: IntoIterator<Item = Range<S>>,
267 S: ToOffset,
268 T: Into<String>,
269 {
270 self.edit_internal(ranges, new_text, false, cx)
271 }
272
273 pub fn edit_with_autoindent<I, S, T>(
274 &mut self,
275 ranges: I,
276 new_text: T,
277 cx: &mut ModelContext<Self>,
278 ) where
279 I: IntoIterator<Item = Range<S>>,
280 S: ToOffset,
281 T: Into<String>,
282 {
283 self.edit_internal(ranges, new_text, true, cx)
284 }
285
286 pub fn edit_internal<I, S, T>(
287 &mut self,
288 ranges_iter: I,
289 new_text: T,
290 autoindent: bool,
291 cx: &mut ModelContext<Self>,
292 ) where
293 I: IntoIterator<Item = Range<S>>,
294 S: ToOffset,
295 T: Into<String>,
296 {
297 if let Some(buffer) = self.as_singleton() {
298 let snapshot = self.read(cx);
299 let ranges = ranges_iter
300 .into_iter()
301 .map(|range| range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot));
302 return buffer.update(cx, |buffer, cx| {
303 if autoindent {
304 buffer.edit_with_autoindent(ranges, new_text, cx)
305 } else {
306 buffer.edit(ranges, new_text, cx)
307 }
308 });
309 }
310
311 let snapshot = self.read(cx);
312 let mut buffer_edits: HashMap<usize, Vec<(Range<usize>, bool)>> = Default::default();
313 let mut cursor = snapshot.excerpts.cursor::<usize>();
314 for range in ranges_iter {
315 let start = range.start.to_offset(&snapshot);
316 let end = range.end.to_offset(&snapshot);
317 cursor.seek(&start, Bias::Right, &());
318 if cursor.item().is_none() && start == *cursor.start() {
319 cursor.prev(&());
320 }
321 let start_excerpt = cursor.item().expect("start offset out of bounds");
322 let start_overshoot = start - cursor.start();
323 let buffer_start =
324 start_excerpt.range.start.to_offset(&start_excerpt.buffer) + start_overshoot;
325
326 cursor.seek(&end, Bias::Right, &());
327 if cursor.item().is_none() && end == *cursor.start() {
328 cursor.prev(&());
329 }
330 let end_excerpt = cursor.item().expect("end offset out of bounds");
331 let end_overshoot = end - cursor.start();
332 let buffer_end = end_excerpt.range.start.to_offset(&end_excerpt.buffer) + end_overshoot;
333
334 if start_excerpt.id == end_excerpt.id {
335 buffer_edits
336 .entry(start_excerpt.buffer_id)
337 .or_insert(Vec::new())
338 .push((buffer_start..buffer_end, true));
339 } else {
340 let start_excerpt_range =
341 buffer_start..start_excerpt.range.end.to_offset(&start_excerpt.buffer);
342 let end_excerpt_range =
343 end_excerpt.range.start.to_offset(&end_excerpt.buffer)..buffer_end;
344 buffer_edits
345 .entry(start_excerpt.buffer_id)
346 .or_insert(Vec::new())
347 .push((start_excerpt_range, true));
348 buffer_edits
349 .entry(end_excerpt.buffer_id)
350 .or_insert(Vec::new())
351 .push((end_excerpt_range, false));
352
353 cursor.seek(&start, Bias::Right, &());
354 cursor.next(&());
355 while let Some(excerpt) = cursor.item() {
356 if excerpt.id == end_excerpt.id {
357 break;
358 }
359 buffer_edits
360 .entry(excerpt.buffer_id)
361 .or_insert(Vec::new())
362 .push((excerpt.range.to_offset(&excerpt.buffer), false));
363 cursor.next(&());
364 }
365 }
366 }
367
368 let new_text = new_text.into();
369 for (buffer_id, mut edits) in buffer_edits {
370 edits.sort_unstable_by_key(|(range, _)| range.start);
371 self.buffers.borrow()[&buffer_id]
372 .buffer
373 .update(cx, |buffer, cx| {
374 let mut edits = edits.into_iter().peekable();
375 let mut insertions = Vec::new();
376 let mut deletions = Vec::new();
377 while let Some((mut range, mut is_insertion)) = edits.next() {
378 while let Some((next_range, next_is_insertion)) = edits.peek() {
379 if range.end >= next_range.start {
380 range.end = cmp::max(next_range.end, range.end);
381 is_insertion |= *next_is_insertion;
382 edits.next();
383 } else {
384 break;
385 }
386 }
387
388 if is_insertion {
389 insertions.push(
390 buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
391 );
392 } else if !range.is_empty() {
393 deletions.push(
394 buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
395 );
396 }
397 }
398
399 if autoindent {
400 buffer.edit_with_autoindent(deletions, "", cx);
401 buffer.edit_with_autoindent(insertions, new_text.clone(), cx);
402 } else {
403 buffer.edit(deletions, "", cx);
404 buffer.edit(insertions, new_text.clone(), cx);
405 }
406 })
407 }
408 }
409
410 pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
411 self.start_transaction_at(Instant::now(), cx)
412 }
413
414 pub(crate) fn start_transaction_at(
415 &mut self,
416 now: Instant,
417 cx: &mut ModelContext<Self>,
418 ) -> Option<TransactionId> {
419 if let Some(buffer) = self.as_singleton() {
420 return buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
421 }
422
423 for BufferState { buffer, .. } in self.buffers.borrow().values() {
424 buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
425 }
426 self.history.start_transaction(now)
427 }
428
429 pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
430 self.end_transaction_at(Instant::now(), cx)
431 }
432
433 pub(crate) fn end_transaction_at(
434 &mut self,
435 now: Instant,
436 cx: &mut ModelContext<Self>,
437 ) -> Option<TransactionId> {
438 if let Some(buffer) = self.as_singleton() {
439 return buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx));
440 }
441
442 let mut buffer_transactions = HashSet::default();
443 for BufferState { buffer, .. } in self.buffers.borrow().values() {
444 if let Some(transaction_id) =
445 buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
446 {
447 buffer_transactions.insert((buffer.id(), transaction_id));
448 }
449 }
450
451 if self.history.end_transaction(now, buffer_transactions) {
452 let transaction_id = self.history.group().unwrap();
453 Some(transaction_id)
454 } else {
455 None
456 }
457 }
458
459 pub fn set_active_selections(
460 &mut self,
461 selections: &[Selection<Anchor>],
462 cx: &mut ModelContext<Self>,
463 ) {
464 let mut selections_by_buffer: HashMap<usize, Vec<Selection<text::Anchor>>> =
465 Default::default();
466 let snapshot = self.read(cx);
467 let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();
468 for selection in selections {
469 cursor.seek(&Some(&selection.start.excerpt_id), Bias::Left, &());
470 while let Some(excerpt) = cursor.item() {
471 if excerpt.id > selection.end.excerpt_id {
472 break;
473 }
474
475 let mut start = excerpt.range.start.clone();
476 let mut end = excerpt.range.end.clone();
477 if excerpt.id == selection.start.excerpt_id {
478 start = selection.start.text_anchor.clone();
479 }
480 if excerpt.id == selection.end.excerpt_id {
481 end = selection.end.text_anchor.clone();
482 }
483 selections_by_buffer
484 .entry(excerpt.buffer_id)
485 .or_default()
486 .push(Selection {
487 id: selection.id,
488 start,
489 end,
490 reversed: selection.reversed,
491 goal: selection.goal,
492 });
493
494 cursor.next(&());
495 }
496 }
497
498 for (buffer_id, mut selections) in selections_by_buffer {
499 self.buffers.borrow()[&buffer_id]
500 .buffer
501 .update(cx, |buffer, cx| {
502 selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap());
503 let mut selections = selections.into_iter().peekable();
504 let merged_selections = Arc::from_iter(iter::from_fn(|| {
505 let mut selection = selections.next()?;
506 while let Some(next_selection) = selections.peek() {
507 if selection
508 .end
509 .cmp(&next_selection.start, buffer)
510 .unwrap()
511 .is_ge()
512 {
513 let next_selection = selections.next().unwrap();
514 if next_selection
515 .end
516 .cmp(&selection.end, buffer)
517 .unwrap()
518 .is_ge()
519 {
520 selection.end = next_selection.end;
521 }
522 } else {
523 break;
524 }
525 }
526 Some(selection)
527 }));
528 buffer.set_active_selections(merged_selections, cx);
529 });
530 }
531 }
532
533 pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
534 for buffer in self.buffers.borrow().values() {
535 buffer
536 .buffer
537 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
538 }
539 }
540
541 pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
542 if let Some(buffer) = self.as_singleton() {
543 return buffer.update(cx, |buffer, cx| buffer.undo(cx));
544 }
545
546 while let Some(transaction) = self.history.pop_undo() {
547 let mut undone = false;
548 for (buffer_id, buffer_transaction_id) in &transaction.buffer_transactions {
549 if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(&buffer_id) {
550 undone |= buffer.update(cx, |buf, cx| {
551 buf.undo_transaction(*buffer_transaction_id, cx)
552 });
553 }
554 }
555
556 if undone {
557 return Some(transaction.id);
558 }
559 }
560
561 None
562 }
563
564 pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
565 if let Some(buffer) = self.as_singleton() {
566 return buffer.update(cx, |buffer, cx| buffer.redo(cx));
567 }
568
569 while let Some(transaction) = self.history.pop_redo() {
570 let mut redone = false;
571 for (buffer_id, buffer_transaction_id) in &transaction.buffer_transactions {
572 if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(&buffer_id) {
573 redone |= buffer.update(cx, |buf, cx| {
574 buf.redo_transaction(*buffer_transaction_id, cx)
575 });
576 }
577 }
578
579 if redone {
580 return Some(transaction.id);
581 }
582 }
583
584 None
585 }
586
587 pub fn push_excerpt<O>(
588 &mut self,
589 props: ExcerptProperties<O>,
590 cx: &mut ModelContext<Self>,
591 ) -> ExcerptId
592 where
593 O: text::ToOffset,
594 {
595 self.insert_excerpt_after(&ExcerptId::max(), props, cx)
596 }
597
598 pub fn insert_excerpt_after<O>(
599 &mut self,
600 prev_excerpt_id: &ExcerptId,
601 props: ExcerptProperties<O>,
602 cx: &mut ModelContext<Self>,
603 ) -> ExcerptId
604 where
605 O: text::ToOffset,
606 {
607 assert_eq!(self.history.transaction_depth, 0);
608 self.sync(cx);
609
610 let buffer_snapshot = props.buffer.read(cx).snapshot();
611 let range = buffer_snapshot.anchor_before(&props.range.start)
612 ..buffer_snapshot.anchor_after(&props.range.end);
613 let mut snapshot = self.snapshot.borrow_mut();
614 let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();
615 let mut new_excerpts = cursor.slice(&Some(prev_excerpt_id), Bias::Right, &());
616
617 let mut prev_id = ExcerptId::min();
618 let edit_start = new_excerpts.summary().text.bytes;
619 new_excerpts.update_last(
620 |excerpt| {
621 excerpt.has_trailing_newline = true;
622 prev_id = excerpt.id.clone();
623 },
624 &(),
625 );
626
627 let mut next_id = ExcerptId::max();
628 if let Some(next_excerpt) = cursor.item() {
629 next_id = next_excerpt.id.clone();
630 }
631
632 let id = ExcerptId::between(&prev_id, &next_id);
633
634 let mut buffers = self.buffers.borrow_mut();
635 let buffer_state = buffers
636 .entry(props.buffer.id())
637 .or_insert_with(|| BufferState {
638 last_version: buffer_snapshot.version().clone(),
639 last_parse_count: buffer_snapshot.parse_count(),
640 last_diagnostics_update_count: buffer_snapshot.diagnostics_update_count(),
641 excerpts: Default::default(),
642 _subscriptions: [
643 cx.observe(&props.buffer, |_, _, cx| cx.notify()),
644 cx.subscribe(&props.buffer, Self::on_buffer_event),
645 ],
646 buffer: props.buffer.clone(),
647 });
648 if let Err(ix) = buffer_state.excerpts.binary_search(&id) {
649 buffer_state.excerpts.insert(ix, id.clone());
650 }
651
652 let excerpt = Excerpt::new(
653 id.clone(),
654 props.buffer.id(),
655 buffer_snapshot,
656 range,
657 cursor.item().is_some(),
658 );
659 new_excerpts.push(excerpt, &());
660 let edit_end = new_excerpts.summary().text.bytes;
661
662 new_excerpts.push_tree(cursor.suffix(&()), &());
663 drop(cursor);
664 snapshot.excerpts = new_excerpts;
665
666 self.subscriptions.publish_mut([Edit {
667 old: edit_start..edit_start,
668 new: edit_start..edit_end,
669 }]);
670
671 cx.notify();
672 id
673 }
674
675 pub fn excerpt_ids_for_buffer(&self, buffer: &ModelHandle<Buffer>) -> Vec<ExcerptId> {
676 self.buffers
677 .borrow()
678 .get(&buffer.id())
679 .map_or(Vec::new(), |state| state.excerpts.clone())
680 }
681
682 pub fn remove_excerpts<'a>(
683 &mut self,
684 excerpt_ids: impl IntoIterator<Item = &'a ExcerptId>,
685 cx: &mut ModelContext<Self>,
686 ) {
687 let mut buffers = self.buffers.borrow_mut();
688 let mut snapshot = self.snapshot.borrow_mut();
689 let mut new_excerpts = SumTree::new();
690 let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>();
691 let mut edits = Vec::new();
692 let mut excerpt_ids = excerpt_ids.into_iter().peekable();
693
694 while let Some(mut excerpt_id) = excerpt_ids.next() {
695 // Seek to the next excerpt to remove, preserving any preceding excerpts.
696 new_excerpts.push_tree(cursor.slice(&Some(excerpt_id), Bias::Left, &()), &());
697 if let Some(mut excerpt) = cursor.item() {
698 if excerpt.id != *excerpt_id {
699 continue;
700 }
701 let mut old_start = cursor.start().1;
702
703 // Skip over the removed excerpt.
704 loop {
705 if let Some(buffer_state) = buffers.get_mut(&excerpt.buffer_id) {
706 buffer_state.excerpts.retain(|id| id != excerpt_id);
707 if buffer_state.excerpts.is_empty() {
708 buffers.remove(&excerpt.buffer_id);
709 }
710 }
711 cursor.next(&());
712
713 // Skip over any subsequent excerpts that are also removed.
714 if let Some(&next_excerpt_id) = excerpt_ids.peek() {
715 if let Some(next_excerpt) = cursor.item() {
716 if next_excerpt.id == *next_excerpt_id {
717 excerpt = next_excerpt;
718 excerpt_id = excerpt_ids.next().unwrap();
719 continue;
720 }
721 }
722 }
723
724 break;
725 }
726
727 // When removing the last excerpt, remove the trailing newline from
728 // the previous excerpt.
729 if cursor.item().is_none() && old_start > 0 {
730 old_start -= 1;
731 new_excerpts.update_last(|e| e.has_trailing_newline = false, &());
732 }
733
734 // Push an edit for the removal of this run of excerpts.
735 let old_end = cursor.start().1;
736 let new_start = new_excerpts.summary().text.bytes;
737 edits.push(Edit {
738 old: old_start..old_end,
739 new: new_start..new_start,
740 });
741 }
742 }
743 new_excerpts.push_tree(cursor.suffix(&()), &());
744 drop(cursor);
745 snapshot.excerpts = new_excerpts;
746 self.subscriptions.publish_mut(edits);
747 cx.notify();
748 }
749
750 fn on_buffer_event(
751 &mut self,
752 _: ModelHandle<Buffer>,
753 event: &Event,
754 cx: &mut ModelContext<Self>,
755 ) {
756 cx.emit(event.clone());
757 }
758
759 pub fn save(&mut self, cx: &mut ModelContext<Self>) -> Result<Task<Result<()>>> {
760 let mut save_tasks = Vec::new();
761 for BufferState { buffer, .. } in self.buffers.borrow().values() {
762 save_tasks.push(buffer.update(cx, |buffer, cx| buffer.save(cx))?);
763 }
764
765 Ok(cx.spawn(|_, _| async move {
766 for save in save_tasks {
767 save.await?;
768 }
769 Ok(())
770 }))
771 }
772
773 pub fn language<'a>(&self, cx: &'a AppContext) -> Option<&'a Arc<Language>> {
774 self.buffers
775 .borrow()
776 .values()
777 .next()
778 .and_then(|state| state.buffer.read(cx).language())
779 }
780
781 pub fn file<'a>(&self, cx: &'a AppContext) -> Option<&'a dyn File> {
782 self.as_singleton()?.read(cx).file()
783 }
784
785 #[cfg(test)]
786 pub fn is_parsing(&self, cx: &AppContext) -> bool {
787 self.as_singleton().unwrap().read(cx).is_parsing()
788 }
789
790 fn sync(&self, cx: &AppContext) {
791 let mut snapshot = self.snapshot.borrow_mut();
792 let mut excerpts_to_edit = Vec::new();
793 let mut reparsed = false;
794 let mut diagnostics_updated = false;
795 let mut is_dirty = false;
796 let mut has_conflict = false;
797 let mut buffers = self.buffers.borrow_mut();
798 for buffer_state in buffers.values_mut() {
799 let buffer = buffer_state.buffer.read(cx);
800 let version = buffer.version();
801 let parse_count = buffer.parse_count();
802 let diagnostics_update_count = buffer.diagnostics_update_count();
803
804 let buffer_edited = version.gt(&buffer_state.last_version);
805 let buffer_reparsed = parse_count > buffer_state.last_parse_count;
806 let buffer_diagnostics_updated =
807 diagnostics_update_count > buffer_state.last_diagnostics_update_count;
808 if buffer_edited || buffer_reparsed || buffer_diagnostics_updated {
809 buffer_state.last_version = version;
810 buffer_state.last_parse_count = parse_count;
811 buffer_state.last_diagnostics_update_count = diagnostics_update_count;
812 excerpts_to_edit.extend(
813 buffer_state
814 .excerpts
815 .iter()
816 .map(|excerpt_id| (excerpt_id, buffer_state.buffer.clone(), buffer_edited)),
817 );
818 }
819
820 reparsed |= buffer_reparsed;
821 diagnostics_updated |= buffer_diagnostics_updated;
822 is_dirty |= buffer.is_dirty();
823 has_conflict |= buffer.has_conflict();
824 }
825 if reparsed {
826 snapshot.parse_count += 1;
827 }
828 if diagnostics_updated {
829 snapshot.diagnostics_update_count += 1;
830 }
831 snapshot.is_dirty = is_dirty;
832 snapshot.has_conflict = has_conflict;
833
834 excerpts_to_edit.sort_unstable_by_key(|(excerpt_id, _, _)| *excerpt_id);
835
836 let mut edits = Vec::new();
837 let mut new_excerpts = SumTree::new();
838 let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>();
839
840 for (id, buffer, buffer_edited) in excerpts_to_edit {
841 new_excerpts.push_tree(cursor.slice(&Some(id), Bias::Left, &()), &());
842 let old_excerpt = cursor.item().unwrap();
843 let buffer_id = buffer.id();
844 let buffer = buffer.read(cx);
845
846 let mut new_excerpt;
847 if buffer_edited {
848 edits.extend(
849 buffer
850 .edits_since_in_range::<usize>(
851 old_excerpt.buffer.version(),
852 old_excerpt.range.clone(),
853 )
854 .map(|mut edit| {
855 let excerpt_old_start = cursor.start().1;
856 let excerpt_new_start = new_excerpts.summary().text.bytes;
857 edit.old.start += excerpt_old_start;
858 edit.old.end += excerpt_old_start;
859 edit.new.start += excerpt_new_start;
860 edit.new.end += excerpt_new_start;
861 edit
862 }),
863 );
864
865 new_excerpt = Excerpt::new(
866 id.clone(),
867 buffer_id,
868 buffer.snapshot(),
869 old_excerpt.range.clone(),
870 old_excerpt.has_trailing_newline,
871 );
872 } else {
873 new_excerpt = old_excerpt.clone();
874 new_excerpt.buffer = buffer.snapshot();
875 }
876
877 new_excerpts.push(new_excerpt, &());
878 cursor.next(&());
879 }
880 new_excerpts.push_tree(cursor.suffix(&()), &());
881
882 drop(cursor);
883 snapshot.excerpts = new_excerpts;
884
885 self.subscriptions.publish(edits);
886 }
887}
888
889#[cfg(any(test, feature = "test-support"))]
890impl MultiBuffer {
891 pub fn randomly_edit(
892 &mut self,
893 rng: &mut impl rand::Rng,
894 count: usize,
895 cx: &mut ModelContext<Self>,
896 ) {
897 use text::RandomCharIter;
898
899 let snapshot = self.read(cx);
900 let mut old_ranges: Vec<Range<usize>> = Vec::new();
901 for _ in 0..count {
902 let last_end = old_ranges.last().map_or(0, |last_range| last_range.end + 1);
903 if last_end > snapshot.len() {
904 break;
905 }
906 let end_ix = snapshot.clip_offset(rng.gen_range(0..=last_end), Bias::Right);
907 let start_ix = snapshot.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
908 old_ranges.push(start_ix..end_ix);
909 }
910 let new_text_len = rng.gen_range(0..10);
911 let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
912 log::info!("mutating multi-buffer at {:?}: {:?}", old_ranges, new_text);
913 drop(snapshot);
914
915 self.edit(old_ranges.iter().cloned(), new_text.as_str(), cx);
916 }
917}
918
919impl Entity for MultiBuffer {
920 type Event = language::Event;
921}
922
923impl MultiBufferSnapshot {
924 pub fn text(&self) -> String {
925 self.chunks(0..self.len(), None)
926 .map(|chunk| chunk.text)
927 .collect()
928 }
929
930 pub fn reversed_chars_at<'a, T: ToOffset>(
931 &'a self,
932 position: T,
933 ) -> impl Iterator<Item = char> + 'a {
934 let mut offset = position.to_offset(self);
935 let mut cursor = self.excerpts.cursor::<usize>();
936 cursor.seek(&offset, Bias::Left, &());
937 let mut excerpt_chunks = cursor.item().map(|excerpt| {
938 let end_before_footer = cursor.start() + excerpt.text_summary.bytes;
939 let start = excerpt.range.start.to_offset(&excerpt.buffer);
940 let end = start + (cmp::min(offset, end_before_footer) - cursor.start());
941 excerpt.buffer.reversed_chunks_in_range(start..end)
942 });
943 iter::from_fn(move || {
944 if offset == *cursor.start() {
945 cursor.prev(&());
946 let excerpt = cursor.item()?;
947 excerpt_chunks = Some(
948 excerpt
949 .buffer
950 .reversed_chunks_in_range(excerpt.range.clone()),
951 );
952 }
953
954 let excerpt = cursor.item().unwrap();
955 if offset == cursor.end(&()) && excerpt.has_trailing_newline {
956 offset -= 1;
957 Some("\n")
958 } else {
959 let chunk = excerpt_chunks.as_mut().unwrap().next().unwrap();
960 offset -= chunk.len();
961 Some(chunk)
962 }
963 })
964 .flat_map(|c| c.chars().rev())
965 }
966
967 pub fn chars_at<'a, T: ToOffset>(&'a self, position: T) -> impl Iterator<Item = char> + 'a {
968 let offset = position.to_offset(self);
969 self.text_for_range(offset..self.len())
970 .flat_map(|chunk| chunk.chars())
971 }
972
973 pub fn text_for_range<'a, T: ToOffset>(
974 &'a self,
975 range: Range<T>,
976 ) -> impl Iterator<Item = &'a str> {
977 self.chunks(range, None).map(|chunk| chunk.text)
978 }
979
980 pub fn is_line_blank(&self, row: u32) -> bool {
981 self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row)))
982 .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
983 }
984
985 pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
986 where
987 T: ToOffset,
988 {
989 let position = position.to_offset(self);
990 position == self.clip_offset(position, Bias::Left)
991 && self
992 .bytes_in_range(position..self.len())
993 .flatten()
994 .copied()
995 .take(needle.len())
996 .eq(needle.bytes())
997 }
998
999 fn as_singleton(&self) -> Option<&BufferSnapshot> {
1000 let mut excerpts = self.excerpts.iter();
1001 let buffer = excerpts.next().map(|excerpt| &excerpt.buffer);
1002 if excerpts.next().is_none() {
1003 buffer
1004 } else {
1005 None
1006 }
1007 }
1008
1009 pub fn len(&self) -> usize {
1010 self.excerpts.summary().text.bytes
1011 }
1012
1013 pub fn max_buffer_row(&self) -> u32 {
1014 self.excerpts.summary().max_buffer_row
1015 }
1016
1017 pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
1018 let mut cursor = self.excerpts.cursor::<usize>();
1019 cursor.seek(&offset, Bias::Right, &());
1020 let overshoot = if let Some(excerpt) = cursor.item() {
1021 let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1022 let buffer_offset = excerpt
1023 .buffer
1024 .clip_offset(excerpt_start + (offset - cursor.start()), bias);
1025 buffer_offset.saturating_sub(excerpt_start)
1026 } else {
1027 0
1028 };
1029 cursor.start() + overshoot
1030 }
1031
1032 pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
1033 let mut cursor = self.excerpts.cursor::<Point>();
1034 cursor.seek(&point, Bias::Right, &());
1035 let overshoot = if let Some(excerpt) = cursor.item() {
1036 let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
1037 let buffer_point = excerpt
1038 .buffer
1039 .clip_point(excerpt_start + (point - cursor.start()), bias);
1040 buffer_point.saturating_sub(excerpt_start)
1041 } else {
1042 Point::zero()
1043 };
1044 *cursor.start() + overshoot
1045 }
1046
1047 pub fn clip_point_utf16(&self, point: PointUtf16, bias: Bias) -> PointUtf16 {
1048 let mut cursor = self.excerpts.cursor::<PointUtf16>();
1049 cursor.seek(&point, Bias::Right, &());
1050 let overshoot = if let Some(excerpt) = cursor.item() {
1051 let excerpt_start = excerpt
1052 .buffer
1053 .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
1054 let buffer_point = excerpt
1055 .buffer
1056 .clip_point_utf16(excerpt_start + (point - cursor.start()), bias);
1057 buffer_point.saturating_sub(excerpt_start)
1058 } else {
1059 PointUtf16::zero()
1060 };
1061 *cursor.start() + overshoot
1062 }
1063
1064 pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> MultiBufferBytes<'a> {
1065 let range = range.start.to_offset(self)..range.end.to_offset(self);
1066 let mut excerpts = self.excerpts.cursor::<usize>();
1067 excerpts.seek(&range.start, Bias::Right, &());
1068
1069 let mut chunk = &[][..];
1070 let excerpt_bytes = if let Some(excerpt) = excerpts.item() {
1071 let mut excerpt_bytes = excerpt
1072 .bytes_in_range(range.start - excerpts.start()..range.end - excerpts.start());
1073 chunk = excerpt_bytes.next().unwrap_or(&[][..]);
1074 Some(excerpt_bytes)
1075 } else {
1076 None
1077 };
1078
1079 MultiBufferBytes {
1080 range,
1081 excerpts,
1082 excerpt_bytes,
1083 chunk,
1084 }
1085 }
1086
1087 pub fn buffer_rows<'a>(&'a self, start_row: u32) -> MultiBufferRows<'a> {
1088 let mut result = MultiBufferRows {
1089 buffer_row_range: 0..0,
1090 excerpts: self.excerpts.cursor(),
1091 };
1092 result.seek(start_row);
1093 result
1094 }
1095
1096 pub fn chunks<'a, T: ToOffset>(
1097 &'a self,
1098 range: Range<T>,
1099 theme: Option<&'a SyntaxTheme>,
1100 ) -> MultiBufferChunks<'a> {
1101 let range = range.start.to_offset(self)..range.end.to_offset(self);
1102 let mut chunks = MultiBufferChunks {
1103 range: range.clone(),
1104 excerpts: self.excerpts.cursor(),
1105 excerpt_chunks: None,
1106 theme,
1107 };
1108 chunks.seek(range.start);
1109 chunks
1110 }
1111
1112 pub fn offset_to_point(&self, offset: usize) -> Point {
1113 let mut cursor = self.excerpts.cursor::<(usize, Point)>();
1114 cursor.seek(&offset, Bias::Right, &());
1115 if let Some(excerpt) = cursor.item() {
1116 let (start_offset, start_point) = cursor.start();
1117 let overshoot = offset - start_offset;
1118 let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1119 let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
1120 let buffer_point = excerpt
1121 .buffer
1122 .offset_to_point(excerpt_start_offset + overshoot);
1123 *start_point + (buffer_point - excerpt_start_point)
1124 } else {
1125 self.excerpts.summary().text.lines
1126 }
1127 }
1128
1129 pub fn point_to_offset(&self, point: Point) -> usize {
1130 let mut cursor = self.excerpts.cursor::<(Point, usize)>();
1131 cursor.seek(&point, Bias::Right, &());
1132 if let Some(excerpt) = cursor.item() {
1133 let (start_point, start_offset) = cursor.start();
1134 let overshoot = point - start_point;
1135 let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1136 let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
1137 let buffer_offset = excerpt
1138 .buffer
1139 .point_to_offset(excerpt_start_point + overshoot);
1140 *start_offset + buffer_offset - excerpt_start_offset
1141 } else {
1142 self.excerpts.summary().text.bytes
1143 }
1144 }
1145
1146 pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
1147 let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>();
1148 cursor.seek(&point, Bias::Right, &());
1149 if let Some(excerpt) = cursor.item() {
1150 let (start_point, start_offset) = cursor.start();
1151 let overshoot = point - start_point;
1152 let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1153 let excerpt_start_point = excerpt
1154 .buffer
1155 .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
1156 let buffer_offset = excerpt
1157 .buffer
1158 .point_utf16_to_offset(excerpt_start_point + overshoot);
1159 *start_offset + (buffer_offset - excerpt_start_offset)
1160 } else {
1161 self.excerpts.summary().text.bytes
1162 }
1163 }
1164
1165 pub fn indent_column_for_line(&self, row: u32) -> u32 {
1166 if let Some((buffer, range)) = self.buffer_line_for_row(row) {
1167 buffer
1168 .indent_column_for_line(range.start.row)
1169 .min(range.end.column)
1170 .saturating_sub(range.start.column)
1171 } else {
1172 0
1173 }
1174 }
1175
1176 pub fn line_len(&self, row: u32) -> u32 {
1177 if let Some((_, range)) = self.buffer_line_for_row(row) {
1178 range.end.column - range.start.column
1179 } else {
1180 0
1181 }
1182 }
1183
1184 fn buffer_line_for_row(&self, row: u32) -> Option<(&BufferSnapshot, Range<Point>)> {
1185 let mut cursor = self.excerpts.cursor::<Point>();
1186 cursor.seek(&Point::new(row, 0), Bias::Right, &());
1187 if let Some(excerpt) = cursor.item() {
1188 let overshoot = row - cursor.start().row;
1189 let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
1190 let excerpt_end = excerpt.range.end.to_point(&excerpt.buffer);
1191 let buffer_row = excerpt_start.row + overshoot;
1192 let line_start = Point::new(buffer_row, 0);
1193 let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
1194 return Some((
1195 &excerpt.buffer,
1196 line_start.max(excerpt_start)..line_end.min(excerpt_end),
1197 ));
1198 }
1199 None
1200 }
1201
1202 pub fn max_point(&self) -> Point {
1203 self.text_summary().lines
1204 }
1205
1206 pub fn text_summary(&self) -> TextSummary {
1207 self.excerpts.summary().text
1208 }
1209
1210 pub fn text_summary_for_range<'a, D, O>(&'a self, range: Range<O>) -> D
1211 where
1212 D: TextDimension,
1213 O: ToOffset,
1214 {
1215 let mut summary = D::default();
1216 let mut range = range.start.to_offset(self)..range.end.to_offset(self);
1217 let mut cursor = self.excerpts.cursor::<usize>();
1218 cursor.seek(&range.start, Bias::Right, &());
1219 if let Some(excerpt) = cursor.item() {
1220 let mut end_before_newline = cursor.end(&());
1221 if excerpt.has_trailing_newline {
1222 end_before_newline -= 1;
1223 }
1224
1225 let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1226 let start_in_excerpt = excerpt_start + (range.start - cursor.start());
1227 let end_in_excerpt =
1228 excerpt_start + (cmp::min(end_before_newline, range.end) - cursor.start());
1229 summary.add_assign(
1230 &excerpt
1231 .buffer
1232 .text_summary_for_range(start_in_excerpt..end_in_excerpt),
1233 );
1234
1235 if range.end > end_before_newline {
1236 summary.add_assign(&D::from_text_summary(&TextSummary {
1237 bytes: 1,
1238 lines: Point::new(1 as u32, 0),
1239 lines_utf16: PointUtf16::new(1 as u32, 0),
1240 first_line_chars: 0,
1241 last_line_chars: 0,
1242 longest_row: 0,
1243 longest_row_chars: 0,
1244 }));
1245 }
1246
1247 cursor.next(&());
1248 }
1249
1250 if range.end > *cursor.start() {
1251 summary.add_assign(&D::from_text_summary(&cursor.summary::<_, TextSummary>(
1252 &range.end,
1253 Bias::Right,
1254 &(),
1255 )));
1256 if let Some(excerpt) = cursor.item() {
1257 range.end = cmp::max(*cursor.start(), range.end);
1258
1259 let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1260 let end_in_excerpt = excerpt_start + (range.end - cursor.start());
1261 summary.add_assign(
1262 &excerpt
1263 .buffer
1264 .text_summary_for_range(excerpt_start..end_in_excerpt),
1265 );
1266 }
1267 }
1268
1269 summary
1270 }
1271
1272 pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
1273 where
1274 D: TextDimension + Ord + Sub<D, Output = D>,
1275 {
1276 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1277 cursor.seek(&Some(&anchor.excerpt_id), Bias::Left, &());
1278 if cursor.item().is_none() {
1279 cursor.next(&());
1280 }
1281
1282 let mut position = D::from_text_summary(&cursor.start().text);
1283 if let Some(excerpt) = cursor.item() {
1284 if excerpt.id == anchor.excerpt_id {
1285 let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
1286 let buffer_position = anchor.text_anchor.summary::<D>(&excerpt.buffer);
1287 if buffer_position > excerpt_buffer_start {
1288 position.add_assign(&(buffer_position - excerpt_buffer_start));
1289 }
1290 }
1291 }
1292 position
1293 }
1294
1295 pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
1296 where
1297 D: TextDimension + Ord + Sub<D, Output = D>,
1298 I: 'a + IntoIterator<Item = &'a Anchor>,
1299 {
1300 let mut anchors = anchors.into_iter().peekable();
1301 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1302 let mut summaries = Vec::new();
1303 while let Some(anchor) = anchors.peek() {
1304 let excerpt_id = &anchor.excerpt_id;
1305 let excerpt_anchors = iter::from_fn(|| {
1306 let anchor = anchors.peek()?;
1307 if anchor.excerpt_id == *excerpt_id {
1308 Some(&anchors.next().unwrap().text_anchor)
1309 } else {
1310 None
1311 }
1312 });
1313
1314 cursor.seek_forward(&Some(excerpt_id), Bias::Left, &());
1315 if cursor.item().is_none() {
1316 cursor.next(&());
1317 }
1318
1319 let position = D::from_text_summary(&cursor.start().text);
1320 if let Some(excerpt) = cursor.item() {
1321 if excerpt.id == *excerpt_id {
1322 let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
1323 summaries.extend(
1324 excerpt
1325 .buffer
1326 .summaries_for_anchors::<D, _>(excerpt_anchors)
1327 .map(move |summary| {
1328 let mut position = position.clone();
1329 let excerpt_buffer_start = excerpt_buffer_start.clone();
1330 if summary > excerpt_buffer_start {
1331 position.add_assign(&(summary - excerpt_buffer_start));
1332 }
1333 position
1334 }),
1335 );
1336 continue;
1337 }
1338 }
1339
1340 summaries.extend(excerpt_anchors.map(|_| position.clone()));
1341 }
1342
1343 summaries
1344 }
1345
1346 pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
1347 self.anchor_at(position, Bias::Left)
1348 }
1349
1350 pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
1351 self.anchor_at(position, Bias::Right)
1352 }
1353
1354 pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
1355 let offset = position.to_offset(self);
1356 let mut cursor = self.excerpts.cursor::<(usize, Option<&ExcerptId>)>();
1357 cursor.seek(&offset, Bias::Right, &());
1358 if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left {
1359 cursor.prev(&());
1360 }
1361 if let Some(excerpt) = cursor.item() {
1362 let mut overshoot = offset.saturating_sub(cursor.start().0);
1363 if excerpt.has_trailing_newline && offset == cursor.end(&()).0 {
1364 overshoot -= 1;
1365 bias = Bias::Right;
1366 }
1367
1368 let buffer_start = excerpt.range.start.to_offset(&excerpt.buffer);
1369 let text_anchor =
1370 excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
1371 Anchor {
1372 excerpt_id: excerpt.id.clone(),
1373 text_anchor,
1374 }
1375 } else if offset == 0 && bias == Bias::Left {
1376 Anchor::min()
1377 } else {
1378 Anchor::max()
1379 }
1380 }
1381
1382 pub fn anchor_in_excerpt(&self, excerpt_id: ExcerptId, text_anchor: text::Anchor) -> Anchor {
1383 let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1384 cursor.seek(&Some(&excerpt_id), Bias::Left, &());
1385 if let Some(excerpt) = cursor.item() {
1386 if excerpt.id == excerpt_id {
1387 let text_anchor = excerpt.clip_anchor(text_anchor);
1388 drop(cursor);
1389 return Anchor {
1390 excerpt_id,
1391 text_anchor,
1392 };
1393 }
1394 }
1395 panic!("excerpt not found");
1396 }
1397
1398 pub fn range_contains_excerpt_boundary<T: ToOffset>(&self, range: Range<T>) -> bool {
1399 let start = range.start.to_offset(self);
1400 let end = range.end.to_offset(self);
1401 let mut cursor = self.excerpts.cursor::<(usize, Option<&ExcerptId>)>();
1402 cursor.seek(&start, Bias::Right, &());
1403 let start_id = cursor
1404 .item()
1405 .or_else(|| cursor.prev_item())
1406 .map(|excerpt| &excerpt.id);
1407 cursor.seek_forward(&end, Bias::Right, &());
1408 let end_id = cursor
1409 .item()
1410 .or_else(|| cursor.prev_item())
1411 .map(|excerpt| &excerpt.id);
1412 start_id != end_id
1413 }
1414
1415 pub fn parse_count(&self) -> usize {
1416 self.parse_count
1417 }
1418
1419 pub fn enclosing_bracket_ranges<T: ToOffset>(
1420 &self,
1421 range: Range<T>,
1422 ) -> Option<(Range<usize>, Range<usize>)> {
1423 let range = range.start.to_offset(self)..range.end.to_offset(self);
1424
1425 let mut cursor = self.excerpts.cursor::<usize>();
1426 cursor.seek(&range.start, Bias::Right, &());
1427 let start_excerpt = cursor.item();
1428
1429 cursor.seek(&range.end, Bias::Right, &());
1430 let end_excerpt = cursor.item();
1431
1432 start_excerpt
1433 .zip(end_excerpt)
1434 .and_then(|(start_excerpt, end_excerpt)| {
1435 if start_excerpt.id != end_excerpt.id {
1436 return None;
1437 }
1438
1439 let excerpt_buffer_start =
1440 start_excerpt.range.start.to_offset(&start_excerpt.buffer);
1441 let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
1442
1443 let start_in_buffer =
1444 excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
1445 let end_in_buffer =
1446 excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
1447 let (mut start_bracket_range, mut end_bracket_range) = start_excerpt
1448 .buffer
1449 .enclosing_bracket_ranges(start_in_buffer..end_in_buffer)?;
1450
1451 if start_bracket_range.start >= excerpt_buffer_start
1452 && end_bracket_range.end < excerpt_buffer_end
1453 {
1454 start_bracket_range.start =
1455 cursor.start() + (start_bracket_range.start - excerpt_buffer_start);
1456 start_bracket_range.end =
1457 cursor.start() + (start_bracket_range.end - excerpt_buffer_start);
1458 end_bracket_range.start =
1459 cursor.start() + (end_bracket_range.start - excerpt_buffer_start);
1460 end_bracket_range.end =
1461 cursor.start() + (end_bracket_range.end - excerpt_buffer_start);
1462 Some((start_bracket_range, end_bracket_range))
1463 } else {
1464 None
1465 }
1466 })
1467 }
1468
1469 pub fn diagnostics_update_count(&self) -> usize {
1470 self.diagnostics_update_count
1471 }
1472
1473 pub fn language(&self) -> Option<&Arc<Language>> {
1474 self.excerpts
1475 .iter()
1476 .next()
1477 .and_then(|excerpt| excerpt.buffer.language())
1478 }
1479
1480 pub fn is_dirty(&self) -> bool {
1481 self.is_dirty
1482 }
1483
1484 pub fn has_conflict(&self) -> bool {
1485 self.has_conflict
1486 }
1487
1488 pub fn diagnostic_group<'a, O>(
1489 &'a self,
1490 provider_name: &'a str,
1491 group_id: usize,
1492 ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
1493 where
1494 O: text::FromAnchor + 'a,
1495 {
1496 self.as_singleton()
1497 .into_iter()
1498 .flat_map(move |buffer| buffer.diagnostic_group(provider_name, group_id))
1499 }
1500
1501 pub fn diagnostics_in_range<'a, T, O>(
1502 &'a self,
1503 range: Range<T>,
1504 ) -> impl Iterator<Item = (&'a str, DiagnosticEntry<O>)> + 'a
1505 where
1506 T: 'a + ToOffset,
1507 O: 'a + text::FromAnchor,
1508 {
1509 self.as_singleton().into_iter().flat_map(move |buffer| {
1510 buffer.diagnostics_in_range(range.start.to_offset(self)..range.end.to_offset(self))
1511 })
1512 }
1513
1514 pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
1515 let range = range.start.to_offset(self)..range.end.to_offset(self);
1516
1517 let mut cursor = self.excerpts.cursor::<usize>();
1518 cursor.seek(&range.start, Bias::Right, &());
1519 let start_excerpt = cursor.item();
1520
1521 cursor.seek(&range.end, Bias::Right, &());
1522 let end_excerpt = cursor.item();
1523
1524 start_excerpt
1525 .zip(end_excerpt)
1526 .and_then(|(start_excerpt, end_excerpt)| {
1527 if start_excerpt.id != end_excerpt.id {
1528 return None;
1529 }
1530
1531 let excerpt_buffer_start =
1532 start_excerpt.range.start.to_offset(&start_excerpt.buffer);
1533 let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
1534
1535 let start_in_buffer =
1536 excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
1537 let end_in_buffer =
1538 excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
1539 let mut ancestor_buffer_range = start_excerpt
1540 .buffer
1541 .range_for_syntax_ancestor(start_in_buffer..end_in_buffer)?;
1542 ancestor_buffer_range.start =
1543 cmp::max(ancestor_buffer_range.start, excerpt_buffer_start);
1544 ancestor_buffer_range.end = cmp::min(ancestor_buffer_range.end, excerpt_buffer_end);
1545
1546 let start = cursor.start() + (ancestor_buffer_range.start - excerpt_buffer_start);
1547 let end = cursor.start() + (ancestor_buffer_range.end - excerpt_buffer_start);
1548 Some(start..end)
1549 })
1550 }
1551
1552 fn buffer_snapshot_for_excerpt<'a>(
1553 &'a self,
1554 excerpt_id: &'a ExcerptId,
1555 ) -> Option<&'a BufferSnapshot> {
1556 let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1557 cursor.seek(&Some(excerpt_id), Bias::Left, &());
1558 if let Some(excerpt) = cursor.item() {
1559 if excerpt.id == *excerpt_id {
1560 return Some(&excerpt.buffer);
1561 }
1562 }
1563 None
1564 }
1565
1566 pub fn remote_selections_in_range<'a>(
1567 &'a self,
1568 range: &'a Range<Anchor>,
1569 ) -> impl 'a + Iterator<Item = (ReplicaId, Selection<Anchor>)> {
1570 let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1571 cursor.seek(&Some(&range.start.excerpt_id), Bias::Left, &());
1572 cursor
1573 .take_while(move |excerpt| excerpt.id <= range.end.excerpt_id)
1574 .flat_map(move |excerpt| {
1575 let mut query_range = excerpt.range.start.clone()..excerpt.range.end.clone();
1576 if excerpt.id == range.start.excerpt_id {
1577 query_range.start = range.start.text_anchor.clone();
1578 }
1579 if excerpt.id == range.end.excerpt_id {
1580 query_range.end = range.end.text_anchor.clone();
1581 }
1582
1583 excerpt
1584 .buffer
1585 .remote_selections_in_range(query_range)
1586 .flat_map(move |(replica_id, selections)| {
1587 selections.map(move |selection| {
1588 let mut start = Anchor {
1589 excerpt_id: excerpt.id.clone(),
1590 text_anchor: selection.start.clone(),
1591 };
1592 let mut end = Anchor {
1593 excerpt_id: excerpt.id.clone(),
1594 text_anchor: selection.end.clone(),
1595 };
1596 if range.start.cmp(&start, self).unwrap().is_gt() {
1597 start = range.start.clone();
1598 }
1599 if range.end.cmp(&end, self).unwrap().is_lt() {
1600 end = range.end.clone();
1601 }
1602
1603 (
1604 replica_id,
1605 Selection {
1606 id: selection.id,
1607 start,
1608 end,
1609 reversed: selection.reversed,
1610 goal: selection.goal,
1611 },
1612 )
1613 })
1614 })
1615 })
1616 }
1617}
1618
1619impl History {
1620 fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
1621 self.transaction_depth += 1;
1622 if self.transaction_depth == 1 {
1623 let id = post_inc(&mut self.next_transaction_id);
1624 self.undo_stack.push(Transaction {
1625 id,
1626 buffer_transactions: Default::default(),
1627 first_edit_at: now,
1628 last_edit_at: now,
1629 });
1630 Some(id)
1631 } else {
1632 None
1633 }
1634 }
1635
1636 fn end_transaction(
1637 &mut self,
1638 now: Instant,
1639 buffer_transactions: HashSet<(usize, TransactionId)>,
1640 ) -> bool {
1641 assert_ne!(self.transaction_depth, 0);
1642 self.transaction_depth -= 1;
1643 if self.transaction_depth == 0 {
1644 if buffer_transactions.is_empty() {
1645 self.undo_stack.pop();
1646 false
1647 } else {
1648 let transaction = self.undo_stack.last_mut().unwrap();
1649 transaction.last_edit_at = now;
1650 transaction.buffer_transactions.extend(buffer_transactions);
1651 true
1652 }
1653 } else {
1654 false
1655 }
1656 }
1657
1658 fn pop_undo(&mut self) -> Option<&Transaction> {
1659 assert_eq!(self.transaction_depth, 0);
1660 if let Some(transaction) = self.undo_stack.pop() {
1661 self.redo_stack.push(transaction);
1662 self.redo_stack.last()
1663 } else {
1664 None
1665 }
1666 }
1667
1668 fn pop_redo(&mut self) -> Option<&Transaction> {
1669 assert_eq!(self.transaction_depth, 0);
1670 if let Some(transaction) = self.redo_stack.pop() {
1671 self.undo_stack.push(transaction);
1672 self.undo_stack.last()
1673 } else {
1674 None
1675 }
1676 }
1677
1678 fn group(&mut self) -> Option<TransactionId> {
1679 let mut new_len = self.undo_stack.len();
1680 let mut transactions = self.undo_stack.iter_mut();
1681
1682 if let Some(mut transaction) = transactions.next_back() {
1683 while let Some(prev_transaction) = transactions.next_back() {
1684 if transaction.first_edit_at - prev_transaction.last_edit_at <= self.group_interval
1685 {
1686 transaction = prev_transaction;
1687 new_len -= 1;
1688 } else {
1689 break;
1690 }
1691 }
1692 }
1693
1694 let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
1695 if let Some(last_transaction) = transactions_to_keep.last_mut() {
1696 if let Some(transaction) = transactions_to_merge.last() {
1697 last_transaction.last_edit_at = transaction.last_edit_at;
1698 }
1699 }
1700
1701 self.undo_stack.truncate(new_len);
1702 self.undo_stack.last().map(|t| t.id)
1703 }
1704}
1705
1706impl Excerpt {
1707 fn new(
1708 id: ExcerptId,
1709 buffer_id: usize,
1710 buffer: BufferSnapshot,
1711 range: Range<text::Anchor>,
1712 has_trailing_newline: bool,
1713 ) -> Self {
1714 Excerpt {
1715 id,
1716 max_buffer_row: range.end.to_point(&buffer).row,
1717 text_summary: buffer.text_summary_for_range::<TextSummary, _>(range.to_offset(&buffer)),
1718 buffer_id,
1719 buffer,
1720 range,
1721 has_trailing_newline,
1722 }
1723 }
1724
1725 fn chunks_in_range<'a>(
1726 &'a self,
1727 range: Range<usize>,
1728 theme: Option<&'a SyntaxTheme>,
1729 ) -> ExcerptChunks<'a> {
1730 let content_start = self.range.start.to_offset(&self.buffer);
1731 let chunks_start = content_start + range.start;
1732 let chunks_end = content_start + cmp::min(range.end, self.text_summary.bytes);
1733
1734 let footer_height = if self.has_trailing_newline
1735 && range.start <= self.text_summary.bytes
1736 && range.end > self.text_summary.bytes
1737 {
1738 1
1739 } else {
1740 0
1741 };
1742
1743 let content_chunks = self.buffer.chunks(chunks_start..chunks_end, theme);
1744
1745 ExcerptChunks {
1746 content_chunks,
1747 footer_height,
1748 }
1749 }
1750
1751 fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
1752 let content_start = self.range.start.to_offset(&self.buffer);
1753 let bytes_start = content_start + range.start;
1754 let bytes_end = content_start + cmp::min(range.end, self.text_summary.bytes);
1755 let footer_height = if self.has_trailing_newline
1756 && range.start <= self.text_summary.bytes
1757 && range.end > self.text_summary.bytes
1758 {
1759 1
1760 } else {
1761 0
1762 };
1763 let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
1764
1765 ExcerptBytes {
1766 content_bytes,
1767 footer_height,
1768 }
1769 }
1770
1771 fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
1772 if text_anchor
1773 .cmp(&self.range.start, &self.buffer)
1774 .unwrap()
1775 .is_lt()
1776 {
1777 self.range.start.clone()
1778 } else if text_anchor
1779 .cmp(&self.range.end, &self.buffer)
1780 .unwrap()
1781 .is_gt()
1782 {
1783 self.range.end.clone()
1784 } else {
1785 text_anchor
1786 }
1787 }
1788}
1789
1790impl fmt::Debug for Excerpt {
1791 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1792 f.debug_struct("Excerpt")
1793 .field("id", &self.id)
1794 .field("buffer_id", &self.buffer_id)
1795 .field("range", &self.range)
1796 .field("text_summary", &self.text_summary)
1797 .field("has_trailing_newline", &self.has_trailing_newline)
1798 .finish()
1799 }
1800}
1801
1802impl sum_tree::Item for Excerpt {
1803 type Summary = ExcerptSummary;
1804
1805 fn summary(&self) -> Self::Summary {
1806 let mut text = self.text_summary.clone();
1807 if self.has_trailing_newline {
1808 text += TextSummary::from("\n");
1809 }
1810 ExcerptSummary {
1811 excerpt_id: self.id.clone(),
1812 max_buffer_row: self.max_buffer_row,
1813 text,
1814 }
1815 }
1816}
1817
1818impl sum_tree::Summary for ExcerptSummary {
1819 type Context = ();
1820
1821 fn add_summary(&mut self, summary: &Self, _: &()) {
1822 debug_assert!(summary.excerpt_id > self.excerpt_id);
1823 self.excerpt_id = summary.excerpt_id.clone();
1824 self.text.add_summary(&summary.text, &());
1825 self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row);
1826 }
1827}
1828
1829impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
1830 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1831 *self += &summary.text;
1832 }
1833}
1834
1835impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
1836 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1837 *self += summary.text.bytes;
1838 }
1839}
1840
1841impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
1842 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
1843 Ord::cmp(self, &cursor_location.text.bytes)
1844 }
1845}
1846
1847impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Option<&'a ExcerptId> {
1848 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
1849 Ord::cmp(self, &Some(&cursor_location.excerpt_id))
1850 }
1851}
1852
1853impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
1854 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1855 *self += summary.text.lines;
1856 }
1857}
1858
1859impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
1860 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1861 *self += summary.text.lines_utf16
1862 }
1863}
1864
1865impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a ExcerptId> {
1866 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1867 *self = Some(&summary.excerpt_id);
1868 }
1869}
1870
1871impl<'a> MultiBufferRows<'a> {
1872 pub fn seek(&mut self, row: u32) {
1873 self.buffer_row_range = 0..0;
1874
1875 self.excerpts
1876 .seek_forward(&Point::new(row, 0), Bias::Right, &());
1877 if self.excerpts.item().is_none() {
1878 self.excerpts.prev(&());
1879
1880 if self.excerpts.item().is_none() && row == 0 {
1881 self.buffer_row_range = 0..1;
1882 return;
1883 }
1884 }
1885
1886 if let Some(excerpt) = self.excerpts.item() {
1887 let overshoot = row - self.excerpts.start().row;
1888 let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer).row;
1889 self.buffer_row_range.start = excerpt_start + overshoot;
1890 self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
1891 }
1892 }
1893}
1894
1895impl<'a> Iterator for MultiBufferRows<'a> {
1896 type Item = Option<u32>;
1897
1898 fn next(&mut self) -> Option<Self::Item> {
1899 loop {
1900 if !self.buffer_row_range.is_empty() {
1901 let row = Some(self.buffer_row_range.start);
1902 self.buffer_row_range.start += 1;
1903 return Some(row);
1904 }
1905 self.excerpts.item()?;
1906 self.excerpts.next(&());
1907 let excerpt = self.excerpts.item()?;
1908 self.buffer_row_range.start = excerpt.range.start.to_point(&excerpt.buffer).row;
1909 self.buffer_row_range.end =
1910 self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
1911 }
1912 }
1913}
1914
1915impl<'a> MultiBufferChunks<'a> {
1916 pub fn offset(&self) -> usize {
1917 self.range.start
1918 }
1919
1920 pub fn seek(&mut self, offset: usize) {
1921 self.range.start = offset;
1922 self.excerpts.seek(&offset, Bias::Right, &());
1923 if let Some(excerpt) = self.excerpts.item() {
1924 self.excerpt_chunks = Some(excerpt.chunks_in_range(
1925 self.range.start - self.excerpts.start()..self.range.end - self.excerpts.start(),
1926 self.theme,
1927 ));
1928 } else {
1929 self.excerpt_chunks = None;
1930 }
1931 }
1932}
1933
1934impl<'a> Iterator for MultiBufferChunks<'a> {
1935 type Item = Chunk<'a>;
1936
1937 fn next(&mut self) -> Option<Self::Item> {
1938 if self.range.is_empty() {
1939 None
1940 } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
1941 self.range.start += chunk.text.len();
1942 Some(chunk)
1943 } else {
1944 self.excerpts.next(&());
1945 let excerpt = self.excerpts.item()?;
1946 self.excerpt_chunks = Some(
1947 excerpt.chunks_in_range(0..self.range.end - self.excerpts.start(), self.theme),
1948 );
1949 self.next()
1950 }
1951 }
1952}
1953
1954impl<'a> MultiBufferBytes<'a> {
1955 fn consume(&mut self, len: usize) {
1956 self.range.start += len;
1957 self.chunk = &self.chunk[len..];
1958
1959 if !self.range.is_empty() && self.chunk.is_empty() {
1960 if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
1961 self.chunk = chunk;
1962 } else {
1963 self.excerpts.next(&());
1964 if let Some(excerpt) = self.excerpts.item() {
1965 let mut excerpt_bytes =
1966 excerpt.bytes_in_range(0..self.range.end - self.excerpts.start());
1967 self.chunk = excerpt_bytes.next().unwrap();
1968 self.excerpt_bytes = Some(excerpt_bytes);
1969 }
1970 }
1971 }
1972 }
1973}
1974
1975impl<'a> Iterator for MultiBufferBytes<'a> {
1976 type Item = &'a [u8];
1977
1978 fn next(&mut self) -> Option<Self::Item> {
1979 let chunk = self.chunk;
1980 if chunk.is_empty() {
1981 None
1982 } else {
1983 self.consume(chunk.len());
1984 Some(chunk)
1985 }
1986 }
1987}
1988
1989impl<'a> io::Read for MultiBufferBytes<'a> {
1990 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1991 let len = cmp::min(buf.len(), self.chunk.len());
1992 buf[..len].copy_from_slice(&self.chunk[..len]);
1993 if len > 0 {
1994 self.consume(len);
1995 }
1996 Ok(len)
1997 }
1998}
1999
2000impl<'a> Iterator for ExcerptBytes<'a> {
2001 type Item = &'a [u8];
2002
2003 fn next(&mut self) -> Option<Self::Item> {
2004 if let Some(chunk) = self.content_bytes.next() {
2005 if !chunk.is_empty() {
2006 return Some(chunk);
2007 }
2008 }
2009
2010 if self.footer_height > 0 {
2011 let result = &NEWLINES[..self.footer_height];
2012 self.footer_height = 0;
2013 return Some(result);
2014 }
2015
2016 None
2017 }
2018}
2019
2020impl<'a> Iterator for ExcerptChunks<'a> {
2021 type Item = Chunk<'a>;
2022
2023 fn next(&mut self) -> Option<Self::Item> {
2024 if let Some(chunk) = self.content_chunks.next() {
2025 return Some(chunk);
2026 }
2027
2028 if self.footer_height > 0 {
2029 let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
2030 self.footer_height = 0;
2031 return Some(Chunk {
2032 text,
2033 ..Default::default()
2034 });
2035 }
2036
2037 None
2038 }
2039}
2040
2041impl ToOffset for Point {
2042 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
2043 snapshot.point_to_offset(*self)
2044 }
2045}
2046
2047impl ToOffset for PointUtf16 {
2048 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
2049 snapshot.point_utf16_to_offset(*self)
2050 }
2051}
2052
2053impl ToOffset for usize {
2054 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
2055 assert!(*self <= snapshot.len(), "offset is out of range");
2056 *self
2057 }
2058}
2059
2060impl ToPoint for usize {
2061 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
2062 snapshot.offset_to_point(*self)
2063 }
2064}
2065
2066impl ToPoint for Point {
2067 fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
2068 *self
2069 }
2070}
2071
2072#[cfg(test)]
2073mod tests {
2074 use super::*;
2075 use gpui::MutableAppContext;
2076 use language::{Buffer, Rope};
2077 use rand::prelude::*;
2078 use std::env;
2079 use text::{Point, RandomCharIter};
2080 use util::test::sample_text;
2081
2082 #[gpui::test]
2083 fn test_singleton_multibuffer(cx: &mut MutableAppContext) {
2084 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
2085 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
2086
2087 let snapshot = multibuffer.read(cx).snapshot(cx);
2088 assert_eq!(snapshot.text(), buffer.read(cx).text());
2089
2090 assert_eq!(
2091 snapshot.buffer_rows(0).collect::<Vec<_>>(),
2092 (0..buffer.read(cx).row_count())
2093 .map(Some)
2094 .collect::<Vec<_>>()
2095 );
2096
2097 buffer.update(cx, |buffer, cx| buffer.edit([1..3], "XXX\n", cx));
2098 let snapshot = multibuffer.read(cx).snapshot(cx);
2099
2100 assert_eq!(snapshot.text(), buffer.read(cx).text());
2101 assert_eq!(
2102 snapshot.buffer_rows(0).collect::<Vec<_>>(),
2103 (0..buffer.read(cx).row_count())
2104 .map(Some)
2105 .collect::<Vec<_>>()
2106 );
2107 }
2108
2109 #[gpui::test]
2110 fn test_excerpt_buffer(cx: &mut MutableAppContext) {
2111 let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
2112 let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
2113 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2114
2115 let subscription = multibuffer.update(cx, |multibuffer, cx| {
2116 let subscription = multibuffer.subscribe();
2117 multibuffer.push_excerpt(
2118 ExcerptProperties {
2119 buffer: &buffer_1,
2120 range: Point::new(1, 2)..Point::new(2, 5),
2121 },
2122 cx,
2123 );
2124 assert_eq!(
2125 subscription.consume().into_inner(),
2126 [Edit {
2127 old: 0..0,
2128 new: 0..10
2129 }]
2130 );
2131
2132 multibuffer.push_excerpt(
2133 ExcerptProperties {
2134 buffer: &buffer_1,
2135 range: Point::new(3, 3)..Point::new(4, 4),
2136 },
2137 cx,
2138 );
2139 multibuffer.push_excerpt(
2140 ExcerptProperties {
2141 buffer: &buffer_2,
2142 range: Point::new(3, 1)..Point::new(3, 3),
2143 },
2144 cx,
2145 );
2146 assert_eq!(
2147 subscription.consume().into_inner(),
2148 [Edit {
2149 old: 10..10,
2150 new: 10..22
2151 }]
2152 );
2153
2154 subscription
2155 });
2156
2157 let snapshot = multibuffer.read(cx).snapshot(cx);
2158 assert_eq!(
2159 snapshot.text(),
2160 concat!(
2161 "bbbb\n", // Preserve newlines
2162 "ccccc\n", //
2163 "ddd\n", //
2164 "eeee\n", //
2165 "jj" //
2166 )
2167 );
2168 assert_eq!(
2169 snapshot.buffer_rows(0).collect::<Vec<_>>(),
2170 [Some(1), Some(2), Some(3), Some(4), Some(3)]
2171 );
2172 assert_eq!(
2173 snapshot.buffer_rows(2).collect::<Vec<_>>(),
2174 [Some(3), Some(4), Some(3)]
2175 );
2176 assert_eq!(snapshot.buffer_rows(4).collect::<Vec<_>>(), [Some(3)]);
2177 assert_eq!(snapshot.buffer_rows(5).collect::<Vec<_>>(), []);
2178 assert!(!snapshot.range_contains_excerpt_boundary(Point::new(1, 0)..Point::new(1, 5)));
2179 assert!(snapshot.range_contains_excerpt_boundary(Point::new(1, 0)..Point::new(2, 0)));
2180 assert!(snapshot.range_contains_excerpt_boundary(Point::new(1, 0)..Point::new(4, 0)));
2181 assert!(!snapshot.range_contains_excerpt_boundary(Point::new(2, 0)..Point::new(3, 0)));
2182 assert!(!snapshot.range_contains_excerpt_boundary(Point::new(4, 0)..Point::new(4, 2)));
2183 assert!(!snapshot.range_contains_excerpt_boundary(Point::new(4, 2)..Point::new(4, 2)));
2184
2185 buffer_1.update(cx, |buffer, cx| {
2186 buffer.edit(
2187 [
2188 Point::new(0, 0)..Point::new(0, 0),
2189 Point::new(2, 1)..Point::new(2, 3),
2190 ],
2191 "\n",
2192 cx,
2193 );
2194 });
2195
2196 let snapshot = multibuffer.read(cx).snapshot(cx);
2197 assert_eq!(
2198 snapshot.text(),
2199 concat!(
2200 "bbbb\n", // Preserve newlines
2201 "c\n", //
2202 "cc\n", //
2203 "ddd\n", //
2204 "eeee\n", //
2205 "jj" //
2206 )
2207 );
2208
2209 assert_eq!(
2210 subscription.consume().into_inner(),
2211 [Edit {
2212 old: 6..8,
2213 new: 6..7
2214 }]
2215 );
2216
2217 let snapshot = multibuffer.read(cx).snapshot(cx);
2218 assert_eq!(
2219 snapshot.clip_point(Point::new(0, 5), Bias::Left),
2220 Point::new(0, 4)
2221 );
2222 assert_eq!(
2223 snapshot.clip_point(Point::new(0, 5), Bias::Right),
2224 Point::new(0, 4)
2225 );
2226 assert_eq!(
2227 snapshot.clip_point(Point::new(5, 1), Bias::Right),
2228 Point::new(5, 1)
2229 );
2230 assert_eq!(
2231 snapshot.clip_point(Point::new(5, 2), Bias::Right),
2232 Point::new(5, 2)
2233 );
2234 assert_eq!(
2235 snapshot.clip_point(Point::new(5, 3), Bias::Right),
2236 Point::new(5, 2)
2237 );
2238
2239 let snapshot = multibuffer.update(cx, |multibuffer, cx| {
2240 let buffer_2_excerpt_id = multibuffer.excerpt_ids_for_buffer(&buffer_2)[0].clone();
2241 multibuffer.remove_excerpts(&[buffer_2_excerpt_id], cx);
2242 multibuffer.snapshot(cx)
2243 });
2244
2245 assert_eq!(
2246 snapshot.text(),
2247 concat!(
2248 "bbbb\n", // Preserve newlines
2249 "c\n", //
2250 "cc\n", //
2251 "ddd\n", //
2252 "eeee", //
2253 )
2254 );
2255 }
2256
2257 #[gpui::test]
2258 fn test_empty_excerpt_buffer(cx: &mut MutableAppContext) {
2259 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2260
2261 let snapshot = multibuffer.read(cx).snapshot(cx);
2262 assert_eq!(snapshot.text(), "");
2263 assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), &[Some(0)]);
2264 assert_eq!(snapshot.buffer_rows(1).collect::<Vec<_>>(), &[]);
2265 }
2266
2267 #[gpui::test]
2268 fn test_singleton_multibuffer_anchors(cx: &mut MutableAppContext) {
2269 let buffer = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
2270 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
2271 let old_snapshot = multibuffer.read(cx).snapshot(cx);
2272 buffer.update(cx, |buffer, cx| {
2273 buffer.edit([0..0], "X", cx);
2274 buffer.edit([5..5], "Y", cx);
2275 });
2276 let new_snapshot = multibuffer.read(cx).snapshot(cx);
2277
2278 assert_eq!(old_snapshot.text(), "abcd");
2279 assert_eq!(new_snapshot.text(), "XabcdY");
2280
2281 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
2282 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
2283 assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
2284 assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
2285 }
2286
2287 #[gpui::test]
2288 fn test_multibuffer_anchors(cx: &mut MutableAppContext) {
2289 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
2290 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
2291 let multibuffer = cx.add_model(|cx| {
2292 let mut multibuffer = MultiBuffer::new(0);
2293 multibuffer.push_excerpt(
2294 ExcerptProperties {
2295 buffer: &buffer_1,
2296 range: 0..4,
2297 },
2298 cx,
2299 );
2300 multibuffer.push_excerpt(
2301 ExcerptProperties {
2302 buffer: &buffer_2,
2303 range: 0..5,
2304 },
2305 cx,
2306 );
2307 multibuffer
2308 });
2309 let old_snapshot = multibuffer.read(cx).snapshot(cx);
2310
2311 assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
2312 assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
2313 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
2314 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
2315 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
2316 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
2317
2318 buffer_1.update(cx, |buffer, cx| {
2319 buffer.edit([0..0], "W", cx);
2320 buffer.edit([5..5], "X", cx);
2321 });
2322 buffer_2.update(cx, |buffer, cx| {
2323 buffer.edit([0..0], "Y", cx);
2324 buffer.edit([6..0], "Z", cx);
2325 });
2326 let new_snapshot = multibuffer.read(cx).snapshot(cx);
2327
2328 assert_eq!(old_snapshot.text(), "abcd\nefghi");
2329 assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
2330
2331 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
2332 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
2333 assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
2334 assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
2335 assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
2336 assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
2337 assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
2338 assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
2339 assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
2340 assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
2341 }
2342
2343 #[gpui::test(iterations = 100)]
2344 fn test_random_excerpts(cx: &mut MutableAppContext, mut rng: StdRng) {
2345 let operations = env::var("OPERATIONS")
2346 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2347 .unwrap_or(10);
2348
2349 let mut buffers: Vec<ModelHandle<Buffer>> = Vec::new();
2350 let list = cx.add_model(|_| MultiBuffer::new(0));
2351 let mut excerpt_ids = Vec::new();
2352 let mut expected_excerpts = Vec::<(ModelHandle<Buffer>, Range<text::Anchor>)>::new();
2353 let mut old_versions = Vec::new();
2354
2355 for _ in 0..operations {
2356 match rng.gen_range(0..100) {
2357 0..=19 if !buffers.is_empty() => {
2358 let buffer = buffers.choose(&mut rng).unwrap();
2359 buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
2360 }
2361 20..=29 if !expected_excerpts.is_empty() => {
2362 let mut ids_to_remove = vec![];
2363 for _ in 0..rng.gen_range(1..=3) {
2364 if expected_excerpts.is_empty() {
2365 break;
2366 }
2367
2368 let ix = rng.gen_range(0..expected_excerpts.len());
2369 ids_to_remove.push(excerpt_ids.remove(ix));
2370 let (buffer, range) = expected_excerpts.remove(ix);
2371 let buffer = buffer.read(cx);
2372 log::info!(
2373 "Removing excerpt {}: {:?}",
2374 ix,
2375 buffer
2376 .text_for_range(range.to_offset(&buffer))
2377 .collect::<String>(),
2378 );
2379 }
2380 ids_to_remove.sort_unstable();
2381 list.update(cx, |list, cx| list.remove_excerpts(&ids_to_remove, cx));
2382 }
2383 _ => {
2384 let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
2385 let base_text = RandomCharIter::new(&mut rng).take(10).collect::<String>();
2386 buffers.push(cx.add_model(|cx| Buffer::new(0, base_text, cx)));
2387 buffers.last().unwrap()
2388 } else {
2389 buffers.choose(&mut rng).unwrap()
2390 };
2391
2392 let buffer = buffer_handle.read(cx);
2393 let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
2394 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
2395 let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
2396 let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len());
2397 let prev_excerpt_id = excerpt_ids
2398 .get(prev_excerpt_ix)
2399 .cloned()
2400 .unwrap_or(ExcerptId::max());
2401 let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len());
2402
2403 log::info!(
2404 "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}",
2405 excerpt_ix,
2406 expected_excerpts.len(),
2407 buffer_handle.id(),
2408 buffer.text(),
2409 start_ix..end_ix,
2410 &buffer.text()[start_ix..end_ix]
2411 );
2412
2413 let excerpt_id = list.update(cx, |list, cx| {
2414 list.insert_excerpt_after(
2415 &prev_excerpt_id,
2416 ExcerptProperties {
2417 buffer: &buffer_handle,
2418 range: start_ix..end_ix,
2419 },
2420 cx,
2421 )
2422 });
2423
2424 excerpt_ids.insert(excerpt_ix, excerpt_id);
2425 expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range));
2426 }
2427 }
2428
2429 if rng.gen_bool(0.3) {
2430 list.update(cx, |list, cx| {
2431 old_versions.push((list.snapshot(cx), list.subscribe()));
2432 })
2433 }
2434
2435 let snapshot = list.read(cx).snapshot(cx);
2436
2437 let mut excerpt_starts = Vec::new();
2438 let mut expected_text = String::new();
2439 let mut expected_buffer_rows = Vec::new();
2440 for (buffer, range) in &expected_excerpts {
2441 let buffer = buffer.read(cx);
2442 let buffer_range = range.to_offset(buffer);
2443
2444 excerpt_starts.push(TextSummary::from(expected_text.as_str()));
2445 expected_text.extend(buffer.text_for_range(buffer_range.clone()));
2446 expected_text.push('\n');
2447
2448 let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
2449 ..=buffer.offset_to_point(buffer_range.end).row;
2450 for row in buffer_row_range {
2451 expected_buffer_rows.push(Some(row));
2452 }
2453 }
2454 // Remove final trailing newline.
2455 if !expected_excerpts.is_empty() {
2456 expected_text.pop();
2457 }
2458
2459 // Always report one buffer row
2460 if expected_buffer_rows.is_empty() {
2461 expected_buffer_rows.push(Some(0));
2462 }
2463
2464 assert_eq!(snapshot.text(), expected_text);
2465 log::info!("MultiBuffer text: {:?}", expected_text);
2466
2467 assert_eq!(
2468 snapshot.buffer_rows(0).collect::<Vec<_>>(),
2469 expected_buffer_rows,
2470 );
2471
2472 for _ in 0..5 {
2473 let start_row = rng.gen_range(0..=expected_buffer_rows.len());
2474 assert_eq!(
2475 snapshot.buffer_rows(start_row as u32).collect::<Vec<_>>(),
2476 &expected_buffer_rows[start_row..],
2477 "buffer_rows({})",
2478 start_row
2479 );
2480 }
2481
2482 assert_eq!(
2483 snapshot.max_buffer_row(),
2484 expected_buffer_rows
2485 .into_iter()
2486 .filter_map(|r| r)
2487 .max()
2488 .unwrap()
2489 );
2490
2491 let mut excerpt_starts = excerpt_starts.into_iter();
2492 for (buffer, range) in &expected_excerpts {
2493 let buffer_id = buffer.id();
2494 let buffer = buffer.read(cx);
2495 let buffer_range = range.to_offset(buffer);
2496 let buffer_start_point = buffer.offset_to_point(buffer_range.start);
2497 let buffer_start_point_utf16 =
2498 buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
2499
2500 let excerpt_start = excerpt_starts.next().unwrap();
2501 let mut offset = excerpt_start.bytes;
2502 let mut buffer_offset = buffer_range.start;
2503 let mut point = excerpt_start.lines;
2504 let mut buffer_point = buffer_start_point;
2505 let mut point_utf16 = excerpt_start.lines_utf16;
2506 let mut buffer_point_utf16 = buffer_start_point_utf16;
2507 for ch in buffer
2508 .snapshot()
2509 .chunks(buffer_range.clone(), None)
2510 .flat_map(|c| c.text.chars())
2511 {
2512 for _ in 0..ch.len_utf8() {
2513 let left_offset = snapshot.clip_offset(offset, Bias::Left);
2514 let right_offset = snapshot.clip_offset(offset, Bias::Right);
2515 let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
2516 let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
2517 assert_eq!(
2518 left_offset,
2519 excerpt_start.bytes + (buffer_left_offset - buffer_range.start),
2520 "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
2521 offset,
2522 buffer_id,
2523 buffer_offset,
2524 );
2525 assert_eq!(
2526 right_offset,
2527 excerpt_start.bytes + (buffer_right_offset - buffer_range.start),
2528 "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
2529 offset,
2530 buffer_id,
2531 buffer_offset,
2532 );
2533
2534 let left_point = snapshot.clip_point(point, Bias::Left);
2535 let right_point = snapshot.clip_point(point, Bias::Right);
2536 let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
2537 let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
2538 assert_eq!(
2539 left_point,
2540 excerpt_start.lines + (buffer_left_point - buffer_start_point),
2541 "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
2542 point,
2543 buffer_id,
2544 buffer_point,
2545 );
2546 assert_eq!(
2547 right_point,
2548 excerpt_start.lines + (buffer_right_point - buffer_start_point),
2549 "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
2550 point,
2551 buffer_id,
2552 buffer_point,
2553 );
2554
2555 assert_eq!(
2556 snapshot.point_to_offset(left_point),
2557 left_offset,
2558 "point_to_offset({:?})",
2559 left_point,
2560 );
2561 assert_eq!(
2562 snapshot.offset_to_point(left_offset),
2563 left_point,
2564 "offset_to_point({:?})",
2565 left_offset,
2566 );
2567
2568 offset += 1;
2569 buffer_offset += 1;
2570 if ch == '\n' {
2571 point += Point::new(1, 0);
2572 buffer_point += Point::new(1, 0);
2573 } else {
2574 point += Point::new(0, 1);
2575 buffer_point += Point::new(0, 1);
2576 }
2577 }
2578
2579 for _ in 0..ch.len_utf16() {
2580 let left_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Left);
2581 let right_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Right);
2582 let buffer_left_point_utf16 =
2583 buffer.clip_point_utf16(buffer_point_utf16, Bias::Left);
2584 let buffer_right_point_utf16 =
2585 buffer.clip_point_utf16(buffer_point_utf16, Bias::Right);
2586 assert_eq!(
2587 left_point_utf16,
2588 excerpt_start.lines_utf16
2589 + (buffer_left_point_utf16 - buffer_start_point_utf16),
2590 "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
2591 point_utf16,
2592 buffer_id,
2593 buffer_point_utf16,
2594 );
2595 assert_eq!(
2596 right_point_utf16,
2597 excerpt_start.lines_utf16
2598 + (buffer_right_point_utf16 - buffer_start_point_utf16),
2599 "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
2600 point_utf16,
2601 buffer_id,
2602 buffer_point_utf16,
2603 );
2604
2605 if ch == '\n' {
2606 point_utf16 += PointUtf16::new(1, 0);
2607 buffer_point_utf16 += PointUtf16::new(1, 0);
2608 } else {
2609 point_utf16 += PointUtf16::new(0, 1);
2610 buffer_point_utf16 += PointUtf16::new(0, 1);
2611 }
2612 }
2613 }
2614 }
2615
2616 for (row, line) in expected_text.split('\n').enumerate() {
2617 assert_eq!(
2618 snapshot.line_len(row as u32),
2619 line.len() as u32,
2620 "line_len({}).",
2621 row
2622 );
2623 }
2624
2625 let text_rope = Rope::from(expected_text.as_str());
2626 for _ in 0..10 {
2627 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
2628 let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
2629
2630 assert_eq!(
2631 snapshot
2632 .text_for_range(start_ix..end_ix)
2633 .collect::<String>(),
2634 &expected_text[start_ix..end_ix],
2635 "incorrect text for range {:?}",
2636 start_ix..end_ix
2637 );
2638
2639 let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
2640 assert_eq!(
2641 snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
2642 expected_summary,
2643 "incorrect summary for range {:?}",
2644 start_ix..end_ix
2645 );
2646 }
2647
2648 for _ in 0..10 {
2649 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
2650 assert_eq!(
2651 snapshot.reversed_chars_at(end_ix).collect::<String>(),
2652 expected_text[..end_ix].chars().rev().collect::<String>(),
2653 );
2654 }
2655
2656 for _ in 0..10 {
2657 let end_ix = rng.gen_range(0..=text_rope.len());
2658 let start_ix = rng.gen_range(0..=end_ix);
2659 assert_eq!(
2660 snapshot
2661 .bytes_in_range(start_ix..end_ix)
2662 .flatten()
2663 .copied()
2664 .collect::<Vec<_>>(),
2665 expected_text.as_bytes()[start_ix..end_ix].to_vec(),
2666 "bytes_in_range({:?})",
2667 start_ix..end_ix,
2668 );
2669 }
2670 }
2671
2672 let snapshot = list.read(cx).snapshot(cx);
2673 for (old_snapshot, subscription) in old_versions {
2674 let edits = subscription.consume().into_inner();
2675
2676 log::info!(
2677 "applying subscription edits to old text: {:?}: {:?}",
2678 old_snapshot.text(),
2679 edits,
2680 );
2681
2682 let mut text = old_snapshot.text();
2683 for edit in edits {
2684 let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
2685 text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
2686 }
2687 assert_eq!(text.to_string(), snapshot.text());
2688 }
2689 }
2690
2691 #[gpui::test]
2692 fn test_history(cx: &mut MutableAppContext) {
2693 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "1234", cx));
2694 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "5678", cx));
2695 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2696 let group_interval = multibuffer.read(cx).history.group_interval;
2697 multibuffer.update(cx, |multibuffer, cx| {
2698 multibuffer.push_excerpt(
2699 ExcerptProperties {
2700 buffer: &buffer_1,
2701 range: 0..buffer_1.read(cx).len(),
2702 },
2703 cx,
2704 );
2705 multibuffer.push_excerpt(
2706 ExcerptProperties {
2707 buffer: &buffer_2,
2708 range: 0..buffer_2.read(cx).len(),
2709 },
2710 cx,
2711 );
2712 });
2713
2714 let mut now = Instant::now();
2715
2716 multibuffer.update(cx, |multibuffer, cx| {
2717 multibuffer.start_transaction_at(now, cx);
2718 multibuffer.edit(
2719 [
2720 Point::new(0, 0)..Point::new(0, 0),
2721 Point::new(1, 0)..Point::new(1, 0),
2722 ],
2723 "A",
2724 cx,
2725 );
2726 multibuffer.edit(
2727 [
2728 Point::new(0, 1)..Point::new(0, 1),
2729 Point::new(1, 1)..Point::new(1, 1),
2730 ],
2731 "B",
2732 cx,
2733 );
2734 multibuffer.end_transaction_at(now, cx);
2735 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2736
2737 now += 2 * group_interval;
2738 multibuffer.start_transaction_at(now, cx);
2739 multibuffer.edit([2..2], "C", cx);
2740 multibuffer.end_transaction_at(now, cx);
2741 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2742
2743 multibuffer.undo(cx);
2744 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2745
2746 multibuffer.undo(cx);
2747 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
2748
2749 multibuffer.redo(cx);
2750 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2751
2752 multibuffer.redo(cx);
2753 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2754
2755 buffer_1.update(cx, |buffer_1, cx| buffer_1.undo(cx));
2756 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2757
2758 multibuffer.undo(cx);
2759 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
2760
2761 multibuffer.redo(cx);
2762 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2763
2764 multibuffer.redo(cx);
2765 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2766
2767 multibuffer.undo(cx);
2768 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2769
2770 buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
2771 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2772
2773 multibuffer.undo(cx);
2774 assert_eq!(multibuffer.read(cx).text(), "C1234\n5678");
2775 });
2776 }
2777}