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