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