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