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