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