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