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