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