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