1mod anchor;
2
3pub use anchor::{Anchor, AnchorRangeExt};
4use anyhow::Result;
5use clock::ReplicaId;
6use collections::{HashMap, HashSet};
7use gpui::{AppContext, ElementBox, Entity, ModelContext, ModelHandle, MutableAppContext, Task};
8use language::{
9 Buffer, BufferChunks, BufferSnapshot, Chunk, DiagnosticEntry, Event, File, Language, Selection,
10 ToOffset as _, ToPoint as _, TransactionId,
11};
12use std::{
13 cell::{Ref, RefCell},
14 cmp, fmt, io,
15 iter::{self, FromIterator},
16 ops::{Range, Sub},
17 str,
18 sync::Arc,
19 time::{Duration, Instant, SystemTime},
20};
21use sum_tree::{Bias, Cursor, SumTree};
22use text::{
23 locator::Locator,
24 rope::TextDimension,
25 subscription::{Subscription, Topic},
26 AnchorRangeExt as _, Edit, Point, PointUtf16, TextSummary,
27};
28use theme::SyntaxTheme;
29use util::post_inc;
30
31const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize];
32
33pub type ExcerptId = Locator;
34
35pub struct MultiBuffer {
36 snapshot: RefCell<MultiBufferSnapshot>,
37 buffers: HashMap<usize, BufferState>,
38 subscriptions: Topic,
39 singleton: bool,
40 replica_id: ReplicaId,
41 history: History,
42}
43
44struct History {
45 next_transaction_id: usize,
46 undo_stack: Vec<Transaction>,
47 redo_stack: Vec<Transaction>,
48 transaction_depth: usize,
49 group_interval: Duration,
50}
51
52struct Transaction {
53 id: usize,
54 buffer_transactions: HashSet<(usize, text::TransactionId)>,
55 first_edit_at: Instant,
56 last_edit_at: Instant,
57}
58
59pub trait ToOffset: 'static + fmt::Debug {
60 fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
61}
62
63pub trait ToPoint: 'static + fmt::Debug {
64 fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point;
65}
66
67pub trait FromAnchor: 'static {
68 fn from_anchor(anchor: &Anchor, snapshot: &MultiBufferSnapshot) -> Self;
69}
70
71#[derive(Debug)]
72struct BufferState {
73 buffer: ModelHandle<Buffer>,
74 last_version: clock::Global,
75 last_parse_count: usize,
76 last_diagnostics_update_count: usize,
77 excerpts: Vec<ExcerptId>,
78}
79
80#[derive(Clone, Default)]
81pub struct MultiBufferSnapshot {
82 excerpts: SumTree<Excerpt>,
83 parse_count: usize,
84 diagnostics_update_count: usize,
85}
86
87pub type RenderHeaderFn = Arc<dyn 'static + Send + Sync + Fn(&AppContext) -> ElementBox>;
88
89pub struct ExcerptProperties<'a, T> {
90 pub buffer: &'a ModelHandle<Buffer>,
91 pub range: Range<T>,
92 pub header_height: u8,
93 pub render_header: Option<RenderHeaderFn>,
94}
95
96#[derive(Clone)]
97struct Excerpt {
98 id: ExcerptId,
99 buffer_id: usize,
100 buffer: BufferSnapshot,
101 range: Range<text::Anchor>,
102 render_header: Option<RenderHeaderFn>,
103 text_summary: TextSummary,
104 header_height: u8,
105 has_trailing_newline: bool,
106}
107
108#[derive(Clone, Debug, Default)]
109struct ExcerptSummary {
110 excerpt_id: ExcerptId,
111 text: TextSummary,
112}
113
114pub struct MultiBufferChunks<'a> {
115 range: Range<usize>,
116 cursor: Cursor<'a, Excerpt, usize>,
117 header_height: u8,
118 has_trailing_newline: bool,
119 excerpt_chunks: Option<BufferChunks<'a>>,
120 theme: Option<&'a SyntaxTheme>,
121}
122
123pub struct MultiBufferBytes<'a> {
124 range: Range<usize>,
125 excerpts: Cursor<'a, Excerpt, usize>,
126 excerpt_chunks: Option<language::rope::Bytes<'a>>,
127 excerpt_chunk: &'a [u8],
128}
129
130impl MultiBuffer {
131 pub fn new(replica_id: ReplicaId) -> Self {
132 Self {
133 snapshot: Default::default(),
134 buffers: Default::default(),
135 subscriptions: Default::default(),
136 singleton: false,
137 replica_id,
138 history: History {
139 next_transaction_id: Default::default(),
140 undo_stack: Default::default(),
141 redo_stack: Default::default(),
142 transaction_depth: 0,
143 group_interval: Duration::from_millis(300),
144 },
145 }
146 }
147
148 pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
149 let mut this = Self::new(buffer.read(cx).replica_id());
150 this.singleton = true;
151 this.push_excerpt(
152 ExcerptProperties {
153 buffer: &buffer,
154 range: text::Anchor::min()..text::Anchor::max(),
155 header_height: 0,
156 render_header: None,
157 },
158 cx,
159 );
160 this
161 }
162
163 pub fn build_simple(text: &str, cx: &mut MutableAppContext) -> ModelHandle<Self> {
164 let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
165 cx.add_model(|cx| Self::singleton(buffer, cx))
166 }
167
168 pub fn replica_id(&self) -> ReplicaId {
169 self.replica_id
170 }
171
172 pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot {
173 self.sync(cx);
174 self.snapshot.borrow().clone()
175 }
176
177 pub fn read(&self, cx: &AppContext) -> Ref<MultiBufferSnapshot> {
178 self.sync(cx);
179 self.snapshot.borrow()
180 }
181
182 pub fn as_singleton(&self) -> Option<&ModelHandle<Buffer>> {
183 if self.singleton {
184 return Some(&self.buffers.values().next().unwrap().buffer);
185 } else {
186 None
187 }
188 }
189
190 pub fn subscribe(&mut self) -> Subscription {
191 self.subscriptions.subscribe()
192 }
193
194 pub fn edit<I, S, T>(&mut self, ranges: I, new_text: T, cx: &mut ModelContext<Self>)
195 where
196 I: IntoIterator<Item = Range<S>>,
197 S: ToOffset,
198 T: Into<String>,
199 {
200 self.edit_internal(ranges, new_text, false, cx)
201 }
202
203 pub fn edit_with_autoindent<I, S, T>(
204 &mut self,
205 ranges: I,
206 new_text: T,
207 cx: &mut ModelContext<Self>,
208 ) where
209 I: IntoIterator<Item = Range<S>>,
210 S: ToOffset,
211 T: Into<String>,
212 {
213 self.edit_internal(ranges, new_text, true, cx)
214 }
215
216 pub fn edit_internal<I, S, T>(
217 &mut self,
218 ranges_iter: I,
219 new_text: T,
220 autoindent: bool,
221 cx: &mut ModelContext<Self>,
222 ) where
223 I: IntoIterator<Item = Range<S>>,
224 S: ToOffset,
225 T: Into<String>,
226 {
227 if let Some(buffer) = self.as_singleton() {
228 let snapshot = self.read(cx);
229 let ranges = ranges_iter
230 .into_iter()
231 .map(|range| range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot));
232 return buffer.update(cx, |buffer, cx| {
233 if autoindent {
234 buffer.edit_with_autoindent(ranges, new_text, cx)
235 } else {
236 buffer.edit(ranges, new_text, cx)
237 }
238 });
239 }
240
241 let snapshot = self.read(cx);
242 let mut buffer_edits: HashMap<usize, Vec<(Range<usize>, bool)>> = Default::default();
243 let mut cursor = snapshot.excerpts.cursor::<usize>();
244 for range in ranges_iter {
245 let start = range.start.to_offset(&snapshot);
246 let end = range.end.to_offset(&snapshot);
247 cursor.seek(&start, Bias::Right, &());
248 let start_excerpt = cursor.item().expect("start offset out of bounds");
249 let start_overshoot =
250 (start - cursor.start()).saturating_sub(start_excerpt.header_height as usize);
251 let buffer_start =
252 start_excerpt.range.start.to_offset(&start_excerpt.buffer) + start_overshoot;
253
254 cursor.seek(&end, Bias::Right, &());
255 let end_excerpt = cursor.item().expect("end offset out of bounds");
256 let end_overshoot =
257 (end - cursor.start()).saturating_sub(end_excerpt.header_height as usize);
258 let buffer_end = end_excerpt.range.start.to_offset(&end_excerpt.buffer) + end_overshoot;
259
260 if start_excerpt.id == end_excerpt.id {
261 buffer_edits
262 .entry(start_excerpt.buffer_id)
263 .or_insert(Vec::new())
264 .push((buffer_start..buffer_end, true));
265 } else {
266 let start_excerpt_range =
267 buffer_start..start_excerpt.range.end.to_offset(&start_excerpt.buffer);
268 let end_excerpt_range =
269 end_excerpt.range.start.to_offset(&end_excerpt.buffer)..buffer_end;
270 buffer_edits
271 .entry(start_excerpt.buffer_id)
272 .or_insert(Vec::new())
273 .push((start_excerpt_range, true));
274 buffer_edits
275 .entry(end_excerpt.buffer_id)
276 .or_insert(Vec::new())
277 .push((end_excerpt_range, false));
278
279 cursor.seek(&start, Bias::Right, &());
280 cursor.next(&());
281 while let Some(excerpt) = cursor.item() {
282 if excerpt.id == end_excerpt.id {
283 break;
284 }
285
286 let excerpt_range = start_excerpt.range.end.to_offset(&start_excerpt.buffer)
287 ..start_excerpt.range.end.to_offset(&start_excerpt.buffer);
288 buffer_edits
289 .entry(excerpt.buffer_id)
290 .or_insert(Vec::new())
291 .push((excerpt_range, false));
292 cursor.next(&());
293 }
294 }
295 }
296
297 let new_text = new_text.into();
298 for (buffer_id, mut edits) in buffer_edits {
299 edits.sort_unstable_by_key(|(range, _)| range.start);
300 self.buffers[&buffer_id].buffer.update(cx, |buffer, cx| {
301 let mut edits = edits.into_iter().peekable();
302 let mut insertions = Vec::new();
303 let mut deletions = Vec::new();
304 while let Some((mut range, mut is_insertion)) = edits.next() {
305 while let Some((next_range, next_is_insertion)) = edits.peek() {
306 if range.end >= next_range.start {
307 range.end = cmp::max(next_range.end, range.end);
308 is_insertion |= *next_is_insertion;
309 edits.next();
310 } else {
311 break;
312 }
313 }
314
315 if is_insertion {
316 insertions.push(
317 buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
318 );
319 } else {
320 deletions.push(
321 buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
322 );
323 }
324 }
325
326 if autoindent {
327 buffer.edit_with_autoindent(deletions, "", cx);
328 buffer.edit_with_autoindent(insertions, new_text.clone(), cx);
329 } else {
330 buffer.edit(deletions, "", cx);
331 buffer.edit(insertions, new_text.clone(), cx);
332 }
333 })
334 }
335 }
336
337 pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
338 self.start_transaction_at(Instant::now(), cx)
339 }
340
341 pub(crate) fn start_transaction_at(
342 &mut self,
343 now: Instant,
344 cx: &mut ModelContext<Self>,
345 ) -> Option<TransactionId> {
346 if let Some(buffer) = self.as_singleton() {
347 return buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
348 }
349
350 for BufferState { buffer, .. } in self.buffers.values() {
351 buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
352 }
353 self.history.start_transaction(now)
354 }
355
356 pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
357 self.end_transaction_at(Instant::now(), cx)
358 }
359
360 pub(crate) fn end_transaction_at(
361 &mut self,
362 now: Instant,
363 cx: &mut ModelContext<Self>,
364 ) -> Option<TransactionId> {
365 if let Some(buffer) = self.as_singleton() {
366 return buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx));
367 }
368
369 let mut buffer_transactions = HashSet::default();
370 for BufferState { buffer, .. } in self.buffers.values() {
371 if let Some(transaction_id) =
372 buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
373 {
374 buffer_transactions.insert((buffer.id(), transaction_id));
375 }
376 }
377
378 if self.history.end_transaction(now, buffer_transactions) {
379 let transaction_id = self.history.group().unwrap();
380 Some(transaction_id)
381 } else {
382 None
383 }
384 }
385
386 pub fn set_active_selections(
387 &mut self,
388 selections: &[Selection<Anchor>],
389 cx: &mut ModelContext<Self>,
390 ) {
391 let mut selections_by_buffer: HashMap<usize, Vec<Selection<text::Anchor>>> =
392 Default::default();
393 let snapshot = self.read(cx);
394 let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();
395 for selection in selections {
396 cursor.seek(&Some(&selection.start.excerpt_id), Bias::Left, &());
397 while let Some(excerpt) = cursor.item() {
398 if excerpt.id > selection.end.excerpt_id {
399 break;
400 }
401
402 let mut start = excerpt.range.start.clone();
403 let mut end = excerpt.range.end.clone();
404 if excerpt.id == selection.start.excerpt_id {
405 start = selection.start.text_anchor.clone();
406 }
407 if excerpt.id == selection.end.excerpt_id {
408 end = selection.end.text_anchor.clone();
409 }
410 selections_by_buffer
411 .entry(excerpt.buffer_id)
412 .or_default()
413 .push(Selection {
414 id: selection.id,
415 start,
416 end,
417 reversed: selection.reversed,
418 goal: selection.goal,
419 });
420
421 cursor.next(&());
422 }
423 }
424
425 for (buffer_id, mut selections) in selections_by_buffer {
426 self.buffers[&buffer_id].buffer.update(cx, |buffer, cx| {
427 selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap());
428 let mut selections = selections.into_iter().peekable();
429 let merged_selections = Arc::from_iter(iter::from_fn(|| {
430 let mut selection = selections.next()?;
431 while let Some(next_selection) = selections.peek() {
432 if selection
433 .end
434 .cmp(&next_selection.start, buffer)
435 .unwrap()
436 .is_ge()
437 {
438 let next_selection = selections.next().unwrap();
439 if next_selection
440 .end
441 .cmp(&selection.end, buffer)
442 .unwrap()
443 .is_ge()
444 {
445 selection.end = next_selection.end;
446 }
447 } else {
448 break;
449 }
450 }
451 Some(selection)
452 }));
453 buffer.set_active_selections(merged_selections, cx);
454 });
455 }
456 }
457
458 pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
459 for buffer in self.buffers.values() {
460 buffer
461 .buffer
462 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
463 }
464 }
465
466 pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
467 if let Some(buffer) = self.as_singleton() {
468 return buffer.update(cx, |buffer, cx| buffer.undo(cx));
469 }
470
471 while let Some(transaction) = self.history.pop_undo() {
472 let mut undone = false;
473 for (buffer_id, buffer_transaction_id) in &transaction.buffer_transactions {
474 if let Some(BufferState { buffer, .. }) = self.buffers.get(&buffer_id) {
475 undone |= buffer.update(cx, |buf, cx| {
476 buf.undo_transaction(*buffer_transaction_id, cx)
477 });
478 }
479 }
480
481 if undone {
482 return Some(transaction.id);
483 }
484 }
485
486 None
487 }
488
489 pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
490 if let Some(buffer) = self.as_singleton() {
491 return buffer.update(cx, |buffer, cx| buffer.redo(cx));
492 }
493
494 while let Some(transaction) = self.history.pop_redo() {
495 let mut redone = false;
496 for (buffer_id, buffer_transaction_id) in &transaction.buffer_transactions {
497 if let Some(BufferState { buffer, .. }) = self.buffers.get(&buffer_id) {
498 redone |= buffer.update(cx, |buf, cx| {
499 buf.redo_transaction(*buffer_transaction_id, cx)
500 });
501 }
502 }
503
504 if redone {
505 return Some(transaction.id);
506 }
507 }
508
509 None
510 }
511
512 pub fn push_excerpt<O>(
513 &mut self,
514 props: ExcerptProperties<O>,
515 cx: &mut ModelContext<Self>,
516 ) -> ExcerptId
517 where
518 O: text::ToOffset,
519 {
520 assert_eq!(self.history.transaction_depth, 0);
521 self.sync(cx);
522
523 let buffer = props.buffer.clone();
524 cx.subscribe(&buffer, Self::on_buffer_event).detach();
525
526 let buffer_snapshot = buffer.read(cx).snapshot();
527 let range = buffer_snapshot.anchor_before(&props.range.start)
528 ..buffer_snapshot.anchor_after(&props.range.end);
529 let last_version = buffer_snapshot.version().clone();
530 let last_parse_count = buffer_snapshot.parse_count();
531 let last_diagnostics_update_count = buffer_snapshot.diagnostics_update_count();
532
533 let mut snapshot = self.snapshot.borrow_mut();
534 let prev_id = snapshot.excerpts.last().map(|e| &e.id);
535 let id = ExcerptId::between(prev_id.unwrap_or(&ExcerptId::min()), &ExcerptId::max());
536
537 let edit_start = snapshot.excerpts.summary().text.bytes;
538 let excerpt = Excerpt::new(
539 id.clone(),
540 buffer.id(),
541 buffer_snapshot,
542 range,
543 props.header_height,
544 props.render_header,
545 !self.singleton,
546 );
547 let edit = Edit {
548 old: edit_start..edit_start,
549 new: edit_start..edit_start + excerpt.text_summary.bytes,
550 };
551 snapshot.excerpts.push(excerpt, &());
552 self.buffers
553 .entry(props.buffer.id())
554 .or_insert_with(|| BufferState {
555 buffer,
556 last_version,
557 last_parse_count,
558 last_diagnostics_update_count,
559 excerpts: Default::default(),
560 })
561 .excerpts
562 .push(id.clone());
563
564 self.subscriptions.publish_mut([edit]);
565
566 cx.notify();
567
568 id
569 }
570
571 fn on_buffer_event(
572 &mut self,
573 _: ModelHandle<Buffer>,
574 event: &Event,
575 cx: &mut ModelContext<Self>,
576 ) {
577 cx.emit(event.clone());
578 }
579
580 pub fn save(
581 &mut self,
582 cx: &mut ModelContext<Self>,
583 ) -> Result<Task<Result<(clock::Global, SystemTime)>>> {
584 self.as_singleton()
585 .unwrap()
586 .update(cx, |buffer, cx| buffer.save(cx))
587 }
588
589 pub fn language<'a>(&self, cx: &'a AppContext) -> Option<&'a Arc<Language>> {
590 self.buffers
591 .values()
592 .next()
593 .and_then(|state| state.buffer.read(cx).language())
594 }
595
596 pub fn file<'a>(&self, cx: &'a AppContext) -> Option<&'a dyn File> {
597 self.as_singleton().unwrap().read(cx).file()
598 }
599
600 pub fn is_dirty(&self, cx: &AppContext) -> bool {
601 self.as_singleton().unwrap().read(cx).is_dirty()
602 }
603
604 pub fn has_conflict(&self, cx: &AppContext) -> bool {
605 self.as_singleton().unwrap().read(cx).has_conflict()
606 }
607
608 pub fn is_parsing(&self, cx: &AppContext) -> bool {
609 self.as_singleton().unwrap().read(cx).is_parsing()
610 }
611
612 fn sync(&self, cx: &AppContext) {
613 let mut snapshot = self.snapshot.borrow_mut();
614 let mut excerpts_to_edit = Vec::new();
615 let mut reparsed = false;
616 let mut diagnostics_updated = false;
617 for buffer_state in self.buffers.values() {
618 let buffer = buffer_state.buffer.read(cx);
619 let buffer_edited = buffer.version().gt(&buffer_state.last_version);
620 let buffer_reparsed = buffer.parse_count() > buffer_state.last_parse_count;
621 let buffer_diagnostics_updated =
622 buffer.diagnostics_update_count() > buffer_state.last_diagnostics_update_count;
623 if buffer_edited || buffer_reparsed || buffer_diagnostics_updated {
624 excerpts_to_edit.extend(
625 buffer_state
626 .excerpts
627 .iter()
628 .map(|excerpt_id| (excerpt_id, buffer_state, buffer_edited)),
629 );
630 }
631
632 reparsed |= buffer_reparsed;
633 diagnostics_updated |= buffer_diagnostics_updated;
634 }
635 if reparsed {
636 snapshot.parse_count += 1;
637 }
638 if diagnostics_updated {
639 snapshot.diagnostics_update_count += 1;
640 }
641 excerpts_to_edit.sort_unstable_by_key(|(excerpt_id, _, _)| *excerpt_id);
642
643 let mut edits = Vec::new();
644 let mut new_excerpts = SumTree::new();
645 let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>();
646
647 for (id, buffer_state, buffer_edited) in excerpts_to_edit {
648 new_excerpts.push_tree(cursor.slice(&Some(id), Bias::Left, &()), &());
649 let old_excerpt = cursor.item().unwrap();
650 let buffer = buffer_state.buffer.read(cx);
651
652 let mut new_excerpt;
653 if buffer_edited {
654 edits.extend(
655 buffer
656 .edits_since_in_range::<usize>(
657 old_excerpt.buffer.version(),
658 old_excerpt.range.clone(),
659 )
660 .map(|mut edit| {
661 let excerpt_old_start =
662 cursor.start().1 + old_excerpt.header_height as usize;
663 let excerpt_new_start = new_excerpts.summary().text.bytes
664 + old_excerpt.header_height as usize;
665 edit.old.start += excerpt_old_start;
666 edit.old.end += excerpt_old_start;
667 edit.new.start += excerpt_new_start;
668 edit.new.end += excerpt_new_start;
669 edit
670 }),
671 );
672
673 new_excerpt = Excerpt::new(
674 id.clone(),
675 buffer_state.buffer.id(),
676 buffer.snapshot(),
677 old_excerpt.range.clone(),
678 old_excerpt.header_height,
679 old_excerpt.render_header.clone(),
680 !self.singleton,
681 );
682 } else {
683 new_excerpt = old_excerpt.clone();
684 new_excerpt.buffer = buffer.snapshot();
685 }
686
687 new_excerpts.push(new_excerpt, &());
688 cursor.next(&());
689 }
690 new_excerpts.push_tree(cursor.suffix(&()), &());
691
692 drop(cursor);
693 snapshot.excerpts = new_excerpts;
694
695 self.subscriptions.publish(edits);
696 }
697}
698
699#[cfg(any(test, feature = "test-support"))]
700impl MultiBuffer {
701 pub fn randomly_edit<R: rand::Rng>(
702 &mut self,
703 rng: &mut R,
704 count: usize,
705 cx: &mut ModelContext<Self>,
706 ) {
707 self.as_singleton()
708 .unwrap()
709 .update(cx, |buffer, cx| buffer.randomly_edit(rng, count, cx));
710 self.sync(cx);
711 }
712}
713
714impl Entity for MultiBuffer {
715 type Event = language::Event;
716}
717
718impl MultiBufferSnapshot {
719 pub fn text(&self) -> String {
720 self.chunks(0..self.len(), None)
721 .map(|chunk| chunk.text)
722 .collect()
723 }
724
725 pub fn excerpt_headers_in_range<'a>(
726 &'a self,
727 range: Range<u32>,
728 ) -> impl 'a + Iterator<Item = (Range<u32>, RenderHeaderFn)> {
729 let mut cursor = self.excerpts.cursor::<Point>();
730 cursor.seek(&Point::new(range.start, 0), Bias::Right, &());
731
732 if let Some(excerpt) = cursor.item() {
733 if range.start >= cursor.start().row + excerpt.header_height as u32 {
734 cursor.next(&());
735 }
736 }
737
738 iter::from_fn(move || {
739 while let Some(excerpt) = cursor.item() {
740 if cursor.start().row >= range.end {
741 break;
742 }
743
744 if let Some(render) = excerpt.render_header.clone() {
745 let start = cursor.start().row;
746 let end = start + excerpt.header_height as u32;
747 cursor.next(&());
748 return Some((start..end, render));
749 } else {
750 cursor.next(&());
751 }
752 }
753 None
754 })
755 }
756
757 pub fn reversed_chars_at<'a, T: ToOffset>(
758 &'a self,
759 position: T,
760 ) -> impl Iterator<Item = char> + 'a {
761 let mut offset = position.to_offset(self);
762 let mut cursor = self.excerpts.cursor::<usize>();
763 cursor.seek(&offset, Bias::Left, &());
764 let mut excerpt_chunks = cursor.item().map(|excerpt| {
765 let start_after_header = cursor.start() + excerpt.header_height as usize;
766 let mut end_before_footer = cursor.start() + excerpt.text_summary.bytes;
767 if excerpt.has_trailing_newline {
768 end_before_footer -= 1;
769 }
770
771 let start = excerpt.range.start.to_offset(&excerpt.buffer);
772 let end =
773 start + (cmp::min(offset, end_before_footer).saturating_sub(start_after_header));
774 excerpt.buffer.reversed_chunks_in_range(start..end)
775 });
776 iter::from_fn(move || {
777 if offset == *cursor.start() {
778 cursor.prev(&());
779 let excerpt = cursor.item()?;
780 excerpt_chunks = Some(
781 excerpt
782 .buffer
783 .reversed_chunks_in_range(excerpt.range.clone()),
784 );
785 }
786
787 let excerpt = cursor.item().unwrap();
788 if offset <= cursor.start() + excerpt.header_height as usize {
789 let header_height = offset - cursor.start();
790 offset -= header_height;
791 Some(unsafe { str::from_utf8_unchecked(&NEWLINES[..header_height]) })
792 } else if offset == cursor.end(&()) && excerpt.has_trailing_newline {
793 offset -= 1;
794 Some("\n")
795 } else {
796 let chunk = excerpt_chunks.as_mut().unwrap().next().unwrap();
797 offset -= chunk.len();
798 Some(chunk)
799 }
800 })
801 .flat_map(|c| c.chars().rev())
802 }
803
804 pub fn chars_at<'a, T: ToOffset>(&'a self, position: T) -> impl Iterator<Item = char> + 'a {
805 let offset = position.to_offset(self);
806 self.text_for_range(offset..self.len())
807 .flat_map(|chunk| chunk.chars())
808 }
809
810 pub fn text_for_range<'a, T: ToOffset>(
811 &'a self,
812 range: Range<T>,
813 ) -> impl Iterator<Item = &'a str> {
814 self.chunks(range, None).map(|chunk| chunk.text)
815 }
816
817 pub fn is_line_blank(&self, row: u32) -> bool {
818 self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row)))
819 .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
820 }
821
822 pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
823 where
824 T: ToOffset,
825 {
826 let position = position.to_offset(self);
827 position == self.clip_offset(position, Bias::Left)
828 && self
829 .bytes_in_range(position..self.len())
830 .flatten()
831 .copied()
832 .take(needle.len())
833 .eq(needle.bytes())
834 }
835
836 fn as_singleton(&self) -> Option<&BufferSnapshot> {
837 let mut excerpts = self.excerpts.iter();
838 let buffer = excerpts.next().map(|excerpt| &excerpt.buffer);
839 if excerpts.next().is_none() {
840 buffer
841 } else {
842 None
843 }
844 }
845
846 pub fn len(&self) -> usize {
847 self.excerpts.summary().text.bytes
848 }
849
850 pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
851 let mut cursor = self.excerpts.cursor::<usize>();
852 cursor.seek(&offset, Bias::Right, &());
853 if let Some(excerpt) = cursor.item() {
854 let start_after_header = *cursor.start() + excerpt.header_height as usize;
855 if offset < start_after_header {
856 *cursor.start()
857 } else {
858 let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
859 let buffer_offset = excerpt
860 .buffer
861 .clip_offset(excerpt_start + (offset - start_after_header), bias);
862 let offset_in_excerpt = if buffer_offset > excerpt_start {
863 buffer_offset - excerpt_start
864 } else {
865 0
866 };
867 start_after_header + offset_in_excerpt
868 }
869 } else {
870 self.excerpts.summary().text.bytes
871 }
872 }
873
874 pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
875 let mut cursor = self.excerpts.cursor::<Point>();
876 cursor.seek(&point, Bias::Right, &());
877 if let Some(excerpt) = cursor.item() {
878 let start_after_header = *cursor.start() + Point::new(excerpt.header_height as u32, 0);
879 if point < start_after_header {
880 *cursor.start()
881 } else {
882 let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
883 let buffer_point = excerpt
884 .buffer
885 .clip_point(excerpt_start + (point - start_after_header), bias);
886 let point_in_excerpt = if buffer_point > excerpt_start {
887 buffer_point - excerpt_start
888 } else {
889 Point::zero()
890 };
891 start_after_header + point_in_excerpt
892 }
893 } else {
894 self.excerpts.summary().text.lines
895 }
896 }
897
898 pub fn clip_point_utf16(&self, point: PointUtf16, bias: Bias) -> PointUtf16 {
899 let mut cursor = self.excerpts.cursor::<PointUtf16>();
900 cursor.seek(&point, Bias::Right, &());
901 if let Some(excerpt) = cursor.item() {
902 let start_after_header =
903 *cursor.start() + PointUtf16::new(excerpt.header_height as u32, 0);
904 if point < start_after_header {
905 *cursor.start()
906 } else {
907 let excerpt_start = excerpt
908 .buffer
909 .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
910 let buffer_point = excerpt
911 .buffer
912 .clip_point_utf16(excerpt_start + (point - start_after_header), bias);
913 let point_in_excerpt = if buffer_point > excerpt_start {
914 buffer_point - excerpt_start
915 } else {
916 PointUtf16::new(0, 0)
917 };
918 start_after_header + point_in_excerpt
919 }
920 } else {
921 self.excerpts.summary().text.lines_utf16
922 }
923 }
924
925 pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> MultiBufferBytes<'a> {
926 let range = range.start.to_offset(self)..range.end.to_offset(self);
927 let mut excerpts = self.excerpts.cursor::<usize>();
928 excerpts.seek(&range.start, Bias::Right, &());
929 let mut bytes = MultiBufferBytes {
930 range,
931 excerpts,
932 excerpt_chunks: None,
933 excerpt_chunk: &[],
934 };
935 bytes.reset_excerpt_bytes();
936 bytes
937 }
938
939 pub fn chunks<'a, T: ToOffset>(
940 &'a self,
941 range: Range<T>,
942 theme: Option<&'a SyntaxTheme>,
943 ) -> MultiBufferChunks<'a> {
944 let mut result = MultiBufferChunks {
945 range: 0..range.end.to_offset(self),
946 cursor: self.excerpts.cursor::<usize>(),
947 header_height: 0,
948 excerpt_chunks: None,
949 has_trailing_newline: false,
950 theme,
951 };
952 result.seek(range.start.to_offset(self));
953 result
954 }
955
956 pub fn offset_to_point(&self, offset: usize) -> Point {
957 let mut cursor = self.excerpts.cursor::<(usize, Point)>();
958 cursor.seek(&offset, Bias::Right, &());
959 if let Some(excerpt) = cursor.item() {
960 let (start_offset, start_point) = cursor.start();
961 let overshoot = offset - start_offset;
962 let header_height = excerpt.header_height as usize;
963 if overshoot < header_height {
964 *start_point
965 } else {
966 let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
967 let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
968 let buffer_point = excerpt
969 .buffer
970 .offset_to_point(excerpt_start_offset + (overshoot - header_height));
971 *start_point
972 + Point::new(header_height as u32, 0)
973 + (buffer_point - excerpt_start_point)
974 }
975 } else {
976 self.excerpts.summary().text.lines
977 }
978 }
979
980 pub fn point_to_offset(&self, point: Point) -> usize {
981 let mut cursor = self.excerpts.cursor::<(Point, usize)>();
982 cursor.seek(&point, Bias::Right, &());
983 if let Some(excerpt) = cursor.item() {
984 let (start_point, start_offset) = cursor.start();
985 let overshoot = point - start_point;
986 let header_height = Point::new(excerpt.header_height as u32, 0);
987 if overshoot < header_height {
988 *start_offset
989 } else {
990 let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
991 let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
992 let buffer_offset = excerpt
993 .buffer
994 .point_to_offset(excerpt_start_point + (overshoot - header_height));
995 *start_offset + excerpt.header_height as usize + buffer_offset
996 - excerpt_start_offset
997 }
998 } else {
999 self.excerpts.summary().text.bytes
1000 }
1001 }
1002
1003 pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
1004 let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>();
1005 cursor.seek(&point, Bias::Right, &());
1006 if let Some(excerpt) = cursor.item() {
1007 let (start_point, start_offset) = cursor.start();
1008 let overshoot = point - start_point;
1009 let header_height = PointUtf16::new(excerpt.header_height as u32, 0);
1010 if overshoot < header_height {
1011 *start_offset
1012 } else {
1013 let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1014 let excerpt_start_point = excerpt
1015 .buffer
1016 .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
1017 let buffer_offset = excerpt
1018 .buffer
1019 .point_utf16_to_offset(excerpt_start_point + (overshoot - header_height));
1020 *start_offset
1021 + excerpt.header_height as usize
1022 + (buffer_offset - excerpt_start_offset)
1023 }
1024 } else {
1025 self.excerpts.summary().text.bytes
1026 }
1027 }
1028
1029 pub fn indent_column_for_line(&self, row: u32) -> u32 {
1030 if let Some((buffer, range)) = self.buffer_line_for_row(row) {
1031 buffer
1032 .indent_column_for_line(range.start.row)
1033 .min(range.end.column)
1034 .saturating_sub(range.start.column)
1035 } else {
1036 0
1037 }
1038 }
1039
1040 pub fn line_len(&self, row: u32) -> u32 {
1041 if let Some((_, range)) = self.buffer_line_for_row(row) {
1042 range.end.column - range.start.column
1043 } else {
1044 0
1045 }
1046 }
1047
1048 fn buffer_line_for_row(&self, row: u32) -> Option<(&BufferSnapshot, Range<Point>)> {
1049 let mut cursor = self.excerpts.cursor::<Point>();
1050 cursor.seek(&Point::new(row, 0), Bias::Right, &());
1051 if let Some(excerpt) = cursor.item() {
1052 let overshoot = row - cursor.start().row;
1053 let header_height = excerpt.header_height as u32;
1054 if overshoot >= header_height {
1055 let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
1056 let excerpt_end = excerpt.range.end.to_point(&excerpt.buffer);
1057 let buffer_row = excerpt_start.row + overshoot - header_height;
1058 let line_start = Point::new(buffer_row, 0);
1059 let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
1060 return Some((
1061 &excerpt.buffer,
1062 line_start.max(excerpt_start)..line_end.min(excerpt_end),
1063 ));
1064 }
1065 }
1066 None
1067 }
1068
1069 pub fn max_point(&self) -> Point {
1070 self.text_summary().lines
1071 }
1072
1073 pub fn text_summary(&self) -> TextSummary {
1074 self.excerpts.summary().text
1075 }
1076
1077 pub fn text_summary_for_range<'a, D, O>(&'a self, range: Range<O>) -> D
1078 where
1079 D: TextDimension,
1080 O: ToOffset,
1081 {
1082 let mut summary = D::default();
1083 let mut range = range.start.to_offset(self)..range.end.to_offset(self);
1084 let mut cursor = self.excerpts.cursor::<usize>();
1085 cursor.seek(&range.start, Bias::Right, &());
1086 if let Some(excerpt) = cursor.item() {
1087 let start_after_header = cursor.start() + excerpt.header_height as usize;
1088 if range.start < start_after_header {
1089 let header_len = cmp::min(range.end, start_after_header) - range.start;
1090 summary.add_assign(&D::from_text_summary(&TextSummary {
1091 bytes: header_len,
1092 lines: Point::new(header_len as u32, 0),
1093 lines_utf16: PointUtf16::new(header_len as u32, 0),
1094 first_line_chars: 0,
1095 last_line_chars: 0,
1096 longest_row: 0,
1097 longest_row_chars: 0,
1098 }));
1099 range.start = start_after_header;
1100 range.end = cmp::max(range.start, range.end);
1101 }
1102
1103 let mut end_before_newline = cursor.end(&());
1104 if excerpt.has_trailing_newline {
1105 end_before_newline -= 1;
1106 }
1107
1108 let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1109 let start_in_excerpt = excerpt_start + (range.start - start_after_header);
1110 let end_in_excerpt =
1111 excerpt_start + (cmp::min(end_before_newline, range.end) - start_after_header);
1112 summary.add_assign(
1113 &excerpt
1114 .buffer
1115 .text_summary_for_range(start_in_excerpt..end_in_excerpt),
1116 );
1117
1118 if range.end > end_before_newline {
1119 summary.add_assign(&D::from_text_summary(&TextSummary {
1120 bytes: 1,
1121 lines: Point::new(1 as u32, 0),
1122 lines_utf16: PointUtf16::new(1 as u32, 0),
1123 first_line_chars: 0,
1124 last_line_chars: 0,
1125 longest_row: 0,
1126 longest_row_chars: 0,
1127 }));
1128 }
1129
1130 cursor.next(&());
1131 }
1132
1133 if range.end > *cursor.start() {
1134 summary.add_assign(&D::from_text_summary(&cursor.summary::<_, TextSummary>(
1135 &range.end,
1136 Bias::Right,
1137 &(),
1138 )));
1139 if let Some(excerpt) = cursor.item() {
1140 let start_after_header = cursor.start() + excerpt.header_height as usize;
1141 let header_len =
1142 cmp::min(range.end - cursor.start(), excerpt.header_height as usize);
1143 summary.add_assign(&D::from_text_summary(&TextSummary {
1144 bytes: header_len,
1145 lines: Point::new(header_len as u32, 0),
1146 lines_utf16: PointUtf16::new(header_len as u32, 0),
1147 first_line_chars: 0,
1148 last_line_chars: 0,
1149 longest_row: 0,
1150 longest_row_chars: 0,
1151 }));
1152 range.end = cmp::max(start_after_header, range.end);
1153
1154 let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1155 let end_in_excerpt = excerpt_start + (range.end - start_after_header);
1156 summary.add_assign(
1157 &excerpt
1158 .buffer
1159 .text_summary_for_range(excerpt_start..end_in_excerpt),
1160 );
1161 cursor.next(&());
1162 }
1163 }
1164
1165 summary
1166 }
1167
1168 pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
1169 where
1170 D: TextDimension + Ord + Sub<D, Output = D>,
1171 {
1172 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1173 cursor.seek(&Some(&anchor.excerpt_id), Bias::Left, &());
1174 if let Some(excerpt) = cursor.item() {
1175 if excerpt.id == anchor.excerpt_id {
1176 let mut excerpt_start = D::from_text_summary(&cursor.start().text);
1177 excerpt_start.add_summary(&excerpt.header_summary(), &());
1178 let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
1179 let buffer_point = anchor.text_anchor.summary::<D>(&excerpt.buffer);
1180 if buffer_point > excerpt_buffer_start {
1181 excerpt_start.add_assign(&(buffer_point - excerpt_buffer_start));
1182 }
1183 return excerpt_start;
1184 }
1185 }
1186 D::from_text_summary(&cursor.start().text)
1187 }
1188
1189 pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
1190 where
1191 D: TextDimension + Ord + Sub<D, Output = D>,
1192 I: 'a + IntoIterator<Item = &'a Anchor>,
1193 {
1194 let mut anchors = anchors.into_iter().peekable();
1195 let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1196 let mut summaries = Vec::new();
1197 while let Some(anchor) = anchors.peek() {
1198 let excerpt_id = &anchor.excerpt_id;
1199 let excerpt_anchors = iter::from_fn(|| {
1200 let anchor = anchors.peek()?;
1201 if anchor.excerpt_id == *excerpt_id {
1202 Some(&anchors.next().unwrap().text_anchor)
1203 } else {
1204 None
1205 }
1206 });
1207
1208 cursor.seek_forward(&Some(excerpt_id), Bias::Left, &());
1209 if let Some(excerpt) = cursor.item() {
1210 if excerpt.id == *excerpt_id {
1211 let mut excerpt_start = D::from_text_summary(&cursor.start().text);
1212 excerpt_start.add_summary(&excerpt.header_summary(), &());
1213 let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
1214 summaries.extend(
1215 excerpt
1216 .buffer
1217 .summaries_for_anchors::<D, _>(excerpt_anchors)
1218 .map(move |summary| {
1219 let mut excerpt_start = excerpt_start.clone();
1220 let excerpt_buffer_start = excerpt_buffer_start.clone();
1221 if summary > excerpt_buffer_start {
1222 excerpt_start.add_assign(&(summary - excerpt_buffer_start));
1223 }
1224 excerpt_start
1225 }),
1226 );
1227 continue;
1228 }
1229 }
1230
1231 let summary = D::from_text_summary(&cursor.start().text);
1232 summaries.extend(excerpt_anchors.map(|_| summary.clone()));
1233 }
1234
1235 summaries
1236 }
1237
1238 pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
1239 self.anchor_at(position, Bias::Left)
1240 }
1241
1242 pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
1243 self.anchor_at(position, Bias::Right)
1244 }
1245
1246 pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
1247 let offset = position.to_offset(self);
1248 let mut cursor = self.excerpts.cursor::<(usize, Option<&ExcerptId>)>();
1249 cursor.seek(&offset, Bias::Right, &());
1250 if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left {
1251 cursor.prev(&());
1252 }
1253 if let Some(excerpt) = cursor.item() {
1254 let start_after_header = cursor.start().0 + excerpt.header_height as usize;
1255 let mut overshoot = offset.saturating_sub(start_after_header);
1256 if excerpt.has_trailing_newline && offset == cursor.end(&()).0 {
1257 overshoot -= 1;
1258 bias = Bias::Right;
1259 }
1260
1261 let buffer_start = excerpt.range.start.to_offset(&excerpt.buffer);
1262 Anchor {
1263 excerpt_id: excerpt.id.clone(),
1264 text_anchor: excerpt.buffer.anchor_at(buffer_start + overshoot, bias),
1265 }
1266 } else if offset == 0 && bias == Bias::Left {
1267 Anchor::min()
1268 } else {
1269 Anchor::max()
1270 }
1271 }
1272
1273 pub fn parse_count(&self) -> usize {
1274 self.parse_count
1275 }
1276
1277 pub fn enclosing_bracket_ranges<T: ToOffset>(
1278 &self,
1279 range: Range<T>,
1280 ) -> Option<(Range<usize>, Range<usize>)> {
1281 let range = range.start.to_offset(self)..range.end.to_offset(self);
1282 self.as_singleton().unwrap().enclosing_bracket_ranges(range)
1283 }
1284
1285 pub fn diagnostics_update_count(&self) -> usize {
1286 self.diagnostics_update_count
1287 }
1288
1289 pub fn language(&self) -> Option<&Arc<Language>> {
1290 self.excerpts
1291 .iter()
1292 .next()
1293 .and_then(|excerpt| excerpt.buffer.language())
1294 }
1295
1296 pub fn diagnostic_group<'a, O>(
1297 &'a self,
1298 group_id: usize,
1299 ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
1300 where
1301 O: text::FromAnchor + 'a,
1302 {
1303 self.as_singleton().unwrap().diagnostic_group(group_id)
1304 }
1305
1306 pub fn diagnostics_in_range<'a, T, O>(
1307 &'a self,
1308 range: Range<T>,
1309 ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
1310 where
1311 T: 'a + ToOffset,
1312 O: 'a + text::FromAnchor,
1313 {
1314 let range = range.start.to_offset(self)..range.end.to_offset(self);
1315 self.as_singleton().unwrap().diagnostics_in_range(range)
1316 }
1317
1318 pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
1319 let range = range.start.to_offset(self)..range.end.to_offset(self);
1320 self.as_singleton()
1321 .unwrap()
1322 .range_for_syntax_ancestor(range)
1323 }
1324
1325 fn buffer_snapshot_for_excerpt<'a>(
1326 &'a self,
1327 excerpt_id: &'a ExcerptId,
1328 ) -> Option<&'a BufferSnapshot> {
1329 let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1330 cursor.seek(&Some(excerpt_id), Bias::Left, &());
1331 if let Some(excerpt) = cursor.item() {
1332 if excerpt.id == *excerpt_id {
1333 return Some(&excerpt.buffer);
1334 }
1335 }
1336 None
1337 }
1338
1339 pub fn remote_selections_in_range<'a>(
1340 &'a self,
1341 range: &'a Range<Anchor>,
1342 ) -> impl 'a + Iterator<Item = (ReplicaId, Selection<Anchor>)> {
1343 let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1344 cursor.seek(&Some(&range.start.excerpt_id), Bias::Left, &());
1345 cursor
1346 .take_while(move |excerpt| excerpt.id <= range.end.excerpt_id)
1347 .flat_map(move |excerpt| {
1348 let mut query_range = excerpt.range.start.clone()..excerpt.range.end.clone();
1349 if excerpt.id == range.start.excerpt_id {
1350 query_range.start = range.start.text_anchor.clone();
1351 }
1352 if excerpt.id == range.end.excerpt_id {
1353 query_range.end = range.end.text_anchor.clone();
1354 }
1355
1356 excerpt
1357 .buffer
1358 .remote_selections_in_range(query_range)
1359 .flat_map(move |(replica_id, selections)| {
1360 selections.map(move |selection| {
1361 let mut start = Anchor {
1362 excerpt_id: excerpt.id.clone(),
1363 text_anchor: selection.start.clone(),
1364 };
1365 let mut end = Anchor {
1366 excerpt_id: excerpt.id.clone(),
1367 text_anchor: selection.end.clone(),
1368 };
1369 if range.start.cmp(&start, self).unwrap().is_gt() {
1370 start = range.start.clone();
1371 }
1372 if range.end.cmp(&end, self).unwrap().is_lt() {
1373 end = range.end.clone();
1374 }
1375
1376 (
1377 replica_id,
1378 Selection {
1379 id: selection.id,
1380 start,
1381 end,
1382 reversed: selection.reversed,
1383 goal: selection.goal,
1384 },
1385 )
1386 })
1387 })
1388 })
1389 }
1390}
1391
1392impl History {
1393 fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
1394 self.transaction_depth += 1;
1395 if self.transaction_depth == 1 {
1396 let id = post_inc(&mut self.next_transaction_id);
1397 self.undo_stack.push(Transaction {
1398 id,
1399 buffer_transactions: Default::default(),
1400 first_edit_at: now,
1401 last_edit_at: now,
1402 });
1403 Some(id)
1404 } else {
1405 None
1406 }
1407 }
1408
1409 fn end_transaction(
1410 &mut self,
1411 now: Instant,
1412 buffer_transactions: HashSet<(usize, TransactionId)>,
1413 ) -> bool {
1414 assert_ne!(self.transaction_depth, 0);
1415 self.transaction_depth -= 1;
1416 if self.transaction_depth == 0 {
1417 if buffer_transactions.is_empty() {
1418 self.undo_stack.pop();
1419 false
1420 } else {
1421 let transaction = self.undo_stack.last_mut().unwrap();
1422 transaction.last_edit_at = now;
1423 transaction.buffer_transactions.extend(buffer_transactions);
1424 true
1425 }
1426 } else {
1427 false
1428 }
1429 }
1430
1431 fn pop_undo(&mut self) -> Option<&Transaction> {
1432 assert_eq!(self.transaction_depth, 0);
1433 if let Some(transaction) = self.undo_stack.pop() {
1434 self.redo_stack.push(transaction);
1435 self.redo_stack.last()
1436 } else {
1437 None
1438 }
1439 }
1440
1441 fn pop_redo(&mut self) -> Option<&Transaction> {
1442 assert_eq!(self.transaction_depth, 0);
1443 if let Some(transaction) = self.redo_stack.pop() {
1444 self.undo_stack.push(transaction);
1445 self.undo_stack.last()
1446 } else {
1447 None
1448 }
1449 }
1450
1451 fn group(&mut self) -> Option<TransactionId> {
1452 let mut new_len = self.undo_stack.len();
1453 let mut transactions = self.undo_stack.iter_mut();
1454
1455 if let Some(mut transaction) = transactions.next_back() {
1456 while let Some(prev_transaction) = transactions.next_back() {
1457 if transaction.first_edit_at - prev_transaction.last_edit_at <= self.group_interval
1458 {
1459 transaction = prev_transaction;
1460 new_len -= 1;
1461 } else {
1462 break;
1463 }
1464 }
1465 }
1466
1467 let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
1468 if let Some(last_transaction) = transactions_to_keep.last_mut() {
1469 if let Some(transaction) = transactions_to_merge.last() {
1470 last_transaction.last_edit_at = transaction.last_edit_at;
1471 }
1472 }
1473
1474 self.undo_stack.truncate(new_len);
1475 self.undo_stack.last().map(|t| t.id)
1476 }
1477}
1478
1479impl Excerpt {
1480 fn new(
1481 id: ExcerptId,
1482 buffer_id: usize,
1483 buffer: BufferSnapshot,
1484 range: Range<text::Anchor>,
1485 header_height: u8,
1486 render_header: Option<RenderHeaderFn>,
1487 has_trailing_newline: bool,
1488 ) -> Self {
1489 let mut text_summary =
1490 buffer.text_summary_for_range::<TextSummary, _>(range.to_offset(&buffer));
1491 if header_height > 0 {
1492 text_summary.first_line_chars = 0;
1493 text_summary.lines.row += header_height as u32;
1494 text_summary.lines_utf16.row += header_height as u32;
1495 text_summary.bytes += header_height as usize;
1496 text_summary.longest_row += header_height as u32;
1497 }
1498 if has_trailing_newline {
1499 text_summary.last_line_chars = 0;
1500 text_summary.lines.row += 1;
1501 text_summary.lines.column = 0;
1502 text_summary.lines_utf16.row += 1;
1503 text_summary.lines_utf16.column = 0;
1504 text_summary.bytes += 1;
1505 }
1506
1507 Excerpt {
1508 id,
1509 buffer_id,
1510 buffer,
1511 range,
1512 text_summary,
1513 header_height,
1514 render_header,
1515 has_trailing_newline,
1516 }
1517 }
1518
1519 fn header_summary(&self) -> TextSummary {
1520 TextSummary {
1521 bytes: self.header_height as usize,
1522 lines: Point::new(self.header_height as u32, 0),
1523 lines_utf16: PointUtf16::new(self.header_height as u32, 0),
1524 first_line_chars: 0,
1525 last_line_chars: 0,
1526 longest_row: 0,
1527 longest_row_chars: 0,
1528 }
1529 }
1530}
1531
1532impl fmt::Debug for Excerpt {
1533 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1534 f.debug_struct("Excerpt")
1535 .field("id", &self.id)
1536 .field("buffer_id", &self.buffer_id)
1537 .field("range", &self.range)
1538 .field("text_summary", &self.text_summary)
1539 .field("header_height", &self.header_height)
1540 .field("has_trailing_newline", &self.has_trailing_newline)
1541 .finish()
1542 }
1543}
1544
1545impl sum_tree::Item for Excerpt {
1546 type Summary = ExcerptSummary;
1547
1548 fn summary(&self) -> Self::Summary {
1549 ExcerptSummary {
1550 excerpt_id: self.id.clone(),
1551 text: self.text_summary.clone(),
1552 }
1553 }
1554}
1555
1556impl sum_tree::Summary for ExcerptSummary {
1557 type Context = ();
1558
1559 fn add_summary(&mut self, summary: &Self, _: &()) {
1560 debug_assert!(summary.excerpt_id > self.excerpt_id);
1561 self.excerpt_id = summary.excerpt_id.clone();
1562 self.text.add_summary(&summary.text, &());
1563 }
1564}
1565
1566impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
1567 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1568 *self += &summary.text;
1569 }
1570}
1571
1572impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
1573 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1574 *self += summary.text.bytes;
1575 }
1576}
1577
1578impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
1579 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
1580 Ord::cmp(self, &cursor_location.text.bytes)
1581 }
1582}
1583
1584impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Option<&'a ExcerptId> {
1585 fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
1586 Ord::cmp(self, &Some(&cursor_location.excerpt_id))
1587 }
1588}
1589
1590impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
1591 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1592 *self += summary.text.lines;
1593 }
1594}
1595
1596impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
1597 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1598 *self += summary.text.lines_utf16
1599 }
1600}
1601
1602impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a ExcerptId> {
1603 fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1604 *self = Some(&summary.excerpt_id);
1605 }
1606}
1607
1608impl<'a> MultiBufferChunks<'a> {
1609 pub fn offset(&self) -> usize {
1610 self.range.start
1611 }
1612
1613 pub fn seek(&mut self, offset: usize) {
1614 self.range.start = offset;
1615 self.cursor.seek_forward(&offset, Bias::Right, &());
1616 self.header_height = 0;
1617 self.excerpt_chunks = None;
1618 if let Some(excerpt) = self.cursor.item() {
1619 let buffer_range = excerpt.range.to_offset(&excerpt.buffer);
1620 self.header_height = excerpt.header_height;
1621 self.has_trailing_newline = excerpt.has_trailing_newline;
1622
1623 let buffer_start;
1624 let start_overshoot = self.range.start - self.cursor.start();
1625 if start_overshoot < excerpt.header_height as usize {
1626 self.header_height -= start_overshoot as u8;
1627 buffer_start = buffer_range.start;
1628 } else {
1629 buffer_start =
1630 buffer_range.start + start_overshoot - excerpt.header_height as usize;
1631 self.header_height = 0;
1632 }
1633
1634 let buffer_end;
1635 let end_overshoot = self.range.end - self.cursor.start();
1636 if end_overshoot < excerpt.header_height as usize {
1637 self.header_height -= excerpt.header_height - end_overshoot as u8;
1638 buffer_end = buffer_start;
1639 } else {
1640 buffer_end = cmp::min(
1641 buffer_range.end,
1642 buffer_range.start + end_overshoot - excerpt.header_height as usize,
1643 );
1644 }
1645
1646 self.excerpt_chunks = Some(excerpt.buffer.chunks(buffer_start..buffer_end, self.theme));
1647 }
1648 }
1649}
1650
1651impl<'a> Iterator for MultiBufferChunks<'a> {
1652 type Item = Chunk<'a>;
1653
1654 fn next(&mut self) -> Option<Self::Item> {
1655 loop {
1656 if self.header_height > 0 {
1657 let chunk = Chunk {
1658 text: unsafe {
1659 str::from_utf8_unchecked(&NEWLINES[..self.header_height as usize])
1660 },
1661 ..Default::default()
1662 };
1663 self.range.start += self.header_height as usize;
1664 self.header_height = 0;
1665 return Some(chunk);
1666 }
1667
1668 if let Some(excerpt_chunks) = self.excerpt_chunks.as_mut() {
1669 if let Some(chunk) = excerpt_chunks.next() {
1670 self.range.start += chunk.text.len();
1671 return Some(chunk);
1672 }
1673 self.excerpt_chunks.take();
1674 if self.has_trailing_newline && self.cursor.end(&()) <= self.range.end {
1675 self.range.start += 1;
1676 return Some(Chunk {
1677 text: "\n",
1678 ..Default::default()
1679 });
1680 }
1681 }
1682
1683 self.cursor.next(&());
1684 if *self.cursor.start() >= self.range.end {
1685 return None;
1686 }
1687
1688 let excerpt = self.cursor.item()?;
1689 let buffer_range = excerpt.range.to_offset(&excerpt.buffer);
1690
1691 let buffer_end = cmp::min(
1692 buffer_range.end,
1693 buffer_range.start + self.range.end
1694 - excerpt.header_height as usize
1695 - self.cursor.start(),
1696 );
1697
1698 self.header_height = excerpt.header_height;
1699 self.has_trailing_newline = excerpt.has_trailing_newline;
1700 self.excerpt_chunks = Some(
1701 excerpt
1702 .buffer
1703 .chunks(buffer_range.start..buffer_end, self.theme),
1704 );
1705 }
1706 }
1707}
1708
1709impl<'a> MultiBufferBytes<'a> {
1710 fn peek(&mut self) -> Option<&'a [u8]> {
1711 if self.range.is_empty() {
1712 return None;
1713 }
1714
1715 let excerpt = self.excerpts.item()?;
1716 let header_end = self.excerpts.start() + excerpt.header_height as usize;
1717 let mut footer_start = self.excerpts.start() + excerpt.text_summary.bytes;
1718 if excerpt.has_trailing_newline {
1719 footer_start -= 1;
1720 }
1721
1722 dbg!(self.range.start, header_end, footer_start);
1723 if self.range.start < header_end {
1724 let header_height = cmp::min(header_end - self.range.start, self.range.len());
1725 Some(&NEWLINES[..header_height])
1726 } else if self.range.start == footer_start {
1727 Some(&NEWLINES[..1])
1728 } else {
1729 Some(self.excerpt_chunk)
1730 }
1731 }
1732
1733 fn consume(&mut self, len: usize) {
1734 self.range.start += len;
1735 if self.range.is_empty() {
1736 return;
1737 }
1738
1739 if let Some(excerpt) = self.excerpts.item() {
1740 let header_end = self.excerpts.start() + excerpt.header_height as usize;
1741
1742 if self.range.start == self.excerpts.end(&()) {
1743 self.excerpts.next(&());
1744 self.reset_excerpt_bytes();
1745 } else if self.range.start > header_end {
1746 self.excerpt_chunks.as_mut().unwrap().next();
1747 }
1748 }
1749 }
1750
1751 fn reset_excerpt_bytes(&mut self) {
1752 self.excerpt_chunks = self.excerpts.item().map(|excerpt| {
1753 let start_after_header = self.excerpts.start() + excerpt.header_height as usize;
1754 let mut end_before_footer = self.excerpts.start() + excerpt.text_summary.bytes;
1755 if excerpt.has_trailing_newline {
1756 end_before_footer -= 1;
1757 }
1758
1759 let buffer_start = excerpt.range.start.to_offset(&excerpt.buffer);
1760 let start = buffer_start + self.range.start.saturating_sub(start_after_header);
1761 let end = buffer_start
1762 + cmp::min(self.range.end, end_before_footer).saturating_sub(start_after_header);
1763 excerpt.buffer.bytes_in_range(start..end)
1764 });
1765 }
1766}
1767
1768impl<'a> Iterator for MultiBufferBytes<'a> {
1769 type Item = &'a [u8];
1770
1771 fn next(&mut self) -> Option<Self::Item> {
1772 let result = self.peek()?;
1773 self.consume(result.len());
1774 Some(result)
1775 }
1776}
1777
1778impl<'a> io::Read for MultiBufferBytes<'a> {
1779 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1780 if let Some(chunk) = self.peek() {
1781 let len = cmp::min(buf.len(), chunk.len());
1782 buf[..len].copy_from_slice(&chunk[..len]);
1783 self.consume(len);
1784 Ok(len)
1785 } else {
1786 Ok(0)
1787 }
1788 }
1789}
1790
1791impl ToOffset for Point {
1792 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
1793 snapshot.point_to_offset(*self)
1794 }
1795}
1796
1797impl ToOffset for PointUtf16 {
1798 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
1799 snapshot.point_utf16_to_offset(*self)
1800 }
1801}
1802
1803impl ToOffset for usize {
1804 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
1805 assert!(*self <= snapshot.len(), "offset is out of range");
1806 *self
1807 }
1808}
1809
1810impl ToPoint for usize {
1811 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
1812 snapshot.offset_to_point(*self)
1813 }
1814}
1815
1816impl ToPoint for Point {
1817 fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
1818 *self
1819 }
1820}
1821
1822#[cfg(test)]
1823mod tests {
1824 use super::*;
1825 use gpui::{elements::Empty, Element, MutableAppContext};
1826 use language::Buffer;
1827 use rand::prelude::*;
1828 use std::env;
1829 use text::{Point, RandomCharIter};
1830 use util::test::sample_text;
1831
1832 #[gpui::test]
1833 fn test_singleton_multibuffer(cx: &mut MutableAppContext) {
1834 let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
1835 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
1836 assert_eq!(
1837 multibuffer.read(cx).snapshot(cx).text(),
1838 buffer.read(cx).text()
1839 );
1840
1841 buffer.update(cx, |buffer, cx| buffer.edit([1..3], "XXX", cx));
1842 assert_eq!(
1843 multibuffer.read(cx).snapshot(cx).text(),
1844 buffer.read(cx).text()
1845 );
1846 }
1847
1848 #[gpui::test]
1849 fn test_excerpt_buffer(cx: &mut MutableAppContext) {
1850 let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
1851 let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
1852 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
1853
1854 let subscription = multibuffer.update(cx, |multibuffer, cx| {
1855 let subscription = multibuffer.subscribe();
1856 multibuffer.push_excerpt(
1857 ExcerptProperties {
1858 buffer: &buffer_1,
1859 range: Point::new(1, 2)..Point::new(2, 5),
1860 header_height: 2,
1861 render_header: Some(Arc::new(|_| Empty::new().named("header 1"))),
1862 },
1863 cx,
1864 );
1865 assert_eq!(
1866 subscription.consume().into_inner(),
1867 [Edit {
1868 old: 0..0,
1869 new: 0..13
1870 }]
1871 );
1872
1873 multibuffer.push_excerpt(
1874 ExcerptProperties {
1875 buffer: &buffer_1,
1876 range: Point::new(3, 3)..Point::new(4, 4),
1877 header_height: 1,
1878 render_header: Some(Arc::new(|_| Empty::new().named("header 2"))),
1879 },
1880 cx,
1881 );
1882 multibuffer.push_excerpt(
1883 ExcerptProperties {
1884 buffer: &buffer_2,
1885 range: Point::new(3, 1)..Point::new(3, 3),
1886 header_height: 3,
1887 render_header: Some(Arc::new(|_| Empty::new().named("header 3"))),
1888 },
1889 cx,
1890 );
1891 assert_eq!(
1892 subscription.consume().into_inner(),
1893 [Edit {
1894 old: 13..13,
1895 new: 13..29
1896 }]
1897 );
1898
1899 subscription
1900 });
1901
1902 assert_eq!(
1903 multibuffer.read(cx).snapshot(cx).text(),
1904 concat!(
1905 "\n", // Preserve newlines
1906 "\n", //
1907 "bbbb\n", //
1908 "ccccc\n", //
1909 "\n", //
1910 "ddd\n", //
1911 "eeee\n", //
1912 "\n", //
1913 "\n", //
1914 "\n", //
1915 "jj\n" //
1916 )
1917 );
1918
1919 {
1920 let snapshot = multibuffer.read(cx).read(cx);
1921 assert_eq!(
1922 snapshot
1923 .excerpt_headers_in_range(0..snapshot.max_point().row + 1)
1924 .map(|(rows, render)| (rows, render(cx).name().unwrap().to_string()))
1925 .collect::<Vec<_>>(),
1926 &[
1927 (0..2, "header 1".into()),
1928 (4..5, "header 2".into()),
1929 (7..10, "header 3".into())
1930 ]
1931 );
1932
1933 assert_eq!(
1934 snapshot
1935 .excerpt_headers_in_range(1..5)
1936 .map(|(rows, render)| (rows, render(cx).name().unwrap().to_string()))
1937 .collect::<Vec<_>>(),
1938 &[(0..2, "header 1".into()), (4..5, "header 2".into())]
1939 );
1940
1941 assert_eq!(
1942 snapshot
1943 .excerpt_headers_in_range(2..8)
1944 .map(|(rows, render)| (rows, render(cx).name().unwrap().to_string()))
1945 .collect::<Vec<_>>(),
1946 &[(4..5, "header 2".into()), (7..10, "header 3".into())]
1947 );
1948 }
1949
1950 buffer_1.update(cx, |buffer, cx| {
1951 buffer.edit(
1952 [
1953 Point::new(0, 0)..Point::new(0, 0),
1954 Point::new(2, 1)..Point::new(2, 3),
1955 ],
1956 "\n",
1957 cx,
1958 );
1959 });
1960
1961 assert_eq!(
1962 multibuffer.read(cx).snapshot(cx).text(),
1963 concat!(
1964 "\n", // Preserve newlines
1965 "\n", //
1966 "bbbb\n", //
1967 "c\n", //
1968 "cc\n", //
1969 "\n", //
1970 "ddd\n", //
1971 "eeee\n", //
1972 "\n", //
1973 "\n", //
1974 "\n", //
1975 "jj\n" //
1976 )
1977 );
1978
1979 assert_eq!(
1980 subscription.consume().into_inner(),
1981 [Edit {
1982 old: 8..10,
1983 new: 8..9
1984 }]
1985 );
1986 }
1987
1988 #[gpui::test]
1989 fn test_singleton_multibuffer_anchors(cx: &mut MutableAppContext) {
1990 let buffer = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
1991 let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
1992 let old_snapshot = multibuffer.read(cx).snapshot(cx);
1993 buffer.update(cx, |buffer, cx| {
1994 buffer.edit([0..0], "X", cx);
1995 buffer.edit([5..5], "Y", cx);
1996 });
1997 let new_snapshot = multibuffer.read(cx).snapshot(cx);
1998
1999 assert_eq!(old_snapshot.text(), "abcd");
2000 assert_eq!(new_snapshot.text(), "XabcdY");
2001
2002 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
2003 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
2004 assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
2005 assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
2006 }
2007
2008 #[gpui::test]
2009 fn test_multibuffer_anchors(cx: &mut MutableAppContext) {
2010 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
2011 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
2012 let multibuffer = cx.add_model(|cx| {
2013 let mut multibuffer = MultiBuffer::new(0);
2014 multibuffer.push_excerpt(
2015 ExcerptProperties {
2016 buffer: &buffer_1,
2017 range: 0..4,
2018 header_height: 1,
2019 render_header: None,
2020 },
2021 cx,
2022 );
2023 multibuffer.push_excerpt(
2024 ExcerptProperties {
2025 buffer: &buffer_2,
2026 range: 0..5,
2027 header_height: 1,
2028 render_header: None,
2029 },
2030 cx,
2031 );
2032 multibuffer
2033 });
2034 let old_snapshot = multibuffer.read(cx).snapshot(cx);
2035
2036 buffer_1.update(cx, |buffer, cx| {
2037 buffer.edit([0..0], "W", cx);
2038 buffer.edit([5..5], "X", cx);
2039 });
2040 buffer_2.update(cx, |buffer, cx| {
2041 buffer.edit([0..0], "Y", cx);
2042 buffer.edit([6..0], "Z", cx);
2043 });
2044 let new_snapshot = multibuffer.read(cx).snapshot(cx);
2045
2046 assert_eq!(old_snapshot.text(), "\nabcd\n\nefghi\n");
2047 assert_eq!(new_snapshot.text(), "\nWabcdX\n\nYefghiZ\n");
2048
2049 assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 1);
2050 assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 2);
2051 assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 1);
2052 assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
2053 assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
2054 assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
2055 assert_eq!(old_snapshot.anchor_before(7).to_offset(&new_snapshot), 9);
2056 assert_eq!(old_snapshot.anchor_after(7).to_offset(&new_snapshot), 10);
2057 assert_eq!(old_snapshot.anchor_before(13).to_offset(&new_snapshot), 16);
2058 assert_eq!(old_snapshot.anchor_after(13).to_offset(&new_snapshot), 17);
2059 }
2060
2061 #[gpui::test(iterations = 100)]
2062 fn test_random_excerpts(cx: &mut MutableAppContext, mut rng: StdRng) {
2063 let operations = env::var("OPERATIONS")
2064 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2065 .unwrap_or(10);
2066
2067 let mut buffers: Vec<ModelHandle<Buffer>> = Vec::new();
2068 let list = cx.add_model(|_| MultiBuffer::new(0));
2069 let mut excerpt_ids = Vec::new();
2070 let mut expected_excerpts = Vec::new();
2071 let mut old_versions = Vec::new();
2072
2073 for _ in 0..operations {
2074 match rng.gen_range(0..100) {
2075 0..=19 if !buffers.is_empty() => {
2076 let buffer = buffers.choose(&mut rng).unwrap();
2077 buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
2078 }
2079 _ => {
2080 let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
2081 let base_text = RandomCharIter::new(&mut rng).take(10).collect::<String>();
2082 buffers.push(cx.add_model(|cx| Buffer::new(0, base_text, cx)));
2083 buffers.last().unwrap()
2084 } else {
2085 buffers.choose(&mut rng).unwrap()
2086 };
2087
2088 let buffer = buffer_handle.read(cx);
2089 let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
2090 let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
2091 let header_height = rng.gen_range(0..=5);
2092 let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
2093 log::info!(
2094 "Pushing excerpt wih header {}, buffer {}: {:?}[{:?}] = {:?}",
2095 header_height,
2096 buffer_handle.id(),
2097 buffer.text(),
2098 start_ix..end_ix,
2099 &buffer.text()[start_ix..end_ix]
2100 );
2101
2102 let excerpt_id = list.update(cx, |list, cx| {
2103 list.push_excerpt(
2104 ExcerptProperties {
2105 buffer: &buffer_handle,
2106 range: start_ix..end_ix,
2107 header_height,
2108 render_header: None,
2109 },
2110 cx,
2111 )
2112 });
2113 excerpt_ids.push(excerpt_id);
2114 expected_excerpts.push((buffer_handle.clone(), anchor_range, header_height));
2115 }
2116 }
2117
2118 if rng.gen_bool(0.3) {
2119 list.update(cx, |list, cx| {
2120 old_versions.push((list.snapshot(cx), list.subscribe()));
2121 })
2122 }
2123
2124 let snapshot = list.read(cx).snapshot(cx);
2125
2126 let mut excerpt_starts = Vec::new();
2127 let mut expected_text = String::new();
2128 for (buffer, range, header_height) in &expected_excerpts {
2129 let buffer = buffer.read(cx);
2130 let buffer_range = range.to_offset(buffer);
2131
2132 for _ in 0..*header_height {
2133 expected_text.push('\n');
2134 }
2135
2136 excerpt_starts.push(TextSummary::from(expected_text.as_str()));
2137 expected_text.extend(buffer.text_for_range(buffer_range.clone()));
2138 expected_text.push('\n');
2139 }
2140
2141 assert_eq!(snapshot.text(), expected_text);
2142
2143 let mut excerpt_starts = excerpt_starts.into_iter();
2144 for (buffer, range, _) in &expected_excerpts {
2145 let buffer_id = buffer.id();
2146 let buffer = buffer.read(cx);
2147 let buffer_range = range.to_offset(buffer);
2148 let buffer_start_point = buffer.offset_to_point(buffer_range.start);
2149 let buffer_start_point_utf16 =
2150 buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
2151
2152 let excerpt_start = excerpt_starts.next().unwrap();
2153 let mut offset = excerpt_start.bytes;
2154 let mut buffer_offset = buffer_range.start;
2155 let mut point = excerpt_start.lines;
2156 let mut buffer_point = buffer_start_point;
2157 let mut point_utf16 = excerpt_start.lines_utf16;
2158 let mut buffer_point_utf16 = buffer_start_point_utf16;
2159 for byte in buffer.bytes_in_range(buffer_range.clone()).flatten() {
2160 let left_offset = snapshot.clip_offset(offset, Bias::Left);
2161 let right_offset = snapshot.clip_offset(offset, Bias::Right);
2162 let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
2163 let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
2164 assert_eq!(
2165 left_offset,
2166 excerpt_start.bytes + (buffer_left_offset - buffer_range.start),
2167 "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
2168 offset,
2169 buffer_id,
2170 buffer_offset,
2171 );
2172 assert_eq!(
2173 right_offset,
2174 excerpt_start.bytes + (buffer_right_offset - buffer_range.start),
2175 "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
2176 offset,
2177 buffer_id,
2178 buffer_offset,
2179 );
2180
2181 let left_point = snapshot.clip_point(point, Bias::Left);
2182 let right_point = snapshot.clip_point(point, Bias::Right);
2183 let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
2184 let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
2185 assert_eq!(
2186 left_point,
2187 excerpt_start.lines + (buffer_left_point - buffer_start_point),
2188 "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
2189 point,
2190 buffer_id,
2191 buffer_point,
2192 );
2193 assert_eq!(
2194 right_point,
2195 excerpt_start.lines + (buffer_right_point - buffer_start_point),
2196 "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
2197 point,
2198 buffer_id,
2199 buffer_point,
2200 );
2201
2202 let left_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Left);
2203 let right_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Right);
2204 let buffer_left_point_utf16 =
2205 buffer.clip_point_utf16(buffer_point_utf16, Bias::Left);
2206 let buffer_right_point_utf16 =
2207 buffer.clip_point_utf16(buffer_point_utf16, Bias::Right);
2208 assert_eq!(
2209 left_point_utf16,
2210 excerpt_start.lines_utf16
2211 + (buffer_left_point_utf16 - buffer_start_point_utf16),
2212 "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
2213 point_utf16,
2214 buffer_id,
2215 buffer_point_utf16,
2216 );
2217 assert_eq!(
2218 right_point_utf16,
2219 excerpt_start.lines_utf16
2220 + (buffer_right_point_utf16 - buffer_start_point_utf16),
2221 "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
2222 point_utf16,
2223 buffer_id,
2224 buffer_point_utf16,
2225 );
2226
2227 assert_eq!(
2228 snapshot.point_to_offset(left_point),
2229 left_offset,
2230 "point_to_offset({:?})",
2231 left_point,
2232 );
2233 assert_eq!(
2234 snapshot.offset_to_point(left_offset),
2235 left_point,
2236 "offset_to_point({:?})",
2237 left_offset,
2238 );
2239
2240 offset += 1;
2241 buffer_offset += 1;
2242 if *byte == b'\n' {
2243 point += Point::new(1, 0);
2244 point_utf16 += PointUtf16::new(1, 0);
2245 buffer_point += Point::new(1, 0);
2246 buffer_point_utf16 += PointUtf16::new(1, 0);
2247 } else {
2248 point += Point::new(0, 1);
2249 point_utf16 += PointUtf16::new(0, 1);
2250 buffer_point += Point::new(0, 1);
2251 buffer_point_utf16 += PointUtf16::new(0, 1);
2252 }
2253 }
2254 }
2255
2256 for (row, line) in expected_text.split('\n').enumerate() {
2257 assert_eq!(
2258 snapshot.line_len(row as u32),
2259 line.len() as u32,
2260 "line_len({}).",
2261 row
2262 );
2263 }
2264
2265 for _ in 0..10 {
2266 let end_ix = snapshot.clip_offset(rng.gen_range(0..=snapshot.len()), Bias::Right);
2267 let start_ix = snapshot.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
2268
2269 assert_eq!(
2270 snapshot
2271 .text_for_range(start_ix..end_ix)
2272 .collect::<String>(),
2273 &expected_text[start_ix..end_ix],
2274 "incorrect text for range {:?}",
2275 start_ix..end_ix
2276 );
2277
2278 let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
2279 assert_eq!(
2280 snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
2281 expected_summary,
2282 "incorrect summary for range {:?}",
2283 start_ix..end_ix
2284 );
2285 }
2286
2287 for _ in 0..10 {
2288 let end_ix = snapshot.clip_offset(rng.gen_range(0..=snapshot.len()), Bias::Right);
2289 assert_eq!(
2290 snapshot.reversed_chars_at(end_ix).collect::<String>(),
2291 expected_text[..end_ix].chars().rev().collect::<String>(),
2292 );
2293 }
2294
2295 for _ in 0..10 {
2296 let end_ix = rng.gen_range(0..=snapshot.len());
2297 let start_ix = rng.gen_range(0..=end_ix);
2298 dbg!(&expected_text);
2299 assert_eq!(
2300 snapshot
2301 .bytes_in_range(start_ix..end_ix)
2302 .flatten()
2303 .copied()
2304 .collect::<Vec<_>>(),
2305 expected_text.as_bytes()[start_ix..end_ix].to_vec(),
2306 "bytes_in_range({:?})",
2307 start_ix..end_ix,
2308 );
2309 }
2310 }
2311
2312 let snapshot = list.read(cx).snapshot(cx);
2313 for (old_snapshot, subscription) in old_versions {
2314 let edits = subscription.consume().into_inner();
2315
2316 log::info!(
2317 "applying edits since old text: {:?}: {:?}",
2318 old_snapshot.text(),
2319 edits,
2320 );
2321
2322 let mut text = old_snapshot.text();
2323 for edit in edits {
2324 let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
2325 text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
2326 }
2327 assert_eq!(text.to_string(), snapshot.text());
2328 }
2329 }
2330
2331 #[gpui::test]
2332 fn test_history(cx: &mut MutableAppContext) {
2333 let buffer_1 = cx.add_model(|cx| Buffer::new(0, "1234", cx));
2334 let buffer_2 = cx.add_model(|cx| Buffer::new(0, "5678", cx));
2335 let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2336 let group_interval = multibuffer.read(cx).history.group_interval;
2337 multibuffer.update(cx, |multibuffer, cx| {
2338 multibuffer.push_excerpt(
2339 ExcerptProperties {
2340 buffer: &buffer_1,
2341 range: 0..buffer_1.read(cx).len(),
2342 header_height: 0,
2343 render_header: None,
2344 },
2345 cx,
2346 );
2347 multibuffer.push_excerpt(
2348 ExcerptProperties {
2349 buffer: &buffer_2,
2350 range: 0..buffer_2.read(cx).len(),
2351 header_height: 0,
2352 render_header: None,
2353 },
2354 cx,
2355 );
2356 });
2357
2358 let mut now = Instant::now();
2359
2360 multibuffer.update(cx, |multibuffer, cx| {
2361 multibuffer.start_transaction_at(now, cx);
2362 multibuffer.edit(
2363 [
2364 Point::new(0, 0)..Point::new(0, 0),
2365 Point::new(1, 0)..Point::new(1, 0),
2366 ],
2367 "A",
2368 cx,
2369 );
2370 multibuffer.edit(
2371 [
2372 Point::new(0, 1)..Point::new(0, 1),
2373 Point::new(1, 1)..Point::new(1, 1),
2374 ],
2375 "B",
2376 cx,
2377 );
2378 multibuffer.end_transaction_at(now, cx);
2379 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678\n");
2380
2381 now += 2 * group_interval;
2382 multibuffer.start_transaction_at(now, cx);
2383 multibuffer.edit([2..2], "C", cx);
2384 multibuffer.end_transaction_at(now, cx);
2385 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678\n");
2386
2387 multibuffer.undo(cx);
2388 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678\n");
2389
2390 multibuffer.undo(cx);
2391 assert_eq!(multibuffer.read(cx).text(), "1234\n5678\n");
2392
2393 multibuffer.redo(cx);
2394 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678\n");
2395
2396 multibuffer.redo(cx);
2397 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678\n");
2398
2399 buffer_1.update(cx, |buffer_1, cx| buffer_1.undo(cx));
2400 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678\n");
2401
2402 multibuffer.undo(cx);
2403 assert_eq!(multibuffer.read(cx).text(), "1234\n5678\n");
2404
2405 multibuffer.redo(cx);
2406 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678\n");
2407
2408 multibuffer.redo(cx);
2409 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678\n");
2410
2411 multibuffer.undo(cx);
2412 assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678\n");
2413
2414 buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
2415 assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678\n");
2416
2417 multibuffer.undo(cx);
2418 assert_eq!(multibuffer.read(cx).text(), "C1234\n5678\n");
2419 });
2420 }
2421}