multi_buffer.rs

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