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