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