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