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