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