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