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