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