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