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