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