multi_buffer.rs

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