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