1mod anchor;
2
3pub use anchor::{Anchor, AnchorRangeExt};
4use anyhow::Result;
5use clock::ReplicaId;
6use collections::{Bound, HashMap, HashSet};
7use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
8pub use language::Completion;
9use language::{
10 char_kind, Buffer, BufferChunks, BufferSnapshot, CharKind, Chunk, DiagnosticEntry, Event, File,
11 Language, OffsetRangeExt, Outline, OutlineItem, Selection, ToOffset as _, ToPoint as _,
12 ToPointUtf16 as _, TransactionId,
13};
14use settings::Settings;
15use smallvec::SmallVec;
16use std::{
17 cell::{Ref, RefCell},
18 cmp, fmt, io,
19 iter::{self, FromIterator},
20 mem,
21 ops::{Range, RangeBounds, Sub},
22 str,
23 sync::Arc,
24 time::{Duration, Instant},
25};
26use sum_tree::{Bias, Cursor, SumTree};
27use text::{
28 locator::Locator,
29 rope::TextDimension,
30 subscription::{Subscription, Topic},
31 Edit, Point, PointUtf16, TextSummary,
32};
33use theme::SyntaxTheme;
34use util::post_inc;
35
36const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize];
37
38pub type ExcerptId = Locator;
39
40pub struct MultiBuffer {
41 snapshot: RefCell<MultiBufferSnapshot>,
42 buffers: RefCell<HashMap<usize, BufferState>>,
43 used_excerpt_ids: SumTree<ExcerptId>,
44 next_excerpt_key: usize,
45 subscriptions: Topic,
46 singleton: bool,
47 replica_id: ReplicaId,
48 history: History,
49 title: Option<String>,
50}
51
52#[derive(Clone)]
53struct History {
54 next_transaction_id: TransactionId,
55 undo_stack: Vec<Transaction>,
56 redo_stack: Vec<Transaction>,
57 transaction_depth: usize,
58 group_interval: Duration,
59}
60
61#[derive(Clone)]
62struct Transaction {
63 id: TransactionId,
64 buffer_transactions: HashMap<usize, text::TransactionId>,
65 first_edit_at: Instant,
66 last_edit_at: Instant,
67 suppress_grouping: bool,
68}
69
70pub trait ToOffset: 'static + fmt::Debug {
71 fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
72}
73
74pub trait ToPoint: 'static + fmt::Debug {
75 fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point;
76}
77
78pub trait ToPointUtf16: 'static + fmt::Debug {
79 fn to_point_utf16(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16;
80}
81
82struct BufferState {
83 buffer: ModelHandle<Buffer>,
84 last_version: clock::Global,
85 last_parse_count: usize,
86 last_selections_update_count: usize,
87 last_diagnostics_update_count: usize,
88 last_file_update_count: usize,
89 excerpts: Vec<ExcerptId>,
90 _subscriptions: [gpui::Subscription; 2],
91}
92
93#[derive(Clone, Default)]
94pub struct MultiBufferSnapshot {
95 singleton: bool,
96 excerpts: SumTree<Excerpt>,
97 parse_count: usize,
98 diagnostics_update_count: usize,
99 trailing_excerpt_update_count: usize,
100 edit_count: usize,
101 is_dirty: bool,
102 has_conflict: bool,
103}
104
105pub struct ExcerptBoundary {
106 pub id: ExcerptId,
107 pub key: usize,
108 pub row: u32,
109 pub buffer: BufferSnapshot,
110 pub range: ExcerptRange<text::Anchor>,
111 pub starts_new_buffer: bool,
112}
113
114#[derive(Clone)]
115struct Excerpt {
116 id: ExcerptId,
117 key: usize,
118 buffer_id: usize,
119 buffer: BufferSnapshot,
120 range: ExcerptRange<text::Anchor>,
121 max_buffer_row: u32,
122 text_summary: TextSummary,
123 has_trailing_newline: bool,
124}
125
126#[derive(Clone, Debug, Eq, PartialEq)]
127pub struct ExcerptRange<T> {
128 pub context: Range<T>,
129 pub primary: Option<Range<T>>,
130}
131
132#[derive(Clone, Debug, Default)]
133struct ExcerptSummary {
134 excerpt_id: ExcerptId,
135 max_buffer_row: u32,
136 text: TextSummary,
137}
138
139pub struct MultiBufferRows<'a> {
140 buffer_row_range: Range<u32>,
141 excerpts: Cursor<'a, Excerpt, Point>,
142}
143
144pub struct MultiBufferChunks<'a> {
145 range: Range<usize>,
146 excerpts: Cursor<'a, Excerpt, usize>,
147 excerpt_chunks: Option<ExcerptChunks<'a>>,
148 language_aware: bool,
149}
150
151pub struct MultiBufferBytes<'a> {
152 range: Range<usize>,
153 excerpts: Cursor<'a, Excerpt, usize>,
154 excerpt_bytes: Option<ExcerptBytes<'a>>,
155 chunk: &'a [u8],
156}
157
158struct ExcerptChunks<'a> {
159 content_chunks: BufferChunks<'a>,
160 footer_height: usize,
161}
162
163struct ExcerptBytes<'a> {
164 content_bytes: language::rope::Bytes<'a>,
165 footer_height: usize,
166}
167
168impl MultiBuffer {
169 pub fn new(replica_id: ReplicaId) -> Self {
170 Self {
171 snapshot: Default::default(),
172 buffers: Default::default(),
173 used_excerpt_ids: Default::default(),
174 next_excerpt_key: Default::default(),
175 subscriptions: Default::default(),
176 singleton: false,
177 replica_id,
178 history: History {
179 next_transaction_id: Default::default(),
180 undo_stack: Default::default(),
181 redo_stack: Default::default(),
182 transaction_depth: 0,
183 group_interval: Duration::from_millis(300),
184 },
185 title: Default::default(),
186 }
187 }
188
189 pub fn clone(&self, new_cx: &mut ModelContext<Self>) -> Self {
190 let mut buffers = HashMap::default();
191 for (buffer_id, buffer_state) in self.buffers.borrow().iter() {
192 buffers.insert(
193 *buffer_id,
194 BufferState {
195 buffer: buffer_state.buffer.clone(),
196 last_version: buffer_state.last_version.clone(),
197 last_parse_count: buffer_state.last_parse_count,
198 last_selections_update_count: buffer_state.last_selections_update_count,
199 last_diagnostics_update_count: buffer_state.last_diagnostics_update_count,
200 last_file_update_count: buffer_state.last_file_update_count,
201 excerpts: buffer_state.excerpts.clone(),
202 _subscriptions: [
203 new_cx.observe(&buffer_state.buffer, |_, _, cx| cx.notify()),
204 new_cx.subscribe(&buffer_state.buffer, Self::on_buffer_event),
205 ],
206 },
207 );
208 }
209 Self {
210 snapshot: RefCell::new(self.snapshot.borrow().clone()),
211 buffers: RefCell::new(buffers),
212 used_excerpt_ids: self.used_excerpt_ids.clone(),
213 next_excerpt_key: self.next_excerpt_key,
214 subscriptions: Default::default(),
215 singleton: self.singleton,
216 replica_id: self.replica_id,
217 history: self.history.clone(),
218 title: self.title.clone(),
219 }
220 }
221
222 pub fn with_title(mut self, title: String) -> Self {
223 self.title = Some(title);
224 self
225 }
226
227 pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
228 let mut this = Self::new(buffer.read(cx).replica_id());
229 this.singleton = true;
230 this.push_excerpts(
231 buffer,
232 [ExcerptRange {
233 context: text::Anchor::MIN..text::Anchor::MAX,
234 primary: None,
235 }],
236 cx,
237 );
238 this.snapshot.borrow_mut().singleton = true;
239 this
240 }
241
242 pub fn replica_id(&self) -> ReplicaId {
243 self.replica_id
244 }
245
246 pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot {
247 self.sync(cx);
248 self.snapshot.borrow().clone()
249 }
250
251 pub(crate) fn read(&self, cx: &AppContext) -> Ref<MultiBufferSnapshot> {
252 self.sync(cx);
253 self.snapshot.borrow()
254 }
255
256 pub fn as_singleton(&self) -> Option<ModelHandle<Buffer>> {
257 if self.singleton {
258 return Some(
259 self.buffers
260 .borrow()
261 .values()
262 .next()
263 .unwrap()
264 .buffer
265 .clone(),
266 );
267 } else {
268 None
269 }
270 }
271
272 pub fn is_singleton(&self) -> bool {
273 self.singleton
274 }
275
276 pub fn subscribe(&mut self) -> Subscription {
277 self.subscriptions.subscribe()
278 }
279
280 pub fn is_dirty(&self, cx: &AppContext) -> bool {
281 self.read(cx).is_dirty()
282 }
283
284 pub fn has_conflict(&self, cx: &AppContext) -> bool {
285 self.read(cx).has_conflict()
286 }
287
288 pub fn len(&self, cx: &AppContext) -> usize {
289 self.read(cx).len()
290 }
291
292 pub fn symbols_containing<T: ToOffset>(
293 &self,
294 offset: T,
295 theme: Option<&SyntaxTheme>,
296 cx: &AppContext,
297 ) -> Option<(usize, Vec<OutlineItem<Anchor>>)> {
298 self.read(cx).symbols_containing(offset, theme)
299 }
300
301 pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ModelContext<Self>)
302 where
303 I: IntoIterator<Item = (Range<S>, T)>,
304 S: ToOffset,
305 T: Into<Arc<str>>,
306 {
307 self.edit_internal(edits, false, cx)
308 }
309
310 pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ModelContext<Self>)
311 where
312 I: IntoIterator<Item = (Range<S>, T)>,
313 S: ToOffset,
314 T: Into<Arc<str>>,
315 {
316 self.edit_internal(edits, true, cx)
317 }
318
319 pub fn edit_internal<I, S, T>(
320 &mut self,
321 edits: I,
322 autoindent: bool,
323 cx: &mut ModelContext<Self>,
324 ) where
325 I: IntoIterator<Item = (Range<S>, T)>,
326 S: ToOffset,
327 T: Into<Arc<str>>,
328 {
329 if self.buffers.borrow().is_empty() {
330 return;
331 }
332
333 let snapshot = self.read(cx);
334 let edits = edits.into_iter().map(|(range, new_text)| {
335 let mut range = range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot);
336 if range.start > range.end {
337 mem::swap(&mut range.start, &mut range.end);
338 }
339 (range, new_text)
340 });
341
342 if let Some(buffer) = self.as_singleton() {
343 return buffer.update(cx, |buffer, cx| {
344 let language_name = buffer.language().map(|language| language.name());
345 let indent_size = cx.global::<Settings>().tab_size(language_name.as_deref());
346 if autoindent {
347 buffer.edit_with_autoindent(edits, indent_size, cx);
348 } else {
349 buffer.edit(edits, cx);
350 }
351 });
352 }
353
354 let mut buffer_edits: HashMap<usize, Vec<(Range<usize>, Arc<str>, bool)>> =
355 Default::default();
356 let mut cursor = snapshot.excerpts.cursor::<usize>();
357 for (range, new_text) in edits {
358 let new_text: Arc<str> = new_text.into();
359 cursor.seek(&range.start, Bias::Right, &());
360 if cursor.item().is_none() && range.start == *cursor.start() {
361 cursor.prev(&());
362 }
363 let start_excerpt = cursor.item().expect("start offset out of bounds");
364 let start_overshoot = range.start - cursor.start();
365 let buffer_start = start_excerpt
366 .range
367 .context
368 .start
369 .to_offset(&start_excerpt.buffer)
370 + start_overshoot;
371
372 cursor.seek(&range.end, Bias::Right, &());
373 if cursor.item().is_none() && range.end == *cursor.start() {
374 cursor.prev(&());
375 }
376 let end_excerpt = cursor.item().expect("end offset out of bounds");
377 let end_overshoot = range.end - cursor.start();
378 let buffer_end = end_excerpt
379 .range
380 .context
381 .start
382 .to_offset(&end_excerpt.buffer)
383 + end_overshoot;
384
385 if start_excerpt.id == end_excerpt.id {
386 buffer_edits
387 .entry(start_excerpt.buffer_id)
388 .or_insert(Vec::new())
389 .push((buffer_start..buffer_end, new_text, true));
390 } else {
391 let start_excerpt_range = buffer_start
392 ..start_excerpt
393 .range
394 .context
395 .end
396 .to_offset(&start_excerpt.buffer);
397 let end_excerpt_range = end_excerpt
398 .range
399 .context
400 .start
401 .to_offset(&end_excerpt.buffer)
402 ..buffer_end;
403 buffer_edits
404 .entry(start_excerpt.buffer_id)
405 .or_insert(Vec::new())
406 .push((start_excerpt_range, new_text.clone(), true));
407 buffer_edits
408 .entry(end_excerpt.buffer_id)
409 .or_insert(Vec::new())
410 .push((end_excerpt_range, new_text.clone(), false));
411
412 cursor.seek(&range.start, Bias::Right, &());
413 cursor.next(&());
414 while let Some(excerpt) = cursor.item() {
415 if excerpt.id == end_excerpt.id {
416 break;
417 }
418 buffer_edits
419 .entry(excerpt.buffer_id)
420 .or_insert(Vec::new())
421 .push((
422 excerpt.range.context.to_offset(&excerpt.buffer),
423 new_text.clone(),
424 false,
425 ));
426 cursor.next(&());
427 }
428 }
429 }
430
431 for (buffer_id, mut edits) in buffer_edits {
432 edits.sort_unstable_by_key(|(range, _, _)| range.start);
433 self.buffers.borrow()[&buffer_id]
434 .buffer
435 .update(cx, |buffer, cx| {
436 let mut edits = edits.into_iter().peekable();
437 let mut insertions = Vec::new();
438 let mut deletions = Vec::new();
439 let empty_str: Arc<str> = "".into();
440 while let Some((mut range, new_text, mut is_insertion)) = edits.next() {
441 while let Some((next_range, _, next_is_insertion)) = edits.peek() {
442 if range.end >= next_range.start {
443 range.end = cmp::max(next_range.end, range.end);
444
445 is_insertion |= *next_is_insertion;
446 edits.next();
447 } else {
448 break;
449 }
450 }
451
452 if is_insertion {
453 insertions.push((
454 buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
455 new_text.clone(),
456 ));
457 } else if !range.is_empty() {
458 deletions.push((
459 buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
460 empty_str.clone(),
461 ));
462 }
463 }
464 let language_name = buffer.language().map(|l| l.name());
465 let indent_size = cx.global::<Settings>().tab_size(language_name.as_deref());
466
467 if autoindent {
468 buffer.edit_with_autoindent(deletions, indent_size, cx);
469 buffer.edit_with_autoindent(insertions, indent_size, cx);
470 } else {
471 buffer.edit(deletions, cx);
472 buffer.edit(insertions, cx);
473 }
474 })
475 }
476 }
477
478 pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
479 self.start_transaction_at(Instant::now(), cx)
480 }
481
482 pub(crate) fn start_transaction_at(
483 &mut self,
484 now: Instant,
485 cx: &mut ModelContext<Self>,
486 ) -> Option<TransactionId> {
487 if let Some(buffer) = self.as_singleton() {
488 return buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
489 }
490
491 for BufferState { buffer, .. } in self.buffers.borrow().values() {
492 buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
493 }
494 self.history.start_transaction(now)
495 }
496
497 pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
498 self.end_transaction_at(Instant::now(), cx)
499 }
500
501 pub(crate) fn end_transaction_at(
502 &mut self,
503 now: Instant,
504 cx: &mut ModelContext<Self>,
505 ) -> Option<TransactionId> {
506 if let Some(buffer) = self.as_singleton() {
507 return buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx));
508 }
509
510 let mut buffer_transactions = HashMap::default();
511 for BufferState { buffer, .. } in self.buffers.borrow().values() {
512 if let Some(transaction_id) =
513 buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
514 {
515 buffer_transactions.insert(buffer.id(), transaction_id);
516 }
517 }
518
519 if self.history.end_transaction(now, buffer_transactions) {
520 let transaction_id = self.history.group().unwrap();
521 Some(transaction_id)
522 } else {
523 None
524 }
525 }
526
527 pub fn finalize_last_transaction(&mut self, cx: &mut ModelContext<Self>) {
528 self.history.finalize_last_transaction();
529 for BufferState { buffer, .. } in self.buffers.borrow().values() {
530 buffer.update(cx, |buffer, _| {
531 buffer.finalize_last_transaction();
532 });
533 }
534 }
535
536 pub fn push_transaction<'a, T>(&mut self, buffer_transactions: T)
537 where
538 T: IntoIterator<Item = (&'a ModelHandle<Buffer>, &'a language::Transaction)>,
539 {
540 self.history
541 .push_transaction(buffer_transactions, Instant::now());
542 self.history.finalize_last_transaction();
543 }
544
545 pub fn set_active_selections(
546 &mut self,
547 selections: &[Selection<Anchor>],
548 line_mode: bool,
549 cx: &mut ModelContext<Self>,
550 ) {
551 let mut selections_by_buffer: HashMap<usize, Vec<Selection<text::Anchor>>> =
552 Default::default();
553 let snapshot = self.read(cx);
554 let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();
555 for selection in selections {
556 cursor.seek(&Some(&selection.start.excerpt_id), Bias::Left, &());
557 while let Some(excerpt) = cursor.item() {
558 if excerpt.id > selection.end.excerpt_id {
559 break;
560 }
561
562 let mut start = excerpt.range.context.start.clone();
563 let mut end = excerpt.range.context.end.clone();
564 if excerpt.id == selection.start.excerpt_id {
565 start = selection.start.text_anchor.clone();
566 }
567 if excerpt.id == selection.end.excerpt_id {
568 end = selection.end.text_anchor.clone();
569 }
570 selections_by_buffer
571 .entry(excerpt.buffer_id)
572 .or_default()
573 .push(Selection {
574 id: selection.id,
575 start,
576 end,
577 reversed: selection.reversed,
578 goal: selection.goal,
579 });
580
581 cursor.next(&());
582 }
583 }
584
585 for (buffer_id, buffer_state) in self.buffers.borrow().iter() {
586 if !selections_by_buffer.contains_key(buffer_id) {
587 buffer_state
588 .buffer
589 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
590 }
591 }
592
593 for (buffer_id, mut selections) in selections_by_buffer {
594 self.buffers.borrow()[&buffer_id]
595 .buffer
596 .update(cx, |buffer, cx| {
597 selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer));
598 let mut selections = selections.into_iter().peekable();
599 let merged_selections = Arc::from_iter(iter::from_fn(|| {
600 let mut selection = selections.next()?;
601 while let Some(next_selection) = selections.peek() {
602 if selection.end.cmp(&next_selection.start, buffer).is_ge() {
603 let next_selection = selections.next().unwrap();
604 if next_selection.end.cmp(&selection.end, buffer).is_ge() {
605 selection.end = next_selection.end;
606 }
607 } else {
608 break;
609 }
610 }
611 Some(selection)
612 }));
613 buffer.set_active_selections(merged_selections, line_mode, cx);
614 });
615 }
616 }
617
618 pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
619 for buffer in self.buffers.borrow().values() {
620 buffer
621 .buffer
622 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
623 }
624 }
625
626 pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
627 if let Some(buffer) = self.as_singleton() {
628 return buffer.update(cx, |buffer, cx| buffer.undo(cx));
629 }
630
631 while let Some(transaction) = self.history.pop_undo() {
632 let mut undone = false;
633 for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions {
634 if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(&buffer_id) {
635 undone |= buffer.update(cx, |buffer, cx| {
636 let undo_to = *buffer_transaction_id;
637 if let Some(entry) = buffer.peek_undo_stack() {
638 *buffer_transaction_id = entry.transaction_id();
639 }
640 buffer.undo_to_transaction(undo_to, cx)
641 });
642 }
643 }
644
645 if undone {
646 return Some(transaction.id);
647 }
648 }
649
650 None
651 }
652
653 pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
654 if let Some(buffer) = self.as_singleton() {
655 return buffer.update(cx, |buffer, cx| buffer.redo(cx));
656 }
657
658 while let Some(transaction) = self.history.pop_redo() {
659 let mut redone = false;
660 for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions {
661 if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(&buffer_id) {
662 redone |= buffer.update(cx, |buffer, cx| {
663 let redo_to = *buffer_transaction_id;
664 if let Some(entry) = buffer.peek_redo_stack() {
665 *buffer_transaction_id = entry.transaction_id();
666 }
667 buffer.redo_to_transaction(redo_to, cx)
668 });
669 }
670 }
671
672 if redone {
673 return Some(transaction.id);
674 }
675 }
676
677 None
678 }
679
680 pub fn push_excerpts<O>(
681 &mut self,
682 buffer: ModelHandle<Buffer>,
683 ranges: impl IntoIterator<Item = ExcerptRange<O>>,
684 cx: &mut ModelContext<Self>,
685 ) -> Vec<ExcerptId>
686 where
687 O: text::ToOffset,
688 {
689 self.insert_excerpts_after(&ExcerptId::max(), buffer, ranges, cx)
690 }
691
692 pub fn push_excerpts_with_context_lines<O>(
693 &mut self,
694 buffer: ModelHandle<Buffer>,
695 ranges: Vec<Range<O>>,
696 context_line_count: u32,
697 cx: &mut ModelContext<Self>,
698 ) -> Vec<Range<Anchor>>
699 where
700 O: text::ToPoint + text::ToOffset,
701 {
702 let buffer_id = buffer.id();
703 let buffer_snapshot = buffer.read(cx).snapshot();
704 let max_point = buffer_snapshot.max_point();
705
706 let mut range_counts = Vec::new();
707 let mut excerpt_ranges = Vec::new();
708 let mut range_iter = ranges
709 .iter()
710 .map(|range| {
711 range.start.to_point(&buffer_snapshot)..range.end.to_point(&buffer_snapshot)
712 })
713 .peekable();
714 while let Some(range) = range_iter.next() {
715 let excerpt_start = Point::new(range.start.row.saturating_sub(context_line_count), 0);
716 let mut excerpt_end =
717 Point::new(range.end.row + 1 + context_line_count, 0).min(max_point);
718 let mut ranges_in_excerpt = 1;
719
720 while let Some(next_range) = range_iter.peek() {
721 if next_range.start.row <= excerpt_end.row + context_line_count {
722 excerpt_end =
723 Point::new(next_range.end.row + 1 + context_line_count, 0).min(max_point);
724 ranges_in_excerpt += 1;
725 range_iter.next();
726 } else {
727 break;
728 }
729 }
730
731 excerpt_ranges.push(ExcerptRange {
732 context: excerpt_start..excerpt_end,
733 primary: Some(range),
734 });
735 range_counts.push(ranges_in_excerpt);
736 }
737
738 let excerpt_ids = self.push_excerpts(buffer, excerpt_ranges, cx);
739
740 let mut anchor_ranges = Vec::new();
741 let mut ranges = ranges.into_iter();
742 for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.into_iter()) {
743 anchor_ranges.extend(ranges.by_ref().take(range_count).map(|range| {
744 let start = Anchor {
745 buffer_id: Some(buffer_id),
746 excerpt_id: excerpt_id.clone(),
747 text_anchor: buffer_snapshot.anchor_after(range.start),
748 };
749 let end = Anchor {
750 buffer_id: Some(buffer_id),
751 excerpt_id: excerpt_id.clone(),
752 text_anchor: buffer_snapshot.anchor_after(range.end),
753 };
754 start..end
755 }))
756 }
757 anchor_ranges
758 }
759
760 pub fn insert_excerpts_after<O>(
761 &mut self,
762 prev_excerpt_id: &ExcerptId,
763 buffer: ModelHandle<Buffer>,
764 ranges: impl IntoIterator<Item = ExcerptRange<O>>,
765 cx: &mut ModelContext<Self>,
766 ) -> Vec<ExcerptId>
767 where
768 O: text::ToOffset,
769 {
770 assert_eq!(self.history.transaction_depth, 0);
771 let mut ranges = ranges.into_iter().peekable();
772 if ranges.peek().is_none() {
773 return Default::default();
774 }
775
776 self.sync(cx);
777
778 let buffer_id = buffer.id();
779 let buffer_snapshot = buffer.read(cx).snapshot();
780
781 let mut buffers = self.buffers.borrow_mut();
782 let buffer_state = buffers.entry(buffer_id).or_insert_with(|| BufferState {
783 last_version: buffer_snapshot.version().clone(),
784 last_parse_count: buffer_snapshot.parse_count(),
785 last_selections_update_count: buffer_snapshot.selections_update_count(),
786 last_diagnostics_update_count: buffer_snapshot.diagnostics_update_count(),
787 last_file_update_count: buffer_snapshot.file_update_count(),
788 excerpts: Default::default(),
789 _subscriptions: [
790 cx.observe(&buffer, |_, _, cx| cx.notify()),
791 cx.subscribe(&buffer, Self::on_buffer_event),
792 ],
793 buffer,
794 });
795
796 let mut snapshot = self.snapshot.borrow_mut();
797 let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();
798 let mut new_excerpts = cursor.slice(&Some(prev_excerpt_id), Bias::Right, &());
799
800 let edit_start = new_excerpts.summary().text.bytes;
801 new_excerpts.update_last(
802 |excerpt| {
803 excerpt.has_trailing_newline = true;
804 },
805 &(),
806 );
807
808 let mut used_cursor = self.used_excerpt_ids.cursor::<Locator>();
809 used_cursor.seek(prev_excerpt_id, Bias::Right, &());
810 let mut prev_id = if let Some(excerpt_id) = used_cursor.prev_item() {
811 excerpt_id.clone()
812 } else {
813 ExcerptId::min()
814 };
815 let next_id = if let Some(excerpt_id) = used_cursor.item() {
816 excerpt_id.clone()
817 } else {
818 ExcerptId::max()
819 };
820 drop(used_cursor);
821
822 let mut ids = Vec::new();
823 while let Some(range) = ranges.next() {
824 let id = ExcerptId::between(&prev_id, &next_id);
825 if let Err(ix) = buffer_state.excerpts.binary_search(&id) {
826 buffer_state.excerpts.insert(ix, id.clone());
827 }
828 let range = ExcerptRange {
829 context: buffer_snapshot.anchor_before(&range.context.start)
830 ..buffer_snapshot.anchor_after(&range.context.end),
831 primary: range.primary.map(|primary| {
832 buffer_snapshot.anchor_before(&primary.start)
833 ..buffer_snapshot.anchor_after(&primary.end)
834 }),
835 };
836 let excerpt = Excerpt::new(
837 id.clone(),
838 post_inc(&mut self.next_excerpt_key),
839 buffer_id,
840 buffer_snapshot.clone(),
841 range,
842 ranges.peek().is_some() || cursor.item().is_some(),
843 );
844 new_excerpts.push(excerpt, &());
845 prev_id = id.clone();
846 ids.push(id);
847 }
848 self.used_excerpt_ids.edit(
849 ids.iter().cloned().map(sum_tree::Edit::Insert).collect(),
850 &(),
851 );
852
853 let edit_end = new_excerpts.summary().text.bytes;
854
855 let suffix = cursor.suffix(&());
856 let changed_trailing_excerpt = suffix.is_empty();
857 new_excerpts.push_tree(suffix, &());
858 drop(cursor);
859 snapshot.excerpts = new_excerpts;
860 if changed_trailing_excerpt {
861 snapshot.trailing_excerpt_update_count += 1;
862 }
863
864 self.subscriptions.publish_mut([Edit {
865 old: edit_start..edit_start,
866 new: edit_start..edit_end,
867 }]);
868 cx.emit(Event::Edited);
869 cx.notify();
870 ids
871 }
872
873 pub fn clear(&mut self, cx: &mut ModelContext<Self>) {
874 self.sync(cx);
875 self.buffers.borrow_mut().clear();
876 let mut snapshot = self.snapshot.borrow_mut();
877 let prev_len = snapshot.len();
878 snapshot.excerpts = Default::default();
879 snapshot.trailing_excerpt_update_count += 1;
880 snapshot.is_dirty = false;
881 snapshot.has_conflict = false;
882
883 self.subscriptions.publish_mut([Edit {
884 old: 0..prev_len,
885 new: 0..0,
886 }]);
887 cx.emit(Event::Edited);
888 cx.notify();
889 }
890
891 pub fn excerpts_for_buffer(
892 &self,
893 buffer: &ModelHandle<Buffer>,
894 cx: &AppContext,
895 ) -> Vec<(ExcerptId, ExcerptRange<text::Anchor>)> {
896 let mut excerpts = Vec::new();
897 let snapshot = self.read(cx);
898 let buffers = self.buffers.borrow();
899 let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();
900 for excerpt_id in buffers
901 .get(&buffer.id())
902 .map(|state| &state.excerpts)
903 .into_iter()
904 .flatten()
905 {
906 cursor.seek_forward(&Some(excerpt_id), Bias::Left, &());
907 if let Some(excerpt) = cursor.item() {
908 if excerpt.id == *excerpt_id {
909 excerpts.push((excerpt.id.clone(), excerpt.range.clone()));
910 }
911 }
912 }
913
914 excerpts
915 }
916
917 pub fn excerpt_ids(&self) -> Vec<ExcerptId> {
918 self.buffers
919 .borrow()
920 .values()
921 .flat_map(|state| state.excerpts.iter().cloned())
922 .collect()
923 }
924
925 pub fn excerpt_containing(
926 &self,
927 position: impl ToOffset,
928 cx: &AppContext,
929 ) -> Option<(ModelHandle<Buffer>, Range<text::Anchor>)> {
930 let snapshot = self.read(cx);
931 let position = position.to_offset(&snapshot);
932
933 let mut cursor = snapshot.excerpts.cursor::<usize>();
934 cursor.seek(&position, Bias::Right, &());
935 cursor.item().map(|excerpt| {
936 (
937 self.buffers
938 .borrow()
939 .get(&excerpt.buffer_id)
940 .unwrap()
941 .buffer
942 .clone(),
943 excerpt.range.context.clone(),
944 )
945 })
946 }
947
948 // If point is at the end of the buffer, the last excerpt is returned
949 pub fn point_to_buffer_offset<'a, T: ToOffset>(
950 &'a self,
951 point: T,
952 cx: &AppContext,
953 ) -> Option<(ModelHandle<Buffer>, usize)> {
954 let snapshot = self.read(cx);
955 let offset = point.to_offset(&snapshot);
956 let mut cursor = snapshot.excerpts.cursor::<usize>();
957 cursor.seek(&offset, Bias::Right, &());
958 if cursor.item().is_none() {
959 cursor.prev(&());
960 }
961
962 cursor.item().map(|excerpt| {
963 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
964 let buffer_point = excerpt_start + offset - *cursor.start();
965 let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone();
966
967 (buffer, buffer_point)
968 })
969 }
970
971 pub fn range_to_buffer_ranges<'a, T: ToOffset>(
972 &'a self,
973 range: Range<T>,
974 cx: &AppContext,
975 ) -> Vec<(ModelHandle<Buffer>, Range<usize>)> {
976 let snapshot = self.read(cx);
977 let start = range.start.to_offset(&snapshot);
978 let end = range.end.to_offset(&snapshot);
979
980 let mut result = Vec::new();
981 let mut cursor = snapshot.excerpts.cursor::<usize>();
982 cursor.seek(&start, Bias::Right, &());
983 while let Some(excerpt) = cursor.item() {
984 if *cursor.start() > end {
985 break;
986 }
987
988 let mut end_before_newline = cursor.end(&());
989 if excerpt.has_trailing_newline {
990 end_before_newline -= 1;
991 }
992 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
993 let start = excerpt_start + (cmp::max(start, *cursor.start()) - *cursor.start());
994 let end = excerpt_start + (cmp::min(end, end_before_newline) - *cursor.start());
995 let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone();
996 result.push((buffer, start..end));
997 cursor.next(&());
998 }
999
1000 result
1001 }
1002
1003 pub fn remove_excerpts<'a>(
1004 &mut self,
1005 excerpt_ids: impl IntoIterator<Item = &'a ExcerptId>,
1006 cx: &mut ModelContext<Self>,
1007 ) {
1008 self.sync(cx);
1009 let mut buffers = self.buffers.borrow_mut();
1010 let mut snapshot = self.snapshot.borrow_mut();
1011 let mut new_excerpts = SumTree::new();
1012 let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>();
1013 let mut edits = Vec::new();
1014 let mut excerpt_ids = excerpt_ids.into_iter().peekable();
1015
1016 while let Some(mut excerpt_id) = excerpt_ids.next() {
1017 // Seek to the next excerpt to remove, preserving any preceding excerpts.
1018 new_excerpts.push_tree(cursor.slice(&Some(excerpt_id), Bias::Left, &()), &());
1019 if let Some(mut excerpt) = cursor.item() {
1020 if excerpt.id != *excerpt_id {
1021 continue;
1022 }
1023 let mut old_start = cursor.start().1;
1024
1025 // Skip over the removed excerpt.
1026 loop {
1027 if let Some(buffer_state) = buffers.get_mut(&excerpt.buffer_id) {
1028 buffer_state.excerpts.retain(|id| id != excerpt_id);
1029 if buffer_state.excerpts.is_empty() {
1030 buffers.remove(&excerpt.buffer_id);
1031 }
1032 }
1033 cursor.next(&());
1034
1035 // Skip over any subsequent excerpts that are also removed.
1036 if let Some(&next_excerpt_id) = excerpt_ids.peek() {
1037 if let Some(next_excerpt) = cursor.item() {
1038 if next_excerpt.id == *next_excerpt_id {
1039 excerpt = next_excerpt;
1040 excerpt_id = excerpt_ids.next().unwrap();
1041 continue;
1042 }
1043 }
1044 }
1045
1046 break;
1047 }
1048
1049 // When removing the last excerpt, remove the trailing newline from
1050 // the previous excerpt.
1051 if cursor.item().is_none() && old_start > 0 {
1052 old_start -= 1;
1053 new_excerpts.update_last(|e| e.has_trailing_newline = false, &());
1054 }
1055
1056 // Push an edit for the removal of this run of excerpts.
1057 let old_end = cursor.start().1;
1058 let new_start = new_excerpts.summary().text.bytes;
1059 edits.push(Edit {
1060 old: old_start..old_end,
1061 new: new_start..new_start,
1062 });
1063 }
1064 }
1065 let suffix = cursor.suffix(&());
1066 let changed_trailing_excerpt = suffix.is_empty();
1067 new_excerpts.push_tree(suffix, &());
1068 drop(cursor);
1069 snapshot.excerpts = new_excerpts;
1070 if changed_trailing_excerpt {
1071 snapshot.trailing_excerpt_update_count += 1;
1072 }
1073
1074 self.subscriptions.publish_mut(edits);
1075 cx.emit(Event::Edited);
1076 cx.notify();
1077 }
1078
1079 pub fn text_anchor_for_position<'a, T: ToOffset>(
1080 &'a self,
1081 position: T,
1082 cx: &AppContext,
1083 ) -> Option<(ModelHandle<Buffer>, language::Anchor)> {
1084 let snapshot = self.read(cx);
1085 let anchor = snapshot.anchor_before(position);
1086 let buffer = self
1087 .buffers
1088 .borrow()
1089 .get(&anchor.buffer_id?)?
1090 .buffer
1091 .clone();
1092 Some((buffer, anchor.text_anchor))
1093 }
1094
1095 fn on_buffer_event(
1096 &mut self,
1097 _: ModelHandle<Buffer>,
1098 event: &Event,
1099 cx: &mut ModelContext<Self>,
1100 ) {
1101 cx.emit(event.clone());
1102 }
1103
1104 pub fn all_buffers(&self) -> HashSet<ModelHandle<Buffer>> {
1105 self.buffers
1106 .borrow()
1107 .values()
1108 .map(|state| state.buffer.clone())
1109 .collect()
1110 }
1111
1112 pub fn buffer(&self, buffer_id: usize) -> Option<ModelHandle<Buffer>> {
1113 self.buffers
1114 .borrow()
1115 .get(&buffer_id)
1116 .map(|state| state.buffer.clone())
1117 }
1118
1119 pub fn save(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
1120 let mut save_tasks = Vec::new();
1121 for BufferState { buffer, .. } in self.buffers.borrow().values() {
1122 save_tasks.push(buffer.update(cx, |buffer, cx| buffer.save(cx)));
1123 }
1124
1125 cx.spawn(|_, _| async move {
1126 for save in save_tasks {
1127 save.await?;
1128 }
1129 Ok(())
1130 })
1131 }
1132
1133 pub fn is_completion_trigger<T>(&self, position: T, text: &str, cx: &AppContext) -> bool
1134 where
1135 T: ToOffset,
1136 {
1137 let mut chars = text.chars();
1138 let char = if let Some(char) = chars.next() {
1139 char
1140 } else {
1141 return false;
1142 };
1143 if chars.next().is_some() {
1144 return false;
1145 }
1146
1147 if char.is_alphanumeric() || char == '_' {
1148 return true;
1149 }
1150
1151 let snapshot = self.snapshot(cx);
1152 let anchor = snapshot.anchor_before(position);
1153 anchor
1154 .buffer_id
1155 .and_then(|buffer_id| {
1156 let buffer = self.buffers.borrow().get(&buffer_id)?.buffer.clone();
1157 Some(
1158 buffer
1159 .read(cx)
1160 .completion_triggers()
1161 .iter()
1162 .any(|string| string == text),
1163 )
1164 })
1165 .unwrap_or(false)
1166 }
1167
1168 pub fn language_at<'a, T: ToOffset>(
1169 &self,
1170 point: T,
1171 cx: &'a AppContext,
1172 ) -> Option<&'a Arc<Language>> {
1173 self.point_to_buffer_offset(point, cx)
1174 .and_then(|(buffer, _)| buffer.read(cx).language())
1175 }
1176
1177 pub fn files<'a>(&'a self, cx: &'a AppContext) -> SmallVec<[&'a dyn File; 2]> {
1178 let buffers = self.buffers.borrow();
1179 buffers
1180 .values()
1181 .filter_map(|buffer| buffer.buffer.read(cx).file())
1182 .collect()
1183 }
1184
1185 pub fn title(&self, cx: &AppContext) -> String {
1186 if let Some(title) = self.title.clone() {
1187 return title;
1188 }
1189
1190 if let Some(buffer) = self.as_singleton() {
1191 if let Some(file) = buffer.read(cx).file() {
1192 return file.file_name(cx).to_string_lossy().into();
1193 }
1194 }
1195
1196 "untitled".into()
1197 }
1198
1199 #[cfg(test)]
1200 pub fn is_parsing(&self, cx: &AppContext) -> bool {
1201 self.as_singleton().unwrap().read(cx).is_parsing()
1202 }
1203
1204 fn sync(&self, cx: &AppContext) {
1205 let mut snapshot = self.snapshot.borrow_mut();
1206 let mut excerpts_to_edit = Vec::new();
1207 let mut reparsed = false;
1208 let mut diagnostics_updated = false;
1209 let mut is_dirty = false;
1210 let mut has_conflict = false;
1211 let mut edited = false;
1212 let mut buffers = self.buffers.borrow_mut();
1213 for buffer_state in buffers.values_mut() {
1214 let buffer = buffer_state.buffer.read(cx);
1215 let version = buffer.version();
1216 let parse_count = buffer.parse_count();
1217 let selections_update_count = buffer.selections_update_count();
1218 let diagnostics_update_count = buffer.diagnostics_update_count();
1219 let file_update_count = buffer.file_update_count();
1220
1221 let buffer_edited = version.changed_since(&buffer_state.last_version);
1222 let buffer_reparsed = parse_count > buffer_state.last_parse_count;
1223 let buffer_selections_updated =
1224 selections_update_count > buffer_state.last_selections_update_count;
1225 let buffer_diagnostics_updated =
1226 diagnostics_update_count > buffer_state.last_diagnostics_update_count;
1227 let buffer_file_updated = file_update_count > buffer_state.last_file_update_count;
1228 if buffer_edited
1229 || buffer_reparsed
1230 || buffer_selections_updated
1231 || buffer_diagnostics_updated
1232 || buffer_file_updated
1233 {
1234 buffer_state.last_version = version;
1235 buffer_state.last_parse_count = parse_count;
1236 buffer_state.last_selections_update_count = selections_update_count;
1237 buffer_state.last_diagnostics_update_count = diagnostics_update_count;
1238 buffer_state.last_file_update_count = file_update_count;
1239 excerpts_to_edit.extend(
1240 buffer_state
1241 .excerpts
1242 .iter()
1243 .map(|excerpt_id| (excerpt_id, buffer_state.buffer.clone(), buffer_edited)),
1244 );
1245 }
1246
1247 edited |= buffer_edited;
1248 reparsed |= buffer_reparsed;
1249 diagnostics_updated |= buffer_diagnostics_updated;
1250 is_dirty |= buffer.is_dirty();
1251 has_conflict |= buffer.has_conflict();
1252 }
1253 if edited {
1254 snapshot.edit_count += 1;
1255 }
1256 if reparsed {
1257 snapshot.parse_count += 1;
1258 }
1259 if diagnostics_updated {
1260 snapshot.diagnostics_update_count += 1;
1261 }
1262 snapshot.is_dirty = is_dirty;
1263 snapshot.has_conflict = has_conflict;
1264
1265 excerpts_to_edit.sort_unstable_by_key(|(excerpt_id, _, _)| *excerpt_id);
1266
1267 let mut edits = Vec::new();
1268 let mut new_excerpts = SumTree::new();
1269 let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>();
1270
1271 for (id, buffer, buffer_edited) in excerpts_to_edit {
1272 new_excerpts.push_tree(cursor.slice(&Some(id), Bias::Left, &()), &());
1273 let old_excerpt = cursor.item().unwrap();
1274 let buffer_id = buffer.id();
1275 let buffer = buffer.read(cx);
1276
1277 let mut new_excerpt;
1278 if buffer_edited {
1279 edits.extend(
1280 buffer
1281 .edits_since_in_range::<usize>(
1282 old_excerpt.buffer.version(),
1283 old_excerpt.range.context.clone(),
1284 )
1285 .map(|mut edit| {
1286 let excerpt_old_start = cursor.start().1;
1287 let excerpt_new_start = new_excerpts.summary().text.bytes;
1288 edit.old.start += excerpt_old_start;
1289 edit.old.end += excerpt_old_start;
1290 edit.new.start += excerpt_new_start;
1291 edit.new.end += excerpt_new_start;
1292 edit
1293 }),
1294 );
1295
1296 new_excerpt = Excerpt::new(
1297 id.clone(),
1298 old_excerpt.key,
1299 buffer_id,
1300 buffer.snapshot(),
1301 old_excerpt.range.clone(),
1302 old_excerpt.has_trailing_newline,
1303 );
1304 } else {
1305 new_excerpt = old_excerpt.clone();
1306 new_excerpt.buffer = buffer.snapshot();
1307 }
1308
1309 new_excerpts.push(new_excerpt, &());
1310 cursor.next(&());
1311 }
1312 new_excerpts.push_tree(cursor.suffix(&()), &());
1313
1314 drop(cursor);
1315 snapshot.excerpts = new_excerpts;
1316
1317 self.subscriptions.publish(edits);
1318 }
1319}
1320
1321#[cfg(any(test, feature = "test-support"))]
1322impl MultiBuffer {
1323 pub fn build_simple(text: &str, cx: &mut gpui::MutableAppContext) -> ModelHandle<Self> {
1324 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
1325 cx.add_model(|cx| Self::singleton(buffer, cx))
1326 }
1327
1328 pub fn build_random(
1329 rng: &mut impl rand::Rng,
1330 cx: &mut gpui::MutableAppContext,
1331 ) -> ModelHandle<Self> {
1332 cx.add_model(|cx| {
1333 let mut multibuffer = MultiBuffer::new(0);
1334 let mutation_count = rng.gen_range(1..=5);
1335 multibuffer.randomly_edit_excerpts(rng, mutation_count, cx);
1336 multibuffer
1337 })
1338 }
1339
1340 pub fn randomly_edit(
1341 &mut self,
1342 rng: &mut impl rand::Rng,
1343 edit_count: usize,
1344 cx: &mut ModelContext<Self>,
1345 ) {
1346 use text::RandomCharIter;
1347
1348 let snapshot = self.read(cx);
1349 let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
1350 let mut last_end = None;
1351 for _ in 0..edit_count {
1352 if last_end.map_or(false, |last_end| last_end >= snapshot.len()) {
1353 break;
1354 }
1355
1356 let new_start = last_end.map_or(0, |last_end| last_end + 1);
1357 let end = snapshot.clip_offset(rng.gen_range(new_start..=snapshot.len()), Bias::Right);
1358 let start = snapshot.clip_offset(rng.gen_range(new_start..=end), Bias::Right);
1359 last_end = Some(end);
1360
1361 let mut range = start..end;
1362 if rng.gen_bool(0.2) {
1363 mem::swap(&mut range.start, &mut range.end);
1364 }
1365
1366 let new_text_len = rng.gen_range(0..10);
1367 let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
1368
1369 edits.push((range, new_text.into()));
1370 }
1371 log::info!("mutating multi-buffer with {:?}", edits);
1372 drop(snapshot);
1373
1374 self.edit(edits, cx);
1375 }
1376
1377 pub fn randomly_edit_excerpts(
1378 &mut self,
1379 rng: &mut impl rand::Rng,
1380 mutation_count: usize,
1381 cx: &mut ModelContext<Self>,
1382 ) {
1383 use rand::prelude::*;
1384 use std::env;
1385 use text::RandomCharIter;
1386
1387 let max_excerpts = env::var("MAX_EXCERPTS")
1388 .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))
1389 .unwrap_or(5);
1390
1391 let mut buffers = Vec::new();
1392 for _ in 0..mutation_count {
1393 if rng.gen_bool(0.05) {
1394 log::info!("Clearing multi-buffer");
1395 self.clear(cx);
1396 continue;
1397 }
1398
1399 let excerpt_ids = self
1400 .buffers
1401 .borrow()
1402 .values()
1403 .flat_map(|b| &b.excerpts)
1404 .cloned()
1405 .collect::<Vec<_>>();
1406 if excerpt_ids.len() == 0 || (rng.gen() && excerpt_ids.len() < max_excerpts) {
1407 let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() {
1408 let text = RandomCharIter::new(&mut *rng).take(10).collect::<String>();
1409 buffers.push(cx.add_model(|cx| Buffer::new(0, text, cx)));
1410 let buffer = buffers.last().unwrap();
1411 log::info!(
1412 "Creating new buffer {} with text: {:?}",
1413 buffer.id(),
1414 buffer.read(cx).text()
1415 );
1416 buffers.last().unwrap().clone()
1417 } else {
1418 self.buffers
1419 .borrow()
1420 .values()
1421 .choose(rng)
1422 .unwrap()
1423 .buffer
1424 .clone()
1425 };
1426
1427 let buffer = buffer_handle.read(cx);
1428 let buffer_text = buffer.text();
1429 let ranges = (0..rng.gen_range(0..5))
1430 .map(|_| {
1431 let end_ix =
1432 buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
1433 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
1434 ExcerptRange {
1435 context: start_ix..end_ix,
1436 primary: None,
1437 }
1438 })
1439 .collect::<Vec<_>>();
1440 log::info!(
1441 "Inserting excerpts from buffer {} and ranges {:?}: {:?}",
1442 buffer_handle.id(),
1443 ranges,
1444 ranges
1445 .iter()
1446 .map(|range| &buffer_text[range.context.clone()])
1447 .collect::<Vec<_>>()
1448 );
1449
1450 let excerpt_id = self.push_excerpts(buffer_handle.clone(), ranges, cx);
1451 log::info!("Inserted with id: {:?}", excerpt_id);
1452 } else {
1453 let remove_count = rng.gen_range(1..=excerpt_ids.len());
1454 let mut excerpts_to_remove = excerpt_ids
1455 .choose_multiple(rng, remove_count)
1456 .cloned()
1457 .collect::<Vec<_>>();
1458 excerpts_to_remove.sort();
1459 log::info!("Removing excerpts {:?}", excerpts_to_remove);
1460 self.remove_excerpts(&excerpts_to_remove, cx);
1461 }
1462 }
1463 }
1464
1465 pub fn randomly_mutate(
1466 &mut self,
1467 rng: &mut impl rand::Rng,
1468 mutation_count: usize,
1469 cx: &mut ModelContext<Self>,
1470 ) {
1471 use rand::prelude::*;
1472
1473 if rng.gen_bool(0.7) || self.singleton {
1474 let buffer = self
1475 .buffers
1476 .borrow()
1477 .values()
1478 .choose(rng)
1479 .map(|state| state.buffer.clone());
1480
1481 if rng.gen() && buffer.is_some() {
1482 buffer.unwrap().update(cx, |buffer, cx| {
1483 if rng.gen() {
1484 buffer.randomly_edit(rng, mutation_count, cx);
1485 } else {
1486 buffer.randomly_undo_redo(rng, cx);
1487 }
1488 });
1489 } else {
1490 self.randomly_edit(rng, mutation_count, cx);
1491 }
1492 } else {
1493 self.randomly_edit_excerpts(rng, mutation_count, cx);
1494 }
1495 }
1496}
1497
1498impl Entity for MultiBuffer {
1499 type Event = language::Event;
1500}
1501
1502impl MultiBufferSnapshot {
1503 pub fn text(&self) -> String {
1504 self.chunks(0..self.len(), false)
1505 .map(|chunk| chunk.text)
1506 .collect()
1507 }
1508
1509 pub fn reversed_chars_at<'a, T: ToOffset>(
1510 &'a self,
1511 position: T,
1512 ) -> impl Iterator<Item = char> + 'a {
1513 let mut offset = position.to_offset(self);
1514 let mut cursor = self.excerpts.cursor::<usize>();
1515 cursor.seek(&offset, Bias::Left, &());
1516 let mut excerpt_chunks = cursor.item().map(|excerpt| {
1517 let end_before_footer = cursor.start() + excerpt.text_summary.bytes;
1518 let start = excerpt.range.context.start.to_offset(&excerpt.buffer);
1519 let end = start + (cmp::min(offset, end_before_footer) - cursor.start());
1520 excerpt.buffer.reversed_chunks_in_range(start..end)
1521 });
1522 iter::from_fn(move || {
1523 if offset == *cursor.start() {
1524 cursor.prev(&());
1525 let excerpt = cursor.item()?;
1526 excerpt_chunks = Some(
1527 excerpt
1528 .buffer
1529 .reversed_chunks_in_range(excerpt.range.context.clone()),
1530 );
1531 }
1532
1533 let excerpt = cursor.item().unwrap();
1534 if offset == cursor.end(&()) && excerpt.has_trailing_newline {
1535 offset -= 1;
1536 Some("\n")
1537 } else {
1538 let chunk = excerpt_chunks.as_mut().unwrap().next().unwrap();
1539 offset -= chunk.len();
1540 Some(chunk)
1541 }
1542 })
1543 .flat_map(|c| c.chars().rev())
1544 }
1545
1546 pub fn chars_at<'a, T: ToOffset>(&'a self, position: T) -> impl Iterator<Item = char> + 'a {
1547 let offset = position.to_offset(self);
1548 self.text_for_range(offset..self.len())
1549 .flat_map(|chunk| chunk.chars())
1550 }
1551
1552 pub fn text_for_range<'a, T: ToOffset>(
1553 &'a self,
1554 range: Range<T>,
1555 ) -> impl Iterator<Item = &'a str> {
1556 self.chunks(range, false).map(|chunk| chunk.text)
1557 }
1558
1559 pub fn is_line_blank(&self, row: u32) -> bool {
1560 self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row)))
1561 .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
1562 }
1563
1564 pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
1565 where
1566 T: ToOffset,
1567 {
1568 let position = position.to_offset(self);
1569 position == self.clip_offset(position, Bias::Left)
1570 && self
1571 .bytes_in_range(position..self.len())
1572 .flatten()
1573 .copied()
1574 .take(needle.len())
1575 .eq(needle.bytes())
1576 }
1577
1578 pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) {
1579 let mut start = start.to_offset(self);
1580 let mut end = start;
1581 let mut next_chars = self.chars_at(start).peekable();
1582 let mut prev_chars = self.reversed_chars_at(start).peekable();
1583 let word_kind = cmp::max(
1584 prev_chars.peek().copied().map(char_kind),
1585 next_chars.peek().copied().map(char_kind),
1586 );
1587
1588 for ch in prev_chars {
1589 if Some(char_kind(ch)) == word_kind && ch != '\n' {
1590 start -= ch.len_utf8();
1591 } else {
1592 break;
1593 }
1594 }
1595
1596 for ch in next_chars {
1597 if Some(char_kind(ch)) == word_kind && ch != '\n' {
1598 end += ch.len_utf8();
1599 } else {
1600 break;
1601 }
1602 }
1603
1604 (start..end, word_kind)
1605 }
1606
1607 pub fn as_singleton(&self) -> Option<(&ExcerptId, usize, &BufferSnapshot)> {
1608 if self.singleton {
1609 self.excerpts
1610 .iter()
1611 .next()
1612 .map(|e| (&e.id, e.buffer_id, &e.buffer))
1613 } else {
1614 None
1615 }
1616 }
1617
1618 pub fn len(&self) -> usize {
1619 self.excerpts.summary().text.bytes
1620 }
1621
1622 pub fn max_buffer_row(&self) -> u32 {
1623 self.excerpts.summary().max_buffer_row
1624 }
1625
1626 pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
1627 if let Some((_, _, buffer)) = self.as_singleton() {
1628 return buffer.clip_offset(offset, bias);
1629 }
1630
1631 let mut cursor = self.excerpts.cursor::<usize>();
1632 cursor.seek(&offset, Bias::Right, &());
1633 let overshoot = if let Some(excerpt) = cursor.item() {
1634 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
1635 let buffer_offset = excerpt
1636 .buffer
1637 .clip_offset(excerpt_start + (offset - cursor.start()), bias);
1638 buffer_offset.saturating_sub(excerpt_start)
1639 } else {
1640 0
1641 };
1642 cursor.start() + overshoot
1643 }
1644
1645 pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
1646 if let Some((_, _, buffer)) = self.as_singleton() {
1647 return buffer.clip_point(point, bias);
1648 }
1649
1650 let mut cursor = self.excerpts.cursor::<Point>();
1651 cursor.seek(&point, Bias::Right, &());
1652 let overshoot = if let Some(excerpt) = cursor.item() {
1653 let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
1654 let buffer_point = excerpt
1655 .buffer
1656 .clip_point(excerpt_start + (point - cursor.start()), bias);
1657 buffer_point.saturating_sub(excerpt_start)
1658 } else {
1659 Point::zero()
1660 };
1661 *cursor.start() + overshoot
1662 }
1663
1664 pub fn clip_point_utf16(&self, point: PointUtf16, bias: Bias) -> PointUtf16 {
1665 if let Some((_, _, buffer)) = self.as_singleton() {
1666 return buffer.clip_point_utf16(point, bias);
1667 }
1668
1669 let mut cursor = self.excerpts.cursor::<PointUtf16>();
1670 cursor.seek(&point, Bias::Right, &());
1671 let overshoot = if let Some(excerpt) = cursor.item() {
1672 let excerpt_start = excerpt
1673 .buffer
1674 .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
1675 let buffer_point = excerpt
1676 .buffer
1677 .clip_point_utf16(excerpt_start + (point - cursor.start()), bias);
1678 buffer_point.saturating_sub(excerpt_start)
1679 } else {
1680 PointUtf16::zero()
1681 };
1682 *cursor.start() + overshoot
1683 }
1684
1685 pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> MultiBufferBytes<'a> {
1686 let range = range.start.to_offset(self)..range.end.to_offset(self);
1687 let mut excerpts = self.excerpts.cursor::<usize>();
1688 excerpts.seek(&range.start, Bias::Right, &());
1689
1690 let mut chunk = &[][..];
1691 let excerpt_bytes = if let Some(excerpt) = excerpts.item() {
1692 let mut excerpt_bytes = excerpt
1693 .bytes_in_range(range.start - excerpts.start()..range.end - excerpts.start());
1694 chunk = excerpt_bytes.next().unwrap_or(&[][..]);
1695 Some(excerpt_bytes)
1696 } else {
1697 None
1698 };
1699
1700 MultiBufferBytes {
1701 range,
1702 excerpts,
1703 excerpt_bytes,
1704 chunk,
1705 }
1706 }
1707
1708 pub fn buffer_rows<'a>(&'a self, start_row: u32) -> MultiBufferRows<'a> {
1709 let mut result = MultiBufferRows {
1710 buffer_row_range: 0..0,
1711 excerpts: self.excerpts.cursor(),
1712 };
1713 result.seek(start_row);
1714 result
1715 }
1716
1717 pub fn chunks<'a, T: ToOffset>(
1718 &'a self,
1719 range: Range<T>,
1720 language_aware: bool,
1721 ) -> MultiBufferChunks<'a> {
1722 let range = range.start.to_offset(self)..range.end.to_offset(self);
1723 let mut chunks = MultiBufferChunks {
1724 range: range.clone(),
1725 excerpts: self.excerpts.cursor(),
1726 excerpt_chunks: None,
1727 language_aware,
1728 };
1729 chunks.seek(range.start);
1730 chunks
1731 }
1732
1733 pub fn offset_to_point(&self, offset: usize) -> Point {
1734 if let Some((_, _, buffer)) = self.as_singleton() {
1735 return buffer.offset_to_point(offset);
1736 }
1737
1738 let mut cursor = self.excerpts.cursor::<(usize, Point)>();
1739 cursor.seek(&offset, Bias::Right, &());
1740 if let Some(excerpt) = cursor.item() {
1741 let (start_offset, start_point) = cursor.start();
1742 let overshoot = offset - start_offset;
1743 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
1744 let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
1745 let buffer_point = excerpt
1746 .buffer
1747 .offset_to_point(excerpt_start_offset + overshoot);
1748 *start_point + (buffer_point - excerpt_start_point)
1749 } else {
1750 self.excerpts.summary().text.lines
1751 }
1752 }
1753
1754 pub fn offset_to_point_utf16(&self, offset: usize) -> PointUtf16 {
1755 if let Some((_, _, buffer)) = self.as_singleton() {
1756 return buffer.offset_to_point_utf16(offset);
1757 }
1758
1759 let mut cursor = self.excerpts.cursor::<(usize, PointUtf16)>();
1760 cursor.seek(&offset, Bias::Right, &());
1761 if let Some(excerpt) = cursor.item() {
1762 let (start_offset, start_point) = cursor.start();
1763 let overshoot = offset - start_offset;
1764 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
1765 let excerpt_start_point = excerpt.range.context.start.to_point_utf16(&excerpt.buffer);
1766 let buffer_point = excerpt
1767 .buffer
1768 .offset_to_point_utf16(excerpt_start_offset + overshoot);
1769 *start_point + (buffer_point - excerpt_start_point)
1770 } else {
1771 self.excerpts.summary().text.lines_utf16
1772 }
1773 }
1774
1775 pub fn point_to_point_utf16(&self, point: Point) -> PointUtf16 {
1776 if let Some((_, _, buffer)) = self.as_singleton() {
1777 return buffer.point_to_point_utf16(point);
1778 }
1779
1780 let mut cursor = self.excerpts.cursor::<(Point, PointUtf16)>();
1781 cursor.seek(&point, Bias::Right, &());
1782 if let Some(excerpt) = cursor.item() {
1783 let (start_offset, start_point) = cursor.start();
1784 let overshoot = point - start_offset;
1785 let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
1786 let excerpt_start_point_utf16 =
1787 excerpt.range.context.start.to_point_utf16(&excerpt.buffer);
1788 let buffer_point = excerpt
1789 .buffer
1790 .point_to_point_utf16(excerpt_start_point + overshoot);
1791 *start_point + (buffer_point - excerpt_start_point_utf16)
1792 } else {
1793 self.excerpts.summary().text.lines_utf16
1794 }
1795 }
1796
1797 pub fn point_to_offset(&self, point: Point) -> usize {
1798 if let Some((_, _, buffer)) = self.as_singleton() {
1799 return buffer.point_to_offset(point);
1800 }
1801
1802 let mut cursor = self.excerpts.cursor::<(Point, usize)>();
1803 cursor.seek(&point, Bias::Right, &());
1804 if let Some(excerpt) = cursor.item() {
1805 let (start_point, start_offset) = cursor.start();
1806 let overshoot = point - start_point;
1807 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
1808 let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
1809 let buffer_offset = excerpt
1810 .buffer
1811 .point_to_offset(excerpt_start_point + overshoot);
1812 *start_offset + buffer_offset - excerpt_start_offset
1813 } else {
1814 self.excerpts.summary().text.bytes
1815 }
1816 }
1817
1818 pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
1819 if let Some((_, _, buffer)) = self.as_singleton() {
1820 return buffer.point_utf16_to_offset(point);
1821 }
1822
1823 let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>();
1824 cursor.seek(&point, Bias::Right, &());
1825 if let Some(excerpt) = cursor.item() {
1826 let (start_point, start_offset) = cursor.start();
1827 let overshoot = point - start_point;
1828 let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
1829 let excerpt_start_point = excerpt
1830 .buffer
1831 .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
1832 let buffer_offset = excerpt
1833 .buffer
1834 .point_utf16_to_offset(excerpt_start_point + overshoot);
1835 *start_offset + (buffer_offset - excerpt_start_offset)
1836 } else {
1837 self.excerpts.summary().text.bytes
1838 }
1839 }
1840
1841 pub fn indent_column_for_line(&self, row: u32) -> u32 {
1842 if let Some((buffer, range)) = self.buffer_line_for_row(row) {
1843 buffer
1844 .indent_column_for_line(range.start.row)
1845 .min(range.end.column)
1846 .saturating_sub(range.start.column)
1847 } else {
1848 0
1849 }
1850 }
1851
1852 pub fn line_len(&self, row: u32) -> u32 {
1853 if let Some((_, range)) = self.buffer_line_for_row(row) {
1854 range.end.column - range.start.column
1855 } else {
1856 0
1857 }
1858 }
1859
1860 pub fn buffer_line_for_row(&self, row: u32) -> Option<(&BufferSnapshot, Range<Point>)> {
1861 let mut cursor = self.excerpts.cursor::<Point>();
1862 cursor.seek(&Point::new(row, 0), Bias::Right, &());
1863 if let Some(excerpt) = cursor.item() {
1864 let overshoot = row - cursor.start().row;
1865 let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
1866 let excerpt_end = excerpt.range.context.end.to_point(&excerpt.buffer);
1867 let buffer_row = excerpt_start.row + overshoot;
1868 let line_start = Point::new(buffer_row, 0);
1869 let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
1870 return Some((
1871 &excerpt.buffer,
1872 line_start.max(excerpt_start)..line_end.min(excerpt_end),
1873 ));
1874 }
1875 None
1876 }
1877
1878 pub fn max_point(&self) -> Point {
1879 self.text_summary().lines
1880 }
1881
1882 pub fn text_summary(&self) -> TextSummary {
1883 self.excerpts.summary().text.clone()
1884 }
1885
1886 pub fn text_summary_for_range<'a, D, O>(&'a self, range: Range<O>) -> D
1887 where
1888 D: TextDimension,
1889 O: ToOffset,
1890 {
1891 let mut summary = D::default();
1892 let mut range = range.start.to_offset(self)..range.end.to_offset(self);
1893 let mut cursor = self.excerpts.cursor::<usize>();
1894 cursor.seek(&range.start, Bias::Right, &());
1895 if let Some(excerpt) = cursor.item() {
1896 let mut end_before_newline = cursor.end(&());
1897 if excerpt.has_trailing_newline {
1898 end_before_newline -= 1;
1899 }
1900
1901 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
1902 let start_in_excerpt = excerpt_start + (range.start - cursor.start());
1903 let end_in_excerpt =
1904 excerpt_start + (cmp::min(end_before_newline, range.end) - cursor.start());
1905 summary.add_assign(
1906 &excerpt
1907 .buffer
1908 .text_summary_for_range(start_in_excerpt..end_in_excerpt),
1909 );
1910
1911 if range.end > end_before_newline {
1912 summary.add_assign(&D::from_text_summary(&TextSummary {
1913 bytes: 1,
1914 lines: Point::new(1 as u32, 0),
1915 lines_utf16: PointUtf16::new(1 as u32, 0),
1916 first_line_chars: 0,
1917 last_line_chars: 0,
1918 longest_row: 0,
1919 longest_row_chars: 0,
1920 }));
1921 }
1922
1923 cursor.next(&());
1924 }
1925
1926 if range.end > *cursor.start() {
1927 summary.add_assign(&D::from_text_summary(&cursor.summary::<_, TextSummary>(
1928 &range.end,
1929 Bias::Right,
1930 &(),
1931 )));
1932 if let Some(excerpt) = cursor.item() {
1933 range.end = cmp::max(*cursor.start(), range.end);
1934
1935 let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
1936 let end_in_excerpt = excerpt_start + (range.end - cursor.start());
1937 summary.add_assign(
1938 &excerpt
1939 .buffer
1940 .text_summary_for_range(excerpt_start..end_in_excerpt),
1941 );
1942 }
1943 }
1944
1945 summary
1946 }
1947
1948 pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
1949 where
1950 D: TextDimension + Ord + Sub<D, Output = D>,
1951 {
1952 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1953 cursor.seek(&Some(&anchor.excerpt_id), Bias::Left, &());
1954 if cursor.item().is_none() {
1955 cursor.next(&());
1956 }
1957
1958 let mut position = D::from_text_summary(&cursor.start().text);
1959 if let Some(excerpt) = cursor.item() {
1960 if excerpt.id == anchor.excerpt_id {
1961 let excerpt_buffer_start =
1962 excerpt.range.context.start.summary::<D>(&excerpt.buffer);
1963 let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer);
1964 let buffer_position = cmp::min(
1965 excerpt_buffer_end,
1966 anchor.text_anchor.summary::<D>(&excerpt.buffer),
1967 );
1968 if buffer_position > excerpt_buffer_start {
1969 position.add_assign(&(buffer_position - excerpt_buffer_start));
1970 }
1971 }
1972 }
1973 position
1974 }
1975
1976 pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
1977 where
1978 D: TextDimension + Ord + Sub<D, Output = D>,
1979 I: 'a + IntoIterator<Item = &'a Anchor>,
1980 {
1981 if let Some((_, _, buffer)) = self.as_singleton() {
1982 return buffer
1983 .summaries_for_anchors(anchors.into_iter().map(|a| &a.text_anchor))
1984 .collect();
1985 }
1986
1987 let mut anchors = anchors.into_iter().peekable();
1988 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1989 let mut summaries = Vec::new();
1990 while let Some(anchor) = anchors.peek() {
1991 let excerpt_id = &anchor.excerpt_id;
1992 let excerpt_anchors = iter::from_fn(|| {
1993 let anchor = anchors.peek()?;
1994 if anchor.excerpt_id == *excerpt_id {
1995 Some(&anchors.next().unwrap().text_anchor)
1996 } else {
1997 None
1998 }
1999 });
2000
2001 cursor.seek_forward(&Some(excerpt_id), Bias::Left, &());
2002 if cursor.item().is_none() {
2003 cursor.next(&());
2004 }
2005
2006 let position = D::from_text_summary(&cursor.start().text);
2007 if let Some(excerpt) = cursor.item() {
2008 if excerpt.id == *excerpt_id {
2009 let excerpt_buffer_start =
2010 excerpt.range.context.start.summary::<D>(&excerpt.buffer);
2011 let excerpt_buffer_end =
2012 excerpt.range.context.end.summary::<D>(&excerpt.buffer);
2013 summaries.extend(
2014 excerpt
2015 .buffer
2016 .summaries_for_anchors::<D, _>(excerpt_anchors)
2017 .map(move |summary| {
2018 let summary = cmp::min(excerpt_buffer_end.clone(), summary);
2019 let mut position = position.clone();
2020 let excerpt_buffer_start = excerpt_buffer_start.clone();
2021 if summary > excerpt_buffer_start {
2022 position.add_assign(&(summary - excerpt_buffer_start));
2023 }
2024 position
2025 }),
2026 );
2027 continue;
2028 }
2029 }
2030
2031 summaries.extend(excerpt_anchors.map(|_| position.clone()));
2032 }
2033
2034 summaries
2035 }
2036
2037 pub fn refresh_anchors<'a, I>(&'a self, anchors: I) -> Vec<(usize, Anchor, bool)>
2038 where
2039 I: 'a + IntoIterator<Item = &'a Anchor>,
2040 {
2041 let mut anchors = anchors.into_iter().enumerate().peekable();
2042 let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
2043 let mut result = Vec::new();
2044 while let Some((_, anchor)) = anchors.peek() {
2045 let old_excerpt_id = &anchor.excerpt_id;
2046
2047 // Find the location where this anchor's excerpt should be.
2048 cursor.seek_forward(&Some(old_excerpt_id), Bias::Left, &());
2049 if cursor.item().is_none() {
2050 cursor.next(&());
2051 }
2052
2053 let next_excerpt = cursor.item();
2054 let prev_excerpt = cursor.prev_item();
2055
2056 // Process all of the anchors for this excerpt.
2057 while let Some((_, anchor)) = anchors.peek() {
2058 if anchor.excerpt_id != *old_excerpt_id {
2059 break;
2060 }
2061 let mut kept_position = false;
2062 let (anchor_ix, anchor) = anchors.next().unwrap();
2063 let mut anchor = anchor.clone();
2064
2065 // Leave min and max anchors unchanged.
2066 if *old_excerpt_id == ExcerptId::max() || *old_excerpt_id == ExcerptId::min() {
2067 kept_position = true;
2068 }
2069 // If the old excerpt still exists at this location, then leave
2070 // the anchor unchanged.
2071 else if next_excerpt.map_or(false, |excerpt| {
2072 excerpt.id == *old_excerpt_id && excerpt.contains(&anchor)
2073 }) {
2074 kept_position = true;
2075 }
2076 // If the old excerpt no longer exists at this location, then attempt to
2077 // find an equivalent position for this anchor in an adjacent excerpt.
2078 else {
2079 for excerpt in [next_excerpt, prev_excerpt].iter().filter_map(|e| *e) {
2080 if excerpt.contains(&anchor) {
2081 anchor.excerpt_id = excerpt.id.clone();
2082 kept_position = true;
2083 break;
2084 }
2085 }
2086 }
2087 // If there's no adjacent excerpt that contains the anchor's position,
2088 // then report that the anchor has lost its position.
2089 if !kept_position {
2090 anchor = if let Some(excerpt) = next_excerpt {
2091 let mut text_anchor = excerpt
2092 .range
2093 .context
2094 .start
2095 .bias(anchor.text_anchor.bias, &excerpt.buffer);
2096 if text_anchor
2097 .cmp(&excerpt.range.context.end, &excerpt.buffer)
2098 .is_gt()
2099 {
2100 text_anchor = excerpt.range.context.end.clone();
2101 }
2102 Anchor {
2103 buffer_id: Some(excerpt.buffer_id),
2104 excerpt_id: excerpt.id.clone(),
2105 text_anchor,
2106 }
2107 } else if let Some(excerpt) = prev_excerpt {
2108 let mut text_anchor = excerpt
2109 .range
2110 .context
2111 .end
2112 .bias(anchor.text_anchor.bias, &excerpt.buffer);
2113 if text_anchor
2114 .cmp(&excerpt.range.context.start, &excerpt.buffer)
2115 .is_lt()
2116 {
2117 text_anchor = excerpt.range.context.start.clone();
2118 }
2119 Anchor {
2120 buffer_id: Some(excerpt.buffer_id),
2121 excerpt_id: excerpt.id.clone(),
2122 text_anchor,
2123 }
2124 } else if anchor.text_anchor.bias == Bias::Left {
2125 Anchor::min()
2126 } else {
2127 Anchor::max()
2128 };
2129 }
2130
2131 result.push((anchor_ix, anchor, kept_position));
2132 }
2133 }
2134 result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self));
2135 result
2136 }
2137
2138 pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
2139 self.anchor_at(position, Bias::Left)
2140 }
2141
2142 pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
2143 self.anchor_at(position, Bias::Right)
2144 }
2145
2146 pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
2147 let offset = position.to_offset(self);
2148 if let Some((excerpt_id, buffer_id, buffer)) = self.as_singleton() {
2149 return Anchor {
2150 buffer_id: Some(buffer_id),
2151 excerpt_id: excerpt_id.clone(),
2152 text_anchor: buffer.anchor_at(offset, bias),
2153 };
2154 }
2155
2156 let mut cursor = self.excerpts.cursor::<(usize, Option<&ExcerptId>)>();
2157 cursor.seek(&offset, Bias::Right, &());
2158 if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left {
2159 cursor.prev(&());
2160 }
2161 if let Some(excerpt) = cursor.item() {
2162 let mut overshoot = offset.saturating_sub(cursor.start().0);
2163 if excerpt.has_trailing_newline && offset == cursor.end(&()).0 {
2164 overshoot -= 1;
2165 bias = Bias::Right;
2166 }
2167
2168 let buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2169 let text_anchor =
2170 excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
2171 Anchor {
2172 buffer_id: Some(excerpt.buffer_id),
2173 excerpt_id: excerpt.id.clone(),
2174 text_anchor,
2175 }
2176 } else if offset == 0 && bias == Bias::Left {
2177 Anchor::min()
2178 } else {
2179 Anchor::max()
2180 }
2181 }
2182
2183 pub fn anchor_in_excerpt(&self, excerpt_id: ExcerptId, text_anchor: text::Anchor) -> Anchor {
2184 let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
2185 cursor.seek(&Some(&excerpt_id), Bias::Left, &());
2186 if let Some(excerpt) = cursor.item() {
2187 if excerpt.id == excerpt_id {
2188 let text_anchor = excerpt.clip_anchor(text_anchor);
2189 drop(cursor);
2190 return Anchor {
2191 buffer_id: Some(excerpt.buffer_id),
2192 excerpt_id,
2193 text_anchor,
2194 };
2195 }
2196 }
2197 panic!("excerpt not found");
2198 }
2199
2200 pub fn can_resolve(&self, anchor: &Anchor) -> bool {
2201 if anchor.excerpt_id == ExcerptId::min() || anchor.excerpt_id == ExcerptId::max() {
2202 true
2203 } else if let Some(excerpt) = self.excerpt(&anchor.excerpt_id) {
2204 excerpt.buffer.can_resolve(&anchor.text_anchor)
2205 } else {
2206 false
2207 }
2208 }
2209
2210 pub fn excerpt_boundaries_in_range<'a, R, T>(
2211 &'a self,
2212 range: R,
2213 ) -> impl Iterator<Item = ExcerptBoundary> + 'a
2214 where
2215 R: RangeBounds<T>,
2216 T: ToOffset,
2217 {
2218 let start_offset;
2219 let start = match range.start_bound() {
2220 Bound::Included(start) => {
2221 start_offset = start.to_offset(self);
2222 Bound::Included(start_offset)
2223 }
2224 Bound::Excluded(start) => {
2225 start_offset = start.to_offset(self);
2226 Bound::Excluded(start_offset)
2227 }
2228 Bound::Unbounded => {
2229 start_offset = 0;
2230 Bound::Unbounded
2231 }
2232 };
2233 let end = match range.end_bound() {
2234 Bound::Included(end) => Bound::Included(end.to_offset(self)),
2235 Bound::Excluded(end) => Bound::Excluded(end.to_offset(self)),
2236 Bound::Unbounded => Bound::Unbounded,
2237 };
2238 let bounds = (start, end);
2239
2240 let mut cursor = self.excerpts.cursor::<(usize, Point)>();
2241 cursor.seek(&start_offset, Bias::Right, &());
2242 if cursor.item().is_none() {
2243 cursor.prev(&());
2244 }
2245 if !bounds.contains(&cursor.start().0) {
2246 cursor.next(&());
2247 }
2248
2249 let mut prev_buffer_id = cursor.prev_item().map(|excerpt| excerpt.buffer_id);
2250 std::iter::from_fn(move || {
2251 if self.singleton {
2252 None
2253 } else if bounds.contains(&cursor.start().0) {
2254 let excerpt = cursor.item()?;
2255 let starts_new_buffer = Some(excerpt.buffer_id) != prev_buffer_id;
2256 let boundary = ExcerptBoundary {
2257 id: excerpt.id.clone(),
2258 key: excerpt.key,
2259 row: cursor.start().1.row,
2260 buffer: excerpt.buffer.clone(),
2261 range: excerpt.range.clone(),
2262 starts_new_buffer,
2263 };
2264
2265 prev_buffer_id = Some(excerpt.buffer_id);
2266 cursor.next(&());
2267 Some(boundary)
2268 } else {
2269 None
2270 }
2271 })
2272 }
2273
2274 pub fn edit_count(&self) -> usize {
2275 self.edit_count
2276 }
2277
2278 pub fn parse_count(&self) -> usize {
2279 self.parse_count
2280 }
2281
2282 pub fn enclosing_bracket_ranges<T: ToOffset>(
2283 &self,
2284 range: Range<T>,
2285 ) -> Option<(Range<usize>, Range<usize>)> {
2286 let range = range.start.to_offset(self)..range.end.to_offset(self);
2287
2288 let mut cursor = self.excerpts.cursor::<usize>();
2289 cursor.seek(&range.start, Bias::Right, &());
2290 let start_excerpt = cursor.item();
2291
2292 cursor.seek(&range.end, Bias::Right, &());
2293 let end_excerpt = cursor.item();
2294
2295 start_excerpt
2296 .zip(end_excerpt)
2297 .and_then(|(start_excerpt, end_excerpt)| {
2298 if start_excerpt.id != end_excerpt.id {
2299 return None;
2300 }
2301
2302 let excerpt_buffer_start = start_excerpt
2303 .range
2304 .context
2305 .start
2306 .to_offset(&start_excerpt.buffer);
2307 let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
2308
2309 let start_in_buffer =
2310 excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
2311 let end_in_buffer =
2312 excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
2313 let (mut start_bracket_range, mut end_bracket_range) = start_excerpt
2314 .buffer
2315 .enclosing_bracket_ranges(start_in_buffer..end_in_buffer)?;
2316
2317 if start_bracket_range.start >= excerpt_buffer_start
2318 && end_bracket_range.end < excerpt_buffer_end
2319 {
2320 start_bracket_range.start =
2321 cursor.start() + (start_bracket_range.start - excerpt_buffer_start);
2322 start_bracket_range.end =
2323 cursor.start() + (start_bracket_range.end - excerpt_buffer_start);
2324 end_bracket_range.start =
2325 cursor.start() + (end_bracket_range.start - excerpt_buffer_start);
2326 end_bracket_range.end =
2327 cursor.start() + (end_bracket_range.end - excerpt_buffer_start);
2328 Some((start_bracket_range, end_bracket_range))
2329 } else {
2330 None
2331 }
2332 })
2333 }
2334
2335 pub fn diagnostics_update_count(&self) -> usize {
2336 self.diagnostics_update_count
2337 }
2338
2339 pub fn trailing_excerpt_update_count(&self) -> usize {
2340 self.trailing_excerpt_update_count
2341 }
2342
2343 pub fn language(&self) -> Option<&Arc<Language>> {
2344 self.excerpts
2345 .iter()
2346 .next()
2347 .and_then(|excerpt| excerpt.buffer.language())
2348 }
2349
2350 pub fn is_dirty(&self) -> bool {
2351 self.is_dirty
2352 }
2353
2354 pub fn has_conflict(&self) -> bool {
2355 self.has_conflict
2356 }
2357
2358 pub fn diagnostic_group<'a, O>(
2359 &'a self,
2360 group_id: usize,
2361 ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
2362 where
2363 O: text::FromAnchor + 'a,
2364 {
2365 self.as_singleton()
2366 .into_iter()
2367 .flat_map(move |(_, _, buffer)| buffer.diagnostic_group(group_id))
2368 }
2369
2370 pub fn diagnostics_in_range<'a, T, O>(
2371 &'a self,
2372 range: Range<T>,
2373 reversed: bool,
2374 ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
2375 where
2376 T: 'a + ToOffset,
2377 O: 'a + text::FromAnchor,
2378 {
2379 self.as_singleton()
2380 .into_iter()
2381 .flat_map(move |(_, _, buffer)| {
2382 buffer.diagnostics_in_range(
2383 range.start.to_offset(self)..range.end.to_offset(self),
2384 reversed,
2385 )
2386 })
2387 }
2388
2389 pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
2390 let range = range.start.to_offset(self)..range.end.to_offset(self);
2391
2392 let mut cursor = self.excerpts.cursor::<usize>();
2393 cursor.seek(&range.start, Bias::Right, &());
2394 let start_excerpt = cursor.item();
2395
2396 cursor.seek(&range.end, Bias::Right, &());
2397 let end_excerpt = cursor.item();
2398
2399 start_excerpt
2400 .zip(end_excerpt)
2401 .and_then(|(start_excerpt, end_excerpt)| {
2402 if start_excerpt.id != end_excerpt.id {
2403 return None;
2404 }
2405
2406 let excerpt_buffer_start = start_excerpt
2407 .range
2408 .context
2409 .start
2410 .to_offset(&start_excerpt.buffer);
2411 let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
2412
2413 let start_in_buffer =
2414 excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
2415 let end_in_buffer =
2416 excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
2417 let mut ancestor_buffer_range = start_excerpt
2418 .buffer
2419 .range_for_syntax_ancestor(start_in_buffer..end_in_buffer)?;
2420 ancestor_buffer_range.start =
2421 cmp::max(ancestor_buffer_range.start, excerpt_buffer_start);
2422 ancestor_buffer_range.end = cmp::min(ancestor_buffer_range.end, excerpt_buffer_end);
2423
2424 let start = cursor.start() + (ancestor_buffer_range.start - excerpt_buffer_start);
2425 let end = cursor.start() + (ancestor_buffer_range.end - excerpt_buffer_start);
2426 Some(start..end)
2427 })
2428 }
2429
2430 pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
2431 let (excerpt_id, _, buffer) = self.as_singleton()?;
2432 let outline = buffer.outline(theme)?;
2433 Some(Outline::new(
2434 outline
2435 .items
2436 .into_iter()
2437 .map(|item| OutlineItem {
2438 depth: item.depth,
2439 range: self.anchor_in_excerpt(excerpt_id.clone(), item.range.start)
2440 ..self.anchor_in_excerpt(excerpt_id.clone(), item.range.end),
2441 text: item.text,
2442 highlight_ranges: item.highlight_ranges,
2443 name_ranges: item.name_ranges,
2444 })
2445 .collect(),
2446 ))
2447 }
2448
2449 pub fn symbols_containing<T: ToOffset>(
2450 &self,
2451 offset: T,
2452 theme: Option<&SyntaxTheme>,
2453 ) -> Option<(usize, Vec<OutlineItem<Anchor>>)> {
2454 let anchor = self.anchor_before(offset);
2455 let excerpt_id = anchor.excerpt_id();
2456 let excerpt = self.excerpt(excerpt_id)?;
2457 Some((
2458 excerpt.buffer_id,
2459 excerpt
2460 .buffer
2461 .symbols_containing(anchor.text_anchor, theme)
2462 .into_iter()
2463 .flatten()
2464 .map(|item| OutlineItem {
2465 depth: item.depth,
2466 range: self.anchor_in_excerpt(excerpt_id.clone(), item.range.start)
2467 ..self.anchor_in_excerpt(excerpt_id.clone(), item.range.end),
2468 text: item.text,
2469 highlight_ranges: item.highlight_ranges,
2470 name_ranges: item.name_ranges,
2471 })
2472 .collect(),
2473 ))
2474 }
2475
2476 fn excerpt<'a>(&'a self, excerpt_id: &'a ExcerptId) -> Option<&'a Excerpt> {
2477 let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
2478 cursor.seek(&Some(excerpt_id), Bias::Left, &());
2479 if let Some(excerpt) = cursor.item() {
2480 if excerpt.id == *excerpt_id {
2481 return Some(excerpt);
2482 }
2483 }
2484 None
2485 }
2486
2487 pub fn remote_selections_in_range<'a>(
2488 &'a self,
2489 range: &'a Range<Anchor>,
2490 ) -> impl 'a + Iterator<Item = (ReplicaId, bool, Selection<Anchor>)> {
2491 let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
2492 cursor.seek(&Some(&range.start.excerpt_id), Bias::Left, &());
2493 cursor
2494 .take_while(move |excerpt| excerpt.id <= range.end.excerpt_id)
2495 .flat_map(move |excerpt| {
2496 let mut query_range =
2497 excerpt.range.context.start.clone()..excerpt.range.context.end.clone();
2498 if excerpt.id == range.start.excerpt_id {
2499 query_range.start = range.start.text_anchor.clone();
2500 }
2501 if excerpt.id == range.end.excerpt_id {
2502 query_range.end = range.end.text_anchor.clone();
2503 }
2504
2505 excerpt
2506 .buffer
2507 .remote_selections_in_range(query_range)
2508 .flat_map(move |(replica_id, line_mode, selections)| {
2509 selections.map(move |selection| {
2510 let mut start = Anchor {
2511 buffer_id: Some(excerpt.buffer_id),
2512 excerpt_id: excerpt.id.clone(),
2513 text_anchor: selection.start.clone(),
2514 };
2515 let mut end = Anchor {
2516 buffer_id: Some(excerpt.buffer_id),
2517 excerpt_id: excerpt.id.clone(),
2518 text_anchor: selection.end.clone(),
2519 };
2520 if range.start.cmp(&start, self).is_gt() {
2521 start = range.start.clone();
2522 }
2523 if range.end.cmp(&end, self).is_lt() {
2524 end = range.end.clone();
2525 }
2526
2527 (
2528 replica_id,
2529 line_mode,
2530 Selection {
2531 id: selection.id,
2532 start,
2533 end,
2534 reversed: selection.reversed,
2535 goal: selection.goal,
2536 },
2537 )
2538 })
2539 })
2540 })
2541 }
2542}
2543
2544#[cfg(any(test, feature = "test-support"))]
2545impl MultiBufferSnapshot {
2546 pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
2547 let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
2548 let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
2549 start..end
2550 }
2551}
2552
2553impl History {
2554 fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
2555 self.transaction_depth += 1;
2556 if self.transaction_depth == 1 {
2557 let id = self.next_transaction_id.tick();
2558 self.undo_stack.push(Transaction {
2559 id,
2560 buffer_transactions: Default::default(),
2561 first_edit_at: now,
2562 last_edit_at: now,
2563 suppress_grouping: false,
2564 });
2565 Some(id)
2566 } else {
2567 None
2568 }
2569 }
2570
2571 fn end_transaction(
2572 &mut self,
2573 now: Instant,
2574 buffer_transactions: HashMap<usize, TransactionId>,
2575 ) -> bool {
2576 assert_ne!(self.transaction_depth, 0);
2577 self.transaction_depth -= 1;
2578 if self.transaction_depth == 0 {
2579 if buffer_transactions.is_empty() {
2580 self.undo_stack.pop();
2581 false
2582 } else {
2583 self.redo_stack.clear();
2584 let transaction = self.undo_stack.last_mut().unwrap();
2585 transaction.last_edit_at = now;
2586 for (buffer_id, transaction_id) in buffer_transactions {
2587 transaction
2588 .buffer_transactions
2589 .entry(buffer_id)
2590 .or_insert(transaction_id);
2591 }
2592 true
2593 }
2594 } else {
2595 false
2596 }
2597 }
2598
2599 fn push_transaction<'a, T>(&mut self, buffer_transactions: T, now: Instant)
2600 where
2601 T: IntoIterator<Item = (&'a ModelHandle<Buffer>, &'a language::Transaction)>,
2602 {
2603 assert_eq!(self.transaction_depth, 0);
2604 let transaction = Transaction {
2605 id: self.next_transaction_id.tick(),
2606 buffer_transactions: buffer_transactions
2607 .into_iter()
2608 .map(|(buffer, transaction)| (buffer.id(), transaction.id))
2609 .collect(),
2610 first_edit_at: now,
2611 last_edit_at: now,
2612 suppress_grouping: false,
2613 };
2614 if !transaction.buffer_transactions.is_empty() {
2615 self.undo_stack.push(transaction);
2616 self.redo_stack.clear();
2617 }
2618 }
2619
2620 fn finalize_last_transaction(&mut self) {
2621 if let Some(transaction) = self.undo_stack.last_mut() {
2622 transaction.suppress_grouping = true;
2623 }
2624 }
2625
2626 fn pop_undo(&mut self) -> Option<&mut Transaction> {
2627 assert_eq!(self.transaction_depth, 0);
2628 if let Some(transaction) = self.undo_stack.pop() {
2629 self.redo_stack.push(transaction);
2630 self.redo_stack.last_mut()
2631 } else {
2632 None
2633 }
2634 }
2635
2636 fn pop_redo(&mut self) -> Option<&mut Transaction> {
2637 assert_eq!(self.transaction_depth, 0);
2638 if let Some(transaction) = self.redo_stack.pop() {
2639 self.undo_stack.push(transaction);
2640 self.undo_stack.last_mut()
2641 } else {
2642 None
2643 }
2644 }
2645
2646 fn group(&mut self) -> Option<TransactionId> {
2647 let mut new_len = self.undo_stack.len();
2648 let mut transactions = self.undo_stack.iter_mut();
2649
2650 if let Some(mut transaction) = transactions.next_back() {
2651 while let Some(prev_transaction) = transactions.next_back() {
2652 if !prev_transaction.suppress_grouping
2653 && transaction.first_edit_at - prev_transaction.last_edit_at
2654 <= self.group_interval
2655 {
2656 transaction = prev_transaction;
2657 new_len -= 1;
2658 } else {
2659 break;
2660 }
2661 }
2662 }
2663
2664 let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
2665 if let Some(last_transaction) = transactions_to_keep.last_mut() {
2666 if let Some(transaction) = transactions_to_merge.last() {
2667 last_transaction.last_edit_at = transaction.last_edit_at;
2668 }
2669 for to_merge in transactions_to_merge {
2670 for (buffer_id, transaction_id) in &to_merge.buffer_transactions {
2671 last_transaction
2672 .buffer_transactions
2673 .entry(*buffer_id)
2674 .or_insert(*transaction_id);
2675 }
2676 }
2677 }
2678
2679 self.undo_stack.truncate(new_len);
2680 self.undo_stack.last().map(|t| t.id)
2681 }
2682}
2683
2684impl Excerpt {
2685 fn new(
2686 id: ExcerptId,
2687 key: usize,
2688 buffer_id: usize,
2689 buffer: BufferSnapshot,
2690 range: ExcerptRange<text::Anchor>,
2691 has_trailing_newline: bool,
2692 ) -> Self {
2693 Excerpt {
2694 id,
2695 key,
2696 max_buffer_row: range.context.end.to_point(&buffer).row,
2697 text_summary: buffer
2698 .text_summary_for_range::<TextSummary, _>(range.context.to_offset(&buffer)),
2699 buffer_id,
2700 buffer,
2701 range,
2702 has_trailing_newline,
2703 }
2704 }
2705
2706 fn chunks_in_range<'a>(
2707 &'a self,
2708 range: Range<usize>,
2709 language_aware: bool,
2710 ) -> ExcerptChunks<'a> {
2711 let content_start = self.range.context.start.to_offset(&self.buffer);
2712 let chunks_start = content_start + range.start;
2713 let chunks_end = content_start + cmp::min(range.end, self.text_summary.bytes);
2714
2715 let footer_height = if self.has_trailing_newline
2716 && range.start <= self.text_summary.bytes
2717 && range.end > self.text_summary.bytes
2718 {
2719 1
2720 } else {
2721 0
2722 };
2723
2724 let content_chunks = self.buffer.chunks(chunks_start..chunks_end, language_aware);
2725
2726 ExcerptChunks {
2727 content_chunks,
2728 footer_height,
2729 }
2730 }
2731
2732 fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
2733 let content_start = self.range.context.start.to_offset(&self.buffer);
2734 let bytes_start = content_start + range.start;
2735 let bytes_end = content_start + cmp::min(range.end, self.text_summary.bytes);
2736 let footer_height = if self.has_trailing_newline
2737 && range.start <= self.text_summary.bytes
2738 && range.end > self.text_summary.bytes
2739 {
2740 1
2741 } else {
2742 0
2743 };
2744 let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
2745
2746 ExcerptBytes {
2747 content_bytes,
2748 footer_height,
2749 }
2750 }
2751
2752 fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
2753 if text_anchor
2754 .cmp(&self.range.context.start, &self.buffer)
2755 .is_lt()
2756 {
2757 self.range.context.start.clone()
2758 } else if text_anchor
2759 .cmp(&self.range.context.end, &self.buffer)
2760 .is_gt()
2761 {
2762 self.range.context.end.clone()
2763 } else {
2764 text_anchor
2765 }
2766 }
2767
2768 fn contains(&self, anchor: &Anchor) -> bool {
2769 Some(self.buffer_id) == anchor.buffer_id
2770 && self
2771 .range
2772 .context
2773 .start
2774 .cmp(&anchor.text_anchor, &self.buffer)
2775 .is_le()
2776 && self
2777 .range
2778 .context
2779 .end
2780 .cmp(&anchor.text_anchor, &self.buffer)
2781 .is_ge()
2782 }
2783}
2784
2785impl fmt::Debug for Excerpt {
2786 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2787 f.debug_struct("Excerpt")
2788 .field("id", &self.id)
2789 .field("buffer_id", &self.buffer_id)
2790 .field("range", &self.range)
2791 .field("text_summary", &self.text_summary)
2792 .field("has_trailing_newline", &self.has_trailing_newline)
2793 .finish()
2794 }
2795}
2796
2797impl sum_tree::Item for Excerpt {
2798 type Summary = ExcerptSummary;
2799
2800 fn summary(&self) -> Self::Summary {
2801 let mut text = self.text_summary.clone();
2802 if self.has_trailing_newline {
2803 text += TextSummary::from("\n");
2804 }
2805 ExcerptSummary {
2806 excerpt_id: self.id.clone(),
2807 max_buffer_row: self.max_buffer_row,
2808 text,
2809 }
2810 }
2811}
2812
2813impl sum_tree::Summary for ExcerptSummary {
2814 type Context = ();
2815
2816 fn add_summary(&mut self, summary: &Self, _: &()) {
2817 debug_assert!(summary.excerpt_id > self.excerpt_id);
2818 self.excerpt_id = summary.excerpt_id.clone();
2819 self.text.add_summary(&summary.text, &());
2820 self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row);
2821 }
2822}
2823
2824impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
2825 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2826 *self += &summary.text;
2827 }
2828}
2829
2830impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
2831 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2832 *self += summary.text.bytes;
2833 }
2834}
2835
2836impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
2837 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
2838 Ord::cmp(self, &cursor_location.text.bytes)
2839 }
2840}
2841
2842impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Option<&'a ExcerptId> {
2843 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
2844 Ord::cmp(self, &Some(&cursor_location.excerpt_id))
2845 }
2846}
2847
2848impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
2849 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2850 *self += summary.text.lines;
2851 }
2852}
2853
2854impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
2855 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2856 *self += summary.text.lines_utf16
2857 }
2858}
2859
2860impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a ExcerptId> {
2861 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2862 *self = Some(&summary.excerpt_id);
2863 }
2864}
2865
2866impl<'a> MultiBufferRows<'a> {
2867 pub fn seek(&mut self, row: u32) {
2868 self.buffer_row_range = 0..0;
2869
2870 self.excerpts
2871 .seek_forward(&Point::new(row, 0), Bias::Right, &());
2872 if self.excerpts.item().is_none() {
2873 self.excerpts.prev(&());
2874
2875 if self.excerpts.item().is_none() && row == 0 {
2876 self.buffer_row_range = 0..1;
2877 return;
2878 }
2879 }
2880
2881 if let Some(excerpt) = self.excerpts.item() {
2882 let overshoot = row - self.excerpts.start().row;
2883 let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
2884 self.buffer_row_range.start = excerpt_start + overshoot;
2885 self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
2886 }
2887 }
2888}
2889
2890impl<'a> Iterator for MultiBufferRows<'a> {
2891 type Item = Option<u32>;
2892
2893 fn next(&mut self) -> Option<Self::Item> {
2894 loop {
2895 if !self.buffer_row_range.is_empty() {
2896 let row = Some(self.buffer_row_range.start);
2897 self.buffer_row_range.start += 1;
2898 return Some(row);
2899 }
2900 self.excerpts.item()?;
2901 self.excerpts.next(&());
2902 let excerpt = self.excerpts.item()?;
2903 self.buffer_row_range.start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
2904 self.buffer_row_range.end =
2905 self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
2906 }
2907 }
2908}
2909
2910impl<'a> MultiBufferChunks<'a> {
2911 pub fn offset(&self) -> usize {
2912 self.range.start
2913 }
2914
2915 pub fn seek(&mut self, offset: usize) {
2916 self.range.start = offset;
2917 self.excerpts.seek(&offset, Bias::Right, &());
2918 if let Some(excerpt) = self.excerpts.item() {
2919 self.excerpt_chunks = Some(excerpt.chunks_in_range(
2920 self.range.start - self.excerpts.start()..self.range.end - self.excerpts.start(),
2921 self.language_aware,
2922 ));
2923 } else {
2924 self.excerpt_chunks = None;
2925 }
2926 }
2927}
2928
2929impl<'a> Iterator for MultiBufferChunks<'a> {
2930 type Item = Chunk<'a>;
2931
2932 fn next(&mut self) -> Option<Self::Item> {
2933 if self.range.is_empty() {
2934 None
2935 } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
2936 self.range.start += chunk.text.len();
2937 Some(chunk)
2938 } else {
2939 self.excerpts.next(&());
2940 let excerpt = self.excerpts.item()?;
2941 self.excerpt_chunks = Some(excerpt.chunks_in_range(
2942 0..self.range.end - self.excerpts.start(),
2943 self.language_aware,
2944 ));
2945 self.next()
2946 }
2947 }
2948}
2949
2950impl<'a> MultiBufferBytes<'a> {
2951 fn consume(&mut self, len: usize) {
2952 self.range.start += len;
2953 self.chunk = &self.chunk[len..];
2954
2955 if !self.range.is_empty() && self.chunk.is_empty() {
2956 if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
2957 self.chunk = chunk;
2958 } else {
2959 self.excerpts.next(&());
2960 if let Some(excerpt) = self.excerpts.item() {
2961 let mut excerpt_bytes =
2962 excerpt.bytes_in_range(0..self.range.end - self.excerpts.start());
2963 self.chunk = excerpt_bytes.next().unwrap();
2964 self.excerpt_bytes = Some(excerpt_bytes);
2965 }
2966 }
2967 }
2968 }
2969}
2970
2971impl<'a> Iterator for MultiBufferBytes<'a> {
2972 type Item = &'a [u8];
2973
2974 fn next(&mut self) -> Option<Self::Item> {
2975 let chunk = self.chunk;
2976 if chunk.is_empty() {
2977 None
2978 } else {
2979 self.consume(chunk.len());
2980 Some(chunk)
2981 }
2982 }
2983}
2984
2985impl<'a> io::Read for MultiBufferBytes<'a> {
2986 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2987 let len = cmp::min(buf.len(), self.chunk.len());
2988 buf[..len].copy_from_slice(&self.chunk[..len]);
2989 if len > 0 {
2990 self.consume(len);
2991 }
2992 Ok(len)
2993 }
2994}
2995
2996impl<'a> Iterator for ExcerptBytes<'a> {
2997 type Item = &'a [u8];
2998
2999 fn next(&mut self) -> Option<Self::Item> {
3000 if let Some(chunk) = self.content_bytes.next() {
3001 if !chunk.is_empty() {
3002 return Some(chunk);
3003 }
3004 }
3005
3006 if self.footer_height > 0 {
3007 let result = &NEWLINES[..self.footer_height];
3008 self.footer_height = 0;
3009 return Some(result);
3010 }
3011
3012 None
3013 }
3014}
3015
3016impl<'a> Iterator for ExcerptChunks<'a> {
3017 type Item = Chunk<'a>;
3018
3019 fn next(&mut self) -> Option<Self::Item> {
3020 if let Some(chunk) = self.content_chunks.next() {
3021 return Some(chunk);
3022 }
3023
3024 if self.footer_height > 0 {
3025 let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
3026 self.footer_height = 0;
3027 return Some(Chunk {
3028 text,
3029 ..Default::default()
3030 });
3031 }
3032
3033 None
3034 }
3035}
3036
3037impl ToOffset for Point {
3038 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3039 snapshot.point_to_offset(*self)
3040 }
3041}
3042
3043impl ToOffset for PointUtf16 {
3044 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3045 snapshot.point_utf16_to_offset(*self)
3046 }
3047}
3048
3049impl ToOffset for usize {
3050 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3051 assert!(*self <= snapshot.len(), "offset is out of range");
3052 *self
3053 }
3054}
3055
3056impl ToPoint for usize {
3057 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
3058 snapshot.offset_to_point(*self)
3059 }
3060}
3061
3062impl ToPoint for Point {
3063 fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
3064 *self
3065 }
3066}
3067
3068impl ToPointUtf16 for usize {
3069 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
3070 snapshot.offset_to_point_utf16(*self)
3071 }
3072}
3073
3074impl ToPointUtf16 for Point {
3075 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
3076 snapshot.point_to_point_utf16(*self)
3077 }
3078}
3079
3080impl ToPointUtf16 for PointUtf16 {
3081 fn to_point_utf16<'a>(&self, _: &MultiBufferSnapshot) -> PointUtf16 {
3082 *self
3083 }
3084}
3085
3086#[cfg(test)]
3087mod tests {
3088 use super::*;
3089 use gpui::MutableAppContext;
3090 use language::{Buffer, Rope};
3091 use rand::prelude::*;
3092 use std::{env, rc::Rc};
3093 use text::{Point, RandomCharIter};
3094 use util::test::sample_text;
3095
3096 #[gpui::test]
3097 fn test_singleton_multibuffer(cx: &mut MutableAppContext) {
3098 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
3099 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
3100
3101 let snapshot = multibuffer.read(cx).snapshot(cx);
3102 assert_eq!(snapshot.text(), buffer.read(cx).text());
3103
3104 assert_eq!(
3105 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3106 (0..buffer.read(cx).row_count())
3107 .map(Some)
3108 .collect::<Vec<_>>()
3109 );
3110
3111 buffer.update(cx, |buffer, cx| buffer.edit([(1..3, "XXX\n")], cx));
3112 let snapshot = multibuffer.read(cx).snapshot(cx);
3113
3114 assert_eq!(snapshot.text(), buffer.read(cx).text());
3115 assert_eq!(
3116 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3117 (0..buffer.read(cx).row_count())
3118 .map(Some)
3119 .collect::<Vec<_>>()
3120 );
3121 }
3122
3123 #[gpui::test]
3124 fn test_remote_multibuffer(cx: &mut MutableAppContext) {
3125 let host_buffer = cx.add_model(|cx| Buffer::new(0, "a", cx));
3126 let guest_buffer = cx.add_model(|cx| {
3127 let message = host_buffer.read(cx).to_proto();
3128 Buffer::from_proto(1, message, None, cx).unwrap()
3129 });
3130 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(guest_buffer.clone(), cx));
3131 let snapshot = multibuffer.read(cx).snapshot(cx);
3132 assert_eq!(snapshot.text(), "a");
3133
3134 guest_buffer.update(cx, |buffer, cx| buffer.edit([(1..1, "b")], cx));
3135 let snapshot = multibuffer.read(cx).snapshot(cx);
3136 assert_eq!(snapshot.text(), "ab");
3137
3138 guest_buffer.update(cx, |buffer, cx| buffer.edit([(2..2, "c")], cx));
3139 let snapshot = multibuffer.read(cx).snapshot(cx);
3140 assert_eq!(snapshot.text(), "abc");
3141 }
3142
3143 #[gpui::test]
3144 fn test_excerpt_buffer(cx: &mut MutableAppContext) {
3145 let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
3146 let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
3147 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3148
3149 let events = Rc::new(RefCell::new(Vec::<Event>::new()));
3150 multibuffer.update(cx, |_, cx| {
3151 let events = events.clone();
3152 cx.subscribe(&multibuffer, move |_, _, event, _| {
3153 events.borrow_mut().push(event.clone())
3154 })
3155 .detach();
3156 });
3157
3158 let subscription = multibuffer.update(cx, |multibuffer, cx| {
3159 let subscription = multibuffer.subscribe();
3160 multibuffer.push_excerpts(
3161 buffer_1.clone(),
3162 [ExcerptRange {
3163 context: Point::new(1, 2)..Point::new(2, 5),
3164 primary: None,
3165 }],
3166 cx,
3167 );
3168 assert_eq!(
3169 subscription.consume().into_inner(),
3170 [Edit {
3171 old: 0..0,
3172 new: 0..10
3173 }]
3174 );
3175
3176 multibuffer.push_excerpts(
3177 buffer_1.clone(),
3178 [ExcerptRange {
3179 context: Point::new(3, 3)..Point::new(4, 4),
3180 primary: None,
3181 }],
3182 cx,
3183 );
3184 multibuffer.push_excerpts(
3185 buffer_2.clone(),
3186 [ExcerptRange {
3187 context: Point::new(3, 1)..Point::new(3, 3),
3188 primary: None,
3189 }],
3190 cx,
3191 );
3192 assert_eq!(
3193 subscription.consume().into_inner(),
3194 [Edit {
3195 old: 10..10,
3196 new: 10..22
3197 }]
3198 );
3199
3200 subscription
3201 });
3202
3203 // Adding excerpts emits an edited event.
3204 assert_eq!(
3205 events.borrow().as_slice(),
3206 &[Event::Edited, Event::Edited, Event::Edited]
3207 );
3208
3209 let snapshot = multibuffer.read(cx).snapshot(cx);
3210 assert_eq!(
3211 snapshot.text(),
3212 concat!(
3213 "bbbb\n", // Preserve newlines
3214 "ccccc\n", //
3215 "ddd\n", //
3216 "eeee\n", //
3217 "jj" //
3218 )
3219 );
3220 assert_eq!(
3221 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3222 [Some(1), Some(2), Some(3), Some(4), Some(3)]
3223 );
3224 assert_eq!(
3225 snapshot.buffer_rows(2).collect::<Vec<_>>(),
3226 [Some(3), Some(4), Some(3)]
3227 );
3228 assert_eq!(snapshot.buffer_rows(4).collect::<Vec<_>>(), [Some(3)]);
3229 assert_eq!(snapshot.buffer_rows(5).collect::<Vec<_>>(), []);
3230
3231 assert_eq!(
3232 boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot),
3233 &[
3234 (0, "bbbb\nccccc".to_string(), true),
3235 (2, "ddd\neeee".to_string(), false),
3236 (4, "jj".to_string(), true),
3237 ]
3238 );
3239 assert_eq!(
3240 boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot),
3241 &[(0, "bbbb\nccccc".to_string(), true)]
3242 );
3243 assert_eq!(
3244 boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot),
3245 &[]
3246 );
3247 assert_eq!(
3248 boundaries_in_range(Point::new(1, 0)..Point::new(2, 0), &snapshot),
3249 &[]
3250 );
3251 assert_eq!(
3252 boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
3253 &[(2, "ddd\neeee".to_string(), false)]
3254 );
3255 assert_eq!(
3256 boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
3257 &[(2, "ddd\neeee".to_string(), false)]
3258 );
3259 assert_eq!(
3260 boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot),
3261 &[(2, "ddd\neeee".to_string(), false)]
3262 );
3263 assert_eq!(
3264 boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot),
3265 &[(4, "jj".to_string(), true)]
3266 );
3267 assert_eq!(
3268 boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot),
3269 &[]
3270 );
3271
3272 buffer_1.update(cx, |buffer, cx| {
3273 let text = "\n";
3274 buffer.edit(
3275 [
3276 (Point::new(0, 0)..Point::new(0, 0), text),
3277 (Point::new(2, 1)..Point::new(2, 3), text),
3278 ],
3279 cx,
3280 );
3281 });
3282
3283 let snapshot = multibuffer.read(cx).snapshot(cx);
3284 assert_eq!(
3285 snapshot.text(),
3286 concat!(
3287 "bbbb\n", // Preserve newlines
3288 "c\n", //
3289 "cc\n", //
3290 "ddd\n", //
3291 "eeee\n", //
3292 "jj" //
3293 )
3294 );
3295
3296 assert_eq!(
3297 subscription.consume().into_inner(),
3298 [Edit {
3299 old: 6..8,
3300 new: 6..7
3301 }]
3302 );
3303
3304 let snapshot = multibuffer.read(cx).snapshot(cx);
3305 assert_eq!(
3306 snapshot.clip_point(Point::new(0, 5), Bias::Left),
3307 Point::new(0, 4)
3308 );
3309 assert_eq!(
3310 snapshot.clip_point(Point::new(0, 5), Bias::Right),
3311 Point::new(0, 4)
3312 );
3313 assert_eq!(
3314 snapshot.clip_point(Point::new(5, 1), Bias::Right),
3315 Point::new(5, 1)
3316 );
3317 assert_eq!(
3318 snapshot.clip_point(Point::new(5, 2), Bias::Right),
3319 Point::new(5, 2)
3320 );
3321 assert_eq!(
3322 snapshot.clip_point(Point::new(5, 3), Bias::Right),
3323 Point::new(5, 2)
3324 );
3325
3326 let snapshot = multibuffer.update(cx, |multibuffer, cx| {
3327 let (buffer_2_excerpt_id, _) =
3328 multibuffer.excerpts_for_buffer(&buffer_2, cx)[0].clone();
3329 multibuffer.remove_excerpts(&[buffer_2_excerpt_id], cx);
3330 multibuffer.snapshot(cx)
3331 });
3332
3333 assert_eq!(
3334 snapshot.text(),
3335 concat!(
3336 "bbbb\n", // Preserve newlines
3337 "c\n", //
3338 "cc\n", //
3339 "ddd\n", //
3340 "eeee", //
3341 )
3342 );
3343
3344 fn boundaries_in_range(
3345 range: Range<Point>,
3346 snapshot: &MultiBufferSnapshot,
3347 ) -> Vec<(u32, String, bool)> {
3348 snapshot
3349 .excerpt_boundaries_in_range(range)
3350 .map(|boundary| {
3351 (
3352 boundary.row,
3353 boundary
3354 .buffer
3355 .text_for_range(boundary.range.context)
3356 .collect::<String>(),
3357 boundary.starts_new_buffer,
3358 )
3359 })
3360 .collect::<Vec<_>>()
3361 }
3362 }
3363
3364 #[gpui::test]
3365 fn test_excerpts_with_context_lines(cx: &mut MutableAppContext) {
3366 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(20, 3, 'a'), cx));
3367 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3368 let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
3369 multibuffer.push_excerpts_with_context_lines(
3370 buffer.clone(),
3371 vec![
3372 Point::new(3, 2)..Point::new(4, 2),
3373 Point::new(7, 1)..Point::new(7, 3),
3374 Point::new(15, 0)..Point::new(15, 0),
3375 ],
3376 2,
3377 cx,
3378 )
3379 });
3380
3381 let snapshot = multibuffer.read(cx).snapshot(cx);
3382 assert_eq!(
3383 snapshot.text(),
3384 "bbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\n\nnnn\nooo\nppp\nqqq\nrrr\n"
3385 );
3386
3387 assert_eq!(
3388 anchor_ranges
3389 .iter()
3390 .map(|range| range.to_point(&snapshot))
3391 .collect::<Vec<_>>(),
3392 vec![
3393 Point::new(2, 2)..Point::new(3, 2),
3394 Point::new(6, 1)..Point::new(6, 3),
3395 Point::new(12, 0)..Point::new(12, 0)
3396 ]
3397 );
3398 }
3399
3400 #[gpui::test]
3401 fn test_empty_excerpt_buffer(cx: &mut MutableAppContext) {
3402 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3403
3404 let snapshot = multibuffer.read(cx).snapshot(cx);
3405 assert_eq!(snapshot.text(), "");
3406 assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), &[Some(0)]);
3407 assert_eq!(snapshot.buffer_rows(1).collect::<Vec<_>>(), &[]);
3408 }
3409
3410 #[gpui::test]
3411 fn test_singleton_multibuffer_anchors(cx: &mut MutableAppContext) {
3412 let buffer = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
3413 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
3414 let old_snapshot = multibuffer.read(cx).snapshot(cx);
3415 buffer.update(cx, |buffer, cx| {
3416 buffer.edit([(0..0, "X")], cx);
3417 buffer.edit([(5..5, "Y")], cx);
3418 });
3419 let new_snapshot = multibuffer.read(cx).snapshot(cx);
3420
3421 assert_eq!(old_snapshot.text(), "abcd");
3422 assert_eq!(new_snapshot.text(), "XabcdY");
3423
3424 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
3425 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
3426 assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
3427 assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
3428 }
3429
3430 #[gpui::test]
3431 fn test_multibuffer_anchors(cx: &mut MutableAppContext) {
3432 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
3433 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
3434 let multibuffer = cx.add_model(|cx| {
3435 let mut multibuffer = MultiBuffer::new(0);
3436 multibuffer.push_excerpts(
3437 buffer_1.clone(),
3438 [ExcerptRange {
3439 context: 0..4,
3440 primary: None,
3441 }],
3442 cx,
3443 );
3444 multibuffer.push_excerpts(
3445 buffer_2.clone(),
3446 [ExcerptRange {
3447 context: 0..5,
3448 primary: None,
3449 }],
3450 cx,
3451 );
3452 multibuffer
3453 });
3454 let old_snapshot = multibuffer.read(cx).snapshot(cx);
3455
3456 assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
3457 assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
3458 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
3459 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
3460 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
3461 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
3462
3463 buffer_1.update(cx, |buffer, cx| {
3464 buffer.edit([(0..0, "W")], cx);
3465 buffer.edit([(5..5, "X")], cx);
3466 });
3467 buffer_2.update(cx, |buffer, cx| {
3468 buffer.edit([(0..0, "Y")], cx);
3469 buffer.edit([(6..6, "Z")], cx);
3470 });
3471 let new_snapshot = multibuffer.read(cx).snapshot(cx);
3472
3473 assert_eq!(old_snapshot.text(), "abcd\nefghi");
3474 assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
3475
3476 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
3477 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
3478 assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
3479 assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
3480 assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
3481 assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
3482 assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
3483 assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
3484 assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
3485 assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
3486 }
3487
3488 #[gpui::test]
3489 fn test_multibuffer_resolving_anchors_after_replacing_their_excerpts(
3490 cx: &mut MutableAppContext,
3491 ) {
3492 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
3493 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "ABCDEFGHIJKLMNOP", cx));
3494 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3495
3496 // Create an insertion id in buffer 1 that doesn't exist in buffer 2.
3497 // Add an excerpt from buffer 1 that spans this new insertion.
3498 buffer_1.update(cx, |buffer, cx| buffer.edit([(4..4, "123")], cx));
3499 let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| {
3500 multibuffer
3501 .push_excerpts(
3502 buffer_1.clone(),
3503 [ExcerptRange {
3504 context: 0..7,
3505 primary: None,
3506 }],
3507 cx,
3508 )
3509 .pop()
3510 .unwrap()
3511 });
3512
3513 let snapshot_1 = multibuffer.read(cx).snapshot(cx);
3514 assert_eq!(snapshot_1.text(), "abcd123");
3515
3516 // Replace the buffer 1 excerpt with new excerpts from buffer 2.
3517 let (excerpt_id_2, excerpt_id_3) = multibuffer.update(cx, |multibuffer, cx| {
3518 multibuffer.remove_excerpts([&excerpt_id_1], cx);
3519 let mut ids = multibuffer
3520 .push_excerpts(
3521 buffer_2.clone(),
3522 [
3523 ExcerptRange {
3524 context: 0..4,
3525 primary: None,
3526 },
3527 ExcerptRange {
3528 context: 6..10,
3529 primary: None,
3530 },
3531 ExcerptRange {
3532 context: 12..16,
3533 primary: None,
3534 },
3535 ],
3536 cx,
3537 )
3538 .into_iter();
3539 (ids.next().unwrap(), ids.next().unwrap())
3540 });
3541 let snapshot_2 = multibuffer.read(cx).snapshot(cx);
3542 assert_eq!(snapshot_2.text(), "ABCD\nGHIJ\nMNOP");
3543
3544 // The old excerpt id doesn't get reused.
3545 assert_ne!(excerpt_id_2, excerpt_id_1);
3546
3547 // Resolve some anchors from the previous snapshot in the new snapshot.
3548 // Although there is still an excerpt with the same id, it is for
3549 // a different buffer, so we don't attempt to resolve the old text
3550 // anchor in the new buffer.
3551 assert_eq!(
3552 snapshot_2.summary_for_anchor::<usize>(&snapshot_1.anchor_before(2)),
3553 0
3554 );
3555 assert_eq!(
3556 snapshot_2.summaries_for_anchors::<usize, _>(&[
3557 snapshot_1.anchor_before(2),
3558 snapshot_1.anchor_after(3)
3559 ]),
3560 vec![0, 0]
3561 );
3562 let refresh =
3563 snapshot_2.refresh_anchors(&[snapshot_1.anchor_before(2), snapshot_1.anchor_after(3)]);
3564 assert_eq!(
3565 refresh,
3566 &[
3567 (0, snapshot_2.anchor_before(0), false),
3568 (1, snapshot_2.anchor_after(0), false),
3569 ]
3570 );
3571
3572 // Replace the middle excerpt with a smaller excerpt in buffer 2,
3573 // that intersects the old excerpt.
3574 let excerpt_id_5 = multibuffer.update(cx, |multibuffer, cx| {
3575 multibuffer.remove_excerpts([&excerpt_id_3], cx);
3576 multibuffer
3577 .insert_excerpts_after(
3578 &excerpt_id_3,
3579 buffer_2.clone(),
3580 [ExcerptRange {
3581 context: 5..8,
3582 primary: None,
3583 }],
3584 cx,
3585 )
3586 .pop()
3587 .unwrap()
3588 });
3589
3590 let snapshot_3 = multibuffer.read(cx).snapshot(cx);
3591 assert_eq!(snapshot_3.text(), "ABCD\nFGH\nMNOP");
3592 assert_ne!(excerpt_id_5, excerpt_id_3);
3593
3594 // Resolve some anchors from the previous snapshot in the new snapshot.
3595 // The anchor in the middle excerpt snaps to the beginning of the
3596 // excerpt, since it is not
3597 let anchors = [
3598 snapshot_2.anchor_before(0),
3599 snapshot_2.anchor_after(2),
3600 snapshot_2.anchor_after(6),
3601 snapshot_2.anchor_after(14),
3602 ];
3603 assert_eq!(
3604 snapshot_3.summaries_for_anchors::<usize, _>(&anchors),
3605 &[0, 2, 5, 13]
3606 );
3607
3608 let new_anchors = snapshot_3.refresh_anchors(&anchors);
3609 assert_eq!(
3610 new_anchors.iter().map(|a| (a.0, a.2)).collect::<Vec<_>>(),
3611 &[(0, true), (1, true), (2, true), (3, true)]
3612 );
3613 assert_eq!(
3614 snapshot_3.summaries_for_anchors::<usize, _>(new_anchors.iter().map(|a| &a.1)),
3615 &[0, 2, 7, 13]
3616 );
3617 }
3618
3619 #[gpui::test(iterations = 100)]
3620 fn test_random_multibuffer(cx: &mut MutableAppContext, mut rng: StdRng) {
3621 let operations = env::var("OPERATIONS")
3622 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
3623 .unwrap_or(10);
3624
3625 let mut buffers: Vec<ModelHandle<Buffer>> = Vec::new();
3626 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3627 let mut excerpt_ids = Vec::new();
3628 let mut expected_excerpts = Vec::<(ModelHandle<Buffer>, Range<text::Anchor>)>::new();
3629 let mut anchors = Vec::new();
3630 let mut old_versions = Vec::new();
3631
3632 for _ in 0..operations {
3633 match rng.gen_range(0..100) {
3634 0..=19 if !buffers.is_empty() => {
3635 let buffer = buffers.choose(&mut rng).unwrap();
3636 buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
3637 }
3638 20..=29 if !expected_excerpts.is_empty() => {
3639 let mut ids_to_remove = vec![];
3640 for _ in 0..rng.gen_range(1..=3) {
3641 if expected_excerpts.is_empty() {
3642 break;
3643 }
3644
3645 let ix = rng.gen_range(0..expected_excerpts.len());
3646 ids_to_remove.push(excerpt_ids.remove(ix));
3647 let (buffer, range) = expected_excerpts.remove(ix);
3648 let buffer = buffer.read(cx);
3649 log::info!(
3650 "Removing excerpt {}: {:?}",
3651 ix,
3652 buffer
3653 .text_for_range(range.to_offset(&buffer))
3654 .collect::<String>(),
3655 );
3656 }
3657 ids_to_remove.sort_unstable();
3658 multibuffer.update(cx, |multibuffer, cx| {
3659 multibuffer.remove_excerpts(&ids_to_remove, cx)
3660 });
3661 }
3662 30..=39 if !expected_excerpts.is_empty() => {
3663 let multibuffer = multibuffer.read(cx).read(cx);
3664 let offset =
3665 multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left);
3666 let bias = if rng.gen() { Bias::Left } else { Bias::Right };
3667 log::info!("Creating anchor at {} with bias {:?}", offset, bias);
3668 anchors.push(multibuffer.anchor_at(offset, bias));
3669 anchors.sort_by(|a, b| a.cmp(&b, &multibuffer));
3670 }
3671 40..=44 if !anchors.is_empty() => {
3672 let multibuffer = multibuffer.read(cx).read(cx);
3673 let prev_len = anchors.len();
3674 anchors = multibuffer
3675 .refresh_anchors(&anchors)
3676 .into_iter()
3677 .map(|a| a.1)
3678 .collect();
3679
3680 // Ensure the newly-refreshed anchors point to a valid excerpt and don't
3681 // overshoot its boundaries.
3682 assert_eq!(anchors.len(), prev_len);
3683 let mut cursor = multibuffer.excerpts.cursor::<Option<&ExcerptId>>();
3684 for anchor in &anchors {
3685 if anchor.excerpt_id == ExcerptId::min()
3686 || anchor.excerpt_id == ExcerptId::max()
3687 {
3688 continue;
3689 }
3690
3691 cursor.seek_forward(&Some(&anchor.excerpt_id), Bias::Left, &());
3692 let excerpt = cursor.item().unwrap();
3693 assert_eq!(excerpt.id, anchor.excerpt_id);
3694 assert!(excerpt.contains(anchor));
3695 }
3696 }
3697 _ => {
3698 let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
3699 let base_text = RandomCharIter::new(&mut rng).take(10).collect::<String>();
3700 buffers.push(cx.add_model(|cx| Buffer::new(0, base_text, cx)));
3701 buffers.last().unwrap()
3702 } else {
3703 buffers.choose(&mut rng).unwrap()
3704 };
3705
3706 let buffer = buffer_handle.read(cx);
3707 let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
3708 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
3709 let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
3710 let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len());
3711 let prev_excerpt_id = excerpt_ids
3712 .get(prev_excerpt_ix)
3713 .cloned()
3714 .unwrap_or(ExcerptId::max());
3715 let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len());
3716
3717 log::info!(
3718 "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}",
3719 excerpt_ix,
3720 expected_excerpts.len(),
3721 buffer_handle.id(),
3722 buffer.text(),
3723 start_ix..end_ix,
3724 &buffer.text()[start_ix..end_ix]
3725 );
3726
3727 let excerpt_id = multibuffer.update(cx, |multibuffer, cx| {
3728 multibuffer
3729 .insert_excerpts_after(
3730 &prev_excerpt_id,
3731 buffer_handle.clone(),
3732 [ExcerptRange {
3733 context: start_ix..end_ix,
3734 primary: None,
3735 }],
3736 cx,
3737 )
3738 .pop()
3739 .unwrap()
3740 });
3741
3742 excerpt_ids.insert(excerpt_ix, excerpt_id);
3743 expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range));
3744 }
3745 }
3746
3747 if rng.gen_bool(0.3) {
3748 multibuffer.update(cx, |multibuffer, cx| {
3749 old_versions.push((multibuffer.snapshot(cx), multibuffer.subscribe()));
3750 })
3751 }
3752
3753 let snapshot = multibuffer.read(cx).snapshot(cx);
3754
3755 let mut excerpt_starts = Vec::new();
3756 let mut expected_text = String::new();
3757 let mut expected_buffer_rows = Vec::new();
3758 for (buffer, range) in &expected_excerpts {
3759 let buffer = buffer.read(cx);
3760 let buffer_range = range.to_offset(buffer);
3761
3762 excerpt_starts.push(TextSummary::from(expected_text.as_str()));
3763 expected_text.extend(buffer.text_for_range(buffer_range.clone()));
3764 expected_text.push('\n');
3765
3766 let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
3767 ..=buffer.offset_to_point(buffer_range.end).row;
3768 for row in buffer_row_range {
3769 expected_buffer_rows.push(Some(row));
3770 }
3771 }
3772 // Remove final trailing newline.
3773 if !expected_excerpts.is_empty() {
3774 expected_text.pop();
3775 }
3776
3777 // Always report one buffer row
3778 if expected_buffer_rows.is_empty() {
3779 expected_buffer_rows.push(Some(0));
3780 }
3781
3782 assert_eq!(snapshot.text(), expected_text);
3783 log::info!("MultiBuffer text: {:?}", expected_text);
3784
3785 assert_eq!(
3786 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3787 expected_buffer_rows,
3788 );
3789
3790 for _ in 0..5 {
3791 let start_row = rng.gen_range(0..=expected_buffer_rows.len());
3792 assert_eq!(
3793 snapshot.buffer_rows(start_row as u32).collect::<Vec<_>>(),
3794 &expected_buffer_rows[start_row..],
3795 "buffer_rows({})",
3796 start_row
3797 );
3798 }
3799
3800 assert_eq!(
3801 snapshot.max_buffer_row(),
3802 expected_buffer_rows
3803 .into_iter()
3804 .filter_map(|r| r)
3805 .max()
3806 .unwrap()
3807 );
3808
3809 let mut excerpt_starts = excerpt_starts.into_iter();
3810 for (buffer, range) in &expected_excerpts {
3811 let buffer_id = buffer.id();
3812 let buffer = buffer.read(cx);
3813 let buffer_range = range.to_offset(buffer);
3814 let buffer_start_point = buffer.offset_to_point(buffer_range.start);
3815 let buffer_start_point_utf16 =
3816 buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
3817
3818 let excerpt_start = excerpt_starts.next().unwrap();
3819 let mut offset = excerpt_start.bytes;
3820 let mut buffer_offset = buffer_range.start;
3821 let mut point = excerpt_start.lines;
3822 let mut buffer_point = buffer_start_point;
3823 let mut point_utf16 = excerpt_start.lines_utf16;
3824 let mut buffer_point_utf16 = buffer_start_point_utf16;
3825 for ch in buffer
3826 .snapshot()
3827 .chunks(buffer_range.clone(), false)
3828 .flat_map(|c| c.text.chars())
3829 {
3830 for _ in 0..ch.len_utf8() {
3831 let left_offset = snapshot.clip_offset(offset, Bias::Left);
3832 let right_offset = snapshot.clip_offset(offset, Bias::Right);
3833 let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
3834 let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
3835 assert_eq!(
3836 left_offset,
3837 excerpt_start.bytes + (buffer_left_offset - buffer_range.start),
3838 "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
3839 offset,
3840 buffer_id,
3841 buffer_offset,
3842 );
3843 assert_eq!(
3844 right_offset,
3845 excerpt_start.bytes + (buffer_right_offset - buffer_range.start),
3846 "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
3847 offset,
3848 buffer_id,
3849 buffer_offset,
3850 );
3851
3852 let left_point = snapshot.clip_point(point, Bias::Left);
3853 let right_point = snapshot.clip_point(point, Bias::Right);
3854 let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
3855 let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
3856 assert_eq!(
3857 left_point,
3858 excerpt_start.lines + (buffer_left_point - buffer_start_point),
3859 "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
3860 point,
3861 buffer_id,
3862 buffer_point,
3863 );
3864 assert_eq!(
3865 right_point,
3866 excerpt_start.lines + (buffer_right_point - buffer_start_point),
3867 "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
3868 point,
3869 buffer_id,
3870 buffer_point,
3871 );
3872
3873 assert_eq!(
3874 snapshot.point_to_offset(left_point),
3875 left_offset,
3876 "point_to_offset({:?})",
3877 left_point,
3878 );
3879 assert_eq!(
3880 snapshot.offset_to_point(left_offset),
3881 left_point,
3882 "offset_to_point({:?})",
3883 left_offset,
3884 );
3885
3886 offset += 1;
3887 buffer_offset += 1;
3888 if ch == '\n' {
3889 point += Point::new(1, 0);
3890 buffer_point += Point::new(1, 0);
3891 } else {
3892 point += Point::new(0, 1);
3893 buffer_point += Point::new(0, 1);
3894 }
3895 }
3896
3897 for _ in 0..ch.len_utf16() {
3898 let left_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Left);
3899 let right_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Right);
3900 let buffer_left_point_utf16 =
3901 buffer.clip_point_utf16(buffer_point_utf16, Bias::Left);
3902 let buffer_right_point_utf16 =
3903 buffer.clip_point_utf16(buffer_point_utf16, Bias::Right);
3904 assert_eq!(
3905 left_point_utf16,
3906 excerpt_start.lines_utf16
3907 + (buffer_left_point_utf16 - buffer_start_point_utf16),
3908 "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
3909 point_utf16,
3910 buffer_id,
3911 buffer_point_utf16,
3912 );
3913 assert_eq!(
3914 right_point_utf16,
3915 excerpt_start.lines_utf16
3916 + (buffer_right_point_utf16 - buffer_start_point_utf16),
3917 "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
3918 point_utf16,
3919 buffer_id,
3920 buffer_point_utf16,
3921 );
3922
3923 if ch == '\n' {
3924 point_utf16 += PointUtf16::new(1, 0);
3925 buffer_point_utf16 += PointUtf16::new(1, 0);
3926 } else {
3927 point_utf16 += PointUtf16::new(0, 1);
3928 buffer_point_utf16 += PointUtf16::new(0, 1);
3929 }
3930 }
3931 }
3932 }
3933
3934 for (row, line) in expected_text.split('\n').enumerate() {
3935 assert_eq!(
3936 snapshot.line_len(row as u32),
3937 line.len() as u32,
3938 "line_len({}).",
3939 row
3940 );
3941 }
3942
3943 let text_rope = Rope::from(expected_text.as_str());
3944 for _ in 0..10 {
3945 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
3946 let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
3947
3948 let text_for_range = snapshot
3949 .text_for_range(start_ix..end_ix)
3950 .collect::<String>();
3951 assert_eq!(
3952 text_for_range,
3953 &expected_text[start_ix..end_ix],
3954 "incorrect text for range {:?}",
3955 start_ix..end_ix
3956 );
3957
3958 let excerpted_buffer_ranges = multibuffer
3959 .read(cx)
3960 .range_to_buffer_ranges(start_ix..end_ix, cx);
3961 let excerpted_buffers_text = excerpted_buffer_ranges
3962 .into_iter()
3963 .map(|(buffer, buffer_range)| {
3964 buffer
3965 .read(cx)
3966 .text_for_range(buffer_range)
3967 .collect::<String>()
3968 })
3969 .collect::<Vec<_>>()
3970 .join("\n");
3971 assert_eq!(excerpted_buffers_text, text_for_range);
3972
3973 let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
3974 assert_eq!(
3975 snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
3976 expected_summary,
3977 "incorrect summary for range {:?}",
3978 start_ix..end_ix
3979 );
3980 }
3981
3982 // Anchor resolution
3983 let summaries = snapshot.summaries_for_anchors::<usize, _>(&anchors);
3984 assert_eq!(anchors.len(), summaries.len());
3985 for (anchor, resolved_offset) in anchors.iter().zip(summaries) {
3986 assert!(resolved_offset <= snapshot.len());
3987 assert_eq!(
3988 snapshot.summary_for_anchor::<usize>(anchor),
3989 resolved_offset
3990 );
3991 }
3992
3993 for _ in 0..10 {
3994 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
3995 assert_eq!(
3996 snapshot.reversed_chars_at(end_ix).collect::<String>(),
3997 expected_text[..end_ix].chars().rev().collect::<String>(),
3998 );
3999 }
4000
4001 for _ in 0..10 {
4002 let end_ix = rng.gen_range(0..=text_rope.len());
4003 let start_ix = rng.gen_range(0..=end_ix);
4004 assert_eq!(
4005 snapshot
4006 .bytes_in_range(start_ix..end_ix)
4007 .flatten()
4008 .copied()
4009 .collect::<Vec<_>>(),
4010 expected_text.as_bytes()[start_ix..end_ix].to_vec(),
4011 "bytes_in_range({:?})",
4012 start_ix..end_ix,
4013 );
4014 }
4015 }
4016
4017 let snapshot = multibuffer.read(cx).snapshot(cx);
4018 for (old_snapshot, subscription) in old_versions {
4019 let edits = subscription.consume().into_inner();
4020
4021 log::info!(
4022 "applying subscription edits to old text: {:?}: {:?}",
4023 old_snapshot.text(),
4024 edits,
4025 );
4026
4027 let mut text = old_snapshot.text();
4028 for edit in edits {
4029 let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
4030 text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
4031 }
4032 assert_eq!(text.to_string(), snapshot.text());
4033 }
4034 }
4035
4036 #[gpui::test]
4037 fn test_history(cx: &mut MutableAppContext) {
4038 cx.set_global(Settings::test(cx));
4039 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "1234", cx));
4040 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "5678", cx));
4041 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4042 let group_interval = multibuffer.read(cx).history.group_interval;
4043 multibuffer.update(cx, |multibuffer, cx| {
4044 multibuffer.push_excerpts(
4045 buffer_1.clone(),
4046 [ExcerptRange {
4047 context: 0..buffer_1.read(cx).len(),
4048 primary: None,
4049 }],
4050 cx,
4051 );
4052 multibuffer.push_excerpts(
4053 buffer_2.clone(),
4054 [ExcerptRange {
4055 context: 0..buffer_2.read(cx).len(),
4056 primary: None,
4057 }],
4058 cx,
4059 );
4060 });
4061
4062 let mut now = Instant::now();
4063
4064 multibuffer.update(cx, |multibuffer, cx| {
4065 multibuffer.start_transaction_at(now, cx);
4066 multibuffer.edit(
4067 [
4068 (Point::new(0, 0)..Point::new(0, 0), "A"),
4069 (Point::new(1, 0)..Point::new(1, 0), "A"),
4070 ],
4071 cx,
4072 );
4073 multibuffer.edit(
4074 [
4075 (Point::new(0, 1)..Point::new(0, 1), "B"),
4076 (Point::new(1, 1)..Point::new(1, 1), "B"),
4077 ],
4078 cx,
4079 );
4080 multibuffer.end_transaction_at(now, cx);
4081 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
4082
4083 // Edit buffer 1 through the multibuffer
4084 now += 2 * group_interval;
4085 multibuffer.start_transaction_at(now, cx);
4086 multibuffer.edit([(2..2, "C")], cx);
4087 multibuffer.end_transaction_at(now, cx);
4088 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
4089
4090 // Edit buffer 1 independently
4091 buffer_1.update(cx, |buffer_1, cx| {
4092 buffer_1.start_transaction_at(now);
4093 buffer_1.edit([(3..3, "D")], cx);
4094 buffer_1.end_transaction_at(now, cx);
4095
4096 now += 2 * group_interval;
4097 buffer_1.start_transaction_at(now);
4098 buffer_1.edit([(4..4, "E")], cx);
4099 buffer_1.end_transaction_at(now, cx);
4100 });
4101 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
4102
4103 // An undo in the multibuffer undoes the multibuffer transaction
4104 // and also any individual buffer edits that have occured since
4105 // that transaction.
4106 multibuffer.undo(cx);
4107 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
4108
4109 multibuffer.undo(cx);
4110 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
4111
4112 multibuffer.redo(cx);
4113 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
4114
4115 multibuffer.redo(cx);
4116 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
4117
4118 // Undo buffer 2 independently.
4119 buffer_2.update(cx, |buffer_2, cx| buffer_2.undo(cx));
4120 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\n5678");
4121
4122 // An undo in the multibuffer undoes the components of the
4123 // the last multibuffer transaction that are not already undone.
4124 multibuffer.undo(cx);
4125 assert_eq!(multibuffer.read(cx).text(), "AB1234\n5678");
4126
4127 multibuffer.undo(cx);
4128 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
4129
4130 multibuffer.redo(cx);
4131 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
4132
4133 buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
4134 assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
4135
4136 // Redo stack gets cleared after an edit.
4137 now += 2 * group_interval;
4138 multibuffer.start_transaction_at(now, cx);
4139 multibuffer.edit([(0..0, "X")], cx);
4140 multibuffer.end_transaction_at(now, cx);
4141 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
4142 multibuffer.redo(cx);
4143 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
4144 multibuffer.undo(cx);
4145 assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
4146 multibuffer.undo(cx);
4147 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
4148 });
4149 }
4150}