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