1mod anchor;
2
3pub use anchor::{Anchor, AnchorRangeExt};
4use anyhow::Result;
5use clock::ReplicaId;
6use collections::{Bound, HashMap, HashSet};
7use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
8pub use language::Completion;
9use language::{
10 Buffer, BufferChunks, BufferSnapshot, Chunk, DiagnosticEntry, Event, File, Language, Outline,
11 OutlineItem, Selection, ToOffset as _, ToPoint as _, ToPointUtf16 as _, TransactionId,
12};
13use std::{
14 cell::{Ref, RefCell},
15 cmp, fmt, io,
16 iter::{self, FromIterator},
17 ops::{Range, RangeBounds, Sub},
18 str,
19 sync::Arc,
20 time::{Duration, Instant},
21};
22use sum_tree::{Bias, Cursor, SumTree};
23use text::{
24 locator::Locator,
25 rope::TextDimension,
26 subscription::{Subscription, Topic},
27 AnchorRangeExt as _, Edit, Point, PointUtf16, TextSummary,
28};
29use theme::SyntaxTheme;
30
31const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize];
32
33pub type ExcerptId = Locator;
34
35pub struct MultiBuffer {
36 snapshot: RefCell<MultiBufferSnapshot>,
37 buffers: RefCell<HashMap<usize, BufferState>>,
38 subscriptions: Topic,
39 singleton: bool,
40 replica_id: ReplicaId,
41 history: History,
42 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: HashSet<(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 = HashSet::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: HashSet<(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 transaction.buffer_transactions.extend(buffer_transactions);
2242 true
2243 }
2244 } else {
2245 false
2246 }
2247 }
2248
2249 fn push_transaction<'a, T>(&mut self, buffer_transactions: T, now: Instant)
2250 where
2251 T: IntoIterator<Item = (&'a ModelHandle<Buffer>, &'a language::Transaction)>,
2252 {
2253 assert_eq!(self.transaction_depth, 0);
2254 self.undo_stack.push(Transaction {
2255 id: self.next_transaction_id.tick(),
2256 buffer_transactions: buffer_transactions
2257 .into_iter()
2258 .map(|(buffer, transaction)| (buffer.id(), transaction.id))
2259 .collect(),
2260 first_edit_at: now,
2261 last_edit_at: now,
2262 suppress_grouping: false,
2263 });
2264 }
2265
2266 fn finalize_last_transaction(&mut self) {
2267 if let Some(transaction) = self.undo_stack.last_mut() {
2268 transaction.suppress_grouping = true;
2269 }
2270 }
2271
2272 fn pop_undo(&mut self) -> Option<&Transaction> {
2273 assert_eq!(self.transaction_depth, 0);
2274 if let Some(transaction) = self.undo_stack.pop() {
2275 self.redo_stack.push(transaction);
2276 self.redo_stack.last()
2277 } else {
2278 None
2279 }
2280 }
2281
2282 fn pop_redo(&mut self) -> Option<&Transaction> {
2283 assert_eq!(self.transaction_depth, 0);
2284 if let Some(transaction) = self.redo_stack.pop() {
2285 self.undo_stack.push(transaction);
2286 self.undo_stack.last()
2287 } else {
2288 None
2289 }
2290 }
2291
2292 fn group(&mut self) -> Option<TransactionId> {
2293 let mut new_len = self.undo_stack.len();
2294 let mut transactions = self.undo_stack.iter_mut();
2295
2296 if let Some(mut transaction) = transactions.next_back() {
2297 while let Some(prev_transaction) = transactions.next_back() {
2298 if !prev_transaction.suppress_grouping
2299 && transaction.first_edit_at - prev_transaction.last_edit_at
2300 <= self.group_interval
2301 {
2302 transaction = prev_transaction;
2303 new_len -= 1;
2304 } else {
2305 break;
2306 }
2307 }
2308 }
2309
2310 let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
2311 if let Some(last_transaction) = transactions_to_keep.last_mut() {
2312 if let Some(transaction) = transactions_to_merge.last() {
2313 last_transaction.last_edit_at = transaction.last_edit_at;
2314 }
2315 }
2316
2317 self.undo_stack.truncate(new_len);
2318 self.undo_stack.last().map(|t| t.id)
2319 }
2320}
2321
2322impl Excerpt {
2323 fn new(
2324 id: ExcerptId,
2325 buffer_id: usize,
2326 buffer: BufferSnapshot,
2327 range: Range<text::Anchor>,
2328 has_trailing_newline: bool,
2329 ) -> Self {
2330 Excerpt {
2331 id,
2332 max_buffer_row: range.end.to_point(&buffer).row,
2333 text_summary: buffer.text_summary_for_range::<TextSummary, _>(range.to_offset(&buffer)),
2334 buffer_id,
2335 buffer,
2336 range,
2337 has_trailing_newline,
2338 }
2339 }
2340
2341 fn chunks_in_range<'a>(
2342 &'a self,
2343 range: Range<usize>,
2344 language_aware: bool,
2345 ) -> ExcerptChunks<'a> {
2346 let content_start = self.range.start.to_offset(&self.buffer);
2347 let chunks_start = content_start + range.start;
2348 let chunks_end = content_start + cmp::min(range.end, self.text_summary.bytes);
2349
2350 let footer_height = if self.has_trailing_newline
2351 && range.start <= self.text_summary.bytes
2352 && range.end > self.text_summary.bytes
2353 {
2354 1
2355 } else {
2356 0
2357 };
2358
2359 let content_chunks = self.buffer.chunks(chunks_start..chunks_end, language_aware);
2360
2361 ExcerptChunks {
2362 content_chunks,
2363 footer_height,
2364 }
2365 }
2366
2367 fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
2368 let content_start = self.range.start.to_offset(&self.buffer);
2369 let bytes_start = content_start + range.start;
2370 let bytes_end = content_start + cmp::min(range.end, self.text_summary.bytes);
2371 let footer_height = if self.has_trailing_newline
2372 && range.start <= self.text_summary.bytes
2373 && range.end > self.text_summary.bytes
2374 {
2375 1
2376 } else {
2377 0
2378 };
2379 let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
2380
2381 ExcerptBytes {
2382 content_bytes,
2383 footer_height,
2384 }
2385 }
2386
2387 fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
2388 if text_anchor
2389 .cmp(&self.range.start, &self.buffer)
2390 .unwrap()
2391 .is_lt()
2392 {
2393 self.range.start.clone()
2394 } else if text_anchor
2395 .cmp(&self.range.end, &self.buffer)
2396 .unwrap()
2397 .is_gt()
2398 {
2399 self.range.end.clone()
2400 } else {
2401 text_anchor
2402 }
2403 }
2404
2405 fn contains(&self, anchor: &Anchor) -> bool {
2406 self.buffer_id == anchor.buffer_id
2407 && self
2408 .range
2409 .start
2410 .cmp(&anchor.text_anchor, &self.buffer)
2411 .unwrap()
2412 .is_le()
2413 && self
2414 .range
2415 .end
2416 .cmp(&anchor.text_anchor, &self.buffer)
2417 .unwrap()
2418 .is_ge()
2419 }
2420}
2421
2422impl fmt::Debug for Excerpt {
2423 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2424 f.debug_struct("Excerpt")
2425 .field("id", &self.id)
2426 .field("buffer_id", &self.buffer_id)
2427 .field("range", &self.range)
2428 .field("text_summary", &self.text_summary)
2429 .field("has_trailing_newline", &self.has_trailing_newline)
2430 .finish()
2431 }
2432}
2433
2434impl sum_tree::Item for Excerpt {
2435 type Summary = ExcerptSummary;
2436
2437 fn summary(&self) -> Self::Summary {
2438 let mut text = self.text_summary.clone();
2439 if self.has_trailing_newline {
2440 text += TextSummary::from("\n");
2441 }
2442 ExcerptSummary {
2443 excerpt_id: self.id.clone(),
2444 max_buffer_row: self.max_buffer_row,
2445 text,
2446 }
2447 }
2448}
2449
2450impl sum_tree::Summary for ExcerptSummary {
2451 type Context = ();
2452
2453 fn add_summary(&mut self, summary: &Self, _: &()) {
2454 debug_assert!(summary.excerpt_id > self.excerpt_id);
2455 self.excerpt_id = summary.excerpt_id.clone();
2456 self.text.add_summary(&summary.text, &());
2457 self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row);
2458 }
2459}
2460
2461impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
2462 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2463 *self += &summary.text;
2464 }
2465}
2466
2467impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
2468 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2469 *self += summary.text.bytes;
2470 }
2471}
2472
2473impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
2474 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
2475 Ord::cmp(self, &cursor_location.text.bytes)
2476 }
2477}
2478
2479impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Option<&'a ExcerptId> {
2480 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
2481 Ord::cmp(self, &Some(&cursor_location.excerpt_id))
2482 }
2483}
2484
2485impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
2486 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2487 *self += summary.text.lines;
2488 }
2489}
2490
2491impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
2492 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2493 *self += summary.text.lines_utf16
2494 }
2495}
2496
2497impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a ExcerptId> {
2498 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2499 *self = Some(&summary.excerpt_id);
2500 }
2501}
2502
2503impl<'a> MultiBufferRows<'a> {
2504 pub fn seek(&mut self, row: u32) {
2505 self.buffer_row_range = 0..0;
2506
2507 self.excerpts
2508 .seek_forward(&Point::new(row, 0), Bias::Right, &());
2509 if self.excerpts.item().is_none() {
2510 self.excerpts.prev(&());
2511
2512 if self.excerpts.item().is_none() && row == 0 {
2513 self.buffer_row_range = 0..1;
2514 return;
2515 }
2516 }
2517
2518 if let Some(excerpt) = self.excerpts.item() {
2519 let overshoot = row - self.excerpts.start().row;
2520 let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer).row;
2521 self.buffer_row_range.start = excerpt_start + overshoot;
2522 self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
2523 }
2524 }
2525}
2526
2527impl<'a> Iterator for MultiBufferRows<'a> {
2528 type Item = Option<u32>;
2529
2530 fn next(&mut self) -> Option<Self::Item> {
2531 loop {
2532 if !self.buffer_row_range.is_empty() {
2533 let row = Some(self.buffer_row_range.start);
2534 self.buffer_row_range.start += 1;
2535 return Some(row);
2536 }
2537 self.excerpts.item()?;
2538 self.excerpts.next(&());
2539 let excerpt = self.excerpts.item()?;
2540 self.buffer_row_range.start = excerpt.range.start.to_point(&excerpt.buffer).row;
2541 self.buffer_row_range.end =
2542 self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
2543 }
2544 }
2545}
2546
2547impl<'a> MultiBufferChunks<'a> {
2548 pub fn offset(&self) -> usize {
2549 self.range.start
2550 }
2551
2552 pub fn seek(&mut self, offset: usize) {
2553 self.range.start = offset;
2554 self.excerpts.seek(&offset, Bias::Right, &());
2555 if let Some(excerpt) = self.excerpts.item() {
2556 self.excerpt_chunks = Some(excerpt.chunks_in_range(
2557 self.range.start - self.excerpts.start()..self.range.end - self.excerpts.start(),
2558 self.language_aware,
2559 ));
2560 } else {
2561 self.excerpt_chunks = None;
2562 }
2563 }
2564}
2565
2566impl<'a> Iterator for MultiBufferChunks<'a> {
2567 type Item = Chunk<'a>;
2568
2569 fn next(&mut self) -> Option<Self::Item> {
2570 if self.range.is_empty() {
2571 None
2572 } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
2573 self.range.start += chunk.text.len();
2574 Some(chunk)
2575 } else {
2576 self.excerpts.next(&());
2577 let excerpt = self.excerpts.item()?;
2578 self.excerpt_chunks = Some(excerpt.chunks_in_range(
2579 0..self.range.end - self.excerpts.start(),
2580 self.language_aware,
2581 ));
2582 self.next()
2583 }
2584 }
2585}
2586
2587impl<'a> MultiBufferBytes<'a> {
2588 fn consume(&mut self, len: usize) {
2589 self.range.start += len;
2590 self.chunk = &self.chunk[len..];
2591
2592 if !self.range.is_empty() && self.chunk.is_empty() {
2593 if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
2594 self.chunk = chunk;
2595 } else {
2596 self.excerpts.next(&());
2597 if let Some(excerpt) = self.excerpts.item() {
2598 let mut excerpt_bytes =
2599 excerpt.bytes_in_range(0..self.range.end - self.excerpts.start());
2600 self.chunk = excerpt_bytes.next().unwrap();
2601 self.excerpt_bytes = Some(excerpt_bytes);
2602 }
2603 }
2604 }
2605 }
2606}
2607
2608impl<'a> Iterator for MultiBufferBytes<'a> {
2609 type Item = &'a [u8];
2610
2611 fn next(&mut self) -> Option<Self::Item> {
2612 let chunk = self.chunk;
2613 if chunk.is_empty() {
2614 None
2615 } else {
2616 self.consume(chunk.len());
2617 Some(chunk)
2618 }
2619 }
2620}
2621
2622impl<'a> io::Read for MultiBufferBytes<'a> {
2623 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2624 let len = cmp::min(buf.len(), self.chunk.len());
2625 buf[..len].copy_from_slice(&self.chunk[..len]);
2626 if len > 0 {
2627 self.consume(len);
2628 }
2629 Ok(len)
2630 }
2631}
2632
2633impl<'a> Iterator for ExcerptBytes<'a> {
2634 type Item = &'a [u8];
2635
2636 fn next(&mut self) -> Option<Self::Item> {
2637 if let Some(chunk) = self.content_bytes.next() {
2638 if !chunk.is_empty() {
2639 return Some(chunk);
2640 }
2641 }
2642
2643 if self.footer_height > 0 {
2644 let result = &NEWLINES[..self.footer_height];
2645 self.footer_height = 0;
2646 return Some(result);
2647 }
2648
2649 None
2650 }
2651}
2652
2653impl<'a> Iterator for ExcerptChunks<'a> {
2654 type Item = Chunk<'a>;
2655
2656 fn next(&mut self) -> Option<Self::Item> {
2657 if let Some(chunk) = self.content_chunks.next() {
2658 return Some(chunk);
2659 }
2660
2661 if self.footer_height > 0 {
2662 let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
2663 self.footer_height = 0;
2664 return Some(Chunk {
2665 text,
2666 ..Default::default()
2667 });
2668 }
2669
2670 None
2671 }
2672}
2673
2674impl ToOffset for Point {
2675 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
2676 snapshot.point_to_offset(*self)
2677 }
2678}
2679
2680impl ToOffset for PointUtf16 {
2681 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
2682 snapshot.point_utf16_to_offset(*self)
2683 }
2684}
2685
2686impl ToOffset for usize {
2687 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
2688 assert!(*self <= snapshot.len(), "offset is out of range");
2689 *self
2690 }
2691}
2692
2693impl ToPoint for usize {
2694 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
2695 snapshot.offset_to_point(*self)
2696 }
2697}
2698
2699impl ToPoint for Point {
2700 fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
2701 *self
2702 }
2703}
2704
2705impl ToPointUtf16 for usize {
2706 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
2707 snapshot.offset_to_point_utf16(*self)
2708 }
2709}
2710
2711impl ToPointUtf16 for Point {
2712 fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
2713 snapshot.point_to_point_utf16(*self)
2714 }
2715}
2716
2717impl ToPointUtf16 for PointUtf16 {
2718 fn to_point_utf16<'a>(&self, _: &MultiBufferSnapshot) -> PointUtf16 {
2719 *self
2720 }
2721}
2722
2723pub fn char_kind(c: char) -> CharKind {
2724 if c == '\n' {
2725 CharKind::Newline
2726 } else if c.is_whitespace() {
2727 CharKind::Whitespace
2728 } else if c.is_alphanumeric() || c == '_' {
2729 CharKind::Word
2730 } else {
2731 CharKind::Punctuation
2732 }
2733}
2734
2735#[cfg(test)]
2736mod tests {
2737 use super::*;
2738 use gpui::MutableAppContext;
2739 use language::{Buffer, Rope};
2740 use rand::prelude::*;
2741 use std::env;
2742 use text::{Point, RandomCharIter};
2743 use util::test::sample_text;
2744
2745 #[gpui::test]
2746 fn test_singleton_multibuffer(cx: &mut MutableAppContext) {
2747 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
2748 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
2749
2750 let snapshot = multibuffer.read(cx).snapshot(cx);
2751 assert_eq!(snapshot.text(), buffer.read(cx).text());
2752
2753 assert_eq!(
2754 snapshot.buffer_rows(0).collect::<Vec<_>>(),
2755 (0..buffer.read(cx).row_count())
2756 .map(Some)
2757 .collect::<Vec<_>>()
2758 );
2759
2760 buffer.update(cx, |buffer, cx| buffer.edit([1..3], "XXX\n", cx));
2761 let snapshot = multibuffer.read(cx).snapshot(cx);
2762
2763 assert_eq!(snapshot.text(), buffer.read(cx).text());
2764 assert_eq!(
2765 snapshot.buffer_rows(0).collect::<Vec<_>>(),
2766 (0..buffer.read(cx).row_count())
2767 .map(Some)
2768 .collect::<Vec<_>>()
2769 );
2770 }
2771
2772 #[gpui::test]
2773 fn test_remote_multibuffer(cx: &mut MutableAppContext) {
2774 let host_buffer = cx.add_model(|cx| Buffer::new(0, "a", cx));
2775 let guest_buffer = cx.add_model(|cx| {
2776 let message = host_buffer.read(cx).to_proto();
2777 Buffer::from_proto(1, message, None, cx).unwrap()
2778 });
2779 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(guest_buffer.clone(), cx));
2780 let snapshot = multibuffer.read(cx).snapshot(cx);
2781 assert_eq!(snapshot.text(), "a");
2782
2783 guest_buffer.update(cx, |buffer, cx| buffer.edit([1..1], "b", cx));
2784 let snapshot = multibuffer.read(cx).snapshot(cx);
2785 assert_eq!(snapshot.text(), "ab");
2786
2787 guest_buffer.update(cx, |buffer, cx| buffer.edit([2..2], "c", cx));
2788 let snapshot = multibuffer.read(cx).snapshot(cx);
2789 assert_eq!(snapshot.text(), "abc");
2790 }
2791
2792 #[gpui::test]
2793 fn test_excerpt_buffer(cx: &mut MutableAppContext) {
2794 let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
2795 let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
2796 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2797
2798 let subscription = multibuffer.update(cx, |multibuffer, cx| {
2799 let subscription = multibuffer.subscribe();
2800 multibuffer.push_excerpts(buffer_1.clone(), [Point::new(1, 2)..Point::new(2, 5)], cx);
2801 assert_eq!(
2802 subscription.consume().into_inner(),
2803 [Edit {
2804 old: 0..0,
2805 new: 0..10
2806 }]
2807 );
2808
2809 multibuffer.push_excerpts(buffer_1.clone(), [Point::new(3, 3)..Point::new(4, 4)], cx);
2810 multibuffer.push_excerpts(buffer_2.clone(), [Point::new(3, 1)..Point::new(3, 3)], cx);
2811 assert_eq!(
2812 subscription.consume().into_inner(),
2813 [Edit {
2814 old: 10..10,
2815 new: 10..22
2816 }]
2817 );
2818
2819 subscription
2820 });
2821
2822 let snapshot = multibuffer.read(cx).snapshot(cx);
2823 assert_eq!(
2824 snapshot.text(),
2825 concat!(
2826 "bbbb\n", // Preserve newlines
2827 "ccccc\n", //
2828 "ddd\n", //
2829 "eeee\n", //
2830 "jj" //
2831 )
2832 );
2833 assert_eq!(
2834 snapshot.buffer_rows(0).collect::<Vec<_>>(),
2835 [Some(1), Some(2), Some(3), Some(4), Some(3)]
2836 );
2837 assert_eq!(
2838 snapshot.buffer_rows(2).collect::<Vec<_>>(),
2839 [Some(3), Some(4), Some(3)]
2840 );
2841 assert_eq!(snapshot.buffer_rows(4).collect::<Vec<_>>(), [Some(3)]);
2842 assert_eq!(snapshot.buffer_rows(5).collect::<Vec<_>>(), []);
2843
2844 assert_eq!(
2845 boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot),
2846 &[
2847 (0, "bbbb\nccccc".to_string(), true),
2848 (2, "ddd\neeee".to_string(), false),
2849 (4, "jj".to_string(), true),
2850 ]
2851 );
2852 assert_eq!(
2853 boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot),
2854 &[(0, "bbbb\nccccc".to_string(), true)]
2855 );
2856 assert_eq!(
2857 boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot),
2858 &[]
2859 );
2860 assert_eq!(
2861 boundaries_in_range(Point::new(1, 0)..Point::new(2, 0), &snapshot),
2862 &[]
2863 );
2864 assert_eq!(
2865 boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
2866 &[(2, "ddd\neeee".to_string(), false)]
2867 );
2868 assert_eq!(
2869 boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
2870 &[(2, "ddd\neeee".to_string(), false)]
2871 );
2872 assert_eq!(
2873 boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot),
2874 &[(2, "ddd\neeee".to_string(), false)]
2875 );
2876 assert_eq!(
2877 boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot),
2878 &[(4, "jj".to_string(), true)]
2879 );
2880 assert_eq!(
2881 boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot),
2882 &[]
2883 );
2884
2885 buffer_1.update(cx, |buffer, cx| {
2886 buffer.edit(
2887 [
2888 Point::new(0, 0)..Point::new(0, 0),
2889 Point::new(2, 1)..Point::new(2, 3),
2890 ],
2891 "\n",
2892 cx,
2893 );
2894 });
2895
2896 let snapshot = multibuffer.read(cx).snapshot(cx);
2897 assert_eq!(
2898 snapshot.text(),
2899 concat!(
2900 "bbbb\n", // Preserve newlines
2901 "c\n", //
2902 "cc\n", //
2903 "ddd\n", //
2904 "eeee\n", //
2905 "jj" //
2906 )
2907 );
2908
2909 assert_eq!(
2910 subscription.consume().into_inner(),
2911 [Edit {
2912 old: 6..8,
2913 new: 6..7
2914 }]
2915 );
2916
2917 let snapshot = multibuffer.read(cx).snapshot(cx);
2918 assert_eq!(
2919 snapshot.clip_point(Point::new(0, 5), Bias::Left),
2920 Point::new(0, 4)
2921 );
2922 assert_eq!(
2923 snapshot.clip_point(Point::new(0, 5), Bias::Right),
2924 Point::new(0, 4)
2925 );
2926 assert_eq!(
2927 snapshot.clip_point(Point::new(5, 1), Bias::Right),
2928 Point::new(5, 1)
2929 );
2930 assert_eq!(
2931 snapshot.clip_point(Point::new(5, 2), Bias::Right),
2932 Point::new(5, 2)
2933 );
2934 assert_eq!(
2935 snapshot.clip_point(Point::new(5, 3), Bias::Right),
2936 Point::new(5, 2)
2937 );
2938
2939 let snapshot = multibuffer.update(cx, |multibuffer, cx| {
2940 let buffer_2_excerpt_id = multibuffer.excerpt_ids_for_buffer(&buffer_2)[0].clone();
2941 multibuffer.remove_excerpts(&[buffer_2_excerpt_id], cx);
2942 multibuffer.snapshot(cx)
2943 });
2944
2945 assert_eq!(
2946 snapshot.text(),
2947 concat!(
2948 "bbbb\n", // Preserve newlines
2949 "c\n", //
2950 "cc\n", //
2951 "ddd\n", //
2952 "eeee", //
2953 )
2954 );
2955
2956 fn boundaries_in_range(
2957 range: Range<Point>,
2958 snapshot: &MultiBufferSnapshot,
2959 ) -> Vec<(u32, String, bool)> {
2960 snapshot
2961 .excerpt_boundaries_in_range(range)
2962 .map(|boundary| {
2963 (
2964 boundary.row,
2965 boundary
2966 .buffer
2967 .text_for_range(boundary.range)
2968 .collect::<String>(),
2969 boundary.starts_new_buffer,
2970 )
2971 })
2972 .collect::<Vec<_>>()
2973 }
2974 }
2975
2976 #[gpui::test]
2977 fn test_excerpts_with_context_lines(cx: &mut MutableAppContext) {
2978 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(20, 3, 'a'), cx));
2979 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2980 let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
2981 multibuffer.push_excerpts_with_context_lines(
2982 buffer.clone(),
2983 vec![
2984 Point::new(3, 2)..Point::new(4, 2),
2985 Point::new(7, 1)..Point::new(7, 3),
2986 Point::new(15, 0)..Point::new(15, 0),
2987 ],
2988 2,
2989 cx,
2990 )
2991 });
2992
2993 let snapshot = multibuffer.read(cx).snapshot(cx);
2994 assert_eq!(
2995 snapshot.text(),
2996 "bbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\n\nnnn\nooo\nppp\nqqq\nrrr\n"
2997 );
2998
2999 assert_eq!(
3000 anchor_ranges
3001 .iter()
3002 .map(|range| range.to_point(&snapshot))
3003 .collect::<Vec<_>>(),
3004 vec![
3005 Point::new(2, 2)..Point::new(3, 2),
3006 Point::new(6, 1)..Point::new(6, 3),
3007 Point::new(12, 0)..Point::new(12, 0)
3008 ]
3009 );
3010 }
3011
3012 #[gpui::test]
3013 fn test_empty_excerpt_buffer(cx: &mut MutableAppContext) {
3014 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3015
3016 let snapshot = multibuffer.read(cx).snapshot(cx);
3017 assert_eq!(snapshot.text(), "");
3018 assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), &[Some(0)]);
3019 assert_eq!(snapshot.buffer_rows(1).collect::<Vec<_>>(), &[]);
3020 }
3021
3022 #[gpui::test]
3023 fn test_singleton_multibuffer_anchors(cx: &mut MutableAppContext) {
3024 let buffer = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
3025 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
3026 let old_snapshot = multibuffer.read(cx).snapshot(cx);
3027 buffer.update(cx, |buffer, cx| {
3028 buffer.edit([0..0], "X", cx);
3029 buffer.edit([5..5], "Y", cx);
3030 });
3031 let new_snapshot = multibuffer.read(cx).snapshot(cx);
3032
3033 assert_eq!(old_snapshot.text(), "abcd");
3034 assert_eq!(new_snapshot.text(), "XabcdY");
3035
3036 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
3037 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
3038 assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
3039 assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
3040 }
3041
3042 #[gpui::test]
3043 fn test_multibuffer_anchors(cx: &mut MutableAppContext) {
3044 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
3045 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
3046 let multibuffer = cx.add_model(|cx| {
3047 let mut multibuffer = MultiBuffer::new(0);
3048 multibuffer.push_excerpts(buffer_1.clone(), [0..4], cx);
3049 multibuffer.push_excerpts(buffer_2.clone(), [0..5], cx);
3050 multibuffer
3051 });
3052 let old_snapshot = multibuffer.read(cx).snapshot(cx);
3053
3054 assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
3055 assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
3056 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
3057 assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
3058 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
3059 assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
3060
3061 buffer_1.update(cx, |buffer, cx| {
3062 buffer.edit([0..0], "W", cx);
3063 buffer.edit([5..5], "X", cx);
3064 });
3065 buffer_2.update(cx, |buffer, cx| {
3066 buffer.edit([0..0], "Y", cx);
3067 buffer.edit([6..0], "Z", cx);
3068 });
3069 let new_snapshot = multibuffer.read(cx).snapshot(cx);
3070
3071 assert_eq!(old_snapshot.text(), "abcd\nefghi");
3072 assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
3073
3074 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
3075 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
3076 assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
3077 assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
3078 assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
3079 assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
3080 assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
3081 assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
3082 assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
3083 assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
3084 }
3085
3086 #[gpui::test]
3087 fn test_multibuffer_resolving_anchors_after_replacing_their_excerpts(
3088 cx: &mut MutableAppContext,
3089 ) {
3090 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
3091 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "ABCDEFGHIJKLMNOP", cx));
3092 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3093
3094 // Create an insertion id in buffer 1 that doesn't exist in buffer 2.
3095 // Add an excerpt from buffer 1 that spans this new insertion.
3096 buffer_1.update(cx, |buffer, cx| buffer.edit([4..4], "123", cx));
3097 let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| {
3098 multibuffer
3099 .push_excerpts(buffer_1.clone(), [0..7], cx)
3100 .pop()
3101 .unwrap()
3102 });
3103
3104 let snapshot_1 = multibuffer.read(cx).snapshot(cx);
3105 assert_eq!(snapshot_1.text(), "abcd123");
3106
3107 // Replace the buffer 1 excerpt with new excerpts from buffer 2.
3108 let (excerpt_id_2, excerpt_id_3) = multibuffer.update(cx, |multibuffer, cx| {
3109 multibuffer.remove_excerpts([&excerpt_id_1], cx);
3110 let mut ids = multibuffer
3111 .push_excerpts(buffer_2.clone(), [0..4, 6..10, 12..16], cx)
3112 .into_iter();
3113 (ids.next().unwrap(), ids.next().unwrap())
3114 });
3115 let snapshot_2 = multibuffer.read(cx).snapshot(cx);
3116 assert_eq!(snapshot_2.text(), "ABCD\nGHIJ\nMNOP");
3117
3118 // The old excerpt id has been reused.
3119 assert_eq!(excerpt_id_2, excerpt_id_1);
3120
3121 // Resolve some anchors from the previous snapshot in the new snapshot.
3122 // Although there is still an excerpt with the same id, it is for
3123 // a different buffer, so we don't attempt to resolve the old text
3124 // anchor in the new buffer.
3125 assert_eq!(
3126 snapshot_2.summary_for_anchor::<usize>(&snapshot_1.anchor_before(2)),
3127 0
3128 );
3129 assert_eq!(
3130 snapshot_2.summaries_for_anchors::<usize, _>(&[
3131 snapshot_1.anchor_before(2),
3132 snapshot_1.anchor_after(3)
3133 ]),
3134 vec![0, 0]
3135 );
3136 let refresh =
3137 snapshot_2.refresh_anchors(&[snapshot_1.anchor_before(2), snapshot_1.anchor_after(3)]);
3138 assert_eq!(
3139 refresh,
3140 &[
3141 (0, snapshot_2.anchor_before(0), false),
3142 (1, snapshot_2.anchor_after(0), false),
3143 ]
3144 );
3145
3146 // Replace the middle excerpt with a smaller excerpt in buffer 2,
3147 // that intersects the old excerpt.
3148 let excerpt_id_5 = multibuffer.update(cx, |multibuffer, cx| {
3149 multibuffer.remove_excerpts([&excerpt_id_3], cx);
3150 multibuffer
3151 .insert_excerpts_after(&excerpt_id_3, buffer_2.clone(), [5..8], cx)
3152 .pop()
3153 .unwrap()
3154 });
3155
3156 let snapshot_3 = multibuffer.read(cx).snapshot(cx);
3157 assert_eq!(snapshot_3.text(), "ABCD\nFGH\nMNOP");
3158 assert_ne!(excerpt_id_5, excerpt_id_3);
3159
3160 // Resolve some anchors from the previous snapshot in the new snapshot.
3161 // The anchor in the middle excerpt snaps to the beginning of the
3162 // excerpt, since it is not
3163 let anchors = [
3164 snapshot_2.anchor_before(0),
3165 snapshot_2.anchor_after(2),
3166 snapshot_2.anchor_after(6),
3167 snapshot_2.anchor_after(14),
3168 ];
3169 assert_eq!(
3170 snapshot_3.summaries_for_anchors::<usize, _>(&anchors),
3171 &[0, 2, 9, 13]
3172 );
3173
3174 let new_anchors = snapshot_3.refresh_anchors(&anchors);
3175 assert_eq!(
3176 new_anchors.iter().map(|a| (a.0, a.2)).collect::<Vec<_>>(),
3177 &[(0, true), (1, true), (2, true), (3, true)]
3178 );
3179 assert_eq!(
3180 snapshot_3.summaries_for_anchors::<usize, _>(new_anchors.iter().map(|a| &a.1)),
3181 &[0, 2, 7, 13]
3182 );
3183 }
3184
3185 #[gpui::test(iterations = 100)]
3186 fn test_random_multibuffer(cx: &mut MutableAppContext, mut rng: StdRng) {
3187 let operations = env::var("OPERATIONS")
3188 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
3189 .unwrap_or(10);
3190
3191 let mut buffers: Vec<ModelHandle<Buffer>> = Vec::new();
3192 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3193 let mut excerpt_ids = Vec::new();
3194 let mut expected_excerpts = Vec::<(ModelHandle<Buffer>, Range<text::Anchor>)>::new();
3195 let mut anchors = Vec::new();
3196 let mut old_versions = Vec::new();
3197
3198 for _ in 0..operations {
3199 match rng.gen_range(0..100) {
3200 0..=19 if !buffers.is_empty() => {
3201 let buffer = buffers.choose(&mut rng).unwrap();
3202 buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
3203 }
3204 20..=29 if !expected_excerpts.is_empty() => {
3205 let mut ids_to_remove = vec![];
3206 for _ in 0..rng.gen_range(1..=3) {
3207 if expected_excerpts.is_empty() {
3208 break;
3209 }
3210
3211 let ix = rng.gen_range(0..expected_excerpts.len());
3212 ids_to_remove.push(excerpt_ids.remove(ix));
3213 let (buffer, range) = expected_excerpts.remove(ix);
3214 let buffer = buffer.read(cx);
3215 log::info!(
3216 "Removing excerpt {}: {:?}",
3217 ix,
3218 buffer
3219 .text_for_range(range.to_offset(&buffer))
3220 .collect::<String>(),
3221 );
3222 }
3223 ids_to_remove.sort_unstable();
3224 multibuffer.update(cx, |multibuffer, cx| {
3225 multibuffer.remove_excerpts(&ids_to_remove, cx)
3226 });
3227 }
3228 30..=39 if !expected_excerpts.is_empty() => {
3229 let multibuffer = multibuffer.read(cx).read(cx);
3230 let offset =
3231 multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left);
3232 let bias = if rng.gen() { Bias::Left } else { Bias::Right };
3233 log::info!("Creating anchor at {} with bias {:?}", offset, bias);
3234 anchors.push(multibuffer.anchor_at(offset, bias));
3235 anchors.sort_by(|a, b| a.cmp(&b, &multibuffer).unwrap());
3236 }
3237 40..=44 if !anchors.is_empty() => {
3238 let multibuffer = multibuffer.read(cx).read(cx);
3239
3240 anchors = multibuffer
3241 .refresh_anchors(&anchors)
3242 .into_iter()
3243 .map(|a| a.1)
3244 .collect();
3245
3246 // Ensure the newly-refreshed anchors point to a valid excerpt and don't
3247 // overshoot its boundaries.
3248 let mut cursor = multibuffer.excerpts.cursor::<Option<&ExcerptId>>();
3249 for anchor in &anchors {
3250 if anchor.excerpt_id == ExcerptId::min()
3251 || anchor.excerpt_id == ExcerptId::max()
3252 {
3253 continue;
3254 }
3255
3256 cursor.seek_forward(&Some(&anchor.excerpt_id), Bias::Left, &());
3257 let excerpt = cursor.item().unwrap();
3258 assert_eq!(excerpt.id, anchor.excerpt_id);
3259 assert!(excerpt.contains(anchor));
3260 }
3261 }
3262 _ => {
3263 let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
3264 let base_text = RandomCharIter::new(&mut rng).take(10).collect::<String>();
3265 buffers.push(cx.add_model(|cx| Buffer::new(0, base_text, cx)));
3266 buffers.last().unwrap()
3267 } else {
3268 buffers.choose(&mut rng).unwrap()
3269 };
3270
3271 let buffer = buffer_handle.read(cx);
3272 let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
3273 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
3274 let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
3275 let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len());
3276 let prev_excerpt_id = excerpt_ids
3277 .get(prev_excerpt_ix)
3278 .cloned()
3279 .unwrap_or(ExcerptId::max());
3280 let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len());
3281
3282 log::info!(
3283 "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}",
3284 excerpt_ix,
3285 expected_excerpts.len(),
3286 buffer_handle.id(),
3287 buffer.text(),
3288 start_ix..end_ix,
3289 &buffer.text()[start_ix..end_ix]
3290 );
3291
3292 let excerpt_id = multibuffer.update(cx, |multibuffer, cx| {
3293 multibuffer
3294 .insert_excerpts_after(
3295 &prev_excerpt_id,
3296 buffer_handle.clone(),
3297 [start_ix..end_ix],
3298 cx,
3299 )
3300 .pop()
3301 .unwrap()
3302 });
3303
3304 excerpt_ids.insert(excerpt_ix, excerpt_id);
3305 expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range));
3306 }
3307 }
3308
3309 if rng.gen_bool(0.3) {
3310 multibuffer.update(cx, |multibuffer, cx| {
3311 old_versions.push((multibuffer.snapshot(cx), multibuffer.subscribe()));
3312 })
3313 }
3314
3315 let snapshot = multibuffer.read(cx).snapshot(cx);
3316
3317 let mut excerpt_starts = Vec::new();
3318 let mut expected_text = String::new();
3319 let mut expected_buffer_rows = Vec::new();
3320 for (buffer, range) in &expected_excerpts {
3321 let buffer = buffer.read(cx);
3322 let buffer_range = range.to_offset(buffer);
3323
3324 excerpt_starts.push(TextSummary::from(expected_text.as_str()));
3325 expected_text.extend(buffer.text_for_range(buffer_range.clone()));
3326 expected_text.push('\n');
3327
3328 let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
3329 ..=buffer.offset_to_point(buffer_range.end).row;
3330 for row in buffer_row_range {
3331 expected_buffer_rows.push(Some(row));
3332 }
3333 }
3334 // Remove final trailing newline.
3335 if !expected_excerpts.is_empty() {
3336 expected_text.pop();
3337 }
3338
3339 // Always report one buffer row
3340 if expected_buffer_rows.is_empty() {
3341 expected_buffer_rows.push(Some(0));
3342 }
3343
3344 assert_eq!(snapshot.text(), expected_text);
3345 log::info!("MultiBuffer text: {:?}", expected_text);
3346
3347 assert_eq!(
3348 snapshot.buffer_rows(0).collect::<Vec<_>>(),
3349 expected_buffer_rows,
3350 );
3351
3352 for _ in 0..5 {
3353 let start_row = rng.gen_range(0..=expected_buffer_rows.len());
3354 assert_eq!(
3355 snapshot.buffer_rows(start_row as u32).collect::<Vec<_>>(),
3356 &expected_buffer_rows[start_row..],
3357 "buffer_rows({})",
3358 start_row
3359 );
3360 }
3361
3362 assert_eq!(
3363 snapshot.max_buffer_row(),
3364 expected_buffer_rows
3365 .into_iter()
3366 .filter_map(|r| r)
3367 .max()
3368 .unwrap()
3369 );
3370
3371 let mut excerpt_starts = excerpt_starts.into_iter();
3372 for (buffer, range) in &expected_excerpts {
3373 let buffer_id = buffer.id();
3374 let buffer = buffer.read(cx);
3375 let buffer_range = range.to_offset(buffer);
3376 let buffer_start_point = buffer.offset_to_point(buffer_range.start);
3377 let buffer_start_point_utf16 =
3378 buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
3379
3380 let excerpt_start = excerpt_starts.next().unwrap();
3381 let mut offset = excerpt_start.bytes;
3382 let mut buffer_offset = buffer_range.start;
3383 let mut point = excerpt_start.lines;
3384 let mut buffer_point = buffer_start_point;
3385 let mut point_utf16 = excerpt_start.lines_utf16;
3386 let mut buffer_point_utf16 = buffer_start_point_utf16;
3387 for ch in buffer
3388 .snapshot()
3389 .chunks(buffer_range.clone(), false)
3390 .flat_map(|c| c.text.chars())
3391 {
3392 for _ in 0..ch.len_utf8() {
3393 let left_offset = snapshot.clip_offset(offset, Bias::Left);
3394 let right_offset = snapshot.clip_offset(offset, Bias::Right);
3395 let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
3396 let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
3397 assert_eq!(
3398 left_offset,
3399 excerpt_start.bytes + (buffer_left_offset - buffer_range.start),
3400 "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
3401 offset,
3402 buffer_id,
3403 buffer_offset,
3404 );
3405 assert_eq!(
3406 right_offset,
3407 excerpt_start.bytes + (buffer_right_offset - buffer_range.start),
3408 "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
3409 offset,
3410 buffer_id,
3411 buffer_offset,
3412 );
3413
3414 let left_point = snapshot.clip_point(point, Bias::Left);
3415 let right_point = snapshot.clip_point(point, Bias::Right);
3416 let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
3417 let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
3418 assert_eq!(
3419 left_point,
3420 excerpt_start.lines + (buffer_left_point - buffer_start_point),
3421 "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
3422 point,
3423 buffer_id,
3424 buffer_point,
3425 );
3426 assert_eq!(
3427 right_point,
3428 excerpt_start.lines + (buffer_right_point - buffer_start_point),
3429 "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
3430 point,
3431 buffer_id,
3432 buffer_point,
3433 );
3434
3435 assert_eq!(
3436 snapshot.point_to_offset(left_point),
3437 left_offset,
3438 "point_to_offset({:?})",
3439 left_point,
3440 );
3441 assert_eq!(
3442 snapshot.offset_to_point(left_offset),
3443 left_point,
3444 "offset_to_point({:?})",
3445 left_offset,
3446 );
3447
3448 offset += 1;
3449 buffer_offset += 1;
3450 if ch == '\n' {
3451 point += Point::new(1, 0);
3452 buffer_point += Point::new(1, 0);
3453 } else {
3454 point += Point::new(0, 1);
3455 buffer_point += Point::new(0, 1);
3456 }
3457 }
3458
3459 for _ in 0..ch.len_utf16() {
3460 let left_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Left);
3461 let right_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Right);
3462 let buffer_left_point_utf16 =
3463 buffer.clip_point_utf16(buffer_point_utf16, Bias::Left);
3464 let buffer_right_point_utf16 =
3465 buffer.clip_point_utf16(buffer_point_utf16, Bias::Right);
3466 assert_eq!(
3467 left_point_utf16,
3468 excerpt_start.lines_utf16
3469 + (buffer_left_point_utf16 - buffer_start_point_utf16),
3470 "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
3471 point_utf16,
3472 buffer_id,
3473 buffer_point_utf16,
3474 );
3475 assert_eq!(
3476 right_point_utf16,
3477 excerpt_start.lines_utf16
3478 + (buffer_right_point_utf16 - buffer_start_point_utf16),
3479 "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
3480 point_utf16,
3481 buffer_id,
3482 buffer_point_utf16,
3483 );
3484
3485 if ch == '\n' {
3486 point_utf16 += PointUtf16::new(1, 0);
3487 buffer_point_utf16 += PointUtf16::new(1, 0);
3488 } else {
3489 point_utf16 += PointUtf16::new(0, 1);
3490 buffer_point_utf16 += PointUtf16::new(0, 1);
3491 }
3492 }
3493 }
3494 }
3495
3496 for (row, line) in expected_text.split('\n').enumerate() {
3497 assert_eq!(
3498 snapshot.line_len(row as u32),
3499 line.len() as u32,
3500 "line_len({}).",
3501 row
3502 );
3503 }
3504
3505 let text_rope = Rope::from(expected_text.as_str());
3506 for _ in 0..10 {
3507 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
3508 let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
3509
3510 let text_for_range = snapshot
3511 .text_for_range(start_ix..end_ix)
3512 .collect::<String>();
3513 assert_eq!(
3514 text_for_range,
3515 &expected_text[start_ix..end_ix],
3516 "incorrect text for range {:?}",
3517 start_ix..end_ix
3518 );
3519
3520 let excerpted_buffer_ranges =
3521 multibuffer.read(cx).excerpted_buffers(start_ix..end_ix, cx);
3522 let excerpted_buffers_text = excerpted_buffer_ranges
3523 .into_iter()
3524 .map(|(buffer, buffer_range)| {
3525 buffer
3526 .read(cx)
3527 .text_for_range(buffer_range)
3528 .collect::<String>()
3529 })
3530 .collect::<Vec<_>>()
3531 .join("\n");
3532 assert_eq!(excerpted_buffers_text, text_for_range);
3533
3534 let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
3535 assert_eq!(
3536 snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
3537 expected_summary,
3538 "incorrect summary for range {:?}",
3539 start_ix..end_ix
3540 );
3541 }
3542
3543 // Anchor resolution
3544 for (anchor, resolved_offset) in anchors
3545 .iter()
3546 .zip(snapshot.summaries_for_anchors::<usize, _>(&anchors))
3547 {
3548 assert!(resolved_offset <= snapshot.len());
3549 assert_eq!(
3550 snapshot.summary_for_anchor::<usize>(anchor),
3551 resolved_offset
3552 );
3553 }
3554
3555 for _ in 0..10 {
3556 let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
3557 assert_eq!(
3558 snapshot.reversed_chars_at(end_ix).collect::<String>(),
3559 expected_text[..end_ix].chars().rev().collect::<String>(),
3560 );
3561 }
3562
3563 for _ in 0..10 {
3564 let end_ix = rng.gen_range(0..=text_rope.len());
3565 let start_ix = rng.gen_range(0..=end_ix);
3566 assert_eq!(
3567 snapshot
3568 .bytes_in_range(start_ix..end_ix)
3569 .flatten()
3570 .copied()
3571 .collect::<Vec<_>>(),
3572 expected_text.as_bytes()[start_ix..end_ix].to_vec(),
3573 "bytes_in_range({:?})",
3574 start_ix..end_ix,
3575 );
3576 }
3577 }
3578
3579 let snapshot = multibuffer.read(cx).snapshot(cx);
3580 for (old_snapshot, subscription) in old_versions {
3581 let edits = subscription.consume().into_inner();
3582
3583 log::info!(
3584 "applying subscription edits to old text: {:?}: {:?}",
3585 old_snapshot.text(),
3586 edits,
3587 );
3588
3589 let mut text = old_snapshot.text();
3590 for edit in edits {
3591 let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
3592 text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
3593 }
3594 assert_eq!(text.to_string(), snapshot.text());
3595 }
3596 }
3597
3598 #[gpui::test]
3599 fn test_history(cx: &mut MutableAppContext) {
3600 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "1234", cx));
3601 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "5678", cx));
3602 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3603 let group_interval = multibuffer.read(cx).history.group_interval;
3604 multibuffer.update(cx, |multibuffer, cx| {
3605 multibuffer.push_excerpts(buffer_1.clone(), [0..buffer_1.read(cx).len()], cx);
3606 multibuffer.push_excerpts(buffer_2.clone(), [0..buffer_2.read(cx).len()], cx);
3607 });
3608
3609 let mut now = Instant::now();
3610
3611 multibuffer.update(cx, |multibuffer, cx| {
3612 multibuffer.start_transaction_at(now, cx);
3613 multibuffer.edit(
3614 [
3615 Point::new(0, 0)..Point::new(0, 0),
3616 Point::new(1, 0)..Point::new(1, 0),
3617 ],
3618 "A",
3619 cx,
3620 );
3621 multibuffer.edit(
3622 [
3623 Point::new(0, 1)..Point::new(0, 1),
3624 Point::new(1, 1)..Point::new(1, 1),
3625 ],
3626 "B",
3627 cx,
3628 );
3629 multibuffer.end_transaction_at(now, cx);
3630 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
3631
3632 now += 2 * group_interval;
3633 multibuffer.start_transaction_at(now, cx);
3634 multibuffer.edit([2..2], "C", cx);
3635 multibuffer.end_transaction_at(now, cx);
3636 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
3637
3638 multibuffer.undo(cx);
3639 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
3640
3641 multibuffer.undo(cx);
3642 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
3643
3644 multibuffer.redo(cx);
3645 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
3646
3647 multibuffer.redo(cx);
3648 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
3649
3650 buffer_1.update(cx, |buffer_1, cx| buffer_1.undo(cx));
3651 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
3652
3653 multibuffer.undo(cx);
3654 assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
3655
3656 multibuffer.redo(cx);
3657 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
3658
3659 multibuffer.redo(cx);
3660 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
3661
3662 multibuffer.undo(cx);
3663 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
3664
3665 buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
3666 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
3667
3668 multibuffer.undo(cx);
3669 assert_eq!(multibuffer.read(cx).text(), "C1234\n5678");
3670 });
3671 }
3672}