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