multi_buffer.rs

   1mod anchor;
   2
   3pub use anchor::{Anchor, AnchorRangeExt, Offset};
   4use anyhow::{anyhow, Result};
   5use clock::ReplicaId;
   6use collections::{BTreeMap, Bound, HashMap, HashSet};
   7use futures::{channel::mpsc, SinkExt};
   8use git::diff::DiffHunk;
   9use gpui::{AppContext, EventEmitter, Model, ModelContext};
  10use itertools::Itertools;
  11use language::{
  12    char_kind,
  13    language_settings::{language_settings, LanguageSettings},
  14    AutoindentMode, Buffer, BufferChunks, BufferRow, BufferSnapshot, Capability, CharKind, Chunk,
  15    CursorShape, DiagnosticEntry, File, IndentGuide, IndentSize, Language, LanguageScope,
  16    OffsetRangeExt, OffsetUtf16, Outline, OutlineItem, Point, PointUtf16, Selection, TextDimension,
  17    ToOffset as _, ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _, TransactionId, Unclipped,
  18};
  19use smallvec::SmallVec;
  20use std::{
  21    borrow::Cow,
  22    cell::{Ref, RefCell},
  23    cmp, fmt,
  24    future::Future,
  25    io,
  26    iter::{self, FromIterator},
  27    mem,
  28    ops::{Range, RangeBounds, Sub},
  29    str,
  30    sync::Arc,
  31    time::{Duration, Instant},
  32};
  33use sum_tree::{Bias, Cursor, SumTree};
  34use text::{
  35    locator::Locator,
  36    subscription::{Subscription, Topic},
  37    BufferId, Edit, TextSummary,
  38};
  39use theme::SyntaxTheme;
  40
  41use util::post_inc;
  42
  43#[cfg(any(test, feature = "test-support"))]
  44use gpui::Context;
  45
  46const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];
  47
  48#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
  49pub struct ExcerptId(usize);
  50
  51/// One or more [`Buffers`](Buffer) being edited in a single view.
  52///
  53/// See <https://zed.dev/features#multi-buffers>
  54pub struct MultiBuffer {
  55    /// A snapshot of the [`Excerpt`]s in the MultiBuffer.
  56    /// Use [`MultiBuffer::snapshot`] to get a up-to-date snapshot.
  57    snapshot: RefCell<MultiBufferSnapshot>,
  58    /// Contains the state of the buffers being edited
  59    buffers: RefCell<HashMap<BufferId, BufferState>>,
  60    subscriptions: Topic,
  61    /// If true, the multi-buffer only contains a single [`Buffer`] and a single [`Excerpt`]
  62    singleton: bool,
  63    replica_id: ReplicaId,
  64    history: History,
  65    title: Option<String>,
  66    capability: Capability,
  67}
  68
  69#[derive(Clone, Debug, PartialEq, Eq)]
  70pub enum Event {
  71    ExcerptsAdded {
  72        buffer: Model<Buffer>,
  73        predecessor: ExcerptId,
  74        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
  75    },
  76    ExcerptsRemoved {
  77        ids: Vec<ExcerptId>,
  78    },
  79    ExcerptsEdited {
  80        ids: Vec<ExcerptId>,
  81    },
  82    Edited {
  83        singleton_buffer_edited: bool,
  84    },
  85    TransactionUndone {
  86        transaction_id: TransactionId,
  87    },
  88    Reloaded,
  89    DiffBaseChanged,
  90    DiffUpdated {
  91        buffer: Model<Buffer>,
  92    },
  93    LanguageChanged,
  94    CapabilityChanged,
  95    Reparsed,
  96    Saved,
  97    FileHandleChanged,
  98    Closed,
  99    DirtyChanged,
 100    DiagnosticsUpdated,
 101}
 102
 103pub type MultiBufferPoint = Point;
 104
 105#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq, serde::Deserialize)]
 106#[serde(transparent)]
 107pub struct MultiBufferRow(pub u32);
 108
 109impl MultiBufferRow {
 110    pub const MIN: Self = Self(0);
 111    pub const MAX: Self = Self(u32::MAX);
 112}
 113
 114#[derive(Clone)]
 115struct History {
 116    next_transaction_id: TransactionId,
 117    undo_stack: Vec<Transaction>,
 118    redo_stack: Vec<Transaction>,
 119    transaction_depth: usize,
 120    group_interval: Duration,
 121}
 122
 123#[derive(Clone)]
 124struct Transaction {
 125    id: TransactionId,
 126    buffer_transactions: HashMap<BufferId, text::TransactionId>,
 127    first_edit_at: Instant,
 128    last_edit_at: Instant,
 129    suppress_grouping: bool,
 130}
 131
 132pub trait ToOffset: 'static + fmt::Debug {
 133    fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
 134}
 135
 136pub trait ToOffsetUtf16: 'static + fmt::Debug {
 137    fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16;
 138}
 139
 140pub trait ToPoint: 'static + fmt::Debug {
 141    fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point;
 142}
 143
 144pub trait ToPointUtf16: 'static + fmt::Debug {
 145    fn to_point_utf16(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16;
 146}
 147
 148struct BufferState {
 149    buffer: Model<Buffer>,
 150    last_version: clock::Global,
 151    last_parse_count: usize,
 152    last_selections_update_count: usize,
 153    last_diagnostics_update_count: usize,
 154    last_file_update_count: usize,
 155    last_git_diff_update_count: usize,
 156    excerpts: Vec<Locator>,
 157    _subscriptions: [gpui::Subscription; 2],
 158}
 159
 160/// The contents of a [`MultiBuffer`] at a single point in time.
 161#[derive(Clone, Default)]
 162pub struct MultiBufferSnapshot {
 163    singleton: bool,
 164    excerpts: SumTree<Excerpt>,
 165    excerpt_ids: SumTree<ExcerptIdMapping>,
 166    parse_count: usize,
 167    diagnostics_update_count: usize,
 168    trailing_excerpt_update_count: usize,
 169    git_diff_update_count: usize,
 170    edit_count: usize,
 171    is_dirty: bool,
 172    has_conflict: bool,
 173    show_headers: bool,
 174}
 175
 176/// A boundary between [`Excerpt`]s in a [`MultiBuffer`]
 177pub struct ExcerptBoundary {
 178    pub id: ExcerptId,
 179    pub row: MultiBufferRow,
 180    pub buffer: BufferSnapshot,
 181    pub range: ExcerptRange<text::Anchor>,
 182    /// It's possible to have multiple excerpts in the same buffer,
 183    /// and they are rendered together without a new File header.
 184    ///
 185    /// This flag indicates that the excerpt is the first one in the buffer.
 186    pub starts_new_buffer: bool,
 187}
 188
 189/// A slice into a [`Buffer`] that is being edited in a [`MultiBuffer`].
 190#[derive(Clone)]
 191struct Excerpt {
 192    /// The unique identifier for this excerpt
 193    id: ExcerptId,
 194    /// The location of the excerpt in the [`MultiBuffer`]
 195    locator: Locator,
 196    /// The buffer being excerpted
 197    buffer_id: BufferId,
 198    /// A snapshot of the buffer being excerpted
 199    buffer: BufferSnapshot,
 200    /// The range of the buffer to be shown in the excerpt
 201    range: ExcerptRange<text::Anchor>,
 202    /// The last row in the excerpted slice of the buffer
 203    max_buffer_row: BufferRow,
 204    /// A summary of the text in the excerpt
 205    text_summary: TextSummary,
 206    has_trailing_newline: bool,
 207}
 208
 209/// A public view into an [`Excerpt`] in a [`MultiBuffer`].
 210///
 211/// Contains methods for getting the [`Buffer`] of the excerpt,
 212/// as well as mapping offsets to/from buffer and multibuffer coordinates.
 213#[derive(Clone)]
 214pub struct MultiBufferExcerpt<'a> {
 215    excerpt: &'a Excerpt,
 216    excerpt_offset: usize,
 217}
 218
 219#[derive(Clone, Debug)]
 220struct ExcerptIdMapping {
 221    id: ExcerptId,
 222    locator: Locator,
 223}
 224
 225/// A range of text from a single [`Buffer`], to be shown as an [`Excerpt`].
 226/// These ranges are relative to the buffer itself
 227#[derive(Clone, Debug, Eq, PartialEq)]
 228pub struct ExcerptRange<T> {
 229    /// The full range of text to be shown in the excerpt.
 230    pub context: Range<T>,
 231    /// The primary range of text to be highlighted in the excerpt.
 232    /// In a multi-buffer search, this would be the text that matched the search
 233    pub primary: Option<Range<T>>,
 234}
 235
 236#[derive(Clone, Debug, Default)]
 237struct ExcerptSummary {
 238    excerpt_id: ExcerptId,
 239    /// The location of the last [`Excerpt`] being summarized
 240    excerpt_locator: Locator,
 241    /// The maximum row of the [`Excerpt`]s being summarized
 242    max_buffer_row: MultiBufferRow,
 243    text: TextSummary,
 244}
 245
 246#[derive(Clone)]
 247pub struct MultiBufferRows<'a> {
 248    buffer_row_range: Range<u32>,
 249    excerpts: Cursor<'a, Excerpt, Point>,
 250}
 251
 252pub struct MultiBufferChunks<'a> {
 253    range: Range<usize>,
 254    excerpts: Cursor<'a, Excerpt, usize>,
 255    excerpt_chunks: Option<ExcerptChunks<'a>>,
 256    language_aware: bool,
 257}
 258
 259pub struct MultiBufferBytes<'a> {
 260    range: Range<usize>,
 261    excerpts: Cursor<'a, Excerpt, usize>,
 262    excerpt_bytes: Option<ExcerptBytes<'a>>,
 263    chunk: &'a [u8],
 264}
 265
 266pub struct ReversedMultiBufferBytes<'a> {
 267    range: Range<usize>,
 268    excerpts: Cursor<'a, Excerpt, usize>,
 269    excerpt_bytes: Option<ExcerptBytes<'a>>,
 270    chunk: &'a [u8],
 271}
 272
 273struct ExcerptChunks<'a> {
 274    content_chunks: BufferChunks<'a>,
 275    footer_height: usize,
 276}
 277
 278struct ExcerptBytes<'a> {
 279    content_bytes: text::Bytes<'a>,
 280    padding_height: usize,
 281    reversed: bool,
 282}
 283
 284#[derive(Clone, Debug, PartialEq)]
 285pub struct MultiBufferIndentGuide {
 286    pub multibuffer_row_range: Range<MultiBufferRow>,
 287    pub buffer: IndentGuide,
 288}
 289
 290impl std::ops::Deref for MultiBufferIndentGuide {
 291    type Target = IndentGuide;
 292
 293    fn deref(&self) -> &Self::Target {
 294        &self.buffer
 295    }
 296}
 297
 298impl MultiBuffer {
 299    pub fn new(replica_id: ReplicaId, capability: Capability) -> Self {
 300        Self {
 301            snapshot: RefCell::new(MultiBufferSnapshot {
 302                show_headers: true,
 303                ..MultiBufferSnapshot::default()
 304            }),
 305            buffers: RefCell::default(),
 306            subscriptions: Topic::default(),
 307            singleton: false,
 308            capability,
 309            replica_id,
 310            title: None,
 311            history: History {
 312                next_transaction_id: clock::Lamport::default(),
 313                undo_stack: Vec::new(),
 314                redo_stack: Vec::new(),
 315                transaction_depth: 0,
 316                group_interval: Duration::from_millis(300),
 317            },
 318        }
 319    }
 320
 321    pub fn without_headers(replica_id: ReplicaId, capability: Capability) -> Self {
 322        Self {
 323            snapshot: Default::default(),
 324            buffers: Default::default(),
 325            subscriptions: Default::default(),
 326            singleton: false,
 327            capability,
 328            replica_id,
 329            history: History {
 330                next_transaction_id: Default::default(),
 331                undo_stack: Default::default(),
 332                redo_stack: Default::default(),
 333                transaction_depth: 0,
 334                group_interval: Duration::from_millis(300),
 335            },
 336            title: Default::default(),
 337        }
 338    }
 339
 340    pub fn clone(&self, new_cx: &mut ModelContext<Self>) -> Self {
 341        let mut buffers = HashMap::default();
 342        for (buffer_id, buffer_state) in self.buffers.borrow().iter() {
 343            buffers.insert(
 344                *buffer_id,
 345                BufferState {
 346                    buffer: buffer_state.buffer.clone(),
 347                    last_version: buffer_state.last_version.clone(),
 348                    last_parse_count: buffer_state.last_parse_count,
 349                    last_selections_update_count: buffer_state.last_selections_update_count,
 350                    last_diagnostics_update_count: buffer_state.last_diagnostics_update_count,
 351                    last_file_update_count: buffer_state.last_file_update_count,
 352                    last_git_diff_update_count: buffer_state.last_git_diff_update_count,
 353                    excerpts: buffer_state.excerpts.clone(),
 354                    _subscriptions: [
 355                        new_cx.observe(&buffer_state.buffer, |_, _, cx| cx.notify()),
 356                        new_cx.subscribe(&buffer_state.buffer, Self::on_buffer_event),
 357                    ],
 358                },
 359            );
 360        }
 361        Self {
 362            snapshot: RefCell::new(self.snapshot.borrow().clone()),
 363            buffers: RefCell::new(buffers),
 364            subscriptions: Default::default(),
 365            singleton: self.singleton,
 366            capability: self.capability,
 367            replica_id: self.replica_id,
 368            history: self.history.clone(),
 369            title: self.title.clone(),
 370        }
 371    }
 372
 373    pub fn with_title(mut self, title: String) -> Self {
 374        self.title = Some(title);
 375        self
 376    }
 377
 378    pub fn read_only(&self) -> bool {
 379        self.capability == Capability::ReadOnly
 380    }
 381
 382    pub fn singleton(buffer: Model<Buffer>, cx: &mut ModelContext<Self>) -> Self {
 383        let mut this = Self::new(buffer.read(cx).replica_id(), buffer.read(cx).capability());
 384        this.singleton = true;
 385        this.push_excerpts(
 386            buffer,
 387            [ExcerptRange {
 388                context: text::Anchor::MIN..text::Anchor::MAX,
 389                primary: None,
 390            }],
 391            cx,
 392        );
 393        this.snapshot.borrow_mut().singleton = true;
 394        this
 395    }
 396
 397    pub fn replica_id(&self) -> ReplicaId {
 398        self.replica_id
 399    }
 400
 401    /// Returns an up-to-date snapshot of the MultiBuffer.
 402    pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot {
 403        self.sync(cx);
 404        self.snapshot.borrow().clone()
 405    }
 406
 407    pub fn read(&self, cx: &AppContext) -> Ref<MultiBufferSnapshot> {
 408        self.sync(cx);
 409        self.snapshot.borrow()
 410    }
 411
 412    pub fn as_singleton(&self) -> Option<Model<Buffer>> {
 413        if self.singleton {
 414            return Some(
 415                self.buffers
 416                    .borrow()
 417                    .values()
 418                    .next()
 419                    .unwrap()
 420                    .buffer
 421                    .clone(),
 422            );
 423        } else {
 424            None
 425        }
 426    }
 427
 428    pub fn is_singleton(&self) -> bool {
 429        self.singleton
 430    }
 431
 432    pub fn subscribe(&mut self) -> Subscription {
 433        self.subscriptions.subscribe()
 434    }
 435
 436    pub fn is_dirty(&self, cx: &AppContext) -> bool {
 437        self.read(cx).is_dirty()
 438    }
 439
 440    pub fn has_conflict(&self, cx: &AppContext) -> bool {
 441        self.read(cx).has_conflict()
 442    }
 443
 444    // The `is_empty` signature doesn't match what clippy expects
 445    #[allow(clippy::len_without_is_empty)]
 446    pub fn len(&self, cx: &AppContext) -> usize {
 447        self.read(cx).len()
 448    }
 449
 450    pub fn is_empty(&self, cx: &AppContext) -> bool {
 451        self.len(cx) != 0
 452    }
 453
 454    pub fn symbols_containing<T: ToOffset>(
 455        &self,
 456        offset: T,
 457        theme: Option<&SyntaxTheme>,
 458        cx: &AppContext,
 459    ) -> Option<(BufferId, Vec<OutlineItem<Anchor>>)> {
 460        self.read(cx).symbols_containing(offset, theme)
 461    }
 462
 463    pub fn edit<I, S, T>(
 464        &mut self,
 465        edits: I,
 466        mut autoindent_mode: Option<AutoindentMode>,
 467        cx: &mut ModelContext<Self>,
 468    ) where
 469        I: IntoIterator<Item = (Range<S>, T)>,
 470        S: ToOffset,
 471        T: Into<Arc<str>>,
 472    {
 473        if self.read_only() {
 474            return;
 475        }
 476        if self.buffers.borrow().is_empty() {
 477            return;
 478        }
 479
 480        let snapshot = self.read(cx);
 481        let edits = edits.into_iter().map(|(range, new_text)| {
 482            let mut range = range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot);
 483            if range.start > range.end {
 484                mem::swap(&mut range.start, &mut range.end);
 485            }
 486            (range, new_text)
 487        });
 488
 489        if let Some(buffer) = self.as_singleton() {
 490            return buffer.update(cx, |buffer, cx| {
 491                buffer.edit(edits, autoindent_mode, cx);
 492            });
 493        }
 494
 495        let original_indent_columns = match &mut autoindent_mode {
 496            Some(AutoindentMode::Block {
 497                original_indent_columns,
 498            }) => mem::take(original_indent_columns),
 499            _ => Default::default(),
 500        };
 501
 502        struct BufferEdit {
 503            range: Range<usize>,
 504            new_text: Arc<str>,
 505            is_insertion: bool,
 506            original_indent_column: u32,
 507        }
 508        let mut buffer_edits: HashMap<BufferId, Vec<BufferEdit>> = Default::default();
 509        let mut edited_excerpt_ids = Vec::new();
 510        let mut cursor = snapshot.excerpts.cursor::<usize>();
 511        for (ix, (range, new_text)) in edits.enumerate() {
 512            let new_text: Arc<str> = new_text.into();
 513            let original_indent_column = original_indent_columns.get(ix).copied().unwrap_or(0);
 514            cursor.seek(&range.start, Bias::Right, &());
 515            if cursor.item().is_none() && range.start == *cursor.start() {
 516                cursor.prev(&());
 517            }
 518            let start_excerpt = cursor.item().expect("start offset out of bounds");
 519            let start_overshoot = range.start - cursor.start();
 520            let buffer_start = start_excerpt
 521                .range
 522                .context
 523                .start
 524                .to_offset(&start_excerpt.buffer)
 525                + start_overshoot;
 526            edited_excerpt_ids.push(start_excerpt.id);
 527
 528            cursor.seek(&range.end, Bias::Right, &());
 529            if cursor.item().is_none() && range.end == *cursor.start() {
 530                cursor.prev(&());
 531            }
 532            let end_excerpt = cursor.item().expect("end offset out of bounds");
 533            let end_overshoot = range.end - cursor.start();
 534            let buffer_end = end_excerpt
 535                .range
 536                .context
 537                .start
 538                .to_offset(&end_excerpt.buffer)
 539                + end_overshoot;
 540
 541            if start_excerpt.id == end_excerpt.id {
 542                buffer_edits
 543                    .entry(start_excerpt.buffer_id)
 544                    .or_insert(Vec::new())
 545                    .push(BufferEdit {
 546                        range: buffer_start..buffer_end,
 547                        new_text,
 548                        is_insertion: true,
 549                        original_indent_column,
 550                    });
 551            } else {
 552                edited_excerpt_ids.push(end_excerpt.id);
 553                let start_excerpt_range = buffer_start
 554                    ..start_excerpt
 555                        .range
 556                        .context
 557                        .end
 558                        .to_offset(&start_excerpt.buffer);
 559                let end_excerpt_range = end_excerpt
 560                    .range
 561                    .context
 562                    .start
 563                    .to_offset(&end_excerpt.buffer)
 564                    ..buffer_end;
 565                buffer_edits
 566                    .entry(start_excerpt.buffer_id)
 567                    .or_insert(Vec::new())
 568                    .push(BufferEdit {
 569                        range: start_excerpt_range,
 570                        new_text: new_text.clone(),
 571                        is_insertion: true,
 572                        original_indent_column,
 573                    });
 574                buffer_edits
 575                    .entry(end_excerpt.buffer_id)
 576                    .or_insert(Vec::new())
 577                    .push(BufferEdit {
 578                        range: end_excerpt_range,
 579                        new_text: new_text.clone(),
 580                        is_insertion: false,
 581                        original_indent_column,
 582                    });
 583
 584                cursor.seek(&range.start, Bias::Right, &());
 585                cursor.next(&());
 586                while let Some(excerpt) = cursor.item() {
 587                    if excerpt.id == end_excerpt.id {
 588                        break;
 589                    }
 590                    buffer_edits
 591                        .entry(excerpt.buffer_id)
 592                        .or_insert(Vec::new())
 593                        .push(BufferEdit {
 594                            range: excerpt.range.context.to_offset(&excerpt.buffer),
 595                            new_text: new_text.clone(),
 596                            is_insertion: false,
 597                            original_indent_column,
 598                        });
 599                    edited_excerpt_ids.push(excerpt.id);
 600                    cursor.next(&());
 601                }
 602            }
 603        }
 604
 605        drop(cursor);
 606        drop(snapshot);
 607        // Non-generic part of edit, hoisted out to avoid blowing up LLVM IR.
 608        fn tail(
 609            this: &mut MultiBuffer,
 610            buffer_edits: HashMap<BufferId, Vec<BufferEdit>>,
 611            autoindent_mode: Option<AutoindentMode>,
 612            edited_excerpt_ids: Vec<ExcerptId>,
 613            cx: &mut ModelContext<MultiBuffer>,
 614        ) {
 615            for (buffer_id, mut edits) in buffer_edits {
 616                edits.sort_unstable_by_key(|edit| edit.range.start);
 617                this.buffers.borrow()[&buffer_id]
 618                    .buffer
 619                    .update(cx, |buffer, cx| {
 620                        let mut edits = edits.into_iter().peekable();
 621                        let mut insertions = Vec::new();
 622                        let mut original_indent_columns = Vec::new();
 623                        let mut deletions = Vec::new();
 624                        let empty_str: Arc<str> = "".into();
 625                        while let Some(BufferEdit {
 626                            mut range,
 627                            new_text,
 628                            mut is_insertion,
 629                            original_indent_column,
 630                        }) = edits.next()
 631                        {
 632                            while let Some(BufferEdit {
 633                                range: next_range,
 634                                is_insertion: next_is_insertion,
 635                                ..
 636                            }) = edits.peek()
 637                            {
 638                                if range.end >= next_range.start {
 639                                    range.end = cmp::max(next_range.end, range.end);
 640                                    is_insertion |= *next_is_insertion;
 641                                    edits.next();
 642                                } else {
 643                                    break;
 644                                }
 645                            }
 646
 647                            if is_insertion {
 648                                original_indent_columns.push(original_indent_column);
 649                                insertions.push((
 650                                    buffer.anchor_before(range.start)
 651                                        ..buffer.anchor_before(range.end),
 652                                    new_text.clone(),
 653                                ));
 654                            } else if !range.is_empty() {
 655                                deletions.push((
 656                                    buffer.anchor_before(range.start)
 657                                        ..buffer.anchor_before(range.end),
 658                                    empty_str.clone(),
 659                                ));
 660                            }
 661                        }
 662
 663                        let deletion_autoindent_mode =
 664                            if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
 665                                Some(AutoindentMode::Block {
 666                                    original_indent_columns: Default::default(),
 667                                })
 668                            } else {
 669                                None
 670                            };
 671                        let insertion_autoindent_mode =
 672                            if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
 673                                Some(AutoindentMode::Block {
 674                                    original_indent_columns,
 675                                })
 676                            } else {
 677                                None
 678                            };
 679
 680                        buffer.edit(deletions, deletion_autoindent_mode, cx);
 681                        buffer.edit(insertions, insertion_autoindent_mode, cx);
 682                    })
 683            }
 684
 685            cx.emit(Event::ExcerptsEdited {
 686                ids: edited_excerpt_ids,
 687            });
 688        }
 689        tail(self, buffer_edits, autoindent_mode, edited_excerpt_ids, cx);
 690    }
 691
 692    pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 693        self.start_transaction_at(Instant::now(), cx)
 694    }
 695
 696    pub fn start_transaction_at(
 697        &mut self,
 698        now: Instant,
 699        cx: &mut ModelContext<Self>,
 700    ) -> Option<TransactionId> {
 701        if let Some(buffer) = self.as_singleton() {
 702            return buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
 703        }
 704
 705        for BufferState { buffer, .. } in self.buffers.borrow().values() {
 706            buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
 707        }
 708        self.history.start_transaction(now)
 709    }
 710
 711    pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 712        self.end_transaction_at(Instant::now(), cx)
 713    }
 714
 715    pub fn end_transaction_at(
 716        &mut self,
 717        now: Instant,
 718        cx: &mut ModelContext<Self>,
 719    ) -> Option<TransactionId> {
 720        if let Some(buffer) = self.as_singleton() {
 721            return buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx));
 722        }
 723
 724        let mut buffer_transactions = HashMap::default();
 725        for BufferState { buffer, .. } in self.buffers.borrow().values() {
 726            if let Some(transaction_id) =
 727                buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
 728            {
 729                buffer_transactions.insert(buffer.read(cx).remote_id(), transaction_id);
 730            }
 731        }
 732
 733        if self.history.end_transaction(now, buffer_transactions) {
 734            let transaction_id = self.history.group().unwrap();
 735            Some(transaction_id)
 736        } else {
 737            None
 738        }
 739    }
 740
 741    pub fn merge_transactions(
 742        &mut self,
 743        transaction: TransactionId,
 744        destination: TransactionId,
 745        cx: &mut ModelContext<Self>,
 746    ) {
 747        if let Some(buffer) = self.as_singleton() {
 748            buffer.update(cx, |buffer, _| {
 749                buffer.merge_transactions(transaction, destination)
 750            });
 751        } else {
 752            if let Some(transaction) = self.history.forget(transaction) {
 753                if let Some(destination) = self.history.transaction_mut(destination) {
 754                    for (buffer_id, buffer_transaction_id) in transaction.buffer_transactions {
 755                        if let Some(destination_buffer_transaction_id) =
 756                            destination.buffer_transactions.get(&buffer_id)
 757                        {
 758                            if let Some(state) = self.buffers.borrow().get(&buffer_id) {
 759                                state.buffer.update(cx, |buffer, _| {
 760                                    buffer.merge_transactions(
 761                                        buffer_transaction_id,
 762                                        *destination_buffer_transaction_id,
 763                                    )
 764                                });
 765                            }
 766                        } else {
 767                            destination
 768                                .buffer_transactions
 769                                .insert(buffer_id, buffer_transaction_id);
 770                        }
 771                    }
 772                }
 773            }
 774        }
 775    }
 776
 777    pub fn finalize_last_transaction(&mut self, cx: &mut ModelContext<Self>) {
 778        self.history.finalize_last_transaction();
 779        for BufferState { buffer, .. } in self.buffers.borrow().values() {
 780            buffer.update(cx, |buffer, _| {
 781                buffer.finalize_last_transaction();
 782            });
 783        }
 784    }
 785
 786    pub fn push_transaction<'a, T>(&mut self, buffer_transactions: T, cx: &mut ModelContext<Self>)
 787    where
 788        T: IntoIterator<Item = (&'a Model<Buffer>, &'a language::Transaction)>,
 789    {
 790        self.history
 791            .push_transaction(buffer_transactions, Instant::now(), cx);
 792        self.history.finalize_last_transaction();
 793    }
 794
 795    pub fn group_until_transaction(
 796        &mut self,
 797        transaction_id: TransactionId,
 798        cx: &mut ModelContext<Self>,
 799    ) {
 800        if let Some(buffer) = self.as_singleton() {
 801            buffer.update(cx, |buffer, _| {
 802                buffer.group_until_transaction(transaction_id)
 803            });
 804        } else {
 805            self.history.group_until(transaction_id);
 806        }
 807    }
 808
 809    pub fn set_active_selections(
 810        &mut self,
 811        selections: &[Selection<Anchor>],
 812        line_mode: bool,
 813        cursor_shape: CursorShape,
 814        cx: &mut ModelContext<Self>,
 815    ) {
 816        let mut selections_by_buffer: HashMap<BufferId, Vec<Selection<text::Anchor>>> =
 817            Default::default();
 818        let snapshot = self.read(cx);
 819        let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>();
 820        for selection in selections {
 821            let start_locator = snapshot.excerpt_locator_for_id(selection.start.excerpt_id);
 822            let end_locator = snapshot.excerpt_locator_for_id(selection.end.excerpt_id);
 823
 824            cursor.seek(&Some(start_locator), Bias::Left, &());
 825            while let Some(excerpt) = cursor.item() {
 826                if excerpt.locator > *end_locator {
 827                    break;
 828                }
 829
 830                let mut start = excerpt.range.context.start;
 831                let mut end = excerpt.range.context.end;
 832                if excerpt.id == selection.start.excerpt_id {
 833                    start = selection.start.text_anchor;
 834                }
 835                if excerpt.id == selection.end.excerpt_id {
 836                    end = selection.end.text_anchor;
 837                }
 838                selections_by_buffer
 839                    .entry(excerpt.buffer_id)
 840                    .or_default()
 841                    .push(Selection {
 842                        id: selection.id,
 843                        start,
 844                        end,
 845                        reversed: selection.reversed,
 846                        goal: selection.goal,
 847                    });
 848
 849                cursor.next(&());
 850            }
 851        }
 852
 853        for (buffer_id, buffer_state) in self.buffers.borrow().iter() {
 854            if !selections_by_buffer.contains_key(buffer_id) {
 855                buffer_state
 856                    .buffer
 857                    .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
 858            }
 859        }
 860
 861        for (buffer_id, mut selections) in selections_by_buffer {
 862            self.buffers.borrow()[&buffer_id]
 863                .buffer
 864                .update(cx, |buffer, cx| {
 865                    selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer));
 866                    let mut selections = selections.into_iter().peekable();
 867                    let merged_selections = Arc::from_iter(iter::from_fn(|| {
 868                        let mut selection = selections.next()?;
 869                        while let Some(next_selection) = selections.peek() {
 870                            if selection.end.cmp(&next_selection.start, buffer).is_ge() {
 871                                let next_selection = selections.next().unwrap();
 872                                if next_selection.end.cmp(&selection.end, buffer).is_ge() {
 873                                    selection.end = next_selection.end;
 874                                }
 875                            } else {
 876                                break;
 877                            }
 878                        }
 879                        Some(selection)
 880                    }));
 881                    buffer.set_active_selections(merged_selections, line_mode, cursor_shape, cx);
 882                });
 883        }
 884    }
 885
 886    pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
 887        for buffer in self.buffers.borrow().values() {
 888            buffer
 889                .buffer
 890                .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
 891        }
 892    }
 893
 894    pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 895        let mut transaction_id = None;
 896        if let Some(buffer) = self.as_singleton() {
 897            transaction_id = buffer.update(cx, |buffer, cx| buffer.undo(cx));
 898        } else {
 899            while let Some(transaction) = self.history.pop_undo() {
 900                let mut undone = false;
 901                for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions {
 902                    if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
 903                        undone |= buffer.update(cx, |buffer, cx| {
 904                            let undo_to = *buffer_transaction_id;
 905                            if let Some(entry) = buffer.peek_undo_stack() {
 906                                *buffer_transaction_id = entry.transaction_id();
 907                            }
 908                            buffer.undo_to_transaction(undo_to, cx)
 909                        });
 910                    }
 911                }
 912
 913                if undone {
 914                    transaction_id = Some(transaction.id);
 915                    break;
 916                }
 917            }
 918        }
 919
 920        if let Some(transaction_id) = transaction_id {
 921            cx.emit(Event::TransactionUndone { transaction_id });
 922        }
 923
 924        transaction_id
 925    }
 926
 927    pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 928        if let Some(buffer) = self.as_singleton() {
 929            return buffer.update(cx, |buffer, cx| buffer.redo(cx));
 930        }
 931
 932        while let Some(transaction) = self.history.pop_redo() {
 933            let mut redone = false;
 934            for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions {
 935                if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
 936                    redone |= buffer.update(cx, |buffer, cx| {
 937                        let redo_to = *buffer_transaction_id;
 938                        if let Some(entry) = buffer.peek_redo_stack() {
 939                            *buffer_transaction_id = entry.transaction_id();
 940                        }
 941                        buffer.redo_to_transaction(redo_to, cx)
 942                    });
 943                }
 944            }
 945
 946            if redone {
 947                return Some(transaction.id);
 948            }
 949        }
 950
 951        None
 952    }
 953
 954    pub fn undo_transaction(&mut self, transaction_id: TransactionId, cx: &mut ModelContext<Self>) {
 955        if let Some(buffer) = self.as_singleton() {
 956            buffer.update(cx, |buffer, cx| buffer.undo_transaction(transaction_id, cx));
 957        } else if let Some(transaction) = self.history.remove_from_undo(transaction_id) {
 958            for (buffer_id, transaction_id) in &transaction.buffer_transactions {
 959                if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
 960                    buffer.update(cx, |buffer, cx| {
 961                        buffer.undo_transaction(*transaction_id, cx)
 962                    });
 963                }
 964            }
 965        }
 966    }
 967
 968    pub fn stream_excerpts_with_context_lines(
 969        &mut self,
 970        buffer: Model<Buffer>,
 971        ranges: Vec<Range<text::Anchor>>,
 972        context_line_count: u32,
 973        cx: &mut ModelContext<Self>,
 974    ) -> mpsc::Receiver<Range<Anchor>> {
 975        let (buffer_id, buffer_snapshot) =
 976            buffer.update(cx, |buffer, _| (buffer.remote_id(), buffer.snapshot()));
 977
 978        let (mut tx, rx) = mpsc::channel(256);
 979        cx.spawn(move |this, mut cx| async move {
 980            let mut excerpt_ranges = Vec::new();
 981            let mut range_counts = Vec::new();
 982            cx.background_executor()
 983                .scoped(|scope| {
 984                    scope.spawn(async {
 985                        let (ranges, counts) =
 986                            build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
 987                        excerpt_ranges = ranges;
 988                        range_counts = counts;
 989                    });
 990                })
 991                .await;
 992
 993            let mut ranges = ranges.into_iter();
 994            let mut range_counts = range_counts.into_iter();
 995            for excerpt_ranges in excerpt_ranges.chunks(100) {
 996                let excerpt_ids = match this.update(&mut cx, |this, cx| {
 997                    this.push_excerpts(buffer.clone(), excerpt_ranges.iter().cloned(), cx)
 998                }) {
 999                    Ok(excerpt_ids) => excerpt_ids,
1000                    Err(_) => return,
1001                };
1002
1003                for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.by_ref())
1004                {
1005                    for range in ranges.by_ref().take(range_count) {
1006                        let start = Anchor {
1007                            buffer_id: Some(buffer_id),
1008                            excerpt_id: excerpt_id,
1009                            text_anchor: range.start,
1010                        };
1011                        let end = Anchor {
1012                            buffer_id: Some(buffer_id),
1013                            excerpt_id: excerpt_id,
1014                            text_anchor: range.end,
1015                        };
1016                        if tx.send(start..end).await.is_err() {
1017                            break;
1018                        }
1019                    }
1020                }
1021            }
1022        })
1023        .detach();
1024
1025        rx
1026    }
1027
1028    pub fn push_excerpts<O>(
1029        &mut self,
1030        buffer: Model<Buffer>,
1031        ranges: impl IntoIterator<Item = ExcerptRange<O>>,
1032        cx: &mut ModelContext<Self>,
1033    ) -> Vec<ExcerptId>
1034    where
1035        O: text::ToOffset,
1036    {
1037        self.insert_excerpts_after(ExcerptId::max(), buffer, ranges, cx)
1038    }
1039
1040    pub fn push_excerpts_with_context_lines<O>(
1041        &mut self,
1042        buffer: Model<Buffer>,
1043        ranges: Vec<Range<O>>,
1044        context_line_count: u32,
1045        cx: &mut ModelContext<Self>,
1046    ) -> Vec<Range<Anchor>>
1047    where
1048        O: text::ToPoint + text::ToOffset,
1049    {
1050        let buffer_id = buffer.read(cx).remote_id();
1051        let buffer_snapshot = buffer.read(cx).snapshot();
1052        let (excerpt_ranges, range_counts) =
1053            build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
1054
1055        let excerpt_ids = self.push_excerpts(buffer, excerpt_ranges, cx);
1056
1057        let mut anchor_ranges = Vec::new();
1058        let mut ranges = ranges.into_iter();
1059        for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.into_iter()) {
1060            anchor_ranges.extend(ranges.by_ref().take(range_count).map(|range| {
1061                let start = Anchor {
1062                    buffer_id: Some(buffer_id),
1063                    excerpt_id,
1064                    text_anchor: buffer_snapshot.anchor_after(range.start),
1065                };
1066                let end = Anchor {
1067                    buffer_id: Some(buffer_id),
1068                    excerpt_id,
1069                    text_anchor: buffer_snapshot.anchor_after(range.end),
1070                };
1071                start..end
1072            }))
1073        }
1074        anchor_ranges
1075    }
1076
1077    pub fn insert_excerpts_after<O>(
1078        &mut self,
1079        prev_excerpt_id: ExcerptId,
1080        buffer: Model<Buffer>,
1081        ranges: impl IntoIterator<Item = ExcerptRange<O>>,
1082        cx: &mut ModelContext<Self>,
1083    ) -> Vec<ExcerptId>
1084    where
1085        O: text::ToOffset,
1086    {
1087        let mut ids = Vec::new();
1088        let mut next_excerpt_id =
1089            if let Some(last_entry) = self.snapshot.borrow().excerpt_ids.last() {
1090                last_entry.id.0 + 1
1091            } else {
1092                1
1093            };
1094        self.insert_excerpts_with_ids_after(
1095            prev_excerpt_id,
1096            buffer,
1097            ranges.into_iter().map(|range| {
1098                let id = ExcerptId(post_inc(&mut next_excerpt_id));
1099                ids.push(id);
1100                (id, range)
1101            }),
1102            cx,
1103        );
1104        ids
1105    }
1106
1107    pub fn insert_excerpts_with_ids_after<O>(
1108        &mut self,
1109        prev_excerpt_id: ExcerptId,
1110        buffer: Model<Buffer>,
1111        ranges: impl IntoIterator<Item = (ExcerptId, ExcerptRange<O>)>,
1112        cx: &mut ModelContext<Self>,
1113    ) where
1114        O: text::ToOffset,
1115    {
1116        assert_eq!(self.history.transaction_depth, 0);
1117        let mut ranges = ranges.into_iter().peekable();
1118        if ranges.peek().is_none() {
1119            return Default::default();
1120        }
1121
1122        self.sync(cx);
1123
1124        let buffer_id = buffer.read(cx).remote_id();
1125        let buffer_snapshot = buffer.read(cx).snapshot();
1126
1127        let mut buffers = self.buffers.borrow_mut();
1128        let buffer_state = buffers.entry(buffer_id).or_insert_with(|| BufferState {
1129            last_version: buffer_snapshot.version().clone(),
1130            last_parse_count: buffer_snapshot.parse_count(),
1131            last_selections_update_count: buffer_snapshot.selections_update_count(),
1132            last_diagnostics_update_count: buffer_snapshot.diagnostics_update_count(),
1133            last_file_update_count: buffer_snapshot.file_update_count(),
1134            last_git_diff_update_count: buffer_snapshot.git_diff_update_count(),
1135            excerpts: Default::default(),
1136            _subscriptions: [
1137                cx.observe(&buffer, |_, _, cx| cx.notify()),
1138                cx.subscribe(&buffer, Self::on_buffer_event),
1139            ],
1140            buffer: buffer.clone(),
1141        });
1142
1143        let mut snapshot = self.snapshot.borrow_mut();
1144
1145        let mut prev_locator = snapshot.excerpt_locator_for_id(prev_excerpt_id).clone();
1146        let mut new_excerpt_ids = mem::take(&mut snapshot.excerpt_ids);
1147        let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>();
1148        let mut new_excerpts = cursor.slice(&prev_locator, Bias::Right, &());
1149        prev_locator = cursor.start().unwrap_or(Locator::min_ref()).clone();
1150
1151        let edit_start = new_excerpts.summary().text.len;
1152        new_excerpts.update_last(
1153            |excerpt| {
1154                excerpt.has_trailing_newline = true;
1155            },
1156            &(),
1157        );
1158
1159        let next_locator = if let Some(excerpt) = cursor.item() {
1160            excerpt.locator.clone()
1161        } else {
1162            Locator::max()
1163        };
1164
1165        let mut excerpts = Vec::new();
1166        while let Some((id, range)) = ranges.next() {
1167            let locator = Locator::between(&prev_locator, &next_locator);
1168            if let Err(ix) = buffer_state.excerpts.binary_search(&locator) {
1169                buffer_state.excerpts.insert(ix, locator.clone());
1170            }
1171            let range = ExcerptRange {
1172                context: buffer_snapshot.anchor_before(&range.context.start)
1173                    ..buffer_snapshot.anchor_after(&range.context.end),
1174                primary: range.primary.map(|primary| {
1175                    buffer_snapshot.anchor_before(&primary.start)
1176                        ..buffer_snapshot.anchor_after(&primary.end)
1177                }),
1178            };
1179            excerpts.push((id, range.clone()));
1180            let excerpt = Excerpt::new(
1181                id,
1182                locator.clone(),
1183                buffer_id,
1184                buffer_snapshot.clone(),
1185                range,
1186                ranges.peek().is_some() || cursor.item().is_some(),
1187            );
1188            new_excerpts.push(excerpt, &());
1189            prev_locator = locator.clone();
1190
1191            if let Some(last_mapping_entry) = new_excerpt_ids.last() {
1192                assert!(id > last_mapping_entry.id, "excerpt ids must be increasing");
1193            }
1194            new_excerpt_ids.push(ExcerptIdMapping { id, locator }, &());
1195        }
1196
1197        let edit_end = new_excerpts.summary().text.len;
1198
1199        let suffix = cursor.suffix(&());
1200        let changed_trailing_excerpt = suffix.is_empty();
1201        new_excerpts.append(suffix, &());
1202        drop(cursor);
1203        snapshot.excerpts = new_excerpts;
1204        snapshot.excerpt_ids = new_excerpt_ids;
1205        if changed_trailing_excerpt {
1206            snapshot.trailing_excerpt_update_count += 1;
1207        }
1208
1209        self.subscriptions.publish_mut([Edit {
1210            old: edit_start..edit_start,
1211            new: edit_start..edit_end,
1212        }]);
1213        cx.emit(Event::Edited {
1214            singleton_buffer_edited: false,
1215        });
1216        cx.emit(Event::ExcerptsAdded {
1217            buffer,
1218            predecessor: prev_excerpt_id,
1219            excerpts,
1220        });
1221        cx.notify();
1222    }
1223
1224    pub fn clear(&mut self, cx: &mut ModelContext<Self>) {
1225        self.sync(cx);
1226        let ids = self.excerpt_ids();
1227        self.buffers.borrow_mut().clear();
1228        let mut snapshot = self.snapshot.borrow_mut();
1229        let prev_len = snapshot.len();
1230        snapshot.excerpts = Default::default();
1231        snapshot.trailing_excerpt_update_count += 1;
1232        snapshot.is_dirty = false;
1233        snapshot.has_conflict = false;
1234
1235        self.subscriptions.publish_mut([Edit {
1236            old: 0..prev_len,
1237            new: 0..0,
1238        }]);
1239        cx.emit(Event::Edited {
1240            singleton_buffer_edited: false,
1241        });
1242        cx.emit(Event::ExcerptsRemoved { ids });
1243        cx.notify();
1244    }
1245
1246    pub fn excerpts_for_buffer(
1247        &self,
1248        buffer: &Model<Buffer>,
1249        cx: &AppContext,
1250    ) -> Vec<(ExcerptId, ExcerptRange<text::Anchor>)> {
1251        let mut excerpts = Vec::new();
1252        let snapshot = self.read(cx);
1253        let buffers = self.buffers.borrow();
1254        let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>();
1255        for locator in buffers
1256            .get(&buffer.read(cx).remote_id())
1257            .map(|state| &state.excerpts)
1258            .into_iter()
1259            .flatten()
1260        {
1261            cursor.seek_forward(&Some(locator), Bias::Left, &());
1262            if let Some(excerpt) = cursor.item() {
1263                if excerpt.locator == *locator {
1264                    excerpts.push((excerpt.id, excerpt.range.clone()));
1265                }
1266            }
1267        }
1268
1269        excerpts
1270    }
1271
1272    pub fn excerpt_buffer_ids(&self) -> Vec<BufferId> {
1273        self.snapshot
1274            .borrow()
1275            .excerpts
1276            .iter()
1277            .map(|entry| entry.buffer_id)
1278            .collect()
1279    }
1280
1281    pub fn excerpt_ids(&self) -> Vec<ExcerptId> {
1282        self.snapshot
1283            .borrow()
1284            .excerpts
1285            .iter()
1286            .map(|entry| entry.id)
1287            .collect()
1288    }
1289
1290    pub fn excerpt_containing(
1291        &self,
1292        position: impl ToOffset,
1293        cx: &AppContext,
1294    ) -> Option<(ExcerptId, Model<Buffer>, Range<text::Anchor>)> {
1295        let snapshot = self.read(cx);
1296        let position = position.to_offset(&snapshot);
1297
1298        let mut cursor = snapshot.excerpts.cursor::<usize>();
1299        cursor.seek(&position, Bias::Right, &());
1300        cursor
1301            .item()
1302            .or_else(|| snapshot.excerpts.last())
1303            .map(|excerpt| {
1304                (
1305                    excerpt.id,
1306                    self.buffers
1307                        .borrow()
1308                        .get(&excerpt.buffer_id)
1309                        .unwrap()
1310                        .buffer
1311                        .clone(),
1312                    excerpt.range.context.clone(),
1313                )
1314            })
1315    }
1316
1317    // If point is at the end of the buffer, the last excerpt is returned
1318    pub fn point_to_buffer_offset<T: ToOffset>(
1319        &self,
1320        point: T,
1321        cx: &AppContext,
1322    ) -> Option<(Model<Buffer>, usize, ExcerptId)> {
1323        let snapshot = self.read(cx);
1324        let offset = point.to_offset(&snapshot);
1325        let mut cursor = snapshot.excerpts.cursor::<usize>();
1326        cursor.seek(&offset, Bias::Right, &());
1327        if cursor.item().is_none() {
1328            cursor.prev(&());
1329        }
1330
1331        cursor.item().map(|excerpt| {
1332            let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
1333            let buffer_point = excerpt_start + offset - *cursor.start();
1334            let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone();
1335
1336            (buffer, buffer_point, excerpt.id)
1337        })
1338    }
1339
1340    pub fn range_to_buffer_ranges<T: ToOffset>(
1341        &self,
1342        range: Range<T>,
1343        cx: &AppContext,
1344    ) -> Vec<(Model<Buffer>, Range<usize>, ExcerptId)> {
1345        let snapshot = self.read(cx);
1346        let start = range.start.to_offset(&snapshot);
1347        let end = range.end.to_offset(&snapshot);
1348
1349        let mut result = Vec::new();
1350        let mut cursor = snapshot.excerpts.cursor::<usize>();
1351        cursor.seek(&start, Bias::Right, &());
1352        if cursor.item().is_none() {
1353            cursor.prev(&());
1354        }
1355
1356        while let Some(excerpt) = cursor.item() {
1357            if *cursor.start() > end {
1358                break;
1359            }
1360
1361            let mut end_before_newline = cursor.end(&());
1362            if excerpt.has_trailing_newline {
1363                end_before_newline -= 1;
1364            }
1365            let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
1366            let start = excerpt_start + (cmp::max(start, *cursor.start()) - *cursor.start());
1367            let end = excerpt_start + (cmp::min(end, end_before_newline) - *cursor.start());
1368            let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone();
1369            result.push((buffer, start..end, excerpt.id));
1370            cursor.next(&());
1371        }
1372
1373        result
1374    }
1375
1376    pub fn remove_excerpts(
1377        &mut self,
1378        excerpt_ids: impl IntoIterator<Item = ExcerptId>,
1379        cx: &mut ModelContext<Self>,
1380    ) {
1381        self.sync(cx);
1382        let ids = excerpt_ids.into_iter().collect::<Vec<_>>();
1383        if ids.is_empty() {
1384            return;
1385        }
1386
1387        let mut buffers = self.buffers.borrow_mut();
1388        let mut snapshot = self.snapshot.borrow_mut();
1389        let mut new_excerpts = SumTree::new();
1390        let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>();
1391        let mut edits = Vec::new();
1392        let mut excerpt_ids = ids.iter().copied().peekable();
1393
1394        while let Some(excerpt_id) = excerpt_ids.next() {
1395            // Seek to the next excerpt to remove, preserving any preceding excerpts.
1396            let locator = snapshot.excerpt_locator_for_id(excerpt_id);
1397            new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &());
1398
1399            if let Some(mut excerpt) = cursor.item() {
1400                if excerpt.id != excerpt_id {
1401                    continue;
1402                }
1403                let mut old_start = cursor.start().1;
1404
1405                // Skip over the removed excerpt.
1406                'remove_excerpts: loop {
1407                    if let Some(buffer_state) = buffers.get_mut(&excerpt.buffer_id) {
1408                        buffer_state.excerpts.retain(|l| l != &excerpt.locator);
1409                        if buffer_state.excerpts.is_empty() {
1410                            buffers.remove(&excerpt.buffer_id);
1411                        }
1412                    }
1413                    cursor.next(&());
1414
1415                    // Skip over any subsequent excerpts that are also removed.
1416                    if let Some(&next_excerpt_id) = excerpt_ids.peek() {
1417                        let next_locator = snapshot.excerpt_locator_for_id(next_excerpt_id);
1418                        if let Some(next_excerpt) = cursor.item() {
1419                            if next_excerpt.locator == *next_locator {
1420                                excerpt_ids.next();
1421                                excerpt = next_excerpt;
1422                                continue 'remove_excerpts;
1423                            }
1424                        }
1425                    }
1426
1427                    break;
1428                }
1429
1430                // When removing the last excerpt, remove the trailing newline from
1431                // the previous excerpt.
1432                if cursor.item().is_none() && old_start > 0 {
1433                    old_start -= 1;
1434                    new_excerpts.update_last(|e| e.has_trailing_newline = false, &());
1435                }
1436
1437                // Push an edit for the removal of this run of excerpts.
1438                let old_end = cursor.start().1;
1439                let new_start = new_excerpts.summary().text.len;
1440                edits.push(Edit {
1441                    old: old_start..old_end,
1442                    new: new_start..new_start,
1443                });
1444            }
1445        }
1446        let suffix = cursor.suffix(&());
1447        let changed_trailing_excerpt = suffix.is_empty();
1448        new_excerpts.append(suffix, &());
1449        drop(cursor);
1450        snapshot.excerpts = new_excerpts;
1451
1452        if changed_trailing_excerpt {
1453            snapshot.trailing_excerpt_update_count += 1;
1454        }
1455
1456        self.subscriptions.publish_mut(edits);
1457        cx.emit(Event::Edited {
1458            singleton_buffer_edited: false,
1459        });
1460        cx.emit(Event::ExcerptsRemoved { ids });
1461        cx.notify();
1462    }
1463
1464    pub fn wait_for_anchors<'a>(
1465        &self,
1466        anchors: impl 'a + Iterator<Item = Anchor>,
1467        cx: &mut ModelContext<Self>,
1468    ) -> impl 'static + Future<Output = Result<()>> {
1469        let borrow = self.buffers.borrow();
1470        let mut error = None;
1471        let mut futures = Vec::new();
1472        for anchor in anchors {
1473            if let Some(buffer_id) = anchor.buffer_id {
1474                if let Some(buffer) = borrow.get(&buffer_id) {
1475                    buffer.buffer.update(cx, |buffer, _| {
1476                        futures.push(buffer.wait_for_anchors([anchor.text_anchor]))
1477                    });
1478                } else {
1479                    error = Some(anyhow!(
1480                        "buffer {buffer_id} is not part of this multi-buffer"
1481                    ));
1482                    break;
1483                }
1484            }
1485        }
1486        async move {
1487            if let Some(error) = error {
1488                Err(error)?;
1489            }
1490            for future in futures {
1491                future.await?;
1492            }
1493            Ok(())
1494        }
1495    }
1496
1497    pub fn text_anchor_for_position<T: ToOffset>(
1498        &self,
1499        position: T,
1500        cx: &AppContext,
1501    ) -> Option<(Model<Buffer>, language::Anchor)> {
1502        let snapshot = self.read(cx);
1503        let anchor = snapshot.anchor_before(position);
1504        let buffer = self
1505            .buffers
1506            .borrow()
1507            .get(&anchor.buffer_id?)?
1508            .buffer
1509            .clone();
1510        Some((buffer, anchor.text_anchor))
1511    }
1512
1513    fn on_buffer_event(
1514        &mut self,
1515        buffer: Model<Buffer>,
1516        event: &language::Event,
1517        cx: &mut ModelContext<Self>,
1518    ) {
1519        cx.emit(match event {
1520            language::Event::Edited => Event::Edited {
1521                singleton_buffer_edited: true,
1522            },
1523            language::Event::DirtyChanged => Event::DirtyChanged,
1524            language::Event::Saved => Event::Saved,
1525            language::Event::FileHandleChanged => Event::FileHandleChanged,
1526            language::Event::Reloaded => Event::Reloaded,
1527            language::Event::DiffBaseChanged => Event::DiffBaseChanged,
1528            language::Event::DiffUpdated => Event::DiffUpdated { buffer },
1529            language::Event::LanguageChanged => Event::LanguageChanged,
1530            language::Event::Reparsed => Event::Reparsed,
1531            language::Event::DiagnosticsUpdated => Event::DiagnosticsUpdated,
1532            language::Event::Closed => Event::Closed,
1533            language::Event::CapabilityChanged => {
1534                self.capability = buffer.read(cx).capability();
1535                Event::CapabilityChanged
1536            }
1537
1538            //
1539            language::Event::Operation(_) => return,
1540        });
1541    }
1542
1543    pub fn all_buffers(&self) -> HashSet<Model<Buffer>> {
1544        self.buffers
1545            .borrow()
1546            .values()
1547            .map(|state| state.buffer.clone())
1548            .collect()
1549    }
1550
1551    pub fn buffer(&self, buffer_id: BufferId) -> Option<Model<Buffer>> {
1552        self.buffers
1553            .borrow()
1554            .get(&buffer_id)
1555            .map(|state| state.buffer.clone())
1556    }
1557
1558    pub fn language_at<T: ToOffset>(&self, point: T, cx: &AppContext) -> Option<Arc<Language>> {
1559        self.point_to_buffer_offset(point, cx)
1560            .and_then(|(buffer, offset, _)| buffer.read(cx).language_at(offset))
1561    }
1562
1563    pub fn settings_at<'a, T: ToOffset>(
1564        &self,
1565        point: T,
1566        cx: &'a AppContext,
1567    ) -> &'a LanguageSettings {
1568        let mut language = None;
1569        let mut file = None;
1570        if let Some((buffer, offset, _)) = self.point_to_buffer_offset(point, cx) {
1571            let buffer = buffer.read(cx);
1572            language = buffer.language_at(offset);
1573            file = buffer.file();
1574        }
1575        language_settings(language.as_ref(), file, cx)
1576    }
1577
1578    pub fn for_each_buffer(&self, mut f: impl FnMut(&Model<Buffer>)) {
1579        self.buffers
1580            .borrow()
1581            .values()
1582            .for_each(|state| f(&state.buffer))
1583    }
1584
1585    pub fn title<'a>(&'a self, cx: &'a AppContext) -> Cow<'a, str> {
1586        if let Some(title) = self.title.as_ref() {
1587            return title.into();
1588        }
1589
1590        if let Some(buffer) = self.as_singleton() {
1591            if let Some(file) = buffer.read(cx).file() {
1592                return file.file_name(cx).to_string_lossy();
1593            }
1594        }
1595
1596        "untitled".into()
1597    }
1598
1599    pub fn set_title(&mut self, title: String, cx: &mut ModelContext<Self>) {
1600        self.title = Some(title);
1601        cx.notify();
1602    }
1603
1604    #[cfg(any(test, feature = "test-support"))]
1605    pub fn is_parsing(&self, cx: &AppContext) -> bool {
1606        self.as_singleton().unwrap().read(cx).is_parsing()
1607    }
1608
1609    pub fn expand_excerpts(
1610        &mut self,
1611        ids: impl IntoIterator<Item = ExcerptId>,
1612        line_count: u32,
1613        cx: &mut ModelContext<Self>,
1614    ) {
1615        if line_count == 0 {
1616            return;
1617        }
1618        self.sync(cx);
1619
1620        let snapshot = self.snapshot(cx);
1621        let locators = snapshot.excerpt_locators_for_ids(ids);
1622        let mut new_excerpts = SumTree::new();
1623        let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>();
1624        let mut edits = Vec::<Edit<usize>>::new();
1625
1626        for locator in &locators {
1627            let prefix = cursor.slice(&Some(locator), Bias::Left, &());
1628            new_excerpts.append(prefix, &());
1629
1630            let mut excerpt = cursor.item().unwrap().clone();
1631            let old_text_len = excerpt.text_summary.len;
1632
1633            let start_row = excerpt
1634                .range
1635                .context
1636                .start
1637                .to_point(&excerpt.buffer)
1638                .row
1639                .saturating_sub(line_count);
1640            let start_point = Point::new(start_row, 0);
1641            excerpt.range.context.start = excerpt.buffer.anchor_before(start_point);
1642
1643            let end_point = excerpt.buffer.clip_point(
1644                excerpt.range.context.end.to_point(&excerpt.buffer) + Point::new(line_count, 0),
1645                Bias::Left,
1646            );
1647            excerpt.range.context.end = excerpt.buffer.anchor_after(end_point);
1648            excerpt.max_buffer_row = end_point.row;
1649
1650            excerpt.text_summary = excerpt
1651                .buffer
1652                .text_summary_for_range(start_point..end_point);
1653
1654            let new_start_offset = new_excerpts.summary().text.len;
1655            let old_start_offset = cursor.start().1;
1656            let edit = Edit {
1657                old: old_start_offset..old_start_offset + old_text_len,
1658                new: new_start_offset..new_start_offset + excerpt.text_summary.len,
1659            };
1660
1661            if let Some(last_edit) = edits.last_mut() {
1662                if last_edit.old.end == edit.old.start {
1663                    last_edit.old.end = edit.old.end;
1664                    last_edit.new.end = edit.new.end;
1665                } else {
1666                    edits.push(edit);
1667                }
1668            } else {
1669                edits.push(edit);
1670            }
1671
1672            new_excerpts.push(excerpt, &());
1673
1674            cursor.next(&());
1675        }
1676
1677        new_excerpts.append(cursor.suffix(&()), &());
1678
1679        drop(cursor);
1680        self.snapshot.borrow_mut().excerpts = new_excerpts;
1681
1682        self.subscriptions.publish_mut(edits);
1683        cx.emit(Event::Edited {
1684            singleton_buffer_edited: false,
1685        });
1686        cx.notify();
1687    }
1688
1689    fn sync(&self, cx: &AppContext) {
1690        let mut snapshot = self.snapshot.borrow_mut();
1691        let mut excerpts_to_edit = Vec::new();
1692        let mut reparsed = false;
1693        let mut diagnostics_updated = false;
1694        let mut git_diff_updated = false;
1695        let mut is_dirty = false;
1696        let mut has_conflict = false;
1697        let mut edited = false;
1698        let mut buffers = self.buffers.borrow_mut();
1699        for buffer_state in buffers.values_mut() {
1700            let buffer = buffer_state.buffer.read(cx);
1701            let version = buffer.version();
1702            let parse_count = buffer.parse_count();
1703            let selections_update_count = buffer.selections_update_count();
1704            let diagnostics_update_count = buffer.diagnostics_update_count();
1705            let file_update_count = buffer.file_update_count();
1706            let git_diff_update_count = buffer.git_diff_update_count();
1707
1708            let buffer_edited = version.changed_since(&buffer_state.last_version);
1709            let buffer_reparsed = parse_count > buffer_state.last_parse_count;
1710            let buffer_selections_updated =
1711                selections_update_count > buffer_state.last_selections_update_count;
1712            let buffer_diagnostics_updated =
1713                diagnostics_update_count > buffer_state.last_diagnostics_update_count;
1714            let buffer_file_updated = file_update_count > buffer_state.last_file_update_count;
1715            let buffer_git_diff_updated =
1716                git_diff_update_count > buffer_state.last_git_diff_update_count;
1717            if buffer_edited
1718                || buffer_reparsed
1719                || buffer_selections_updated
1720                || buffer_diagnostics_updated
1721                || buffer_file_updated
1722                || buffer_git_diff_updated
1723            {
1724                buffer_state.last_version = version;
1725                buffer_state.last_parse_count = parse_count;
1726                buffer_state.last_selections_update_count = selections_update_count;
1727                buffer_state.last_diagnostics_update_count = diagnostics_update_count;
1728                buffer_state.last_file_update_count = file_update_count;
1729                buffer_state.last_git_diff_update_count = git_diff_update_count;
1730                excerpts_to_edit.extend(
1731                    buffer_state
1732                        .excerpts
1733                        .iter()
1734                        .map(|locator| (locator, buffer_state.buffer.clone(), buffer_edited)),
1735                );
1736            }
1737
1738            edited |= buffer_edited;
1739            reparsed |= buffer_reparsed;
1740            diagnostics_updated |= buffer_diagnostics_updated;
1741            git_diff_updated |= buffer_git_diff_updated;
1742            is_dirty |= buffer.is_dirty();
1743            has_conflict |= buffer.has_conflict();
1744        }
1745        if edited {
1746            snapshot.edit_count += 1;
1747        }
1748        if reparsed {
1749            snapshot.parse_count += 1;
1750        }
1751        if diagnostics_updated {
1752            snapshot.diagnostics_update_count += 1;
1753        }
1754        if git_diff_updated {
1755            snapshot.git_diff_update_count += 1;
1756        }
1757        snapshot.is_dirty = is_dirty;
1758        snapshot.has_conflict = has_conflict;
1759
1760        excerpts_to_edit.sort_unstable_by_key(|(locator, _, _)| *locator);
1761
1762        let mut edits = Vec::new();
1763        let mut new_excerpts = SumTree::new();
1764        let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>();
1765
1766        for (locator, buffer, buffer_edited) in excerpts_to_edit {
1767            new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &());
1768            let old_excerpt = cursor.item().unwrap();
1769            let buffer = buffer.read(cx);
1770            let buffer_id = buffer.remote_id();
1771
1772            let mut new_excerpt;
1773            if buffer_edited {
1774                edits.extend(
1775                    buffer
1776                        .edits_since_in_range::<usize>(
1777                            old_excerpt.buffer.version(),
1778                            old_excerpt.range.context.clone(),
1779                        )
1780                        .map(|mut edit| {
1781                            let excerpt_old_start = cursor.start().1;
1782                            let excerpt_new_start = new_excerpts.summary().text.len;
1783                            edit.old.start += excerpt_old_start;
1784                            edit.old.end += excerpt_old_start;
1785                            edit.new.start += excerpt_new_start;
1786                            edit.new.end += excerpt_new_start;
1787                            edit
1788                        }),
1789                );
1790
1791                new_excerpt = Excerpt::new(
1792                    old_excerpt.id,
1793                    locator.clone(),
1794                    buffer_id,
1795                    buffer.snapshot(),
1796                    old_excerpt.range.clone(),
1797                    old_excerpt.has_trailing_newline,
1798                );
1799            } else {
1800                new_excerpt = old_excerpt.clone();
1801                new_excerpt.buffer = buffer.snapshot();
1802            }
1803
1804            new_excerpts.push(new_excerpt, &());
1805            cursor.next(&());
1806        }
1807        new_excerpts.append(cursor.suffix(&()), &());
1808
1809        drop(cursor);
1810        snapshot.excerpts = new_excerpts;
1811
1812        self.subscriptions.publish(edits);
1813    }
1814}
1815
1816#[cfg(any(test, feature = "test-support"))]
1817impl MultiBuffer {
1818    pub fn build_simple(text: &str, cx: &mut gpui::AppContext) -> Model<Self> {
1819        let buffer = cx.new_model(|cx| Buffer::local(text, cx));
1820        cx.new_model(|cx| Self::singleton(buffer, cx))
1821    }
1822
1823    pub fn build_multi<const COUNT: usize>(
1824        excerpts: [(&str, Vec<Range<Point>>); COUNT],
1825        cx: &mut gpui::AppContext,
1826    ) -> Model<Self> {
1827        let multi = cx.new_model(|_| Self::new(0, Capability::ReadWrite));
1828        for (text, ranges) in excerpts {
1829            let buffer = cx.new_model(|cx| Buffer::local(text, cx));
1830            let excerpt_ranges = ranges.into_iter().map(|range| ExcerptRange {
1831                context: range,
1832                primary: None,
1833            });
1834            multi.update(cx, |multi, cx| {
1835                multi.push_excerpts(buffer, excerpt_ranges, cx)
1836            });
1837        }
1838
1839        multi
1840    }
1841
1842    pub fn build_from_buffer(buffer: Model<Buffer>, cx: &mut gpui::AppContext) -> Model<Self> {
1843        cx.new_model(|cx| Self::singleton(buffer, cx))
1844    }
1845
1846    pub fn build_random(rng: &mut impl rand::Rng, cx: &mut gpui::AppContext) -> Model<Self> {
1847        cx.new_model(|cx| {
1848            let mut multibuffer = MultiBuffer::new(0, Capability::ReadWrite);
1849            let mutation_count = rng.gen_range(1..=5);
1850            multibuffer.randomly_edit_excerpts(rng, mutation_count, cx);
1851            multibuffer
1852        })
1853    }
1854
1855    pub fn randomly_edit(
1856        &mut self,
1857        rng: &mut impl rand::Rng,
1858        edit_count: usize,
1859        cx: &mut ModelContext<Self>,
1860    ) {
1861        use util::RandomCharIter;
1862
1863        let snapshot = self.read(cx);
1864        let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
1865        let mut last_end = None;
1866        for _ in 0..edit_count {
1867            if last_end.map_or(false, |last_end| last_end >= snapshot.len()) {
1868                break;
1869            }
1870
1871            let new_start = last_end.map_or(0, |last_end| last_end + 1);
1872            let end = snapshot.clip_offset(rng.gen_range(new_start..=snapshot.len()), Bias::Right);
1873            let start = snapshot.clip_offset(rng.gen_range(new_start..=end), Bias::Right);
1874            last_end = Some(end);
1875
1876            let mut range = start..end;
1877            if rng.gen_bool(0.2) {
1878                mem::swap(&mut range.start, &mut range.end);
1879            }
1880
1881            let new_text_len = rng.gen_range(0..10);
1882            let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
1883
1884            edits.push((range, new_text.into()));
1885        }
1886        log::info!("mutating multi-buffer with {:?}", edits);
1887        drop(snapshot);
1888
1889        self.edit(edits, None, cx);
1890    }
1891
1892    pub fn randomly_edit_excerpts(
1893        &mut self,
1894        rng: &mut impl rand::Rng,
1895        mutation_count: usize,
1896        cx: &mut ModelContext<Self>,
1897    ) {
1898        use rand::prelude::*;
1899        use std::env;
1900        use util::RandomCharIter;
1901
1902        let max_excerpts = env::var("MAX_EXCERPTS")
1903            .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))
1904            .unwrap_or(5);
1905
1906        let mut buffers = Vec::new();
1907        for _ in 0..mutation_count {
1908            if rng.gen_bool(0.05) {
1909                log::info!("Clearing multi-buffer");
1910                self.clear(cx);
1911                continue;
1912            } else if rng.gen_bool(0.1) && !self.excerpt_ids().is_empty() {
1913                let ids = self.excerpt_ids();
1914                let mut excerpts = HashSet::default();
1915                for _ in 0..rng.gen_range(0..ids.len()) {
1916                    excerpts.extend(ids.choose(rng).copied());
1917                }
1918
1919                let line_count = rng.gen_range(0..5);
1920
1921                log::info!("Expanding excerpts {excerpts:?} by {line_count} lines");
1922
1923                self.expand_excerpts(excerpts.iter().cloned(), line_count, cx);
1924                continue;
1925            }
1926
1927            let excerpt_ids = self.excerpt_ids();
1928            if excerpt_ids.is_empty() || (rng.gen() && excerpt_ids.len() < max_excerpts) {
1929                let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() {
1930                    let text = RandomCharIter::new(&mut *rng).take(10).collect::<String>();
1931                    buffers.push(cx.new_model(|cx| Buffer::local(text, cx)));
1932                    let buffer = buffers.last().unwrap().read(cx);
1933                    log::info!(
1934                        "Creating new buffer {} with text: {:?}",
1935                        buffer.remote_id(),
1936                        buffer.text()
1937                    );
1938                    buffers.last().unwrap().clone()
1939                } else {
1940                    self.buffers
1941                        .borrow()
1942                        .values()
1943                        .choose(rng)
1944                        .unwrap()
1945                        .buffer
1946                        .clone()
1947                };
1948
1949                let buffer = buffer_handle.read(cx);
1950                let buffer_text = buffer.text();
1951                let ranges = (0..rng.gen_range(0..5))
1952                    .map(|_| {
1953                        let end_ix =
1954                            buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
1955                        let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
1956                        ExcerptRange {
1957                            context: start_ix..end_ix,
1958                            primary: None,
1959                        }
1960                    })
1961                    .collect::<Vec<_>>();
1962                log::info!(
1963                    "Inserting excerpts from buffer {} and ranges {:?}: {:?}",
1964                    buffer_handle.read(cx).remote_id(),
1965                    ranges.iter().map(|r| &r.context).collect::<Vec<_>>(),
1966                    ranges
1967                        .iter()
1968                        .map(|r| &buffer_text[r.context.clone()])
1969                        .collect::<Vec<_>>()
1970                );
1971
1972                let excerpt_id = self.push_excerpts(buffer_handle.clone(), ranges, cx);
1973                log::info!("Inserted with ids: {:?}", excerpt_id);
1974            } else {
1975                let remove_count = rng.gen_range(1..=excerpt_ids.len());
1976                let mut excerpts_to_remove = excerpt_ids
1977                    .choose_multiple(rng, remove_count)
1978                    .cloned()
1979                    .collect::<Vec<_>>();
1980                let snapshot = self.snapshot.borrow();
1981                excerpts_to_remove.sort_unstable_by(|a, b| a.cmp(b, &snapshot));
1982                drop(snapshot);
1983                log::info!("Removing excerpts {:?}", excerpts_to_remove);
1984                self.remove_excerpts(excerpts_to_remove, cx);
1985            }
1986        }
1987    }
1988
1989    pub fn randomly_mutate(
1990        &mut self,
1991        rng: &mut impl rand::Rng,
1992        mutation_count: usize,
1993        cx: &mut ModelContext<Self>,
1994    ) {
1995        use rand::prelude::*;
1996
1997        if rng.gen_bool(0.7) || self.singleton {
1998            let buffer = self
1999                .buffers
2000                .borrow()
2001                .values()
2002                .choose(rng)
2003                .map(|state| state.buffer.clone());
2004
2005            if let Some(buffer) = buffer {
2006                buffer.update(cx, |buffer, cx| {
2007                    if rng.gen() {
2008                        buffer.randomly_edit(rng, mutation_count, cx);
2009                    } else {
2010                        buffer.randomly_undo_redo(rng, cx);
2011                    }
2012                });
2013            } else {
2014                self.randomly_edit(rng, mutation_count, cx);
2015            }
2016        } else {
2017            self.randomly_edit_excerpts(rng, mutation_count, cx);
2018        }
2019
2020        self.check_invariants(cx);
2021    }
2022
2023    fn check_invariants(&self, cx: &mut ModelContext<Self>) {
2024        let snapshot = self.read(cx);
2025        let excerpts = snapshot.excerpts.items(&());
2026        let excerpt_ids = snapshot.excerpt_ids.items(&());
2027
2028        for (ix, excerpt) in excerpts.iter().enumerate() {
2029            if ix == 0 {
2030                if excerpt.locator <= Locator::min() {
2031                    panic!("invalid first excerpt locator {:?}", excerpt.locator);
2032                }
2033            } else {
2034                if excerpt.locator <= excerpts[ix - 1].locator {
2035                    panic!("excerpts are out-of-order: {:?}", excerpts);
2036                }
2037            }
2038        }
2039
2040        for (ix, entry) in excerpt_ids.iter().enumerate() {
2041            if ix == 0 {
2042                if entry.id.cmp(&ExcerptId::min(), &snapshot).is_le() {
2043                    panic!("invalid first excerpt id {:?}", entry.id);
2044                }
2045            } else {
2046                if entry.id <= excerpt_ids[ix - 1].id {
2047                    panic!("excerpt ids are out-of-order: {:?}", excerpt_ids);
2048                }
2049            }
2050        }
2051    }
2052}
2053
2054impl EventEmitter<Event> for MultiBuffer {}
2055
2056impl MultiBufferSnapshot {
2057    pub fn text(&self) -> String {
2058        self.chunks(0..self.len(), false)
2059            .map(|chunk| chunk.text)
2060            .collect()
2061    }
2062
2063    pub fn reversed_chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
2064        let mut offset = position.to_offset(self);
2065        let mut cursor = self.excerpts.cursor::<usize>();
2066        cursor.seek(&offset, Bias::Left, &());
2067        let mut excerpt_chunks = cursor.item().map(|excerpt| {
2068            let end_before_footer = cursor.start() + excerpt.text_summary.len;
2069            let start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2070            let end = start + (cmp::min(offset, end_before_footer) - cursor.start());
2071            excerpt.buffer.reversed_chunks_in_range(start..end)
2072        });
2073        iter::from_fn(move || {
2074            if offset == *cursor.start() {
2075                cursor.prev(&());
2076                let excerpt = cursor.item()?;
2077                excerpt_chunks = Some(
2078                    excerpt
2079                        .buffer
2080                        .reversed_chunks_in_range(excerpt.range.context.clone()),
2081                );
2082            }
2083
2084            let excerpt = cursor.item().unwrap();
2085            if offset == cursor.end(&()) && excerpt.has_trailing_newline {
2086                offset -= 1;
2087                Some("\n")
2088            } else {
2089                let chunk = excerpt_chunks.as_mut().unwrap().next().unwrap();
2090                offset -= chunk.len();
2091                Some(chunk)
2092            }
2093        })
2094        .flat_map(|c| c.chars().rev())
2095    }
2096
2097    pub fn chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
2098        let offset = position.to_offset(self);
2099        self.text_for_range(offset..self.len())
2100            .flat_map(|chunk| chunk.chars())
2101    }
2102
2103    pub fn text_for_range<T: ToOffset>(&self, range: Range<T>) -> impl Iterator<Item = &str> + '_ {
2104        self.chunks(range, false).map(|chunk| chunk.text)
2105    }
2106
2107    pub fn is_line_blank(&self, row: MultiBufferRow) -> bool {
2108        self.text_for_range(Point::new(row.0, 0)..Point::new(row.0, self.line_len(row)))
2109            .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
2110    }
2111
2112    pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
2113    where
2114        T: ToOffset,
2115    {
2116        let position = position.to_offset(self);
2117        position == self.clip_offset(position, Bias::Left)
2118            && self
2119                .bytes_in_range(position..self.len())
2120                .flatten()
2121                .copied()
2122                .take(needle.len())
2123                .eq(needle.bytes())
2124    }
2125
2126    pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) {
2127        let mut start = start.to_offset(self);
2128        let mut end = start;
2129        let mut next_chars = self.chars_at(start).peekable();
2130        let mut prev_chars = self.reversed_chars_at(start).peekable();
2131
2132        let scope = self.language_scope_at(start);
2133        let kind = |c| char_kind(&scope, c);
2134        let word_kind = cmp::max(
2135            prev_chars.peek().copied().map(kind),
2136            next_chars.peek().copied().map(kind),
2137        );
2138
2139        for ch in prev_chars {
2140            if Some(kind(ch)) == word_kind && ch != '\n' {
2141                start -= ch.len_utf8();
2142            } else {
2143                break;
2144            }
2145        }
2146
2147        for ch in next_chars {
2148            if Some(kind(ch)) == word_kind && ch != '\n' {
2149                end += ch.len_utf8();
2150            } else {
2151                break;
2152            }
2153        }
2154
2155        (start..end, word_kind)
2156    }
2157
2158    pub fn as_singleton(&self) -> Option<(&ExcerptId, BufferId, &BufferSnapshot)> {
2159        if self.singleton {
2160            self.excerpts
2161                .iter()
2162                .next()
2163                .map(|e| (&e.id, e.buffer_id, &e.buffer))
2164        } else {
2165            None
2166        }
2167    }
2168
2169    pub fn len(&self) -> usize {
2170        self.excerpts.summary().text.len
2171    }
2172
2173    pub fn is_empty(&self) -> bool {
2174        self.excerpts.summary().text.len == 0
2175    }
2176
2177    pub fn max_buffer_row(&self) -> MultiBufferRow {
2178        self.excerpts.summary().max_buffer_row
2179    }
2180
2181    pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
2182        if let Some((_, _, buffer)) = self.as_singleton() {
2183            return buffer.clip_offset(offset, bias);
2184        }
2185
2186        let mut cursor = self.excerpts.cursor::<usize>();
2187        cursor.seek(&offset, Bias::Right, &());
2188        let overshoot = if let Some(excerpt) = cursor.item() {
2189            let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2190            let buffer_offset = excerpt
2191                .buffer
2192                .clip_offset(excerpt_start + (offset - cursor.start()), bias);
2193            buffer_offset.saturating_sub(excerpt_start)
2194        } else {
2195            0
2196        };
2197        cursor.start() + overshoot
2198    }
2199
2200    pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
2201        if let Some((_, _, buffer)) = self.as_singleton() {
2202            return buffer.clip_point(point, bias);
2203        }
2204
2205        let mut cursor = self.excerpts.cursor::<Point>();
2206        cursor.seek(&point, Bias::Right, &());
2207        let overshoot = if let Some(excerpt) = cursor.item() {
2208            let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
2209            let buffer_point = excerpt
2210                .buffer
2211                .clip_point(excerpt_start + (point - cursor.start()), bias);
2212            buffer_point.saturating_sub(excerpt_start)
2213        } else {
2214            Point::zero()
2215        };
2216        *cursor.start() + overshoot
2217    }
2218
2219    pub fn clip_offset_utf16(&self, offset: OffsetUtf16, bias: Bias) -> OffsetUtf16 {
2220        if let Some((_, _, buffer)) = self.as_singleton() {
2221            return buffer.clip_offset_utf16(offset, bias);
2222        }
2223
2224        let mut cursor = self.excerpts.cursor::<OffsetUtf16>();
2225        cursor.seek(&offset, Bias::Right, &());
2226        let overshoot = if let Some(excerpt) = cursor.item() {
2227            let excerpt_start = excerpt.range.context.start.to_offset_utf16(&excerpt.buffer);
2228            let buffer_offset = excerpt
2229                .buffer
2230                .clip_offset_utf16(excerpt_start + (offset - cursor.start()), bias);
2231            OffsetUtf16(buffer_offset.0.saturating_sub(excerpt_start.0))
2232        } else {
2233            OffsetUtf16(0)
2234        };
2235        *cursor.start() + overshoot
2236    }
2237
2238    pub fn clip_point_utf16(&self, point: Unclipped<PointUtf16>, bias: Bias) -> PointUtf16 {
2239        if let Some((_, _, buffer)) = self.as_singleton() {
2240            return buffer.clip_point_utf16(point, bias);
2241        }
2242
2243        let mut cursor = self.excerpts.cursor::<PointUtf16>();
2244        cursor.seek(&point.0, Bias::Right, &());
2245        let overshoot = if let Some(excerpt) = cursor.item() {
2246            let excerpt_start = excerpt
2247                .buffer
2248                .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
2249            let buffer_point = excerpt
2250                .buffer
2251                .clip_point_utf16(Unclipped(excerpt_start + (point.0 - cursor.start())), bias);
2252            buffer_point.saturating_sub(excerpt_start)
2253        } else {
2254            PointUtf16::zero()
2255        };
2256        *cursor.start() + overshoot
2257    }
2258
2259    pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> MultiBufferBytes {
2260        let range = range.start.to_offset(self)..range.end.to_offset(self);
2261        let mut excerpts = self.excerpts.cursor::<usize>();
2262        excerpts.seek(&range.start, Bias::Right, &());
2263
2264        let mut chunk = &[][..];
2265        let excerpt_bytes = if let Some(excerpt) = excerpts.item() {
2266            let mut excerpt_bytes = excerpt
2267                .bytes_in_range(range.start - excerpts.start()..range.end - excerpts.start());
2268            chunk = excerpt_bytes.next().unwrap_or(&[][..]);
2269            Some(excerpt_bytes)
2270        } else {
2271            None
2272        };
2273        MultiBufferBytes {
2274            range,
2275            excerpts,
2276            excerpt_bytes,
2277            chunk,
2278        }
2279    }
2280
2281    pub fn reversed_bytes_in_range<T: ToOffset>(
2282        &self,
2283        range: Range<T>,
2284    ) -> ReversedMultiBufferBytes {
2285        let range = range.start.to_offset(self)..range.end.to_offset(self);
2286        let mut excerpts = self.excerpts.cursor::<usize>();
2287        excerpts.seek(&range.end, Bias::Left, &());
2288
2289        let mut chunk = &[][..];
2290        let excerpt_bytes = if let Some(excerpt) = excerpts.item() {
2291            let mut excerpt_bytes = excerpt.reversed_bytes_in_range(
2292                range.start.saturating_sub(*excerpts.start())..range.end - *excerpts.start(),
2293            );
2294            chunk = excerpt_bytes.next().unwrap_or(&[][..]);
2295            Some(excerpt_bytes)
2296        } else {
2297            None
2298        };
2299
2300        ReversedMultiBufferBytes {
2301            range,
2302            excerpts,
2303            excerpt_bytes,
2304            chunk,
2305        }
2306    }
2307
2308    pub fn buffer_rows(&self, start_row: MultiBufferRow) -> MultiBufferRows {
2309        let mut result = MultiBufferRows {
2310            buffer_row_range: 0..0,
2311            excerpts: self.excerpts.cursor(),
2312        };
2313        result.seek(start_row);
2314        result
2315    }
2316
2317    pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> MultiBufferChunks {
2318        let range = range.start.to_offset(self)..range.end.to_offset(self);
2319        let mut chunks = MultiBufferChunks {
2320            range: range.clone(),
2321            excerpts: self.excerpts.cursor(),
2322            excerpt_chunks: None,
2323            language_aware,
2324        };
2325        chunks.seek(range.start);
2326        chunks
2327    }
2328
2329    pub fn offset_to_point(&self, offset: usize) -> Point {
2330        if let Some((_, _, buffer)) = self.as_singleton() {
2331            return buffer.offset_to_point(offset);
2332        }
2333
2334        let mut cursor = self.excerpts.cursor::<(usize, Point)>();
2335        cursor.seek(&offset, Bias::Right, &());
2336        if let Some(excerpt) = cursor.item() {
2337            let (start_offset, start_point) = cursor.start();
2338            let overshoot = offset - start_offset;
2339            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2340            let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
2341            let buffer_point = excerpt
2342                .buffer
2343                .offset_to_point(excerpt_start_offset + overshoot);
2344            *start_point + (buffer_point - excerpt_start_point)
2345        } else {
2346            self.excerpts.summary().text.lines
2347        }
2348    }
2349
2350    pub fn offset_to_point_utf16(&self, offset: usize) -> PointUtf16 {
2351        if let Some((_, _, buffer)) = self.as_singleton() {
2352            return buffer.offset_to_point_utf16(offset);
2353        }
2354
2355        let mut cursor = self.excerpts.cursor::<(usize, PointUtf16)>();
2356        cursor.seek(&offset, Bias::Right, &());
2357        if let Some(excerpt) = cursor.item() {
2358            let (start_offset, start_point) = cursor.start();
2359            let overshoot = offset - start_offset;
2360            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2361            let excerpt_start_point = excerpt.range.context.start.to_point_utf16(&excerpt.buffer);
2362            let buffer_point = excerpt
2363                .buffer
2364                .offset_to_point_utf16(excerpt_start_offset + overshoot);
2365            *start_point + (buffer_point - excerpt_start_point)
2366        } else {
2367            self.excerpts.summary().text.lines_utf16()
2368        }
2369    }
2370
2371    pub fn point_to_point_utf16(&self, point: Point) -> PointUtf16 {
2372        if let Some((_, _, buffer)) = self.as_singleton() {
2373            return buffer.point_to_point_utf16(point);
2374        }
2375
2376        let mut cursor = self.excerpts.cursor::<(Point, PointUtf16)>();
2377        cursor.seek(&point, Bias::Right, &());
2378        if let Some(excerpt) = cursor.item() {
2379            let (start_offset, start_point) = cursor.start();
2380            let overshoot = point - start_offset;
2381            let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
2382            let excerpt_start_point_utf16 =
2383                excerpt.range.context.start.to_point_utf16(&excerpt.buffer);
2384            let buffer_point = excerpt
2385                .buffer
2386                .point_to_point_utf16(excerpt_start_point + overshoot);
2387            *start_point + (buffer_point - excerpt_start_point_utf16)
2388        } else {
2389            self.excerpts.summary().text.lines_utf16()
2390        }
2391    }
2392
2393    pub fn point_to_offset(&self, point: Point) -> usize {
2394        if let Some((_, _, buffer)) = self.as_singleton() {
2395            return buffer.point_to_offset(point);
2396        }
2397
2398        let mut cursor = self.excerpts.cursor::<(Point, usize)>();
2399        cursor.seek(&point, Bias::Right, &());
2400        if let Some(excerpt) = cursor.item() {
2401            let (start_point, start_offset) = cursor.start();
2402            let overshoot = point - start_point;
2403            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2404            let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
2405            let buffer_offset = excerpt
2406                .buffer
2407                .point_to_offset(excerpt_start_point + overshoot);
2408            *start_offset + buffer_offset - excerpt_start_offset
2409        } else {
2410            self.excerpts.summary().text.len
2411        }
2412    }
2413
2414    pub fn offset_utf16_to_offset(&self, offset_utf16: OffsetUtf16) -> usize {
2415        if let Some((_, _, buffer)) = self.as_singleton() {
2416            return buffer.offset_utf16_to_offset(offset_utf16);
2417        }
2418
2419        let mut cursor = self.excerpts.cursor::<(OffsetUtf16, usize)>();
2420        cursor.seek(&offset_utf16, Bias::Right, &());
2421        if let Some(excerpt) = cursor.item() {
2422            let (start_offset_utf16, start_offset) = cursor.start();
2423            let overshoot = offset_utf16 - start_offset_utf16;
2424            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2425            let excerpt_start_offset_utf16 =
2426                excerpt.buffer.offset_to_offset_utf16(excerpt_start_offset);
2427            let buffer_offset = excerpt
2428                .buffer
2429                .offset_utf16_to_offset(excerpt_start_offset_utf16 + overshoot);
2430            *start_offset + (buffer_offset - excerpt_start_offset)
2431        } else {
2432            self.excerpts.summary().text.len
2433        }
2434    }
2435
2436    pub fn offset_to_offset_utf16(&self, offset: usize) -> OffsetUtf16 {
2437        if let Some((_, _, buffer)) = self.as_singleton() {
2438            return buffer.offset_to_offset_utf16(offset);
2439        }
2440
2441        let mut cursor = self.excerpts.cursor::<(usize, OffsetUtf16)>();
2442        cursor.seek(&offset, Bias::Right, &());
2443        if let Some(excerpt) = cursor.item() {
2444            let (start_offset, start_offset_utf16) = cursor.start();
2445            let overshoot = offset - start_offset;
2446            let excerpt_start_offset_utf16 =
2447                excerpt.range.context.start.to_offset_utf16(&excerpt.buffer);
2448            let excerpt_start_offset = excerpt
2449                .buffer
2450                .offset_utf16_to_offset(excerpt_start_offset_utf16);
2451            let buffer_offset_utf16 = excerpt
2452                .buffer
2453                .offset_to_offset_utf16(excerpt_start_offset + overshoot);
2454            *start_offset_utf16 + (buffer_offset_utf16 - excerpt_start_offset_utf16)
2455        } else {
2456            self.excerpts.summary().text.len_utf16
2457        }
2458    }
2459
2460    pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
2461        if let Some((_, _, buffer)) = self.as_singleton() {
2462            return buffer.point_utf16_to_offset(point);
2463        }
2464
2465        let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>();
2466        cursor.seek(&point, Bias::Right, &());
2467        if let Some(excerpt) = cursor.item() {
2468            let (start_point, start_offset) = cursor.start();
2469            let overshoot = point - start_point;
2470            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2471            let excerpt_start_point = excerpt
2472                .buffer
2473                .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
2474            let buffer_offset = excerpt
2475                .buffer
2476                .point_utf16_to_offset(excerpt_start_point + overshoot);
2477            *start_offset + (buffer_offset - excerpt_start_offset)
2478        } else {
2479            self.excerpts.summary().text.len
2480        }
2481    }
2482
2483    pub fn point_to_buffer_offset<T: ToOffset>(
2484        &self,
2485        point: T,
2486    ) -> Option<(&BufferSnapshot, usize)> {
2487        let offset = point.to_offset(self);
2488        let mut cursor = self.excerpts.cursor::<usize>();
2489        cursor.seek(&offset, Bias::Right, &());
2490        if cursor.item().is_none() {
2491            cursor.prev(&());
2492        }
2493
2494        cursor.item().map(|excerpt| {
2495            let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2496            let buffer_point = excerpt_start + offset - *cursor.start();
2497            (&excerpt.buffer, buffer_point)
2498        })
2499    }
2500
2501    pub fn suggested_indents(
2502        &self,
2503        rows: impl IntoIterator<Item = u32>,
2504        cx: &AppContext,
2505    ) -> BTreeMap<MultiBufferRow, IndentSize> {
2506        let mut result = BTreeMap::new();
2507
2508        let mut rows_for_excerpt = Vec::new();
2509        let mut cursor = self.excerpts.cursor::<Point>();
2510        let mut rows = rows.into_iter().peekable();
2511        let mut prev_row = u32::MAX;
2512        let mut prev_language_indent_size = IndentSize::default();
2513
2514        while let Some(row) = rows.next() {
2515            cursor.seek(&Point::new(row, 0), Bias::Right, &());
2516            let excerpt = match cursor.item() {
2517                Some(excerpt) => excerpt,
2518                _ => continue,
2519            };
2520
2521            // Retrieve the language and indent size once for each disjoint region being indented.
2522            let single_indent_size = if row.saturating_sub(1) == prev_row {
2523                prev_language_indent_size
2524            } else {
2525                excerpt
2526                    .buffer
2527                    .language_indent_size_at(Point::new(row, 0), cx)
2528            };
2529            prev_language_indent_size = single_indent_size;
2530            prev_row = row;
2531
2532            let start_buffer_row = excerpt.range.context.start.to_point(&excerpt.buffer).row;
2533            let start_multibuffer_row = cursor.start().row;
2534
2535            rows_for_excerpt.push(row);
2536            while let Some(next_row) = rows.peek().copied() {
2537                if cursor.end(&()).row > next_row {
2538                    rows_for_excerpt.push(next_row);
2539                    rows.next();
2540                } else {
2541                    break;
2542                }
2543            }
2544
2545            let buffer_rows = rows_for_excerpt
2546                .drain(..)
2547                .map(|row| start_buffer_row + row - start_multibuffer_row);
2548            let buffer_indents = excerpt
2549                .buffer
2550                .suggested_indents(buffer_rows, single_indent_size);
2551            let multibuffer_indents = buffer_indents.into_iter().map(|(row, indent)| {
2552                (
2553                    MultiBufferRow(start_multibuffer_row + row - start_buffer_row),
2554                    indent,
2555                )
2556            });
2557            result.extend(multibuffer_indents);
2558        }
2559
2560        result
2561    }
2562
2563    pub fn indent_size_for_line(&self, row: MultiBufferRow) -> IndentSize {
2564        if let Some((buffer, range)) = self.buffer_line_for_row(row) {
2565            let mut size = buffer.indent_size_for_line(range.start.row);
2566            size.len = size
2567                .len
2568                .min(range.end.column)
2569                .saturating_sub(range.start.column);
2570            size
2571        } else {
2572            IndentSize::spaces(0)
2573        }
2574    }
2575
2576    pub fn prev_non_blank_row(&self, mut row: MultiBufferRow) -> Option<MultiBufferRow> {
2577        while row.0 > 0 {
2578            row.0 -= 1;
2579            if !self.is_line_blank(row) {
2580                return Some(row);
2581            }
2582        }
2583        None
2584    }
2585
2586    pub fn line_len(&self, row: MultiBufferRow) -> u32 {
2587        if let Some((_, range)) = self.buffer_line_for_row(row) {
2588            range.end.column - range.start.column
2589        } else {
2590            0
2591        }
2592    }
2593
2594    pub fn buffer_line_for_row(
2595        &self,
2596        row: MultiBufferRow,
2597    ) -> Option<(&BufferSnapshot, Range<Point>)> {
2598        let mut cursor = self.excerpts.cursor::<Point>();
2599        let point = Point::new(row.0, 0);
2600        cursor.seek(&point, Bias::Right, &());
2601        if cursor.item().is_none() && *cursor.start() == point {
2602            cursor.prev(&());
2603        }
2604        if let Some(excerpt) = cursor.item() {
2605            let overshoot = row.0 - cursor.start().row;
2606            let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
2607            let excerpt_end = excerpt.range.context.end.to_point(&excerpt.buffer);
2608            let buffer_row = excerpt_start.row + overshoot;
2609            let line_start = Point::new(buffer_row, 0);
2610            let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
2611            return Some((
2612                &excerpt.buffer,
2613                line_start.max(excerpt_start)..line_end.min(excerpt_end),
2614            ));
2615        }
2616        None
2617    }
2618
2619    pub fn max_point(&self) -> Point {
2620        self.text_summary().lines
2621    }
2622
2623    pub fn text_summary(&self) -> TextSummary {
2624        self.excerpts.summary().text.clone()
2625    }
2626
2627    pub fn text_summary_for_range<D, O>(&self, range: Range<O>) -> D
2628    where
2629        D: TextDimension,
2630        O: ToOffset,
2631    {
2632        let mut summary = D::default();
2633        let mut range = range.start.to_offset(self)..range.end.to_offset(self);
2634        let mut cursor = self.excerpts.cursor::<usize>();
2635        cursor.seek(&range.start, Bias::Right, &());
2636        if let Some(excerpt) = cursor.item() {
2637            let mut end_before_newline = cursor.end(&());
2638            if excerpt.has_trailing_newline {
2639                end_before_newline -= 1;
2640            }
2641
2642            let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2643            let start_in_excerpt = excerpt_start + (range.start - cursor.start());
2644            let end_in_excerpt =
2645                excerpt_start + (cmp::min(end_before_newline, range.end) - cursor.start());
2646            summary.add_assign(
2647                &excerpt
2648                    .buffer
2649                    .text_summary_for_range(start_in_excerpt..end_in_excerpt),
2650            );
2651
2652            if range.end > end_before_newline {
2653                summary.add_assign(&D::from_text_summary(&TextSummary::from("\n")));
2654            }
2655
2656            cursor.next(&());
2657        }
2658
2659        if range.end > *cursor.start() {
2660            summary.add_assign(&D::from_text_summary(&cursor.summary::<_, TextSummary>(
2661                &range.end,
2662                Bias::Right,
2663                &(),
2664            )));
2665            if let Some(excerpt) = cursor.item() {
2666                range.end = cmp::max(*cursor.start(), range.end);
2667
2668                let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2669                let end_in_excerpt = excerpt_start + (range.end - cursor.start());
2670                summary.add_assign(
2671                    &excerpt
2672                        .buffer
2673                        .text_summary_for_range(excerpt_start..end_in_excerpt),
2674                );
2675            }
2676        }
2677
2678        summary
2679    }
2680
2681    pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
2682    where
2683        D: TextDimension + Ord + Sub<D, Output = D>,
2684    {
2685        let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
2686        let locator = self.excerpt_locator_for_id(anchor.excerpt_id);
2687
2688        cursor.seek(locator, Bias::Left, &());
2689        if cursor.item().is_none() {
2690            cursor.next(&());
2691        }
2692
2693        let mut position = D::from_text_summary(&cursor.start().text);
2694        if let Some(excerpt) = cursor.item() {
2695            if excerpt.id == anchor.excerpt_id {
2696                let excerpt_buffer_start =
2697                    excerpt.range.context.start.summary::<D>(&excerpt.buffer);
2698                let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer);
2699                let buffer_position = cmp::min(
2700                    excerpt_buffer_end,
2701                    anchor.text_anchor.summary::<D>(&excerpt.buffer),
2702                );
2703                if buffer_position > excerpt_buffer_start {
2704                    position.add_assign(&(buffer_position - excerpt_buffer_start));
2705                }
2706            }
2707        }
2708        position
2709    }
2710
2711    pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
2712    where
2713        D: TextDimension + Ord + Sub<D, Output = D>,
2714        I: 'a + IntoIterator<Item = &'a Anchor>,
2715    {
2716        if let Some((_, _, buffer)) = self.as_singleton() {
2717            return buffer
2718                .summaries_for_anchors(anchors.into_iter().map(|a| &a.text_anchor))
2719                .collect();
2720        }
2721
2722        let mut anchors = anchors.into_iter().peekable();
2723        let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
2724        let mut summaries = Vec::new();
2725        while let Some(anchor) = anchors.peek() {
2726            let excerpt_id = anchor.excerpt_id;
2727            let excerpt_anchors = iter::from_fn(|| {
2728                let anchor = anchors.peek()?;
2729                if anchor.excerpt_id == excerpt_id {
2730                    Some(&anchors.next().unwrap().text_anchor)
2731                } else {
2732                    None
2733                }
2734            });
2735
2736            let locator = self.excerpt_locator_for_id(excerpt_id);
2737            cursor.seek_forward(locator, Bias::Left, &());
2738            if cursor.item().is_none() {
2739                cursor.next(&());
2740            }
2741
2742            let position = D::from_text_summary(&cursor.start().text);
2743            if let Some(excerpt) = cursor.item() {
2744                if excerpt.id == excerpt_id {
2745                    let excerpt_buffer_start =
2746                        excerpt.range.context.start.summary::<D>(&excerpt.buffer);
2747                    let excerpt_buffer_end =
2748                        excerpt.range.context.end.summary::<D>(&excerpt.buffer);
2749                    summaries.extend(
2750                        excerpt
2751                            .buffer
2752                            .summaries_for_anchors::<D, _>(excerpt_anchors)
2753                            .map(move |summary| {
2754                                let summary = cmp::min(excerpt_buffer_end.clone(), summary);
2755                                let mut position = position.clone();
2756                                let excerpt_buffer_start = excerpt_buffer_start.clone();
2757                                if summary > excerpt_buffer_start {
2758                                    position.add_assign(&(summary - excerpt_buffer_start));
2759                                }
2760                                position
2761                            }),
2762                    );
2763                    continue;
2764                }
2765            }
2766
2767            summaries.extend(excerpt_anchors.map(|_| position.clone()));
2768        }
2769
2770        summaries
2771    }
2772
2773    pub fn refresh_anchors<'a, I>(&'a self, anchors: I) -> Vec<(usize, Anchor, bool)>
2774    where
2775        I: 'a + IntoIterator<Item = &'a Anchor>,
2776    {
2777        let mut anchors = anchors.into_iter().enumerate().peekable();
2778        let mut cursor = self.excerpts.cursor::<Option<&Locator>>();
2779        cursor.next(&());
2780
2781        let mut result = Vec::new();
2782
2783        while let Some((_, anchor)) = anchors.peek() {
2784            let old_excerpt_id = anchor.excerpt_id;
2785
2786            // Find the location where this anchor's excerpt should be.
2787            let old_locator = self.excerpt_locator_for_id(old_excerpt_id);
2788            cursor.seek_forward(&Some(old_locator), Bias::Left, &());
2789
2790            if cursor.item().is_none() {
2791                cursor.next(&());
2792            }
2793
2794            let next_excerpt = cursor.item();
2795            let prev_excerpt = cursor.prev_item();
2796
2797            // Process all of the anchors for this excerpt.
2798            while let Some((_, anchor)) = anchors.peek() {
2799                if anchor.excerpt_id != old_excerpt_id {
2800                    break;
2801                }
2802                let (anchor_ix, anchor) = anchors.next().unwrap();
2803                let mut anchor = *anchor;
2804
2805                // Leave min and max anchors unchanged if invalid or
2806                // if the old excerpt still exists at this location
2807                let mut kept_position = next_excerpt
2808                    .map_or(false, |e| e.id == old_excerpt_id && e.contains(&anchor))
2809                    || old_excerpt_id == ExcerptId::max()
2810                    || old_excerpt_id == ExcerptId::min();
2811
2812                // If the old excerpt no longer exists at this location, then attempt to
2813                // find an equivalent position for this anchor in an adjacent excerpt.
2814                if !kept_position {
2815                    for excerpt in [next_excerpt, prev_excerpt].iter().filter_map(|e| *e) {
2816                        if excerpt.contains(&anchor) {
2817                            anchor.excerpt_id = excerpt.id;
2818                            kept_position = true;
2819                            break;
2820                        }
2821                    }
2822                }
2823
2824                // If there's no adjacent excerpt that contains the anchor's position,
2825                // then report that the anchor has lost its position.
2826                if !kept_position {
2827                    anchor = if let Some(excerpt) = next_excerpt {
2828                        let mut text_anchor = excerpt
2829                            .range
2830                            .context
2831                            .start
2832                            .bias(anchor.text_anchor.bias, &excerpt.buffer);
2833                        if text_anchor
2834                            .cmp(&excerpt.range.context.end, &excerpt.buffer)
2835                            .is_gt()
2836                        {
2837                            text_anchor = excerpt.range.context.end;
2838                        }
2839                        Anchor {
2840                            buffer_id: Some(excerpt.buffer_id),
2841                            excerpt_id: excerpt.id,
2842                            text_anchor,
2843                        }
2844                    } else if let Some(excerpt) = prev_excerpt {
2845                        let mut text_anchor = excerpt
2846                            .range
2847                            .context
2848                            .end
2849                            .bias(anchor.text_anchor.bias, &excerpt.buffer);
2850                        if text_anchor
2851                            .cmp(&excerpt.range.context.start, &excerpt.buffer)
2852                            .is_lt()
2853                        {
2854                            text_anchor = excerpt.range.context.start;
2855                        }
2856                        Anchor {
2857                            buffer_id: Some(excerpt.buffer_id),
2858                            excerpt_id: excerpt.id,
2859                            text_anchor,
2860                        }
2861                    } else if anchor.text_anchor.bias == Bias::Left {
2862                        Anchor::min()
2863                    } else {
2864                        Anchor::max()
2865                    };
2866                }
2867
2868                result.push((anchor_ix, anchor, kept_position));
2869            }
2870        }
2871        result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self));
2872        result
2873    }
2874
2875    pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
2876        self.anchor_at(position, Bias::Left)
2877    }
2878
2879    pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
2880        self.anchor_at(position, Bias::Right)
2881    }
2882
2883    pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
2884        let offset = position.to_offset(self);
2885        if let Some((excerpt_id, buffer_id, buffer)) = self.as_singleton() {
2886            return Anchor {
2887                buffer_id: Some(buffer_id),
2888                excerpt_id: *excerpt_id,
2889                text_anchor: buffer.anchor_at(offset, bias),
2890            };
2891        }
2892
2893        let mut cursor = self.excerpts.cursor::<(usize, Option<ExcerptId>)>();
2894        cursor.seek(&offset, Bias::Right, &());
2895        if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left {
2896            cursor.prev(&());
2897        }
2898        if let Some(excerpt) = cursor.item() {
2899            let mut overshoot = offset.saturating_sub(cursor.start().0);
2900            if excerpt.has_trailing_newline && offset == cursor.end(&()).0 {
2901                overshoot -= 1;
2902                bias = Bias::Right;
2903            }
2904
2905            let buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2906            let text_anchor =
2907                excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
2908            Anchor {
2909                buffer_id: Some(excerpt.buffer_id),
2910                excerpt_id: excerpt.id,
2911                text_anchor,
2912            }
2913        } else if offset == 0 && bias == Bias::Left {
2914            Anchor::min()
2915        } else {
2916            Anchor::max()
2917        }
2918    }
2919
2920    /// Returns an anchor for the given excerpt and text anchor,
2921    /// returns None if the excerpt_id is no longer valid.
2922    pub fn anchor_in_excerpt(
2923        &self,
2924        excerpt_id: ExcerptId,
2925        text_anchor: text::Anchor,
2926    ) -> Option<Anchor> {
2927        let locator = self.excerpt_locator_for_id(excerpt_id);
2928        let mut cursor = self.excerpts.cursor::<Option<&Locator>>();
2929        cursor.seek(locator, Bias::Left, &());
2930        if let Some(excerpt) = cursor.item() {
2931            if excerpt.id == excerpt_id {
2932                let text_anchor = excerpt.clip_anchor(text_anchor);
2933                drop(cursor);
2934                return Some(Anchor {
2935                    buffer_id: Some(excerpt.buffer_id),
2936                    excerpt_id,
2937                    text_anchor,
2938                });
2939            }
2940        }
2941        None
2942    }
2943
2944    pub fn can_resolve(&self, anchor: &Anchor) -> bool {
2945        if anchor.excerpt_id == ExcerptId::min() || anchor.excerpt_id == ExcerptId::max() {
2946            true
2947        } else if let Some(excerpt) = self.excerpt(anchor.excerpt_id) {
2948            excerpt.buffer.can_resolve(&anchor.text_anchor)
2949        } else {
2950            false
2951        }
2952    }
2953
2954    pub fn excerpts(
2955        &self,
2956    ) -> impl Iterator<Item = (ExcerptId, &BufferSnapshot, ExcerptRange<text::Anchor>)> {
2957        self.excerpts
2958            .iter()
2959            .map(|excerpt| (excerpt.id, &excerpt.buffer, excerpt.range.clone()))
2960    }
2961
2962    fn excerpts_for_range<T: ToOffset>(
2963        &self,
2964        range: Range<T>,
2965    ) -> impl Iterator<Item = (&Excerpt, usize)> + '_ {
2966        let range = range.start.to_offset(self)..range.end.to_offset(self);
2967
2968        let mut cursor = self.excerpts.cursor::<usize>();
2969        cursor.seek(&range.start, Bias::Right, &());
2970        cursor.prev(&());
2971
2972        iter::from_fn(move || {
2973            cursor.next(&());
2974            if cursor.start() < &range.end {
2975                cursor.item().map(|item| (item, *cursor.start()))
2976            } else {
2977                None
2978            }
2979        })
2980    }
2981
2982    pub fn excerpt_boundaries_in_range<R, T>(
2983        &self,
2984        range: R,
2985    ) -> impl Iterator<Item = ExcerptBoundary> + '_
2986    where
2987        R: RangeBounds<T>,
2988        T: ToOffset,
2989    {
2990        let start_offset;
2991        let start = match range.start_bound() {
2992            Bound::Included(start) => {
2993                start_offset = start.to_offset(self);
2994                Bound::Included(start_offset)
2995            }
2996            Bound::Excluded(start) => {
2997                start_offset = start.to_offset(self);
2998                Bound::Excluded(start_offset)
2999            }
3000            Bound::Unbounded => {
3001                start_offset = 0;
3002                Bound::Unbounded
3003            }
3004        };
3005        let end = match range.end_bound() {
3006            Bound::Included(end) => Bound::Included(end.to_offset(self)),
3007            Bound::Excluded(end) => Bound::Excluded(end.to_offset(self)),
3008            Bound::Unbounded => Bound::Unbounded,
3009        };
3010        let bounds = (start, end);
3011
3012        let mut cursor = self.excerpts.cursor::<(usize, Point)>();
3013        cursor.seek(&start_offset, Bias::Right, &());
3014        if cursor.item().is_none() {
3015            cursor.prev(&());
3016        }
3017        if !bounds.contains(&cursor.start().0) {
3018            cursor.next(&());
3019        }
3020
3021        let mut prev_buffer_id = cursor.prev_item().map(|excerpt| excerpt.buffer_id);
3022        std::iter::from_fn(move || {
3023            if self.singleton {
3024                None
3025            } else if bounds.contains(&cursor.start().0) {
3026                let excerpt = cursor.item()?;
3027                let starts_new_buffer = Some(excerpt.buffer_id) != prev_buffer_id;
3028                let boundary = ExcerptBoundary {
3029                    id: excerpt.id,
3030                    row: MultiBufferRow(cursor.start().1.row),
3031                    buffer: excerpt.buffer.clone(),
3032                    range: excerpt.range.clone(),
3033                    starts_new_buffer,
3034                };
3035
3036                prev_buffer_id = Some(excerpt.buffer_id);
3037                cursor.next(&());
3038                Some(boundary)
3039            } else {
3040                None
3041            }
3042        })
3043    }
3044
3045    pub fn edit_count(&self) -> usize {
3046        self.edit_count
3047    }
3048
3049    pub fn parse_count(&self) -> usize {
3050        self.parse_count
3051    }
3052
3053    /// Returns the smallest enclosing bracket ranges containing the given range or
3054    /// None if no brackets contain range or the range is not contained in a single
3055    /// excerpt
3056    ///
3057    /// Can optionally pass a range_filter to filter the ranges of brackets to consider
3058    pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
3059        &self,
3060        range: Range<T>,
3061        range_filter: Option<&dyn Fn(Range<usize>, Range<usize>) -> bool>,
3062    ) -> Option<(Range<usize>, Range<usize>)> {
3063        let range = range.start.to_offset(self)..range.end.to_offset(self);
3064        let excerpt = self.excerpt_containing(range.clone())?;
3065
3066        // Filter to ranges contained in the excerpt
3067        let range_filter = |open: Range<usize>, close: Range<usize>| -> bool {
3068            excerpt.contains_buffer_range(open.start..close.end)
3069                && range_filter.map_or(true, |filter| {
3070                    filter(
3071                        excerpt.map_range_from_buffer(open),
3072                        excerpt.map_range_from_buffer(close),
3073                    )
3074                })
3075        };
3076
3077        let (open, close) = excerpt.buffer().innermost_enclosing_bracket_ranges(
3078            excerpt.map_range_to_buffer(range),
3079            Some(&range_filter),
3080        )?;
3081
3082        Some((
3083            excerpt.map_range_from_buffer(open),
3084            excerpt.map_range_from_buffer(close),
3085        ))
3086    }
3087
3088    /// Returns enclosing bracket ranges containing the given range or returns None if the range is
3089    /// not contained in a single excerpt
3090    pub fn enclosing_bracket_ranges<T: ToOffset>(
3091        &self,
3092        range: Range<T>,
3093    ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + '_> {
3094        let range = range.start.to_offset(self)..range.end.to_offset(self);
3095        let excerpt = self.excerpt_containing(range.clone())?;
3096
3097        Some(
3098            excerpt
3099                .buffer()
3100                .enclosing_bracket_ranges(excerpt.map_range_to_buffer(range))
3101                .filter_map(move |(open, close)| {
3102                    if excerpt.contains_buffer_range(open.start..close.end) {
3103                        Some((
3104                            excerpt.map_range_from_buffer(open),
3105                            excerpt.map_range_from_buffer(close),
3106                        ))
3107                    } else {
3108                        None
3109                    }
3110                }),
3111        )
3112    }
3113
3114    /// Returns bracket range pairs overlapping the given `range` or returns None if the `range` is
3115    /// not contained in a single excerpt
3116    pub fn bracket_ranges<T: ToOffset>(
3117        &self,
3118        range: Range<T>,
3119    ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + '_> {
3120        let range = range.start.to_offset(self)..range.end.to_offset(self);
3121        let excerpt = self.excerpt_containing(range.clone())?;
3122
3123        Some(
3124            excerpt
3125                .buffer()
3126                .bracket_ranges(excerpt.map_range_to_buffer(range))
3127                .filter_map(move |(start_bracket_range, close_bracket_range)| {
3128                    let buffer_range = start_bracket_range.start..close_bracket_range.end;
3129                    if excerpt.contains_buffer_range(buffer_range) {
3130                        Some((
3131                            excerpt.map_range_from_buffer(start_bracket_range),
3132                            excerpt.map_range_from_buffer(close_bracket_range),
3133                        ))
3134                    } else {
3135                        None
3136                    }
3137                }),
3138        )
3139    }
3140
3141    pub fn redacted_ranges<'a, T: ToOffset>(
3142        &'a self,
3143        range: Range<T>,
3144        redaction_enabled: impl Fn(Option<&Arc<dyn File>>) -> bool + 'a,
3145    ) -> impl Iterator<Item = Range<usize>> + 'a {
3146        let range = range.start.to_offset(self)..range.end.to_offset(self);
3147        self.excerpts_for_range(range.clone())
3148            .filter_map(move |(excerpt, excerpt_offset)| {
3149                redaction_enabled(excerpt.buffer.file()).then(move || {
3150                    let excerpt_buffer_start =
3151                        excerpt.range.context.start.to_offset(&excerpt.buffer);
3152
3153                    excerpt
3154                        .buffer
3155                        .redacted_ranges(excerpt.range.context.clone())
3156                        .map(move |mut redacted_range| {
3157                            // Re-base onto the excerpts coordinates in the multibuffer
3158                            redacted_range.start = excerpt_offset
3159                                + redacted_range.start.saturating_sub(excerpt_buffer_start);
3160                            redacted_range.end = excerpt_offset
3161                                + redacted_range.end.saturating_sub(excerpt_buffer_start);
3162
3163                            redacted_range
3164                        })
3165                        .skip_while(move |redacted_range| redacted_range.end < range.start)
3166                        .take_while(move |redacted_range| redacted_range.start < range.end)
3167                })
3168            })
3169            .flatten()
3170    }
3171
3172    pub fn runnable_ranges(
3173        &self,
3174        range: Range<Anchor>,
3175    ) -> impl Iterator<Item = language::RunnableRange> + '_ {
3176        let range = range.start.to_offset(self)..range.end.to_offset(self);
3177        self.excerpts_for_range(range.clone())
3178            .flat_map(move |(excerpt, excerpt_offset)| {
3179                let excerpt_buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
3180
3181                excerpt
3182                    .buffer
3183                    .runnable_ranges(excerpt.range.context.clone())
3184                    .filter_map(move |mut runnable| {
3185                        // Re-base onto the excerpts coordinates in the multibuffer
3186                        //
3187                        // The node matching our runnables query might partially overlap with
3188                        // the provided range. If the run indicator is outside of excerpt bounds, do not actually show it.
3189                        if runnable.run_range.start < excerpt_buffer_start {
3190                            return None;
3191                        }
3192                        if language::ToPoint::to_point(&runnable.run_range.end, &excerpt.buffer).row
3193                            > excerpt.max_buffer_row
3194                        {
3195                            return None;
3196                        }
3197                        runnable.run_range.start =
3198                            excerpt_offset + runnable.run_range.start - excerpt_buffer_start;
3199                        runnable.run_range.end =
3200                            excerpt_offset + runnable.run_range.end - excerpt_buffer_start;
3201                        Some(runnable)
3202                    })
3203                    .skip_while(move |runnable| runnable.run_range.end < range.start)
3204                    .take_while(move |runnable| runnable.run_range.start < range.end)
3205            })
3206    }
3207
3208    pub fn indent_guides_in_range(
3209        &self,
3210        range: Range<Anchor>,
3211        cx: &AppContext,
3212    ) -> Vec<MultiBufferIndentGuide> {
3213        // Fast path for singleton buffers, we can skip the conversion between offsets.
3214        if let Some((_, _, snapshot)) = self.as_singleton() {
3215            return snapshot
3216                .indent_guides_in_range(range.start.text_anchor..range.end.text_anchor, cx)
3217                .into_iter()
3218                .map(|guide| MultiBufferIndentGuide {
3219                    multibuffer_row_range: MultiBufferRow(guide.start_row)
3220                        ..MultiBufferRow(guide.end_row),
3221                    buffer: guide,
3222                })
3223                .collect();
3224        }
3225
3226        let range = range.start.to_offset(self)..range.end.to_offset(self);
3227
3228        self.excerpts_for_range(range.clone())
3229            .flat_map(move |(excerpt, excerpt_offset)| {
3230                let excerpt_buffer_start_row =
3231                    excerpt.range.context.start.to_point(&excerpt.buffer).row;
3232                let excerpt_offset_row = crate::ToPoint::to_point(&excerpt_offset, self).row;
3233
3234                excerpt
3235                    .buffer
3236                    .indent_guides_in_range(excerpt.range.context.clone(), cx)
3237                    .into_iter()
3238                    .map(move |indent_guide| {
3239                        let start_row = excerpt_offset_row
3240                            + (indent_guide.start_row - excerpt_buffer_start_row);
3241                        let end_row =
3242                            excerpt_offset_row + (indent_guide.end_row - excerpt_buffer_start_row);
3243
3244                        MultiBufferIndentGuide {
3245                            multibuffer_row_range: MultiBufferRow(start_row)
3246                                ..MultiBufferRow(end_row),
3247                            buffer: indent_guide,
3248                        }
3249                    })
3250            })
3251            .collect()
3252    }
3253
3254    pub fn diagnostics_update_count(&self) -> usize {
3255        self.diagnostics_update_count
3256    }
3257
3258    pub fn git_diff_update_count(&self) -> usize {
3259        self.git_diff_update_count
3260    }
3261
3262    pub fn trailing_excerpt_update_count(&self) -> usize {
3263        self.trailing_excerpt_update_count
3264    }
3265
3266    pub fn file_at<T: ToOffset>(&self, point: T) -> Option<&Arc<dyn File>> {
3267        self.point_to_buffer_offset(point)
3268            .and_then(|(buffer, _)| buffer.file())
3269    }
3270
3271    pub fn language_at<T: ToOffset>(&self, point: T) -> Option<&Arc<Language>> {
3272        self.point_to_buffer_offset(point)
3273            .and_then(|(buffer, offset)| buffer.language_at(offset))
3274    }
3275
3276    pub fn settings_at<'a, T: ToOffset>(
3277        &'a self,
3278        point: T,
3279        cx: &'a AppContext,
3280    ) -> &'a LanguageSettings {
3281        let mut language = None;
3282        let mut file = None;
3283        if let Some((buffer, offset)) = self.point_to_buffer_offset(point) {
3284            language = buffer.language_at(offset);
3285            file = buffer.file();
3286        }
3287        language_settings(language, file, cx)
3288    }
3289
3290    pub fn language_scope_at<T: ToOffset>(&self, point: T) -> Option<LanguageScope> {
3291        self.point_to_buffer_offset(point)
3292            .and_then(|(buffer, offset)| buffer.language_scope_at(offset))
3293    }
3294
3295    pub fn language_indent_size_at<T: ToOffset>(
3296        &self,
3297        position: T,
3298        cx: &AppContext,
3299    ) -> Option<IndentSize> {
3300        let (buffer_snapshot, offset) = self.point_to_buffer_offset(position)?;
3301        Some(buffer_snapshot.language_indent_size_at(offset, cx))
3302    }
3303
3304    pub fn is_dirty(&self) -> bool {
3305        self.is_dirty
3306    }
3307
3308    pub fn has_conflict(&self) -> bool {
3309        self.has_conflict
3310    }
3311
3312    pub fn has_diagnostics(&self) -> bool {
3313        self.excerpts
3314            .iter()
3315            .any(|excerpt| excerpt.buffer.has_diagnostics())
3316    }
3317
3318    pub fn diagnostic_group<'a, O>(
3319        &'a self,
3320        group_id: usize,
3321    ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
3322    where
3323        O: text::FromAnchor + 'a,
3324    {
3325        self.as_singleton()
3326            .into_iter()
3327            .flat_map(move |(_, _, buffer)| buffer.diagnostic_group(group_id))
3328    }
3329
3330    pub fn diagnostics_in_range<'a, T, O>(
3331        &'a self,
3332        range: Range<T>,
3333        reversed: bool,
3334    ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
3335    where
3336        T: 'a + ToOffset,
3337        O: 'a + text::FromAnchor + Ord,
3338    {
3339        self.as_singleton()
3340            .into_iter()
3341            .flat_map(move |(_, _, buffer)| {
3342                buffer.diagnostics_in_range(
3343                    range.start.to_offset(self)..range.end.to_offset(self),
3344                    reversed,
3345                )
3346            })
3347    }
3348
3349    pub fn has_git_diffs(&self) -> bool {
3350        for excerpt in self.excerpts.iter() {
3351            if excerpt.buffer.has_git_diff() {
3352                return true;
3353            }
3354        }
3355        false
3356    }
3357
3358    pub fn git_diff_hunks_in_range_rev(
3359        &self,
3360        row_range: Range<MultiBufferRow>,
3361    ) -> impl Iterator<Item = DiffHunk<MultiBufferRow>> + '_ {
3362        let mut cursor = self.excerpts.cursor::<Point>();
3363
3364        cursor.seek(&Point::new(row_range.end.0, 0), Bias::Left, &());
3365        if cursor.item().is_none() {
3366            cursor.prev(&());
3367        }
3368
3369        std::iter::from_fn(move || {
3370            let excerpt = cursor.item()?;
3371            let multibuffer_start = *cursor.start();
3372            let multibuffer_end = multibuffer_start + excerpt.text_summary.lines;
3373            if multibuffer_start.row >= row_range.end.0 {
3374                return None;
3375            }
3376
3377            let mut buffer_start = excerpt.range.context.start;
3378            let mut buffer_end = excerpt.range.context.end;
3379            let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
3380            let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
3381
3382            if row_range.start.0 > multibuffer_start.row {
3383                let buffer_start_point =
3384                    excerpt_start_point + Point::new(row_range.start.0 - multibuffer_start.row, 0);
3385                buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
3386            }
3387
3388            if row_range.end.0 < multibuffer_end.row {
3389                let buffer_end_point =
3390                    excerpt_start_point + Point::new(row_range.end.0 - multibuffer_start.row, 0);
3391                buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
3392            }
3393
3394            let buffer_hunks = excerpt
3395                .buffer
3396                .git_diff_hunks_intersecting_range_rev(buffer_start..buffer_end)
3397                .map(move |hunk| {
3398                    let start = multibuffer_start.row
3399                        + hunk
3400                            .associated_range
3401                            .start
3402                            .saturating_sub(excerpt_start_point.row);
3403                    let end = multibuffer_start.row
3404                        + hunk
3405                            .associated_range
3406                            .end
3407                            .min(excerpt_end_point.row + 1)
3408                            .saturating_sub(excerpt_start_point.row);
3409
3410                    DiffHunk {
3411                        associated_range: MultiBufferRow(start)..MultiBufferRow(end),
3412                        diff_base_byte_range: hunk.diff_base_byte_range.clone(),
3413                        buffer_range: hunk.buffer_range.clone(),
3414                        buffer_id: hunk.buffer_id,
3415                    }
3416                });
3417
3418            cursor.prev(&());
3419
3420            Some(buffer_hunks)
3421        })
3422        .flatten()
3423    }
3424
3425    pub fn git_diff_hunks_in_range(
3426        &self,
3427        row_range: Range<MultiBufferRow>,
3428    ) -> impl Iterator<Item = DiffHunk<MultiBufferRow>> + '_ {
3429        let mut cursor = self.excerpts.cursor::<Point>();
3430
3431        cursor.seek(&Point::new(row_range.start.0, 0), Bias::Left, &());
3432
3433        std::iter::from_fn(move || {
3434            let excerpt = cursor.item()?;
3435            let multibuffer_start = *cursor.start();
3436            let multibuffer_end = multibuffer_start + excerpt.text_summary.lines;
3437            let mut buffer_start = excerpt.range.context.start;
3438            let mut buffer_end = excerpt.range.context.end;
3439
3440            let excerpt_rows = match multibuffer_start.row.cmp(&row_range.end.0) {
3441                cmp::Ordering::Less => {
3442                    let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
3443                    let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
3444
3445                    if row_range.start.0 > multibuffer_start.row {
3446                        let buffer_start_point = excerpt_start_point
3447                            + Point::new(row_range.start.0 - multibuffer_start.row, 0);
3448                        buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
3449                    }
3450
3451                    if row_range.end.0 < multibuffer_end.row {
3452                        let buffer_end_point = excerpt_start_point
3453                            + Point::new(row_range.end.0 - multibuffer_start.row, 0);
3454                        buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
3455                    }
3456                    excerpt_start_point.row..excerpt_end_point.row
3457                }
3458                cmp::Ordering::Equal if row_range.end.0 == 0 => {
3459                    buffer_end = buffer_start;
3460                    0..0
3461                }
3462                cmp::Ordering::Greater | cmp::Ordering::Equal => return None,
3463            };
3464
3465            let buffer_hunks = excerpt
3466                .buffer
3467                .git_diff_hunks_intersecting_range(buffer_start..buffer_end)
3468                .map(move |hunk| {
3469                    let buffer_range = if excerpt_rows.start == 0 && excerpt_rows.end == 0 {
3470                        MultiBufferRow(0)..MultiBufferRow(1)
3471                    } else {
3472                        let start = multibuffer_start.row
3473                            + hunk
3474                                .associated_range
3475                                .start
3476                                .saturating_sub(excerpt_rows.start);
3477                        let end = multibuffer_start.row
3478                            + hunk
3479                                .associated_range
3480                                .end
3481                                .min(excerpt_rows.end + 1)
3482                                .saturating_sub(excerpt_rows.start);
3483                        MultiBufferRow(start)..MultiBufferRow(end)
3484                    };
3485                    DiffHunk {
3486                        associated_range: buffer_range,
3487                        diff_base_byte_range: hunk.diff_base_byte_range.clone(),
3488                        buffer_range: hunk.buffer_range.clone(),
3489                        buffer_id: hunk.buffer_id,
3490                    }
3491                });
3492
3493            cursor.next(&());
3494
3495            Some(buffer_hunks)
3496        })
3497        .flatten()
3498    }
3499
3500    pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
3501        let range = range.start.to_offset(self)..range.end.to_offset(self);
3502        let excerpt = self.excerpt_containing(range.clone())?;
3503
3504        let ancestor_buffer_range = excerpt
3505            .buffer()
3506            .range_for_syntax_ancestor(excerpt.map_range_to_buffer(range))?;
3507
3508        Some(excerpt.map_range_from_buffer(ancestor_buffer_range))
3509    }
3510
3511    pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
3512        let (excerpt_id, _, buffer) = self.as_singleton()?;
3513        let outline = buffer.outline(theme)?;
3514        Some(Outline::new(
3515            outline
3516                .items
3517                .into_iter()
3518                .flat_map(|item| {
3519                    Some(OutlineItem {
3520                        depth: item.depth,
3521                        range: self.anchor_in_excerpt(*excerpt_id, item.range.start)?
3522                            ..self.anchor_in_excerpt(*excerpt_id, item.range.end)?,
3523                        text: item.text,
3524                        highlight_ranges: item.highlight_ranges,
3525                        name_ranges: item.name_ranges,
3526                    })
3527                })
3528                .collect(),
3529        ))
3530    }
3531
3532    pub fn symbols_containing<T: ToOffset>(
3533        &self,
3534        offset: T,
3535        theme: Option<&SyntaxTheme>,
3536    ) -> Option<(BufferId, Vec<OutlineItem<Anchor>>)> {
3537        let anchor = self.anchor_before(offset);
3538        let excerpt_id = anchor.excerpt_id;
3539        let excerpt = self.excerpt(excerpt_id)?;
3540        Some((
3541            excerpt.buffer_id,
3542            excerpt
3543                .buffer
3544                .symbols_containing(anchor.text_anchor, theme)
3545                .into_iter()
3546                .flatten()
3547                .flat_map(|item| {
3548                    Some(OutlineItem {
3549                        depth: item.depth,
3550                        range: self.anchor_in_excerpt(excerpt_id, item.range.start)?
3551                            ..self.anchor_in_excerpt(excerpt_id, item.range.end)?,
3552                        text: item.text,
3553                        highlight_ranges: item.highlight_ranges,
3554                        name_ranges: item.name_ranges,
3555                    })
3556                })
3557                .collect(),
3558        ))
3559    }
3560
3561    fn excerpt_locator_for_id(&self, id: ExcerptId) -> &Locator {
3562        if id == ExcerptId::min() {
3563            Locator::min_ref()
3564        } else if id == ExcerptId::max() {
3565            Locator::max_ref()
3566        } else {
3567            let mut cursor = self.excerpt_ids.cursor::<ExcerptId>();
3568            cursor.seek(&id, Bias::Left, &());
3569            if let Some(entry) = cursor.item() {
3570                if entry.id == id {
3571                    return &entry.locator;
3572                }
3573            }
3574            panic!("invalid excerpt id {:?}", id)
3575        }
3576    }
3577
3578    // Returns the locators referenced by the given excerpt ids, sorted by locator.
3579    fn excerpt_locators_for_ids(
3580        &self,
3581        ids: impl IntoIterator<Item = ExcerptId>,
3582    ) -> SmallVec<[Locator; 1]> {
3583        let mut sorted_ids = ids.into_iter().collect::<SmallVec<[_; 1]>>();
3584        sorted_ids.sort_unstable();
3585        let mut locators = SmallVec::new();
3586
3587        while sorted_ids.last() == Some(&ExcerptId::max()) {
3588            sorted_ids.pop();
3589            locators.push(Locator::max());
3590        }
3591
3592        let mut sorted_ids = sorted_ids.into_iter().dedup().peekable();
3593        if sorted_ids.peek() == Some(&ExcerptId::min()) {
3594            sorted_ids.next();
3595            locators.push(Locator::min());
3596        }
3597
3598        let mut cursor = self.excerpt_ids.cursor::<ExcerptId>();
3599        for id in sorted_ids {
3600            if cursor.seek_forward(&id, Bias::Left, &()) {
3601                locators.push(cursor.item().unwrap().locator.clone());
3602            } else {
3603                panic!("invalid excerpt id {:?}", id);
3604            }
3605        }
3606
3607        locators.sort_unstable();
3608        locators
3609    }
3610
3611    pub fn buffer_id_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<BufferId> {
3612        Some(self.excerpt(excerpt_id)?.buffer_id)
3613    }
3614
3615    pub fn buffer_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<&BufferSnapshot> {
3616        Some(&self.excerpt(excerpt_id)?.buffer)
3617    }
3618
3619    fn excerpt(&self, excerpt_id: ExcerptId) -> Option<&Excerpt> {
3620        let mut cursor = self.excerpts.cursor::<Option<&Locator>>();
3621        let locator = self.excerpt_locator_for_id(excerpt_id);
3622        cursor.seek(&Some(locator), Bias::Left, &());
3623        if let Some(excerpt) = cursor.item() {
3624            if excerpt.id == excerpt_id {
3625                return Some(excerpt);
3626            }
3627        }
3628        None
3629    }
3630
3631    /// Returns the excerpt containing range and its offset start within the multibuffer or none if `range` spans multiple excerpts
3632    pub fn excerpt_containing<T: ToOffset>(&self, range: Range<T>) -> Option<MultiBufferExcerpt> {
3633        let range = range.start.to_offset(self)..range.end.to_offset(self);
3634
3635        let mut cursor = self.excerpts.cursor::<usize>();
3636        cursor.seek(&range.start, Bias::Right, &());
3637        let start_excerpt = cursor.item()?;
3638
3639        if range.start == range.end {
3640            return Some(MultiBufferExcerpt::new(start_excerpt, *cursor.start()));
3641        }
3642
3643        cursor.seek(&range.end, Bias::Right, &());
3644        let end_excerpt = cursor.item()?;
3645
3646        if start_excerpt.id == end_excerpt.id {
3647            Some(MultiBufferExcerpt::new(start_excerpt, *cursor.start()))
3648        } else {
3649            None
3650        }
3651    }
3652
3653    pub fn remote_selections_in_range<'a>(
3654        &'a self,
3655        range: &'a Range<Anchor>,
3656    ) -> impl 'a + Iterator<Item = (ReplicaId, bool, CursorShape, Selection<Anchor>)> {
3657        let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
3658        let start_locator = self.excerpt_locator_for_id(range.start.excerpt_id);
3659        let end_locator = self.excerpt_locator_for_id(range.end.excerpt_id);
3660        cursor.seek(start_locator, Bias::Left, &());
3661        cursor
3662            .take_while(move |excerpt| excerpt.locator <= *end_locator)
3663            .flat_map(move |excerpt| {
3664                let mut query_range = excerpt.range.context.start..excerpt.range.context.end;
3665                if excerpt.id == range.start.excerpt_id {
3666                    query_range.start = range.start.text_anchor;
3667                }
3668                if excerpt.id == range.end.excerpt_id {
3669                    query_range.end = range.end.text_anchor;
3670                }
3671
3672                excerpt
3673                    .buffer
3674                    .remote_selections_in_range(query_range)
3675                    .flat_map(move |(replica_id, line_mode, cursor_shape, selections)| {
3676                        selections.map(move |selection| {
3677                            let mut start = Anchor {
3678                                buffer_id: Some(excerpt.buffer_id),
3679                                excerpt_id: excerpt.id,
3680                                text_anchor: selection.start,
3681                            };
3682                            let mut end = Anchor {
3683                                buffer_id: Some(excerpt.buffer_id),
3684                                excerpt_id: excerpt.id,
3685                                text_anchor: selection.end,
3686                            };
3687                            if range.start.cmp(&start, self).is_gt() {
3688                                start = range.start;
3689                            }
3690                            if range.end.cmp(&end, self).is_lt() {
3691                                end = range.end;
3692                            }
3693
3694                            (
3695                                replica_id,
3696                                line_mode,
3697                                cursor_shape,
3698                                Selection {
3699                                    id: selection.id,
3700                                    start,
3701                                    end,
3702                                    reversed: selection.reversed,
3703                                    goal: selection.goal,
3704                                },
3705                            )
3706                        })
3707                    })
3708            })
3709    }
3710
3711    pub fn show_headers(&self) -> bool {
3712        self.show_headers
3713    }
3714}
3715
3716#[cfg(any(test, feature = "test-support"))]
3717impl MultiBufferSnapshot {
3718    pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
3719        let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
3720        let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
3721        start..end
3722    }
3723}
3724
3725impl History {
3726    fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
3727        self.transaction_depth += 1;
3728        if self.transaction_depth == 1 {
3729            let id = self.next_transaction_id.tick();
3730            self.undo_stack.push(Transaction {
3731                id,
3732                buffer_transactions: Default::default(),
3733                first_edit_at: now,
3734                last_edit_at: now,
3735                suppress_grouping: false,
3736            });
3737            Some(id)
3738        } else {
3739            None
3740        }
3741    }
3742
3743    fn end_transaction(
3744        &mut self,
3745        now: Instant,
3746        buffer_transactions: HashMap<BufferId, TransactionId>,
3747    ) -> bool {
3748        assert_ne!(self.transaction_depth, 0);
3749        self.transaction_depth -= 1;
3750        if self.transaction_depth == 0 {
3751            if buffer_transactions.is_empty() {
3752                self.undo_stack.pop();
3753                false
3754            } else {
3755                self.redo_stack.clear();
3756                let transaction = self.undo_stack.last_mut().unwrap();
3757                transaction.last_edit_at = now;
3758                for (buffer_id, transaction_id) in buffer_transactions {
3759                    transaction
3760                        .buffer_transactions
3761                        .entry(buffer_id)
3762                        .or_insert(transaction_id);
3763                }
3764                true
3765            }
3766        } else {
3767            false
3768        }
3769    }
3770
3771    fn push_transaction<'a, T>(
3772        &mut self,
3773        buffer_transactions: T,
3774        now: Instant,
3775        cx: &mut ModelContext<MultiBuffer>,
3776    ) where
3777        T: IntoIterator<Item = (&'a Model<Buffer>, &'a language::Transaction)>,
3778    {
3779        assert_eq!(self.transaction_depth, 0);
3780        let transaction = Transaction {
3781            id: self.next_transaction_id.tick(),
3782            buffer_transactions: buffer_transactions
3783                .into_iter()
3784                .map(|(buffer, transaction)| (buffer.read(cx).remote_id(), transaction.id))
3785                .collect(),
3786            first_edit_at: now,
3787            last_edit_at: now,
3788            suppress_grouping: false,
3789        };
3790        if !transaction.buffer_transactions.is_empty() {
3791            self.undo_stack.push(transaction);
3792            self.redo_stack.clear();
3793        }
3794    }
3795
3796    fn finalize_last_transaction(&mut self) {
3797        if let Some(transaction) = self.undo_stack.last_mut() {
3798            transaction.suppress_grouping = true;
3799        }
3800    }
3801
3802    fn forget(&mut self, transaction_id: TransactionId) -> Option<Transaction> {
3803        if let Some(ix) = self
3804            .undo_stack
3805            .iter()
3806            .rposition(|transaction| transaction.id == transaction_id)
3807        {
3808            Some(self.undo_stack.remove(ix))
3809        } else if let Some(ix) = self
3810            .redo_stack
3811            .iter()
3812            .rposition(|transaction| transaction.id == transaction_id)
3813        {
3814            Some(self.redo_stack.remove(ix))
3815        } else {
3816            None
3817        }
3818    }
3819
3820    fn transaction_mut(&mut self, transaction_id: TransactionId) -> Option<&mut Transaction> {
3821        self.undo_stack
3822            .iter_mut()
3823            .find(|transaction| transaction.id == transaction_id)
3824            .or_else(|| {
3825                self.redo_stack
3826                    .iter_mut()
3827                    .find(|transaction| transaction.id == transaction_id)
3828            })
3829    }
3830
3831    fn pop_undo(&mut self) -> Option<&mut Transaction> {
3832        assert_eq!(self.transaction_depth, 0);
3833        if let Some(transaction) = self.undo_stack.pop() {
3834            self.redo_stack.push(transaction);
3835            self.redo_stack.last_mut()
3836        } else {
3837            None
3838        }
3839    }
3840
3841    fn pop_redo(&mut self) -> Option<&mut Transaction> {
3842        assert_eq!(self.transaction_depth, 0);
3843        if let Some(transaction) = self.redo_stack.pop() {
3844            self.undo_stack.push(transaction);
3845            self.undo_stack.last_mut()
3846        } else {
3847            None
3848        }
3849    }
3850
3851    fn remove_from_undo(&mut self, transaction_id: TransactionId) -> Option<&Transaction> {
3852        let ix = self
3853            .undo_stack
3854            .iter()
3855            .rposition(|transaction| transaction.id == transaction_id)?;
3856        let transaction = self.undo_stack.remove(ix);
3857        self.redo_stack.push(transaction);
3858        self.redo_stack.last()
3859    }
3860
3861    fn group(&mut self) -> Option<TransactionId> {
3862        let mut count = 0;
3863        let mut transactions = self.undo_stack.iter();
3864        if let Some(mut transaction) = transactions.next_back() {
3865            while let Some(prev_transaction) = transactions.next_back() {
3866                if !prev_transaction.suppress_grouping
3867                    && transaction.first_edit_at - prev_transaction.last_edit_at
3868                        <= self.group_interval
3869                {
3870                    transaction = prev_transaction;
3871                    count += 1;
3872                } else {
3873                    break;
3874                }
3875            }
3876        }
3877        self.group_trailing(count)
3878    }
3879
3880    fn group_until(&mut self, transaction_id: TransactionId) {
3881        let mut count = 0;
3882        for transaction in self.undo_stack.iter().rev() {
3883            if transaction.id == transaction_id {
3884                self.group_trailing(count);
3885                break;
3886            } else if transaction.suppress_grouping {
3887                break;
3888            } else {
3889                count += 1;
3890            }
3891        }
3892    }
3893
3894    fn group_trailing(&mut self, n: usize) -> Option<TransactionId> {
3895        let new_len = self.undo_stack.len() - n;
3896        let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
3897        if let Some(last_transaction) = transactions_to_keep.last_mut() {
3898            if let Some(transaction) = transactions_to_merge.last() {
3899                last_transaction.last_edit_at = transaction.last_edit_at;
3900            }
3901            for to_merge in transactions_to_merge {
3902                for (buffer_id, transaction_id) in &to_merge.buffer_transactions {
3903                    last_transaction
3904                        .buffer_transactions
3905                        .entry(*buffer_id)
3906                        .or_insert(*transaction_id);
3907                }
3908            }
3909        }
3910
3911        self.undo_stack.truncate(new_len);
3912        self.undo_stack.last().map(|t| t.id)
3913    }
3914}
3915
3916impl Excerpt {
3917    fn new(
3918        id: ExcerptId,
3919        locator: Locator,
3920        buffer_id: BufferId,
3921        buffer: BufferSnapshot,
3922        range: ExcerptRange<text::Anchor>,
3923        has_trailing_newline: bool,
3924    ) -> Self {
3925        Excerpt {
3926            id,
3927            locator,
3928            max_buffer_row: range.context.end.to_point(&buffer).row,
3929            text_summary: buffer
3930                .text_summary_for_range::<TextSummary, _>(range.context.to_offset(&buffer)),
3931            buffer_id,
3932            buffer,
3933            range,
3934            has_trailing_newline,
3935        }
3936    }
3937
3938    fn chunks_in_range(&self, range: Range<usize>, language_aware: bool) -> ExcerptChunks {
3939        let content_start = self.range.context.start.to_offset(&self.buffer);
3940        let chunks_start = content_start + range.start;
3941        let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
3942
3943        let footer_height = if self.has_trailing_newline
3944            && range.start <= self.text_summary.len
3945            && range.end > self.text_summary.len
3946        {
3947            1
3948        } else {
3949            0
3950        };
3951
3952        let content_chunks = self.buffer.chunks(chunks_start..chunks_end, language_aware);
3953
3954        ExcerptChunks {
3955            content_chunks,
3956            footer_height,
3957        }
3958    }
3959
3960    fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
3961        let content_start = self.range.context.start.to_offset(&self.buffer);
3962        let bytes_start = content_start + range.start;
3963        let bytes_end = content_start + cmp::min(range.end, self.text_summary.len);
3964        let footer_height = if self.has_trailing_newline
3965            && range.start <= self.text_summary.len
3966            && range.end > self.text_summary.len
3967        {
3968            1
3969        } else {
3970            0
3971        };
3972        let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
3973
3974        ExcerptBytes {
3975            content_bytes,
3976            padding_height: footer_height,
3977            reversed: false,
3978        }
3979    }
3980
3981    fn reversed_bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
3982        let content_start = self.range.context.start.to_offset(&self.buffer);
3983        let bytes_start = content_start + range.start;
3984        let bytes_end = content_start + cmp::min(range.end, self.text_summary.len);
3985        let footer_height = if self.has_trailing_newline
3986            && range.start <= self.text_summary.len
3987            && range.end > self.text_summary.len
3988        {
3989            1
3990        } else {
3991            0
3992        };
3993        let content_bytes = self.buffer.reversed_bytes_in_range(bytes_start..bytes_end);
3994
3995        ExcerptBytes {
3996            content_bytes,
3997            padding_height: footer_height,
3998            reversed: true,
3999        }
4000    }
4001
4002    fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
4003        if text_anchor
4004            .cmp(&self.range.context.start, &self.buffer)
4005            .is_lt()
4006        {
4007            self.range.context.start
4008        } else if text_anchor
4009            .cmp(&self.range.context.end, &self.buffer)
4010            .is_gt()
4011        {
4012            self.range.context.end
4013        } else {
4014            text_anchor
4015        }
4016    }
4017
4018    fn contains(&self, anchor: &Anchor) -> bool {
4019        Some(self.buffer_id) == anchor.buffer_id
4020            && self
4021                .range
4022                .context
4023                .start
4024                .cmp(&anchor.text_anchor, &self.buffer)
4025                .is_le()
4026            && self
4027                .range
4028                .context
4029                .end
4030                .cmp(&anchor.text_anchor, &self.buffer)
4031                .is_ge()
4032    }
4033
4034    /// The [`Excerpt`]'s start offset in its [`Buffer`]
4035    fn buffer_start_offset(&self) -> usize {
4036        self.range.context.start.to_offset(&self.buffer)
4037    }
4038
4039    /// The [`Excerpt`]'s end offset in its [`Buffer`]
4040    fn buffer_end_offset(&self) -> usize {
4041        self.buffer_start_offset() + self.text_summary.len
4042    }
4043}
4044
4045impl<'a> MultiBufferExcerpt<'a> {
4046    fn new(excerpt: &'a Excerpt, excerpt_offset: usize) -> Self {
4047        MultiBufferExcerpt {
4048            excerpt,
4049            excerpt_offset,
4050        }
4051    }
4052
4053    pub fn buffer(&self) -> &'a BufferSnapshot {
4054        &self.excerpt.buffer
4055    }
4056
4057    /// Maps an offset within the [`MultiBuffer`] to an offset within the [`Buffer`]
4058    pub fn map_offset_to_buffer(&self, offset: usize) -> usize {
4059        self.excerpt.buffer_start_offset() + offset.saturating_sub(self.excerpt_offset)
4060    }
4061
4062    /// Maps a range within the [`MultiBuffer`] to a range within the [`Buffer`]
4063    pub fn map_range_to_buffer(&self, range: Range<usize>) -> Range<usize> {
4064        self.map_offset_to_buffer(range.start)..self.map_offset_to_buffer(range.end)
4065    }
4066
4067    /// Map an offset within the [`Buffer`] to an offset within the [`MultiBuffer`]
4068    pub fn map_offset_from_buffer(&self, buffer_offset: usize) -> usize {
4069        let mut buffer_offset_in_excerpt =
4070            buffer_offset.saturating_sub(self.excerpt.buffer_start_offset());
4071        buffer_offset_in_excerpt =
4072            cmp::min(buffer_offset_in_excerpt, self.excerpt.text_summary.len);
4073
4074        self.excerpt_offset + buffer_offset_in_excerpt
4075    }
4076
4077    /// Map a range within the [`Buffer`] to a range within the [`MultiBuffer`]
4078    pub fn map_range_from_buffer(&self, buffer_range: Range<usize>) -> Range<usize> {
4079        self.map_offset_from_buffer(buffer_range.start)
4080            ..self.map_offset_from_buffer(buffer_range.end)
4081    }
4082
4083    /// Returns true if the entirety of the given range is in the buffer's excerpt
4084    pub fn contains_buffer_range(&self, range: Range<usize>) -> bool {
4085        range.start >= self.excerpt.buffer_start_offset()
4086            && range.end <= self.excerpt.buffer_end_offset()
4087    }
4088}
4089
4090impl ExcerptId {
4091    pub fn min() -> Self {
4092        Self(0)
4093    }
4094
4095    pub fn max() -> Self {
4096        Self(usize::MAX)
4097    }
4098
4099    pub fn to_proto(&self) -> u64 {
4100        self.0 as _
4101    }
4102
4103    pub fn from_proto(proto: u64) -> Self {
4104        Self(proto as _)
4105    }
4106
4107    pub fn cmp(&self, other: &Self, snapshot: &MultiBufferSnapshot) -> cmp::Ordering {
4108        let a = snapshot.excerpt_locator_for_id(*self);
4109        let b = snapshot.excerpt_locator_for_id(*other);
4110        a.cmp(b).then_with(|| self.0.cmp(&other.0))
4111    }
4112}
4113
4114impl Into<usize> for ExcerptId {
4115    fn into(self) -> usize {
4116        self.0
4117    }
4118}
4119
4120impl fmt::Debug for Excerpt {
4121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4122        f.debug_struct("Excerpt")
4123            .field("id", &self.id)
4124            .field("locator", &self.locator)
4125            .field("buffer_id", &self.buffer_id)
4126            .field("range", &self.range)
4127            .field("text_summary", &self.text_summary)
4128            .field("has_trailing_newline", &self.has_trailing_newline)
4129            .finish()
4130    }
4131}
4132
4133impl sum_tree::Item for Excerpt {
4134    type Summary = ExcerptSummary;
4135
4136    fn summary(&self) -> Self::Summary {
4137        let mut text = self.text_summary.clone();
4138        if self.has_trailing_newline {
4139            text += TextSummary::from("\n");
4140        }
4141        ExcerptSummary {
4142            excerpt_id: self.id,
4143            excerpt_locator: self.locator.clone(),
4144            max_buffer_row: MultiBufferRow(self.max_buffer_row),
4145            text,
4146        }
4147    }
4148}
4149
4150impl sum_tree::Item for ExcerptIdMapping {
4151    type Summary = ExcerptId;
4152
4153    fn summary(&self) -> Self::Summary {
4154        self.id
4155    }
4156}
4157
4158impl sum_tree::KeyedItem for ExcerptIdMapping {
4159    type Key = ExcerptId;
4160
4161    fn key(&self) -> Self::Key {
4162        self.id
4163    }
4164}
4165
4166impl sum_tree::Summary for ExcerptId {
4167    type Context = ();
4168
4169    fn add_summary(&mut self, other: &Self, _: &()) {
4170        *self = *other;
4171    }
4172}
4173
4174impl sum_tree::Summary for ExcerptSummary {
4175    type Context = ();
4176
4177    fn add_summary(&mut self, summary: &Self, _: &()) {
4178        debug_assert!(summary.excerpt_locator > self.excerpt_locator);
4179        self.excerpt_locator = summary.excerpt_locator.clone();
4180        self.text.add_summary(&summary.text, &());
4181        self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row);
4182    }
4183}
4184
4185impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
4186    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4187        *self += &summary.text;
4188    }
4189}
4190
4191impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
4192    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4193        *self += summary.text.len;
4194    }
4195}
4196
4197impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
4198    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
4199        Ord::cmp(self, &cursor_location.text.len)
4200    }
4201}
4202
4203impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, Option<&'a Locator>> for Locator {
4204    fn cmp(&self, cursor_location: &Option<&'a Locator>, _: &()) -> cmp::Ordering {
4205        Ord::cmp(&Some(self), cursor_location)
4206    }
4207}
4208
4209impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Locator {
4210    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
4211        Ord::cmp(self, &cursor_location.excerpt_locator)
4212    }
4213}
4214
4215impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for OffsetUtf16 {
4216    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4217        *self += summary.text.len_utf16;
4218    }
4219}
4220
4221impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
4222    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4223        *self += summary.text.lines;
4224    }
4225}
4226
4227impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
4228    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4229        *self += summary.text.lines_utf16()
4230    }
4231}
4232
4233impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a Locator> {
4234    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4235        *self = Some(&summary.excerpt_locator);
4236    }
4237}
4238
4239impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<ExcerptId> {
4240    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4241        *self = Some(summary.excerpt_id);
4242    }
4243}
4244
4245impl<'a> MultiBufferRows<'a> {
4246    pub fn seek(&mut self, row: MultiBufferRow) {
4247        self.buffer_row_range = 0..0;
4248
4249        self.excerpts
4250            .seek_forward(&Point::new(row.0, 0), Bias::Right, &());
4251        if self.excerpts.item().is_none() {
4252            self.excerpts.prev(&());
4253
4254            if self.excerpts.item().is_none() && row.0 == 0 {
4255                self.buffer_row_range = 0..1;
4256                return;
4257            }
4258        }
4259
4260        if let Some(excerpt) = self.excerpts.item() {
4261            let overshoot = row.0 - self.excerpts.start().row;
4262            let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
4263            self.buffer_row_range.start = excerpt_start + overshoot;
4264            self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
4265        }
4266    }
4267}
4268
4269impl<'a> Iterator for MultiBufferRows<'a> {
4270    type Item = Option<u32>;
4271
4272    fn next(&mut self) -> Option<Self::Item> {
4273        loop {
4274            if !self.buffer_row_range.is_empty() {
4275                let row = Some(self.buffer_row_range.start);
4276                self.buffer_row_range.start += 1;
4277                return Some(row);
4278            }
4279            self.excerpts.item()?;
4280            self.excerpts.next(&());
4281            let excerpt = self.excerpts.item()?;
4282            self.buffer_row_range.start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
4283            self.buffer_row_range.end =
4284                self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
4285        }
4286    }
4287}
4288
4289impl<'a> MultiBufferChunks<'a> {
4290    pub fn offset(&self) -> usize {
4291        self.range.start
4292    }
4293
4294    pub fn seek(&mut self, offset: usize) {
4295        self.range.start = offset;
4296        self.excerpts.seek(&offset, Bias::Right, &());
4297        if let Some(excerpt) = self.excerpts.item() {
4298            self.excerpt_chunks = Some(excerpt.chunks_in_range(
4299                self.range.start - self.excerpts.start()..self.range.end - self.excerpts.start(),
4300                self.language_aware,
4301            ));
4302        } else {
4303            self.excerpt_chunks = None;
4304        }
4305    }
4306}
4307
4308impl<'a> Iterator for MultiBufferChunks<'a> {
4309    type Item = Chunk<'a>;
4310
4311    fn next(&mut self) -> Option<Self::Item> {
4312        if self.range.is_empty() {
4313            None
4314        } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
4315            self.range.start += chunk.text.len();
4316            Some(chunk)
4317        } else {
4318            self.excerpts.next(&());
4319            let excerpt = self.excerpts.item()?;
4320            self.excerpt_chunks = Some(excerpt.chunks_in_range(
4321                0..self.range.end - self.excerpts.start(),
4322                self.language_aware,
4323            ));
4324            self.next()
4325        }
4326    }
4327}
4328
4329impl<'a> MultiBufferBytes<'a> {
4330    fn consume(&mut self, len: usize) {
4331        self.range.start += len;
4332        self.chunk = &self.chunk[len..];
4333
4334        if !self.range.is_empty() && self.chunk.is_empty() {
4335            if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
4336                self.chunk = chunk;
4337            } else {
4338                self.excerpts.next(&());
4339                if let Some(excerpt) = self.excerpts.item() {
4340                    let mut excerpt_bytes =
4341                        excerpt.bytes_in_range(0..self.range.end - self.excerpts.start());
4342                    self.chunk = excerpt_bytes.next().unwrap();
4343                    self.excerpt_bytes = Some(excerpt_bytes);
4344                }
4345            }
4346        }
4347    }
4348}
4349
4350impl<'a> Iterator for MultiBufferBytes<'a> {
4351    type Item = &'a [u8];
4352
4353    fn next(&mut self) -> Option<Self::Item> {
4354        let chunk = self.chunk;
4355        if chunk.is_empty() {
4356            None
4357        } else {
4358            self.consume(chunk.len());
4359            Some(chunk)
4360        }
4361    }
4362}
4363
4364impl<'a> io::Read for MultiBufferBytes<'a> {
4365    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
4366        let len = cmp::min(buf.len(), self.chunk.len());
4367        buf[..len].copy_from_slice(&self.chunk[..len]);
4368        if len > 0 {
4369            self.consume(len);
4370        }
4371        Ok(len)
4372    }
4373}
4374
4375impl<'a> ReversedMultiBufferBytes<'a> {
4376    fn consume(&mut self, len: usize) {
4377        self.range.end -= len;
4378        self.chunk = &self.chunk[..self.chunk.len() - len];
4379
4380        if !self.range.is_empty() && self.chunk.is_empty() {
4381            if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
4382                self.chunk = chunk;
4383            } else {
4384                self.excerpts.prev(&());
4385                if let Some(excerpt) = self.excerpts.item() {
4386                    let mut excerpt_bytes = excerpt.reversed_bytes_in_range(
4387                        self.range.start.saturating_sub(*self.excerpts.start())..usize::MAX,
4388                    );
4389                    self.chunk = excerpt_bytes.next().unwrap();
4390                    self.excerpt_bytes = Some(excerpt_bytes);
4391                }
4392            }
4393        } else {
4394        }
4395    }
4396}
4397
4398impl<'a> io::Read for ReversedMultiBufferBytes<'a> {
4399    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
4400        let len = cmp::min(buf.len(), self.chunk.len());
4401        buf[..len].copy_from_slice(&self.chunk[..len]);
4402        buf[..len].reverse();
4403        if len > 0 {
4404            self.consume(len);
4405        }
4406        Ok(len)
4407    }
4408}
4409impl<'a> Iterator for ExcerptBytes<'a> {
4410    type Item = &'a [u8];
4411
4412    fn next(&mut self) -> Option<Self::Item> {
4413        if self.reversed && self.padding_height > 0 {
4414            let result = &NEWLINES[..self.padding_height];
4415            self.padding_height = 0;
4416            return Some(result);
4417        }
4418
4419        if let Some(chunk) = self.content_bytes.next() {
4420            if !chunk.is_empty() {
4421                return Some(chunk);
4422            }
4423        }
4424
4425        if self.padding_height > 0 {
4426            let result = &NEWLINES[..self.padding_height];
4427            self.padding_height = 0;
4428            return Some(result);
4429        }
4430
4431        None
4432    }
4433}
4434
4435impl<'a> Iterator for ExcerptChunks<'a> {
4436    type Item = Chunk<'a>;
4437
4438    fn next(&mut self) -> Option<Self::Item> {
4439        if let Some(chunk) = self.content_chunks.next() {
4440            return Some(chunk);
4441        }
4442
4443        if self.footer_height > 0 {
4444            let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
4445            self.footer_height = 0;
4446            return Some(Chunk {
4447                text,
4448                ..Default::default()
4449            });
4450        }
4451
4452        None
4453    }
4454}
4455
4456impl ToOffset for Point {
4457    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
4458        snapshot.point_to_offset(*self)
4459    }
4460}
4461
4462impl ToOffset for usize {
4463    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
4464        assert!(*self <= snapshot.len(), "offset is out of range");
4465        *self
4466    }
4467}
4468
4469impl ToOffset for OffsetUtf16 {
4470    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
4471        snapshot.offset_utf16_to_offset(*self)
4472    }
4473}
4474
4475impl ToOffset for PointUtf16 {
4476    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
4477        snapshot.point_utf16_to_offset(*self)
4478    }
4479}
4480
4481impl ToOffsetUtf16 for OffsetUtf16 {
4482    fn to_offset_utf16(&self, _snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
4483        *self
4484    }
4485}
4486
4487impl ToOffsetUtf16 for usize {
4488    fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
4489        snapshot.offset_to_offset_utf16(*self)
4490    }
4491}
4492
4493impl ToPoint for usize {
4494    fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
4495        snapshot.offset_to_point(*self)
4496    }
4497}
4498
4499impl ToPoint for Point {
4500    fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
4501        *self
4502    }
4503}
4504
4505impl ToPointUtf16 for usize {
4506    fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
4507        snapshot.offset_to_point_utf16(*self)
4508    }
4509}
4510
4511impl ToPointUtf16 for Point {
4512    fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
4513        snapshot.point_to_point_utf16(*self)
4514    }
4515}
4516
4517impl ToPointUtf16 for PointUtf16 {
4518    fn to_point_utf16<'a>(&self, _: &MultiBufferSnapshot) -> PointUtf16 {
4519        *self
4520    }
4521}
4522
4523fn build_excerpt_ranges<T>(
4524    buffer: &BufferSnapshot,
4525    ranges: &[Range<T>],
4526    context_line_count: u32,
4527) -> (Vec<ExcerptRange<Point>>, Vec<usize>)
4528where
4529    T: text::ToPoint,
4530{
4531    let max_point = buffer.max_point();
4532    let mut range_counts = Vec::new();
4533    let mut excerpt_ranges = Vec::new();
4534    let mut range_iter = ranges
4535        .iter()
4536        .map(|range| range.start.to_point(buffer)..range.end.to_point(buffer))
4537        .peekable();
4538    while let Some(range) = range_iter.next() {
4539        let excerpt_start = Point::new(range.start.row.saturating_sub(context_line_count), 0);
4540        // These + 1s ensure that we select the whole next line
4541        let mut excerpt_end = Point::new(range.end.row + 1 + context_line_count, 0).min(max_point);
4542
4543        let mut ranges_in_excerpt = 1;
4544
4545        while let Some(next_range) = range_iter.peek() {
4546            if next_range.start.row <= excerpt_end.row + context_line_count {
4547                excerpt_end =
4548                    Point::new(next_range.end.row + 1 + context_line_count, 0).min(max_point);
4549                ranges_in_excerpt += 1;
4550                range_iter.next();
4551            } else {
4552                break;
4553            }
4554        }
4555
4556        excerpt_ranges.push(ExcerptRange {
4557            context: excerpt_start..excerpt_end,
4558            primary: Some(range),
4559        });
4560        range_counts.push(ranges_in_excerpt);
4561    }
4562
4563    (excerpt_ranges, range_counts)
4564}
4565
4566#[cfg(test)]
4567mod tests {
4568    use super::*;
4569    use futures::StreamExt;
4570    use gpui::{AppContext, Context, TestAppContext};
4571    use language::{Buffer, Rope};
4572    use parking_lot::RwLock;
4573    use rand::prelude::*;
4574    use settings::SettingsStore;
4575    use std::env;
4576    use util::test::sample_text;
4577
4578    #[ctor::ctor]
4579    fn init_logger() {
4580        if std::env::var("RUST_LOG").is_ok() {
4581            env_logger::init();
4582        }
4583    }
4584
4585    #[gpui::test]
4586    fn test_singleton(cx: &mut AppContext) {
4587        let buffer = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
4588        let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
4589
4590        let snapshot = multibuffer.read(cx).snapshot(cx);
4591        assert_eq!(snapshot.text(), buffer.read(cx).text());
4592
4593        assert_eq!(
4594            snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
4595            (0..buffer.read(cx).row_count())
4596                .map(Some)
4597                .collect::<Vec<_>>()
4598        );
4599
4600        buffer.update(cx, |buffer, cx| buffer.edit([(1..3, "XXX\n")], None, cx));
4601        let snapshot = multibuffer.read(cx).snapshot(cx);
4602
4603        assert_eq!(snapshot.text(), buffer.read(cx).text());
4604        assert_eq!(
4605            snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
4606            (0..buffer.read(cx).row_count())
4607                .map(Some)
4608                .collect::<Vec<_>>()
4609        );
4610    }
4611
4612    #[gpui::test]
4613    fn test_remote(cx: &mut AppContext) {
4614        let host_buffer = cx.new_model(|cx| Buffer::local("a", cx));
4615        let guest_buffer = cx.new_model(|cx| {
4616            let state = host_buffer.read(cx).to_proto();
4617            let ops = cx
4618                .background_executor()
4619                .block(host_buffer.read(cx).serialize_ops(None, cx));
4620            let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
4621            buffer
4622                .apply_ops(
4623                    ops.into_iter()
4624                        .map(|op| language::proto::deserialize_operation(op).unwrap()),
4625                    cx,
4626                )
4627                .unwrap();
4628            buffer
4629        });
4630        let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(guest_buffer.clone(), cx));
4631        let snapshot = multibuffer.read(cx).snapshot(cx);
4632        assert_eq!(snapshot.text(), "a");
4633
4634        guest_buffer.update(cx, |buffer, cx| buffer.edit([(1..1, "b")], None, cx));
4635        let snapshot = multibuffer.read(cx).snapshot(cx);
4636        assert_eq!(snapshot.text(), "ab");
4637
4638        guest_buffer.update(cx, |buffer, cx| buffer.edit([(2..2, "c")], None, cx));
4639        let snapshot = multibuffer.read(cx).snapshot(cx);
4640        assert_eq!(snapshot.text(), "abc");
4641    }
4642
4643    #[gpui::test]
4644    fn test_excerpt_boundaries_and_clipping(cx: &mut AppContext) {
4645        let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
4646        let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx));
4647        let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
4648
4649        let events = Arc::new(RwLock::new(Vec::<Event>::new()));
4650        multibuffer.update(cx, |_, cx| {
4651            let events = events.clone();
4652            cx.subscribe(&multibuffer, move |_, _, event, _| {
4653                if let Event::Edited { .. } = event {
4654                    events.write().push(event.clone())
4655                }
4656            })
4657            .detach();
4658        });
4659
4660        let subscription = multibuffer.update(cx, |multibuffer, cx| {
4661            let subscription = multibuffer.subscribe();
4662            multibuffer.push_excerpts(
4663                buffer_1.clone(),
4664                [ExcerptRange {
4665                    context: Point::new(1, 2)..Point::new(2, 5),
4666                    primary: None,
4667                }],
4668                cx,
4669            );
4670            assert_eq!(
4671                subscription.consume().into_inner(),
4672                [Edit {
4673                    old: 0..0,
4674                    new: 0..10
4675                }]
4676            );
4677
4678            multibuffer.push_excerpts(
4679                buffer_1.clone(),
4680                [ExcerptRange {
4681                    context: Point::new(3, 3)..Point::new(4, 4),
4682                    primary: None,
4683                }],
4684                cx,
4685            );
4686            multibuffer.push_excerpts(
4687                buffer_2.clone(),
4688                [ExcerptRange {
4689                    context: Point::new(3, 1)..Point::new(3, 3),
4690                    primary: None,
4691                }],
4692                cx,
4693            );
4694            assert_eq!(
4695                subscription.consume().into_inner(),
4696                [Edit {
4697                    old: 10..10,
4698                    new: 10..22
4699                }]
4700            );
4701
4702            subscription
4703        });
4704
4705        // Adding excerpts emits an edited event.
4706        assert_eq!(
4707            events.read().as_slice(),
4708            &[
4709                Event::Edited {
4710                    singleton_buffer_edited: false
4711                },
4712                Event::Edited {
4713                    singleton_buffer_edited: false
4714                },
4715                Event::Edited {
4716                    singleton_buffer_edited: false
4717                }
4718            ]
4719        );
4720
4721        let snapshot = multibuffer.read(cx).snapshot(cx);
4722        assert_eq!(
4723            snapshot.text(),
4724            concat!(
4725                "bbbb\n",  // Preserve newlines
4726                "ccccc\n", //
4727                "ddd\n",   //
4728                "eeee\n",  //
4729                "jj"       //
4730            )
4731        );
4732        assert_eq!(
4733            snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
4734            [Some(1), Some(2), Some(3), Some(4), Some(3)]
4735        );
4736        assert_eq!(
4737            snapshot.buffer_rows(MultiBufferRow(2)).collect::<Vec<_>>(),
4738            [Some(3), Some(4), Some(3)]
4739        );
4740        assert_eq!(
4741            snapshot.buffer_rows(MultiBufferRow(4)).collect::<Vec<_>>(),
4742            [Some(3)]
4743        );
4744        assert_eq!(
4745            snapshot.buffer_rows(MultiBufferRow(5)).collect::<Vec<_>>(),
4746            []
4747        );
4748
4749        assert_eq!(
4750            boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot),
4751            &[
4752                (MultiBufferRow(0), "bbbb\nccccc".to_string(), true),
4753                (MultiBufferRow(2), "ddd\neeee".to_string(), false),
4754                (MultiBufferRow(4), "jj".to_string(), true),
4755            ]
4756        );
4757        assert_eq!(
4758            boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot),
4759            &[(MultiBufferRow(0), "bbbb\nccccc".to_string(), true)]
4760        );
4761        assert_eq!(
4762            boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot),
4763            &[]
4764        );
4765        assert_eq!(
4766            boundaries_in_range(Point::new(1, 0)..Point::new(2, 0), &snapshot),
4767            &[]
4768        );
4769        assert_eq!(
4770            boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
4771            &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)]
4772        );
4773        assert_eq!(
4774            boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
4775            &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)]
4776        );
4777        assert_eq!(
4778            boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot),
4779            &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)]
4780        );
4781        assert_eq!(
4782            boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot),
4783            &[(MultiBufferRow(4), "jj".to_string(), true)]
4784        );
4785        assert_eq!(
4786            boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot),
4787            &[]
4788        );
4789
4790        buffer_1.update(cx, |buffer, cx| {
4791            let text = "\n";
4792            buffer.edit(
4793                [
4794                    (Point::new(0, 0)..Point::new(0, 0), text),
4795                    (Point::new(2, 1)..Point::new(2, 3), text),
4796                ],
4797                None,
4798                cx,
4799            );
4800        });
4801
4802        let snapshot = multibuffer.read(cx).snapshot(cx);
4803        assert_eq!(
4804            snapshot.text(),
4805            concat!(
4806                "bbbb\n", // Preserve newlines
4807                "c\n",    //
4808                "cc\n",   //
4809                "ddd\n",  //
4810                "eeee\n", //
4811                "jj"      //
4812            )
4813        );
4814
4815        assert_eq!(
4816            subscription.consume().into_inner(),
4817            [Edit {
4818                old: 6..8,
4819                new: 6..7
4820            }]
4821        );
4822
4823        let snapshot = multibuffer.read(cx).snapshot(cx);
4824        assert_eq!(
4825            snapshot.clip_point(Point::new(0, 5), Bias::Left),
4826            Point::new(0, 4)
4827        );
4828        assert_eq!(
4829            snapshot.clip_point(Point::new(0, 5), Bias::Right),
4830            Point::new(0, 4)
4831        );
4832        assert_eq!(
4833            snapshot.clip_point(Point::new(5, 1), Bias::Right),
4834            Point::new(5, 1)
4835        );
4836        assert_eq!(
4837            snapshot.clip_point(Point::new(5, 2), Bias::Right),
4838            Point::new(5, 2)
4839        );
4840        assert_eq!(
4841            snapshot.clip_point(Point::new(5, 3), Bias::Right),
4842            Point::new(5, 2)
4843        );
4844
4845        let snapshot = multibuffer.update(cx, |multibuffer, cx| {
4846            let (buffer_2_excerpt_id, _) =
4847                multibuffer.excerpts_for_buffer(&buffer_2, cx)[0].clone();
4848            multibuffer.remove_excerpts([buffer_2_excerpt_id], cx);
4849            multibuffer.snapshot(cx)
4850        });
4851
4852        assert_eq!(
4853            snapshot.text(),
4854            concat!(
4855                "bbbb\n", // Preserve newlines
4856                "c\n",    //
4857                "cc\n",   //
4858                "ddd\n",  //
4859                "eeee",   //
4860            )
4861        );
4862
4863        fn boundaries_in_range(
4864            range: Range<Point>,
4865            snapshot: &MultiBufferSnapshot,
4866        ) -> Vec<(MultiBufferRow, String, bool)> {
4867            snapshot
4868                .excerpt_boundaries_in_range(range)
4869                .map(|boundary| {
4870                    (
4871                        boundary.row,
4872                        boundary
4873                            .buffer
4874                            .text_for_range(boundary.range.context)
4875                            .collect::<String>(),
4876                        boundary.starts_new_buffer,
4877                    )
4878                })
4879                .collect::<Vec<_>>()
4880        }
4881    }
4882
4883    #[gpui::test]
4884    fn test_excerpt_events(cx: &mut AppContext) {
4885        let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(10, 3, 'a'), cx));
4886        let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(10, 3, 'm'), cx));
4887
4888        let leader_multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
4889        let follower_multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
4890        let follower_edit_event_count = Arc::new(RwLock::new(0));
4891
4892        follower_multibuffer.update(cx, |_, cx| {
4893            let follower_edit_event_count = follower_edit_event_count.clone();
4894            cx.subscribe(
4895                &leader_multibuffer,
4896                move |follower, _, event, cx| match event.clone() {
4897                    Event::ExcerptsAdded {
4898                        buffer,
4899                        predecessor,
4900                        excerpts,
4901                    } => follower.insert_excerpts_with_ids_after(predecessor, buffer, excerpts, cx),
4902                    Event::ExcerptsRemoved { ids } => follower.remove_excerpts(ids, cx),
4903                    Event::Edited { .. } => {
4904                        *follower_edit_event_count.write() += 1;
4905                    }
4906                    _ => {}
4907                },
4908            )
4909            .detach();
4910        });
4911
4912        leader_multibuffer.update(cx, |leader, cx| {
4913            leader.push_excerpts(
4914                buffer_1.clone(),
4915                [
4916                    ExcerptRange {
4917                        context: 0..8,
4918                        primary: None,
4919                    },
4920                    ExcerptRange {
4921                        context: 12..16,
4922                        primary: None,
4923                    },
4924                ],
4925                cx,
4926            );
4927            leader.insert_excerpts_after(
4928                leader.excerpt_ids()[0],
4929                buffer_2.clone(),
4930                [
4931                    ExcerptRange {
4932                        context: 0..5,
4933                        primary: None,
4934                    },
4935                    ExcerptRange {
4936                        context: 10..15,
4937                        primary: None,
4938                    },
4939                ],
4940                cx,
4941            )
4942        });
4943        assert_eq!(
4944            leader_multibuffer.read(cx).snapshot(cx).text(),
4945            follower_multibuffer.read(cx).snapshot(cx).text(),
4946        );
4947        assert_eq!(*follower_edit_event_count.read(), 2);
4948
4949        leader_multibuffer.update(cx, |leader, cx| {
4950            let excerpt_ids = leader.excerpt_ids();
4951            leader.remove_excerpts([excerpt_ids[1], excerpt_ids[3]], cx);
4952        });
4953        assert_eq!(
4954            leader_multibuffer.read(cx).snapshot(cx).text(),
4955            follower_multibuffer.read(cx).snapshot(cx).text(),
4956        );
4957        assert_eq!(*follower_edit_event_count.read(), 3);
4958
4959        // Removing an empty set of excerpts is a noop.
4960        leader_multibuffer.update(cx, |leader, cx| {
4961            leader.remove_excerpts([], cx);
4962        });
4963        assert_eq!(
4964            leader_multibuffer.read(cx).snapshot(cx).text(),
4965            follower_multibuffer.read(cx).snapshot(cx).text(),
4966        );
4967        assert_eq!(*follower_edit_event_count.read(), 3);
4968
4969        // Adding an empty set of excerpts is a noop.
4970        leader_multibuffer.update(cx, |leader, cx| {
4971            leader.push_excerpts::<usize>(buffer_2.clone(), [], cx);
4972        });
4973        assert_eq!(
4974            leader_multibuffer.read(cx).snapshot(cx).text(),
4975            follower_multibuffer.read(cx).snapshot(cx).text(),
4976        );
4977        assert_eq!(*follower_edit_event_count.read(), 3);
4978
4979        leader_multibuffer.update(cx, |leader, cx| {
4980            leader.clear(cx);
4981        });
4982        assert_eq!(
4983            leader_multibuffer.read(cx).snapshot(cx).text(),
4984            follower_multibuffer.read(cx).snapshot(cx).text(),
4985        );
4986        assert_eq!(*follower_edit_event_count.read(), 4);
4987    }
4988
4989    #[gpui::test]
4990    fn test_expand_excerpts(cx: &mut AppContext) {
4991        let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
4992        let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
4993
4994        multibuffer.update(cx, |multibuffer, cx| {
4995            multibuffer.push_excerpts_with_context_lines(
4996                buffer.clone(),
4997                vec![
4998                    // Note that in this test, this first excerpt
4999                    // does not contain a new line
5000                    Point::new(3, 2)..Point::new(3, 3),
5001                    Point::new(7, 1)..Point::new(7, 3),
5002                    Point::new(15, 0)..Point::new(15, 0),
5003                ],
5004                1,
5005                cx,
5006            )
5007        });
5008
5009        multibuffer.update(cx, |multibuffer, cx| {
5010            multibuffer.expand_excerpts(multibuffer.excerpt_ids(), 1, cx)
5011        });
5012
5013        let snapshot = multibuffer.read(cx).snapshot(cx);
5014
5015        // Expanding context lines causes the line containing 'fff' to appear in two different excerpts.
5016        // We don't attempt to merge them, because removing the excerpt could create inconsistency with other layers
5017        // that are tracking excerpt ids.
5018        assert_eq!(
5019            snapshot.text(),
5020            concat!(
5021                "bbb\n", // Preserve newlines
5022                "ccc\n", //
5023                "ddd\n", //
5024                "eee\n", //
5025                "fff\n", // <- Same as below
5026                "\n",    // Excerpt boundary
5027                "fff\n", // <- Same as above
5028                "ggg\n", //
5029                "hhh\n", //
5030                "iii\n", //
5031                "jjj\n", //
5032                "\n",    //
5033                "nnn\n", //
5034                "ooo\n", //
5035                "ppp\n", //
5036                "qqq\n", //
5037                "rrr\n", //
5038            )
5039        );
5040    }
5041
5042    #[gpui::test]
5043    fn test_push_excerpts_with_context_lines(cx: &mut AppContext) {
5044        let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
5045        let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
5046        let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
5047            multibuffer.push_excerpts_with_context_lines(
5048                buffer.clone(),
5049                vec![
5050                    // Note that in this test, this first excerpt
5051                    // does contain a new line
5052                    Point::new(3, 2)..Point::new(4, 2),
5053                    Point::new(7, 1)..Point::new(7, 3),
5054                    Point::new(15, 0)..Point::new(15, 0),
5055                ],
5056                2,
5057                cx,
5058            )
5059        });
5060
5061        let snapshot = multibuffer.read(cx).snapshot(cx);
5062        assert_eq!(
5063            snapshot.text(),
5064            concat!(
5065                "bbb\n", // Preserve newlines
5066                "ccc\n", //
5067                "ddd\n", //
5068                "eee\n", //
5069                "fff\n", //
5070                "ggg\n", //
5071                "hhh\n", //
5072                "iii\n", //
5073                "jjj\n", //
5074                "\n",    //
5075                "nnn\n", //
5076                "ooo\n", //
5077                "ppp\n", //
5078                "qqq\n", //
5079                "rrr\n", //
5080            )
5081        );
5082
5083        assert_eq!(
5084            anchor_ranges
5085                .iter()
5086                .map(|range| range.to_point(&snapshot))
5087                .collect::<Vec<_>>(),
5088            vec![
5089                Point::new(2, 2)..Point::new(3, 2),
5090                Point::new(6, 1)..Point::new(6, 3),
5091                Point::new(12, 0)..Point::new(12, 0)
5092            ]
5093        );
5094    }
5095
5096    #[gpui::test]
5097    async fn test_stream_excerpts_with_context_lines(cx: &mut TestAppContext) {
5098        let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
5099        let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
5100        let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
5101            let snapshot = buffer.read(cx);
5102            let ranges = vec![
5103                snapshot.anchor_before(Point::new(3, 2))..snapshot.anchor_before(Point::new(4, 2)),
5104                snapshot.anchor_before(Point::new(7, 1))..snapshot.anchor_before(Point::new(7, 3)),
5105                snapshot.anchor_before(Point::new(15, 0))
5106                    ..snapshot.anchor_before(Point::new(15, 0)),
5107            ];
5108            multibuffer.stream_excerpts_with_context_lines(buffer.clone(), ranges, 2, cx)
5109        });
5110
5111        let anchor_ranges = anchor_ranges.collect::<Vec<_>>().await;
5112
5113        let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx));
5114        assert_eq!(
5115            snapshot.text(),
5116            concat!(
5117                "bbb\n", //
5118                "ccc\n", //
5119                "ddd\n", //
5120                "eee\n", //
5121                "fff\n", //
5122                "ggg\n", //
5123                "hhh\n", //
5124                "iii\n", //
5125                "jjj\n", //
5126                "\n",    //
5127                "nnn\n", //
5128                "ooo\n", //
5129                "ppp\n", //
5130                "qqq\n", //
5131                "rrr\n", //
5132            )
5133        );
5134
5135        assert_eq!(
5136            anchor_ranges
5137                .iter()
5138                .map(|range| range.to_point(&snapshot))
5139                .collect::<Vec<_>>(),
5140            vec![
5141                Point::new(2, 2)..Point::new(3, 2),
5142                Point::new(6, 1)..Point::new(6, 3),
5143                Point::new(12, 0)..Point::new(12, 0)
5144            ]
5145        );
5146    }
5147
5148    #[gpui::test]
5149    fn test_empty_multibuffer(cx: &mut AppContext) {
5150        let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
5151
5152        let snapshot = multibuffer.read(cx).snapshot(cx);
5153        assert_eq!(snapshot.text(), "");
5154        assert_eq!(
5155            snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
5156            &[Some(0)]
5157        );
5158        assert_eq!(
5159            snapshot.buffer_rows(MultiBufferRow(1)).collect::<Vec<_>>(),
5160            &[]
5161        );
5162    }
5163
5164    #[gpui::test]
5165    fn test_singleton_multibuffer_anchors(cx: &mut AppContext) {
5166        let buffer = cx.new_model(|cx| Buffer::local("abcd", cx));
5167        let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
5168        let old_snapshot = multibuffer.read(cx).snapshot(cx);
5169        buffer.update(cx, |buffer, cx| {
5170            buffer.edit([(0..0, "X")], None, cx);
5171            buffer.edit([(5..5, "Y")], None, cx);
5172        });
5173        let new_snapshot = multibuffer.read(cx).snapshot(cx);
5174
5175        assert_eq!(old_snapshot.text(), "abcd");
5176        assert_eq!(new_snapshot.text(), "XabcdY");
5177
5178        assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
5179        assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
5180        assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
5181        assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
5182    }
5183
5184    #[gpui::test]
5185    fn test_multibuffer_anchors(cx: &mut AppContext) {
5186        let buffer_1 = cx.new_model(|cx| Buffer::local("abcd", cx));
5187        let buffer_2 = cx.new_model(|cx| Buffer::local("efghi", cx));
5188        let multibuffer = cx.new_model(|cx| {
5189            let mut multibuffer = MultiBuffer::new(0, Capability::ReadWrite);
5190            multibuffer.push_excerpts(
5191                buffer_1.clone(),
5192                [ExcerptRange {
5193                    context: 0..4,
5194                    primary: None,
5195                }],
5196                cx,
5197            );
5198            multibuffer.push_excerpts(
5199                buffer_2.clone(),
5200                [ExcerptRange {
5201                    context: 0..5,
5202                    primary: None,
5203                }],
5204                cx,
5205            );
5206            multibuffer
5207        });
5208        let old_snapshot = multibuffer.read(cx).snapshot(cx);
5209
5210        assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
5211        assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
5212        assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
5213        assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
5214        assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
5215        assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
5216
5217        buffer_1.update(cx, |buffer, cx| {
5218            buffer.edit([(0..0, "W")], None, cx);
5219            buffer.edit([(5..5, "X")], None, cx);
5220        });
5221        buffer_2.update(cx, |buffer, cx| {
5222            buffer.edit([(0..0, "Y")], None, cx);
5223            buffer.edit([(6..6, "Z")], None, cx);
5224        });
5225        let new_snapshot = multibuffer.read(cx).snapshot(cx);
5226
5227        assert_eq!(old_snapshot.text(), "abcd\nefghi");
5228        assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
5229
5230        assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
5231        assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
5232        assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
5233        assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
5234        assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
5235        assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
5236        assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
5237        assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
5238        assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
5239        assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
5240    }
5241
5242    #[gpui::test]
5243    fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut AppContext) {
5244        let buffer_1 = cx.new_model(|cx| Buffer::local("abcd", cx));
5245        let buffer_2 = cx.new_model(|cx| Buffer::local("ABCDEFGHIJKLMNOP", cx));
5246        let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
5247
5248        // Create an insertion id in buffer 1 that doesn't exist in buffer 2.
5249        // Add an excerpt from buffer 1 that spans this new insertion.
5250        buffer_1.update(cx, |buffer, cx| buffer.edit([(4..4, "123")], None, cx));
5251        let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| {
5252            multibuffer
5253                .push_excerpts(
5254                    buffer_1.clone(),
5255                    [ExcerptRange {
5256                        context: 0..7,
5257                        primary: None,
5258                    }],
5259                    cx,
5260                )
5261                .pop()
5262                .unwrap()
5263        });
5264
5265        let snapshot_1 = multibuffer.read(cx).snapshot(cx);
5266        assert_eq!(snapshot_1.text(), "abcd123");
5267
5268        // Replace the buffer 1 excerpt with new excerpts from buffer 2.
5269        let (excerpt_id_2, excerpt_id_3) = multibuffer.update(cx, |multibuffer, cx| {
5270            multibuffer.remove_excerpts([excerpt_id_1], cx);
5271            let mut ids = multibuffer
5272                .push_excerpts(
5273                    buffer_2.clone(),
5274                    [
5275                        ExcerptRange {
5276                            context: 0..4,
5277                            primary: None,
5278                        },
5279                        ExcerptRange {
5280                            context: 6..10,
5281                            primary: None,
5282                        },
5283                        ExcerptRange {
5284                            context: 12..16,
5285                            primary: None,
5286                        },
5287                    ],
5288                    cx,
5289                )
5290                .into_iter();
5291            (ids.next().unwrap(), ids.next().unwrap())
5292        });
5293        let snapshot_2 = multibuffer.read(cx).snapshot(cx);
5294        assert_eq!(snapshot_2.text(), "ABCD\nGHIJ\nMNOP");
5295
5296        // The old excerpt id doesn't get reused.
5297        assert_ne!(excerpt_id_2, excerpt_id_1);
5298
5299        // Resolve some anchors from the previous snapshot in the new snapshot.
5300        // The current excerpts are from a different buffer, so we don't attempt to
5301        // resolve the old text anchor in the new buffer.
5302        assert_eq!(
5303            snapshot_2.summary_for_anchor::<usize>(&snapshot_1.anchor_before(2)),
5304            0
5305        );
5306        assert_eq!(
5307            snapshot_2.summaries_for_anchors::<usize, _>(&[
5308                snapshot_1.anchor_before(2),
5309                snapshot_1.anchor_after(3)
5310            ]),
5311            vec![0, 0]
5312        );
5313
5314        // Refresh anchors from the old snapshot. The return value indicates that both
5315        // anchors lost their original excerpt.
5316        let refresh =
5317            snapshot_2.refresh_anchors(&[snapshot_1.anchor_before(2), snapshot_1.anchor_after(3)]);
5318        assert_eq!(
5319            refresh,
5320            &[
5321                (0, snapshot_2.anchor_before(0), false),
5322                (1, snapshot_2.anchor_after(0), false),
5323            ]
5324        );
5325
5326        // Replace the middle excerpt with a smaller excerpt in buffer 2,
5327        // that intersects the old excerpt.
5328        let excerpt_id_5 = multibuffer.update(cx, |multibuffer, cx| {
5329            multibuffer.remove_excerpts([excerpt_id_3], cx);
5330            multibuffer
5331                .insert_excerpts_after(
5332                    excerpt_id_2,
5333                    buffer_2.clone(),
5334                    [ExcerptRange {
5335                        context: 5..8,
5336                        primary: None,
5337                    }],
5338                    cx,
5339                )
5340                .pop()
5341                .unwrap()
5342        });
5343
5344        let snapshot_3 = multibuffer.read(cx).snapshot(cx);
5345        assert_eq!(snapshot_3.text(), "ABCD\nFGH\nMNOP");
5346        assert_ne!(excerpt_id_5, excerpt_id_3);
5347
5348        // Resolve some anchors from the previous snapshot in the new snapshot.
5349        // The third anchor can't be resolved, since its excerpt has been removed,
5350        // so it resolves to the same position as its predecessor.
5351        let anchors = [
5352            snapshot_2.anchor_before(0),
5353            snapshot_2.anchor_after(2),
5354            snapshot_2.anchor_after(6),
5355            snapshot_2.anchor_after(14),
5356        ];
5357        assert_eq!(
5358            snapshot_3.summaries_for_anchors::<usize, _>(&anchors),
5359            &[0, 2, 9, 13]
5360        );
5361
5362        let new_anchors = snapshot_3.refresh_anchors(&anchors);
5363        assert_eq!(
5364            new_anchors.iter().map(|a| (a.0, a.2)).collect::<Vec<_>>(),
5365            &[(0, true), (1, true), (2, true), (3, true)]
5366        );
5367        assert_eq!(
5368            snapshot_3.summaries_for_anchors::<usize, _>(new_anchors.iter().map(|a| &a.1)),
5369            &[0, 2, 7, 13]
5370        );
5371    }
5372
5373    #[gpui::test(iterations = 100)]
5374    fn test_random_multibuffer(cx: &mut AppContext, mut rng: StdRng) {
5375        let operations = env::var("OPERATIONS")
5376            .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
5377            .unwrap_or(10);
5378
5379        let mut buffers: Vec<Model<Buffer>> = Vec::new();
5380        let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
5381        let mut excerpt_ids = Vec::<ExcerptId>::new();
5382        let mut expected_excerpts = Vec::<(Model<Buffer>, Range<text::Anchor>)>::new();
5383        let mut anchors = Vec::new();
5384        let mut old_versions = Vec::new();
5385
5386        for _ in 0..operations {
5387            match rng.gen_range(0..100) {
5388                0..=14 if !buffers.is_empty() => {
5389                    let buffer = buffers.choose(&mut rng).unwrap();
5390                    buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
5391                }
5392                15..=19 if !expected_excerpts.is_empty() => {
5393                    multibuffer.update(cx, |multibuffer, cx| {
5394                        let ids = multibuffer.excerpt_ids();
5395                        let mut excerpts = HashSet::default();
5396                        for _ in 0..rng.gen_range(0..ids.len()) {
5397                            excerpts.extend(ids.choose(&mut rng).copied());
5398                        }
5399
5400                        let line_count = rng.gen_range(0..5);
5401
5402                        let excerpt_ixs = excerpts
5403                            .iter()
5404                            .map(|id| excerpt_ids.iter().position(|i| i == id).unwrap())
5405                            .collect::<Vec<_>>();
5406                        log::info!("Expanding excerpts {excerpt_ixs:?} by {line_count} lines");
5407                        multibuffer.expand_excerpts(excerpts.iter().cloned(), line_count, cx);
5408
5409                        if line_count > 0 {
5410                            for id in excerpts {
5411                                let excerpt_ix = excerpt_ids.iter().position(|&i| i == id).unwrap();
5412                                let (buffer, range) = &mut expected_excerpts[excerpt_ix];
5413                                let snapshot = buffer.read(cx).snapshot();
5414                                let mut point_range = range.to_point(&snapshot);
5415                                point_range.start =
5416                                    Point::new(point_range.start.row.saturating_sub(line_count), 0);
5417                                point_range.end = snapshot.clip_point(
5418                                    Point::new(point_range.end.row + line_count, 0),
5419                                    Bias::Left,
5420                                );
5421                                *range = snapshot.anchor_before(point_range.start)
5422                                    ..snapshot.anchor_after(point_range.end);
5423                            }
5424                        }
5425                    });
5426                }
5427                20..=29 if !expected_excerpts.is_empty() => {
5428                    let mut ids_to_remove = vec![];
5429                    for _ in 0..rng.gen_range(1..=3) {
5430                        if expected_excerpts.is_empty() {
5431                            break;
5432                        }
5433
5434                        let ix = rng.gen_range(0..expected_excerpts.len());
5435                        ids_to_remove.push(excerpt_ids.remove(ix));
5436                        let (buffer, range) = expected_excerpts.remove(ix);
5437                        let buffer = buffer.read(cx);
5438                        log::info!(
5439                            "Removing excerpt {}: {:?}",
5440                            ix,
5441                            buffer
5442                                .text_for_range(range.to_offset(buffer))
5443                                .collect::<String>(),
5444                        );
5445                    }
5446                    let snapshot = multibuffer.read(cx).read(cx);
5447                    ids_to_remove.sort_unstable_by(|a, b| a.cmp(&b, &snapshot));
5448                    drop(snapshot);
5449                    multibuffer.update(cx, |multibuffer, cx| {
5450                        multibuffer.remove_excerpts(ids_to_remove, cx)
5451                    });
5452                }
5453                30..=39 if !expected_excerpts.is_empty() => {
5454                    let multibuffer = multibuffer.read(cx).read(cx);
5455                    let offset =
5456                        multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left);
5457                    let bias = if rng.gen() { Bias::Left } else { Bias::Right };
5458                    log::info!("Creating anchor at {} with bias {:?}", offset, bias);
5459                    anchors.push(multibuffer.anchor_at(offset, bias));
5460                    anchors.sort_by(|a, b| a.cmp(b, &multibuffer));
5461                }
5462                40..=44 if !anchors.is_empty() => {
5463                    let multibuffer = multibuffer.read(cx).read(cx);
5464                    let prev_len = anchors.len();
5465                    anchors = multibuffer
5466                        .refresh_anchors(&anchors)
5467                        .into_iter()
5468                        .map(|a| a.1)
5469                        .collect();
5470
5471                    // Ensure the newly-refreshed anchors point to a valid excerpt and don't
5472                    // overshoot its boundaries.
5473                    assert_eq!(anchors.len(), prev_len);
5474                    for anchor in &anchors {
5475                        if anchor.excerpt_id == ExcerptId::min()
5476                            || anchor.excerpt_id == ExcerptId::max()
5477                        {
5478                            continue;
5479                        }
5480
5481                        let excerpt = multibuffer.excerpt(anchor.excerpt_id).unwrap();
5482                        assert_eq!(excerpt.id, anchor.excerpt_id);
5483                        assert!(excerpt.contains(anchor));
5484                    }
5485                }
5486                _ => {
5487                    let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
5488                        let base_text = util::RandomCharIter::new(&mut rng)
5489                            .take(25)
5490                            .collect::<String>();
5491
5492                        buffers.push(cx.new_model(|cx| Buffer::local(base_text, cx)));
5493                        buffers.last().unwrap()
5494                    } else {
5495                        buffers.choose(&mut rng).unwrap()
5496                    };
5497
5498                    let buffer = buffer_handle.read(cx);
5499                    let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
5500                    let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
5501                    let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
5502                    let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len());
5503                    let prev_excerpt_id = excerpt_ids
5504                        .get(prev_excerpt_ix)
5505                        .cloned()
5506                        .unwrap_or_else(ExcerptId::max);
5507                    let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len());
5508
5509                    log::info!(
5510                        "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}",
5511                        excerpt_ix,
5512                        expected_excerpts.len(),
5513                        buffer_handle.read(cx).remote_id(),
5514                        buffer.text(),
5515                        start_ix..end_ix,
5516                        &buffer.text()[start_ix..end_ix]
5517                    );
5518
5519                    let excerpt_id = multibuffer.update(cx, |multibuffer, cx| {
5520                        multibuffer
5521                            .insert_excerpts_after(
5522                                prev_excerpt_id,
5523                                buffer_handle.clone(),
5524                                [ExcerptRange {
5525                                    context: start_ix..end_ix,
5526                                    primary: None,
5527                                }],
5528                                cx,
5529                            )
5530                            .pop()
5531                            .unwrap()
5532                    });
5533
5534                    excerpt_ids.insert(excerpt_ix, excerpt_id);
5535                    expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range));
5536                }
5537            }
5538
5539            if rng.gen_bool(0.3) {
5540                multibuffer.update(cx, |multibuffer, cx| {
5541                    old_versions.push((multibuffer.snapshot(cx), multibuffer.subscribe()));
5542                })
5543            }
5544
5545            let snapshot = multibuffer.read(cx).snapshot(cx);
5546
5547            let mut excerpt_starts = Vec::new();
5548            let mut expected_text = String::new();
5549            let mut expected_buffer_rows = Vec::new();
5550            for (buffer, range) in &expected_excerpts {
5551                let buffer = buffer.read(cx);
5552                let buffer_range = range.to_offset(buffer);
5553
5554                excerpt_starts.push(TextSummary::from(expected_text.as_str()));
5555                expected_text.extend(buffer.text_for_range(buffer_range.clone()));
5556                expected_text.push('\n');
5557
5558                let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
5559                    ..=buffer.offset_to_point(buffer_range.end).row;
5560                for row in buffer_row_range {
5561                    expected_buffer_rows.push(Some(row));
5562                }
5563            }
5564            // Remove final trailing newline.
5565            if !expected_excerpts.is_empty() {
5566                expected_text.pop();
5567            }
5568
5569            // Always report one buffer row
5570            if expected_buffer_rows.is_empty() {
5571                expected_buffer_rows.push(Some(0));
5572            }
5573
5574            assert_eq!(snapshot.text(), expected_text);
5575            log::info!("MultiBuffer text: {:?}", expected_text);
5576
5577            assert_eq!(
5578                snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
5579                expected_buffer_rows,
5580            );
5581
5582            for _ in 0..5 {
5583                let start_row = rng.gen_range(0..=expected_buffer_rows.len());
5584                assert_eq!(
5585                    snapshot
5586                        .buffer_rows(MultiBufferRow(start_row as u32))
5587                        .collect::<Vec<_>>(),
5588                    &expected_buffer_rows[start_row..],
5589                    "buffer_rows({})",
5590                    start_row
5591                );
5592            }
5593
5594            assert_eq!(
5595                snapshot.max_buffer_row().0,
5596                expected_buffer_rows.into_iter().flatten().max().unwrap()
5597            );
5598
5599            let mut excerpt_starts = excerpt_starts.into_iter();
5600            for (buffer, range) in &expected_excerpts {
5601                let buffer = buffer.read(cx);
5602                let buffer_id = buffer.remote_id();
5603                let buffer_range = range.to_offset(buffer);
5604                let buffer_start_point = buffer.offset_to_point(buffer_range.start);
5605                let buffer_start_point_utf16 =
5606                    buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
5607
5608                let excerpt_start = excerpt_starts.next().unwrap();
5609                let mut offset = excerpt_start.len;
5610                let mut buffer_offset = buffer_range.start;
5611                let mut point = excerpt_start.lines;
5612                let mut buffer_point = buffer_start_point;
5613                let mut point_utf16 = excerpt_start.lines_utf16();
5614                let mut buffer_point_utf16 = buffer_start_point_utf16;
5615                for ch in buffer
5616                    .snapshot()
5617                    .chunks(buffer_range.clone(), false)
5618                    .flat_map(|c| c.text.chars())
5619                {
5620                    for _ in 0..ch.len_utf8() {
5621                        let left_offset = snapshot.clip_offset(offset, Bias::Left);
5622                        let right_offset = snapshot.clip_offset(offset, Bias::Right);
5623                        let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
5624                        let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
5625                        assert_eq!(
5626                            left_offset,
5627                            excerpt_start.len + (buffer_left_offset - buffer_range.start),
5628                            "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
5629                            offset,
5630                            buffer_id,
5631                            buffer_offset,
5632                        );
5633                        assert_eq!(
5634                            right_offset,
5635                            excerpt_start.len + (buffer_right_offset - buffer_range.start),
5636                            "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
5637                            offset,
5638                            buffer_id,
5639                            buffer_offset,
5640                        );
5641
5642                        let left_point = snapshot.clip_point(point, Bias::Left);
5643                        let right_point = snapshot.clip_point(point, Bias::Right);
5644                        let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
5645                        let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
5646                        assert_eq!(
5647                            left_point,
5648                            excerpt_start.lines + (buffer_left_point - buffer_start_point),
5649                            "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
5650                            point,
5651                            buffer_id,
5652                            buffer_point,
5653                        );
5654                        assert_eq!(
5655                            right_point,
5656                            excerpt_start.lines + (buffer_right_point - buffer_start_point),
5657                            "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
5658                            point,
5659                            buffer_id,
5660                            buffer_point,
5661                        );
5662
5663                        assert_eq!(
5664                            snapshot.point_to_offset(left_point),
5665                            left_offset,
5666                            "point_to_offset({:?})",
5667                            left_point,
5668                        );
5669                        assert_eq!(
5670                            snapshot.offset_to_point(left_offset),
5671                            left_point,
5672                            "offset_to_point({:?})",
5673                            left_offset,
5674                        );
5675
5676                        offset += 1;
5677                        buffer_offset += 1;
5678                        if ch == '\n' {
5679                            point += Point::new(1, 0);
5680                            buffer_point += Point::new(1, 0);
5681                        } else {
5682                            point += Point::new(0, 1);
5683                            buffer_point += Point::new(0, 1);
5684                        }
5685                    }
5686
5687                    for _ in 0..ch.len_utf16() {
5688                        let left_point_utf16 =
5689                            snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Left);
5690                        let right_point_utf16 =
5691                            snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Right);
5692                        let buffer_left_point_utf16 =
5693                            buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Left);
5694                        let buffer_right_point_utf16 =
5695                            buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Right);
5696                        assert_eq!(
5697                            left_point_utf16,
5698                            excerpt_start.lines_utf16()
5699                                + (buffer_left_point_utf16 - buffer_start_point_utf16),
5700                            "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
5701                            point_utf16,
5702                            buffer_id,
5703                            buffer_point_utf16,
5704                        );
5705                        assert_eq!(
5706                            right_point_utf16,
5707                            excerpt_start.lines_utf16()
5708                                + (buffer_right_point_utf16 - buffer_start_point_utf16),
5709                            "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
5710                            point_utf16,
5711                            buffer_id,
5712                            buffer_point_utf16,
5713                        );
5714
5715                        if ch == '\n' {
5716                            point_utf16 += PointUtf16::new(1, 0);
5717                            buffer_point_utf16 += PointUtf16::new(1, 0);
5718                        } else {
5719                            point_utf16 += PointUtf16::new(0, 1);
5720                            buffer_point_utf16 += PointUtf16::new(0, 1);
5721                        }
5722                    }
5723                }
5724            }
5725
5726            for (row, line) in expected_text.split('\n').enumerate() {
5727                assert_eq!(
5728                    snapshot.line_len(MultiBufferRow(row as u32)),
5729                    line.len() as u32,
5730                    "line_len({}).",
5731                    row
5732                );
5733            }
5734
5735            let text_rope = Rope::from(expected_text.as_str());
5736            for _ in 0..10 {
5737                let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
5738                let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
5739
5740                let text_for_range = snapshot
5741                    .text_for_range(start_ix..end_ix)
5742                    .collect::<String>();
5743                assert_eq!(
5744                    text_for_range,
5745                    &expected_text[start_ix..end_ix],
5746                    "incorrect text for range {:?}",
5747                    start_ix..end_ix
5748                );
5749
5750                let excerpted_buffer_ranges = multibuffer
5751                    .read(cx)
5752                    .range_to_buffer_ranges(start_ix..end_ix, cx);
5753                let excerpted_buffers_text = excerpted_buffer_ranges
5754                    .iter()
5755                    .map(|(buffer, buffer_range, _)| {
5756                        buffer
5757                            .read(cx)
5758                            .text_for_range(buffer_range.clone())
5759                            .collect::<String>()
5760                    })
5761                    .collect::<Vec<_>>()
5762                    .join("\n");
5763                assert_eq!(excerpted_buffers_text, text_for_range);
5764                if !expected_excerpts.is_empty() {
5765                    assert!(!excerpted_buffer_ranges.is_empty());
5766                }
5767
5768                let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
5769                assert_eq!(
5770                    snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
5771                    expected_summary,
5772                    "incorrect summary for range {:?}",
5773                    start_ix..end_ix
5774                );
5775            }
5776
5777            // Anchor resolution
5778            let summaries = snapshot.summaries_for_anchors::<usize, _>(&anchors);
5779            assert_eq!(anchors.len(), summaries.len());
5780            for (anchor, resolved_offset) in anchors.iter().zip(summaries) {
5781                assert!(resolved_offset <= snapshot.len());
5782                assert_eq!(
5783                    snapshot.summary_for_anchor::<usize>(anchor),
5784                    resolved_offset
5785                );
5786            }
5787
5788            for _ in 0..10 {
5789                let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
5790                assert_eq!(
5791                    snapshot.reversed_chars_at(end_ix).collect::<String>(),
5792                    expected_text[..end_ix].chars().rev().collect::<String>(),
5793                );
5794            }
5795
5796            for _ in 0..10 {
5797                let end_ix = rng.gen_range(0..=text_rope.len());
5798                let start_ix = rng.gen_range(0..=end_ix);
5799                assert_eq!(
5800                    snapshot
5801                        .bytes_in_range(start_ix..end_ix)
5802                        .flatten()
5803                        .copied()
5804                        .collect::<Vec<_>>(),
5805                    expected_text.as_bytes()[start_ix..end_ix].to_vec(),
5806                    "bytes_in_range({:?})",
5807                    start_ix..end_ix,
5808                );
5809            }
5810        }
5811
5812        let snapshot = multibuffer.read(cx).snapshot(cx);
5813        for (old_snapshot, subscription) in old_versions {
5814            let edits = subscription.consume().into_inner();
5815
5816            log::info!(
5817                "applying subscription edits to old text: {:?}: {:?}",
5818                old_snapshot.text(),
5819                edits,
5820            );
5821
5822            let mut text = old_snapshot.text();
5823            for edit in edits {
5824                let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
5825                text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
5826            }
5827            assert_eq!(text.to_string(), snapshot.text());
5828        }
5829    }
5830
5831    #[gpui::test]
5832    fn test_history(cx: &mut AppContext) {
5833        let test_settings = SettingsStore::test(cx);
5834        cx.set_global(test_settings);
5835
5836        let buffer_1 = cx.new_model(|cx| Buffer::local("1234", cx));
5837        let buffer_2 = cx.new_model(|cx| Buffer::local("5678", cx));
5838        let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
5839        let group_interval = multibuffer.read(cx).history.group_interval;
5840        multibuffer.update(cx, |multibuffer, cx| {
5841            multibuffer.push_excerpts(
5842                buffer_1.clone(),
5843                [ExcerptRange {
5844                    context: 0..buffer_1.read(cx).len(),
5845                    primary: None,
5846                }],
5847                cx,
5848            );
5849            multibuffer.push_excerpts(
5850                buffer_2.clone(),
5851                [ExcerptRange {
5852                    context: 0..buffer_2.read(cx).len(),
5853                    primary: None,
5854                }],
5855                cx,
5856            );
5857        });
5858
5859        let mut now = Instant::now();
5860
5861        multibuffer.update(cx, |multibuffer, cx| {
5862            let transaction_1 = multibuffer.start_transaction_at(now, cx).unwrap();
5863            multibuffer.edit(
5864                [
5865                    (Point::new(0, 0)..Point::new(0, 0), "A"),
5866                    (Point::new(1, 0)..Point::new(1, 0), "A"),
5867                ],
5868                None,
5869                cx,
5870            );
5871            multibuffer.edit(
5872                [
5873                    (Point::new(0, 1)..Point::new(0, 1), "B"),
5874                    (Point::new(1, 1)..Point::new(1, 1), "B"),
5875                ],
5876                None,
5877                cx,
5878            );
5879            multibuffer.end_transaction_at(now, cx);
5880            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5881
5882            // Edit buffer 1 through the multibuffer
5883            now += 2 * group_interval;
5884            multibuffer.start_transaction_at(now, cx);
5885            multibuffer.edit([(2..2, "C")], None, cx);
5886            multibuffer.end_transaction_at(now, cx);
5887            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
5888
5889            // Edit buffer 1 independently
5890            buffer_1.update(cx, |buffer_1, cx| {
5891                buffer_1.start_transaction_at(now);
5892                buffer_1.edit([(3..3, "D")], None, cx);
5893                buffer_1.end_transaction_at(now, cx);
5894
5895                now += 2 * group_interval;
5896                buffer_1.start_transaction_at(now);
5897                buffer_1.edit([(4..4, "E")], None, cx);
5898                buffer_1.end_transaction_at(now, cx);
5899            });
5900            assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
5901
5902            // An undo in the multibuffer undoes the multibuffer transaction
5903            // and also any individual buffer edits that have occurred since
5904            // that transaction.
5905            multibuffer.undo(cx);
5906            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5907
5908            multibuffer.undo(cx);
5909            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5910
5911            multibuffer.redo(cx);
5912            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5913
5914            multibuffer.redo(cx);
5915            assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
5916
5917            // Undo buffer 2 independently.
5918            buffer_2.update(cx, |buffer_2, cx| buffer_2.undo(cx));
5919            assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\n5678");
5920
5921            // An undo in the multibuffer undoes the components of the
5922            // the last multibuffer transaction that are not already undone.
5923            multibuffer.undo(cx);
5924            assert_eq!(multibuffer.read(cx).text(), "AB1234\n5678");
5925
5926            multibuffer.undo(cx);
5927            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5928
5929            multibuffer.redo(cx);
5930            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
5931
5932            buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
5933            assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
5934
5935            // Redo stack gets cleared after an edit.
5936            now += 2 * group_interval;
5937            multibuffer.start_transaction_at(now, cx);
5938            multibuffer.edit([(0..0, "X")], None, cx);
5939            multibuffer.end_transaction_at(now, cx);
5940            assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5941            multibuffer.redo(cx);
5942            assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5943            multibuffer.undo(cx);
5944            assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
5945            multibuffer.undo(cx);
5946            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5947
5948            // Transactions can be grouped manually.
5949            multibuffer.redo(cx);
5950            multibuffer.redo(cx);
5951            assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5952            multibuffer.group_until_transaction(transaction_1, cx);
5953            multibuffer.undo(cx);
5954            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
5955            multibuffer.redo(cx);
5956            assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
5957        });
5958    }
5959}