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