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