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