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 fn excerpt<'a>(&'a self, excerpt_id: ExcerptId) -> Option<&'a Excerpt> {
2817 let mut cursor = self.excerpts.cursor::<Option<&Locator>>();
2818 let locator = self.excerpt_locator_for_id(excerpt_id);
2819 cursor.seek(&Some(locator), Bias::Left, &());
2820 if let Some(excerpt) = cursor.item() {
2821 if excerpt.id == excerpt_id {
2822 return Some(excerpt);
2823 }
2824 }
2825 None
2826 }
2827
2828 pub fn remote_selections_in_range<'a>(
2829 &'a self,
2830 range: &'a Range<Anchor>,
2831 ) -> impl 'a + Iterator<Item = (ReplicaId, bool, CursorShape, Selection<Anchor>)> {
2832 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
2833 let start_locator = self.excerpt_locator_for_id(range.start.excerpt_id);
2834 let end_locator = self.excerpt_locator_for_id(range.end.excerpt_id);
2835 cursor.seek(start_locator, Bias::Left, &());
2836 cursor
2837 .take_while(move |excerpt| excerpt.locator <= *end_locator)
2838 .flat_map(move |excerpt| {
2839 let mut query_range = excerpt.range.context.start..excerpt.range.context.end;
2840 if excerpt.id == range.start.excerpt_id {
2841 query_range.start = range.start.text_anchor;
2842 }
2843 if excerpt.id == range.end.excerpt_id {
2844 query_range.end = range.end.text_anchor;
2845 }
2846
2847 excerpt
2848 .buffer
2849 .remote_selections_in_range(query_range)
2850 .flat_map(move |(replica_id, line_mode, cursor_shape, selections)| {
2851 selections.map(move |selection| {
2852 let mut start = Anchor {
2853 buffer_id: Some(excerpt.buffer_id),
2854 excerpt_id: excerpt.id.clone(),
2855 text_anchor: selection.start,
2856 };
2857 let mut end = Anchor {
2858 buffer_id: Some(excerpt.buffer_id),
2859 excerpt_id: excerpt.id.clone(),
2860 text_anchor: selection.end,
2861 };
2862 if range.start.cmp(&start, self).is_gt() {
2863 start = range.start.clone();
2864 }
2865 if range.end.cmp(&end, self).is_lt() {
2866 end = range.end.clone();
2867 }
2868
2869 (
2870 replica_id,
2871 line_mode,
2872 cursor_shape,
2873 Selection {
2874 id: selection.id,
2875 start,
2876 end,
2877 reversed: selection.reversed,
2878 goal: selection.goal,
2879 },
2880 )
2881 })
2882 })
2883 })
2884 }
2885}
2886
2887#[cfg(any(test, feature = "test-support"))]
2888impl MultiBufferSnapshot {
2889 pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
2890 let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
2891 let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
2892 start..end
2893 }
2894}
2895
2896impl History {
2897 fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
2898 self.transaction_depth += 1;
2899 if self.transaction_depth == 1 {
2900 let id = self.next_transaction_id.tick();
2901 self.undo_stack.push(Transaction {
2902 id,
2903 buffer_transactions: Default::default(),
2904 first_edit_at: now,
2905 last_edit_at: now,
2906 suppress_grouping: false,
2907 });
2908 Some(id)
2909 } else {
2910 None
2911 }
2912 }
2913
2914 fn end_transaction(
2915 &mut self,
2916 now: Instant,
2917 buffer_transactions: HashMap<usize, TransactionId>,
2918 ) -> bool {
2919 assert_ne!(self.transaction_depth, 0);
2920 self.transaction_depth -= 1;
2921 if self.transaction_depth == 0 {
2922 if buffer_transactions.is_empty() {
2923 self.undo_stack.pop();
2924 false
2925 } else {
2926 self.redo_stack.clear();
2927 let transaction = self.undo_stack.last_mut().unwrap();
2928 transaction.last_edit_at = now;
2929 for (buffer_id, transaction_id) in buffer_transactions {
2930 transaction
2931 .buffer_transactions
2932 .entry(buffer_id)
2933 .or_insert(transaction_id);
2934 }
2935 true
2936 }
2937 } else {
2938 false
2939 }
2940 }
2941
2942 fn push_transaction<'a, T>(&mut self, buffer_transactions: T, now: Instant)
2943 where
2944 T: IntoIterator<Item = (&'a ModelHandle<Buffer>, &'a language::Transaction)>,
2945 {
2946 assert_eq!(self.transaction_depth, 0);
2947 let transaction = Transaction {
2948 id: self.next_transaction_id.tick(),
2949 buffer_transactions: buffer_transactions
2950 .into_iter()
2951 .map(|(buffer, transaction)| (buffer.id(), transaction.id))
2952 .collect(),
2953 first_edit_at: now,
2954 last_edit_at: now,
2955 suppress_grouping: false,
2956 };
2957 if !transaction.buffer_transactions.is_empty() {
2958 self.undo_stack.push(transaction);
2959 self.redo_stack.clear();
2960 }
2961 }
2962
2963 fn finalize_last_transaction(&mut self) {
2964 if let Some(transaction) = self.undo_stack.last_mut() {
2965 transaction.suppress_grouping = true;
2966 }
2967 }
2968
2969 fn pop_undo(&mut self) -> Option<&mut Transaction> {
2970 assert_eq!(self.transaction_depth, 0);
2971 if let Some(transaction) = self.undo_stack.pop() {
2972 self.redo_stack.push(transaction);
2973 self.redo_stack.last_mut()
2974 } else {
2975 None
2976 }
2977 }
2978
2979 fn pop_redo(&mut self) -> Option<&mut Transaction> {
2980 assert_eq!(self.transaction_depth, 0);
2981 if let Some(transaction) = self.redo_stack.pop() {
2982 self.undo_stack.push(transaction);
2983 self.undo_stack.last_mut()
2984 } else {
2985 None
2986 }
2987 }
2988
2989 fn group(&mut self) -> Option<TransactionId> {
2990 let mut count = 0;
2991 let mut transactions = self.undo_stack.iter();
2992 if let Some(mut transaction) = transactions.next_back() {
2993 while let Some(prev_transaction) = transactions.next_back() {
2994 if !prev_transaction.suppress_grouping
2995 && transaction.first_edit_at - prev_transaction.last_edit_at
2996 <= self.group_interval
2997 {
2998 transaction = prev_transaction;
2999 count += 1;
3000 } else {
3001 break;
3002 }
3003 }
3004 }
3005 self.group_trailing(count)
3006 }
3007
3008 fn group_until(&mut self, transaction_id: TransactionId) {
3009 let mut count = 0;
3010 for transaction in self.undo_stack.iter().rev() {
3011 if transaction.id == transaction_id {
3012 self.group_trailing(count);
3013 break;
3014 } else if transaction.suppress_grouping {
3015 break;
3016 } else {
3017 count += 1;
3018 }
3019 }
3020 }
3021
3022 fn group_trailing(&mut self, n: usize) -> Option<TransactionId> {
3023 let new_len = self.undo_stack.len() - n;
3024 let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
3025 if let Some(last_transaction) = transactions_to_keep.last_mut() {
3026 if let Some(transaction) = transactions_to_merge.last() {
3027 last_transaction.last_edit_at = transaction.last_edit_at;
3028 }
3029 for to_merge in transactions_to_merge {
3030 for (buffer_id, transaction_id) in &to_merge.buffer_transactions {
3031 last_transaction
3032 .buffer_transactions
3033 .entry(*buffer_id)
3034 .or_insert(*transaction_id);
3035 }
3036 }
3037 }
3038
3039 self.undo_stack.truncate(new_len);
3040 self.undo_stack.last().map(|t| t.id)
3041 }
3042}
3043
3044impl Excerpt {
3045 fn new(
3046 id: ExcerptId,
3047 locator: Locator,
3048 buffer_id: usize,
3049 buffer: BufferSnapshot,
3050 range: ExcerptRange<text::Anchor>,
3051 has_trailing_newline: bool,
3052 ) -> Self {
3053 Excerpt {
3054 id,
3055 locator,
3056 max_buffer_row: range.context.end.to_point(&buffer).row,
3057 text_summary: buffer
3058 .text_summary_for_range::<TextSummary, _>(range.context.to_offset(&buffer)),
3059 buffer_id,
3060 buffer,
3061 range,
3062 has_trailing_newline,
3063 }
3064 }
3065
3066 fn chunks_in_range(&self, range: Range<usize>, language_aware: bool) -> ExcerptChunks {
3067 let content_start = self.range.context.start.to_offset(&self.buffer);
3068 let chunks_start = content_start + range.start;
3069 let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
3070
3071 let footer_height = if self.has_trailing_newline
3072 && range.start <= self.text_summary.len
3073 && range.end > self.text_summary.len
3074 {
3075 1
3076 } else {
3077 0
3078 };
3079
3080 let content_chunks = self.buffer.chunks(chunks_start..chunks_end, language_aware);
3081
3082 ExcerptChunks {
3083 content_chunks,
3084 footer_height,
3085 }
3086 }
3087
3088 fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
3089 let content_start = self.range.context.start.to_offset(&self.buffer);
3090 let bytes_start = content_start + range.start;
3091 let bytes_end = content_start + cmp::min(range.end, self.text_summary.len);
3092 let footer_height = if self.has_trailing_newline
3093 && range.start <= self.text_summary.len
3094 && range.end > self.text_summary.len
3095 {
3096 1
3097 } else {
3098 0
3099 };
3100 let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
3101
3102 ExcerptBytes {
3103 content_bytes,
3104 footer_height,
3105 }
3106 }
3107
3108 fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
3109 if text_anchor
3110 .cmp(&self.range.context.start, &self.buffer)
3111 .is_lt()
3112 {
3113 self.range.context.start
3114 } else if text_anchor
3115 .cmp(&self.range.context.end, &self.buffer)
3116 .is_gt()
3117 {
3118 self.range.context.end
3119 } else {
3120 text_anchor
3121 }
3122 }
3123
3124 fn contains(&self, anchor: &Anchor) -> bool {
3125 Some(self.buffer_id) == anchor.buffer_id
3126 && self
3127 .range
3128 .context
3129 .start
3130 .cmp(&anchor.text_anchor, &self.buffer)
3131 .is_le()
3132 && self
3133 .range
3134 .context
3135 .end
3136 .cmp(&anchor.text_anchor, &self.buffer)
3137 .is_ge()
3138 }
3139}
3140
3141impl ExcerptId {
3142 pub fn min() -> Self {
3143 Self(0)
3144 }
3145
3146 pub fn max() -> Self {
3147 Self(usize::MAX)
3148 }
3149
3150 pub fn cmp(&self, other: &Self, snapshot: &MultiBufferSnapshot) -> cmp::Ordering {
3151 let a = snapshot.excerpt_locator_for_id(*self);
3152 let b = snapshot.excerpt_locator_for_id(*other);
3153 a.cmp(&b).then_with(|| self.0.cmp(&other.0))
3154 }
3155}
3156
3157impl Into<usize> for ExcerptId {
3158 fn into(self) -> usize {
3159 self.0
3160 }
3161}
3162
3163impl fmt::Debug for Excerpt {
3164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3165 f.debug_struct("Excerpt")
3166 .field("id", &self.id)
3167 .field("locator", &self.locator)
3168 .field("buffer_id", &self.buffer_id)
3169 .field("range", &self.range)
3170 .field("text_summary", &self.text_summary)
3171 .field("has_trailing_newline", &self.has_trailing_newline)
3172 .finish()
3173 }
3174}
3175
3176impl sum_tree::Item for Excerpt {
3177 type Summary = ExcerptSummary;
3178
3179 fn summary(&self) -> Self::Summary {
3180 let mut text = self.text_summary.clone();
3181 if self.has_trailing_newline {
3182 text += TextSummary::from("\n");
3183 }
3184 ExcerptSummary {
3185 excerpt_id: self.id,
3186 excerpt_locator: self.locator.clone(),
3187 max_buffer_row: self.max_buffer_row,
3188 text,
3189 }
3190 }
3191}
3192
3193impl sum_tree::Item for ExcerptIdMapping {
3194 type Summary = ExcerptId;
3195
3196 fn summary(&self) -> Self::Summary {
3197 self.id
3198 }
3199}
3200
3201impl sum_tree::KeyedItem for ExcerptIdMapping {
3202 type Key = ExcerptId;
3203
3204 fn key(&self) -> Self::Key {
3205 self.id
3206 }
3207}
3208
3209impl sum_tree::Summary for ExcerptId {
3210 type Context = ();
3211
3212 fn add_summary(&mut self, other: &Self, _: &()) {
3213 *self = *other;
3214 }
3215}
3216
3217impl sum_tree::Summary for ExcerptSummary {
3218 type Context = ();
3219
3220 fn add_summary(&mut self, summary: &Self, _: &()) {
3221 debug_assert!(summary.excerpt_locator > self.excerpt_locator);
3222 self.excerpt_locator = summary.excerpt_locator.clone();
3223 self.text.add_summary(&summary.text, &());
3224 self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row);
3225 }
3226}
3227
3228impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
3229 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3230 *self += &summary.text;
3231 }
3232}
3233
3234impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
3235 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3236 *self += summary.text.len;
3237 }
3238}
3239
3240impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
3241 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
3242 Ord::cmp(self, &cursor_location.text.len)
3243 }
3244}
3245
3246impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, Option<&'a Locator>> for Locator {
3247 fn cmp(&self, cursor_location: &Option<&'a Locator>, _: &()) -> cmp::Ordering {
3248 Ord::cmp(&Some(self), cursor_location)
3249 }
3250}
3251
3252impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Locator {
3253 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
3254 Ord::cmp(self, &cursor_location.excerpt_locator)
3255 }
3256}
3257
3258impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for OffsetUtf16 {
3259 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3260 *self += summary.text.len_utf16;
3261 }
3262}
3263
3264impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
3265 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3266 *self += summary.text.lines;
3267 }
3268}
3269
3270impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
3271 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3272 *self += summary.text.lines_utf16()
3273 }
3274}
3275
3276impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a Locator> {
3277 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3278 *self = Some(&summary.excerpt_locator);
3279 }
3280}
3281
3282impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<ExcerptId> {
3283 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3284 *self = Some(summary.excerpt_id);
3285 }
3286}
3287
3288impl<'a> MultiBufferRows<'a> {
3289 pub fn seek(&mut self, row: u32) {
3290 self.buffer_row_range = 0..0;
3291
3292 self.excerpts
3293 .seek_forward(&Point::new(row, 0), Bias::Right, &());
3294 if self.excerpts.item().is_none() {
3295 self.excerpts.prev(&());
3296
3297 if self.excerpts.item().is_none() && row == 0 {
3298 self.buffer_row_range = 0..1;
3299 return;
3300 }
3301 }
3302
3303 if let Some(excerpt) = self.excerpts.item() {
3304 let overshoot = row - self.excerpts.start().row;
3305 let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
3306 self.buffer_row_range.start = excerpt_start + overshoot;
3307 self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
3308 }
3309 }
3310}
3311
3312impl<'a> Iterator for MultiBufferRows<'a> {
3313 type Item = Option<u32>;
3314
3315 fn next(&mut self) -> Option<Self::Item> {
3316 loop {
3317 if !self.buffer_row_range.is_empty() {
3318 let row = Some(self.buffer_row_range.start);
3319 self.buffer_row_range.start += 1;
3320 return Some(row);
3321 }
3322 self.excerpts.item()?;
3323 self.excerpts.next(&());
3324 let excerpt = self.excerpts.item()?;
3325 self.buffer_row_range.start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
3326 self.buffer_row_range.end =
3327 self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
3328 }
3329 }
3330}
3331
3332impl<'a> MultiBufferChunks<'a> {
3333 pub fn offset(&self) -> usize {
3334 self.range.start
3335 }
3336
3337 pub fn seek(&mut self, offset: usize) {
3338 self.range.start = offset;
3339 self.excerpts.seek(&offset, Bias::Right, &());
3340 if let Some(excerpt) = self.excerpts.item() {
3341 self.excerpt_chunks = Some(excerpt.chunks_in_range(
3342 self.range.start - self.excerpts.start()..self.range.end - self.excerpts.start(),
3343 self.language_aware,
3344 ));
3345 } else {
3346 self.excerpt_chunks = None;
3347 }
3348 }
3349}
3350
3351impl<'a> Iterator for MultiBufferChunks<'a> {
3352 type Item = Chunk<'a>;
3353
3354 fn next(&mut self) -> Option<Self::Item> {
3355 if self.range.is_empty() {
3356 None
3357 } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
3358 self.range.start += chunk.text.len();
3359 Some(chunk)
3360 } else {
3361 self.excerpts.next(&());
3362 let excerpt = self.excerpts.item()?;
3363 self.excerpt_chunks = Some(excerpt.chunks_in_range(
3364 0..self.range.end - self.excerpts.start(),
3365 self.language_aware,
3366 ));
3367 self.next()
3368 }
3369 }
3370}
3371
3372impl<'a> MultiBufferBytes<'a> {
3373 fn consume(&mut self, len: usize) {
3374 self.range.start += len;
3375 self.chunk = &self.chunk[len..];
3376
3377 if !self.range.is_empty() && self.chunk.is_empty() {
3378 if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
3379 self.chunk = chunk;
3380 } else {
3381 self.excerpts.next(&());
3382 if let Some(excerpt) = self.excerpts.item() {
3383 let mut excerpt_bytes =
3384 excerpt.bytes_in_range(0..self.range.end - self.excerpts.start());
3385 self.chunk = excerpt_bytes.next().unwrap();
3386 self.excerpt_bytes = Some(excerpt_bytes);
3387 }
3388 }
3389 }
3390 }
3391}
3392
3393impl<'a> Iterator for MultiBufferBytes<'a> {
3394 type Item = &'a [u8];
3395
3396 fn next(&mut self) -> Option<Self::Item> {
3397 let chunk = self.chunk;
3398 if chunk.is_empty() {
3399 None
3400 } else {
3401 self.consume(chunk.len());
3402 Some(chunk)
3403 }
3404 }
3405}
3406
3407impl<'a> io::Read for MultiBufferBytes<'a> {
3408 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
3409 let len = cmp::min(buf.len(), self.chunk.len());
3410 buf[..len].copy_from_slice(&self.chunk[..len]);
3411 if len > 0 {
3412 self.consume(len);
3413 }
3414 Ok(len)
3415 }
3416}
3417
3418impl<'a> Iterator for ExcerptBytes<'a> {
3419 type Item = &'a [u8];
3420
3421 fn next(&mut self) -> Option<Self::Item> {
3422 if let Some(chunk) = self.content_bytes.next() {
3423 if !chunk.is_empty() {
3424 return Some(chunk);
3425 }
3426 }
3427
3428 if self.footer_height > 0 {
3429 let result = &NEWLINES[..self.footer_height];
3430 self.footer_height = 0;
3431 return Some(result);
3432 }
3433
3434 None
3435 }
3436}
3437
3438impl<'a> Iterator for ExcerptChunks<'a> {
3439 type Item = Chunk<'a>;
3440
3441 fn next(&mut self) -> Option<Self::Item> {
3442 if let Some(chunk) = self.content_chunks.next() {
3443 return Some(chunk);
3444 }
3445
3446 if self.footer_height > 0 {
3447 let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
3448 self.footer_height = 0;
3449 return Some(Chunk {
3450 text,
3451 ..Default::default()
3452 });
3453 }
3454
3455 None
3456 }
3457}
3458
3459impl ToOffset for Point {
3460 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3461 snapshot.point_to_offset(*self)
3462 }
3463}
3464
3465impl ToOffset for usize {
3466 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3467 assert!(*self <= snapshot.len(), "offset is out of range");
3468 *self
3469 }
3470}
3471
3472impl ToOffset for OffsetUtf16 {
3473 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3474 snapshot.offset_utf16_to_offset(*self)
3475 }
3476}
3477
3478impl ToOffset for PointUtf16 {
3479 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3480 snapshot.point_utf16_to_offset(*self)
3481 }
3482}
3483
3484impl ToOffsetUtf16 for OffsetUtf16 {
3485 fn to_offset_utf16(&self, _snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
3486 *self
3487 }
3488}
3489
3490impl ToOffsetUtf16 for usize {
3491 fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
3492 snapshot.offset_to_offset_utf16(*self)
3493 }
3494}
3495
3496impl ToPoint for usize {
3497 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
3498 snapshot.offset_to_point(*self)
3499 }
3500}
3501
3502impl ToPoint for Point {
3503 fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
3504 *self
3505 }
3506}
3507
3508impl ToPointUtf16 for usize {
3509 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
3510 snapshot.offset_to_point_utf16(*self)
3511 }
3512}
3513
3514impl ToPointUtf16 for Point {
3515 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
3516 snapshot.point_to_point_utf16(*self)
3517 }
3518}
3519
3520impl ToPointUtf16 for PointUtf16 {
3521 fn to_point_utf16<'a>(&self, _: &MultiBufferSnapshot) -> PointUtf16 {
3522 *self
3523 }
3524}
3525
3526#[cfg(test)]
3527mod tests {
3528 use super::*;
3529 use gpui::MutableAppContext;
3530 use language::{Buffer, Rope};
3531 use rand::prelude::*;
3532 use settings::Settings;
3533 use std::{env, rc::Rc};
3534
3535 use util::test::sample_text;
3536
3537 #[gpui::test]
3538 fn test_singleton(cx: &mut MutableAppContext) {
3539 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
3540 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
3541
3542 let snapshot = multibuffer.read(cx).snapshot(cx);
3543 assert_eq!(snapshot.text(), buffer.read(cx).text());
3544
3545 assert_eq!(
3546 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3547 (0..buffer.read(cx).row_count())
3548 .map(Some)
3549 .collect::<Vec<_>>()
3550 );
3551
3552 buffer.update(cx, |buffer, cx| buffer.edit([(1..3, "XXX\n")], None, cx));
3553 let snapshot = multibuffer.read(cx).snapshot(cx);
3554
3555 assert_eq!(snapshot.text(), buffer.read(cx).text());
3556 assert_eq!(
3557 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3558 (0..buffer.read(cx).row_count())
3559 .map(Some)
3560 .collect::<Vec<_>>()
3561 );
3562 }
3563
3564 #[gpui::test]
3565 fn test_remote(cx: &mut MutableAppContext) {
3566 let host_buffer = cx.add_model(|cx| Buffer::new(0, "a", cx));
3567 let guest_buffer = cx.add_model(|cx| {
3568 let state = host_buffer.read(cx).to_proto();
3569 let ops = cx
3570 .background()
3571 .block(host_buffer.read(cx).serialize_ops(cx));
3572 let mut buffer = Buffer::from_proto(1, state, None).unwrap();
3573 buffer
3574 .apply_ops(
3575 ops.into_iter()
3576 .map(|op| language::proto::deserialize_operation(op).unwrap()),
3577 cx,
3578 )
3579 .unwrap();
3580 buffer
3581 });
3582 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(guest_buffer.clone(), cx));
3583 let snapshot = multibuffer.read(cx).snapshot(cx);
3584 assert_eq!(snapshot.text(), "a");
3585
3586 guest_buffer.update(cx, |buffer, cx| buffer.edit([(1..1, "b")], None, cx));
3587 let snapshot = multibuffer.read(cx).snapshot(cx);
3588 assert_eq!(snapshot.text(), "ab");
3589
3590 guest_buffer.update(cx, |buffer, cx| buffer.edit([(2..2, "c")], None, cx));
3591 let snapshot = multibuffer.read(cx).snapshot(cx);
3592 assert_eq!(snapshot.text(), "abc");
3593 }
3594
3595 #[gpui::test]
3596 fn test_excerpt_boundaries_and_clipping(cx: &mut MutableAppContext) {
3597 let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
3598 let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
3599 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3600
3601 let events = Rc::new(RefCell::new(Vec::<Event>::new()));
3602 multibuffer.update(cx, |_, cx| {
3603 let events = events.clone();
3604 cx.subscribe(&multibuffer, move |_, _, event, _| {
3605 if let Event::Edited = event {
3606 events.borrow_mut().push(event.clone())
3607 }
3608 })
3609 .detach();
3610 });
3611
3612 let subscription = multibuffer.update(cx, |multibuffer, cx| {
3613 let subscription = multibuffer.subscribe();
3614 multibuffer.push_excerpts(
3615 buffer_1.clone(),
3616 [ExcerptRange {
3617 context: Point::new(1, 2)..Point::new(2, 5),
3618 primary: None,
3619 }],
3620 cx,
3621 );
3622 assert_eq!(
3623 subscription.consume().into_inner(),
3624 [Edit {
3625 old: 0..0,
3626 new: 0..10
3627 }]
3628 );
3629
3630 multibuffer.push_excerpts(
3631 buffer_1.clone(),
3632 [ExcerptRange {
3633 context: Point::new(3, 3)..Point::new(4, 4),
3634 primary: None,
3635 }],
3636 cx,
3637 );
3638 multibuffer.push_excerpts(
3639 buffer_2.clone(),
3640 [ExcerptRange {
3641 context: Point::new(3, 1)..Point::new(3, 3),
3642 primary: None,
3643 }],
3644 cx,
3645 );
3646 assert_eq!(
3647 subscription.consume().into_inner(),
3648 [Edit {
3649 old: 10..10,
3650 new: 10..22
3651 }]
3652 );
3653
3654 subscription
3655 });
3656
3657 // Adding excerpts emits an edited event.
3658 assert_eq!(
3659 events.borrow().as_slice(),
3660 &[Event::Edited, Event::Edited, Event::Edited]
3661 );
3662
3663 let snapshot = multibuffer.read(cx).snapshot(cx);
3664 assert_eq!(
3665 snapshot.text(),
3666 concat!(
3667 "bbbb\n", // Preserve newlines
3668 "ccccc\n", //
3669 "ddd\n", //
3670 "eeee\n", //
3671 "jj" //
3672 )
3673 );
3674 assert_eq!(
3675 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3676 [Some(1), Some(2), Some(3), Some(4), Some(3)]
3677 );
3678 assert_eq!(
3679 snapshot.buffer_rows(2).collect::<Vec<_>>(),
3680 [Some(3), Some(4), Some(3)]
3681 );
3682 assert_eq!(snapshot.buffer_rows(4).collect::<Vec<_>>(), [Some(3)]);
3683 assert_eq!(snapshot.buffer_rows(5).collect::<Vec<_>>(), []);
3684
3685 assert_eq!(
3686 boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot),
3687 &[
3688 (0, "bbbb\nccccc".to_string(), true),
3689 (2, "ddd\neeee".to_string(), false),
3690 (4, "jj".to_string(), true),
3691 ]
3692 );
3693 assert_eq!(
3694 boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot),
3695 &[(0, "bbbb\nccccc".to_string(), true)]
3696 );
3697 assert_eq!(
3698 boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot),
3699 &[]
3700 );
3701 assert_eq!(
3702 boundaries_in_range(Point::new(1, 0)..Point::new(2, 0), &snapshot),
3703 &[]
3704 );
3705 assert_eq!(
3706 boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
3707 &[(2, "ddd\neeee".to_string(), false)]
3708 );
3709 assert_eq!(
3710 boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
3711 &[(2, "ddd\neeee".to_string(), false)]
3712 );
3713 assert_eq!(
3714 boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot),
3715 &[(2, "ddd\neeee".to_string(), false)]
3716 );
3717 assert_eq!(
3718 boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot),
3719 &[(4, "jj".to_string(), true)]
3720 );
3721 assert_eq!(
3722 boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot),
3723 &[]
3724 );
3725
3726 buffer_1.update(cx, |buffer, cx| {
3727 let text = "\n";
3728 buffer.edit(
3729 [
3730 (Point::new(0, 0)..Point::new(0, 0), text),
3731 (Point::new(2, 1)..Point::new(2, 3), text),
3732 ],
3733 None,
3734 cx,
3735 );
3736 });
3737
3738 let snapshot = multibuffer.read(cx).snapshot(cx);
3739 assert_eq!(
3740 snapshot.text(),
3741 concat!(
3742 "bbbb\n", // Preserve newlines
3743 "c\n", //
3744 "cc\n", //
3745 "ddd\n", //
3746 "eeee\n", //
3747 "jj" //
3748 )
3749 );
3750
3751 assert_eq!(
3752 subscription.consume().into_inner(),
3753 [Edit {
3754 old: 6..8,
3755 new: 6..7
3756 }]
3757 );
3758
3759 let snapshot = multibuffer.read(cx).snapshot(cx);
3760 assert_eq!(
3761 snapshot.clip_point(Point::new(0, 5), Bias::Left),
3762 Point::new(0, 4)
3763 );
3764 assert_eq!(
3765 snapshot.clip_point(Point::new(0, 5), Bias::Right),
3766 Point::new(0, 4)
3767 );
3768 assert_eq!(
3769 snapshot.clip_point(Point::new(5, 1), Bias::Right),
3770 Point::new(5, 1)
3771 );
3772 assert_eq!(
3773 snapshot.clip_point(Point::new(5, 2), Bias::Right),
3774 Point::new(5, 2)
3775 );
3776 assert_eq!(
3777 snapshot.clip_point(Point::new(5, 3), Bias::Right),
3778 Point::new(5, 2)
3779 );
3780
3781 let snapshot = multibuffer.update(cx, |multibuffer, cx| {
3782 let (buffer_2_excerpt_id, _) =
3783 multibuffer.excerpts_for_buffer(&buffer_2, cx)[0].clone();
3784 multibuffer.remove_excerpts([buffer_2_excerpt_id], cx);
3785 multibuffer.snapshot(cx)
3786 });
3787
3788 assert_eq!(
3789 snapshot.text(),
3790 concat!(
3791 "bbbb\n", // Preserve newlines
3792 "c\n", //
3793 "cc\n", //
3794 "ddd\n", //
3795 "eeee", //
3796 )
3797 );
3798
3799 fn boundaries_in_range(
3800 range: Range<Point>,
3801 snapshot: &MultiBufferSnapshot,
3802 ) -> Vec<(u32, String, bool)> {
3803 snapshot
3804 .excerpt_boundaries_in_range(range)
3805 .map(|boundary| {
3806 (
3807 boundary.row,
3808 boundary
3809 .buffer
3810 .text_for_range(boundary.range.context)
3811 .collect::<String>(),
3812 boundary.starts_new_buffer,
3813 )
3814 })
3815 .collect::<Vec<_>>()
3816 }
3817 }
3818
3819 #[gpui::test]
3820 fn test_excerpt_events(cx: &mut MutableAppContext) {
3821 let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(10, 3, 'a'), cx));
3822 let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(10, 3, 'm'), cx));
3823
3824 let leader_multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3825 let follower_multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3826
3827 follower_multibuffer.update(cx, |_, cx| {
3828 cx.subscribe(&leader_multibuffer, |follower, _, event, cx| {
3829 match event.clone() {
3830 Event::ExcerptsAdded {
3831 buffer,
3832 predecessor,
3833 excerpts,
3834 } => follower.insert_excerpts_with_ids_after(predecessor, buffer, excerpts, cx),
3835 Event::ExcerptsRemoved { ids } => follower.remove_excerpts(ids, cx),
3836 _ => {}
3837 }
3838 })
3839 .detach();
3840 });
3841
3842 leader_multibuffer.update(cx, |leader, cx| {
3843 leader.push_excerpts(
3844 buffer_1.clone(),
3845 [
3846 ExcerptRange {
3847 context: 0..8,
3848 primary: None,
3849 },
3850 ExcerptRange {
3851 context: 12..16,
3852 primary: None,
3853 },
3854 ],
3855 cx,
3856 );
3857 leader.insert_excerpts_after(
3858 leader.excerpt_ids()[0],
3859 buffer_2.clone(),
3860 [
3861 ExcerptRange {
3862 context: 0..5,
3863 primary: None,
3864 },
3865 ExcerptRange {
3866 context: 10..15,
3867 primary: None,
3868 },
3869 ],
3870 cx,
3871 )
3872 });
3873 assert_eq!(
3874 leader_multibuffer.read(cx).snapshot(cx).text(),
3875 follower_multibuffer.read(cx).snapshot(cx).text(),
3876 );
3877
3878 leader_multibuffer.update(cx, |leader, cx| {
3879 let excerpt_ids = leader.excerpt_ids();
3880 leader.remove_excerpts([excerpt_ids[1], excerpt_ids[3]], cx);
3881 });
3882 assert_eq!(
3883 leader_multibuffer.read(cx).snapshot(cx).text(),
3884 follower_multibuffer.read(cx).snapshot(cx).text(),
3885 );
3886
3887 leader_multibuffer.update(cx, |leader, cx| {
3888 leader.clear(cx);
3889 });
3890 assert_eq!(
3891 leader_multibuffer.read(cx).snapshot(cx).text(),
3892 follower_multibuffer.read(cx).snapshot(cx).text(),
3893 );
3894 }
3895
3896 #[gpui::test]
3897 fn test_push_excerpts_with_context_lines(cx: &mut MutableAppContext) {
3898 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(20, 3, 'a'), cx));
3899 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3900 let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
3901 multibuffer.push_excerpts_with_context_lines(
3902 buffer.clone(),
3903 vec![
3904 Point::new(3, 2)..Point::new(4, 2),
3905 Point::new(7, 1)..Point::new(7, 3),
3906 Point::new(15, 0)..Point::new(15, 0),
3907 ],
3908 2,
3909 cx,
3910 )
3911 });
3912
3913 let snapshot = multibuffer.read(cx).snapshot(cx);
3914 assert_eq!(
3915 snapshot.text(),
3916 "bbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\n\nnnn\nooo\nppp\nqqq\nrrr\n"
3917 );
3918
3919 assert_eq!(
3920 anchor_ranges
3921 .iter()
3922 .map(|range| range.to_point(&snapshot))
3923 .collect::<Vec<_>>(),
3924 vec![
3925 Point::new(2, 2)..Point::new(3, 2),
3926 Point::new(6, 1)..Point::new(6, 3),
3927 Point::new(12, 0)..Point::new(12, 0)
3928 ]
3929 );
3930 }
3931
3932 #[gpui::test]
3933 fn test_empty_multibuffer(cx: &mut MutableAppContext) {
3934 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3935
3936 let snapshot = multibuffer.read(cx).snapshot(cx);
3937 assert_eq!(snapshot.text(), "");
3938 assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), &[Some(0)]);
3939 assert_eq!(snapshot.buffer_rows(1).collect::<Vec<_>>(), &[]);
3940 }
3941
3942 #[gpui::test]
3943 fn test_singleton_multibuffer_anchors(cx: &mut MutableAppContext) {
3944 let buffer = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
3945 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
3946 let old_snapshot = multibuffer.read(cx).snapshot(cx);
3947 buffer.update(cx, |buffer, cx| {
3948 buffer.edit([(0..0, "X")], None, cx);
3949 buffer.edit([(5..5, "Y")], None, cx);
3950 });
3951 let new_snapshot = multibuffer.read(cx).snapshot(cx);
3952
3953 assert_eq!(old_snapshot.text(), "abcd");
3954 assert_eq!(new_snapshot.text(), "XabcdY");
3955
3956 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
3957 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
3958 assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
3959 assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
3960 }
3961
3962 #[gpui::test]
3963 fn test_multibuffer_anchors(cx: &mut MutableAppContext) {
3964 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
3965 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
3966 let multibuffer = cx.add_model(|cx| {
3967 let mut multibuffer = MultiBuffer::new(0);
3968 multibuffer.push_excerpts(
3969 buffer_1.clone(),
3970 [ExcerptRange {
3971 context: 0..4,
3972 primary: None,
3973 }],
3974 cx,
3975 );
3976 multibuffer.push_excerpts(
3977 buffer_2.clone(),
3978 [ExcerptRange {
3979 context: 0..5,
3980 primary: None,
3981 }],
3982 cx,
3983 );
3984 multibuffer
3985 });
3986 let old_snapshot = multibuffer.read(cx).snapshot(cx);
3987
3988 assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
3989 assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
3990 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
3991 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
3992 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
3993 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
3994
3995 buffer_1.update(cx, |buffer, cx| {
3996 buffer.edit([(0..0, "W")], None, cx);
3997 buffer.edit([(5..5, "X")], None, cx);
3998 });
3999 buffer_2.update(cx, |buffer, cx| {
4000 buffer.edit([(0..0, "Y")], None, cx);
4001 buffer.edit([(6..6, "Z")], None, cx);
4002 });
4003 let new_snapshot = multibuffer.read(cx).snapshot(cx);
4004
4005 assert_eq!(old_snapshot.text(), "abcd\nefghi");
4006 assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
4007
4008 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
4009 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
4010 assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
4011 assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
4012 assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
4013 assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
4014 assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
4015 assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
4016 assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
4017 assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
4018 }
4019
4020 #[gpui::test]
4021 fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut MutableAppContext) {
4022 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
4023 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "ABCDEFGHIJKLMNOP", cx));
4024 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4025
4026 // Create an insertion id in buffer 1 that doesn't exist in buffer 2.
4027 // Add an excerpt from buffer 1 that spans this new insertion.
4028 buffer_1.update(cx, |buffer, cx| buffer.edit([(4..4, "123")], None, cx));
4029 let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| {
4030 multibuffer
4031 .push_excerpts(
4032 buffer_1.clone(),
4033 [ExcerptRange {
4034 context: 0..7,
4035 primary: None,
4036 }],
4037 cx,
4038 )
4039 .pop()
4040 .unwrap()
4041 });
4042
4043 let snapshot_1 = multibuffer.read(cx).snapshot(cx);
4044 assert_eq!(snapshot_1.text(), "abcd123");
4045
4046 // Replace the buffer 1 excerpt with new excerpts from buffer 2.
4047 let (excerpt_id_2, excerpt_id_3) = multibuffer.update(cx, |multibuffer, cx| {
4048 multibuffer.remove_excerpts([excerpt_id_1], cx);
4049 let mut ids = multibuffer
4050 .push_excerpts(
4051 buffer_2.clone(),
4052 [
4053 ExcerptRange {
4054 context: 0..4,
4055 primary: None,
4056 },
4057 ExcerptRange {
4058 context: 6..10,
4059 primary: None,
4060 },
4061 ExcerptRange {
4062 context: 12..16,
4063 primary: None,
4064 },
4065 ],
4066 cx,
4067 )
4068 .into_iter();
4069 (ids.next().unwrap(), ids.next().unwrap())
4070 });
4071 let snapshot_2 = multibuffer.read(cx).snapshot(cx);
4072 assert_eq!(snapshot_2.text(), "ABCD\nGHIJ\nMNOP");
4073
4074 // The old excerpt id doesn't get reused.
4075 assert_ne!(excerpt_id_2, excerpt_id_1);
4076
4077 // Resolve some anchors from the previous snapshot in the new snapshot.
4078 // The current excerpts are from a different buffer, so we don't attempt to
4079 // resolve the old text anchor in the new buffer.
4080 assert_eq!(
4081 snapshot_2.summary_for_anchor::<usize>(&snapshot_1.anchor_before(2)),
4082 0
4083 );
4084 assert_eq!(
4085 snapshot_2.summaries_for_anchors::<usize, _>(&[
4086 snapshot_1.anchor_before(2),
4087 snapshot_1.anchor_after(3)
4088 ]),
4089 vec![0, 0]
4090 );
4091
4092 // Refresh anchors from the old snapshot. The return value indicates that both
4093 // anchors lost their original excerpt.
4094 let refresh =
4095 snapshot_2.refresh_anchors(&[snapshot_1.anchor_before(2), snapshot_1.anchor_after(3)]);
4096 assert_eq!(
4097 refresh,
4098 &[
4099 (0, snapshot_2.anchor_before(0), false),
4100 (1, snapshot_2.anchor_after(0), false),
4101 ]
4102 );
4103
4104 // Replace the middle excerpt with a smaller excerpt in buffer 2,
4105 // that intersects the old excerpt.
4106 let excerpt_id_5 = multibuffer.update(cx, |multibuffer, cx| {
4107 multibuffer.remove_excerpts([excerpt_id_3], cx);
4108 multibuffer
4109 .insert_excerpts_after(
4110 excerpt_id_2,
4111 buffer_2.clone(),
4112 [ExcerptRange {
4113 context: 5..8,
4114 primary: None,
4115 }],
4116 cx,
4117 )
4118 .pop()
4119 .unwrap()
4120 });
4121
4122 let snapshot_3 = multibuffer.read(cx).snapshot(cx);
4123 assert_eq!(snapshot_3.text(), "ABCD\nFGH\nMNOP");
4124 assert_ne!(excerpt_id_5, excerpt_id_3);
4125
4126 // Resolve some anchors from the previous snapshot in the new snapshot.
4127 // The third anchor can't be resolved, since its excerpt has been removed,
4128 // so it resolves to the same position as its predecessor.
4129 let anchors = [
4130 snapshot_2.anchor_before(0),
4131 snapshot_2.anchor_after(2),
4132 snapshot_2.anchor_after(6),
4133 snapshot_2.anchor_after(14),
4134 ];
4135 assert_eq!(
4136 snapshot_3.summaries_for_anchors::<usize, _>(&anchors),
4137 &[0, 2, 9, 13]
4138 );
4139
4140 let new_anchors = snapshot_3.refresh_anchors(&anchors);
4141 assert_eq!(
4142 new_anchors.iter().map(|a| (a.0, a.2)).collect::<Vec<_>>(),
4143 &[(0, true), (1, true), (2, true), (3, true)]
4144 );
4145 assert_eq!(
4146 snapshot_3.summaries_for_anchors::<usize, _>(new_anchors.iter().map(|a| &a.1)),
4147 &[0, 2, 7, 13]
4148 );
4149 }
4150
4151 #[gpui::test(iterations = 100)]
4152 fn test_random_multibuffer(cx: &mut MutableAppContext, mut rng: StdRng) {
4153 let operations = env::var("OPERATIONS")
4154 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
4155 .unwrap_or(10);
4156
4157 let mut buffers: Vec<ModelHandle<Buffer>> = Vec::new();
4158 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4159 let mut excerpt_ids = Vec::<ExcerptId>::new();
4160 let mut expected_excerpts = Vec::<(ModelHandle<Buffer>, Range<text::Anchor>)>::new();
4161 let mut anchors = Vec::new();
4162 let mut old_versions = Vec::new();
4163
4164 for _ in 0..operations {
4165 match rng.gen_range(0..100) {
4166 0..=19 if !buffers.is_empty() => {
4167 let buffer = buffers.choose(&mut rng).unwrap();
4168 buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
4169 }
4170 20..=29 if !expected_excerpts.is_empty() => {
4171 let mut ids_to_remove = vec![];
4172 for _ in 0..rng.gen_range(1..=3) {
4173 if expected_excerpts.is_empty() {
4174 break;
4175 }
4176
4177 let ix = rng.gen_range(0..expected_excerpts.len());
4178 ids_to_remove.push(excerpt_ids.remove(ix));
4179 let (buffer, range) = expected_excerpts.remove(ix);
4180 let buffer = buffer.read(cx);
4181 log::info!(
4182 "Removing excerpt {}: {:?}",
4183 ix,
4184 buffer
4185 .text_for_range(range.to_offset(buffer))
4186 .collect::<String>(),
4187 );
4188 }
4189 let snapshot = multibuffer.read(cx).read(cx);
4190 ids_to_remove.sort_unstable_by(|a, b| a.cmp(&b, &snapshot));
4191 drop(snapshot);
4192 multibuffer.update(cx, |multibuffer, cx| {
4193 multibuffer.remove_excerpts(ids_to_remove, cx)
4194 });
4195 }
4196 30..=39 if !expected_excerpts.is_empty() => {
4197 let multibuffer = multibuffer.read(cx).read(cx);
4198 let offset =
4199 multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left);
4200 let bias = if rng.gen() { Bias::Left } else { Bias::Right };
4201 log::info!("Creating anchor at {} with bias {:?}", offset, bias);
4202 anchors.push(multibuffer.anchor_at(offset, bias));
4203 anchors.sort_by(|a, b| a.cmp(b, &multibuffer));
4204 }
4205 40..=44 if !anchors.is_empty() => {
4206 let multibuffer = multibuffer.read(cx).read(cx);
4207 let prev_len = anchors.len();
4208 anchors = multibuffer
4209 .refresh_anchors(&anchors)
4210 .into_iter()
4211 .map(|a| a.1)
4212 .collect();
4213
4214 // Ensure the newly-refreshed anchors point to a valid excerpt and don't
4215 // overshoot its boundaries.
4216 assert_eq!(anchors.len(), prev_len);
4217 for anchor in &anchors {
4218 if anchor.excerpt_id == ExcerptId::min()
4219 || anchor.excerpt_id == ExcerptId::max()
4220 {
4221 continue;
4222 }
4223
4224 let excerpt = multibuffer.excerpt(anchor.excerpt_id).unwrap();
4225 assert_eq!(excerpt.id, anchor.excerpt_id);
4226 assert!(excerpt.contains(anchor));
4227 }
4228 }
4229 _ => {
4230 let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
4231 let base_text = util::RandomCharIter::new(&mut rng)
4232 .take(10)
4233 .collect::<String>();
4234 buffers.push(cx.add_model(|cx| Buffer::new(0, base_text, cx)));
4235 buffers.last().unwrap()
4236 } else {
4237 buffers.choose(&mut rng).unwrap()
4238 };
4239
4240 let buffer = buffer_handle.read(cx);
4241 let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
4242 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
4243 let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
4244 let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len());
4245 let prev_excerpt_id = excerpt_ids
4246 .get(prev_excerpt_ix)
4247 .cloned()
4248 .unwrap_or_else(ExcerptId::max);
4249 let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len());
4250
4251 log::info!(
4252 "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}",
4253 excerpt_ix,
4254 expected_excerpts.len(),
4255 buffer_handle.id(),
4256 buffer.text(),
4257 start_ix..end_ix,
4258 &buffer.text()[start_ix..end_ix]
4259 );
4260
4261 let excerpt_id = multibuffer.update(cx, |multibuffer, cx| {
4262 multibuffer
4263 .insert_excerpts_after(
4264 prev_excerpt_id,
4265 buffer_handle.clone(),
4266 [ExcerptRange {
4267 context: start_ix..end_ix,
4268 primary: None,
4269 }],
4270 cx,
4271 )
4272 .pop()
4273 .unwrap()
4274 });
4275
4276 excerpt_ids.insert(excerpt_ix, excerpt_id);
4277 expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range));
4278 }
4279 }
4280
4281 if rng.gen_bool(0.3) {
4282 multibuffer.update(cx, |multibuffer, cx| {
4283 old_versions.push((multibuffer.snapshot(cx), multibuffer.subscribe()));
4284 })
4285 }
4286
4287 let snapshot = multibuffer.read(cx).snapshot(cx);
4288
4289 let mut excerpt_starts = Vec::new();
4290 let mut expected_text = String::new();
4291 let mut expected_buffer_rows = Vec::new();
4292 for (buffer, range) in &expected_excerpts {
4293 let buffer = buffer.read(cx);
4294 let buffer_range = range.to_offset(buffer);
4295
4296 excerpt_starts.push(TextSummary::from(expected_text.as_str()));
4297 expected_text.extend(buffer.text_for_range(buffer_range.clone()));
4298 expected_text.push('\n');
4299
4300 let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
4301 ..=buffer.offset_to_point(buffer_range.end).row;
4302 for row in buffer_row_range {
4303 expected_buffer_rows.push(Some(row));
4304 }
4305 }
4306 // Remove final trailing newline.
4307 if !expected_excerpts.is_empty() {
4308 expected_text.pop();
4309 }
4310
4311 // Always report one buffer row
4312 if expected_buffer_rows.is_empty() {
4313 expected_buffer_rows.push(Some(0));
4314 }
4315
4316 assert_eq!(snapshot.text(), expected_text);
4317 log::info!("MultiBuffer text: {:?}", expected_text);
4318
4319 assert_eq!(
4320 snapshot.buffer_rows(0).collect::<Vec<_>>(),
4321 expected_buffer_rows,
4322 );
4323
4324 for _ in 0..5 {
4325 let start_row = rng.gen_range(0..=expected_buffer_rows.len());
4326 assert_eq!(
4327 snapshot.buffer_rows(start_row as u32).collect::<Vec<_>>(),
4328 &expected_buffer_rows[start_row..],
4329 "buffer_rows({})",
4330 start_row
4331 );
4332 }
4333
4334 assert_eq!(
4335 snapshot.max_buffer_row(),
4336 expected_buffer_rows.into_iter().flatten().max().unwrap()
4337 );
4338
4339 let mut excerpt_starts = excerpt_starts.into_iter();
4340 for (buffer, range) in &expected_excerpts {
4341 let buffer_id = buffer.id();
4342 let buffer = buffer.read(cx);
4343 let buffer_range = range.to_offset(buffer);
4344 let buffer_start_point = buffer.offset_to_point(buffer_range.start);
4345 let buffer_start_point_utf16 =
4346 buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
4347
4348 let excerpt_start = excerpt_starts.next().unwrap();
4349 let mut offset = excerpt_start.len;
4350 let mut buffer_offset = buffer_range.start;
4351 let mut point = excerpt_start.lines;
4352 let mut buffer_point = buffer_start_point;
4353 let mut point_utf16 = excerpt_start.lines_utf16();
4354 let mut buffer_point_utf16 = buffer_start_point_utf16;
4355 for ch in buffer
4356 .snapshot()
4357 .chunks(buffer_range.clone(), false)
4358 .flat_map(|c| c.text.chars())
4359 {
4360 for _ in 0..ch.len_utf8() {
4361 let left_offset = snapshot.clip_offset(offset, Bias::Left);
4362 let right_offset = snapshot.clip_offset(offset, Bias::Right);
4363 let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
4364 let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
4365 assert_eq!(
4366 left_offset,
4367 excerpt_start.len + (buffer_left_offset - buffer_range.start),
4368 "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
4369 offset,
4370 buffer_id,
4371 buffer_offset,
4372 );
4373 assert_eq!(
4374 right_offset,
4375 excerpt_start.len + (buffer_right_offset - buffer_range.start),
4376 "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
4377 offset,
4378 buffer_id,
4379 buffer_offset,
4380 );
4381
4382 let left_point = snapshot.clip_point(point, Bias::Left);
4383 let right_point = snapshot.clip_point(point, Bias::Right);
4384 let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
4385 let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
4386 assert_eq!(
4387 left_point,
4388 excerpt_start.lines + (buffer_left_point - buffer_start_point),
4389 "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
4390 point,
4391 buffer_id,
4392 buffer_point,
4393 );
4394 assert_eq!(
4395 right_point,
4396 excerpt_start.lines + (buffer_right_point - buffer_start_point),
4397 "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
4398 point,
4399 buffer_id,
4400 buffer_point,
4401 );
4402
4403 assert_eq!(
4404 snapshot.point_to_offset(left_point),
4405 left_offset,
4406 "point_to_offset({:?})",
4407 left_point,
4408 );
4409 assert_eq!(
4410 snapshot.offset_to_point(left_offset),
4411 left_point,
4412 "offset_to_point({:?})",
4413 left_offset,
4414 );
4415
4416 offset += 1;
4417 buffer_offset += 1;
4418 if ch == '\n' {
4419 point += Point::new(1, 0);
4420 buffer_point += Point::new(1, 0);
4421 } else {
4422 point += Point::new(0, 1);
4423 buffer_point += Point::new(0, 1);
4424 }
4425 }
4426
4427 for _ in 0..ch.len_utf16() {
4428 let left_point_utf16 =
4429 snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Left);
4430 let right_point_utf16 =
4431 snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Right);
4432 let buffer_left_point_utf16 =
4433 buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Left);
4434 let buffer_right_point_utf16 =
4435 buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Right);
4436 assert_eq!(
4437 left_point_utf16,
4438 excerpt_start.lines_utf16()
4439 + (buffer_left_point_utf16 - buffer_start_point_utf16),
4440 "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
4441 point_utf16,
4442 buffer_id,
4443 buffer_point_utf16,
4444 );
4445 assert_eq!(
4446 right_point_utf16,
4447 excerpt_start.lines_utf16()
4448 + (buffer_right_point_utf16 - buffer_start_point_utf16),
4449 "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
4450 point_utf16,
4451 buffer_id,
4452 buffer_point_utf16,
4453 );
4454
4455 if ch == '\n' {
4456 point_utf16 += PointUtf16::new(1, 0);
4457 buffer_point_utf16 += PointUtf16::new(1, 0);
4458 } else {
4459 point_utf16 += PointUtf16::new(0, 1);
4460 buffer_point_utf16 += PointUtf16::new(0, 1);
4461 }
4462 }
4463 }
4464 }
4465
4466 for (row, line) in expected_text.split('\n').enumerate() {
4467 assert_eq!(
4468 snapshot.line_len(row as u32),
4469 line.len() as u32,
4470 "line_len({}).",
4471 row
4472 );
4473 }
4474
4475 let text_rope = Rope::from(expected_text.as_str());
4476 for _ in 0..10 {
4477 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
4478 let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
4479
4480 let text_for_range = snapshot
4481 .text_for_range(start_ix..end_ix)
4482 .collect::<String>();
4483 assert_eq!(
4484 text_for_range,
4485 &expected_text[start_ix..end_ix],
4486 "incorrect text for range {:?}",
4487 start_ix..end_ix
4488 );
4489
4490 let excerpted_buffer_ranges = multibuffer
4491 .read(cx)
4492 .range_to_buffer_ranges(start_ix..end_ix, cx);
4493 let excerpted_buffers_text = excerpted_buffer_ranges
4494 .into_iter()
4495 .map(|(buffer, buffer_range)| {
4496 buffer
4497 .read(cx)
4498 .text_for_range(buffer_range)
4499 .collect::<String>()
4500 })
4501 .collect::<Vec<_>>()
4502 .join("\n");
4503 assert_eq!(excerpted_buffers_text, text_for_range);
4504
4505 let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
4506 assert_eq!(
4507 snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
4508 expected_summary,
4509 "incorrect summary for range {:?}",
4510 start_ix..end_ix
4511 );
4512 }
4513
4514 // Anchor resolution
4515 let summaries = snapshot.summaries_for_anchors::<usize, _>(&anchors);
4516 assert_eq!(anchors.len(), summaries.len());
4517 for (anchor, resolved_offset) in anchors.iter().zip(summaries) {
4518 assert!(resolved_offset <= snapshot.len());
4519 assert_eq!(
4520 snapshot.summary_for_anchor::<usize>(anchor),
4521 resolved_offset
4522 );
4523 }
4524
4525 for _ in 0..10 {
4526 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
4527 assert_eq!(
4528 snapshot.reversed_chars_at(end_ix).collect::<String>(),
4529 expected_text[..end_ix].chars().rev().collect::<String>(),
4530 );
4531 }
4532
4533 for _ in 0..10 {
4534 let end_ix = rng.gen_range(0..=text_rope.len());
4535 let start_ix = rng.gen_range(0..=end_ix);
4536 assert_eq!(
4537 snapshot
4538 .bytes_in_range(start_ix..end_ix)
4539 .flatten()
4540 .copied()
4541 .collect::<Vec<_>>(),
4542 expected_text.as_bytes()[start_ix..end_ix].to_vec(),
4543 "bytes_in_range({:?})",
4544 start_ix..end_ix,
4545 );
4546 }
4547 }
4548
4549 let snapshot = multibuffer.read(cx).snapshot(cx);
4550 for (old_snapshot, subscription) in old_versions {
4551 let edits = subscription.consume().into_inner();
4552
4553 log::info!(
4554 "applying subscription edits to old text: {:?}: {:?}",
4555 old_snapshot.text(),
4556 edits,
4557 );
4558
4559 let mut text = old_snapshot.text();
4560 for edit in edits {
4561 let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
4562 text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
4563 }
4564 assert_eq!(text.to_string(), snapshot.text());
4565 }
4566 }
4567
4568 #[gpui::test]
4569 fn test_history(cx: &mut MutableAppContext) {
4570 cx.set_global(Settings::test(cx));
4571 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "1234", cx));
4572 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "5678", cx));
4573 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4574 let group_interval = multibuffer.read(cx).history.group_interval;
4575 multibuffer.update(cx, |multibuffer, cx| {
4576 multibuffer.push_excerpts(
4577 buffer_1.clone(),
4578 [ExcerptRange {
4579 context: 0..buffer_1.read(cx).len(),
4580 primary: None,
4581 }],
4582 cx,
4583 );
4584 multibuffer.push_excerpts(
4585 buffer_2.clone(),
4586 [ExcerptRange {
4587 context: 0..buffer_2.read(cx).len(),
4588 primary: None,
4589 }],
4590 cx,
4591 );
4592 });
4593
4594 let mut now = Instant::now();
4595
4596 multibuffer.update(cx, |multibuffer, cx| {
4597 let transaction_1 = multibuffer.start_transaction_at(now, cx).unwrap();
4598 multibuffer.edit(
4599 [
4600 (Point::new(0, 0)..Point::new(0, 0), "A"),
4601 (Point::new(1, 0)..Point::new(1, 0), "A"),
4602 ],
4603 None,
4604 cx,
4605 );
4606 multibuffer.edit(
4607 [
4608 (Point::new(0, 1)..Point::new(0, 1), "B"),
4609 (Point::new(1, 1)..Point::new(1, 1), "B"),
4610 ],
4611 None,
4612 cx,
4613 );
4614 multibuffer.end_transaction_at(now, cx);
4615 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
4616
4617 // Edit buffer 1 through the multibuffer
4618 now += 2 * group_interval;
4619 multibuffer.start_transaction_at(now, cx);
4620 multibuffer.edit([(2..2, "C")], None, cx);
4621 multibuffer.end_transaction_at(now, cx);
4622 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
4623
4624 // Edit buffer 1 independently
4625 buffer_1.update(cx, |buffer_1, cx| {
4626 buffer_1.start_transaction_at(now);
4627 buffer_1.edit([(3..3, "D")], None, cx);
4628 buffer_1.end_transaction_at(now, cx);
4629
4630 now += 2 * group_interval;
4631 buffer_1.start_transaction_at(now);
4632 buffer_1.edit([(4..4, "E")], None, cx);
4633 buffer_1.end_transaction_at(now, cx);
4634 });
4635 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
4636
4637 // An undo in the multibuffer undoes the multibuffer transaction
4638 // and also any individual buffer edits that have occured since
4639 // that transaction.
4640 multibuffer.undo(cx);
4641 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
4642
4643 multibuffer.undo(cx);
4644 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
4645
4646 multibuffer.redo(cx);
4647 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
4648
4649 multibuffer.redo(cx);
4650 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
4651
4652 // Undo buffer 2 independently.
4653 buffer_2.update(cx, |buffer_2, cx| buffer_2.undo(cx));
4654 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\n5678");
4655
4656 // An undo in the multibuffer undoes the components of the
4657 // the last multibuffer transaction that are not already undone.
4658 multibuffer.undo(cx);
4659 assert_eq!(multibuffer.read(cx).text(), "AB1234\n5678");
4660
4661 multibuffer.undo(cx);
4662 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
4663
4664 multibuffer.redo(cx);
4665 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
4666
4667 buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
4668 assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
4669
4670 // Redo stack gets cleared after an edit.
4671 now += 2 * group_interval;
4672 multibuffer.start_transaction_at(now, cx);
4673 multibuffer.edit([(0..0, "X")], None, cx);
4674 multibuffer.end_transaction_at(now, cx);
4675 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
4676 multibuffer.redo(cx);
4677 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
4678 multibuffer.undo(cx);
4679 assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
4680 multibuffer.undo(cx);
4681 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
4682
4683 // Transactions can be grouped manually.
4684 multibuffer.redo(cx);
4685 multibuffer.redo(cx);
4686 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
4687 multibuffer.group_until_transaction(transaction_1, cx);
4688 multibuffer.undo(cx);
4689 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
4690 multibuffer.redo(cx);
4691 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
4692 });
4693 }
4694}