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