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 /// Returns the smallest enclosing bracket ranges containing the given range or
2634 /// None if no brackets contain range or the range is not contained in a single
2635 /// excerpt
2636 pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
2637 &self,
2638 range: Range<T>,
2639 ) -> Option<(Range<usize>, Range<usize>)> {
2640 let range = range.start.to_offset(self)..range.end.to_offset(self);
2641
2642 // Get the ranges of the innermost pair of brackets.
2643 let mut result: Option<(Range<usize>, Range<usize>)> = None;
2644
2645 let Some(enclosing_bracket_ranges) = self.enclosing_bracket_ranges(range.clone()) else { return None; };
2646
2647 for (open, close) in enclosing_bracket_ranges {
2648 let len = close.end - open.start;
2649
2650 if let Some((existing_open, existing_close)) = &result {
2651 let existing_len = existing_close.end - existing_open.start;
2652 if len > existing_len {
2653 continue;
2654 }
2655 }
2656
2657 result = Some((open, close));
2658 }
2659
2660 result
2661 }
2662
2663 /// Returns enclosing bracket ranges containing the given range or returns None if the range is
2664 /// not contained in a single excerpt
2665 pub fn enclosing_bracket_ranges<'a, T: ToOffset>(
2666 &'a self,
2667 range: Range<T>,
2668 ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + 'a> {
2669 let range = range.start.to_offset(self)..range.end.to_offset(self);
2670
2671 self.bracket_ranges(range.clone()).map(|range_pairs| {
2672 range_pairs
2673 .filter(move |(open, close)| open.start <= range.start && close.end >= range.end)
2674 })
2675 }
2676
2677 /// Returns bracket range pairs overlapping the given `range` or returns None if the `range` is
2678 /// not contained in a single excerpt
2679 pub fn bracket_ranges<'a, T: ToOffset>(
2680 &'a self,
2681 range: Range<T>,
2682 ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + 'a> {
2683 let range = range.start.to_offset(self)..range.end.to_offset(self);
2684 let excerpt = self.excerpt_containing(range.clone());
2685 excerpt.map(|(excerpt, excerpt_offset)| {
2686 let excerpt_buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2687 let excerpt_buffer_end = excerpt_buffer_start + excerpt.text_summary.len;
2688
2689 let start_in_buffer = excerpt_buffer_start + range.start.saturating_sub(excerpt_offset);
2690 let end_in_buffer = excerpt_buffer_start + range.end.saturating_sub(excerpt_offset);
2691
2692 excerpt
2693 .buffer
2694 .bracket_ranges(start_in_buffer..end_in_buffer)
2695 .filter_map(move |(start_bracket_range, end_bracket_range)| {
2696 if start_bracket_range.start < excerpt_buffer_start
2697 || end_bracket_range.end > excerpt_buffer_end
2698 {
2699 return None;
2700 }
2701
2702 let mut start_bracket_range = start_bracket_range.clone();
2703 start_bracket_range.start =
2704 excerpt_offset + (start_bracket_range.start - excerpt_buffer_start);
2705 start_bracket_range.end =
2706 excerpt_offset + (start_bracket_range.end - excerpt_buffer_start);
2707
2708 let mut end_bracket_range = end_bracket_range.clone();
2709 end_bracket_range.start =
2710 excerpt_offset + (end_bracket_range.start - excerpt_buffer_start);
2711 end_bracket_range.end =
2712 excerpt_offset + (end_bracket_range.end - excerpt_buffer_start);
2713 Some((start_bracket_range, end_bracket_range))
2714 })
2715 })
2716 }
2717
2718 pub fn diagnostics_update_count(&self) -> usize {
2719 self.diagnostics_update_count
2720 }
2721
2722 pub fn git_diff_update_count(&self) -> usize {
2723 self.git_diff_update_count
2724 }
2725
2726 pub fn trailing_excerpt_update_count(&self) -> usize {
2727 self.trailing_excerpt_update_count
2728 }
2729
2730 pub fn language_at<'a, T: ToOffset>(&'a self, point: T) -> Option<&'a Arc<Language>> {
2731 self.point_to_buffer_offset(point)
2732 .and_then(|(buffer, offset)| buffer.language_at(offset))
2733 }
2734
2735 pub fn language_scope_at<'a, T: ToOffset>(&'a self, point: T) -> Option<LanguageScope> {
2736 self.point_to_buffer_offset(point)
2737 .and_then(|(buffer, offset)| buffer.language_scope_at(offset))
2738 }
2739
2740 pub fn is_dirty(&self) -> bool {
2741 self.is_dirty
2742 }
2743
2744 pub fn has_conflict(&self) -> bool {
2745 self.has_conflict
2746 }
2747
2748 pub fn diagnostic_group<'a, O>(
2749 &'a self,
2750 group_id: usize,
2751 ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
2752 where
2753 O: text::FromAnchor + 'a,
2754 {
2755 self.as_singleton()
2756 .into_iter()
2757 .flat_map(move |(_, _, buffer)| buffer.diagnostic_group(group_id))
2758 }
2759
2760 pub fn diagnostics_in_range<'a, T, O>(
2761 &'a self,
2762 range: Range<T>,
2763 reversed: bool,
2764 ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
2765 where
2766 T: 'a + ToOffset,
2767 O: 'a + text::FromAnchor,
2768 {
2769 self.as_singleton()
2770 .into_iter()
2771 .flat_map(move |(_, _, buffer)| {
2772 buffer.diagnostics_in_range(
2773 range.start.to_offset(self)..range.end.to_offset(self),
2774 reversed,
2775 )
2776 })
2777 }
2778
2779 pub fn git_diff_hunks_in_range<'a>(
2780 &'a self,
2781 row_range: Range<u32>,
2782 reversed: bool,
2783 ) -> impl 'a + Iterator<Item = DiffHunk<u32>> {
2784 let mut cursor = self.excerpts.cursor::<Point>();
2785
2786 if reversed {
2787 cursor.seek(&Point::new(row_range.end, 0), Bias::Left, &());
2788 if cursor.item().is_none() {
2789 cursor.prev(&());
2790 }
2791 } else {
2792 cursor.seek(&Point::new(row_range.start, 0), Bias::Right, &());
2793 }
2794
2795 std::iter::from_fn(move || {
2796 let excerpt = cursor.item()?;
2797 let multibuffer_start = *cursor.start();
2798 let multibuffer_end = multibuffer_start + excerpt.text_summary.lines;
2799 if multibuffer_start.row >= row_range.end {
2800 return None;
2801 }
2802
2803 let mut buffer_start = excerpt.range.context.start;
2804 let mut buffer_end = excerpt.range.context.end;
2805 let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
2806 let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
2807
2808 if row_range.start > multibuffer_start.row {
2809 let buffer_start_point =
2810 excerpt_start_point + Point::new(row_range.start - multibuffer_start.row, 0);
2811 buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
2812 }
2813
2814 if row_range.end < multibuffer_end.row {
2815 let buffer_end_point =
2816 excerpt_start_point + Point::new(row_range.end - multibuffer_start.row, 0);
2817 buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
2818 }
2819
2820 let buffer_hunks = excerpt
2821 .buffer
2822 .git_diff_hunks_intersecting_range(buffer_start..buffer_end, reversed)
2823 .filter_map(move |hunk| {
2824 let start = multibuffer_start.row
2825 + hunk
2826 .buffer_range
2827 .start
2828 .saturating_sub(excerpt_start_point.row);
2829 let end = multibuffer_start.row
2830 + hunk
2831 .buffer_range
2832 .end
2833 .min(excerpt_end_point.row + 1)
2834 .saturating_sub(excerpt_start_point.row);
2835
2836 Some(DiffHunk {
2837 buffer_range: start..end,
2838 diff_base_byte_range: hunk.diff_base_byte_range.clone(),
2839 })
2840 });
2841
2842 if reversed {
2843 cursor.prev(&());
2844 } else {
2845 cursor.next(&());
2846 }
2847
2848 Some(buffer_hunks)
2849 })
2850 .flatten()
2851 }
2852
2853 pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
2854 let range = range.start.to_offset(self)..range.end.to_offset(self);
2855
2856 self.excerpt_containing(range.clone())
2857 .and_then(|(excerpt, excerpt_offset)| {
2858 let excerpt_buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2859 let excerpt_buffer_end = excerpt_buffer_start + excerpt.text_summary.len;
2860
2861 let start_in_buffer =
2862 excerpt_buffer_start + range.start.saturating_sub(excerpt_offset);
2863 let end_in_buffer = excerpt_buffer_start + range.end.saturating_sub(excerpt_offset);
2864 let mut ancestor_buffer_range = excerpt
2865 .buffer
2866 .range_for_syntax_ancestor(start_in_buffer..end_in_buffer)?;
2867 ancestor_buffer_range.start =
2868 cmp::max(ancestor_buffer_range.start, excerpt_buffer_start);
2869 ancestor_buffer_range.end = cmp::min(ancestor_buffer_range.end, excerpt_buffer_end);
2870
2871 let start = excerpt_offset + (ancestor_buffer_range.start - excerpt_buffer_start);
2872 let end = excerpt_offset + (ancestor_buffer_range.end - excerpt_buffer_start);
2873 Some(start..end)
2874 })
2875 }
2876
2877 pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
2878 let (excerpt_id, _, buffer) = self.as_singleton()?;
2879 let outline = buffer.outline(theme)?;
2880 Some(Outline::new(
2881 outline
2882 .items
2883 .into_iter()
2884 .map(|item| OutlineItem {
2885 depth: item.depth,
2886 range: self.anchor_in_excerpt(excerpt_id.clone(), item.range.start)
2887 ..self.anchor_in_excerpt(excerpt_id.clone(), item.range.end),
2888 text: item.text,
2889 highlight_ranges: item.highlight_ranges,
2890 name_ranges: item.name_ranges,
2891 })
2892 .collect(),
2893 ))
2894 }
2895
2896 pub fn symbols_containing<T: ToOffset>(
2897 &self,
2898 offset: T,
2899 theme: Option<&SyntaxTheme>,
2900 ) -> Option<(usize, Vec<OutlineItem<Anchor>>)> {
2901 let anchor = self.anchor_before(offset);
2902 let excerpt_id = anchor.excerpt_id();
2903 let excerpt = self.excerpt(excerpt_id)?;
2904 Some((
2905 excerpt.buffer_id,
2906 excerpt
2907 .buffer
2908 .symbols_containing(anchor.text_anchor, theme)
2909 .into_iter()
2910 .flatten()
2911 .map(|item| OutlineItem {
2912 depth: item.depth,
2913 range: self.anchor_in_excerpt(excerpt_id, item.range.start)
2914 ..self.anchor_in_excerpt(excerpt_id, item.range.end),
2915 text: item.text,
2916 highlight_ranges: item.highlight_ranges,
2917 name_ranges: item.name_ranges,
2918 })
2919 .collect(),
2920 ))
2921 }
2922
2923 fn excerpt_locator_for_id<'a>(&'a self, id: ExcerptId) -> &'a Locator {
2924 if id == ExcerptId::min() {
2925 Locator::min_ref()
2926 } else if id == ExcerptId::max() {
2927 Locator::max_ref()
2928 } else {
2929 let mut cursor = self.excerpt_ids.cursor::<ExcerptId>();
2930 cursor.seek(&id, Bias::Left, &());
2931 if let Some(entry) = cursor.item() {
2932 if entry.id == id {
2933 return &entry.locator;
2934 }
2935 }
2936 panic!("invalid excerpt id {:?}", id)
2937 }
2938 }
2939
2940 pub fn buffer_id_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<usize> {
2941 Some(self.excerpt(excerpt_id)?.buffer_id)
2942 }
2943
2944 fn excerpt<'a>(&'a self, excerpt_id: ExcerptId) -> Option<&'a Excerpt> {
2945 let mut cursor = self.excerpts.cursor::<Option<&Locator>>();
2946 let locator = self.excerpt_locator_for_id(excerpt_id);
2947 cursor.seek(&Some(locator), Bias::Left, &());
2948 if let Some(excerpt) = cursor.item() {
2949 if excerpt.id == excerpt_id {
2950 return Some(excerpt);
2951 }
2952 }
2953 None
2954 }
2955
2956 /// Returns the excerpt containing range and its offset start within the multibuffer or none if `range` spans multiple excerpts
2957 fn excerpt_containing<'a, T: ToOffset>(
2958 &'a self,
2959 range: Range<T>,
2960 ) -> Option<(&'a Excerpt, usize)> {
2961 let range = range.start.to_offset(self)..range.end.to_offset(self);
2962
2963 let mut cursor = self.excerpts.cursor::<usize>();
2964 cursor.seek(&range.start, Bias::Right, &());
2965 let start_excerpt = cursor.item();
2966
2967 if range.start == range.end {
2968 return start_excerpt.map(|excerpt| (excerpt, *cursor.start()));
2969 }
2970
2971 cursor.seek(&range.end, Bias::Right, &());
2972 let end_excerpt = cursor.item();
2973
2974 start_excerpt
2975 .zip(end_excerpt)
2976 .and_then(|(start_excerpt, end_excerpt)| {
2977 if start_excerpt.id != end_excerpt.id {
2978 return None;
2979 }
2980
2981 Some((start_excerpt, *cursor.start()))
2982 })
2983 }
2984
2985 pub fn remote_selections_in_range<'a>(
2986 &'a self,
2987 range: &'a Range<Anchor>,
2988 ) -> impl 'a + Iterator<Item = (ReplicaId, bool, CursorShape, Selection<Anchor>)> {
2989 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
2990 let start_locator = self.excerpt_locator_for_id(range.start.excerpt_id);
2991 let end_locator = self.excerpt_locator_for_id(range.end.excerpt_id);
2992 cursor.seek(start_locator, Bias::Left, &());
2993 cursor
2994 .take_while(move |excerpt| excerpt.locator <= *end_locator)
2995 .flat_map(move |excerpt| {
2996 let mut query_range = excerpt.range.context.start..excerpt.range.context.end;
2997 if excerpt.id == range.start.excerpt_id {
2998 query_range.start = range.start.text_anchor;
2999 }
3000 if excerpt.id == range.end.excerpt_id {
3001 query_range.end = range.end.text_anchor;
3002 }
3003
3004 excerpt
3005 .buffer
3006 .remote_selections_in_range(query_range)
3007 .flat_map(move |(replica_id, line_mode, cursor_shape, selections)| {
3008 selections.map(move |selection| {
3009 let mut start = Anchor {
3010 buffer_id: Some(excerpt.buffer_id),
3011 excerpt_id: excerpt.id.clone(),
3012 text_anchor: selection.start,
3013 };
3014 let mut end = Anchor {
3015 buffer_id: Some(excerpt.buffer_id),
3016 excerpt_id: excerpt.id.clone(),
3017 text_anchor: selection.end,
3018 };
3019 if range.start.cmp(&start, self).is_gt() {
3020 start = range.start.clone();
3021 }
3022 if range.end.cmp(&end, self).is_lt() {
3023 end = range.end.clone();
3024 }
3025
3026 (
3027 replica_id,
3028 line_mode,
3029 cursor_shape,
3030 Selection {
3031 id: selection.id,
3032 start,
3033 end,
3034 reversed: selection.reversed,
3035 goal: selection.goal,
3036 },
3037 )
3038 })
3039 })
3040 })
3041 }
3042}
3043
3044#[cfg(any(test, feature = "test-support"))]
3045impl MultiBufferSnapshot {
3046 pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
3047 let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
3048 let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
3049 start..end
3050 }
3051}
3052
3053impl History {
3054 fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
3055 self.transaction_depth += 1;
3056 if self.transaction_depth == 1 {
3057 let id = self.next_transaction_id.tick();
3058 self.undo_stack.push(Transaction {
3059 id,
3060 buffer_transactions: Default::default(),
3061 first_edit_at: now,
3062 last_edit_at: now,
3063 suppress_grouping: false,
3064 });
3065 Some(id)
3066 } else {
3067 None
3068 }
3069 }
3070
3071 fn end_transaction(
3072 &mut self,
3073 now: Instant,
3074 buffer_transactions: HashMap<usize, TransactionId>,
3075 ) -> bool {
3076 assert_ne!(self.transaction_depth, 0);
3077 self.transaction_depth -= 1;
3078 if self.transaction_depth == 0 {
3079 if buffer_transactions.is_empty() {
3080 self.undo_stack.pop();
3081 false
3082 } else {
3083 self.redo_stack.clear();
3084 let transaction = self.undo_stack.last_mut().unwrap();
3085 transaction.last_edit_at = now;
3086 for (buffer_id, transaction_id) in buffer_transactions {
3087 transaction
3088 .buffer_transactions
3089 .entry(buffer_id)
3090 .or_insert(transaction_id);
3091 }
3092 true
3093 }
3094 } else {
3095 false
3096 }
3097 }
3098
3099 fn push_transaction<'a, T>(&mut self, buffer_transactions: T, now: Instant)
3100 where
3101 T: IntoIterator<Item = (&'a ModelHandle<Buffer>, &'a language::Transaction)>,
3102 {
3103 assert_eq!(self.transaction_depth, 0);
3104 let transaction = Transaction {
3105 id: self.next_transaction_id.tick(),
3106 buffer_transactions: buffer_transactions
3107 .into_iter()
3108 .map(|(buffer, transaction)| (buffer.id(), transaction.id))
3109 .collect(),
3110 first_edit_at: now,
3111 last_edit_at: now,
3112 suppress_grouping: false,
3113 };
3114 if !transaction.buffer_transactions.is_empty() {
3115 self.undo_stack.push(transaction);
3116 self.redo_stack.clear();
3117 }
3118 }
3119
3120 fn finalize_last_transaction(&mut self) {
3121 if let Some(transaction) = self.undo_stack.last_mut() {
3122 transaction.suppress_grouping = true;
3123 }
3124 }
3125
3126 fn pop_undo(&mut self) -> Option<&mut Transaction> {
3127 assert_eq!(self.transaction_depth, 0);
3128 if let Some(transaction) = self.undo_stack.pop() {
3129 self.redo_stack.push(transaction);
3130 self.redo_stack.last_mut()
3131 } else {
3132 None
3133 }
3134 }
3135
3136 fn pop_redo(&mut self) -> Option<&mut Transaction> {
3137 assert_eq!(self.transaction_depth, 0);
3138 if let Some(transaction) = self.redo_stack.pop() {
3139 self.undo_stack.push(transaction);
3140 self.undo_stack.last_mut()
3141 } else {
3142 None
3143 }
3144 }
3145
3146 fn group(&mut self) -> Option<TransactionId> {
3147 let mut count = 0;
3148 let mut transactions = self.undo_stack.iter();
3149 if let Some(mut transaction) = transactions.next_back() {
3150 while let Some(prev_transaction) = transactions.next_back() {
3151 if !prev_transaction.suppress_grouping
3152 && transaction.first_edit_at - prev_transaction.last_edit_at
3153 <= self.group_interval
3154 {
3155 transaction = prev_transaction;
3156 count += 1;
3157 } else {
3158 break;
3159 }
3160 }
3161 }
3162 self.group_trailing(count)
3163 }
3164
3165 fn group_until(&mut self, transaction_id: TransactionId) {
3166 let mut count = 0;
3167 for transaction in self.undo_stack.iter().rev() {
3168 if transaction.id == transaction_id {
3169 self.group_trailing(count);
3170 break;
3171 } else if transaction.suppress_grouping {
3172 break;
3173 } else {
3174 count += 1;
3175 }
3176 }
3177 }
3178
3179 fn group_trailing(&mut self, n: usize) -> Option<TransactionId> {
3180 let new_len = self.undo_stack.len() - n;
3181 let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
3182 if let Some(last_transaction) = transactions_to_keep.last_mut() {
3183 if let Some(transaction) = transactions_to_merge.last() {
3184 last_transaction.last_edit_at = transaction.last_edit_at;
3185 }
3186 for to_merge in transactions_to_merge {
3187 for (buffer_id, transaction_id) in &to_merge.buffer_transactions {
3188 last_transaction
3189 .buffer_transactions
3190 .entry(*buffer_id)
3191 .or_insert(*transaction_id);
3192 }
3193 }
3194 }
3195
3196 self.undo_stack.truncate(new_len);
3197 self.undo_stack.last().map(|t| t.id)
3198 }
3199}
3200
3201impl Excerpt {
3202 fn new(
3203 id: ExcerptId,
3204 locator: Locator,
3205 buffer_id: usize,
3206 buffer: BufferSnapshot,
3207 range: ExcerptRange<text::Anchor>,
3208 has_trailing_newline: bool,
3209 ) -> Self {
3210 Excerpt {
3211 id,
3212 locator,
3213 max_buffer_row: range.context.end.to_point(&buffer).row,
3214 text_summary: buffer
3215 .text_summary_for_range::<TextSummary, _>(range.context.to_offset(&buffer)),
3216 buffer_id,
3217 buffer,
3218 range,
3219 has_trailing_newline,
3220 }
3221 }
3222
3223 fn chunks_in_range(&self, range: Range<usize>, language_aware: bool) -> ExcerptChunks {
3224 let content_start = self.range.context.start.to_offset(&self.buffer);
3225 let chunks_start = content_start + range.start;
3226 let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
3227
3228 let footer_height = if self.has_trailing_newline
3229 && range.start <= self.text_summary.len
3230 && range.end > self.text_summary.len
3231 {
3232 1
3233 } else {
3234 0
3235 };
3236
3237 let content_chunks = self.buffer.chunks(chunks_start..chunks_end, language_aware);
3238
3239 ExcerptChunks {
3240 content_chunks,
3241 footer_height,
3242 }
3243 }
3244
3245 fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
3246 let content_start = self.range.context.start.to_offset(&self.buffer);
3247 let bytes_start = content_start + range.start;
3248 let bytes_end = content_start + cmp::min(range.end, self.text_summary.len);
3249 let footer_height = if self.has_trailing_newline
3250 && range.start <= self.text_summary.len
3251 && range.end > self.text_summary.len
3252 {
3253 1
3254 } else {
3255 0
3256 };
3257 let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
3258
3259 ExcerptBytes {
3260 content_bytes,
3261 footer_height,
3262 }
3263 }
3264
3265 fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
3266 if text_anchor
3267 .cmp(&self.range.context.start, &self.buffer)
3268 .is_lt()
3269 {
3270 self.range.context.start
3271 } else if text_anchor
3272 .cmp(&self.range.context.end, &self.buffer)
3273 .is_gt()
3274 {
3275 self.range.context.end
3276 } else {
3277 text_anchor
3278 }
3279 }
3280
3281 fn contains(&self, anchor: &Anchor) -> bool {
3282 Some(self.buffer_id) == anchor.buffer_id
3283 && self
3284 .range
3285 .context
3286 .start
3287 .cmp(&anchor.text_anchor, &self.buffer)
3288 .is_le()
3289 && self
3290 .range
3291 .context
3292 .end
3293 .cmp(&anchor.text_anchor, &self.buffer)
3294 .is_ge()
3295 }
3296}
3297
3298impl ExcerptId {
3299 pub fn min() -> Self {
3300 Self(0)
3301 }
3302
3303 pub fn max() -> Self {
3304 Self(usize::MAX)
3305 }
3306
3307 pub fn to_proto(&self) -> u64 {
3308 self.0 as _
3309 }
3310
3311 pub fn from_proto(proto: u64) -> Self {
3312 Self(proto as _)
3313 }
3314
3315 pub fn cmp(&self, other: &Self, snapshot: &MultiBufferSnapshot) -> cmp::Ordering {
3316 let a = snapshot.excerpt_locator_for_id(*self);
3317 let b = snapshot.excerpt_locator_for_id(*other);
3318 a.cmp(&b).then_with(|| self.0.cmp(&other.0))
3319 }
3320}
3321
3322impl Into<usize> for ExcerptId {
3323 fn into(self) -> usize {
3324 self.0
3325 }
3326}
3327
3328impl fmt::Debug for Excerpt {
3329 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3330 f.debug_struct("Excerpt")
3331 .field("id", &self.id)
3332 .field("locator", &self.locator)
3333 .field("buffer_id", &self.buffer_id)
3334 .field("range", &self.range)
3335 .field("text_summary", &self.text_summary)
3336 .field("has_trailing_newline", &self.has_trailing_newline)
3337 .finish()
3338 }
3339}
3340
3341impl sum_tree::Item for Excerpt {
3342 type Summary = ExcerptSummary;
3343
3344 fn summary(&self) -> Self::Summary {
3345 let mut text = self.text_summary.clone();
3346 if self.has_trailing_newline {
3347 text += TextSummary::from("\n");
3348 }
3349 ExcerptSummary {
3350 excerpt_id: self.id,
3351 excerpt_locator: self.locator.clone(),
3352 max_buffer_row: self.max_buffer_row,
3353 text,
3354 }
3355 }
3356}
3357
3358impl sum_tree::Item for ExcerptIdMapping {
3359 type Summary = ExcerptId;
3360
3361 fn summary(&self) -> Self::Summary {
3362 self.id
3363 }
3364}
3365
3366impl sum_tree::KeyedItem for ExcerptIdMapping {
3367 type Key = ExcerptId;
3368
3369 fn key(&self) -> Self::Key {
3370 self.id
3371 }
3372}
3373
3374impl sum_tree::Summary for ExcerptId {
3375 type Context = ();
3376
3377 fn add_summary(&mut self, other: &Self, _: &()) {
3378 *self = *other;
3379 }
3380}
3381
3382impl sum_tree::Summary for ExcerptSummary {
3383 type Context = ();
3384
3385 fn add_summary(&mut self, summary: &Self, _: &()) {
3386 debug_assert!(summary.excerpt_locator > self.excerpt_locator);
3387 self.excerpt_locator = summary.excerpt_locator.clone();
3388 self.text.add_summary(&summary.text, &());
3389 self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row);
3390 }
3391}
3392
3393impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
3394 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3395 *self += &summary.text;
3396 }
3397}
3398
3399impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
3400 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3401 *self += summary.text.len;
3402 }
3403}
3404
3405impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
3406 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
3407 Ord::cmp(self, &cursor_location.text.len)
3408 }
3409}
3410
3411impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, Option<&'a Locator>> for Locator {
3412 fn cmp(&self, cursor_location: &Option<&'a Locator>, _: &()) -> cmp::Ordering {
3413 Ord::cmp(&Some(self), cursor_location)
3414 }
3415}
3416
3417impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Locator {
3418 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
3419 Ord::cmp(self, &cursor_location.excerpt_locator)
3420 }
3421}
3422
3423impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for OffsetUtf16 {
3424 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3425 *self += summary.text.len_utf16;
3426 }
3427}
3428
3429impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
3430 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3431 *self += summary.text.lines;
3432 }
3433}
3434
3435impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
3436 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3437 *self += summary.text.lines_utf16()
3438 }
3439}
3440
3441impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a Locator> {
3442 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3443 *self = Some(&summary.excerpt_locator);
3444 }
3445}
3446
3447impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<ExcerptId> {
3448 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
3449 *self = Some(summary.excerpt_id);
3450 }
3451}
3452
3453impl<'a> MultiBufferRows<'a> {
3454 pub fn seek(&mut self, row: u32) {
3455 self.buffer_row_range = 0..0;
3456
3457 self.excerpts
3458 .seek_forward(&Point::new(row, 0), Bias::Right, &());
3459 if self.excerpts.item().is_none() {
3460 self.excerpts.prev(&());
3461
3462 if self.excerpts.item().is_none() && row == 0 {
3463 self.buffer_row_range = 0..1;
3464 return;
3465 }
3466 }
3467
3468 if let Some(excerpt) = self.excerpts.item() {
3469 let overshoot = row - self.excerpts.start().row;
3470 let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
3471 self.buffer_row_range.start = excerpt_start + overshoot;
3472 self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
3473 }
3474 }
3475}
3476
3477impl<'a> Iterator for MultiBufferRows<'a> {
3478 type Item = Option<u32>;
3479
3480 fn next(&mut self) -> Option<Self::Item> {
3481 loop {
3482 if !self.buffer_row_range.is_empty() {
3483 let row = Some(self.buffer_row_range.start);
3484 self.buffer_row_range.start += 1;
3485 return Some(row);
3486 }
3487 self.excerpts.item()?;
3488 self.excerpts.next(&());
3489 let excerpt = self.excerpts.item()?;
3490 self.buffer_row_range.start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
3491 self.buffer_row_range.end =
3492 self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
3493 }
3494 }
3495}
3496
3497impl<'a> MultiBufferChunks<'a> {
3498 pub fn offset(&self) -> usize {
3499 self.range.start
3500 }
3501
3502 pub fn seek(&mut self, offset: usize) {
3503 self.range.start = offset;
3504 self.excerpts.seek(&offset, Bias::Right, &());
3505 if let Some(excerpt) = self.excerpts.item() {
3506 self.excerpt_chunks = Some(excerpt.chunks_in_range(
3507 self.range.start - self.excerpts.start()..self.range.end - self.excerpts.start(),
3508 self.language_aware,
3509 ));
3510 } else {
3511 self.excerpt_chunks = None;
3512 }
3513 }
3514}
3515
3516impl<'a> Iterator for MultiBufferChunks<'a> {
3517 type Item = Chunk<'a>;
3518
3519 fn next(&mut self) -> Option<Self::Item> {
3520 if self.range.is_empty() {
3521 None
3522 } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
3523 self.range.start += chunk.text.len();
3524 Some(chunk)
3525 } else {
3526 self.excerpts.next(&());
3527 let excerpt = self.excerpts.item()?;
3528 self.excerpt_chunks = Some(excerpt.chunks_in_range(
3529 0..self.range.end - self.excerpts.start(),
3530 self.language_aware,
3531 ));
3532 self.next()
3533 }
3534 }
3535}
3536
3537impl<'a> MultiBufferBytes<'a> {
3538 fn consume(&mut self, len: usize) {
3539 self.range.start += len;
3540 self.chunk = &self.chunk[len..];
3541
3542 if !self.range.is_empty() && self.chunk.is_empty() {
3543 if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
3544 self.chunk = chunk;
3545 } else {
3546 self.excerpts.next(&());
3547 if let Some(excerpt) = self.excerpts.item() {
3548 let mut excerpt_bytes =
3549 excerpt.bytes_in_range(0..self.range.end - self.excerpts.start());
3550 self.chunk = excerpt_bytes.next().unwrap();
3551 self.excerpt_bytes = Some(excerpt_bytes);
3552 }
3553 }
3554 }
3555 }
3556}
3557
3558impl<'a> Iterator for MultiBufferBytes<'a> {
3559 type Item = &'a [u8];
3560
3561 fn next(&mut self) -> Option<Self::Item> {
3562 let chunk = self.chunk;
3563 if chunk.is_empty() {
3564 None
3565 } else {
3566 self.consume(chunk.len());
3567 Some(chunk)
3568 }
3569 }
3570}
3571
3572impl<'a> io::Read for MultiBufferBytes<'a> {
3573 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
3574 let len = cmp::min(buf.len(), self.chunk.len());
3575 buf[..len].copy_from_slice(&self.chunk[..len]);
3576 if len > 0 {
3577 self.consume(len);
3578 }
3579 Ok(len)
3580 }
3581}
3582
3583impl<'a> Iterator for ExcerptBytes<'a> {
3584 type Item = &'a [u8];
3585
3586 fn next(&mut self) -> Option<Self::Item> {
3587 if let Some(chunk) = self.content_bytes.next() {
3588 if !chunk.is_empty() {
3589 return Some(chunk);
3590 }
3591 }
3592
3593 if self.footer_height > 0 {
3594 let result = &NEWLINES[..self.footer_height];
3595 self.footer_height = 0;
3596 return Some(result);
3597 }
3598
3599 None
3600 }
3601}
3602
3603impl<'a> Iterator for ExcerptChunks<'a> {
3604 type Item = Chunk<'a>;
3605
3606 fn next(&mut self) -> Option<Self::Item> {
3607 if let Some(chunk) = self.content_chunks.next() {
3608 return Some(chunk);
3609 }
3610
3611 if self.footer_height > 0 {
3612 let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
3613 self.footer_height = 0;
3614 return Some(Chunk {
3615 text,
3616 ..Default::default()
3617 });
3618 }
3619
3620 None
3621 }
3622}
3623
3624impl ToOffset for Point {
3625 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3626 snapshot.point_to_offset(*self)
3627 }
3628}
3629
3630impl ToOffset for usize {
3631 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3632 assert!(*self <= snapshot.len(), "offset is out of range");
3633 *self
3634 }
3635}
3636
3637impl ToOffset for OffsetUtf16 {
3638 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3639 snapshot.offset_utf16_to_offset(*self)
3640 }
3641}
3642
3643impl ToOffset for PointUtf16 {
3644 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
3645 snapshot.point_utf16_to_offset(*self)
3646 }
3647}
3648
3649impl ToOffsetUtf16 for OffsetUtf16 {
3650 fn to_offset_utf16(&self, _snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
3651 *self
3652 }
3653}
3654
3655impl ToOffsetUtf16 for usize {
3656 fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
3657 snapshot.offset_to_offset_utf16(*self)
3658 }
3659}
3660
3661impl ToPoint for usize {
3662 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
3663 snapshot.offset_to_point(*self)
3664 }
3665}
3666
3667impl ToPoint for Point {
3668 fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
3669 *self
3670 }
3671}
3672
3673impl ToPointUtf16 for usize {
3674 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
3675 snapshot.offset_to_point_utf16(*self)
3676 }
3677}
3678
3679impl ToPointUtf16 for Point {
3680 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
3681 snapshot.point_to_point_utf16(*self)
3682 }
3683}
3684
3685impl ToPointUtf16 for PointUtf16 {
3686 fn to_point_utf16<'a>(&self, _: &MultiBufferSnapshot) -> PointUtf16 {
3687 *self
3688 }
3689}
3690
3691fn build_excerpt_ranges<T>(
3692 buffer: &BufferSnapshot,
3693 ranges: &[Range<T>],
3694 context_line_count: u32,
3695) -> (Vec<ExcerptRange<Point>>, Vec<usize>)
3696where
3697 T: text::ToPoint,
3698{
3699 let max_point = buffer.max_point();
3700 let mut range_counts = Vec::new();
3701 let mut excerpt_ranges = Vec::new();
3702 let mut range_iter = ranges
3703 .iter()
3704 .map(|range| range.start.to_point(buffer)..range.end.to_point(buffer))
3705 .peekable();
3706 while let Some(range) = range_iter.next() {
3707 let excerpt_start = Point::new(range.start.row.saturating_sub(context_line_count), 0);
3708 let mut excerpt_end = Point::new(range.end.row + 1 + context_line_count, 0).min(max_point);
3709 let mut ranges_in_excerpt = 1;
3710
3711 while let Some(next_range) = range_iter.peek() {
3712 if next_range.start.row <= excerpt_end.row + context_line_count {
3713 excerpt_end =
3714 Point::new(next_range.end.row + 1 + context_line_count, 0).min(max_point);
3715 ranges_in_excerpt += 1;
3716 range_iter.next();
3717 } else {
3718 break;
3719 }
3720 }
3721
3722 excerpt_ranges.push(ExcerptRange {
3723 context: excerpt_start..excerpt_end,
3724 primary: Some(range),
3725 });
3726 range_counts.push(ranges_in_excerpt);
3727 }
3728
3729 (excerpt_ranges, range_counts)
3730}
3731
3732#[cfg(test)]
3733mod tests {
3734 use super::*;
3735 use futures::StreamExt;
3736 use gpui::{MutableAppContext, TestAppContext};
3737 use language::{Buffer, Rope};
3738 use rand::prelude::*;
3739 use settings::Settings;
3740 use std::{env, rc::Rc};
3741 use unindent::Unindent;
3742
3743 use util::test::sample_text;
3744
3745 #[gpui::test]
3746 fn test_singleton(cx: &mut MutableAppContext) {
3747 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
3748 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
3749
3750 let snapshot = multibuffer.read(cx).snapshot(cx);
3751 assert_eq!(snapshot.text(), buffer.read(cx).text());
3752
3753 assert_eq!(
3754 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3755 (0..buffer.read(cx).row_count())
3756 .map(Some)
3757 .collect::<Vec<_>>()
3758 );
3759
3760 buffer.update(cx, |buffer, cx| buffer.edit([(1..3, "XXX\n")], None, cx));
3761 let snapshot = multibuffer.read(cx).snapshot(cx);
3762
3763 assert_eq!(snapshot.text(), buffer.read(cx).text());
3764 assert_eq!(
3765 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3766 (0..buffer.read(cx).row_count())
3767 .map(Some)
3768 .collect::<Vec<_>>()
3769 );
3770 }
3771
3772 #[gpui::test]
3773 fn test_remote(cx: &mut MutableAppContext) {
3774 let host_buffer = cx.add_model(|cx| Buffer::new(0, "a", cx));
3775 let guest_buffer = cx.add_model(|cx| {
3776 let state = host_buffer.read(cx).to_proto();
3777 let ops = cx
3778 .background()
3779 .block(host_buffer.read(cx).serialize_ops(None, cx));
3780 let mut buffer = Buffer::from_proto(1, state, None).unwrap();
3781 buffer
3782 .apply_ops(
3783 ops.into_iter()
3784 .map(|op| language::proto::deserialize_operation(op).unwrap()),
3785 cx,
3786 )
3787 .unwrap();
3788 buffer
3789 });
3790 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(guest_buffer.clone(), cx));
3791 let snapshot = multibuffer.read(cx).snapshot(cx);
3792 assert_eq!(snapshot.text(), "a");
3793
3794 guest_buffer.update(cx, |buffer, cx| buffer.edit([(1..1, "b")], None, cx));
3795 let snapshot = multibuffer.read(cx).snapshot(cx);
3796 assert_eq!(snapshot.text(), "ab");
3797
3798 guest_buffer.update(cx, |buffer, cx| buffer.edit([(2..2, "c")], None, cx));
3799 let snapshot = multibuffer.read(cx).snapshot(cx);
3800 assert_eq!(snapshot.text(), "abc");
3801 }
3802
3803 #[gpui::test]
3804 fn test_excerpt_boundaries_and_clipping(cx: &mut MutableAppContext) {
3805 let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
3806 let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
3807 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3808
3809 let events = Rc::new(RefCell::new(Vec::<Event>::new()));
3810 multibuffer.update(cx, |_, cx| {
3811 let events = events.clone();
3812 cx.subscribe(&multibuffer, move |_, _, event, _| {
3813 if let Event::Edited = event {
3814 events.borrow_mut().push(event.clone())
3815 }
3816 })
3817 .detach();
3818 });
3819
3820 let subscription = multibuffer.update(cx, |multibuffer, cx| {
3821 let subscription = multibuffer.subscribe();
3822 multibuffer.push_excerpts(
3823 buffer_1.clone(),
3824 [ExcerptRange {
3825 context: Point::new(1, 2)..Point::new(2, 5),
3826 primary: None,
3827 }],
3828 cx,
3829 );
3830 assert_eq!(
3831 subscription.consume().into_inner(),
3832 [Edit {
3833 old: 0..0,
3834 new: 0..10
3835 }]
3836 );
3837
3838 multibuffer.push_excerpts(
3839 buffer_1.clone(),
3840 [ExcerptRange {
3841 context: Point::new(3, 3)..Point::new(4, 4),
3842 primary: None,
3843 }],
3844 cx,
3845 );
3846 multibuffer.push_excerpts(
3847 buffer_2.clone(),
3848 [ExcerptRange {
3849 context: Point::new(3, 1)..Point::new(3, 3),
3850 primary: None,
3851 }],
3852 cx,
3853 );
3854 assert_eq!(
3855 subscription.consume().into_inner(),
3856 [Edit {
3857 old: 10..10,
3858 new: 10..22
3859 }]
3860 );
3861
3862 subscription
3863 });
3864
3865 // Adding excerpts emits an edited event.
3866 assert_eq!(
3867 events.borrow().as_slice(),
3868 &[Event::Edited, Event::Edited, Event::Edited]
3869 );
3870
3871 let snapshot = multibuffer.read(cx).snapshot(cx);
3872 assert_eq!(
3873 snapshot.text(),
3874 concat!(
3875 "bbbb\n", // Preserve newlines
3876 "ccccc\n", //
3877 "ddd\n", //
3878 "eeee\n", //
3879 "jj" //
3880 )
3881 );
3882 assert_eq!(
3883 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3884 [Some(1), Some(2), Some(3), Some(4), Some(3)]
3885 );
3886 assert_eq!(
3887 snapshot.buffer_rows(2).collect::<Vec<_>>(),
3888 [Some(3), Some(4), Some(3)]
3889 );
3890 assert_eq!(snapshot.buffer_rows(4).collect::<Vec<_>>(), [Some(3)]);
3891 assert_eq!(snapshot.buffer_rows(5).collect::<Vec<_>>(), []);
3892
3893 assert_eq!(
3894 boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot),
3895 &[
3896 (0, "bbbb\nccccc".to_string(), true),
3897 (2, "ddd\neeee".to_string(), false),
3898 (4, "jj".to_string(), true),
3899 ]
3900 );
3901 assert_eq!(
3902 boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot),
3903 &[(0, "bbbb\nccccc".to_string(), true)]
3904 );
3905 assert_eq!(
3906 boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot),
3907 &[]
3908 );
3909 assert_eq!(
3910 boundaries_in_range(Point::new(1, 0)..Point::new(2, 0), &snapshot),
3911 &[]
3912 );
3913 assert_eq!(
3914 boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
3915 &[(2, "ddd\neeee".to_string(), false)]
3916 );
3917 assert_eq!(
3918 boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
3919 &[(2, "ddd\neeee".to_string(), false)]
3920 );
3921 assert_eq!(
3922 boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot),
3923 &[(2, "ddd\neeee".to_string(), false)]
3924 );
3925 assert_eq!(
3926 boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot),
3927 &[(4, "jj".to_string(), true)]
3928 );
3929 assert_eq!(
3930 boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot),
3931 &[]
3932 );
3933
3934 buffer_1.update(cx, |buffer, cx| {
3935 let text = "\n";
3936 buffer.edit(
3937 [
3938 (Point::new(0, 0)..Point::new(0, 0), text),
3939 (Point::new(2, 1)..Point::new(2, 3), text),
3940 ],
3941 None,
3942 cx,
3943 );
3944 });
3945
3946 let snapshot = multibuffer.read(cx).snapshot(cx);
3947 assert_eq!(
3948 snapshot.text(),
3949 concat!(
3950 "bbbb\n", // Preserve newlines
3951 "c\n", //
3952 "cc\n", //
3953 "ddd\n", //
3954 "eeee\n", //
3955 "jj" //
3956 )
3957 );
3958
3959 assert_eq!(
3960 subscription.consume().into_inner(),
3961 [Edit {
3962 old: 6..8,
3963 new: 6..7
3964 }]
3965 );
3966
3967 let snapshot = multibuffer.read(cx).snapshot(cx);
3968 assert_eq!(
3969 snapshot.clip_point(Point::new(0, 5), Bias::Left),
3970 Point::new(0, 4)
3971 );
3972 assert_eq!(
3973 snapshot.clip_point(Point::new(0, 5), Bias::Right),
3974 Point::new(0, 4)
3975 );
3976 assert_eq!(
3977 snapshot.clip_point(Point::new(5, 1), Bias::Right),
3978 Point::new(5, 1)
3979 );
3980 assert_eq!(
3981 snapshot.clip_point(Point::new(5, 2), Bias::Right),
3982 Point::new(5, 2)
3983 );
3984 assert_eq!(
3985 snapshot.clip_point(Point::new(5, 3), Bias::Right),
3986 Point::new(5, 2)
3987 );
3988
3989 let snapshot = multibuffer.update(cx, |multibuffer, cx| {
3990 let (buffer_2_excerpt_id, _) =
3991 multibuffer.excerpts_for_buffer(&buffer_2, cx)[0].clone();
3992 multibuffer.remove_excerpts([buffer_2_excerpt_id], cx);
3993 multibuffer.snapshot(cx)
3994 });
3995
3996 assert_eq!(
3997 snapshot.text(),
3998 concat!(
3999 "bbbb\n", // Preserve newlines
4000 "c\n", //
4001 "cc\n", //
4002 "ddd\n", //
4003 "eeee", //
4004 )
4005 );
4006
4007 fn boundaries_in_range(
4008 range: Range<Point>,
4009 snapshot: &MultiBufferSnapshot,
4010 ) -> Vec<(u32, String, bool)> {
4011 snapshot
4012 .excerpt_boundaries_in_range(range)
4013 .map(|boundary| {
4014 (
4015 boundary.row,
4016 boundary
4017 .buffer
4018 .text_for_range(boundary.range.context)
4019 .collect::<String>(),
4020 boundary.starts_new_buffer,
4021 )
4022 })
4023 .collect::<Vec<_>>()
4024 }
4025 }
4026
4027 #[gpui::test]
4028 fn test_excerpt_events(cx: &mut MutableAppContext) {
4029 let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(10, 3, 'a'), cx));
4030 let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(10, 3, 'm'), cx));
4031
4032 let leader_multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4033 let follower_multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4034
4035 follower_multibuffer.update(cx, |_, cx| {
4036 cx.subscribe(&leader_multibuffer, |follower, _, event, cx| {
4037 match event.clone() {
4038 Event::ExcerptsAdded {
4039 buffer,
4040 predecessor,
4041 excerpts,
4042 } => follower.insert_excerpts_with_ids_after(predecessor, buffer, excerpts, cx),
4043 Event::ExcerptsRemoved { ids } => follower.remove_excerpts(ids, cx),
4044 _ => {}
4045 }
4046 })
4047 .detach();
4048 });
4049
4050 leader_multibuffer.update(cx, |leader, cx| {
4051 leader.push_excerpts(
4052 buffer_1.clone(),
4053 [
4054 ExcerptRange {
4055 context: 0..8,
4056 primary: None,
4057 },
4058 ExcerptRange {
4059 context: 12..16,
4060 primary: None,
4061 },
4062 ],
4063 cx,
4064 );
4065 leader.insert_excerpts_after(
4066 leader.excerpt_ids()[0],
4067 buffer_2.clone(),
4068 [
4069 ExcerptRange {
4070 context: 0..5,
4071 primary: None,
4072 },
4073 ExcerptRange {
4074 context: 10..15,
4075 primary: None,
4076 },
4077 ],
4078 cx,
4079 )
4080 });
4081 assert_eq!(
4082 leader_multibuffer.read(cx).snapshot(cx).text(),
4083 follower_multibuffer.read(cx).snapshot(cx).text(),
4084 );
4085
4086 leader_multibuffer.update(cx, |leader, cx| {
4087 let excerpt_ids = leader.excerpt_ids();
4088 leader.remove_excerpts([excerpt_ids[1], excerpt_ids[3]], cx);
4089 });
4090 assert_eq!(
4091 leader_multibuffer.read(cx).snapshot(cx).text(),
4092 follower_multibuffer.read(cx).snapshot(cx).text(),
4093 );
4094
4095 leader_multibuffer.update(cx, |leader, cx| {
4096 leader.clear(cx);
4097 });
4098 assert_eq!(
4099 leader_multibuffer.read(cx).snapshot(cx).text(),
4100 follower_multibuffer.read(cx).snapshot(cx).text(),
4101 );
4102 }
4103
4104 #[gpui::test]
4105 fn test_push_excerpts_with_context_lines(cx: &mut MutableAppContext) {
4106 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(20, 3, 'a'), cx));
4107 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4108 let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
4109 multibuffer.push_excerpts_with_context_lines(
4110 buffer.clone(),
4111 vec![
4112 Point::new(3, 2)..Point::new(4, 2),
4113 Point::new(7, 1)..Point::new(7, 3),
4114 Point::new(15, 0)..Point::new(15, 0),
4115 ],
4116 2,
4117 cx,
4118 )
4119 });
4120
4121 let snapshot = multibuffer.read(cx).snapshot(cx);
4122 assert_eq!(
4123 snapshot.text(),
4124 "bbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\n\nnnn\nooo\nppp\nqqq\nrrr\n"
4125 );
4126
4127 assert_eq!(
4128 anchor_ranges
4129 .iter()
4130 .map(|range| range.to_point(&snapshot))
4131 .collect::<Vec<_>>(),
4132 vec![
4133 Point::new(2, 2)..Point::new(3, 2),
4134 Point::new(6, 1)..Point::new(6, 3),
4135 Point::new(12, 0)..Point::new(12, 0)
4136 ]
4137 );
4138 }
4139
4140 #[gpui::test]
4141 async fn test_stream_excerpts_with_context_lines(cx: &mut TestAppContext) {
4142 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(20, 3, 'a'), cx));
4143 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4144 let (task, anchor_ranges) = multibuffer.update(cx, |multibuffer, cx| {
4145 let snapshot = buffer.read(cx);
4146 let ranges = vec![
4147 snapshot.anchor_before(Point::new(3, 2))..snapshot.anchor_before(Point::new(4, 2)),
4148 snapshot.anchor_before(Point::new(7, 1))..snapshot.anchor_before(Point::new(7, 3)),
4149 snapshot.anchor_before(Point::new(15, 0))
4150 ..snapshot.anchor_before(Point::new(15, 0)),
4151 ];
4152 multibuffer.stream_excerpts_with_context_lines(vec![(buffer.clone(), ranges)], 2, cx)
4153 });
4154
4155 let anchor_ranges = anchor_ranges.collect::<Vec<_>>().await;
4156 // Ensure task is finished when stream completes.
4157 task.await;
4158
4159 let snapshot = multibuffer.read_with(cx, |multibuffer, cx| multibuffer.snapshot(cx));
4160 assert_eq!(
4161 snapshot.text(),
4162 "bbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\n\nnnn\nooo\nppp\nqqq\nrrr\n"
4163 );
4164
4165 assert_eq!(
4166 anchor_ranges
4167 .iter()
4168 .map(|range| range.to_point(&snapshot))
4169 .collect::<Vec<_>>(),
4170 vec![
4171 Point::new(2, 2)..Point::new(3, 2),
4172 Point::new(6, 1)..Point::new(6, 3),
4173 Point::new(12, 0)..Point::new(12, 0)
4174 ]
4175 );
4176 }
4177
4178 #[gpui::test]
4179 fn test_empty_multibuffer(cx: &mut MutableAppContext) {
4180 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4181
4182 let snapshot = multibuffer.read(cx).snapshot(cx);
4183 assert_eq!(snapshot.text(), "");
4184 assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), &[Some(0)]);
4185 assert_eq!(snapshot.buffer_rows(1).collect::<Vec<_>>(), &[]);
4186 }
4187
4188 #[gpui::test]
4189 fn test_singleton_multibuffer_anchors(cx: &mut MutableAppContext) {
4190 let buffer = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
4191 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
4192 let old_snapshot = multibuffer.read(cx).snapshot(cx);
4193 buffer.update(cx, |buffer, cx| {
4194 buffer.edit([(0..0, "X")], None, cx);
4195 buffer.edit([(5..5, "Y")], None, cx);
4196 });
4197 let new_snapshot = multibuffer.read(cx).snapshot(cx);
4198
4199 assert_eq!(old_snapshot.text(), "abcd");
4200 assert_eq!(new_snapshot.text(), "XabcdY");
4201
4202 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
4203 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
4204 assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
4205 assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
4206 }
4207
4208 #[gpui::test]
4209 fn test_multibuffer_anchors(cx: &mut MutableAppContext) {
4210 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
4211 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
4212 let multibuffer = cx.add_model(|cx| {
4213 let mut multibuffer = MultiBuffer::new(0);
4214 multibuffer.push_excerpts(
4215 buffer_1.clone(),
4216 [ExcerptRange {
4217 context: 0..4,
4218 primary: None,
4219 }],
4220 cx,
4221 );
4222 multibuffer.push_excerpts(
4223 buffer_2.clone(),
4224 [ExcerptRange {
4225 context: 0..5,
4226 primary: None,
4227 }],
4228 cx,
4229 );
4230 multibuffer
4231 });
4232 let old_snapshot = multibuffer.read(cx).snapshot(cx);
4233
4234 assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
4235 assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
4236 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
4237 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
4238 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
4239 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
4240
4241 buffer_1.update(cx, |buffer, cx| {
4242 buffer.edit([(0..0, "W")], None, cx);
4243 buffer.edit([(5..5, "X")], None, cx);
4244 });
4245 buffer_2.update(cx, |buffer, cx| {
4246 buffer.edit([(0..0, "Y")], None, cx);
4247 buffer.edit([(6..6, "Z")], None, cx);
4248 });
4249 let new_snapshot = multibuffer.read(cx).snapshot(cx);
4250
4251 assert_eq!(old_snapshot.text(), "abcd\nefghi");
4252 assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
4253
4254 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
4255 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
4256 assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
4257 assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
4258 assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
4259 assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
4260 assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
4261 assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
4262 assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
4263 assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
4264 }
4265
4266 #[gpui::test]
4267 fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut MutableAppContext) {
4268 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
4269 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "ABCDEFGHIJKLMNOP", cx));
4270 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4271
4272 // Create an insertion id in buffer 1 that doesn't exist in buffer 2.
4273 // Add an excerpt from buffer 1 that spans this new insertion.
4274 buffer_1.update(cx, |buffer, cx| buffer.edit([(4..4, "123")], None, cx));
4275 let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| {
4276 multibuffer
4277 .push_excerpts(
4278 buffer_1.clone(),
4279 [ExcerptRange {
4280 context: 0..7,
4281 primary: None,
4282 }],
4283 cx,
4284 )
4285 .pop()
4286 .unwrap()
4287 });
4288
4289 let snapshot_1 = multibuffer.read(cx).snapshot(cx);
4290 assert_eq!(snapshot_1.text(), "abcd123");
4291
4292 // Replace the buffer 1 excerpt with new excerpts from buffer 2.
4293 let (excerpt_id_2, excerpt_id_3) = multibuffer.update(cx, |multibuffer, cx| {
4294 multibuffer.remove_excerpts([excerpt_id_1], cx);
4295 let mut ids = multibuffer
4296 .push_excerpts(
4297 buffer_2.clone(),
4298 [
4299 ExcerptRange {
4300 context: 0..4,
4301 primary: None,
4302 },
4303 ExcerptRange {
4304 context: 6..10,
4305 primary: None,
4306 },
4307 ExcerptRange {
4308 context: 12..16,
4309 primary: None,
4310 },
4311 ],
4312 cx,
4313 )
4314 .into_iter();
4315 (ids.next().unwrap(), ids.next().unwrap())
4316 });
4317 let snapshot_2 = multibuffer.read(cx).snapshot(cx);
4318 assert_eq!(snapshot_2.text(), "ABCD\nGHIJ\nMNOP");
4319
4320 // The old excerpt id doesn't get reused.
4321 assert_ne!(excerpt_id_2, excerpt_id_1);
4322
4323 // Resolve some anchors from the previous snapshot in the new snapshot.
4324 // The current excerpts are from a different buffer, so we don't attempt to
4325 // resolve the old text anchor in the new buffer.
4326 assert_eq!(
4327 snapshot_2.summary_for_anchor::<usize>(&snapshot_1.anchor_before(2)),
4328 0
4329 );
4330 assert_eq!(
4331 snapshot_2.summaries_for_anchors::<usize, _>(&[
4332 snapshot_1.anchor_before(2),
4333 snapshot_1.anchor_after(3)
4334 ]),
4335 vec![0, 0]
4336 );
4337
4338 // Refresh anchors from the old snapshot. The return value indicates that both
4339 // anchors lost their original excerpt.
4340 let refresh =
4341 snapshot_2.refresh_anchors(&[snapshot_1.anchor_before(2), snapshot_1.anchor_after(3)]);
4342 assert_eq!(
4343 refresh,
4344 &[
4345 (0, snapshot_2.anchor_before(0), false),
4346 (1, snapshot_2.anchor_after(0), false),
4347 ]
4348 );
4349
4350 // Replace the middle excerpt with a smaller excerpt in buffer 2,
4351 // that intersects the old excerpt.
4352 let excerpt_id_5 = multibuffer.update(cx, |multibuffer, cx| {
4353 multibuffer.remove_excerpts([excerpt_id_3], cx);
4354 multibuffer
4355 .insert_excerpts_after(
4356 excerpt_id_2,
4357 buffer_2.clone(),
4358 [ExcerptRange {
4359 context: 5..8,
4360 primary: None,
4361 }],
4362 cx,
4363 )
4364 .pop()
4365 .unwrap()
4366 });
4367
4368 let snapshot_3 = multibuffer.read(cx).snapshot(cx);
4369 assert_eq!(snapshot_3.text(), "ABCD\nFGH\nMNOP");
4370 assert_ne!(excerpt_id_5, excerpt_id_3);
4371
4372 // Resolve some anchors from the previous snapshot in the new snapshot.
4373 // The third anchor can't be resolved, since its excerpt has been removed,
4374 // so it resolves to the same position as its predecessor.
4375 let anchors = [
4376 snapshot_2.anchor_before(0),
4377 snapshot_2.anchor_after(2),
4378 snapshot_2.anchor_after(6),
4379 snapshot_2.anchor_after(14),
4380 ];
4381 assert_eq!(
4382 snapshot_3.summaries_for_anchors::<usize, _>(&anchors),
4383 &[0, 2, 9, 13]
4384 );
4385
4386 let new_anchors = snapshot_3.refresh_anchors(&anchors);
4387 assert_eq!(
4388 new_anchors.iter().map(|a| (a.0, a.2)).collect::<Vec<_>>(),
4389 &[(0, true), (1, true), (2, true), (3, true)]
4390 );
4391 assert_eq!(
4392 snapshot_3.summaries_for_anchors::<usize, _>(new_anchors.iter().map(|a| &a.1)),
4393 &[0, 2, 7, 13]
4394 );
4395 }
4396
4397 #[gpui::test]
4398 async fn test_diff_hunks_in_range(cx: &mut TestAppContext) {
4399 use git::diff::DiffHunkStatus;
4400
4401 // buffer has two modified hunks with two rows each
4402 let buffer_1 = cx.add_model(|cx| {
4403 let mut buffer = Buffer::new(
4404 0,
4405 "
4406 1.zero
4407 1.ONE
4408 1.TWO
4409 1.three
4410 1.FOUR
4411 1.FIVE
4412 1.six
4413 "
4414 .unindent(),
4415 cx,
4416 );
4417 buffer.set_diff_base(
4418 Some(
4419 "
4420 1.zero
4421 1.one
4422 1.two
4423 1.three
4424 1.four
4425 1.five
4426 1.six
4427 "
4428 .unindent(),
4429 ),
4430 cx,
4431 );
4432 buffer
4433 });
4434
4435 // buffer has a deletion hunk and an insertion hunk
4436 let buffer_2 = cx.add_model(|cx| {
4437 let mut buffer = Buffer::new(
4438 0,
4439 "
4440 2.zero
4441 2.one
4442 2.two
4443 2.three
4444 2.four
4445 2.five
4446 2.six
4447 "
4448 .unindent(),
4449 cx,
4450 );
4451 buffer.set_diff_base(
4452 Some(
4453 "
4454 2.zero
4455 2.one
4456 2.one-and-a-half
4457 2.two
4458 2.three
4459 2.four
4460 2.six
4461 "
4462 .unindent(),
4463 ),
4464 cx,
4465 );
4466 buffer
4467 });
4468
4469 cx.foreground().run_until_parked();
4470
4471 let multibuffer = cx.add_model(|cx| {
4472 let mut multibuffer = MultiBuffer::new(0);
4473 multibuffer.push_excerpts(
4474 buffer_1.clone(),
4475 [
4476 // excerpt ends in the middle of a modified hunk
4477 ExcerptRange {
4478 context: Point::new(0, 0)..Point::new(1, 5),
4479 primary: Default::default(),
4480 },
4481 // excerpt begins in the middle of a modified hunk
4482 ExcerptRange {
4483 context: Point::new(5, 0)..Point::new(6, 5),
4484 primary: Default::default(),
4485 },
4486 ],
4487 cx,
4488 );
4489 multibuffer.push_excerpts(
4490 buffer_2.clone(),
4491 [
4492 // excerpt ends at a deletion
4493 ExcerptRange {
4494 context: Point::new(0, 0)..Point::new(1, 5),
4495 primary: Default::default(),
4496 },
4497 // excerpt starts at a deletion
4498 ExcerptRange {
4499 context: Point::new(2, 0)..Point::new(2, 5),
4500 primary: Default::default(),
4501 },
4502 // excerpt fully contains a deletion hunk
4503 ExcerptRange {
4504 context: Point::new(1, 0)..Point::new(2, 5),
4505 primary: Default::default(),
4506 },
4507 // excerpt fully contains an insertion hunk
4508 ExcerptRange {
4509 context: Point::new(4, 0)..Point::new(6, 5),
4510 primary: Default::default(),
4511 },
4512 ],
4513 cx,
4514 );
4515 multibuffer
4516 });
4517
4518 let snapshot = multibuffer.read_with(cx, |b, cx| b.snapshot(cx));
4519
4520 assert_eq!(
4521 snapshot.text(),
4522 "
4523 1.zero
4524 1.ONE
4525 1.FIVE
4526 1.six
4527 2.zero
4528 2.one
4529 2.two
4530 2.one
4531 2.two
4532 2.four
4533 2.five
4534 2.six"
4535 .unindent()
4536 );
4537
4538 let expected = [
4539 (DiffHunkStatus::Modified, 1..2),
4540 (DiffHunkStatus::Modified, 2..3),
4541 //TODO: Define better when and where removed hunks show up at range extremities
4542 (DiffHunkStatus::Removed, 6..6),
4543 (DiffHunkStatus::Removed, 8..8),
4544 (DiffHunkStatus::Added, 10..11),
4545 ];
4546
4547 assert_eq!(
4548 snapshot
4549 .git_diff_hunks_in_range(0..12, false)
4550 .map(|hunk| (hunk.status(), hunk.buffer_range))
4551 .collect::<Vec<_>>(),
4552 &expected,
4553 );
4554
4555 assert_eq!(
4556 snapshot
4557 .git_diff_hunks_in_range(0..12, true)
4558 .map(|hunk| (hunk.status(), hunk.buffer_range))
4559 .collect::<Vec<_>>(),
4560 expected
4561 .iter()
4562 .rev()
4563 .cloned()
4564 .collect::<Vec<_>>()
4565 .as_slice(),
4566 );
4567 }
4568
4569 #[gpui::test(iterations = 100)]
4570 fn test_random_multibuffer(cx: &mut MutableAppContext, mut rng: StdRng) {
4571 let operations = env::var("OPERATIONS")
4572 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
4573 .unwrap_or(10);
4574
4575 let mut buffers: Vec<ModelHandle<Buffer>> = Vec::new();
4576 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4577 let mut excerpt_ids = Vec::<ExcerptId>::new();
4578 let mut expected_excerpts = Vec::<(ModelHandle<Buffer>, Range<text::Anchor>)>::new();
4579 let mut anchors = Vec::new();
4580 let mut old_versions = Vec::new();
4581
4582 for _ in 0..operations {
4583 match rng.gen_range(0..100) {
4584 0..=19 if !buffers.is_empty() => {
4585 let buffer = buffers.choose(&mut rng).unwrap();
4586 buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
4587 }
4588 20..=29 if !expected_excerpts.is_empty() => {
4589 let mut ids_to_remove = vec![];
4590 for _ in 0..rng.gen_range(1..=3) {
4591 if expected_excerpts.is_empty() {
4592 break;
4593 }
4594
4595 let ix = rng.gen_range(0..expected_excerpts.len());
4596 ids_to_remove.push(excerpt_ids.remove(ix));
4597 let (buffer, range) = expected_excerpts.remove(ix);
4598 let buffer = buffer.read(cx);
4599 log::info!(
4600 "Removing excerpt {}: {:?}",
4601 ix,
4602 buffer
4603 .text_for_range(range.to_offset(buffer))
4604 .collect::<String>(),
4605 );
4606 }
4607 let snapshot = multibuffer.read(cx).read(cx);
4608 ids_to_remove.sort_unstable_by(|a, b| a.cmp(&b, &snapshot));
4609 drop(snapshot);
4610 multibuffer.update(cx, |multibuffer, cx| {
4611 multibuffer.remove_excerpts(ids_to_remove, cx)
4612 });
4613 }
4614 30..=39 if !expected_excerpts.is_empty() => {
4615 let multibuffer = multibuffer.read(cx).read(cx);
4616 let offset =
4617 multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left);
4618 let bias = if rng.gen() { Bias::Left } else { Bias::Right };
4619 log::info!("Creating anchor at {} with bias {:?}", offset, bias);
4620 anchors.push(multibuffer.anchor_at(offset, bias));
4621 anchors.sort_by(|a, b| a.cmp(b, &multibuffer));
4622 }
4623 40..=44 if !anchors.is_empty() => {
4624 let multibuffer = multibuffer.read(cx).read(cx);
4625 let prev_len = anchors.len();
4626 anchors = multibuffer
4627 .refresh_anchors(&anchors)
4628 .into_iter()
4629 .map(|a| a.1)
4630 .collect();
4631
4632 // Ensure the newly-refreshed anchors point to a valid excerpt and don't
4633 // overshoot its boundaries.
4634 assert_eq!(anchors.len(), prev_len);
4635 for anchor in &anchors {
4636 if anchor.excerpt_id == ExcerptId::min()
4637 || anchor.excerpt_id == ExcerptId::max()
4638 {
4639 continue;
4640 }
4641
4642 let excerpt = multibuffer.excerpt(anchor.excerpt_id).unwrap();
4643 assert_eq!(excerpt.id, anchor.excerpt_id);
4644 assert!(excerpt.contains(anchor));
4645 }
4646 }
4647 _ => {
4648 let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
4649 let base_text = util::RandomCharIter::new(&mut rng)
4650 .take(10)
4651 .collect::<String>();
4652 buffers.push(cx.add_model(|cx| Buffer::new(0, base_text, cx)));
4653 buffers.last().unwrap()
4654 } else {
4655 buffers.choose(&mut rng).unwrap()
4656 };
4657
4658 let buffer = buffer_handle.read(cx);
4659 let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
4660 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
4661 let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
4662 let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len());
4663 let prev_excerpt_id = excerpt_ids
4664 .get(prev_excerpt_ix)
4665 .cloned()
4666 .unwrap_or_else(ExcerptId::max);
4667 let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len());
4668
4669 log::info!(
4670 "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}",
4671 excerpt_ix,
4672 expected_excerpts.len(),
4673 buffer_handle.id(),
4674 buffer.text(),
4675 start_ix..end_ix,
4676 &buffer.text()[start_ix..end_ix]
4677 );
4678
4679 let excerpt_id = multibuffer.update(cx, |multibuffer, cx| {
4680 multibuffer
4681 .insert_excerpts_after(
4682 prev_excerpt_id,
4683 buffer_handle.clone(),
4684 [ExcerptRange {
4685 context: start_ix..end_ix,
4686 primary: None,
4687 }],
4688 cx,
4689 )
4690 .pop()
4691 .unwrap()
4692 });
4693
4694 excerpt_ids.insert(excerpt_ix, excerpt_id);
4695 expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range));
4696 }
4697 }
4698
4699 if rng.gen_bool(0.3) {
4700 multibuffer.update(cx, |multibuffer, cx| {
4701 old_versions.push((multibuffer.snapshot(cx), multibuffer.subscribe()));
4702 })
4703 }
4704
4705 let snapshot = multibuffer.read(cx).snapshot(cx);
4706
4707 let mut excerpt_starts = Vec::new();
4708 let mut expected_text = String::new();
4709 let mut expected_buffer_rows = Vec::new();
4710 for (buffer, range) in &expected_excerpts {
4711 let buffer = buffer.read(cx);
4712 let buffer_range = range.to_offset(buffer);
4713
4714 excerpt_starts.push(TextSummary::from(expected_text.as_str()));
4715 expected_text.extend(buffer.text_for_range(buffer_range.clone()));
4716 expected_text.push('\n');
4717
4718 let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
4719 ..=buffer.offset_to_point(buffer_range.end).row;
4720 for row in buffer_row_range {
4721 expected_buffer_rows.push(Some(row));
4722 }
4723 }
4724 // Remove final trailing newline.
4725 if !expected_excerpts.is_empty() {
4726 expected_text.pop();
4727 }
4728
4729 // Always report one buffer row
4730 if expected_buffer_rows.is_empty() {
4731 expected_buffer_rows.push(Some(0));
4732 }
4733
4734 assert_eq!(snapshot.text(), expected_text);
4735 log::info!("MultiBuffer text: {:?}", expected_text);
4736
4737 assert_eq!(
4738 snapshot.buffer_rows(0).collect::<Vec<_>>(),
4739 expected_buffer_rows,
4740 );
4741
4742 for _ in 0..5 {
4743 let start_row = rng.gen_range(0..=expected_buffer_rows.len());
4744 assert_eq!(
4745 snapshot.buffer_rows(start_row as u32).collect::<Vec<_>>(),
4746 &expected_buffer_rows[start_row..],
4747 "buffer_rows({})",
4748 start_row
4749 );
4750 }
4751
4752 assert_eq!(
4753 snapshot.max_buffer_row(),
4754 expected_buffer_rows.into_iter().flatten().max().unwrap()
4755 );
4756
4757 let mut excerpt_starts = excerpt_starts.into_iter();
4758 for (buffer, range) in &expected_excerpts {
4759 let buffer_id = buffer.id();
4760 let buffer = buffer.read(cx);
4761 let buffer_range = range.to_offset(buffer);
4762 let buffer_start_point = buffer.offset_to_point(buffer_range.start);
4763 let buffer_start_point_utf16 =
4764 buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
4765
4766 let excerpt_start = excerpt_starts.next().unwrap();
4767 let mut offset = excerpt_start.len;
4768 let mut buffer_offset = buffer_range.start;
4769 let mut point = excerpt_start.lines;
4770 let mut buffer_point = buffer_start_point;
4771 let mut point_utf16 = excerpt_start.lines_utf16();
4772 let mut buffer_point_utf16 = buffer_start_point_utf16;
4773 for ch in buffer
4774 .snapshot()
4775 .chunks(buffer_range.clone(), false)
4776 .flat_map(|c| c.text.chars())
4777 {
4778 for _ in 0..ch.len_utf8() {
4779 let left_offset = snapshot.clip_offset(offset, Bias::Left);
4780 let right_offset = snapshot.clip_offset(offset, Bias::Right);
4781 let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
4782 let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
4783 assert_eq!(
4784 left_offset,
4785 excerpt_start.len + (buffer_left_offset - buffer_range.start),
4786 "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
4787 offset,
4788 buffer_id,
4789 buffer_offset,
4790 );
4791 assert_eq!(
4792 right_offset,
4793 excerpt_start.len + (buffer_right_offset - buffer_range.start),
4794 "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
4795 offset,
4796 buffer_id,
4797 buffer_offset,
4798 );
4799
4800 let left_point = snapshot.clip_point(point, Bias::Left);
4801 let right_point = snapshot.clip_point(point, Bias::Right);
4802 let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
4803 let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
4804 assert_eq!(
4805 left_point,
4806 excerpt_start.lines + (buffer_left_point - buffer_start_point),
4807 "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
4808 point,
4809 buffer_id,
4810 buffer_point,
4811 );
4812 assert_eq!(
4813 right_point,
4814 excerpt_start.lines + (buffer_right_point - buffer_start_point),
4815 "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
4816 point,
4817 buffer_id,
4818 buffer_point,
4819 );
4820
4821 assert_eq!(
4822 snapshot.point_to_offset(left_point),
4823 left_offset,
4824 "point_to_offset({:?})",
4825 left_point,
4826 );
4827 assert_eq!(
4828 snapshot.offset_to_point(left_offset),
4829 left_point,
4830 "offset_to_point({:?})",
4831 left_offset,
4832 );
4833
4834 offset += 1;
4835 buffer_offset += 1;
4836 if ch == '\n' {
4837 point += Point::new(1, 0);
4838 buffer_point += Point::new(1, 0);
4839 } else {
4840 point += Point::new(0, 1);
4841 buffer_point += Point::new(0, 1);
4842 }
4843 }
4844
4845 for _ in 0..ch.len_utf16() {
4846 let left_point_utf16 =
4847 snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Left);
4848 let right_point_utf16 =
4849 snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Right);
4850 let buffer_left_point_utf16 =
4851 buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Left);
4852 let buffer_right_point_utf16 =
4853 buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Right);
4854 assert_eq!(
4855 left_point_utf16,
4856 excerpt_start.lines_utf16()
4857 + (buffer_left_point_utf16 - buffer_start_point_utf16),
4858 "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
4859 point_utf16,
4860 buffer_id,
4861 buffer_point_utf16,
4862 );
4863 assert_eq!(
4864 right_point_utf16,
4865 excerpt_start.lines_utf16()
4866 + (buffer_right_point_utf16 - buffer_start_point_utf16),
4867 "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
4868 point_utf16,
4869 buffer_id,
4870 buffer_point_utf16,
4871 );
4872
4873 if ch == '\n' {
4874 point_utf16 += PointUtf16::new(1, 0);
4875 buffer_point_utf16 += PointUtf16::new(1, 0);
4876 } else {
4877 point_utf16 += PointUtf16::new(0, 1);
4878 buffer_point_utf16 += PointUtf16::new(0, 1);
4879 }
4880 }
4881 }
4882 }
4883
4884 for (row, line) in expected_text.split('\n').enumerate() {
4885 assert_eq!(
4886 snapshot.line_len(row as u32),
4887 line.len() as u32,
4888 "line_len({}).",
4889 row
4890 );
4891 }
4892
4893 let text_rope = Rope::from(expected_text.as_str());
4894 for _ in 0..10 {
4895 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
4896 let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
4897
4898 let text_for_range = snapshot
4899 .text_for_range(start_ix..end_ix)
4900 .collect::<String>();
4901 assert_eq!(
4902 text_for_range,
4903 &expected_text[start_ix..end_ix],
4904 "incorrect text for range {:?}",
4905 start_ix..end_ix
4906 );
4907
4908 let excerpted_buffer_ranges = multibuffer
4909 .read(cx)
4910 .range_to_buffer_ranges(start_ix..end_ix, cx);
4911 let excerpted_buffers_text = excerpted_buffer_ranges
4912 .into_iter()
4913 .map(|(buffer, buffer_range)| {
4914 buffer
4915 .read(cx)
4916 .text_for_range(buffer_range)
4917 .collect::<String>()
4918 })
4919 .collect::<Vec<_>>()
4920 .join("\n");
4921 assert_eq!(excerpted_buffers_text, text_for_range);
4922
4923 let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
4924 assert_eq!(
4925 snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
4926 expected_summary,
4927 "incorrect summary for range {:?}",
4928 start_ix..end_ix
4929 );
4930 }
4931
4932 // Anchor resolution
4933 let summaries = snapshot.summaries_for_anchors::<usize, _>(&anchors);
4934 assert_eq!(anchors.len(), summaries.len());
4935 for (anchor, resolved_offset) in anchors.iter().zip(summaries) {
4936 assert!(resolved_offset <= snapshot.len());
4937 assert_eq!(
4938 snapshot.summary_for_anchor::<usize>(anchor),
4939 resolved_offset
4940 );
4941 }
4942
4943 for _ in 0..10 {
4944 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
4945 assert_eq!(
4946 snapshot.reversed_chars_at(end_ix).collect::<String>(),
4947 expected_text[..end_ix].chars().rev().collect::<String>(),
4948 );
4949 }
4950
4951 for _ in 0..10 {
4952 let end_ix = rng.gen_range(0..=text_rope.len());
4953 let start_ix = rng.gen_range(0..=end_ix);
4954 assert_eq!(
4955 snapshot
4956 .bytes_in_range(start_ix..end_ix)
4957 .flatten()
4958 .copied()
4959 .collect::<Vec<_>>(),
4960 expected_text.as_bytes()[start_ix..end_ix].to_vec(),
4961 "bytes_in_range({:?})",
4962 start_ix..end_ix,
4963 );
4964 }
4965 }
4966
4967 let snapshot = multibuffer.read(cx).snapshot(cx);
4968 for (old_snapshot, subscription) in old_versions {
4969 let edits = subscription.consume().into_inner();
4970
4971 log::info!(
4972 "applying subscription edits to old text: {:?}: {:?}",
4973 old_snapshot.text(),
4974 edits,
4975 );
4976
4977 let mut text = old_snapshot.text();
4978 for edit in edits {
4979 let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
4980 text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
4981 }
4982 assert_eq!(text.to_string(), snapshot.text());
4983 }
4984 }
4985
4986 #[gpui::test]
4987 fn test_history(cx: &mut MutableAppContext) {
4988 cx.set_global(Settings::test(cx));
4989 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "1234", cx));
4990 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "5678", cx));
4991 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
4992 let group_interval = multibuffer.read(cx).history.group_interval;
4993 multibuffer.update(cx, |multibuffer, cx| {
4994 multibuffer.push_excerpts(
4995 buffer_1.clone(),
4996 [ExcerptRange {
4997 context: 0..buffer_1.read(cx).len(),
4998 primary: None,
4999 }],
5000 cx,
5001 );
5002 multibuffer.push_excerpts(
5003 buffer_2.clone(),
5004 [ExcerptRange {
5005 context: 0..buffer_2.read(cx).len(),
5006 primary: None,
5007 }],
5008 cx,
5009 );
5010 });
5011
5012 let mut now = Instant::now();
5013
5014 multibuffer.update(cx, |multibuffer, cx| {
5015 let transaction_1 = multibuffer.start_transaction_at(now, cx).unwrap();
5016 multibuffer.edit(
5017 [
5018 (Point::new(0, 0)..Point::new(0, 0), "A"),
5019 (Point::new(1, 0)..Point::new(1, 0), "A"),
5020 ],
5021 None,
5022 cx,
5023 );
5024 multibuffer.edit(
5025 [
5026 (Point::new(0, 1)..Point::new(0, 1), "B"),
5027 (Point::new(1, 1)..Point::new(1, 1), "B"),
5028 ],
5029 None,
5030 cx,
5031 );
5032 multibuffer.end_transaction_at(now, cx);
5033 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5034
5035 // Edit buffer 1 through the multibuffer
5036 now += 2 * group_interval;
5037 multibuffer.start_transaction_at(now, cx);
5038 multibuffer.edit([(2..2, "C")], None, cx);
5039 multibuffer.end_transaction_at(now, cx);
5040 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
5041
5042 // Edit buffer 1 independently
5043 buffer_1.update(cx, |buffer_1, cx| {
5044 buffer_1.start_transaction_at(now);
5045 buffer_1.edit([(3..3, "D")], None, cx);
5046 buffer_1.end_transaction_at(now, cx);
5047
5048 now += 2 * group_interval;
5049 buffer_1.start_transaction_at(now);
5050 buffer_1.edit([(4..4, "E")], None, cx);
5051 buffer_1.end_transaction_at(now, cx);
5052 });
5053 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
5054
5055 // An undo in the multibuffer undoes the multibuffer transaction
5056 // and also any individual buffer edits that have occured since
5057 // that transaction.
5058 multibuffer.undo(cx);
5059 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5060
5061 multibuffer.undo(cx);
5062 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5063
5064 multibuffer.redo(cx);
5065 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5066
5067 multibuffer.redo(cx);
5068 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
5069
5070 // Undo buffer 2 independently.
5071 buffer_2.update(cx, |buffer_2, cx| buffer_2.undo(cx));
5072 assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\n5678");
5073
5074 // An undo in the multibuffer undoes the components of the
5075 // the last multibuffer transaction that are not already undone.
5076 multibuffer.undo(cx);
5077 assert_eq!(multibuffer.read(cx).text(), "AB1234\n5678");
5078
5079 multibuffer.undo(cx);
5080 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5081
5082 multibuffer.redo(cx);
5083 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5084
5085 buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
5086 assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
5087
5088 // Redo stack gets cleared after an edit.
5089 now += 2 * group_interval;
5090 multibuffer.start_transaction_at(now, cx);
5091 multibuffer.edit([(0..0, "X")], None, cx);
5092 multibuffer.end_transaction_at(now, cx);
5093 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5094 multibuffer.redo(cx);
5095 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5096 multibuffer.undo(cx);
5097 assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
5098 multibuffer.undo(cx);
5099 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5100
5101 // Transactions can be grouped manually.
5102 multibuffer.redo(cx);
5103 multibuffer.redo(cx);
5104 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5105 multibuffer.group_until_transaction(transaction_1, cx);
5106 multibuffer.undo(cx);
5107 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5108 multibuffer.redo(cx);
5109 assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5110 });
5111 }
5112}