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