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