multi_buffer.rs

   1mod anchor;
   2#[cfg(test)]
   3mod multi_buffer_tests;
   4mod position;
   5
   6pub use anchor::{Anchor, AnchorRangeExt, Offset};
   7pub use position::{TypedOffset, TypedPoint, TypedRow};
   8
   9use anyhow::{anyhow, Result};
  10use buffer_diff::{
  11    BufferDiff, BufferDiffEvent, BufferDiffSnapshot, DiffHunkSecondaryStatus, DiffHunkStatus,
  12};
  13use clock::ReplicaId;
  14use collections::{BTreeMap, Bound, HashMap, HashSet};
  15use futures::{channel::mpsc, SinkExt};
  16use gpui::{App, Context, Entity, EntityId, EventEmitter, Task};
  17use itertools::Itertools;
  18use language::{
  19    language_settings::{language_settings, IndentGuideSettings, LanguageSettings},
  20    AutoindentMode, Buffer, BufferChunks, BufferRow, BufferSnapshot, Capability, CharClassifier,
  21    CharKind, Chunk, CursorShape, DiagnosticEntry, DiskState, File, IndentSize, Language,
  22    LanguageScope, OffsetRangeExt, OffsetUtf16, Outline, OutlineItem, Point, PointUtf16, Selection,
  23    TextDimension, TextObject, ToOffset as _, ToPoint as _, TransactionId, TreeSitterOptions,
  24    Unclipped,
  25};
  26
  27use rope::DimensionPair;
  28use smallvec::SmallVec;
  29use smol::future::yield_now;
  30use std::{
  31    any::type_name,
  32    borrow::Cow,
  33    cell::{Ref, RefCell},
  34    cmp, fmt,
  35    future::Future,
  36    io,
  37    iter::{self, FromIterator},
  38    mem,
  39    ops::{Range, RangeBounds, Sub},
  40    path::Path,
  41    str,
  42    sync::Arc,
  43    time::{Duration, Instant},
  44};
  45use sum_tree::{Bias, Cursor, SumTree, TreeMap};
  46use text::{
  47    locator::Locator,
  48    subscription::{Subscription, Topic},
  49    BufferId, Edit, LineIndent, TextSummary,
  50};
  51use theme::SyntaxTheme;
  52use util::post_inc;
  53
  54#[cfg(any(test, feature = "test-support"))]
  55use gpui::AppContext as _;
  56
  57const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];
  58
  59#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
  60pub struct ExcerptId(usize);
  61
  62/// One or more [`Buffers`](Buffer) being edited in a single view.
  63///
  64/// See <https://zed.dev/features#multi-buffers>
  65pub struct MultiBuffer {
  66    /// A snapshot of the [`Excerpt`]s in the MultiBuffer.
  67    /// Use [`MultiBuffer::snapshot`] to get a up-to-date snapshot.
  68    snapshot: RefCell<MultiBufferSnapshot>,
  69    /// Contains the state of the buffers being edited
  70    buffers: RefCell<HashMap<BufferId, BufferState>>,
  71    // only used by consumers using `set_excerpts_for_buffer`
  72    buffers_by_path: BTreeMap<PathKey, Vec<ExcerptId>>,
  73    diffs: HashMap<BufferId, DiffState>,
  74    all_diff_hunks_expanded: bool,
  75    subscriptions: Topic,
  76    /// If true, the multi-buffer only contains a single [`Buffer`] and a single [`Excerpt`]
  77    singleton: bool,
  78    history: History,
  79    title: Option<String>,
  80    capability: Capability,
  81}
  82
  83#[derive(Clone, Debug, PartialEq, Eq)]
  84pub enum Event {
  85    ExcerptsAdded {
  86        buffer: Entity<Buffer>,
  87        predecessor: ExcerptId,
  88        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
  89    },
  90    ExcerptsRemoved {
  91        ids: Vec<ExcerptId>,
  92    },
  93    ExcerptsExpanded {
  94        ids: Vec<ExcerptId>,
  95    },
  96    ExcerptsEdited {
  97        ids: Vec<ExcerptId>,
  98    },
  99    DiffHunksToggled,
 100    Edited {
 101        singleton_buffer_edited: bool,
 102        edited_buffer: Option<Entity<Buffer>>,
 103    },
 104    TransactionUndone {
 105        transaction_id: TransactionId,
 106    },
 107    Reloaded,
 108    ReloadNeeded,
 109
 110    LanguageChanged(BufferId),
 111    CapabilityChanged,
 112    Reparsed(BufferId),
 113    Saved,
 114    FileHandleChanged,
 115    Closed,
 116    Discarded,
 117    DirtyChanged,
 118    DiagnosticsUpdated,
 119}
 120
 121/// A diff hunk, representing a range of consequent lines in a multibuffer.
 122#[derive(Debug, Clone, PartialEq, Eq)]
 123pub struct MultiBufferDiffHunk {
 124    /// The row range in the multibuffer where this diff hunk appears.
 125    pub row_range: Range<MultiBufferRow>,
 126    /// The buffer ID that this hunk belongs to.
 127    pub buffer_id: BufferId,
 128    /// The range of the underlying buffer that this hunk corresponds to.
 129    pub buffer_range: Range<text::Anchor>,
 130    /// The excerpt that contains the diff hunk.
 131    pub excerpt_id: ExcerptId,
 132    /// The range within the buffer's diff base that this hunk corresponds to.
 133    pub diff_base_byte_range: Range<usize>,
 134    /// Whether or not this hunk also appears in the 'secondary diff'.
 135    pub secondary_status: DiffHunkSecondaryStatus,
 136    pub secondary_diff_base_byte_range: Option<Range<usize>>,
 137}
 138
 139impl MultiBufferDiffHunk {
 140    pub fn status(&self) -> DiffHunkStatus {
 141        if self.buffer_range.start == self.buffer_range.end {
 142            DiffHunkStatus::Removed(self.secondary_status)
 143        } else if self.diff_base_byte_range.is_empty() {
 144            DiffHunkStatus::Added(self.secondary_status)
 145        } else {
 146            DiffHunkStatus::Modified(self.secondary_status)
 147        }
 148    }
 149}
 150
 151#[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Hash, Debug)]
 152pub struct PathKey(String);
 153
 154impl PathKey {
 155    pub fn namespaced(namespace: &str, path: &Path) -> Self {
 156        Self(format!("{}/{}", namespace, path.to_string_lossy()))
 157    }
 158}
 159
 160pub type MultiBufferPoint = Point;
 161type ExcerptOffset = TypedOffset<Excerpt>;
 162type ExcerptPoint = TypedPoint<Excerpt>;
 163
 164#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq, Hash, serde::Deserialize)]
 165#[serde(transparent)]
 166pub struct MultiBufferRow(pub u32);
 167
 168impl MultiBufferRow {
 169    pub const MIN: Self = Self(0);
 170    pub const MAX: Self = Self(u32::MAX);
 171}
 172
 173impl std::ops::Add<usize> for MultiBufferRow {
 174    type Output = Self;
 175
 176    fn add(self, rhs: usize) -> Self::Output {
 177        MultiBufferRow(self.0 + rhs as u32)
 178    }
 179}
 180
 181#[derive(Clone)]
 182struct History {
 183    next_transaction_id: TransactionId,
 184    undo_stack: Vec<Transaction>,
 185    redo_stack: Vec<Transaction>,
 186    transaction_depth: usize,
 187    group_interval: Duration,
 188}
 189
 190#[derive(Clone)]
 191struct Transaction {
 192    id: TransactionId,
 193    buffer_transactions: HashMap<BufferId, text::TransactionId>,
 194    first_edit_at: Instant,
 195    last_edit_at: Instant,
 196    suppress_grouping: bool,
 197}
 198
 199pub trait ToOffset: 'static + fmt::Debug {
 200    fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
 201}
 202
 203pub trait ToOffsetUtf16: 'static + fmt::Debug {
 204    fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16;
 205}
 206
 207pub trait ToPoint: 'static + fmt::Debug {
 208    fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point;
 209}
 210
 211pub trait ToPointUtf16: 'static + fmt::Debug {
 212    fn to_point_utf16(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16;
 213}
 214
 215struct BufferState {
 216    buffer: Entity<Buffer>,
 217    last_version: clock::Global,
 218    last_non_text_state_update_count: usize,
 219    excerpts: Vec<Locator>,
 220    _subscriptions: [gpui::Subscription; 2],
 221}
 222
 223struct DiffState {
 224    diff: Entity<BufferDiff>,
 225    _subscription: gpui::Subscription,
 226}
 227
 228impl DiffState {
 229    fn new(diff: Entity<BufferDiff>, cx: &mut Context<MultiBuffer>) -> Self {
 230        DiffState {
 231            _subscription: cx.subscribe(&diff, |this, diff, event, cx| match event {
 232                BufferDiffEvent::DiffChanged { changed_range } => {
 233                    let changed_range = if let Some(changed_range) = changed_range {
 234                        changed_range.clone()
 235                    } else if diff.read(cx).base_text().is_none() && this.all_diff_hunks_expanded {
 236                        text::Anchor::MIN..text::Anchor::MAX
 237                    } else {
 238                        return;
 239                    };
 240                    this.buffer_diff_changed(diff, changed_range, cx)
 241                }
 242                BufferDiffEvent::LanguageChanged => this.buffer_diff_language_changed(diff, cx),
 243            }),
 244            diff,
 245        }
 246    }
 247}
 248
 249/// The contents of a [`MultiBuffer`] at a single point in time.
 250#[derive(Clone, Default)]
 251pub struct MultiBufferSnapshot {
 252    singleton: bool,
 253    excerpts: SumTree<Excerpt>,
 254    excerpt_ids: SumTree<ExcerptIdMapping>,
 255    diffs: TreeMap<BufferId, BufferDiffSnapshot>,
 256    diff_transforms: SumTree<DiffTransform>,
 257    trailing_excerpt_update_count: usize,
 258    non_text_state_update_count: usize,
 259    edit_count: usize,
 260    is_dirty: bool,
 261    has_deleted_file: bool,
 262    has_conflict: bool,
 263    show_headers: bool,
 264}
 265
 266#[derive(Debug, Clone)]
 267enum DiffTransform {
 268    BufferContent {
 269        summary: TextSummary,
 270        inserted_hunk_info: Option<DiffTransformHunkInfo>,
 271    },
 272    DeletedHunk {
 273        summary: TextSummary,
 274        buffer_id: BufferId,
 275        hunk_info: DiffTransformHunkInfo,
 276        base_text_byte_range: Range<usize>,
 277        has_trailing_newline: bool,
 278    },
 279}
 280
 281#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 282struct DiffTransformHunkInfo {
 283    excerpt_id: ExcerptId,
 284    hunk_start_anchor: text::Anchor,
 285    hunk_secondary_status: DiffHunkSecondaryStatus,
 286}
 287
 288#[derive(Clone)]
 289pub struct ExcerptInfo {
 290    pub id: ExcerptId,
 291    pub buffer: BufferSnapshot,
 292    pub buffer_id: BufferId,
 293    pub range: ExcerptRange<text::Anchor>,
 294    pub end_row: MultiBufferRow,
 295}
 296
 297impl std::fmt::Debug for ExcerptInfo {
 298    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 299        f.debug_struct(type_name::<Self>())
 300            .field("id", &self.id)
 301            .field("buffer_id", &self.buffer_id)
 302            .field("path", &self.buffer.file().map(|f| f.path()))
 303            .field("range", &self.range)
 304            .finish()
 305    }
 306}
 307
 308/// A boundary between `Excerpt`s in a [`MultiBuffer`]
 309#[derive(Debug)]
 310pub struct ExcerptBoundary {
 311    pub prev: Option<ExcerptInfo>,
 312    pub next: Option<ExcerptInfo>,
 313    /// The row in the `MultiBuffer` where the boundary is located
 314    pub row: MultiBufferRow,
 315}
 316
 317impl ExcerptBoundary {
 318    pub fn starts_new_buffer(&self) -> bool {
 319        match (self.prev.as_ref(), self.next.as_ref()) {
 320            (None, _) => true,
 321            (Some(_), None) => false,
 322            (Some(prev), Some(next)) => prev.buffer_id != next.buffer_id,
 323        }
 324    }
 325}
 326
 327#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
 328pub struct RowInfo {
 329    pub buffer_id: Option<BufferId>,
 330    pub buffer_row: Option<u32>,
 331    pub multibuffer_row: Option<MultiBufferRow>,
 332    pub diff_status: Option<buffer_diff::DiffHunkStatus>,
 333}
 334
 335/// A slice into a [`Buffer`] that is being edited in a [`MultiBuffer`].
 336#[derive(Clone)]
 337struct Excerpt {
 338    /// The unique identifier for this excerpt
 339    id: ExcerptId,
 340    /// The location of the excerpt in the [`MultiBuffer`]
 341    locator: Locator,
 342    /// The buffer being excerpted
 343    buffer_id: BufferId,
 344    /// A snapshot of the buffer being excerpted
 345    buffer: BufferSnapshot,
 346    /// The range of the buffer to be shown in the excerpt
 347    range: ExcerptRange<text::Anchor>,
 348    /// The last row in the excerpted slice of the buffer
 349    max_buffer_row: BufferRow,
 350    /// A summary of the text in the excerpt
 351    text_summary: TextSummary,
 352    has_trailing_newline: bool,
 353}
 354
 355/// A public view into an `Excerpt` in a [`MultiBuffer`].
 356///
 357/// Contains methods for getting the [`Buffer`] of the excerpt,
 358/// as well as mapping offsets to/from buffer and multibuffer coordinates.
 359#[derive(Clone)]
 360pub struct MultiBufferExcerpt<'a> {
 361    excerpt: &'a Excerpt,
 362    diff_transforms:
 363        sum_tree::Cursor<'a, DiffTransform, (OutputDimension<usize>, ExcerptDimension<usize>)>,
 364    offset: usize,
 365    excerpt_offset: ExcerptDimension<usize>,
 366    buffer_offset: usize,
 367}
 368
 369#[derive(Clone, Debug)]
 370struct ExcerptIdMapping {
 371    id: ExcerptId,
 372    locator: Locator,
 373}
 374
 375/// A range of text from a single [`Buffer`], to be shown as an `Excerpt`.
 376/// These ranges are relative to the buffer itself
 377#[derive(Clone, Debug, Eq, PartialEq, Hash)]
 378pub struct ExcerptRange<T> {
 379    /// The full range of text to be shown in the excerpt.
 380    pub context: Range<T>,
 381    /// The primary range of text to be highlighted in the excerpt.
 382    /// In a multi-buffer search, this would be the text that matched the search
 383    pub primary: Option<Range<T>>,
 384}
 385
 386#[derive(Clone, Debug, Default)]
 387pub struct ExcerptSummary {
 388    excerpt_id: ExcerptId,
 389    /// The location of the last [`Excerpt`] being summarized
 390    excerpt_locator: Locator,
 391    widest_line_number: u32,
 392    text: TextSummary,
 393}
 394
 395#[derive(Debug, Clone)]
 396pub struct DiffTransformSummary {
 397    input: TextSummary,
 398    output: TextSummary,
 399}
 400
 401#[derive(Clone)]
 402pub struct MultiBufferRows<'a> {
 403    point: Point,
 404    is_empty: bool,
 405    cursor: MultiBufferCursor<'a, Point>,
 406}
 407
 408pub struct MultiBufferChunks<'a> {
 409    excerpts: Cursor<'a, Excerpt, ExcerptOffset>,
 410    diff_transforms: Cursor<'a, DiffTransform, (usize, ExcerptOffset)>,
 411    diffs: &'a TreeMap<BufferId, BufferDiffSnapshot>,
 412    diff_base_chunks: Option<(BufferId, BufferChunks<'a>)>,
 413    buffer_chunk: Option<Chunk<'a>>,
 414    range: Range<usize>,
 415    excerpt_offset_range: Range<ExcerptOffset>,
 416    excerpt_chunks: Option<ExcerptChunks<'a>>,
 417    language_aware: bool,
 418}
 419
 420pub struct ReversedMultiBufferChunks<'a> {
 421    cursor: MultiBufferCursor<'a, usize>,
 422    current_chunks: Option<rope::Chunks<'a>>,
 423    start: usize,
 424    offset: usize,
 425}
 426
 427pub struct MultiBufferBytes<'a> {
 428    range: Range<usize>,
 429    cursor: MultiBufferCursor<'a, usize>,
 430    excerpt_bytes: Option<text::Bytes<'a>>,
 431    has_trailing_newline: bool,
 432    chunk: &'a [u8],
 433}
 434
 435pub struct ReversedMultiBufferBytes<'a> {
 436    range: Range<usize>,
 437    chunks: ReversedMultiBufferChunks<'a>,
 438    chunk: &'a [u8],
 439}
 440
 441#[derive(Clone)]
 442struct MultiBufferCursor<'a, D: TextDimension> {
 443    excerpts: Cursor<'a, Excerpt, ExcerptDimension<D>>,
 444    diff_transforms: Cursor<'a, DiffTransform, (OutputDimension<D>, ExcerptDimension<D>)>,
 445    diffs: &'a TreeMap<BufferId, BufferDiffSnapshot>,
 446    cached_region: Option<MultiBufferRegion<'a, D>>,
 447}
 448
 449#[derive(Clone)]
 450struct MultiBufferRegion<'a, D: TextDimension> {
 451    buffer: &'a BufferSnapshot,
 452    is_main_buffer: bool,
 453    diff_hunk_status: Option<DiffHunkStatus>,
 454    excerpt: &'a Excerpt,
 455    buffer_range: Range<D>,
 456    range: Range<D>,
 457    has_trailing_newline: bool,
 458}
 459
 460struct ExcerptChunks<'a> {
 461    excerpt_id: ExcerptId,
 462    content_chunks: BufferChunks<'a>,
 463    footer_height: usize,
 464}
 465
 466#[derive(Debug)]
 467struct BufferEdit {
 468    range: Range<usize>,
 469    new_text: Arc<str>,
 470    is_insertion: bool,
 471    original_indent_column: u32,
 472    excerpt_id: ExcerptId,
 473}
 474
 475#[derive(Clone, Copy, Debug, PartialEq)]
 476enum DiffChangeKind {
 477    BufferEdited,
 478    DiffUpdated { base_changed: bool },
 479    ExpandOrCollapseHunks { expand: bool },
 480}
 481
 482#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 483pub enum ExpandExcerptDirection {
 484    Up,
 485    Down,
 486    UpAndDown,
 487}
 488
 489impl ExpandExcerptDirection {
 490    pub fn should_expand_up(&self) -> bool {
 491        match self {
 492            ExpandExcerptDirection::Up => true,
 493            ExpandExcerptDirection::Down => false,
 494            ExpandExcerptDirection::UpAndDown => true,
 495        }
 496    }
 497
 498    pub fn should_expand_down(&self) -> bool {
 499        match self {
 500            ExpandExcerptDirection::Up => false,
 501            ExpandExcerptDirection::Down => true,
 502            ExpandExcerptDirection::UpAndDown => true,
 503        }
 504    }
 505}
 506
 507#[derive(Clone, Debug, PartialEq)]
 508pub struct IndentGuide {
 509    pub buffer_id: BufferId,
 510    pub start_row: MultiBufferRow,
 511    pub end_row: MultiBufferRow,
 512    pub depth: u32,
 513    pub tab_size: u32,
 514    pub settings: IndentGuideSettings,
 515}
 516
 517impl IndentGuide {
 518    pub fn indent_level(&self) -> u32 {
 519        self.depth * self.tab_size
 520    }
 521}
 522
 523impl MultiBuffer {
 524    pub fn new(capability: Capability) -> Self {
 525        Self {
 526            snapshot: RefCell::new(MultiBufferSnapshot {
 527                show_headers: true,
 528                ..MultiBufferSnapshot::default()
 529            }),
 530            buffers: RefCell::default(),
 531            diffs: HashMap::default(),
 532            all_diff_hunks_expanded: false,
 533            subscriptions: Topic::default(),
 534            singleton: false,
 535            capability,
 536            title: None,
 537            buffers_by_path: Default::default(),
 538            history: History {
 539                next_transaction_id: clock::Lamport::default(),
 540                undo_stack: Vec::new(),
 541                redo_stack: Vec::new(),
 542                transaction_depth: 0,
 543                group_interval: Duration::from_millis(300),
 544            },
 545        }
 546    }
 547
 548    pub fn without_headers(capability: Capability) -> Self {
 549        Self {
 550            snapshot: Default::default(),
 551            buffers: Default::default(),
 552            buffers_by_path: Default::default(),
 553            diffs: HashMap::default(),
 554            all_diff_hunks_expanded: false,
 555            subscriptions: Default::default(),
 556            singleton: false,
 557            capability,
 558            history: History {
 559                next_transaction_id: Default::default(),
 560                undo_stack: Default::default(),
 561                redo_stack: Default::default(),
 562                transaction_depth: 0,
 563                group_interval: Duration::from_millis(300),
 564            },
 565            title: Default::default(),
 566        }
 567    }
 568
 569    pub fn clone(&self, new_cx: &mut Context<Self>) -> Self {
 570        let mut buffers = HashMap::default();
 571        for (buffer_id, buffer_state) in self.buffers.borrow().iter() {
 572            buffers.insert(
 573                *buffer_id,
 574                BufferState {
 575                    buffer: buffer_state.buffer.clone(),
 576                    last_version: buffer_state.last_version.clone(),
 577                    last_non_text_state_update_count: buffer_state.last_non_text_state_update_count,
 578                    excerpts: buffer_state.excerpts.clone(),
 579                    _subscriptions: [
 580                        new_cx.observe(&buffer_state.buffer, |_, _, cx| cx.notify()),
 581                        new_cx.subscribe(&buffer_state.buffer, Self::on_buffer_event),
 582                    ],
 583                },
 584            );
 585        }
 586        let mut diff_bases = HashMap::default();
 587        for (buffer_id, diff) in self.diffs.iter() {
 588            diff_bases.insert(*buffer_id, DiffState::new(diff.diff.clone(), new_cx));
 589        }
 590        Self {
 591            snapshot: RefCell::new(self.snapshot.borrow().clone()),
 592            buffers: RefCell::new(buffers),
 593            buffers_by_path: Default::default(),
 594            diffs: diff_bases,
 595            all_diff_hunks_expanded: self.all_diff_hunks_expanded,
 596            subscriptions: Default::default(),
 597            singleton: self.singleton,
 598            capability: self.capability,
 599            history: self.history.clone(),
 600            title: self.title.clone(),
 601        }
 602    }
 603
 604    pub fn with_title(mut self, title: String) -> Self {
 605        self.title = Some(title);
 606        self
 607    }
 608
 609    pub fn read_only(&self) -> bool {
 610        self.capability == Capability::ReadOnly
 611    }
 612
 613    pub fn singleton(buffer: Entity<Buffer>, cx: &mut Context<Self>) -> Self {
 614        let mut this = Self::new(buffer.read(cx).capability());
 615        this.singleton = true;
 616        this.push_excerpts(
 617            buffer,
 618            [ExcerptRange {
 619                context: text::Anchor::MIN..text::Anchor::MAX,
 620                primary: None,
 621            }],
 622            cx,
 623        );
 624        this.snapshot.borrow_mut().singleton = true;
 625        this
 626    }
 627
 628    /// Returns an up-to-date snapshot of the MultiBuffer.
 629    pub fn snapshot(&self, cx: &App) -> MultiBufferSnapshot {
 630        self.sync(cx);
 631        self.snapshot.borrow().clone()
 632    }
 633
 634    pub fn read(&self, cx: &App) -> Ref<MultiBufferSnapshot> {
 635        self.sync(cx);
 636        self.snapshot.borrow()
 637    }
 638
 639    pub fn as_singleton(&self) -> Option<Entity<Buffer>> {
 640        if self.singleton {
 641            return Some(
 642                self.buffers
 643                    .borrow()
 644                    .values()
 645                    .next()
 646                    .unwrap()
 647                    .buffer
 648                    .clone(),
 649            );
 650        } else {
 651            None
 652        }
 653    }
 654
 655    pub fn is_singleton(&self) -> bool {
 656        self.singleton
 657    }
 658
 659    pub fn subscribe(&mut self) -> Subscription {
 660        self.subscriptions.subscribe()
 661    }
 662
 663    pub fn is_dirty(&self, cx: &App) -> bool {
 664        self.read(cx).is_dirty()
 665    }
 666
 667    pub fn has_deleted_file(&self, cx: &App) -> bool {
 668        self.read(cx).has_deleted_file()
 669    }
 670
 671    pub fn has_conflict(&self, cx: &App) -> bool {
 672        self.read(cx).has_conflict()
 673    }
 674
 675    // The `is_empty` signature doesn't match what clippy expects
 676    #[allow(clippy::len_without_is_empty)]
 677    pub fn len(&self, cx: &App) -> usize {
 678        self.read(cx).len()
 679    }
 680
 681    pub fn is_empty(&self) -> bool {
 682        self.buffers.borrow().is_empty()
 683    }
 684
 685    pub fn symbols_containing<T: ToOffset>(
 686        &self,
 687        offset: T,
 688        theme: Option<&SyntaxTheme>,
 689        cx: &App,
 690    ) -> Option<(BufferId, Vec<OutlineItem<Anchor>>)> {
 691        self.read(cx).symbols_containing(offset, theme)
 692    }
 693
 694    pub fn edit<I, S, T>(
 695        &self,
 696        edits: I,
 697        autoindent_mode: Option<AutoindentMode>,
 698        cx: &mut Context<Self>,
 699    ) where
 700        I: IntoIterator<Item = (Range<S>, T)>,
 701        S: ToOffset,
 702        T: Into<Arc<str>>,
 703    {
 704        let snapshot = self.read(cx);
 705        let edits = edits
 706            .into_iter()
 707            .map(|(range, new_text)| {
 708                let mut range = range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot);
 709                if range.start > range.end {
 710                    mem::swap(&mut range.start, &mut range.end);
 711                }
 712                (range, new_text.into())
 713            })
 714            .collect::<Vec<_>>();
 715
 716        return edit_internal(self, snapshot, edits, autoindent_mode, cx);
 717
 718        // Non-generic part of edit, hoisted out to avoid blowing up LLVM IR.
 719        fn edit_internal(
 720            this: &MultiBuffer,
 721            snapshot: Ref<MultiBufferSnapshot>,
 722            edits: Vec<(Range<usize>, Arc<str>)>,
 723            mut autoindent_mode: Option<AutoindentMode>,
 724            cx: &mut Context<MultiBuffer>,
 725        ) {
 726            if this.read_only() || this.buffers.borrow().is_empty() {
 727                return;
 728            }
 729
 730            let original_indent_columns = match &mut autoindent_mode {
 731                Some(AutoindentMode::Block {
 732                    original_indent_columns,
 733                }) => mem::take(original_indent_columns),
 734                _ => Default::default(),
 735            };
 736
 737            let (buffer_edits, edited_excerpt_ids) =
 738                this.convert_edits_to_buffer_edits(edits, &snapshot, &original_indent_columns);
 739            drop(snapshot);
 740
 741            for (buffer_id, mut edits) in buffer_edits {
 742                edits.sort_by_key(|edit| edit.range.start);
 743                this.buffers.borrow()[&buffer_id]
 744                    .buffer
 745                    .update(cx, |buffer, cx| {
 746                        let mut edits = edits.into_iter().peekable();
 747                        let mut insertions = Vec::new();
 748                        let mut original_indent_columns = Vec::new();
 749                        let mut deletions = Vec::new();
 750                        let empty_str: Arc<str> = Arc::default();
 751                        while let Some(BufferEdit {
 752                            mut range,
 753                            mut new_text,
 754                            mut is_insertion,
 755                            original_indent_column,
 756                            excerpt_id,
 757                        }) = edits.next()
 758                        {
 759                            while let Some(BufferEdit {
 760                                range: next_range,
 761                                is_insertion: next_is_insertion,
 762                                new_text: next_new_text,
 763                                excerpt_id: next_excerpt_id,
 764                                ..
 765                            }) = edits.peek()
 766                            {
 767                                if range.end >= next_range.start {
 768                                    range.end = cmp::max(next_range.end, range.end);
 769                                    is_insertion |= *next_is_insertion;
 770                                    if excerpt_id == *next_excerpt_id {
 771                                        new_text = format!("{new_text}{next_new_text}").into();
 772                                    }
 773                                    edits.next();
 774                                } else {
 775                                    break;
 776                                }
 777                            }
 778
 779                            if is_insertion {
 780                                original_indent_columns.push(original_indent_column);
 781                                insertions.push((
 782                                    buffer.anchor_before(range.start)
 783                                        ..buffer.anchor_before(range.end),
 784                                    new_text.clone(),
 785                                ));
 786                            } else if !range.is_empty() {
 787                                deletions.push((
 788                                    buffer.anchor_before(range.start)
 789                                        ..buffer.anchor_before(range.end),
 790                                    empty_str.clone(),
 791                                ));
 792                            }
 793                        }
 794
 795                        let deletion_autoindent_mode =
 796                            if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
 797                                Some(AutoindentMode::Block {
 798                                    original_indent_columns: Default::default(),
 799                                })
 800                            } else {
 801                                autoindent_mode.clone()
 802                            };
 803                        let insertion_autoindent_mode =
 804                            if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
 805                                Some(AutoindentMode::Block {
 806                                    original_indent_columns,
 807                                })
 808                            } else {
 809                                autoindent_mode.clone()
 810                            };
 811
 812                        buffer.edit(deletions, deletion_autoindent_mode, cx);
 813                        buffer.edit(insertions, insertion_autoindent_mode, cx);
 814                    })
 815            }
 816
 817            cx.emit(Event::ExcerptsEdited {
 818                ids: edited_excerpt_ids,
 819            });
 820        }
 821    }
 822
 823    fn convert_edits_to_buffer_edits(
 824        &self,
 825        edits: Vec<(Range<usize>, Arc<str>)>,
 826        snapshot: &MultiBufferSnapshot,
 827        original_indent_columns: &[u32],
 828    ) -> (HashMap<BufferId, Vec<BufferEdit>>, Vec<ExcerptId>) {
 829        let mut buffer_edits: HashMap<BufferId, Vec<BufferEdit>> = Default::default();
 830        let mut edited_excerpt_ids = Vec::new();
 831        let mut cursor = snapshot.cursor::<usize>();
 832        for (ix, (range, new_text)) in edits.into_iter().enumerate() {
 833            let original_indent_column = original_indent_columns.get(ix).copied().unwrap_or(0);
 834
 835            cursor.seek(&range.start);
 836            let mut start_region = cursor.region().expect("start offset out of bounds");
 837            if !start_region.is_main_buffer {
 838                cursor.next();
 839                if let Some(region) = cursor.region() {
 840                    start_region = region;
 841                } else {
 842                    continue;
 843                }
 844            }
 845
 846            if range.end < start_region.range.start {
 847                continue;
 848            }
 849
 850            if range.end > start_region.range.end {
 851                cursor.seek_forward(&range.end);
 852            }
 853            let mut end_region = cursor.region().expect("end offset out of bounds");
 854            if !end_region.is_main_buffer {
 855                cursor.prev();
 856                if let Some(region) = cursor.region() {
 857                    end_region = region;
 858                } else {
 859                    continue;
 860                }
 861            }
 862
 863            if range.start > end_region.range.end {
 864                continue;
 865            }
 866
 867            let start_overshoot = range.start.saturating_sub(start_region.range.start);
 868            let end_overshoot = range.end.saturating_sub(end_region.range.start);
 869            let buffer_start = (start_region.buffer_range.start + start_overshoot)
 870                .min(start_region.buffer_range.end);
 871            let buffer_end =
 872                (end_region.buffer_range.start + end_overshoot).min(end_region.buffer_range.end);
 873
 874            if start_region.excerpt.id == end_region.excerpt.id {
 875                if start_region.is_main_buffer {
 876                    edited_excerpt_ids.push(start_region.excerpt.id);
 877                    buffer_edits
 878                        .entry(start_region.buffer.remote_id())
 879                        .or_default()
 880                        .push(BufferEdit {
 881                            range: buffer_start..buffer_end,
 882                            new_text,
 883                            is_insertion: true,
 884                            original_indent_column,
 885                            excerpt_id: start_region.excerpt.id,
 886                        });
 887                }
 888            } else {
 889                let start_excerpt_range = buffer_start..start_region.buffer_range.end;
 890                let end_excerpt_range = end_region.buffer_range.start..buffer_end;
 891                if start_region.is_main_buffer {
 892                    edited_excerpt_ids.push(start_region.excerpt.id);
 893                    buffer_edits
 894                        .entry(start_region.buffer.remote_id())
 895                        .or_default()
 896                        .push(BufferEdit {
 897                            range: start_excerpt_range,
 898                            new_text: new_text.clone(),
 899                            is_insertion: true,
 900                            original_indent_column,
 901                            excerpt_id: start_region.excerpt.id,
 902                        });
 903                }
 904                if end_region.is_main_buffer {
 905                    edited_excerpt_ids.push(end_region.excerpt.id);
 906                    buffer_edits
 907                        .entry(end_region.buffer.remote_id())
 908                        .or_default()
 909                        .push(BufferEdit {
 910                            range: end_excerpt_range,
 911                            new_text: new_text.clone(),
 912                            is_insertion: false,
 913                            original_indent_column,
 914                            excerpt_id: end_region.excerpt.id,
 915                        });
 916                }
 917
 918                cursor.seek(&range.start);
 919                cursor.next_excerpt();
 920                while let Some(region) = cursor.region() {
 921                    if region.excerpt.id == end_region.excerpt.id {
 922                        break;
 923                    }
 924                    if region.is_main_buffer {
 925                        edited_excerpt_ids.push(region.excerpt.id);
 926                        buffer_edits
 927                            .entry(region.buffer.remote_id())
 928                            .or_default()
 929                            .push(BufferEdit {
 930                                range: region.buffer_range,
 931                                new_text: new_text.clone(),
 932                                is_insertion: false,
 933                                original_indent_column,
 934                                excerpt_id: region.excerpt.id,
 935                            });
 936                    }
 937                    cursor.next_excerpt();
 938                }
 939            }
 940        }
 941        (buffer_edits, edited_excerpt_ids)
 942    }
 943
 944    pub fn autoindent_ranges<I, S>(&self, ranges: I, cx: &mut Context<Self>)
 945    where
 946        I: IntoIterator<Item = Range<S>>,
 947        S: ToOffset,
 948    {
 949        let snapshot = self.read(cx);
 950        let empty = Arc::<str>::from("");
 951        let edits = ranges
 952            .into_iter()
 953            .map(|range| {
 954                let mut range = range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot);
 955                if range.start > range.end {
 956                    mem::swap(&mut range.start, &mut range.end);
 957                }
 958                (range, empty.clone())
 959            })
 960            .collect::<Vec<_>>();
 961
 962        return autoindent_ranges_internal(self, snapshot, edits, cx);
 963
 964        fn autoindent_ranges_internal(
 965            this: &MultiBuffer,
 966            snapshot: Ref<MultiBufferSnapshot>,
 967            edits: Vec<(Range<usize>, Arc<str>)>,
 968            cx: &mut Context<MultiBuffer>,
 969        ) {
 970            if this.read_only() || this.buffers.borrow().is_empty() {
 971                return;
 972            }
 973
 974            let (buffer_edits, edited_excerpt_ids) =
 975                this.convert_edits_to_buffer_edits(edits, &snapshot, &[]);
 976            drop(snapshot);
 977
 978            for (buffer_id, mut edits) in buffer_edits {
 979                edits.sort_unstable_by_key(|edit| edit.range.start);
 980
 981                let mut ranges: Vec<Range<usize>> = Vec::new();
 982                for edit in edits {
 983                    if let Some(last_range) = ranges.last_mut() {
 984                        if edit.range.start <= last_range.end {
 985                            last_range.end = last_range.end.max(edit.range.end);
 986                            continue;
 987                        }
 988                    }
 989                    ranges.push(edit.range);
 990                }
 991
 992                this.buffers.borrow()[&buffer_id]
 993                    .buffer
 994                    .update(cx, |buffer, cx| {
 995                        buffer.autoindent_ranges(ranges, cx);
 996                    })
 997            }
 998
 999            cx.emit(Event::ExcerptsEdited {
1000                ids: edited_excerpt_ids,
1001            });
1002        }
1003    }
1004
1005    // Inserts newlines at the given position to create an empty line, returning the start of the new line.
1006    // You can also request the insertion of empty lines above and below the line starting at the returned point.
1007    // Panics if the given position is invalid.
1008    pub fn insert_empty_line(
1009        &mut self,
1010        position: impl ToPoint,
1011        space_above: bool,
1012        space_below: bool,
1013        cx: &mut Context<Self>,
1014    ) -> Point {
1015        let multibuffer_point = position.to_point(&self.read(cx));
1016        let (buffer, buffer_point, _) = self.point_to_buffer_point(multibuffer_point, cx).unwrap();
1017        self.start_transaction(cx);
1018        let empty_line_start = buffer.update(cx, |buffer, cx| {
1019            buffer.insert_empty_line(buffer_point, space_above, space_below, cx)
1020        });
1021        self.end_transaction(cx);
1022        multibuffer_point + (empty_line_start - buffer_point)
1023    }
1024
1025    pub fn start_transaction(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {
1026        self.start_transaction_at(Instant::now(), cx)
1027    }
1028
1029    pub fn start_transaction_at(
1030        &mut self,
1031        now: Instant,
1032        cx: &mut Context<Self>,
1033    ) -> Option<TransactionId> {
1034        if let Some(buffer) = self.as_singleton() {
1035            return buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
1036        }
1037
1038        for BufferState { buffer, .. } in self.buffers.borrow().values() {
1039            buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
1040        }
1041        self.history.start_transaction(now)
1042    }
1043
1044    pub fn end_transaction(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {
1045        self.end_transaction_at(Instant::now(), cx)
1046    }
1047
1048    pub fn end_transaction_at(
1049        &mut self,
1050        now: Instant,
1051        cx: &mut Context<Self>,
1052    ) -> Option<TransactionId> {
1053        if let Some(buffer) = self.as_singleton() {
1054            return buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx));
1055        }
1056
1057        let mut buffer_transactions = HashMap::default();
1058        for BufferState { buffer, .. } in self.buffers.borrow().values() {
1059            if let Some(transaction_id) =
1060                buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
1061            {
1062                buffer_transactions.insert(buffer.read(cx).remote_id(), transaction_id);
1063            }
1064        }
1065
1066        if self.history.end_transaction(now, buffer_transactions) {
1067            let transaction_id = self.history.group().unwrap();
1068            Some(transaction_id)
1069        } else {
1070            None
1071        }
1072    }
1073
1074    pub fn edited_ranges_for_transaction<D>(
1075        &self,
1076        transaction_id: TransactionId,
1077        cx: &App,
1078    ) -> Vec<Range<D>>
1079    where
1080        D: TextDimension + Ord + Sub<D, Output = D>,
1081    {
1082        let Some(transaction) = self.history.transaction(transaction_id) else {
1083            return Vec::new();
1084        };
1085
1086        let mut ranges = Vec::new();
1087        let snapshot = self.read(cx);
1088        let buffers = self.buffers.borrow();
1089        let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>(&());
1090
1091        for (buffer_id, buffer_transaction) in &transaction.buffer_transactions {
1092            let Some(buffer_state) = buffers.get(buffer_id) else {
1093                continue;
1094            };
1095
1096            let buffer = buffer_state.buffer.read(cx);
1097            for range in buffer.edited_ranges_for_transaction_id::<D>(*buffer_transaction) {
1098                for excerpt_id in &buffer_state.excerpts {
1099                    cursor.seek(excerpt_id, Bias::Left, &());
1100                    if let Some(excerpt) = cursor.item() {
1101                        if excerpt.locator == *excerpt_id {
1102                            let excerpt_buffer_start =
1103                                excerpt.range.context.start.summary::<D>(buffer);
1104                            let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(buffer);
1105                            let excerpt_range = excerpt_buffer_start..excerpt_buffer_end;
1106                            if excerpt_range.contains(&range.start)
1107                                && excerpt_range.contains(&range.end)
1108                            {
1109                                let excerpt_start = D::from_text_summary(&cursor.start().text);
1110
1111                                let mut start = excerpt_start;
1112                                start.add_assign(&(range.start - excerpt_buffer_start));
1113                                let mut end = excerpt_start;
1114                                end.add_assign(&(range.end - excerpt_buffer_start));
1115
1116                                ranges.push(start..end);
1117                                break;
1118                            }
1119                        }
1120                    }
1121                }
1122            }
1123        }
1124
1125        ranges.sort_by_key(|range| range.start);
1126        ranges
1127    }
1128
1129    pub fn merge_transactions(
1130        &mut self,
1131        transaction: TransactionId,
1132        destination: TransactionId,
1133        cx: &mut Context<Self>,
1134    ) {
1135        if let Some(buffer) = self.as_singleton() {
1136            buffer.update(cx, |buffer, _| {
1137                buffer.merge_transactions(transaction, destination)
1138            });
1139        } else if let Some(transaction) = self.history.forget(transaction) {
1140            if let Some(destination) = self.history.transaction_mut(destination) {
1141                for (buffer_id, buffer_transaction_id) in transaction.buffer_transactions {
1142                    if let Some(destination_buffer_transaction_id) =
1143                        destination.buffer_transactions.get(&buffer_id)
1144                    {
1145                        if let Some(state) = self.buffers.borrow().get(&buffer_id) {
1146                            state.buffer.update(cx, |buffer, _| {
1147                                buffer.merge_transactions(
1148                                    buffer_transaction_id,
1149                                    *destination_buffer_transaction_id,
1150                                )
1151                            });
1152                        }
1153                    } else {
1154                        destination
1155                            .buffer_transactions
1156                            .insert(buffer_id, buffer_transaction_id);
1157                    }
1158                }
1159            }
1160        }
1161    }
1162
1163    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
1164        self.history.finalize_last_transaction();
1165        for BufferState { buffer, .. } in self.buffers.borrow().values() {
1166            buffer.update(cx, |buffer, _| {
1167                buffer.finalize_last_transaction();
1168            });
1169        }
1170    }
1171
1172    pub fn push_transaction<'a, T>(&mut self, buffer_transactions: T, cx: &Context<Self>)
1173    where
1174        T: IntoIterator<Item = (&'a Entity<Buffer>, &'a language::Transaction)>,
1175    {
1176        self.history
1177            .push_transaction(buffer_transactions, Instant::now(), cx);
1178        self.history.finalize_last_transaction();
1179    }
1180
1181    pub fn group_until_transaction(
1182        &mut self,
1183        transaction_id: TransactionId,
1184        cx: &mut Context<Self>,
1185    ) {
1186        if let Some(buffer) = self.as_singleton() {
1187            buffer.update(cx, |buffer, _| {
1188                buffer.group_until_transaction(transaction_id)
1189            });
1190        } else {
1191            self.history.group_until(transaction_id);
1192        }
1193    }
1194
1195    pub fn set_active_selections(
1196        &self,
1197        selections: &[Selection<Anchor>],
1198        line_mode: bool,
1199        cursor_shape: CursorShape,
1200        cx: &mut Context<Self>,
1201    ) {
1202        let mut selections_by_buffer: HashMap<BufferId, Vec<Selection<text::Anchor>>> =
1203            Default::default();
1204        let snapshot = self.read(cx);
1205        let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>(&());
1206        for selection in selections {
1207            let start_locator = snapshot.excerpt_locator_for_id(selection.start.excerpt_id);
1208            let end_locator = snapshot.excerpt_locator_for_id(selection.end.excerpt_id);
1209
1210            cursor.seek(&Some(start_locator), Bias::Left, &());
1211            while let Some(excerpt) = cursor.item() {
1212                if excerpt.locator > *end_locator {
1213                    break;
1214                }
1215
1216                let mut start = excerpt.range.context.start;
1217                let mut end = excerpt.range.context.end;
1218                if excerpt.id == selection.start.excerpt_id {
1219                    start = selection.start.text_anchor;
1220                }
1221                if excerpt.id == selection.end.excerpt_id {
1222                    end = selection.end.text_anchor;
1223                }
1224                selections_by_buffer
1225                    .entry(excerpt.buffer_id)
1226                    .or_default()
1227                    .push(Selection {
1228                        id: selection.id,
1229                        start,
1230                        end,
1231                        reversed: selection.reversed,
1232                        goal: selection.goal,
1233                    });
1234
1235                cursor.next(&());
1236            }
1237        }
1238
1239        for (buffer_id, buffer_state) in self.buffers.borrow().iter() {
1240            if !selections_by_buffer.contains_key(buffer_id) {
1241                buffer_state
1242                    .buffer
1243                    .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
1244            }
1245        }
1246
1247        for (buffer_id, mut selections) in selections_by_buffer {
1248            self.buffers.borrow()[&buffer_id]
1249                .buffer
1250                .update(cx, |buffer, cx| {
1251                    selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer));
1252                    let mut selections = selections.into_iter().peekable();
1253                    let merged_selections = Arc::from_iter(iter::from_fn(|| {
1254                        let mut selection = selections.next()?;
1255                        while let Some(next_selection) = selections.peek() {
1256                            if selection.end.cmp(&next_selection.start, buffer).is_ge() {
1257                                let next_selection = selections.next().unwrap();
1258                                if next_selection.end.cmp(&selection.end, buffer).is_ge() {
1259                                    selection.end = next_selection.end;
1260                                }
1261                            } else {
1262                                break;
1263                            }
1264                        }
1265                        Some(selection)
1266                    }));
1267                    buffer.set_active_selections(merged_selections, line_mode, cursor_shape, cx);
1268                });
1269        }
1270    }
1271
1272    pub fn remove_active_selections(&self, cx: &mut Context<Self>) {
1273        for buffer in self.buffers.borrow().values() {
1274            buffer
1275                .buffer
1276                .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
1277        }
1278    }
1279
1280    pub fn undo(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {
1281        let mut transaction_id = None;
1282        if let Some(buffer) = self.as_singleton() {
1283            transaction_id = buffer.update(cx, |buffer, cx| buffer.undo(cx));
1284        } else {
1285            while let Some(transaction) = self.history.pop_undo() {
1286                let mut undone = false;
1287                for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions {
1288                    if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
1289                        undone |= buffer.update(cx, |buffer, cx| {
1290                            let undo_to = *buffer_transaction_id;
1291                            if let Some(entry) = buffer.peek_undo_stack() {
1292                                *buffer_transaction_id = entry.transaction_id();
1293                            }
1294                            buffer.undo_to_transaction(undo_to, cx)
1295                        });
1296                    }
1297                }
1298
1299                if undone {
1300                    transaction_id = Some(transaction.id);
1301                    break;
1302                }
1303            }
1304        }
1305
1306        if let Some(transaction_id) = transaction_id {
1307            cx.emit(Event::TransactionUndone { transaction_id });
1308        }
1309
1310        transaction_id
1311    }
1312
1313    pub fn redo(&mut self, cx: &mut Context<Self>) -> Option<TransactionId> {
1314        if let Some(buffer) = self.as_singleton() {
1315            return buffer.update(cx, |buffer, cx| buffer.redo(cx));
1316        }
1317
1318        while let Some(transaction) = self.history.pop_redo() {
1319            let mut redone = false;
1320            for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions {
1321                if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
1322                    redone |= buffer.update(cx, |buffer, cx| {
1323                        let redo_to = *buffer_transaction_id;
1324                        if let Some(entry) = buffer.peek_redo_stack() {
1325                            *buffer_transaction_id = entry.transaction_id();
1326                        }
1327                        buffer.redo_to_transaction(redo_to, cx)
1328                    });
1329                }
1330            }
1331
1332            if redone {
1333                return Some(transaction.id);
1334            }
1335        }
1336
1337        None
1338    }
1339
1340    pub fn undo_transaction(&mut self, transaction_id: TransactionId, cx: &mut Context<Self>) {
1341        if let Some(buffer) = self.as_singleton() {
1342            buffer.update(cx, |buffer, cx| buffer.undo_transaction(transaction_id, cx));
1343        } else if let Some(transaction) = self.history.remove_from_undo(transaction_id) {
1344            for (buffer_id, transaction_id) in &transaction.buffer_transactions {
1345                if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) {
1346                    buffer.update(cx, |buffer, cx| {
1347                        buffer.undo_transaction(*transaction_id, cx)
1348                    });
1349                }
1350            }
1351        }
1352    }
1353
1354    pub fn forget_transaction(&mut self, transaction_id: TransactionId, cx: &mut Context<Self>) {
1355        if let Some(buffer) = self.as_singleton() {
1356            buffer.update(cx, |buffer, _| {
1357                buffer.forget_transaction(transaction_id);
1358            });
1359        } else if let Some(transaction) = self.history.forget(transaction_id) {
1360            for (buffer_id, buffer_transaction_id) in transaction.buffer_transactions {
1361                if let Some(state) = self.buffers.borrow_mut().get_mut(&buffer_id) {
1362                    state.buffer.update(cx, |buffer, _| {
1363                        buffer.forget_transaction(buffer_transaction_id);
1364                    });
1365                }
1366            }
1367        }
1368    }
1369
1370    pub fn push_excerpts<O>(
1371        &mut self,
1372        buffer: Entity<Buffer>,
1373        ranges: impl IntoIterator<Item = ExcerptRange<O>>,
1374        cx: &mut Context<Self>,
1375    ) -> Vec<ExcerptId>
1376    where
1377        O: text::ToOffset,
1378    {
1379        self.insert_excerpts_after(ExcerptId::max(), buffer, ranges, cx)
1380    }
1381
1382    pub fn push_excerpts_with_context_lines<O>(
1383        &mut self,
1384        buffer: Entity<Buffer>,
1385        ranges: Vec<Range<O>>,
1386        context_line_count: u32,
1387        cx: &mut Context<Self>,
1388    ) -> Vec<Range<Anchor>>
1389    where
1390        O: text::ToPoint + text::ToOffset,
1391    {
1392        let buffer_id = buffer.read(cx).remote_id();
1393        let buffer_snapshot = buffer.read(cx).snapshot();
1394        let (excerpt_ranges, range_counts) =
1395            build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
1396
1397        let excerpt_ids = self.push_excerpts(buffer, excerpt_ranges, cx);
1398
1399        let mut anchor_ranges = Vec::new();
1400        let mut ranges = ranges.into_iter();
1401        for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.into_iter()) {
1402            anchor_ranges.extend(ranges.by_ref().take(range_count).map(|range| {
1403                let start = Anchor {
1404                    buffer_id: Some(buffer_id),
1405                    excerpt_id,
1406                    text_anchor: buffer_snapshot.anchor_after(range.start),
1407                    diff_base_anchor: None,
1408                };
1409                let end = Anchor {
1410                    buffer_id: Some(buffer_id),
1411                    excerpt_id,
1412                    text_anchor: buffer_snapshot.anchor_after(range.end),
1413                    diff_base_anchor: None,
1414                };
1415                start..end
1416            }))
1417        }
1418        anchor_ranges
1419    }
1420
1421    pub fn location_for_path(&self, path: &PathKey, cx: &App) -> Option<Anchor> {
1422        let excerpt_id = self.buffers_by_path.get(path)?.first()?;
1423        let snapshot = self.snapshot(cx);
1424        let excerpt = snapshot.excerpt(*excerpt_id)?;
1425        Some(Anchor::in_buffer(
1426            *excerpt_id,
1427            excerpt.buffer_id,
1428            excerpt.range.context.start,
1429        ))
1430    }
1431
1432    pub fn set_excerpts_for_path(
1433        &mut self,
1434        path: PathKey,
1435        buffer: Entity<Buffer>,
1436        ranges: Vec<Range<Point>>,
1437        context_line_count: u32,
1438        cx: &mut Context<Self>,
1439    ) {
1440        let buffer_snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
1441
1442        let mut insert_after = self
1443            .buffers_by_path
1444            .range(..path.clone())
1445            .next_back()
1446            .map(|(_, value)| *value.last().unwrap())
1447            .unwrap_or(ExcerptId::min());
1448        let existing = self.buffers_by_path.get(&path).cloned().unwrap_or_default();
1449
1450        let (new, _) = build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
1451
1452        let mut new_iter = new.into_iter().peekable();
1453        let mut existing_iter = existing.into_iter().peekable();
1454
1455        let mut new_excerpt_ids = Vec::new();
1456        let mut to_remove = Vec::new();
1457        let mut to_insert = Vec::new();
1458        let snapshot = self.snapshot(cx);
1459
1460        let mut excerpts_cursor = snapshot.excerpts.cursor::<Option<&Locator>>(&());
1461        excerpts_cursor.next(&());
1462
1463        loop {
1464            let (new, existing) = match (new_iter.peek(), existing_iter.peek()) {
1465                (Some(new), Some(existing)) => (new, existing),
1466                (None, None) => break,
1467                (None, Some(_)) => {
1468                    to_remove.push(existing_iter.next().unwrap());
1469                    continue;
1470                }
1471                (Some(_), None) => {
1472                    to_insert.push(new_iter.next().unwrap());
1473                    continue;
1474                }
1475            };
1476            let locator = snapshot.excerpt_locator_for_id(*existing);
1477            excerpts_cursor.seek_forward(&Some(locator), Bias::Left, &());
1478            let existing_excerpt = excerpts_cursor.item().unwrap();
1479            if existing_excerpt.buffer_id != buffer_snapshot.remote_id() {
1480                to_remove.push(existing_iter.next().unwrap());
1481                to_insert.push(new_iter.next().unwrap());
1482                continue;
1483            }
1484
1485            let existing_start = existing_excerpt
1486                .range
1487                .context
1488                .start
1489                .to_point(&buffer_snapshot);
1490            let existing_end = existing_excerpt
1491                .range
1492                .context
1493                .end
1494                .to_point(&buffer_snapshot);
1495
1496            if existing_end < new.context.start {
1497                to_remove.push(existing_iter.next().unwrap());
1498                continue;
1499            } else if existing_start > new.context.end {
1500                to_insert.push(new_iter.next().unwrap());
1501                continue;
1502            }
1503
1504            // maybe merge overlapping excerpts?
1505            // it's hard to distinguish between a manually expanded excerpt, and one that
1506            // got smaller because of a missing diff.
1507            if existing_start == new.context.start && existing_end == new.context.end {
1508                new_excerpt_ids.append(&mut self.insert_excerpts_after(
1509                    insert_after,
1510                    buffer.clone(),
1511                    mem::take(&mut to_insert),
1512                    cx,
1513                ));
1514                insert_after = existing_iter.next().unwrap();
1515                new_excerpt_ids.push(insert_after);
1516                new_iter.next();
1517            } else {
1518                to_remove.push(existing_iter.next().unwrap());
1519                to_insert.push(new_iter.next().unwrap());
1520            }
1521        }
1522
1523        new_excerpt_ids.append(&mut self.insert_excerpts_after(
1524            insert_after,
1525            buffer,
1526            to_insert,
1527            cx,
1528        ));
1529        self.remove_excerpts(to_remove, cx);
1530        if new_excerpt_ids.is_empty() {
1531            self.buffers_by_path.remove(&path);
1532        } else {
1533            self.buffers_by_path.insert(path, new_excerpt_ids);
1534        }
1535    }
1536
1537    pub fn paths(&self) -> impl Iterator<Item = PathKey> + '_ {
1538        self.buffers_by_path.keys().cloned()
1539    }
1540
1541    pub fn remove_excerpts_for_path(&mut self, path: PathKey, cx: &mut Context<Self>) {
1542        if let Some(to_remove) = self.buffers_by_path.remove(&path) {
1543            self.remove_excerpts(to_remove, cx)
1544        }
1545    }
1546
1547    pub fn push_multiple_excerpts_with_context_lines(
1548        &self,
1549        buffers_with_ranges: Vec<(Entity<Buffer>, Vec<Range<text::Anchor>>)>,
1550        context_line_count: u32,
1551        cx: &mut Context<Self>,
1552    ) -> Task<Vec<Range<Anchor>>> {
1553        use futures::StreamExt;
1554
1555        let (excerpt_ranges_tx, mut excerpt_ranges_rx) = mpsc::channel(256);
1556
1557        let mut buffer_ids = Vec::with_capacity(buffers_with_ranges.len());
1558
1559        for (buffer, ranges) in buffers_with_ranges {
1560            let (buffer_id, buffer_snapshot) =
1561                buffer.update(cx, |buffer, _| (buffer.remote_id(), buffer.snapshot()));
1562
1563            buffer_ids.push(buffer_id);
1564
1565            cx.background_executor()
1566                .spawn({
1567                    let mut excerpt_ranges_tx = excerpt_ranges_tx.clone();
1568
1569                    async move {
1570                        let (excerpt_ranges, counts) =
1571                            build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
1572                        excerpt_ranges_tx
1573                            .send((buffer_id, buffer.clone(), ranges, excerpt_ranges, counts))
1574                            .await
1575                            .ok();
1576                    }
1577                })
1578                .detach()
1579        }
1580
1581        cx.spawn(move |this, mut cx| async move {
1582            let mut results_by_buffer_id = HashMap::default();
1583            while let Some((buffer_id, buffer, ranges, excerpt_ranges, range_counts)) =
1584                excerpt_ranges_rx.next().await
1585            {
1586                results_by_buffer_id
1587                    .insert(buffer_id, (buffer, ranges, excerpt_ranges, range_counts));
1588            }
1589
1590            let mut multi_buffer_ranges = Vec::default();
1591            'outer: for buffer_id in buffer_ids {
1592                let Some((buffer, ranges, excerpt_ranges, range_counts)) =
1593                    results_by_buffer_id.remove(&buffer_id)
1594                else {
1595                    continue;
1596                };
1597
1598                let mut ranges = ranges.into_iter();
1599                let mut range_counts = range_counts.into_iter();
1600                for excerpt_ranges in excerpt_ranges.chunks(100) {
1601                    let excerpt_ids = match this.update(&mut cx, |this, cx| {
1602                        this.push_excerpts(buffer.clone(), excerpt_ranges.iter().cloned(), cx)
1603                    }) {
1604                        Ok(excerpt_ids) => excerpt_ids,
1605                        Err(_) => continue 'outer,
1606                    };
1607
1608                    for (excerpt_id, range_count) in
1609                        excerpt_ids.into_iter().zip(range_counts.by_ref())
1610                    {
1611                        for range in ranges.by_ref().take(range_count) {
1612                            let start = Anchor {
1613                                buffer_id: Some(buffer_id),
1614                                excerpt_id,
1615                                text_anchor: range.start,
1616                                diff_base_anchor: None,
1617                            };
1618                            let end = Anchor {
1619                                buffer_id: Some(buffer_id),
1620                                excerpt_id,
1621                                text_anchor: range.end,
1622                                diff_base_anchor: None,
1623                            };
1624                            multi_buffer_ranges.push(start..end);
1625                        }
1626                    }
1627                }
1628            }
1629
1630            multi_buffer_ranges
1631        })
1632    }
1633
1634    pub fn insert_excerpts_after<O>(
1635        &mut self,
1636        prev_excerpt_id: ExcerptId,
1637        buffer: Entity<Buffer>,
1638        ranges: impl IntoIterator<Item = ExcerptRange<O>>,
1639        cx: &mut Context<Self>,
1640    ) -> Vec<ExcerptId>
1641    where
1642        O: text::ToOffset,
1643    {
1644        let mut ids = Vec::new();
1645        let mut next_excerpt_id =
1646            if let Some(last_entry) = self.snapshot.borrow().excerpt_ids.last() {
1647                last_entry.id.0 + 1
1648            } else {
1649                1
1650            };
1651        self.insert_excerpts_with_ids_after(
1652            prev_excerpt_id,
1653            buffer,
1654            ranges.into_iter().map(|range| {
1655                let id = ExcerptId(post_inc(&mut next_excerpt_id));
1656                ids.push(id);
1657                (id, range)
1658            }),
1659            cx,
1660        );
1661        ids
1662    }
1663
1664    pub fn insert_excerpts_with_ids_after<O>(
1665        &mut self,
1666        prev_excerpt_id: ExcerptId,
1667        buffer: Entity<Buffer>,
1668        ranges: impl IntoIterator<Item = (ExcerptId, ExcerptRange<O>)>,
1669        cx: &mut Context<Self>,
1670    ) where
1671        O: text::ToOffset,
1672    {
1673        assert_eq!(self.history.transaction_depth, 0);
1674        let mut ranges = ranges.into_iter().peekable();
1675        if ranges.peek().is_none() {
1676            return Default::default();
1677        }
1678
1679        self.sync(cx);
1680
1681        let buffer_id = buffer.read(cx).remote_id();
1682        let buffer_snapshot = buffer.read(cx).snapshot();
1683
1684        let mut buffers = self.buffers.borrow_mut();
1685        let buffer_state = buffers.entry(buffer_id).or_insert_with(|| BufferState {
1686            last_version: buffer_snapshot.version().clone(),
1687            last_non_text_state_update_count: buffer_snapshot.non_text_state_update_count(),
1688            excerpts: Default::default(),
1689            _subscriptions: [
1690                cx.observe(&buffer, |_, _, cx| cx.notify()),
1691                cx.subscribe(&buffer, Self::on_buffer_event),
1692            ],
1693            buffer: buffer.clone(),
1694        });
1695
1696        let mut snapshot = self.snapshot.borrow_mut();
1697
1698        let mut prev_locator = snapshot.excerpt_locator_for_id(prev_excerpt_id).clone();
1699        let mut new_excerpt_ids = mem::take(&mut snapshot.excerpt_ids);
1700        let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>(&());
1701        let mut new_excerpts = cursor.slice(&prev_locator, Bias::Right, &());
1702        prev_locator = cursor.start().unwrap_or(Locator::min_ref()).clone();
1703
1704        let edit_start = ExcerptOffset::new(new_excerpts.summary().text.len);
1705        new_excerpts.update_last(
1706            |excerpt| {
1707                excerpt.has_trailing_newline = true;
1708            },
1709            &(),
1710        );
1711
1712        let next_locator = if let Some(excerpt) = cursor.item() {
1713            excerpt.locator.clone()
1714        } else {
1715            Locator::max()
1716        };
1717
1718        let mut excerpts = Vec::new();
1719        while let Some((id, range)) = ranges.next() {
1720            let locator = Locator::between(&prev_locator, &next_locator);
1721            if let Err(ix) = buffer_state.excerpts.binary_search(&locator) {
1722                buffer_state.excerpts.insert(ix, locator.clone());
1723            }
1724            let range = ExcerptRange {
1725                context: buffer_snapshot.anchor_before(&range.context.start)
1726                    ..buffer_snapshot.anchor_after(&range.context.end),
1727                primary: range.primary.map(|primary| {
1728                    buffer_snapshot.anchor_before(&primary.start)
1729                        ..buffer_snapshot.anchor_after(&primary.end)
1730                }),
1731            };
1732            excerpts.push((id, range.clone()));
1733            let excerpt = Excerpt::new(
1734                id,
1735                locator.clone(),
1736                buffer_id,
1737                buffer_snapshot.clone(),
1738                range,
1739                ranges.peek().is_some() || cursor.item().is_some(),
1740            );
1741            new_excerpts.push(excerpt, &());
1742            prev_locator = locator.clone();
1743
1744            if let Some(last_mapping_entry) = new_excerpt_ids.last() {
1745                assert!(id > last_mapping_entry.id, "excerpt ids must be increasing");
1746            }
1747            new_excerpt_ids.push(ExcerptIdMapping { id, locator }, &());
1748        }
1749
1750        let edit_end = ExcerptOffset::new(new_excerpts.summary().text.len);
1751
1752        let suffix = cursor.suffix(&());
1753        let changed_trailing_excerpt = suffix.is_empty();
1754        new_excerpts.append(suffix, &());
1755        drop(cursor);
1756        snapshot.excerpts = new_excerpts;
1757        snapshot.excerpt_ids = new_excerpt_ids;
1758        if changed_trailing_excerpt {
1759            snapshot.trailing_excerpt_update_count += 1;
1760        }
1761
1762        self.sync_diff_transforms(
1763            &mut snapshot,
1764            vec![Edit {
1765                old: edit_start..edit_start,
1766                new: edit_start..edit_end,
1767            }],
1768            DiffChangeKind::BufferEdited,
1769        );
1770        cx.emit(Event::Edited {
1771            singleton_buffer_edited: false,
1772            edited_buffer: None,
1773        });
1774        cx.emit(Event::ExcerptsAdded {
1775            buffer,
1776            predecessor: prev_excerpt_id,
1777            excerpts,
1778        });
1779        cx.notify();
1780    }
1781
1782    pub fn clear(&mut self, cx: &mut Context<Self>) {
1783        self.sync(cx);
1784        let ids = self.excerpt_ids();
1785        self.buffers.borrow_mut().clear();
1786        let mut snapshot = self.snapshot.borrow_mut();
1787        let start = ExcerptOffset::new(0);
1788        let prev_len = ExcerptOffset::new(snapshot.excerpts.summary().text.len);
1789        snapshot.excerpts = Default::default();
1790        snapshot.trailing_excerpt_update_count += 1;
1791        snapshot.is_dirty = false;
1792        snapshot.has_deleted_file = false;
1793        snapshot.has_conflict = false;
1794
1795        self.sync_diff_transforms(
1796            &mut snapshot,
1797            vec![Edit {
1798                old: start..prev_len,
1799                new: start..start,
1800            }],
1801            DiffChangeKind::BufferEdited,
1802        );
1803        cx.emit(Event::Edited {
1804            singleton_buffer_edited: false,
1805            edited_buffer: None,
1806        });
1807        cx.emit(Event::ExcerptsRemoved { ids });
1808        cx.notify();
1809    }
1810
1811    pub fn excerpts_for_buffer(
1812        &self,
1813        buffer_id: BufferId,
1814        cx: &App,
1815    ) -> Vec<(ExcerptId, ExcerptRange<text::Anchor>)> {
1816        let mut excerpts = Vec::new();
1817        let snapshot = self.read(cx);
1818        let buffers = self.buffers.borrow();
1819        let mut cursor = snapshot.excerpts.cursor::<Option<&Locator>>(&());
1820        for locator in buffers
1821            .get(&buffer_id)
1822            .map(|state| &state.excerpts)
1823            .into_iter()
1824            .flatten()
1825        {
1826            cursor.seek_forward(&Some(locator), Bias::Left, &());
1827            if let Some(excerpt) = cursor.item() {
1828                if excerpt.locator == *locator {
1829                    excerpts.push((excerpt.id, excerpt.range.clone()));
1830                }
1831            }
1832        }
1833
1834        excerpts
1835    }
1836
1837    pub fn excerpt_ranges_for_buffer(&self, buffer_id: BufferId, cx: &App) -> Vec<Range<Point>> {
1838        let snapshot = self.read(cx);
1839        let buffers = self.buffers.borrow();
1840        let mut excerpts = snapshot
1841            .excerpts
1842            .cursor::<(Option<&Locator>, ExcerptDimension<Point>)>(&());
1843        let mut diff_transforms = snapshot
1844            .diff_transforms
1845            .cursor::<(ExcerptDimension<Point>, OutputDimension<Point>)>(&());
1846        diff_transforms.next(&());
1847        let locators = buffers
1848            .get(&buffer_id)
1849            .into_iter()
1850            .flat_map(|state| &state.excerpts);
1851        let mut result = Vec::new();
1852        for locator in locators {
1853            excerpts.seek_forward(&Some(locator), Bias::Left, &());
1854            if let Some(excerpt) = excerpts.item() {
1855                if excerpt.locator == *locator {
1856                    let excerpt_start = excerpts.start().1.clone();
1857                    let excerpt_end =
1858                        ExcerptDimension(excerpt_start.0 + excerpt.text_summary.lines);
1859
1860                    diff_transforms.seek_forward(&excerpt_start, Bias::Left, &());
1861                    let overshoot = excerpt_start.0 - diff_transforms.start().0 .0;
1862                    let start = diff_transforms.start().1 .0 + overshoot;
1863
1864                    diff_transforms.seek_forward(&excerpt_end, Bias::Right, &());
1865                    let overshoot = excerpt_end.0 - diff_transforms.start().0 .0;
1866                    let end = diff_transforms.start().1 .0 + overshoot;
1867
1868                    result.push(start..end)
1869                }
1870            }
1871        }
1872        result
1873    }
1874
1875    pub fn excerpt_buffer_ids(&self) -> Vec<BufferId> {
1876        self.snapshot
1877            .borrow()
1878            .excerpts
1879            .iter()
1880            .map(|entry| entry.buffer_id)
1881            .collect()
1882    }
1883
1884    pub fn excerpt_ids(&self) -> Vec<ExcerptId> {
1885        self.snapshot
1886            .borrow()
1887            .excerpts
1888            .iter()
1889            .map(|entry| entry.id)
1890            .collect()
1891    }
1892
1893    pub fn excerpt_containing(
1894        &self,
1895        position: impl ToOffset,
1896        cx: &App,
1897    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
1898        let snapshot = self.read(cx);
1899        let offset = position.to_offset(&snapshot);
1900
1901        let mut cursor = snapshot.cursor::<usize>();
1902        cursor.seek(&offset);
1903        cursor
1904            .excerpt()
1905            .or_else(|| snapshot.excerpts.last())
1906            .map(|excerpt| {
1907                (
1908                    excerpt.id,
1909                    self.buffers
1910                        .borrow()
1911                        .get(&excerpt.buffer_id)
1912                        .unwrap()
1913                        .buffer
1914                        .clone(),
1915                    excerpt.range.context.clone(),
1916                )
1917            })
1918    }
1919
1920    // If point is at the end of the buffer, the last excerpt is returned
1921    pub fn point_to_buffer_offset<T: ToOffset>(
1922        &self,
1923        point: T,
1924        cx: &App,
1925    ) -> Option<(Entity<Buffer>, usize)> {
1926        let snapshot = self.read(cx);
1927        let (buffer, offset) = snapshot.point_to_buffer_offset(point)?;
1928        Some((
1929            self.buffers
1930                .borrow()
1931                .get(&buffer.remote_id())?
1932                .buffer
1933                .clone(),
1934            offset,
1935        ))
1936    }
1937
1938    // If point is at the end of the buffer, the last excerpt is returned
1939    pub fn point_to_buffer_point<T: ToPoint>(
1940        &self,
1941        point: T,
1942        cx: &App,
1943    ) -> Option<(Entity<Buffer>, Point, ExcerptId)> {
1944        let snapshot = self.read(cx);
1945        let point = point.to_point(&snapshot);
1946        let mut cursor = snapshot.cursor::<Point>();
1947        cursor.seek(&point);
1948
1949        cursor.region().and_then(|region| {
1950            if !region.is_main_buffer {
1951                return None;
1952            }
1953
1954            let overshoot = point - region.range.start;
1955            let buffer_point = region.buffer_range.start + overshoot;
1956            let buffer = self.buffers.borrow()[&region.buffer.remote_id()]
1957                .buffer
1958                .clone();
1959            Some((buffer, buffer_point, region.excerpt.id))
1960        })
1961    }
1962
1963    pub fn buffer_point_to_anchor(
1964        &self,
1965        buffer: &Entity<Buffer>,
1966        point: Point,
1967        cx: &App,
1968    ) -> Option<Anchor> {
1969        let mut found = None;
1970        let snapshot = buffer.read(cx).snapshot();
1971        for (excerpt_id, range) in self.excerpts_for_buffer(snapshot.remote_id(), cx) {
1972            let start = range.context.start.to_point(&snapshot);
1973            let end = range.context.end.to_point(&snapshot);
1974            if start <= point && point < end {
1975                found = Some((snapshot.clip_point(point, Bias::Left), excerpt_id));
1976                break;
1977            }
1978            if point < start {
1979                found = Some((start, excerpt_id));
1980            }
1981            if point > end {
1982                found = Some((end, excerpt_id));
1983            }
1984        }
1985
1986        found.map(|(point, excerpt_id)| {
1987            let text_anchor = snapshot.anchor_after(point);
1988            Anchor::in_buffer(excerpt_id, snapshot.remote_id(), text_anchor)
1989        })
1990    }
1991
1992    pub fn remove_excerpts(
1993        &mut self,
1994        excerpt_ids: impl IntoIterator<Item = ExcerptId>,
1995        cx: &mut Context<Self>,
1996    ) {
1997        self.sync(cx);
1998        let ids = excerpt_ids.into_iter().collect::<Vec<_>>();
1999        if ids.is_empty() {
2000            return;
2001        }
2002
2003        let mut buffers = self.buffers.borrow_mut();
2004        let mut snapshot = self.snapshot.borrow_mut();
2005        let mut new_excerpts = SumTree::default();
2006        let mut cursor = snapshot
2007            .excerpts
2008            .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
2009        let mut edits = Vec::new();
2010        let mut excerpt_ids = ids.iter().copied().peekable();
2011
2012        while let Some(excerpt_id) = excerpt_ids.next() {
2013            // Seek to the next excerpt to remove, preserving any preceding excerpts.
2014            let locator = snapshot.excerpt_locator_for_id(excerpt_id);
2015            new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &());
2016
2017            if let Some(mut excerpt) = cursor.item() {
2018                if excerpt.id != excerpt_id {
2019                    continue;
2020                }
2021                let mut old_start = cursor.start().1;
2022
2023                // Skip over the removed excerpt.
2024                'remove_excerpts: loop {
2025                    if let Some(buffer_state) = buffers.get_mut(&excerpt.buffer_id) {
2026                        buffer_state.excerpts.retain(|l| l != &excerpt.locator);
2027                        if buffer_state.excerpts.is_empty() {
2028                            buffers.remove(&excerpt.buffer_id);
2029                        }
2030                    }
2031                    cursor.next(&());
2032
2033                    // Skip over any subsequent excerpts that are also removed.
2034                    if let Some(&next_excerpt_id) = excerpt_ids.peek() {
2035                        let next_locator = snapshot.excerpt_locator_for_id(next_excerpt_id);
2036                        if let Some(next_excerpt) = cursor.item() {
2037                            if next_excerpt.locator == *next_locator {
2038                                excerpt_ids.next();
2039                                excerpt = next_excerpt;
2040                                continue 'remove_excerpts;
2041                            }
2042                        }
2043                    }
2044
2045                    break;
2046                }
2047
2048                // When removing the last excerpt, remove the trailing newline from
2049                // the previous excerpt.
2050                if cursor.item().is_none() && old_start.value > 0 {
2051                    old_start.value -= 1;
2052                    new_excerpts.update_last(|e| e.has_trailing_newline = false, &());
2053                }
2054
2055                // Push an edit for the removal of this run of excerpts.
2056                let old_end = cursor.start().1;
2057                let new_start = ExcerptOffset::new(new_excerpts.summary().text.len);
2058                edits.push(Edit {
2059                    old: old_start..old_end,
2060                    new: new_start..new_start,
2061                });
2062            }
2063        }
2064        let suffix = cursor.suffix(&());
2065        let changed_trailing_excerpt = suffix.is_empty();
2066        new_excerpts.append(suffix, &());
2067        drop(cursor);
2068        snapshot.excerpts = new_excerpts;
2069
2070        if changed_trailing_excerpt {
2071            snapshot.trailing_excerpt_update_count += 1;
2072        }
2073
2074        self.sync_diff_transforms(&mut snapshot, edits, DiffChangeKind::BufferEdited);
2075        cx.emit(Event::Edited {
2076            singleton_buffer_edited: false,
2077            edited_buffer: None,
2078        });
2079        cx.emit(Event::ExcerptsRemoved { ids });
2080        cx.notify();
2081    }
2082
2083    pub fn wait_for_anchors<'a>(
2084        &self,
2085        anchors: impl 'a + Iterator<Item = Anchor>,
2086        cx: &mut Context<Self>,
2087    ) -> impl 'static + Future<Output = Result<()>> {
2088        let borrow = self.buffers.borrow();
2089        let mut error = None;
2090        let mut futures = Vec::new();
2091        for anchor in anchors {
2092            if let Some(buffer_id) = anchor.buffer_id {
2093                if let Some(buffer) = borrow.get(&buffer_id) {
2094                    buffer.buffer.update(cx, |buffer, _| {
2095                        futures.push(buffer.wait_for_anchors([anchor.text_anchor]))
2096                    });
2097                } else {
2098                    error = Some(anyhow!(
2099                        "buffer {buffer_id} is not part of this multi-buffer"
2100                    ));
2101                    break;
2102                }
2103            }
2104        }
2105        async move {
2106            if let Some(error) = error {
2107                Err(error)?;
2108            }
2109            for future in futures {
2110                future.await?;
2111            }
2112            Ok(())
2113        }
2114    }
2115
2116    pub fn text_anchor_for_position<T: ToOffset>(
2117        &self,
2118        position: T,
2119        cx: &App,
2120    ) -> Option<(Entity<Buffer>, language::Anchor)> {
2121        let snapshot = self.read(cx);
2122        let anchor = snapshot.anchor_before(position);
2123        let buffer = self
2124            .buffers
2125            .borrow()
2126            .get(&anchor.buffer_id?)?
2127            .buffer
2128            .clone();
2129        Some((buffer, anchor.text_anchor))
2130    }
2131
2132    fn on_buffer_event(
2133        &mut self,
2134        buffer: Entity<Buffer>,
2135        event: &language::BufferEvent,
2136        cx: &mut Context<Self>,
2137    ) {
2138        cx.emit(match event {
2139            language::BufferEvent::Edited => Event::Edited {
2140                singleton_buffer_edited: true,
2141                edited_buffer: Some(buffer.clone()),
2142            },
2143            language::BufferEvent::DirtyChanged => Event::DirtyChanged,
2144            language::BufferEvent::Saved => Event::Saved,
2145            language::BufferEvent::FileHandleChanged => Event::FileHandleChanged,
2146            language::BufferEvent::Reloaded => Event::Reloaded,
2147            language::BufferEvent::ReloadNeeded => Event::ReloadNeeded,
2148            language::BufferEvent::LanguageChanged => {
2149                Event::LanguageChanged(buffer.read(cx).remote_id())
2150            }
2151            language::BufferEvent::Reparsed => Event::Reparsed(buffer.read(cx).remote_id()),
2152            language::BufferEvent::DiagnosticsUpdated => Event::DiagnosticsUpdated,
2153            language::BufferEvent::Closed => Event::Closed,
2154            language::BufferEvent::Discarded => Event::Discarded,
2155            language::BufferEvent::CapabilityChanged => {
2156                self.capability = buffer.read(cx).capability();
2157                Event::CapabilityChanged
2158            }
2159            language::BufferEvent::Operation { .. } => return,
2160        });
2161    }
2162
2163    fn buffer_diff_language_changed(&mut self, diff: Entity<BufferDiff>, cx: &mut Context<Self>) {
2164        self.sync(cx);
2165        let mut snapshot = self.snapshot.borrow_mut();
2166        let diff = diff.read(cx);
2167        let buffer_id = diff.buffer_id;
2168        let diff = diff.snapshot(cx);
2169        snapshot.diffs.insert(buffer_id, diff);
2170    }
2171
2172    fn buffer_diff_changed(
2173        &mut self,
2174        diff: Entity<BufferDiff>,
2175        range: Range<text::Anchor>,
2176        cx: &mut Context<Self>,
2177    ) {
2178        self.sync(cx);
2179
2180        let diff = diff.read(cx);
2181        let buffer_id = diff.buffer_id;
2182        let buffers = self.buffers.borrow();
2183        let Some(buffer_state) = buffers.get(&buffer_id) else {
2184            return;
2185        };
2186
2187        let buffer = buffer_state.buffer.read(cx);
2188        let diff_change_range = range.to_offset(buffer);
2189
2190        let mut new_diff = diff.snapshot(cx);
2191        if new_diff.base_text().is_none() && self.all_diff_hunks_expanded {
2192            let secondary_diff_insertion = new_diff
2193                .secondary_diff()
2194                .map_or(true, |secondary_diff| secondary_diff.base_text().is_none());
2195            new_diff = BufferDiff::build_with_single_insertion(
2196                secondary_diff_insertion,
2197                buffer.snapshot(),
2198                cx,
2199            );
2200        }
2201
2202        let mut snapshot = self.snapshot.borrow_mut();
2203        let base_text_changed = snapshot
2204            .diffs
2205            .get(&buffer_id)
2206            .map_or(true, |old_diff| !new_diff.base_texts_eq(old_diff));
2207
2208        snapshot.diffs.insert(buffer_id, new_diff);
2209
2210        let mut excerpt_edits = Vec::new();
2211        for locator in &buffer_state.excerpts {
2212            let mut cursor = snapshot
2213                .excerpts
2214                .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
2215            cursor.seek_forward(&Some(locator), Bias::Left, &());
2216            if let Some(excerpt) = cursor.item() {
2217                if excerpt.locator == *locator {
2218                    let excerpt_buffer_range = excerpt.range.context.to_offset(&excerpt.buffer);
2219                    if diff_change_range.end < excerpt_buffer_range.start
2220                        || diff_change_range.start > excerpt_buffer_range.end
2221                    {
2222                        continue;
2223                    }
2224                    let excerpt_start = cursor.start().1;
2225                    let excerpt_len = ExcerptOffset::new(excerpt.text_summary.len);
2226                    let diff_change_start_in_excerpt = ExcerptOffset::new(
2227                        diff_change_range
2228                            .start
2229                            .saturating_sub(excerpt_buffer_range.start),
2230                    );
2231                    let diff_change_end_in_excerpt = ExcerptOffset::new(
2232                        diff_change_range
2233                            .end
2234                            .saturating_sub(excerpt_buffer_range.start),
2235                    );
2236                    let edit_start = excerpt_start + diff_change_start_in_excerpt.min(excerpt_len);
2237                    let edit_end = excerpt_start + diff_change_end_in_excerpt.min(excerpt_len);
2238                    excerpt_edits.push(Edit {
2239                        old: edit_start..edit_end,
2240                        new: edit_start..edit_end,
2241                    });
2242                }
2243            }
2244        }
2245
2246        self.sync_diff_transforms(
2247            &mut snapshot,
2248            excerpt_edits,
2249            DiffChangeKind::DiffUpdated {
2250                base_changed: base_text_changed,
2251            },
2252        );
2253        cx.emit(Event::Edited {
2254            singleton_buffer_edited: false,
2255            edited_buffer: None,
2256        });
2257    }
2258
2259    pub fn all_buffers(&self) -> HashSet<Entity<Buffer>> {
2260        self.buffers
2261            .borrow()
2262            .values()
2263            .map(|state| state.buffer.clone())
2264            .collect()
2265    }
2266
2267    pub fn buffer(&self, buffer_id: BufferId) -> Option<Entity<Buffer>> {
2268        self.buffers
2269            .borrow()
2270            .get(&buffer_id)
2271            .map(|state| state.buffer.clone())
2272    }
2273
2274    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
2275        self.point_to_buffer_offset(point, cx)
2276            .and_then(|(buffer, offset)| buffer.read(cx).language_at(offset))
2277    }
2278
2279    pub fn settings_at<'a, T: ToOffset>(&self, point: T, cx: &'a App) -> Cow<'a, LanguageSettings> {
2280        let mut language = None;
2281        let mut file = None;
2282        if let Some((buffer, offset)) = self.point_to_buffer_offset(point, cx) {
2283            let buffer = buffer.read(cx);
2284            language = buffer.language_at(offset);
2285            file = buffer.file();
2286        }
2287        language_settings(language.map(|l| l.name()), file, cx)
2288    }
2289
2290    pub fn for_each_buffer(&self, mut f: impl FnMut(&Entity<Buffer>)) {
2291        self.buffers
2292            .borrow()
2293            .values()
2294            .for_each(|state| f(&state.buffer))
2295    }
2296
2297    pub fn title<'a>(&'a self, cx: &'a App) -> Cow<'a, str> {
2298        if let Some(title) = self.title.as_ref() {
2299            return title.into();
2300        }
2301
2302        if let Some(buffer) = self.as_singleton() {
2303            if let Some(file) = buffer.read(cx).file() {
2304                return file.file_name(cx).to_string_lossy();
2305            }
2306        }
2307
2308        "untitled".into()
2309    }
2310
2311    pub fn set_title(&mut self, title: String, cx: &mut Context<Self>) {
2312        self.title = Some(title);
2313        cx.notify();
2314    }
2315
2316    /// Preserve preview tabs containing this multibuffer until additional edits occur.
2317    pub fn refresh_preview(&self, cx: &mut Context<Self>) {
2318        for buffer_state in self.buffers.borrow().values() {
2319            buffer_state
2320                .buffer
2321                .update(cx, |buffer, _cx| buffer.refresh_preview());
2322        }
2323    }
2324
2325    /// Whether we should preserve the preview status of a tab containing this multi-buffer.
2326    pub fn preserve_preview(&self, cx: &App) -> bool {
2327        self.buffers
2328            .borrow()
2329            .values()
2330            .all(|state| state.buffer.read(cx).preserve_preview())
2331    }
2332
2333    #[cfg(any(test, feature = "test-support"))]
2334    pub fn is_parsing(&self, cx: &App) -> bool {
2335        self.as_singleton().unwrap().read(cx).is_parsing()
2336    }
2337
2338    pub fn add_diff(&mut self, diff: Entity<BufferDiff>, cx: &mut Context<Self>) {
2339        let buffer_id = diff.read(cx).buffer_id;
2340        self.buffer_diff_changed(diff.clone(), text::Anchor::MIN..text::Anchor::MAX, cx);
2341        self.diffs.insert(buffer_id, DiffState::new(diff, cx));
2342    }
2343
2344    pub fn diff_for(&self, buffer_id: BufferId) -> Option<Entity<BufferDiff>> {
2345        self.diffs.get(&buffer_id).map(|state| state.diff.clone())
2346    }
2347
2348    pub fn expand_diff_hunks(&mut self, ranges: Vec<Range<Anchor>>, cx: &mut Context<Self>) {
2349        self.expand_or_collapse_diff_hunks(ranges, true, cx);
2350    }
2351
2352    pub fn collapse_diff_hunks(&mut self, ranges: Vec<Range<Anchor>>, cx: &mut Context<Self>) {
2353        self.expand_or_collapse_diff_hunks(ranges, false, cx);
2354    }
2355
2356    pub fn set_all_diff_hunks_expanded(&mut self, cx: &mut Context<Self>) {
2357        self.all_diff_hunks_expanded = true;
2358        self.expand_or_collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], true, cx);
2359    }
2360
2361    pub fn all_diff_hunks_expanded(&mut self) -> bool {
2362        self.all_diff_hunks_expanded
2363    }
2364
2365    pub fn has_multiple_hunks(&self, cx: &App) -> bool {
2366        self.read(cx)
2367            .diff_hunks_in_range(Anchor::min()..Anchor::max())
2368            .nth(1)
2369            .is_some()
2370    }
2371
2372    pub fn has_expanded_diff_hunks_in_ranges(&self, ranges: &[Range<Anchor>], cx: &App) -> bool {
2373        let snapshot = self.read(cx);
2374        let mut cursor = snapshot.diff_transforms.cursor::<usize>(&());
2375        for range in ranges {
2376            let range = range.to_point(&snapshot);
2377            let start = snapshot.point_to_offset(Point::new(range.start.row, 0));
2378            let end = snapshot.point_to_offset(Point::new(range.end.row + 1, 0));
2379            let start = start.saturating_sub(1);
2380            let end = snapshot.len().min(end + 1);
2381            cursor.seek(&start, Bias::Right, &());
2382            while let Some(item) = cursor.item() {
2383                if *cursor.start() >= end {
2384                    break;
2385                }
2386                if item.hunk_info().is_some() {
2387                    return true;
2388                }
2389                cursor.next(&());
2390            }
2391        }
2392        false
2393    }
2394
2395    fn expand_or_collapse_diff_hunks_internal(
2396        &mut self,
2397        ranges: impl Iterator<Item = (Range<Point>, ExcerptId)>,
2398        expand: bool,
2399        cx: &mut Context<Self>,
2400    ) {
2401        self.sync(cx);
2402        let mut snapshot = self.snapshot.borrow_mut();
2403        let mut excerpt_edits = Vec::new();
2404        for (range, end_excerpt_id) in ranges {
2405            for diff_hunk in snapshot.diff_hunks_in_range(range) {
2406                if diff_hunk.excerpt_id.cmp(&end_excerpt_id, &snapshot).is_gt() {
2407                    continue;
2408                }
2409                let start = Anchor::in_buffer(
2410                    diff_hunk.excerpt_id,
2411                    diff_hunk.buffer_id,
2412                    diff_hunk.buffer_range.start,
2413                );
2414                let end = Anchor::in_buffer(
2415                    diff_hunk.excerpt_id,
2416                    diff_hunk.buffer_id,
2417                    diff_hunk.buffer_range.end,
2418                );
2419                let start = snapshot.excerpt_offset_for_anchor(&start);
2420                let end = snapshot.excerpt_offset_for_anchor(&end);
2421                excerpt_edits.push(text::Edit {
2422                    old: start..end,
2423                    new: start..end,
2424                });
2425            }
2426        }
2427
2428        self.sync_diff_transforms(
2429            &mut snapshot,
2430            excerpt_edits,
2431            DiffChangeKind::ExpandOrCollapseHunks { expand },
2432        );
2433        cx.emit(Event::DiffHunksToggled);
2434        cx.emit(Event::Edited {
2435            singleton_buffer_edited: false,
2436            edited_buffer: None,
2437        });
2438    }
2439
2440    pub fn expand_or_collapse_diff_hunks_narrow(
2441        &mut self,
2442        ranges: Vec<Range<Anchor>>,
2443        expand: bool,
2444        cx: &mut Context<Self>,
2445    ) {
2446        let snapshot = self.snapshot.borrow().clone();
2447        self.expand_or_collapse_diff_hunks_internal(
2448            ranges
2449                .iter()
2450                .map(move |range| (range.to_point(&snapshot), range.end.excerpt_id)),
2451            expand,
2452            cx,
2453        );
2454    }
2455
2456    pub fn expand_or_collapse_diff_hunks(
2457        &mut self,
2458        ranges: Vec<Range<Anchor>>,
2459        expand: bool,
2460        cx: &mut Context<Self>,
2461    ) {
2462        let snapshot = self.snapshot.borrow().clone();
2463        self.expand_or_collapse_diff_hunks_internal(
2464            ranges.iter().map(move |range| {
2465                let end_excerpt_id = range.end.excerpt_id;
2466                let range = range.to_point(&snapshot);
2467                let mut peek_end = range.end;
2468                if range.end.row < snapshot.max_row().0 {
2469                    peek_end = Point::new(range.end.row + 1, 0);
2470                };
2471                (range.start..peek_end, end_excerpt_id)
2472            }),
2473            expand,
2474            cx,
2475        );
2476    }
2477
2478    pub fn resize_excerpt(
2479        &mut self,
2480        id: ExcerptId,
2481        range: Range<text::Anchor>,
2482        cx: &mut Context<Self>,
2483    ) {
2484        self.sync(cx);
2485
2486        let mut snapshot = self.snapshot.borrow_mut();
2487        let locator = snapshot.excerpt_locator_for_id(id);
2488        let mut new_excerpts = SumTree::default();
2489        let mut cursor = snapshot
2490            .excerpts
2491            .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
2492        let mut edits = Vec::<Edit<ExcerptOffset>>::new();
2493
2494        let prefix = cursor.slice(&Some(locator), Bias::Left, &());
2495        new_excerpts.append(prefix, &());
2496
2497        let mut excerpt = cursor.item().unwrap().clone();
2498        let old_text_len = ExcerptOffset::new(excerpt.text_summary.len);
2499
2500        excerpt.range.context.start = range.start;
2501        excerpt.range.context.end = range.end;
2502        excerpt.max_buffer_row = range.end.to_point(&excerpt.buffer).row;
2503
2504        excerpt.text_summary = excerpt
2505            .buffer
2506            .text_summary_for_range(excerpt.range.context.clone());
2507
2508        let new_start_offset = ExcerptOffset::new(new_excerpts.summary().text.len);
2509        let old_start_offset = cursor.start().1;
2510        let new_text_len = ExcerptOffset::new(excerpt.text_summary.len);
2511        let edit = Edit {
2512            old: old_start_offset..old_start_offset + old_text_len,
2513            new: new_start_offset..new_start_offset + new_text_len,
2514        };
2515
2516        if let Some(last_edit) = edits.last_mut() {
2517            if last_edit.old.end == edit.old.start {
2518                last_edit.old.end = edit.old.end;
2519                last_edit.new.end = edit.new.end;
2520            } else {
2521                edits.push(edit);
2522            }
2523        } else {
2524            edits.push(edit);
2525        }
2526
2527        new_excerpts.push(excerpt, &());
2528
2529        cursor.next(&());
2530
2531        new_excerpts.append(cursor.suffix(&()), &());
2532
2533        drop(cursor);
2534        snapshot.excerpts = new_excerpts;
2535
2536        self.sync_diff_transforms(&mut snapshot, edits, DiffChangeKind::BufferEdited);
2537        cx.emit(Event::Edited {
2538            singleton_buffer_edited: false,
2539            edited_buffer: None,
2540        });
2541        cx.emit(Event::ExcerptsExpanded { ids: vec![id] });
2542        cx.notify();
2543    }
2544
2545    pub fn expand_excerpts(
2546        &mut self,
2547        ids: impl IntoIterator<Item = ExcerptId>,
2548        line_count: u32,
2549        direction: ExpandExcerptDirection,
2550        cx: &mut Context<Self>,
2551    ) {
2552        if line_count == 0 {
2553            return;
2554        }
2555        self.sync(cx);
2556        let mut snapshot = self.snapshot.borrow_mut();
2557
2558        let ids = ids.into_iter().collect::<Vec<_>>();
2559        let locators = snapshot.excerpt_locators_for_ids(ids.iter().copied());
2560        let mut new_excerpts = SumTree::default();
2561        let mut cursor = snapshot
2562            .excerpts
2563            .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
2564        let mut edits = Vec::<Edit<ExcerptOffset>>::new();
2565
2566        for locator in &locators {
2567            let prefix = cursor.slice(&Some(locator), Bias::Left, &());
2568            new_excerpts.append(prefix, &());
2569
2570            let mut excerpt = cursor.item().unwrap().clone();
2571            let old_text_len = ExcerptOffset::new(excerpt.text_summary.len);
2572
2573            let up_line_count = if direction.should_expand_up() {
2574                line_count
2575            } else {
2576                0
2577            };
2578
2579            let start_row = excerpt
2580                .range
2581                .context
2582                .start
2583                .to_point(&excerpt.buffer)
2584                .row
2585                .saturating_sub(up_line_count);
2586            let start_point = Point::new(start_row, 0);
2587            excerpt.range.context.start = excerpt.buffer.anchor_before(start_point);
2588
2589            let down_line_count = if direction.should_expand_down() {
2590                line_count
2591            } else {
2592                0
2593            };
2594
2595            let mut end_point = excerpt.buffer.clip_point(
2596                excerpt.range.context.end.to_point(&excerpt.buffer)
2597                    + Point::new(down_line_count, 0),
2598                Bias::Left,
2599            );
2600            end_point.column = excerpt.buffer.line_len(end_point.row);
2601            excerpt.range.context.end = excerpt.buffer.anchor_after(end_point);
2602            excerpt.max_buffer_row = end_point.row;
2603
2604            excerpt.text_summary = excerpt
2605                .buffer
2606                .text_summary_for_range(excerpt.range.context.clone());
2607
2608            let new_start_offset = ExcerptOffset::new(new_excerpts.summary().text.len);
2609            let old_start_offset = cursor.start().1;
2610            let new_text_len = ExcerptOffset::new(excerpt.text_summary.len);
2611            let edit = Edit {
2612                old: old_start_offset..old_start_offset + old_text_len,
2613                new: new_start_offset..new_start_offset + new_text_len,
2614            };
2615
2616            if let Some(last_edit) = edits.last_mut() {
2617                if last_edit.old.end == edit.old.start {
2618                    last_edit.old.end = edit.old.end;
2619                    last_edit.new.end = edit.new.end;
2620                } else {
2621                    edits.push(edit);
2622                }
2623            } else {
2624                edits.push(edit);
2625            }
2626
2627            new_excerpts.push(excerpt, &());
2628
2629            cursor.next(&());
2630        }
2631
2632        new_excerpts.append(cursor.suffix(&()), &());
2633
2634        drop(cursor);
2635        snapshot.excerpts = new_excerpts;
2636
2637        self.sync_diff_transforms(&mut snapshot, edits, DiffChangeKind::BufferEdited);
2638        cx.emit(Event::Edited {
2639            singleton_buffer_edited: false,
2640            edited_buffer: None,
2641        });
2642        cx.emit(Event::ExcerptsExpanded { ids });
2643        cx.notify();
2644    }
2645
2646    fn sync(&self, cx: &App) {
2647        let mut snapshot = self.snapshot.borrow_mut();
2648        let mut excerpts_to_edit = Vec::new();
2649        let mut non_text_state_updated = false;
2650        let mut is_dirty = false;
2651        let mut has_deleted_file = false;
2652        let mut has_conflict = false;
2653        let mut edited = false;
2654        let mut buffers = self.buffers.borrow_mut();
2655        for buffer_state in buffers.values_mut() {
2656            let buffer = buffer_state.buffer.read(cx);
2657            let version = buffer.version();
2658            let non_text_state_update_count = buffer.non_text_state_update_count();
2659
2660            let buffer_edited = version.changed_since(&buffer_state.last_version);
2661            let buffer_non_text_state_updated =
2662                non_text_state_update_count > buffer_state.last_non_text_state_update_count;
2663            if buffer_edited || buffer_non_text_state_updated {
2664                buffer_state.last_version = version;
2665                buffer_state.last_non_text_state_update_count = non_text_state_update_count;
2666                excerpts_to_edit.extend(
2667                    buffer_state
2668                        .excerpts
2669                        .iter()
2670                        .map(|locator| (locator, buffer_state.buffer.clone(), buffer_edited)),
2671                );
2672            }
2673
2674            edited |= buffer_edited;
2675            non_text_state_updated |= buffer_non_text_state_updated;
2676            is_dirty |= buffer.is_dirty();
2677            has_deleted_file |= buffer
2678                .file()
2679                .map_or(false, |file| file.disk_state() == DiskState::Deleted);
2680            has_conflict |= buffer.has_conflict();
2681        }
2682        if edited {
2683            snapshot.edit_count += 1;
2684        }
2685        if non_text_state_updated {
2686            snapshot.non_text_state_update_count += 1;
2687        }
2688        snapshot.is_dirty = is_dirty;
2689        snapshot.has_deleted_file = has_deleted_file;
2690        snapshot.has_conflict = has_conflict;
2691
2692        excerpts_to_edit.sort_unstable_by_key(|(locator, _, _)| *locator);
2693
2694        let mut edits = Vec::new();
2695        let mut new_excerpts = SumTree::default();
2696        let mut cursor = snapshot
2697            .excerpts
2698            .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
2699
2700        for (locator, buffer, buffer_edited) in excerpts_to_edit {
2701            new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &());
2702            let old_excerpt = cursor.item().unwrap();
2703            let buffer = buffer.read(cx);
2704            let buffer_id = buffer.remote_id();
2705
2706            let mut new_excerpt;
2707            if buffer_edited {
2708                edits.extend(
2709                    buffer
2710                        .edits_since_in_range::<usize>(
2711                            old_excerpt.buffer.version(),
2712                            old_excerpt.range.context.clone(),
2713                        )
2714                        .map(|edit| {
2715                            let excerpt_old_start = cursor.start().1;
2716                            let excerpt_new_start =
2717                                ExcerptOffset::new(new_excerpts.summary().text.len);
2718                            let old_start = excerpt_old_start + ExcerptOffset::new(edit.old.start);
2719                            let old_end = excerpt_old_start + ExcerptOffset::new(edit.old.end);
2720                            let new_start = excerpt_new_start + ExcerptOffset::new(edit.new.start);
2721                            let new_end = excerpt_new_start + ExcerptOffset::new(edit.new.end);
2722                            Edit {
2723                                old: old_start..old_end,
2724                                new: new_start..new_end,
2725                            }
2726                        }),
2727                );
2728
2729                new_excerpt = Excerpt::new(
2730                    old_excerpt.id,
2731                    locator.clone(),
2732                    buffer_id,
2733                    buffer.snapshot(),
2734                    old_excerpt.range.clone(),
2735                    old_excerpt.has_trailing_newline,
2736                );
2737            } else {
2738                new_excerpt = old_excerpt.clone();
2739                new_excerpt.buffer = buffer.snapshot();
2740            }
2741
2742            new_excerpts.push(new_excerpt, &());
2743            cursor.next(&());
2744        }
2745        new_excerpts.append(cursor.suffix(&()), &());
2746
2747        drop(cursor);
2748        snapshot.excerpts = new_excerpts;
2749
2750        self.sync_diff_transforms(&mut snapshot, edits, DiffChangeKind::BufferEdited);
2751    }
2752
2753    fn sync_diff_transforms(
2754        &self,
2755        snapshot: &mut MultiBufferSnapshot,
2756        excerpt_edits: Vec<text::Edit<ExcerptOffset>>,
2757        change_kind: DiffChangeKind,
2758    ) {
2759        if excerpt_edits.is_empty() {
2760            return;
2761        }
2762
2763        let mut excerpts = snapshot.excerpts.cursor::<ExcerptOffset>(&());
2764        let mut old_diff_transforms = snapshot
2765            .diff_transforms
2766            .cursor::<(ExcerptOffset, usize)>(&());
2767        let mut new_diff_transforms = SumTree::default();
2768        let mut old_expanded_hunks = HashSet::default();
2769        let mut output_edits = Vec::new();
2770        let mut output_delta = 0_isize;
2771        let mut at_transform_boundary = true;
2772        let mut end_of_current_insert = None;
2773
2774        let mut excerpt_edits = excerpt_edits.into_iter().peekable();
2775        while let Some(edit) = excerpt_edits.next() {
2776            excerpts.seek_forward(&edit.new.start, Bias::Right, &());
2777            if excerpts.item().is_none() && *excerpts.start() == edit.new.start {
2778                excerpts.prev(&());
2779            }
2780
2781            // Keep any transforms that are before the edit.
2782            if at_transform_boundary {
2783                at_transform_boundary = false;
2784                let transforms_before_edit =
2785                    old_diff_transforms.slice(&edit.old.start, Bias::Left, &());
2786                self.append_diff_transforms(&mut new_diff_transforms, transforms_before_edit);
2787                if let Some(transform) = old_diff_transforms.item() {
2788                    if old_diff_transforms.end(&()).0 == edit.old.start
2789                        && old_diff_transforms.start().0 < edit.old.start
2790                    {
2791                        self.push_diff_transform(&mut new_diff_transforms, transform.clone());
2792                        old_diff_transforms.next(&());
2793                    }
2794                }
2795            }
2796
2797            // Compute the start of the edit in output coordinates.
2798            let edit_start_overshoot = (edit.old.start - old_diff_transforms.start().0).value;
2799            let edit_old_start = old_diff_transforms.start().1 + edit_start_overshoot;
2800            let edit_new_start = (edit_old_start as isize + output_delta) as usize;
2801
2802            let changed_diff_hunks = self.recompute_diff_transforms_for_edit(
2803                &edit,
2804                &mut excerpts,
2805                &mut old_diff_transforms,
2806                &mut new_diff_transforms,
2807                &mut end_of_current_insert,
2808                &mut old_expanded_hunks,
2809                &snapshot,
2810                change_kind,
2811            );
2812
2813            // Compute the end of the edit in output coordinates.
2814            let edit_old_end_overshoot = edit.old.end - old_diff_transforms.start().0;
2815            let edit_new_end_overshoot = edit.new.end - new_diff_transforms.summary().excerpt_len();
2816            let edit_old_end = old_diff_transforms.start().1 + edit_old_end_overshoot.value;
2817            let edit_new_end =
2818                new_diff_transforms.summary().output.len + edit_new_end_overshoot.value;
2819            let output_edit = Edit {
2820                old: edit_old_start..edit_old_end,
2821                new: edit_new_start..edit_new_end,
2822            };
2823
2824            output_delta += (output_edit.new.end - output_edit.new.start) as isize;
2825            output_delta -= (output_edit.old.end - output_edit.old.start) as isize;
2826            if changed_diff_hunks || matches!(change_kind, DiffChangeKind::BufferEdited) {
2827                output_edits.push(output_edit);
2828            }
2829
2830            // If this is the last edit that intersects the current diff transform,
2831            // then recreate the content up to the end of this transform, to prepare
2832            // for reusing additional slices of the old transforms.
2833            if excerpt_edits.peek().map_or(true, |next_edit| {
2834                next_edit.old.start >= old_diff_transforms.end(&()).0
2835            }) {
2836                let keep_next_old_transform = (old_diff_transforms.start().0 >= edit.old.end)
2837                    && match old_diff_transforms.item() {
2838                        Some(DiffTransform::BufferContent {
2839                            inserted_hunk_info: Some(hunk),
2840                            ..
2841                        }) => excerpts.item().is_some_and(|excerpt| {
2842                            hunk.hunk_start_anchor.is_valid(&excerpt.buffer)
2843                        }),
2844                        _ => true,
2845                    };
2846
2847                let mut excerpt_offset = edit.new.end;
2848                if !keep_next_old_transform {
2849                    excerpt_offset += old_diff_transforms.end(&()).0 - edit.old.end;
2850                    old_diff_transforms.next(&());
2851                }
2852
2853                old_expanded_hunks.clear();
2854                self.push_buffer_content_transform(
2855                    &snapshot,
2856                    &mut new_diff_transforms,
2857                    excerpt_offset,
2858                    end_of_current_insert,
2859                );
2860                at_transform_boundary = true;
2861            }
2862        }
2863
2864        // Keep any transforms that are after the last edit.
2865        self.append_diff_transforms(&mut new_diff_transforms, old_diff_transforms.suffix(&()));
2866
2867        // Ensure there's always at least one buffer content transform.
2868        if new_diff_transforms.is_empty() {
2869            new_diff_transforms.push(
2870                DiffTransform::BufferContent {
2871                    summary: Default::default(),
2872                    inserted_hunk_info: None,
2873                },
2874                &(),
2875            );
2876        }
2877
2878        self.subscriptions.publish(output_edits);
2879        drop(old_diff_transforms);
2880        drop(excerpts);
2881        snapshot.diff_transforms = new_diff_transforms;
2882        snapshot.edit_count += 1;
2883
2884        #[cfg(any(test, feature = "test-support"))]
2885        snapshot.check_invariants();
2886    }
2887
2888    #[allow(clippy::too_many_arguments)]
2889    fn recompute_diff_transforms_for_edit(
2890        &self,
2891        edit: &Edit<TypedOffset<Excerpt>>,
2892        excerpts: &mut Cursor<Excerpt, TypedOffset<Excerpt>>,
2893        old_diff_transforms: &mut Cursor<DiffTransform, (TypedOffset<Excerpt>, usize)>,
2894        new_diff_transforms: &mut SumTree<DiffTransform>,
2895        end_of_current_insert: &mut Option<(TypedOffset<Excerpt>, DiffTransformHunkInfo)>,
2896        old_expanded_hunks: &mut HashSet<DiffTransformHunkInfo>,
2897        snapshot: &MultiBufferSnapshot,
2898        change_kind: DiffChangeKind,
2899    ) -> bool {
2900        log::trace!(
2901            "recomputing diff transform for edit {:?} => {:?}",
2902            edit.old.start.value..edit.old.end.value,
2903            edit.new.start.value..edit.new.end.value
2904        );
2905
2906        // Record which hunks were previously expanded.
2907        while let Some(item) = old_diff_transforms.item() {
2908            if let Some(hunk_info) = item.hunk_info() {
2909                log::trace!(
2910                    "previously expanded hunk at {}",
2911                    old_diff_transforms.start().0
2912                );
2913                old_expanded_hunks.insert(hunk_info);
2914            }
2915            if old_diff_transforms.end(&()).0 > edit.old.end {
2916                break;
2917            }
2918            old_diff_transforms.next(&());
2919        }
2920
2921        // Avoid querying diff hunks if there's no possibility of hunks being expanded.
2922        if old_expanded_hunks.is_empty()
2923            && change_kind == DiffChangeKind::BufferEdited
2924            && !self.all_diff_hunks_expanded
2925        {
2926            return false;
2927        }
2928
2929        // Visit each excerpt that intersects the edit.
2930        let mut did_expand_hunks = false;
2931        while let Some(excerpt) = excerpts.item() {
2932            // Recompute the expanded hunks in the portion of the excerpt that
2933            // intersects the edit.
2934            if let Some((diff, base_text)) = snapshot
2935                .diffs
2936                .get(&excerpt.buffer_id)
2937                .and_then(|diff| Some((diff, diff.base_text()?)))
2938            {
2939                let buffer = &excerpt.buffer;
2940                let excerpt_start = *excerpts.start();
2941                let excerpt_end = excerpt_start + ExcerptOffset::new(excerpt.text_summary.len);
2942                let excerpt_buffer_start = excerpt.range.context.start.to_offset(buffer);
2943                let excerpt_buffer_end = excerpt_buffer_start + excerpt.text_summary.len;
2944                let edit_buffer_start =
2945                    excerpt_buffer_start + edit.new.start.value.saturating_sub(excerpt_start.value);
2946                let edit_buffer_end =
2947                    excerpt_buffer_start + edit.new.end.value.saturating_sub(excerpt_start.value);
2948                let edit_buffer_end = edit_buffer_end.min(excerpt_buffer_end);
2949                let edit_anchor_range =
2950                    buffer.anchor_before(edit_buffer_start)..buffer.anchor_after(edit_buffer_end);
2951
2952                for hunk in diff.hunks_intersecting_range(edit_anchor_range, buffer) {
2953                    let hunk_buffer_range = hunk.buffer_range.to_offset(buffer);
2954
2955                    let hunk_info = DiffTransformHunkInfo {
2956                        excerpt_id: excerpt.id,
2957                        hunk_start_anchor: hunk.buffer_range.start,
2958                        hunk_secondary_status: hunk.secondary_status,
2959                    };
2960                    if hunk_buffer_range.start < excerpt_buffer_start {
2961                        log::trace!("skipping hunk that starts before excerpt");
2962                        continue;
2963                    }
2964
2965                    let hunk_excerpt_start = excerpt_start
2966                        + ExcerptOffset::new(
2967                            hunk_buffer_range.start.saturating_sub(excerpt_buffer_start),
2968                        );
2969                    let hunk_excerpt_end = excerpt_end.min(
2970                        excerpt_start
2971                            + ExcerptOffset::new(hunk_buffer_range.end - excerpt_buffer_start),
2972                    );
2973
2974                    self.push_buffer_content_transform(
2975                        snapshot,
2976                        new_diff_transforms,
2977                        hunk_excerpt_start,
2978                        *end_of_current_insert,
2979                    );
2980
2981                    // For every existing hunk, determine if it was previously expanded
2982                    // and if it should currently be expanded.
2983                    let was_previously_expanded = old_expanded_hunks.contains(&hunk_info);
2984                    let should_expand_hunk = match &change_kind {
2985                        DiffChangeKind::DiffUpdated { base_changed: true } => {
2986                            self.all_diff_hunks_expanded
2987                        }
2988                        DiffChangeKind::ExpandOrCollapseHunks { expand } => {
2989                            let intersects = hunk_buffer_range.is_empty()
2990                                || hunk_buffer_range.end > edit_buffer_start;
2991                            if *expand {
2992                                intersects
2993                                    || was_previously_expanded
2994                                    || self.all_diff_hunks_expanded
2995                            } else {
2996                                !intersects
2997                                    && (was_previously_expanded || self.all_diff_hunks_expanded)
2998                            }
2999                        }
3000                        _ => was_previously_expanded || self.all_diff_hunks_expanded,
3001                    };
3002
3003                    if should_expand_hunk {
3004                        did_expand_hunks = true;
3005                        log::trace!(
3006                            "expanding hunk {:?}, excerpt:{:?}",
3007                            hunk_excerpt_start.value..hunk_excerpt_end.value,
3008                            excerpt.id
3009                        );
3010
3011                        if !hunk.diff_base_byte_range.is_empty()
3012                            && hunk_buffer_range.start >= edit_buffer_start
3013                            && hunk_buffer_range.start <= excerpt_buffer_end
3014                        {
3015                            let mut text_cursor =
3016                                base_text.as_rope().cursor(hunk.diff_base_byte_range.start);
3017                            let mut base_text_summary =
3018                                text_cursor.summary::<TextSummary>(hunk.diff_base_byte_range.end);
3019
3020                            let mut has_trailing_newline = false;
3021                            if base_text_summary.last_line_chars > 0 {
3022                                base_text_summary += TextSummary::newline();
3023                                has_trailing_newline = true;
3024                            }
3025
3026                            new_diff_transforms.push(
3027                                DiffTransform::DeletedHunk {
3028                                    base_text_byte_range: hunk.diff_base_byte_range.clone(),
3029                                    summary: base_text_summary,
3030                                    buffer_id: excerpt.buffer_id,
3031                                    hunk_info,
3032                                    has_trailing_newline,
3033                                },
3034                                &(),
3035                            );
3036                        }
3037
3038                        if !hunk_buffer_range.is_empty() {
3039                            *end_of_current_insert =
3040                                Some((hunk_excerpt_end.min(excerpt_end), hunk_info));
3041                        }
3042                    }
3043                }
3044            }
3045
3046            if excerpts.end(&()) <= edit.new.end {
3047                excerpts.next(&());
3048            } else {
3049                break;
3050            }
3051        }
3052
3053        did_expand_hunks || !old_expanded_hunks.is_empty()
3054    }
3055
3056    fn append_diff_transforms(
3057        &self,
3058        new_transforms: &mut SumTree<DiffTransform>,
3059        subtree: SumTree<DiffTransform>,
3060    ) {
3061        if let Some(DiffTransform::BufferContent {
3062            inserted_hunk_info,
3063            summary,
3064        }) = subtree.first()
3065        {
3066            if self.extend_last_buffer_content_transform(
3067                new_transforms,
3068                *inserted_hunk_info,
3069                *summary,
3070            ) {
3071                let mut cursor = subtree.cursor::<()>(&());
3072                cursor.next(&());
3073                cursor.next(&());
3074                new_transforms.append(cursor.suffix(&()), &());
3075                return;
3076            }
3077        }
3078        new_transforms.append(subtree, &());
3079    }
3080
3081    fn push_diff_transform(
3082        &self,
3083        new_transforms: &mut SumTree<DiffTransform>,
3084        transform: DiffTransform,
3085    ) {
3086        if let DiffTransform::BufferContent {
3087            inserted_hunk_info: inserted_hunk_anchor,
3088            summary,
3089        } = transform
3090        {
3091            if self.extend_last_buffer_content_transform(
3092                new_transforms,
3093                inserted_hunk_anchor,
3094                summary,
3095            ) {
3096                return;
3097            }
3098        }
3099        new_transforms.push(transform, &());
3100    }
3101
3102    fn push_buffer_content_transform(
3103        &self,
3104        old_snapshot: &MultiBufferSnapshot,
3105        new_transforms: &mut SumTree<DiffTransform>,
3106        end_offset: ExcerptOffset,
3107        current_inserted_hunk: Option<(ExcerptOffset, DiffTransformHunkInfo)>,
3108    ) {
3109        let inserted_region = current_inserted_hunk.map(|(insertion_end_offset, hunk_info)| {
3110            (end_offset.min(insertion_end_offset), Some(hunk_info))
3111        });
3112        let unchanged_region = [(end_offset, None)];
3113
3114        for (end_offset, inserted_hunk_info) in inserted_region.into_iter().chain(unchanged_region)
3115        {
3116            let start_offset = new_transforms.summary().excerpt_len();
3117            if end_offset <= start_offset {
3118                continue;
3119            }
3120            let summary_to_add = old_snapshot
3121                .text_summary_for_excerpt_offset_range::<TextSummary>(start_offset..end_offset);
3122
3123            if !self.extend_last_buffer_content_transform(
3124                new_transforms,
3125                inserted_hunk_info,
3126                summary_to_add,
3127            ) {
3128                new_transforms.push(
3129                    DiffTransform::BufferContent {
3130                        summary: summary_to_add,
3131                        inserted_hunk_info,
3132                    },
3133                    &(),
3134                )
3135            }
3136        }
3137    }
3138
3139    fn extend_last_buffer_content_transform(
3140        &self,
3141        new_transforms: &mut SumTree<DiffTransform>,
3142        new_inserted_hunk_info: Option<DiffTransformHunkInfo>,
3143        summary_to_add: TextSummary,
3144    ) -> bool {
3145        let mut did_extend = false;
3146        new_transforms.update_last(
3147            |last_transform| {
3148                if let DiffTransform::BufferContent {
3149                    summary,
3150                    inserted_hunk_info: inserted_hunk_anchor,
3151                } = last_transform
3152                {
3153                    if *inserted_hunk_anchor == new_inserted_hunk_info {
3154                        *summary += summary_to_add;
3155                        did_extend = true;
3156                    }
3157                }
3158            },
3159            &(),
3160        );
3161        did_extend
3162    }
3163}
3164
3165#[cfg(any(test, feature = "test-support"))]
3166impl MultiBuffer {
3167    pub fn build_simple(text: &str, cx: &mut gpui::App) -> Entity<Self> {
3168        let buffer = cx.new(|cx| Buffer::local(text, cx));
3169        cx.new(|cx| Self::singleton(buffer, cx))
3170    }
3171
3172    pub fn build_multi<const COUNT: usize>(
3173        excerpts: [(&str, Vec<Range<Point>>); COUNT],
3174        cx: &mut gpui::App,
3175    ) -> Entity<Self> {
3176        let multi = cx.new(|_| Self::new(Capability::ReadWrite));
3177        for (text, ranges) in excerpts {
3178            let buffer = cx.new(|cx| Buffer::local(text, cx));
3179            let excerpt_ranges = ranges.into_iter().map(|range| ExcerptRange {
3180                context: range,
3181                primary: None,
3182            });
3183            multi.update(cx, |multi, cx| {
3184                multi.push_excerpts(buffer, excerpt_ranges, cx)
3185            });
3186        }
3187
3188        multi
3189    }
3190
3191    pub fn build_from_buffer(buffer: Entity<Buffer>, cx: &mut gpui::App) -> Entity<Self> {
3192        cx.new(|cx| Self::singleton(buffer, cx))
3193    }
3194
3195    pub fn build_random(rng: &mut impl rand::Rng, cx: &mut gpui::App) -> Entity<Self> {
3196        cx.new(|cx| {
3197            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite);
3198            let mutation_count = rng.gen_range(1..=5);
3199            multibuffer.randomly_edit_excerpts(rng, mutation_count, cx);
3200            multibuffer
3201        })
3202    }
3203
3204    pub fn randomly_edit(
3205        &mut self,
3206        rng: &mut impl rand::Rng,
3207        edit_count: usize,
3208        cx: &mut Context<Self>,
3209    ) {
3210        use util::RandomCharIter;
3211
3212        let snapshot = self.read(cx);
3213        let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
3214        let mut last_end = None;
3215        for _ in 0..edit_count {
3216            if last_end.map_or(false, |last_end| last_end >= snapshot.len()) {
3217                break;
3218            }
3219
3220            let new_start = last_end.map_or(0, |last_end| last_end + 1);
3221            let end = snapshot.clip_offset(rng.gen_range(new_start..=snapshot.len()), Bias::Right);
3222            let start = snapshot.clip_offset(rng.gen_range(new_start..=end), Bias::Right);
3223            last_end = Some(end);
3224
3225            let mut range = start..end;
3226            if rng.gen_bool(0.2) {
3227                mem::swap(&mut range.start, &mut range.end);
3228            }
3229
3230            let new_text_len = rng.gen_range(0..10);
3231            let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
3232
3233            edits.push((range, new_text.into()));
3234        }
3235        log::info!("mutating multi-buffer with {:?}", edits);
3236        drop(snapshot);
3237
3238        self.edit(edits, None, cx);
3239    }
3240
3241    pub fn randomly_edit_excerpts(
3242        &mut self,
3243        rng: &mut impl rand::Rng,
3244        mutation_count: usize,
3245        cx: &mut Context<Self>,
3246    ) {
3247        use rand::prelude::*;
3248        use std::env;
3249        use util::RandomCharIter;
3250
3251        let max_excerpts = env::var("MAX_EXCERPTS")
3252            .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))
3253            .unwrap_or(5);
3254
3255        let mut buffers = Vec::new();
3256        for _ in 0..mutation_count {
3257            if rng.gen_bool(0.05) {
3258                log::info!("Clearing multi-buffer");
3259                self.clear(cx);
3260                continue;
3261            } else if rng.gen_bool(0.1) && !self.excerpt_ids().is_empty() {
3262                let ids = self.excerpt_ids();
3263                let mut excerpts = HashSet::default();
3264                for _ in 0..rng.gen_range(0..ids.len()) {
3265                    excerpts.extend(ids.choose(rng).copied());
3266                }
3267
3268                let line_count = rng.gen_range(0..5);
3269
3270                log::info!("Expanding excerpts {excerpts:?} by {line_count} lines");
3271
3272                self.expand_excerpts(
3273                    excerpts.iter().cloned(),
3274                    line_count,
3275                    ExpandExcerptDirection::UpAndDown,
3276                    cx,
3277                );
3278                continue;
3279            }
3280
3281            let excerpt_ids = self.excerpt_ids();
3282            if excerpt_ids.is_empty() || (rng.gen() && excerpt_ids.len() < max_excerpts) {
3283                let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() {
3284                    let text = RandomCharIter::new(&mut *rng).take(10).collect::<String>();
3285                    buffers.push(cx.new(|cx| Buffer::local(text, cx)));
3286                    let buffer = buffers.last().unwrap().read(cx);
3287                    log::info!(
3288                        "Creating new buffer {} with text: {:?}",
3289                        buffer.remote_id(),
3290                        buffer.text()
3291                    );
3292                    buffers.last().unwrap().clone()
3293                } else {
3294                    self.buffers
3295                        .borrow()
3296                        .values()
3297                        .choose(rng)
3298                        .unwrap()
3299                        .buffer
3300                        .clone()
3301                };
3302
3303                let buffer = buffer_handle.read(cx);
3304                let buffer_text = buffer.text();
3305                let ranges = (0..rng.gen_range(0..5))
3306                    .map(|_| {
3307                        let end_ix =
3308                            buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
3309                        let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
3310                        ExcerptRange {
3311                            context: start_ix..end_ix,
3312                            primary: None,
3313                        }
3314                    })
3315                    .collect::<Vec<_>>();
3316                log::info!(
3317                    "Inserting excerpts from buffer {} and ranges {:?}: {:?}",
3318                    buffer_handle.read(cx).remote_id(),
3319                    ranges.iter().map(|r| &r.context).collect::<Vec<_>>(),
3320                    ranges
3321                        .iter()
3322                        .map(|r| &buffer_text[r.context.clone()])
3323                        .collect::<Vec<_>>()
3324                );
3325
3326                let excerpt_id = self.push_excerpts(buffer_handle.clone(), ranges, cx);
3327                log::info!("Inserted with ids: {:?}", excerpt_id);
3328            } else {
3329                let remove_count = rng.gen_range(1..=excerpt_ids.len());
3330                let mut excerpts_to_remove = excerpt_ids
3331                    .choose_multiple(rng, remove_count)
3332                    .cloned()
3333                    .collect::<Vec<_>>();
3334                let snapshot = self.snapshot.borrow();
3335                excerpts_to_remove.sort_unstable_by(|a, b| a.cmp(b, &snapshot));
3336                drop(snapshot);
3337                log::info!("Removing excerpts {:?}", excerpts_to_remove);
3338                self.remove_excerpts(excerpts_to_remove, cx);
3339            }
3340        }
3341    }
3342
3343    pub fn randomly_mutate(
3344        &mut self,
3345        rng: &mut impl rand::Rng,
3346        mutation_count: usize,
3347        cx: &mut Context<Self>,
3348    ) {
3349        use rand::prelude::*;
3350
3351        if rng.gen_bool(0.7) || self.singleton {
3352            let buffer = self
3353                .buffers
3354                .borrow()
3355                .values()
3356                .choose(rng)
3357                .map(|state| state.buffer.clone());
3358
3359            if let Some(buffer) = buffer {
3360                buffer.update(cx, |buffer, cx| {
3361                    if rng.gen() {
3362                        buffer.randomly_edit(rng, mutation_count, cx);
3363                    } else {
3364                        buffer.randomly_undo_redo(rng, cx);
3365                    }
3366                });
3367            } else {
3368                self.randomly_edit(rng, mutation_count, cx);
3369            }
3370        } else {
3371            self.randomly_edit_excerpts(rng, mutation_count, cx);
3372        }
3373
3374        self.check_invariants(cx);
3375    }
3376
3377    fn check_invariants(&self, cx: &App) {
3378        self.read(cx).check_invariants();
3379    }
3380}
3381
3382impl EventEmitter<Event> for MultiBuffer {}
3383
3384impl MultiBufferSnapshot {
3385    pub fn text(&self) -> String {
3386        self.chunks(0..self.len(), false)
3387            .map(|chunk| chunk.text)
3388            .collect()
3389    }
3390
3391    pub fn reversed_chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
3392        self.reversed_chunks_in_range(0..position.to_offset(self))
3393            .flat_map(|c| c.chars().rev())
3394    }
3395
3396    fn reversed_chunks_in_range(&self, range: Range<usize>) -> ReversedMultiBufferChunks {
3397        let mut cursor = self.cursor::<usize>();
3398        cursor.seek(&range.end);
3399        let current_chunks = cursor.region().as_ref().map(|region| {
3400            let start_overshoot = range.start.saturating_sub(region.range.start);
3401            let end_overshoot = range.end - region.range.start;
3402            let end = (region.buffer_range.start + end_overshoot).min(region.buffer_range.end);
3403            let start = region.buffer_range.start + start_overshoot;
3404            region.buffer.reversed_chunks_in_range(start..end)
3405        });
3406        ReversedMultiBufferChunks {
3407            cursor,
3408            current_chunks,
3409            start: range.start,
3410            offset: range.end,
3411        }
3412    }
3413
3414    pub fn chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
3415        let offset = position.to_offset(self);
3416        self.text_for_range(offset..self.len())
3417            .flat_map(|chunk| chunk.chars())
3418    }
3419
3420    pub fn text_for_range<T: ToOffset>(&self, range: Range<T>) -> impl Iterator<Item = &str> + '_ {
3421        self.chunks(range, false).map(|chunk| chunk.text)
3422    }
3423
3424    pub fn is_line_blank(&self, row: MultiBufferRow) -> bool {
3425        self.text_for_range(Point::new(row.0, 0)..Point::new(row.0, self.line_len(row)))
3426            .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
3427    }
3428
3429    pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
3430    where
3431        T: ToOffset,
3432    {
3433        let position = position.to_offset(self);
3434        position == self.clip_offset(position, Bias::Left)
3435            && self
3436                .bytes_in_range(position..self.len())
3437                .flatten()
3438                .copied()
3439                .take(needle.len())
3440                .eq(needle.bytes())
3441    }
3442
3443    pub fn diff_hunks(&self) -> impl Iterator<Item = MultiBufferDiffHunk> + '_ {
3444        self.diff_hunks_in_range(Anchor::min()..Anchor::max())
3445    }
3446
3447    pub fn diff_hunks_in_range<T: ToPoint>(
3448        &self,
3449        range: Range<T>,
3450    ) -> impl Iterator<Item = MultiBufferDiffHunk> + '_ {
3451        let query_range = range.start.to_point(self)..range.end.to_point(self);
3452        self.lift_buffer_metadata(query_range.clone(), move |buffer, buffer_range| {
3453            let diff = self.diffs.get(&buffer.remote_id())?;
3454            let buffer_start = buffer.anchor_before(buffer_range.start);
3455            let buffer_end = buffer.anchor_after(buffer_range.end);
3456            Some(
3457                diff.hunks_intersecting_range(buffer_start..buffer_end, buffer)
3458                    .map(|hunk| {
3459                        (
3460                            Point::new(hunk.row_range.start, 0)..Point::new(hunk.row_range.end, 0),
3461                            hunk,
3462                        )
3463                    }),
3464            )
3465        })
3466        .filter_map(move |(range, hunk, excerpt)| {
3467            if range.start != range.end
3468                && range.end == query_range.start
3469                && !hunk.row_range.is_empty()
3470            {
3471                return None;
3472            }
3473            let end_row = if range.end.column == 0 {
3474                range.end.row
3475            } else {
3476                range.end.row + 1
3477            };
3478            Some(MultiBufferDiffHunk {
3479                row_range: MultiBufferRow(range.start.row)..MultiBufferRow(end_row),
3480                buffer_id: excerpt.buffer_id,
3481                excerpt_id: excerpt.id,
3482                buffer_range: hunk.buffer_range.clone(),
3483                diff_base_byte_range: hunk.diff_base_byte_range.clone(),
3484                secondary_status: hunk.secondary_status,
3485                secondary_diff_base_byte_range: hunk.secondary_diff_base_byte_range,
3486            })
3487        })
3488    }
3489
3490    pub fn excerpt_ids_for_range<T: ToOffset>(
3491        &self,
3492        range: Range<T>,
3493    ) -> impl Iterator<Item = ExcerptId> + '_ {
3494        let range = range.start.to_offset(self)..range.end.to_offset(self);
3495        let mut cursor = self.cursor::<usize>();
3496        cursor.seek(&range.start);
3497        std::iter::from_fn(move || {
3498            let region = cursor.region()?;
3499            if region.range.start >= range.end {
3500                return None;
3501            }
3502            cursor.next_excerpt();
3503            Some(region.excerpt.id)
3504        })
3505    }
3506
3507    pub fn buffer_ids_for_range<T: ToOffset>(
3508        &self,
3509        range: Range<T>,
3510    ) -> impl Iterator<Item = BufferId> + '_ {
3511        let range = range.start.to_offset(self)..range.end.to_offset(self);
3512        let mut cursor = self.cursor::<usize>();
3513        cursor.seek(&range.start);
3514        std::iter::from_fn(move || {
3515            let region = cursor.region()?;
3516            if region.range.start >= range.end {
3517                return None;
3518            }
3519            cursor.next_excerpt();
3520            Some(region.excerpt.buffer_id)
3521        })
3522    }
3523
3524    pub fn ranges_to_buffer_ranges<T: ToOffset>(
3525        &self,
3526        ranges: impl Iterator<Item = Range<T>>,
3527    ) -> impl Iterator<Item = (&BufferSnapshot, Range<usize>, ExcerptId)> {
3528        ranges.flat_map(|range| self.range_to_buffer_ranges(range).into_iter())
3529    }
3530
3531    pub fn range_to_buffer_ranges<T: ToOffset>(
3532        &self,
3533        range: Range<T>,
3534    ) -> Vec<(&BufferSnapshot, Range<usize>, ExcerptId)> {
3535        let start = range.start.to_offset(&self);
3536        let end = range.end.to_offset(&self);
3537
3538        let mut cursor = self.cursor::<usize>();
3539        cursor.seek(&start);
3540
3541        let mut result: Vec<(&BufferSnapshot, Range<usize>, ExcerptId)> = Vec::new();
3542        while let Some(region) = cursor.region() {
3543            if region.range.start > end {
3544                break;
3545            }
3546            if region.is_main_buffer {
3547                let start_overshoot = start.saturating_sub(region.range.start);
3548                let end_overshoot = end.saturating_sub(region.range.start);
3549                let start = region
3550                    .buffer_range
3551                    .end
3552                    .min(region.buffer_range.start + start_overshoot);
3553                let end = region
3554                    .buffer_range
3555                    .end
3556                    .min(region.buffer_range.start + end_overshoot);
3557                if let Some(prev) = result.last_mut().filter(|(_, prev_range, excerpt_id)| {
3558                    *excerpt_id == region.excerpt.id && prev_range.end == start
3559                }) {
3560                    prev.1.end = end;
3561                } else {
3562                    result.push((region.buffer, start..end, region.excerpt.id));
3563                }
3564            }
3565            cursor.next();
3566        }
3567        result
3568    }
3569
3570    pub fn range_to_buffer_ranges_with_deleted_hunks<T: ToOffset>(
3571        &self,
3572        range: Range<T>,
3573    ) -> impl Iterator<Item = (&BufferSnapshot, Range<usize>, ExcerptId, Option<Anchor>)> + '_ {
3574        let start = range.start.to_offset(&self);
3575        let end = range.end.to_offset(&self);
3576
3577        let mut cursor = self.cursor::<usize>();
3578        cursor.seek(&start);
3579
3580        std::iter::from_fn(move || {
3581            let region = cursor.region()?;
3582            if region.range.start > end {
3583                return None;
3584            }
3585            let start_overshoot = start.saturating_sub(region.range.start);
3586            let end_overshoot = end.saturating_sub(region.range.start);
3587            let start = region
3588                .buffer_range
3589                .end
3590                .min(region.buffer_range.start + start_overshoot);
3591            let end = region
3592                .buffer_range
3593                .end
3594                .min(region.buffer_range.start + end_overshoot);
3595
3596            let region_excerpt_id = region.excerpt.id;
3597            let deleted_hunk_anchor = if region.is_main_buffer {
3598                None
3599            } else {
3600                Some(self.anchor_before(region.range.start))
3601            };
3602            let result = (
3603                region.buffer,
3604                start..end,
3605                region_excerpt_id,
3606                deleted_hunk_anchor,
3607            );
3608            cursor.next();
3609            Some(result)
3610        })
3611    }
3612
3613    /// Retrieves buffer metadata for the given range, and converts it into multi-buffer
3614    /// coordinates.
3615    ///
3616    /// The given callback will be called for every excerpt intersecting the given range. It will
3617    /// be passed the excerpt's buffer and the buffer range that the input range intersects.
3618    /// The callback should return an iterator of metadata items from that buffer, each paired
3619    /// with a buffer range.
3620    ///
3621    /// The returned iterator yields each of these metadata items, paired with its range in
3622    /// multi-buffer coordinates.
3623    fn lift_buffer_metadata<'a, D, M, I>(
3624        &'a self,
3625        query_range: Range<D>,
3626        get_buffer_metadata: impl 'a + Fn(&'a BufferSnapshot, Range<D>) -> Option<I>,
3627    ) -> impl Iterator<Item = (Range<D>, M, &'a Excerpt)> + 'a
3628    where
3629        I: Iterator<Item = (Range<D>, M)> + 'a,
3630        D: TextDimension + Ord + Sub<D, Output = D>,
3631    {
3632        let max_position = D::from_text_summary(&self.text_summary());
3633        let mut current_excerpt_metadata: Option<(ExcerptId, I)> = None;
3634        let mut cursor = self.cursor::<D>();
3635
3636        // Find the excerpt and buffer offset where the given range ends.
3637        cursor.seek(&query_range.end);
3638        let mut range_end = None;
3639        while let Some(region) = cursor.region() {
3640            if region.is_main_buffer {
3641                let mut buffer_end = region.buffer_range.start;
3642                let overshoot = if query_range.end > region.range.start {
3643                    query_range.end - region.range.start
3644                } else {
3645                    D::default()
3646                };
3647                buffer_end.add_assign(&overshoot);
3648                range_end = Some((region.excerpt.id, buffer_end));
3649                break;
3650            }
3651            cursor.next();
3652        }
3653
3654        cursor.seek(&query_range.start);
3655
3656        if let Some(region) = cursor.region().filter(|region| !region.is_main_buffer) {
3657            if region.range.start > D::zero(&()) {
3658                cursor.prev()
3659            }
3660        }
3661
3662        iter::from_fn(move || loop {
3663            let excerpt = cursor.excerpt()?;
3664
3665            // If we have already retrieved metadata for this excerpt, continue to use it.
3666            let metadata_iter = if let Some((_, metadata)) = current_excerpt_metadata
3667                .as_mut()
3668                .filter(|(excerpt_id, _)| *excerpt_id == excerpt.id)
3669            {
3670                Some(metadata)
3671            }
3672            // Otherwise, compute the intersection of the input range with the excerpt's range,
3673            // and retrieve the metadata for the resulting range.
3674            else {
3675                let region = cursor.region()?;
3676                let mut buffer_start;
3677                if region.is_main_buffer {
3678                    buffer_start = region.buffer_range.start;
3679                    if query_range.start > region.range.start {
3680                        let overshoot = query_range.start - region.range.start;
3681                        buffer_start.add_assign(&overshoot);
3682                    }
3683                    buffer_start = buffer_start.min(region.buffer_range.end);
3684                } else {
3685                    buffer_start = cursor.main_buffer_position()?;
3686                };
3687                let mut buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer);
3688                if let Some((end_excerpt_id, end_buffer_offset)) = range_end {
3689                    if excerpt.id == end_excerpt_id {
3690                        buffer_end = buffer_end.min(end_buffer_offset);
3691                    }
3692                }
3693
3694                if let Some(iterator) =
3695                    get_buffer_metadata(&excerpt.buffer, buffer_start..buffer_end)
3696                {
3697                    Some(&mut current_excerpt_metadata.insert((excerpt.id, iterator)).1)
3698                } else {
3699                    None
3700                }
3701            };
3702
3703            // Visit each metadata item.
3704            if let Some((metadata_buffer_range, metadata)) = metadata_iter.and_then(Iterator::next)
3705            {
3706                // Find the multibuffer regions that contain the start and end of
3707                // the metadata item's range.
3708                if metadata_buffer_range.start > D::default() {
3709                    while let Some(region) = cursor.region() {
3710                        if region.is_main_buffer
3711                            && (region.buffer_range.end >= metadata_buffer_range.start
3712                                || cursor.is_at_end_of_excerpt())
3713                        {
3714                            break;
3715                        }
3716                        cursor.next();
3717                    }
3718                }
3719                let start_region = cursor.region()?;
3720                while let Some(region) = cursor.region() {
3721                    if region.is_main_buffer
3722                        && (region.buffer_range.end > metadata_buffer_range.end
3723                            || cursor.is_at_end_of_excerpt())
3724                    {
3725                        break;
3726                    }
3727                    cursor.next();
3728                }
3729                let end_region = cursor.region();
3730
3731                // Convert the metadata item's range into multibuffer coordinates.
3732                let mut start_position = start_region.range.start;
3733                let region_buffer_start = start_region.buffer_range.start;
3734                if start_region.is_main_buffer && metadata_buffer_range.start > region_buffer_start
3735                {
3736                    start_position.add_assign(&(metadata_buffer_range.start - region_buffer_start));
3737                    start_position = start_position.min(start_region.range.end);
3738                }
3739
3740                let mut end_position = max_position;
3741                if let Some(end_region) = &end_region {
3742                    end_position = end_region.range.start;
3743                    debug_assert!(end_region.is_main_buffer);
3744                    let region_buffer_start = end_region.buffer_range.start;
3745                    if metadata_buffer_range.end > region_buffer_start {
3746                        end_position.add_assign(&(metadata_buffer_range.end - region_buffer_start));
3747                    }
3748                    end_position = end_position.min(end_region.range.end);
3749                }
3750
3751                if start_position <= query_range.end && end_position >= query_range.start {
3752                    return Some((start_position..end_position, metadata, excerpt));
3753                }
3754            }
3755            // When there are no more metadata items for this excerpt, move to the next excerpt.
3756            else {
3757                current_excerpt_metadata.take();
3758                cursor.next_excerpt();
3759            }
3760        })
3761    }
3762
3763    pub fn diff_hunk_before<T: ToOffset>(&self, position: T) -> Option<MultiBufferDiffHunk> {
3764        let offset = position.to_offset(self);
3765
3766        // Go to the region containing the given offset.
3767        let mut cursor = self.cursor::<DimensionPair<usize, Point>>();
3768        cursor.seek(&DimensionPair {
3769            key: offset,
3770            value: None,
3771        });
3772        let mut region = cursor.region()?;
3773        if region.range.start.key == offset || !region.is_main_buffer {
3774            cursor.prev();
3775            region = cursor.region()?;
3776        }
3777
3778        // Find the corresponding buffer offset.
3779        let overshoot = if region.is_main_buffer {
3780            offset - region.range.start.key
3781        } else {
3782            0
3783        };
3784        let mut max_buffer_offset = region
3785            .buffer
3786            .clip_offset(region.buffer_range.start.key + overshoot, Bias::Right);
3787
3788        loop {
3789            let excerpt = cursor.excerpt()?;
3790            let excerpt_end = excerpt.range.context.end.to_offset(&excerpt.buffer);
3791            let buffer_offset = excerpt_end.min(max_buffer_offset);
3792            let buffer_end = excerpt.buffer.anchor_before(buffer_offset);
3793            let buffer_end_row = buffer_end.to_point(&excerpt.buffer).row;
3794
3795            if let Some(diff) = self.diffs.get(&excerpt.buffer_id) {
3796                for hunk in diff.hunks_intersecting_range_rev(
3797                    excerpt.range.context.start..buffer_end,
3798                    &excerpt.buffer,
3799                ) {
3800                    let hunk_range = hunk.buffer_range.to_offset(&excerpt.buffer);
3801                    if hunk.row_range.end >= buffer_end_row {
3802                        continue;
3803                    }
3804
3805                    let hunk_start = Point::new(hunk.row_range.start, 0);
3806                    let hunk_end = Point::new(hunk.row_range.end, 0);
3807
3808                    cursor.seek_to_buffer_position_in_current_excerpt(&DimensionPair {
3809                        key: hunk_range.start,
3810                        value: None,
3811                    });
3812
3813                    let mut region = cursor.region()?;
3814                    while !region.is_main_buffer || region.buffer_range.start.key >= hunk_range.end
3815                    {
3816                        cursor.prev();
3817                        region = cursor.region()?;
3818                    }
3819
3820                    let overshoot = if region.is_main_buffer {
3821                        hunk_start.saturating_sub(region.buffer_range.start.value.unwrap())
3822                    } else {
3823                        Point::zero()
3824                    };
3825                    let start = region.range.start.value.unwrap() + overshoot;
3826
3827                    while let Some(region) = cursor.region() {
3828                        if !region.is_main_buffer
3829                            || region.buffer_range.end.value.unwrap() <= hunk_end
3830                        {
3831                            cursor.next();
3832                        } else {
3833                            break;
3834                        }
3835                    }
3836
3837                    let end = if let Some(region) = cursor.region() {
3838                        let overshoot = if region.is_main_buffer {
3839                            hunk_end.saturating_sub(region.buffer_range.start.value.unwrap())
3840                        } else {
3841                            Point::zero()
3842                        };
3843                        region.range.start.value.unwrap() + overshoot
3844                    } else {
3845                        self.max_point()
3846                    };
3847
3848                    return Some(MultiBufferDiffHunk {
3849                        row_range: MultiBufferRow(start.row)..MultiBufferRow(end.row),
3850                        buffer_id: excerpt.buffer_id,
3851                        excerpt_id: excerpt.id,
3852                        buffer_range: hunk.buffer_range.clone(),
3853                        diff_base_byte_range: hunk.diff_base_byte_range.clone(),
3854                        secondary_status: hunk.secondary_status,
3855                        secondary_diff_base_byte_range: hunk.secondary_diff_base_byte_range,
3856                    });
3857                }
3858            }
3859
3860            cursor.prev_excerpt();
3861            max_buffer_offset = usize::MAX;
3862        }
3863    }
3864
3865    pub fn has_diff_hunks(&self) -> bool {
3866        self.diffs.values().any(|diff| !diff.is_empty())
3867    }
3868
3869    pub fn surrounding_word<T: ToOffset>(
3870        &self,
3871        start: T,
3872        for_completion: bool,
3873    ) -> (Range<usize>, Option<CharKind>) {
3874        let mut start = start.to_offset(self);
3875        let mut end = start;
3876        let mut next_chars = self.chars_at(start).peekable();
3877        let mut prev_chars = self.reversed_chars_at(start).peekable();
3878
3879        let classifier = self
3880            .char_classifier_at(start)
3881            .for_completion(for_completion);
3882
3883        let word_kind = cmp::max(
3884            prev_chars.peek().copied().map(|c| classifier.kind(c)),
3885            next_chars.peek().copied().map(|c| classifier.kind(c)),
3886        );
3887
3888        for ch in prev_chars {
3889            if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
3890                start -= ch.len_utf8();
3891            } else {
3892                break;
3893            }
3894        }
3895
3896        for ch in next_chars {
3897            if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
3898                end += ch.len_utf8();
3899            } else {
3900                break;
3901            }
3902        }
3903
3904        (start..end, word_kind)
3905    }
3906
3907    pub fn is_singleton(&self) -> bool {
3908        self.singleton
3909    }
3910
3911    pub fn as_singleton(&self) -> Option<(&ExcerptId, BufferId, &BufferSnapshot)> {
3912        if self.singleton {
3913            self.excerpts
3914                .iter()
3915                .next()
3916                .map(|e| (&e.id, e.buffer_id, &e.buffer))
3917        } else {
3918            None
3919        }
3920    }
3921
3922    pub fn len(&self) -> usize {
3923        self.diff_transforms.summary().output.len
3924    }
3925
3926    pub fn is_empty(&self) -> bool {
3927        self.excerpts.summary().text.len == 0
3928    }
3929
3930    pub fn widest_line_number(&self) -> u32 {
3931        self.excerpts.summary().widest_line_number + 1
3932    }
3933
3934    pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> MultiBufferBytes {
3935        let range = range.start.to_offset(self)..range.end.to_offset(self);
3936        let mut excerpts = self.cursor::<usize>();
3937        excerpts.seek(&range.start);
3938
3939        let mut chunk;
3940        let mut has_trailing_newline;
3941        let excerpt_bytes;
3942        if let Some(region) = excerpts.region() {
3943            let mut bytes = region.buffer.bytes_in_range(
3944                region.buffer_range.start + range.start - region.range.start
3945                    ..(region.buffer_range.start + range.end - region.range.start)
3946                        .min(region.buffer_range.end),
3947            );
3948            chunk = bytes.next().unwrap_or(&[][..]);
3949            excerpt_bytes = Some(bytes);
3950            has_trailing_newline = region.has_trailing_newline && range.end >= region.range.end;
3951            if chunk.is_empty() && has_trailing_newline {
3952                chunk = b"\n";
3953                has_trailing_newline = false;
3954            }
3955        } else {
3956            chunk = &[][..];
3957            excerpt_bytes = None;
3958            has_trailing_newline = false;
3959        };
3960
3961        MultiBufferBytes {
3962            range,
3963            cursor: excerpts,
3964            excerpt_bytes,
3965            has_trailing_newline,
3966            chunk,
3967        }
3968    }
3969
3970    pub fn reversed_bytes_in_range<T: ToOffset>(
3971        &self,
3972        range: Range<T>,
3973    ) -> ReversedMultiBufferBytes {
3974        let range = range.start.to_offset(self)..range.end.to_offset(self);
3975        let mut chunks = self.reversed_chunks_in_range(range.clone());
3976        let chunk = chunks.next().map_or(&[][..], |c| c.as_bytes());
3977        ReversedMultiBufferBytes {
3978            range,
3979            chunks,
3980            chunk,
3981        }
3982    }
3983
3984    pub fn row_infos(&self, start_row: MultiBufferRow) -> MultiBufferRows {
3985        let mut cursor = self.cursor::<Point>();
3986        cursor.seek(&Point::new(start_row.0, 0));
3987        let mut result = MultiBufferRows {
3988            point: Point::new(0, 0),
3989            is_empty: self.excerpts.is_empty(),
3990            cursor,
3991        };
3992        result.seek(start_row);
3993        result
3994    }
3995
3996    pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> MultiBufferChunks {
3997        let mut chunks = MultiBufferChunks {
3998            excerpt_offset_range: ExcerptOffset::new(0)..ExcerptOffset::new(0),
3999            range: 0..0,
4000            excerpts: self.excerpts.cursor(&()),
4001            diff_transforms: self.diff_transforms.cursor(&()),
4002            diffs: &self.diffs,
4003            diff_base_chunks: None,
4004            excerpt_chunks: None,
4005            buffer_chunk: None,
4006            language_aware,
4007        };
4008        let range = range.start.to_offset(self)..range.end.to_offset(self);
4009        chunks.seek(range);
4010        chunks
4011    }
4012
4013    pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
4014        self.clip_dimension(offset, bias, text::BufferSnapshot::clip_offset)
4015    }
4016
4017    pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
4018        self.clip_dimension(point, bias, text::BufferSnapshot::clip_point)
4019    }
4020
4021    pub fn clip_offset_utf16(&self, offset: OffsetUtf16, bias: Bias) -> OffsetUtf16 {
4022        self.clip_dimension(offset, bias, text::BufferSnapshot::clip_offset_utf16)
4023    }
4024
4025    pub fn clip_point_utf16(&self, point: Unclipped<PointUtf16>, bias: Bias) -> PointUtf16 {
4026        self.clip_dimension(point.0, bias, |buffer, point, bias| {
4027            buffer.clip_point_utf16(Unclipped(point), bias)
4028        })
4029    }
4030
4031    pub fn offset_to_point(&self, offset: usize) -> Point {
4032        self.convert_dimension(offset, text::BufferSnapshot::offset_to_point)
4033    }
4034
4035    pub fn offset_to_point_utf16(&self, offset: usize) -> PointUtf16 {
4036        self.convert_dimension(offset, text::BufferSnapshot::offset_to_point_utf16)
4037    }
4038
4039    pub fn point_to_point_utf16(&self, point: Point) -> PointUtf16 {
4040        self.convert_dimension(point, text::BufferSnapshot::point_to_point_utf16)
4041    }
4042
4043    pub fn point_to_offset(&self, point: Point) -> usize {
4044        self.convert_dimension(point, text::BufferSnapshot::point_to_offset)
4045    }
4046
4047    pub fn offset_utf16_to_offset(&self, offset: OffsetUtf16) -> usize {
4048        self.convert_dimension(offset, text::BufferSnapshot::offset_utf16_to_offset)
4049    }
4050
4051    pub fn offset_to_offset_utf16(&self, offset: usize) -> OffsetUtf16 {
4052        self.convert_dimension(offset, text::BufferSnapshot::offset_to_offset_utf16)
4053    }
4054
4055    pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
4056        self.convert_dimension(point, text::BufferSnapshot::point_utf16_to_offset)
4057    }
4058
4059    fn clip_dimension<D>(
4060        &self,
4061        position: D,
4062        bias: Bias,
4063        clip_buffer_position: fn(&text::BufferSnapshot, D, Bias) -> D,
4064    ) -> D
4065    where
4066        D: TextDimension + Ord + Sub<D, Output = D>,
4067    {
4068        let mut cursor = self.cursor();
4069        cursor.seek(&position);
4070        if let Some(region) = cursor.region() {
4071            if position >= region.range.end {
4072                return region.range.end;
4073            }
4074            let overshoot = position - region.range.start;
4075            let mut buffer_position = region.buffer_range.start;
4076            buffer_position.add_assign(&overshoot);
4077            let clipped_buffer_position =
4078                clip_buffer_position(&region.buffer, buffer_position, bias);
4079            let mut position = region.range.start;
4080            position.add_assign(&(clipped_buffer_position - region.buffer_range.start));
4081            position
4082        } else {
4083            D::from_text_summary(&self.text_summary())
4084        }
4085    }
4086
4087    fn convert_dimension<D1, D2>(
4088        &self,
4089        key: D1,
4090        convert_buffer_dimension: fn(&text::BufferSnapshot, D1) -> D2,
4091    ) -> D2
4092    where
4093        D1: TextDimension + Ord + Sub<D1, Output = D1>,
4094        D2: TextDimension + Ord + Sub<D2, Output = D2>,
4095    {
4096        let mut cursor = self.cursor::<DimensionPair<D1, D2>>();
4097        cursor.seek(&DimensionPair { key, value: None });
4098        if let Some(region) = cursor.region() {
4099            if key >= region.range.end.key {
4100                return region.range.end.value.unwrap();
4101            }
4102            let start_key = region.range.start.key;
4103            let start_value = region.range.start.value.unwrap();
4104            let buffer_start_key = region.buffer_range.start.key;
4105            let buffer_start_value = region.buffer_range.start.value.unwrap();
4106            let mut buffer_key = buffer_start_key;
4107            buffer_key.add_assign(&(key - start_key));
4108            let buffer_value = convert_buffer_dimension(&region.buffer, buffer_key);
4109            let mut result = start_value;
4110            result.add_assign(&(buffer_value - buffer_start_value));
4111            result
4112        } else {
4113            D2::from_text_summary(&self.text_summary())
4114        }
4115    }
4116
4117    pub fn point_to_buffer_offset<T: ToOffset>(
4118        &self,
4119        point: T,
4120    ) -> Option<(&BufferSnapshot, usize)> {
4121        let offset = point.to_offset(self);
4122        let mut cursor = self.cursor::<usize>();
4123        cursor.seek(&offset);
4124        let region = cursor.region()?;
4125        let overshoot = offset - region.range.start;
4126        let buffer_offset = region.buffer_range.start + overshoot;
4127        Some((region.buffer, buffer_offset))
4128    }
4129
4130    pub fn point_to_buffer_point(&self, point: Point) -> Option<(&BufferSnapshot, Point, bool)> {
4131        let mut cursor = self.cursor::<Point>();
4132        cursor.seek(&point);
4133        let region = cursor.region()?;
4134        let overshoot = point - region.range.start;
4135        let buffer_offset = region.buffer_range.start + overshoot;
4136        Some((region.buffer, buffer_offset, region.is_main_buffer))
4137    }
4138
4139    pub fn suggested_indents(
4140        &self,
4141        rows: impl IntoIterator<Item = u32>,
4142        cx: &App,
4143    ) -> BTreeMap<MultiBufferRow, IndentSize> {
4144        let mut result = BTreeMap::new();
4145
4146        let mut rows_for_excerpt = Vec::new();
4147        let mut cursor = self.cursor::<Point>();
4148        let mut rows = rows.into_iter().peekable();
4149        let mut prev_row = u32::MAX;
4150        let mut prev_language_indent_size = IndentSize::default();
4151
4152        while let Some(row) = rows.next() {
4153            cursor.seek(&Point::new(row, 0));
4154            let Some(region) = cursor.region() else {
4155                continue;
4156            };
4157
4158            // Retrieve the language and indent size once for each disjoint region being indented.
4159            let single_indent_size = if row.saturating_sub(1) == prev_row {
4160                prev_language_indent_size
4161            } else {
4162                region
4163                    .buffer
4164                    .language_indent_size_at(Point::new(row, 0), cx)
4165            };
4166            prev_language_indent_size = single_indent_size;
4167            prev_row = row;
4168
4169            let start_buffer_row = region.buffer_range.start.row;
4170            let start_multibuffer_row = region.range.start.row;
4171            let end_multibuffer_row = region.range.end.row;
4172
4173            rows_for_excerpt.push(row);
4174            while let Some(next_row) = rows.peek().copied() {
4175                if end_multibuffer_row > next_row {
4176                    rows_for_excerpt.push(next_row);
4177                    rows.next();
4178                } else {
4179                    break;
4180                }
4181            }
4182
4183            let buffer_rows = rows_for_excerpt
4184                .drain(..)
4185                .map(|row| start_buffer_row + row - start_multibuffer_row);
4186            let buffer_indents = region
4187                .buffer
4188                .suggested_indents(buffer_rows, single_indent_size);
4189            let multibuffer_indents = buffer_indents.into_iter().map(|(row, indent)| {
4190                (
4191                    MultiBufferRow(start_multibuffer_row + row - start_buffer_row),
4192                    indent,
4193                )
4194            });
4195            result.extend(multibuffer_indents);
4196        }
4197
4198        result
4199    }
4200
4201    pub fn indent_size_for_line(&self, row: MultiBufferRow) -> IndentSize {
4202        if let Some((buffer, range)) = self.buffer_line_for_row(row) {
4203            let mut size = buffer.indent_size_for_line(range.start.row);
4204            size.len = size
4205                .len
4206                .min(range.end.column)
4207                .saturating_sub(range.start.column);
4208            size
4209        } else {
4210            IndentSize::spaces(0)
4211        }
4212    }
4213
4214    pub fn line_indent_for_row(&self, row: MultiBufferRow) -> LineIndent {
4215        if let Some((buffer, range)) = self.buffer_line_for_row(row) {
4216            LineIndent::from_iter(buffer.text_for_range(range).flat_map(|s| s.chars()))
4217        } else {
4218            LineIndent::spaces(0)
4219        }
4220    }
4221
4222    pub fn indent_and_comment_for_line(&self, row: MultiBufferRow, cx: &App) -> String {
4223        let mut indent = self.indent_size_for_line(row).chars().collect::<String>();
4224
4225        if self.settings_at(0, cx).extend_comment_on_newline {
4226            if let Some(language_scope) = self.language_scope_at(Point::new(row.0, 0)) {
4227                let delimiters = language_scope.line_comment_prefixes();
4228                for delimiter in delimiters {
4229                    if *self
4230                        .chars_at(Point::new(row.0, indent.len() as u32))
4231                        .take(delimiter.chars().count())
4232                        .collect::<String>()
4233                        .as_str()
4234                        == **delimiter
4235                    {
4236                        indent.push_str(&delimiter);
4237                        break;
4238                    }
4239                }
4240            }
4241        }
4242
4243        indent
4244    }
4245
4246    pub fn is_line_whitespace_upto<T>(&self, position: T) -> bool
4247    where
4248        T: ToOffset,
4249    {
4250        for char in self.reversed_chars_at(position) {
4251            if !char.is_whitespace() {
4252                return false;
4253            }
4254            if char == '\n' {
4255                return true;
4256            }
4257        }
4258        return true;
4259    }
4260
4261    pub fn prev_non_blank_row(&self, mut row: MultiBufferRow) -> Option<MultiBufferRow> {
4262        while row.0 > 0 {
4263            row.0 -= 1;
4264            if !self.is_line_blank(row) {
4265                return Some(row);
4266            }
4267        }
4268        None
4269    }
4270
4271    pub fn line_len(&self, row: MultiBufferRow) -> u32 {
4272        if let Some((_, range)) = self.buffer_line_for_row(row) {
4273            range.end.column - range.start.column
4274        } else {
4275            0
4276        }
4277    }
4278
4279    pub fn buffer_line_for_row(
4280        &self,
4281        row: MultiBufferRow,
4282    ) -> Option<(&BufferSnapshot, Range<Point>)> {
4283        let mut cursor = self.cursor::<Point>();
4284        let point = Point::new(row.0, 0);
4285        cursor.seek(&point);
4286        let region = cursor.region()?;
4287        let overshoot = point.min(region.range.end) - region.range.start;
4288        let buffer_point = region.buffer_range.start + overshoot;
4289        if buffer_point.row > region.buffer_range.end.row {
4290            return None;
4291        }
4292        let line_start = Point::new(buffer_point.row, 0).max(region.buffer_range.start);
4293        let line_end = Point::new(buffer_point.row, region.buffer.line_len(buffer_point.row))
4294            .min(region.buffer_range.end);
4295        Some((region.buffer, line_start..line_end))
4296    }
4297
4298    pub fn max_point(&self) -> Point {
4299        self.text_summary().lines
4300    }
4301
4302    pub fn max_row(&self) -> MultiBufferRow {
4303        MultiBufferRow(self.text_summary().lines.row)
4304    }
4305
4306    pub fn text_summary(&self) -> TextSummary {
4307        self.diff_transforms.summary().output
4308    }
4309
4310    pub fn text_summary_for_range<D, O>(&self, range: Range<O>) -> D
4311    where
4312        D: TextDimension,
4313        O: ToOffset,
4314    {
4315        let range = range.start.to_offset(self)..range.end.to_offset(self);
4316        let mut cursor = self.diff_transforms.cursor::<(usize, ExcerptOffset)>(&());
4317        cursor.seek(&range.start, Bias::Right, &());
4318
4319        let Some(first_transform) = cursor.item() else {
4320            return D::from_text_summary(&TextSummary::default());
4321        };
4322
4323        let diff_transform_start = cursor.start().0;
4324        let diff_transform_end = cursor.end(&()).0;
4325        let diff_start = range.start;
4326        let start_overshoot = diff_start - diff_transform_start;
4327        let end_overshoot = std::cmp::min(range.end, diff_transform_end) - diff_transform_start;
4328
4329        let mut result = match first_transform {
4330            DiffTransform::BufferContent { .. } => {
4331                let excerpt_start = cursor.start().1 + ExcerptOffset::new(start_overshoot);
4332                let excerpt_end = cursor.start().1 + ExcerptOffset::new(end_overshoot);
4333                self.text_summary_for_excerpt_offset_range(excerpt_start..excerpt_end)
4334            }
4335            DiffTransform::DeletedHunk {
4336                buffer_id,
4337                base_text_byte_range,
4338                has_trailing_newline,
4339                ..
4340            } => {
4341                let buffer_start = base_text_byte_range.start + start_overshoot;
4342                let mut buffer_end = base_text_byte_range.start + end_overshoot;
4343                let Some(base_text) = self.diffs.get(buffer_id).and_then(|diff| diff.base_text())
4344                else {
4345                    panic!("{:?} is in non-existent deleted hunk", range.start)
4346                };
4347
4348                let include_trailing_newline =
4349                    *has_trailing_newline && range.end >= diff_transform_end;
4350                if include_trailing_newline {
4351                    buffer_end -= 1;
4352                }
4353
4354                let mut summary =
4355                    base_text.text_summary_for_range::<D, _>(buffer_start..buffer_end);
4356
4357                if include_trailing_newline {
4358                    summary.add_assign(&D::from_text_summary(&TextSummary::newline()))
4359                }
4360
4361                summary
4362            }
4363        };
4364        if range.end < diff_transform_end {
4365            return result;
4366        }
4367
4368        cursor.next(&());
4369        result.add_assign(&D::from_text_summary(&cursor.summary(
4370            &range.end,
4371            Bias::Right,
4372            &(),
4373        )));
4374
4375        let Some(last_transform) = cursor.item() else {
4376            return result;
4377        };
4378
4379        let overshoot = range.end - cursor.start().0;
4380        let suffix = match last_transform {
4381            DiffTransform::BufferContent { .. } => {
4382                let end = cursor.start().1 + ExcerptOffset::new(overshoot);
4383                self.text_summary_for_excerpt_offset_range::<D>(cursor.start().1..end)
4384            }
4385            DiffTransform::DeletedHunk {
4386                base_text_byte_range,
4387                buffer_id,
4388                has_trailing_newline,
4389                ..
4390            } => {
4391                let buffer_end = base_text_byte_range.start + overshoot;
4392                let Some(base_text) = self.diffs.get(buffer_id).and_then(|diff| diff.base_text())
4393                else {
4394                    panic!("{:?} is in non-existent deleted hunk", range.end)
4395                };
4396
4397                let mut suffix = base_text
4398                    .text_summary_for_range::<D, _>(base_text_byte_range.start..buffer_end);
4399                if *has_trailing_newline && buffer_end == base_text_byte_range.end + 1 {
4400                    suffix.add_assign(&D::from_text_summary(&TextSummary::newline()))
4401                }
4402                suffix
4403            }
4404        };
4405
4406        result.add_assign(&suffix);
4407        result
4408    }
4409
4410    fn text_summary_for_excerpt_offset_range<D>(&self, mut range: Range<ExcerptOffset>) -> D
4411    where
4412        D: TextDimension,
4413    {
4414        // let mut range = range.start..range.end;
4415        let mut summary = D::zero(&());
4416        let mut cursor = self.excerpts.cursor::<ExcerptOffset>(&());
4417        cursor.seek(&range.start, Bias::Right, &());
4418        if let Some(excerpt) = cursor.item() {
4419            let mut end_before_newline = cursor.end(&());
4420            if excerpt.has_trailing_newline {
4421                end_before_newline -= ExcerptOffset::new(1);
4422            }
4423
4424            let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
4425            let start_in_excerpt = excerpt_start + (range.start - *cursor.start()).value;
4426            let end_in_excerpt =
4427                excerpt_start + (cmp::min(end_before_newline, range.end) - *cursor.start()).value;
4428            summary.add_assign(
4429                &excerpt
4430                    .buffer
4431                    .text_summary_for_range(start_in_excerpt..end_in_excerpt),
4432            );
4433
4434            if range.end > end_before_newline {
4435                summary.add_assign(&D::from_text_summary(&TextSummary::from("\n")));
4436            }
4437
4438            cursor.next(&());
4439        }
4440
4441        if range.end > *cursor.start() {
4442            summary.add_assign(
4443                &cursor
4444                    .summary::<_, ExcerptDimension<D>>(&range.end, Bias::Right, &())
4445                    .0,
4446            );
4447            if let Some(excerpt) = cursor.item() {
4448                range.end = cmp::max(*cursor.start(), range.end);
4449
4450                let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
4451                let end_in_excerpt = excerpt_start + (range.end - *cursor.start()).value;
4452                summary.add_assign(
4453                    &excerpt
4454                        .buffer
4455                        .text_summary_for_range(excerpt_start..end_in_excerpt),
4456                );
4457            }
4458        }
4459
4460        summary
4461    }
4462
4463    pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
4464    where
4465        D: TextDimension + Ord + Sub<D, Output = D>,
4466    {
4467        self.summaries_for_anchors([anchor])[0]
4468    }
4469
4470    fn resolve_summary_for_anchor<D>(
4471        &self,
4472        anchor: &Anchor,
4473        excerpt_position: D,
4474        diff_transforms: &mut Cursor<DiffTransform, (ExcerptDimension<D>, OutputDimension<D>)>,
4475    ) -> D
4476    where
4477        D: TextDimension + Ord + Sub<D, Output = D>,
4478    {
4479        loop {
4480            let transform_end_position = diff_transforms.end(&()).0 .0;
4481            let at_transform_end =
4482                excerpt_position == transform_end_position && diff_transforms.item().is_some();
4483            if at_transform_end && anchor.text_anchor.bias == Bias::Right {
4484                diff_transforms.next(&());
4485                continue;
4486            }
4487
4488            let mut position = diff_transforms.start().1 .0;
4489            match diff_transforms.item() {
4490                Some(DiffTransform::DeletedHunk {
4491                    buffer_id,
4492                    base_text_byte_range,
4493                    ..
4494                }) => {
4495                    let mut in_deleted_hunk = false;
4496                    if let Some(diff_base_anchor) = &anchor.diff_base_anchor {
4497                        if let Some(base_text) =
4498                            self.diffs.get(buffer_id).and_then(|diff| diff.base_text())
4499                        {
4500                            if base_text.can_resolve(&diff_base_anchor) {
4501                                let base_text_offset = diff_base_anchor.to_offset(&base_text);
4502                                if base_text_offset >= base_text_byte_range.start
4503                                    && base_text_offset <= base_text_byte_range.end
4504                                {
4505                                    let position_in_hunk = base_text
4506                                        .text_summary_for_range::<D, _>(
4507                                            base_text_byte_range.start..base_text_offset,
4508                                        );
4509                                    position.add_assign(&position_in_hunk);
4510                                    in_deleted_hunk = true;
4511                                } else if at_transform_end {
4512                                    diff_transforms.next(&());
4513                                    continue;
4514                                }
4515                            }
4516                        }
4517                    }
4518                    if !in_deleted_hunk {
4519                        position = diff_transforms.end(&()).1 .0;
4520                    }
4521                }
4522                _ => {
4523                    if at_transform_end && anchor.diff_base_anchor.is_some() {
4524                        diff_transforms.next(&());
4525                        continue;
4526                    }
4527                    let overshoot = excerpt_position - diff_transforms.start().0 .0;
4528                    position.add_assign(&overshoot);
4529                }
4530            }
4531
4532            return position;
4533        }
4534    }
4535
4536    fn excerpt_offset_for_anchor(&self, anchor: &Anchor) -> ExcerptOffset {
4537        let mut cursor = self
4538            .excerpts
4539            .cursor::<(Option<&Locator>, ExcerptOffset)>(&());
4540        let locator = self.excerpt_locator_for_id(anchor.excerpt_id);
4541
4542        cursor.seek(&Some(locator), Bias::Left, &());
4543        if cursor.item().is_none() {
4544            cursor.next(&());
4545        }
4546
4547        let mut position = cursor.start().1;
4548        if let Some(excerpt) = cursor.item() {
4549            if excerpt.id == anchor.excerpt_id {
4550                let excerpt_buffer_start = excerpt
4551                    .buffer
4552                    .offset_for_anchor(&excerpt.range.context.start);
4553                let excerpt_buffer_end =
4554                    excerpt.buffer.offset_for_anchor(&excerpt.range.context.end);
4555                let buffer_position = cmp::min(
4556                    excerpt_buffer_end,
4557                    excerpt.buffer.offset_for_anchor(&anchor.text_anchor),
4558                );
4559                if buffer_position > excerpt_buffer_start {
4560                    position.value += buffer_position - excerpt_buffer_start;
4561                }
4562            }
4563        }
4564        position
4565    }
4566
4567    pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
4568    where
4569        D: TextDimension + Ord + Sub<D, Output = D>,
4570        I: 'a + IntoIterator<Item = &'a Anchor>,
4571    {
4572        let mut anchors = anchors.into_iter().peekable();
4573        let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&());
4574        let mut diff_transforms_cursor = self
4575            .diff_transforms
4576            .cursor::<(ExcerptDimension<D>, OutputDimension<D>)>(&());
4577        diff_transforms_cursor.next(&());
4578
4579        let mut summaries = Vec::new();
4580        while let Some(anchor) = anchors.peek() {
4581            let excerpt_id = anchor.excerpt_id;
4582            let excerpt_anchors = iter::from_fn(|| {
4583                let anchor = anchors.peek()?;
4584                if anchor.excerpt_id == excerpt_id {
4585                    Some(anchors.next().unwrap())
4586                } else {
4587                    None
4588                }
4589            });
4590
4591            let locator = self.excerpt_locator_for_id(excerpt_id);
4592            cursor.seek_forward(locator, Bias::Left, &());
4593            if cursor.item().is_none() {
4594                cursor.next(&());
4595            }
4596
4597            let excerpt_start_position = D::from_text_summary(&cursor.start().text);
4598            if let Some(excerpt) = cursor.item() {
4599                if excerpt.id != excerpt_id {
4600                    let position = self.resolve_summary_for_anchor(
4601                        &Anchor::min(),
4602                        excerpt_start_position,
4603                        &mut diff_transforms_cursor,
4604                    );
4605                    summaries.extend(excerpt_anchors.map(|_| position));
4606                    continue;
4607                }
4608                let excerpt_buffer_start =
4609                    excerpt.range.context.start.summary::<D>(&excerpt.buffer);
4610                let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer);
4611                for (buffer_summary, anchor) in excerpt
4612                    .buffer
4613                    .summaries_for_anchors_with_payload::<D, _, _>(
4614                        excerpt_anchors.map(|a| (&a.text_anchor, a)),
4615                    )
4616                {
4617                    let summary = cmp::min(excerpt_buffer_end, buffer_summary);
4618                    let mut position = excerpt_start_position;
4619                    if summary > excerpt_buffer_start {
4620                        position.add_assign(&(summary - excerpt_buffer_start));
4621                    }
4622
4623                    if position > diff_transforms_cursor.start().0 .0 {
4624                        diff_transforms_cursor.seek_forward(
4625                            &ExcerptDimension(position),
4626                            Bias::Left,
4627                            &(),
4628                        );
4629                    }
4630
4631                    summaries.push(self.resolve_summary_for_anchor(
4632                        anchor,
4633                        position,
4634                        &mut diff_transforms_cursor,
4635                    ));
4636                }
4637            } else {
4638                diff_transforms_cursor.seek_forward(
4639                    &ExcerptDimension(excerpt_start_position),
4640                    Bias::Left,
4641                    &(),
4642                );
4643                let position = self.resolve_summary_for_anchor(
4644                    &Anchor::max(),
4645                    excerpt_start_position,
4646                    &mut diff_transforms_cursor,
4647                );
4648                summaries.extend(excerpt_anchors.map(|_| position));
4649            }
4650        }
4651
4652        summaries
4653    }
4654
4655    pub fn dimensions_from_points<'a, D>(
4656        &'a self,
4657        points: impl 'a + IntoIterator<Item = Point>,
4658    ) -> impl 'a + Iterator<Item = D>
4659    where
4660        D: TextDimension + Sub<D, Output = D>,
4661    {
4662        let mut cursor = self.cursor::<DimensionPair<Point, D>>();
4663        cursor.seek(&DimensionPair {
4664            key: Point::default(),
4665            value: None,
4666        });
4667        let mut points = points.into_iter();
4668        iter::from_fn(move || {
4669            let point = points.next()?;
4670
4671            cursor.seek_forward(&DimensionPair {
4672                key: point,
4673                value: None,
4674            });
4675
4676            if let Some(region) = cursor.region() {
4677                let overshoot = point - region.range.start.key;
4678                let buffer_point = region.buffer_range.start.key + overshoot;
4679                let mut position = region.range.start.value.unwrap();
4680                position.add_assign(
4681                    &region
4682                        .buffer
4683                        .text_summary_for_range(region.buffer_range.start.key..buffer_point),
4684                );
4685                return Some(position);
4686            } else {
4687                return Some(D::from_text_summary(&self.text_summary()));
4688            }
4689        })
4690    }
4691
4692    pub fn refresh_anchors<'a, I>(&'a self, anchors: I) -> Vec<(usize, Anchor, bool)>
4693    where
4694        I: 'a + IntoIterator<Item = &'a Anchor>,
4695    {
4696        let mut anchors = anchors.into_iter().enumerate().peekable();
4697        let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
4698        cursor.next(&());
4699
4700        let mut result = Vec::new();
4701
4702        while let Some((_, anchor)) = anchors.peek() {
4703            let old_excerpt_id = anchor.excerpt_id;
4704
4705            // Find the location where this anchor's excerpt should be.
4706            let old_locator = self.excerpt_locator_for_id(old_excerpt_id);
4707            cursor.seek_forward(&Some(old_locator), Bias::Left, &());
4708
4709            if cursor.item().is_none() {
4710                cursor.next(&());
4711            }
4712
4713            let next_excerpt = cursor.item();
4714            let prev_excerpt = cursor.prev_item();
4715
4716            // Process all of the anchors for this excerpt.
4717            while let Some((_, anchor)) = anchors.peek() {
4718                if anchor.excerpt_id != old_excerpt_id {
4719                    break;
4720                }
4721                let (anchor_ix, anchor) = anchors.next().unwrap();
4722                let mut anchor = *anchor;
4723
4724                // Leave min and max anchors unchanged if invalid or
4725                // if the old excerpt still exists at this location
4726                let mut kept_position = next_excerpt
4727                    .map_or(false, |e| e.id == old_excerpt_id && e.contains(&anchor))
4728                    || old_excerpt_id == ExcerptId::max()
4729                    || old_excerpt_id == ExcerptId::min();
4730
4731                // If the old excerpt no longer exists at this location, then attempt to
4732                // find an equivalent position for this anchor in an adjacent excerpt.
4733                if !kept_position {
4734                    for excerpt in [next_excerpt, prev_excerpt].iter().filter_map(|e| *e) {
4735                        if excerpt.contains(&anchor) {
4736                            anchor.excerpt_id = excerpt.id;
4737                            kept_position = true;
4738                            break;
4739                        }
4740                    }
4741                }
4742
4743                // If there's no adjacent excerpt that contains the anchor's position,
4744                // then report that the anchor has lost its position.
4745                if !kept_position {
4746                    anchor = if let Some(excerpt) = next_excerpt {
4747                        let mut text_anchor = excerpt
4748                            .range
4749                            .context
4750                            .start
4751                            .bias(anchor.text_anchor.bias, &excerpt.buffer);
4752                        if text_anchor
4753                            .cmp(&excerpt.range.context.end, &excerpt.buffer)
4754                            .is_gt()
4755                        {
4756                            text_anchor = excerpt.range.context.end;
4757                        }
4758                        Anchor {
4759                            buffer_id: Some(excerpt.buffer_id),
4760                            excerpt_id: excerpt.id,
4761                            text_anchor,
4762                            diff_base_anchor: None,
4763                        }
4764                    } else if let Some(excerpt) = prev_excerpt {
4765                        let mut text_anchor = excerpt
4766                            .range
4767                            .context
4768                            .end
4769                            .bias(anchor.text_anchor.bias, &excerpt.buffer);
4770                        if text_anchor
4771                            .cmp(&excerpt.range.context.start, &excerpt.buffer)
4772                            .is_lt()
4773                        {
4774                            text_anchor = excerpt.range.context.start;
4775                        }
4776                        Anchor {
4777                            buffer_id: Some(excerpt.buffer_id),
4778                            excerpt_id: excerpt.id,
4779                            text_anchor,
4780                            diff_base_anchor: None,
4781                        }
4782                    } else if anchor.text_anchor.bias == Bias::Left {
4783                        Anchor::min()
4784                    } else {
4785                        Anchor::max()
4786                    };
4787                }
4788
4789                result.push((anchor_ix, anchor, kept_position));
4790            }
4791        }
4792        result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self));
4793        result
4794    }
4795
4796    pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
4797        self.anchor_at(position, Bias::Left)
4798    }
4799
4800    pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
4801        self.anchor_at(position, Bias::Right)
4802    }
4803
4804    pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
4805        let offset = position.to_offset(self);
4806
4807        // Find the given position in the diff transforms. Determine the corresponding
4808        // offset in the excerpts, and whether the position is within a deleted hunk.
4809        let mut diff_transforms = self.diff_transforms.cursor::<(usize, ExcerptOffset)>(&());
4810        diff_transforms.seek(&offset, Bias::Right, &());
4811
4812        if offset == diff_transforms.start().0 && bias == Bias::Left {
4813            if let Some(prev_item) = diff_transforms.prev_item() {
4814                match prev_item {
4815                    DiffTransform::DeletedHunk { .. } => {
4816                        diff_transforms.prev(&());
4817                    }
4818                    _ => {}
4819                }
4820            }
4821        }
4822        let offset_in_transform = offset - diff_transforms.start().0;
4823        let mut excerpt_offset = diff_transforms.start().1;
4824        let mut diff_base_anchor = None;
4825        if let Some(DiffTransform::DeletedHunk {
4826            buffer_id,
4827            base_text_byte_range,
4828            has_trailing_newline,
4829            ..
4830        }) = diff_transforms.item()
4831        {
4832            let base_text = self
4833                .diffs
4834                .get(buffer_id)
4835                .and_then(|diff| diff.base_text())
4836                .expect("missing diff base");
4837            if offset_in_transform > base_text_byte_range.len() {
4838                debug_assert!(*has_trailing_newline);
4839                bias = Bias::Right;
4840            } else {
4841                diff_base_anchor = Some(
4842                    base_text.anchor_at(base_text_byte_range.start + offset_in_transform, bias),
4843                );
4844                bias = Bias::Left;
4845            }
4846        } else {
4847            excerpt_offset += ExcerptOffset::new(offset_in_transform);
4848        };
4849
4850        if let Some((excerpt_id, buffer_id, buffer)) = self.as_singleton() {
4851            return Anchor {
4852                buffer_id: Some(buffer_id),
4853                excerpt_id: *excerpt_id,
4854                text_anchor: buffer.anchor_at(excerpt_offset.value, bias),
4855                diff_base_anchor,
4856            };
4857        }
4858
4859        let mut excerpts = self
4860            .excerpts
4861            .cursor::<(ExcerptOffset, Option<ExcerptId>)>(&());
4862        excerpts.seek(&excerpt_offset, Bias::Right, &());
4863        if excerpts.item().is_none() && excerpt_offset == excerpts.start().0 && bias == Bias::Left {
4864            excerpts.prev(&());
4865        }
4866        if let Some(excerpt) = excerpts.item() {
4867            let mut overshoot = excerpt_offset.saturating_sub(excerpts.start().0).value;
4868            if excerpt.has_trailing_newline && excerpt_offset == excerpts.end(&()).0 {
4869                overshoot -= 1;
4870                bias = Bias::Right;
4871            }
4872
4873            let buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
4874            let text_anchor =
4875                excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
4876            Anchor {
4877                buffer_id: Some(excerpt.buffer_id),
4878                excerpt_id: excerpt.id,
4879                text_anchor,
4880                diff_base_anchor,
4881            }
4882        } else if excerpt_offset.is_zero() && bias == Bias::Left {
4883            Anchor::min()
4884        } else {
4885            Anchor::max()
4886        }
4887    }
4888
4889    /// Returns an anchor for the given excerpt and text anchor,
4890    /// returns None if the excerpt_id is no longer valid.
4891    pub fn anchor_in_excerpt(
4892        &self,
4893        excerpt_id: ExcerptId,
4894        text_anchor: text::Anchor,
4895    ) -> Option<Anchor> {
4896        let locator = self.excerpt_locator_for_id(excerpt_id);
4897        let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
4898        cursor.seek(locator, Bias::Left, &());
4899        if let Some(excerpt) = cursor.item() {
4900            if excerpt.id == excerpt_id {
4901                let text_anchor = excerpt.clip_anchor(text_anchor);
4902                drop(cursor);
4903                return Some(Anchor {
4904                    buffer_id: Some(excerpt.buffer_id),
4905                    excerpt_id,
4906                    text_anchor,
4907                    diff_base_anchor: None,
4908                });
4909            }
4910        }
4911        None
4912    }
4913
4914    pub fn context_range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<Range<text::Anchor>> {
4915        Some(self.excerpt(excerpt_id)?.range.context.clone())
4916    }
4917
4918    pub fn can_resolve(&self, anchor: &Anchor) -> bool {
4919        if anchor.excerpt_id == ExcerptId::min() || anchor.excerpt_id == ExcerptId::max() {
4920            true
4921        } else if let Some(excerpt) = self.excerpt(anchor.excerpt_id) {
4922            excerpt.buffer.can_resolve(&anchor.text_anchor)
4923        } else {
4924            false
4925        }
4926    }
4927
4928    pub fn excerpts(
4929        &self,
4930    ) -> impl Iterator<Item = (ExcerptId, &BufferSnapshot, ExcerptRange<text::Anchor>)> {
4931        self.excerpts
4932            .iter()
4933            .map(|excerpt| (excerpt.id, &excerpt.buffer, excerpt.range.clone()))
4934    }
4935
4936    fn cursor<D: TextDimension + Default>(&self) -> MultiBufferCursor<D> {
4937        let excerpts = self.excerpts.cursor(&());
4938        let diff_transforms = self.diff_transforms.cursor(&());
4939        MultiBufferCursor {
4940            excerpts,
4941            diff_transforms,
4942            diffs: &self.diffs,
4943            cached_region: None,
4944        }
4945    }
4946
4947    pub fn excerpt_before(&self, id: ExcerptId) -> Option<MultiBufferExcerpt<'_>> {
4948        let start_locator = self.excerpt_locator_for_id(id);
4949        let mut excerpts = self
4950            .excerpts
4951            .cursor::<(Option<&Locator>, ExcerptDimension<usize>)>(&());
4952        excerpts.seek(&Some(start_locator), Bias::Left, &());
4953        excerpts.prev(&());
4954
4955        let mut diff_transforms = self
4956            .diff_transforms
4957            .cursor::<(OutputDimension<usize>, ExcerptDimension<usize>)>(&());
4958        diff_transforms.seek(&excerpts.start().1, Bias::Left, &());
4959        if diff_transforms.end(&()).1 < excerpts.start().1 {
4960            diff_transforms.next(&());
4961        }
4962
4963        let excerpt = excerpts.item()?;
4964        Some(MultiBufferExcerpt {
4965            excerpt,
4966            offset: diff_transforms.start().0 .0,
4967            buffer_offset: excerpt.range.context.start.to_offset(&excerpt.buffer),
4968            excerpt_offset: excerpts.start().1.clone(),
4969            diff_transforms,
4970        })
4971    }
4972
4973    pub fn excerpt_boundaries_in_range<R, T>(
4974        &self,
4975        range: R,
4976    ) -> impl Iterator<Item = ExcerptBoundary> + '_
4977    where
4978        R: RangeBounds<T>,
4979        T: ToOffset,
4980    {
4981        let start_offset;
4982        let start = match range.start_bound() {
4983            Bound::Included(start) => {
4984                start_offset = start.to_offset(self);
4985                Bound::Included(start_offset)
4986            }
4987            Bound::Excluded(_) => {
4988                panic!("not supported")
4989            }
4990            Bound::Unbounded => {
4991                start_offset = 0;
4992                Bound::Unbounded
4993            }
4994        };
4995        let end = match range.end_bound() {
4996            Bound::Included(end) => Bound::Included(end.to_offset(self)),
4997            Bound::Excluded(end) => Bound::Excluded(end.to_offset(self)),
4998            Bound::Unbounded => Bound::Unbounded,
4999        };
5000        let bounds = (start, end);
5001
5002        let mut cursor = self.cursor::<DimensionPair<usize, Point>>();
5003        cursor.seek(&DimensionPair {
5004            key: start_offset,
5005            value: None,
5006        });
5007
5008        if cursor
5009            .region()
5010            .is_some_and(|region| bounds.contains(&region.range.start.key))
5011        {
5012            cursor.prev_excerpt();
5013        } else {
5014            cursor.seek_to_start_of_current_excerpt();
5015        }
5016        let mut prev_region = cursor.region();
5017
5018        cursor.next_excerpt();
5019
5020        let mut visited_end = false;
5021        iter::from_fn(move || loop {
5022            if self.singleton {
5023                return None;
5024            }
5025
5026            let next_region = cursor.region();
5027            cursor.next_excerpt();
5028
5029            let next_region_start = if let Some(region) = &next_region {
5030                if !bounds.contains(&region.range.start.key) {
5031                    prev_region = next_region;
5032                    continue;
5033                }
5034                region.range.start.value.unwrap()
5035            } else {
5036                if !bounds.contains(&self.len()) {
5037                    return None;
5038                }
5039                self.max_point()
5040            };
5041            let next_region_end = if let Some(region) = cursor.region() {
5042                region.range.start.value.unwrap()
5043            } else {
5044                self.max_point()
5045            };
5046
5047            let prev = prev_region.as_ref().map(|region| ExcerptInfo {
5048                id: region.excerpt.id,
5049                buffer: region.excerpt.buffer.clone(),
5050                buffer_id: region.excerpt.buffer_id,
5051                range: region.excerpt.range.clone(),
5052                end_row: MultiBufferRow(next_region_start.row),
5053            });
5054
5055            let next = next_region.as_ref().map(|region| ExcerptInfo {
5056                id: region.excerpt.id,
5057                buffer: region.excerpt.buffer.clone(),
5058                buffer_id: region.excerpt.buffer_id,
5059                range: region.excerpt.range.clone(),
5060                end_row: if region.excerpt.has_trailing_newline {
5061                    MultiBufferRow(next_region_end.row - 1)
5062                } else {
5063                    MultiBufferRow(next_region_end.row)
5064                },
5065            });
5066
5067            if next.is_none() {
5068                if visited_end {
5069                    return None;
5070                } else {
5071                    visited_end = true;
5072                }
5073            }
5074
5075            let row = MultiBufferRow(next_region_start.row);
5076
5077            prev_region = next_region;
5078
5079            return Some(ExcerptBoundary { row, prev, next });
5080        })
5081    }
5082
5083    pub fn edit_count(&self) -> usize {
5084        self.edit_count
5085    }
5086
5087    pub fn non_text_state_update_count(&self) -> usize {
5088        self.non_text_state_update_count
5089    }
5090
5091    /// Returns the smallest enclosing bracket ranges containing the given range or
5092    /// None if no brackets contain range or the range is not contained in a single
5093    /// excerpt
5094    ///
5095    /// Can optionally pass a range_filter to filter the ranges of brackets to consider
5096    pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
5097        &self,
5098        range: Range<T>,
5099        range_filter: Option<&dyn Fn(&BufferSnapshot, Range<usize>, Range<usize>) -> bool>,
5100    ) -> Option<(Range<usize>, Range<usize>)> {
5101        let range = range.start.to_offset(self)..range.end.to_offset(self);
5102        let mut excerpt = self.excerpt_containing(range.clone())?;
5103        let buffer = excerpt.buffer();
5104        let excerpt_buffer_range = excerpt.buffer_range();
5105
5106        // Filter to ranges contained in the excerpt
5107        let range_filter = |open: Range<usize>, close: Range<usize>| -> bool {
5108            excerpt_buffer_range.contains(&open.start)
5109                && excerpt_buffer_range.contains(&close.end)
5110                && range_filter.map_or(true, |filter| filter(buffer, open, close))
5111        };
5112
5113        let (open, close) = excerpt.buffer().innermost_enclosing_bracket_ranges(
5114            excerpt.map_range_to_buffer(range),
5115            Some(&range_filter),
5116        )?;
5117
5118        Some((
5119            excerpt.map_range_from_buffer(open),
5120            excerpt.map_range_from_buffer(close),
5121        ))
5122    }
5123
5124    /// Returns enclosing bracket ranges containing the given range or returns None if the range is
5125    /// not contained in a single excerpt
5126    pub fn enclosing_bracket_ranges<T: ToOffset>(
5127        &self,
5128        range: Range<T>,
5129    ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + '_> {
5130        let range = range.start.to_offset(self)..range.end.to_offset(self);
5131        let mut excerpt = self.excerpt_containing(range.clone())?;
5132
5133        Some(
5134            excerpt
5135                .buffer()
5136                .enclosing_bracket_ranges(excerpt.map_range_to_buffer(range))
5137                .filter_map(move |(open, close)| {
5138                    if excerpt.contains_buffer_range(open.start..close.end) {
5139                        Some((
5140                            excerpt.map_range_from_buffer(open),
5141                            excerpt.map_range_from_buffer(close),
5142                        ))
5143                    } else {
5144                        None
5145                    }
5146                }),
5147        )
5148    }
5149
5150    /// Returns enclosing bracket ranges containing the given range or returns None if the range is
5151    /// not contained in a single excerpt
5152    pub fn text_object_ranges<T: ToOffset>(
5153        &self,
5154        range: Range<T>,
5155        options: TreeSitterOptions,
5156    ) -> impl Iterator<Item = (Range<usize>, TextObject)> + '_ {
5157        let range = range.start.to_offset(self)..range.end.to_offset(self);
5158        self.excerpt_containing(range.clone())
5159            .map(|mut excerpt| {
5160                excerpt
5161                    .buffer()
5162                    .text_object_ranges(excerpt.map_range_to_buffer(range), options)
5163                    .filter_map(move |(range, text_object)| {
5164                        if excerpt.contains_buffer_range(range.clone()) {
5165                            Some((excerpt.map_range_from_buffer(range), text_object))
5166                        } else {
5167                            None
5168                        }
5169                    })
5170            })
5171            .into_iter()
5172            .flatten()
5173    }
5174
5175    /// Returns bracket range pairs overlapping the given `range` or returns None if the `range` is
5176    /// not contained in a single excerpt
5177    pub fn bracket_ranges<T: ToOffset>(
5178        &self,
5179        range: Range<T>,
5180    ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + '_> {
5181        let range = range.start.to_offset(self)..range.end.to_offset(self);
5182        let mut excerpt = self.excerpt_containing(range.clone())?;
5183
5184        Some(
5185            excerpt
5186                .buffer()
5187                .bracket_ranges(excerpt.map_range_to_buffer(range))
5188                .filter_map(move |(start_bracket_range, close_bracket_range)| {
5189                    let buffer_range = start_bracket_range.start..close_bracket_range.end;
5190                    if excerpt.contains_buffer_range(buffer_range) {
5191                        Some((
5192                            excerpt.map_range_from_buffer(start_bracket_range),
5193                            excerpt.map_range_from_buffer(close_bracket_range),
5194                        ))
5195                    } else {
5196                        None
5197                    }
5198                }),
5199        )
5200    }
5201
5202    pub fn redacted_ranges<'a, T: ToOffset>(
5203        &'a self,
5204        range: Range<T>,
5205        redaction_enabled: impl Fn(Option<&Arc<dyn File>>) -> bool + 'a,
5206    ) -> impl Iterator<Item = Range<usize>> + 'a {
5207        let range = range.start.to_offset(self)..range.end.to_offset(self);
5208        self.lift_buffer_metadata(range, move |buffer, range| {
5209            if redaction_enabled(buffer.file()) {
5210                Some(buffer.redacted_ranges(range).map(|range| (range, ())))
5211            } else {
5212                None
5213            }
5214        })
5215        .map(|(range, _, _)| range)
5216    }
5217
5218    pub fn runnable_ranges(
5219        &self,
5220        range: Range<Anchor>,
5221    ) -> impl Iterator<Item = language::RunnableRange> + '_ {
5222        let range = range.start.to_offset(self)..range.end.to_offset(self);
5223        self.lift_buffer_metadata(range, move |buffer, range| {
5224            Some(
5225                buffer
5226                    .runnable_ranges(range.clone())
5227                    .filter(move |runnable| {
5228                        runnable.run_range.start >= range.start
5229                            && runnable.run_range.end < range.end
5230                    })
5231                    .map(|runnable| (runnable.run_range.clone(), runnable)),
5232            )
5233        })
5234        .map(|(run_range, runnable, _)| language::RunnableRange {
5235            run_range,
5236            ..runnable
5237        })
5238    }
5239
5240    pub fn line_indents(
5241        &self,
5242        start_row: MultiBufferRow,
5243        buffer_filter: impl Fn(&BufferSnapshot) -> bool,
5244    ) -> impl Iterator<Item = (MultiBufferRow, LineIndent, &BufferSnapshot)> {
5245        let max_point = self.max_point();
5246        let mut cursor = self.cursor::<Point>();
5247        cursor.seek(&Point::new(start_row.0, 0));
5248        iter::from_fn(move || {
5249            let mut region = cursor.region()?;
5250            while !buffer_filter(&region.excerpt.buffer) {
5251                cursor.next();
5252                region = cursor.region()?;
5253            }
5254            let overshoot = start_row.0.saturating_sub(region.range.start.row);
5255            let buffer_start_row =
5256                (region.buffer_range.start.row + overshoot).min(region.buffer_range.end.row);
5257
5258            let buffer_end_row = if region.is_main_buffer
5259                && (region.has_trailing_newline || region.range.end == max_point)
5260            {
5261                region.buffer_range.end.row
5262            } else {
5263                region.buffer_range.end.row.saturating_sub(1)
5264            };
5265
5266            let line_indents = region
5267                .buffer
5268                .line_indents_in_row_range(buffer_start_row..buffer_end_row);
5269            cursor.next();
5270            return Some(line_indents.map(move |(buffer_row, indent)| {
5271                let row = region.range.start.row + (buffer_row - region.buffer_range.start.row);
5272                (MultiBufferRow(row), indent, &region.excerpt.buffer)
5273            }));
5274        })
5275        .flatten()
5276    }
5277
5278    pub fn reversed_line_indents(
5279        &self,
5280        end_row: MultiBufferRow,
5281        buffer_filter: impl Fn(&BufferSnapshot) -> bool,
5282    ) -> impl Iterator<Item = (MultiBufferRow, LineIndent, &BufferSnapshot)> {
5283        let max_point = self.max_point();
5284        let mut cursor = self.cursor::<Point>();
5285        cursor.seek(&Point::new(end_row.0, 0));
5286        iter::from_fn(move || {
5287            let mut region = cursor.region()?;
5288            while !buffer_filter(&region.excerpt.buffer) {
5289                cursor.prev();
5290                region = cursor.region()?;
5291            }
5292
5293            let buffer_start_row = region.buffer_range.start.row;
5294            let buffer_end_row = if region.is_main_buffer
5295                && (region.has_trailing_newline || region.range.end == max_point)
5296            {
5297                region.buffer_range.end.row + 1
5298            } else {
5299                region.buffer_range.end.row
5300            };
5301
5302            let overshoot = end_row.0 - region.range.start.row;
5303            let buffer_end_row =
5304                (region.buffer_range.start.row + overshoot + 1).min(buffer_end_row);
5305
5306            let line_indents = region
5307                .buffer
5308                .reversed_line_indents_in_row_range(buffer_start_row..buffer_end_row);
5309            cursor.prev();
5310            return Some(line_indents.map(move |(buffer_row, indent)| {
5311                let row = region.range.start.row + (buffer_row - region.buffer_range.start.row);
5312                (MultiBufferRow(row), indent, &region.excerpt.buffer)
5313            }));
5314        })
5315        .flatten()
5316    }
5317
5318    pub async fn enclosing_indent(
5319        &self,
5320        mut target_row: MultiBufferRow,
5321    ) -> Option<(Range<MultiBufferRow>, LineIndent)> {
5322        let max_row = MultiBufferRow(self.max_point().row);
5323        if target_row >= max_row {
5324            return None;
5325        }
5326
5327        let mut target_indent = self.line_indent_for_row(target_row);
5328
5329        // If the current row is at the start of an indented block, we want to return this
5330        // block as the enclosing indent.
5331        if !target_indent.is_line_empty() && target_row < max_row {
5332            let next_line_indent = self.line_indent_for_row(MultiBufferRow(target_row.0 + 1));
5333            if !next_line_indent.is_line_empty()
5334                && target_indent.raw_len() < next_line_indent.raw_len()
5335            {
5336                target_indent = next_line_indent;
5337                target_row.0 += 1;
5338            }
5339        }
5340
5341        const SEARCH_ROW_LIMIT: u32 = 25000;
5342        const SEARCH_WHITESPACE_ROW_LIMIT: u32 = 2500;
5343        const YIELD_INTERVAL: u32 = 100;
5344
5345        let mut accessed_row_counter = 0;
5346
5347        // If there is a blank line at the current row, search for the next non indented lines
5348        if target_indent.is_line_empty() {
5349            let start = MultiBufferRow(target_row.0.saturating_sub(SEARCH_WHITESPACE_ROW_LIMIT));
5350            let end =
5351                MultiBufferRow((max_row.0 + 1).min(target_row.0 + SEARCH_WHITESPACE_ROW_LIMIT));
5352
5353            let mut non_empty_line_above = None;
5354            for (row, indent, _) in self.reversed_line_indents(target_row, |_| true) {
5355                if row < start {
5356                    break;
5357                }
5358                accessed_row_counter += 1;
5359                if accessed_row_counter == YIELD_INTERVAL {
5360                    accessed_row_counter = 0;
5361                    yield_now().await;
5362                }
5363                if !indent.is_line_empty() {
5364                    non_empty_line_above = Some((row, indent));
5365                    break;
5366                }
5367            }
5368
5369            let mut non_empty_line_below = None;
5370            for (row, indent, _) in self.line_indents(target_row, |_| true) {
5371                if row > end {
5372                    break;
5373                }
5374                accessed_row_counter += 1;
5375                if accessed_row_counter == YIELD_INTERVAL {
5376                    accessed_row_counter = 0;
5377                    yield_now().await;
5378                }
5379                if !indent.is_line_empty() {
5380                    non_empty_line_below = Some((row, indent));
5381                    break;
5382                }
5383            }
5384
5385            let (row, indent) = match (non_empty_line_above, non_empty_line_below) {
5386                (Some((above_row, above_indent)), Some((below_row, below_indent))) => {
5387                    if above_indent.raw_len() >= below_indent.raw_len() {
5388                        (above_row, above_indent)
5389                    } else {
5390                        (below_row, below_indent)
5391                    }
5392                }
5393                (Some(above), None) => above,
5394                (None, Some(below)) => below,
5395                _ => return None,
5396            };
5397
5398            target_indent = indent;
5399            target_row = row;
5400        }
5401
5402        let start = MultiBufferRow(target_row.0.saturating_sub(SEARCH_ROW_LIMIT));
5403        let end = MultiBufferRow((max_row.0 + 1).min(target_row.0 + SEARCH_ROW_LIMIT));
5404
5405        let mut start_indent = None;
5406        for (row, indent, _) in self.reversed_line_indents(target_row, |_| true) {
5407            if row < start {
5408                break;
5409            }
5410            accessed_row_counter += 1;
5411            if accessed_row_counter == YIELD_INTERVAL {
5412                accessed_row_counter = 0;
5413                yield_now().await;
5414            }
5415            if !indent.is_line_empty() && indent.raw_len() < target_indent.raw_len() {
5416                start_indent = Some((row, indent));
5417                break;
5418            }
5419        }
5420        let (start_row, start_indent_size) = start_indent?;
5421
5422        let mut end_indent = (end, None);
5423        for (row, indent, _) in self.line_indents(target_row, |_| true) {
5424            if row > end {
5425                break;
5426            }
5427            accessed_row_counter += 1;
5428            if accessed_row_counter == YIELD_INTERVAL {
5429                accessed_row_counter = 0;
5430                yield_now().await;
5431            }
5432            if !indent.is_line_empty() && indent.raw_len() < target_indent.raw_len() {
5433                end_indent = (MultiBufferRow(row.0.saturating_sub(1)), Some(indent));
5434                break;
5435            }
5436        }
5437        let (end_row, end_indent_size) = end_indent;
5438
5439        let indent = if let Some(end_indent_size) = end_indent_size {
5440            if start_indent_size.raw_len() > end_indent_size.raw_len() {
5441                start_indent_size
5442            } else {
5443                end_indent_size
5444            }
5445        } else {
5446            start_indent_size
5447        };
5448
5449        Some((start_row..end_row, indent))
5450    }
5451
5452    pub fn indent_guides_in_range<T: ToPoint>(
5453        &self,
5454        range: Range<T>,
5455        ignore_disabled_for_language: bool,
5456        cx: &App,
5457    ) -> impl Iterator<Item = IndentGuide> {
5458        let range = range.start.to_point(self)..range.end.to_point(self);
5459        let start_row = MultiBufferRow(range.start.row);
5460        let end_row = MultiBufferRow(range.end.row);
5461
5462        let mut row_indents = self.line_indents(start_row, |buffer| {
5463            let settings =
5464                language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx);
5465            settings.indent_guides.enabled || ignore_disabled_for_language
5466        });
5467
5468        let mut result = Vec::new();
5469        let mut indent_stack = SmallVec::<[IndentGuide; 8]>::new();
5470
5471        while let Some((first_row, mut line_indent, buffer)) = row_indents.next() {
5472            if first_row > end_row {
5473                break;
5474            }
5475            let current_depth = indent_stack.len() as u32;
5476
5477            let settings =
5478                language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx);
5479            let tab_size = settings.tab_size.get() as u32;
5480
5481            // When encountering empty, continue until found useful line indent
5482            // then add to the indent stack with the depth found
5483            let mut found_indent = false;
5484            let mut last_row = first_row;
5485            if line_indent.is_line_empty() {
5486                while !found_indent {
5487                    let Some((target_row, new_line_indent, _)) = row_indents.next() else {
5488                        break;
5489                    };
5490                    const TRAILING_ROW_SEARCH_LIMIT: u32 = 25;
5491                    if target_row > MultiBufferRow(end_row.0 + TRAILING_ROW_SEARCH_LIMIT) {
5492                        break;
5493                    }
5494
5495                    if new_line_indent.is_line_empty() {
5496                        continue;
5497                    }
5498                    last_row = target_row.min(end_row);
5499                    line_indent = new_line_indent;
5500                    found_indent = true;
5501                    break;
5502                }
5503            } else {
5504                found_indent = true
5505            }
5506
5507            let depth = if found_indent {
5508                line_indent.len(tab_size) / tab_size
5509                    + ((line_indent.len(tab_size) % tab_size) > 0) as u32
5510            } else {
5511                current_depth
5512            };
5513
5514            match depth.cmp(&current_depth) {
5515                cmp::Ordering::Less => {
5516                    for _ in 0..(current_depth - depth) {
5517                        let mut indent = indent_stack.pop().unwrap();
5518                        if last_row != first_row {
5519                            // In this case, we landed on an empty row, had to seek forward,
5520                            // and discovered that the indent we where on is ending.
5521                            // This means that the last display row must
5522                            // be on line that ends this indent range, so we
5523                            // should display the range up to the first non-empty line
5524                            indent.end_row = MultiBufferRow(first_row.0.saturating_sub(1));
5525                        }
5526
5527                        result.push(indent)
5528                    }
5529                }
5530                cmp::Ordering::Greater => {
5531                    for next_depth in current_depth..depth {
5532                        indent_stack.push(IndentGuide {
5533                            buffer_id: buffer.remote_id(),
5534                            start_row: first_row,
5535                            end_row: last_row,
5536                            depth: next_depth,
5537                            tab_size,
5538                            settings: settings.indent_guides,
5539                        });
5540                    }
5541                }
5542                _ => {}
5543            }
5544
5545            for indent in indent_stack.iter_mut() {
5546                indent.end_row = last_row;
5547            }
5548        }
5549
5550        result.extend(indent_stack);
5551        result.into_iter()
5552    }
5553
5554    pub fn trailing_excerpt_update_count(&self) -> usize {
5555        self.trailing_excerpt_update_count
5556    }
5557
5558    pub fn file_at<T: ToOffset>(&self, point: T) -> Option<&Arc<dyn File>> {
5559        self.point_to_buffer_offset(point)
5560            .and_then(|(buffer, _)| buffer.file())
5561    }
5562
5563    pub fn language_at<T: ToOffset>(&self, point: T) -> Option<&Arc<Language>> {
5564        self.point_to_buffer_offset(point)
5565            .and_then(|(buffer, offset)| buffer.language_at(offset))
5566    }
5567
5568    pub fn settings_at<'a, T: ToOffset>(
5569        &'a self,
5570        point: T,
5571        cx: &'a App,
5572    ) -> Cow<'a, LanguageSettings> {
5573        let mut language = None;
5574        let mut file = None;
5575        if let Some((buffer, offset)) = self.point_to_buffer_offset(point) {
5576            language = buffer.language_at(offset);
5577            file = buffer.file();
5578        }
5579        language_settings(language.map(|l| l.name()), file, cx)
5580    }
5581
5582    pub fn language_scope_at<T: ToOffset>(&self, point: T) -> Option<LanguageScope> {
5583        self.point_to_buffer_offset(point)
5584            .and_then(|(buffer, offset)| buffer.language_scope_at(offset))
5585    }
5586
5587    pub fn char_classifier_at<T: ToOffset>(&self, point: T) -> CharClassifier {
5588        self.point_to_buffer_offset(point)
5589            .map(|(buffer, offset)| buffer.char_classifier_at(offset))
5590            .unwrap_or_default()
5591    }
5592
5593    pub fn language_indent_size_at<T: ToOffset>(
5594        &self,
5595        position: T,
5596        cx: &App,
5597    ) -> Option<IndentSize> {
5598        let (buffer_snapshot, offset) = self.point_to_buffer_offset(position)?;
5599        Some(buffer_snapshot.language_indent_size_at(offset, cx))
5600    }
5601
5602    pub fn is_dirty(&self) -> bool {
5603        self.is_dirty
5604    }
5605
5606    pub fn has_deleted_file(&self) -> bool {
5607        self.has_deleted_file
5608    }
5609
5610    pub fn has_conflict(&self) -> bool {
5611        self.has_conflict
5612    }
5613
5614    pub fn has_diagnostics(&self) -> bool {
5615        self.excerpts
5616            .iter()
5617            .any(|excerpt| excerpt.buffer.has_diagnostics())
5618    }
5619
5620    pub fn diagnostic_group(
5621        &self,
5622        buffer_id: BufferId,
5623        group_id: usize,
5624    ) -> impl Iterator<Item = DiagnosticEntry<Point>> + '_ {
5625        self.lift_buffer_metadata(Point::zero()..self.max_point(), move |buffer, _| {
5626            if buffer.remote_id() != buffer_id {
5627                return None;
5628            };
5629            Some(
5630                buffer
5631                    .diagnostic_group(group_id)
5632                    .map(move |DiagnosticEntry { diagnostic, range }| (range, diagnostic)),
5633            )
5634        })
5635        .map(|(range, diagnostic, _)| DiagnosticEntry { diagnostic, range })
5636    }
5637
5638    pub fn diagnostics_in_range<'a, T>(
5639        &'a self,
5640        range: Range<T>,
5641    ) -> impl Iterator<Item = DiagnosticEntry<T>> + 'a
5642    where
5643        T: 'a
5644            + text::ToOffset
5645            + text::FromAnchor
5646            + TextDimension
5647            + Ord
5648            + Sub<T, Output = T>
5649            + fmt::Debug,
5650    {
5651        self.lift_buffer_metadata(range, move |buffer, buffer_range| {
5652            Some(
5653                buffer
5654                    .diagnostics_in_range(buffer_range.start..buffer_range.end, false)
5655                    .map(|entry| (entry.range, entry.diagnostic)),
5656            )
5657        })
5658        .map(|(range, diagnostic, _)| DiagnosticEntry { diagnostic, range })
5659    }
5660
5661    pub fn syntax_ancestor<T: ToOffset>(
5662        &self,
5663        range: Range<T>,
5664    ) -> Option<(tree_sitter::Node, Range<usize>)> {
5665        let range = range.start.to_offset(self)..range.end.to_offset(self);
5666        let mut excerpt = self.excerpt_containing(range.clone())?;
5667        let node = excerpt
5668            .buffer()
5669            .syntax_ancestor(excerpt.map_range_to_buffer(range))?;
5670        Some((node, excerpt.map_range_from_buffer(node.byte_range())))
5671    }
5672
5673    pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
5674        let (excerpt_id, _, buffer) = self.as_singleton()?;
5675        let outline = buffer.outline(theme)?;
5676        Some(Outline::new(
5677            outline
5678                .items
5679                .into_iter()
5680                .flat_map(|item| {
5681                    Some(OutlineItem {
5682                        depth: item.depth,
5683                        range: self.anchor_in_excerpt(*excerpt_id, item.range.start)?
5684                            ..self.anchor_in_excerpt(*excerpt_id, item.range.end)?,
5685                        text: item.text,
5686                        highlight_ranges: item.highlight_ranges,
5687                        name_ranges: item.name_ranges,
5688                        body_range: item.body_range.and_then(|body_range| {
5689                            Some(
5690                                self.anchor_in_excerpt(*excerpt_id, body_range.start)?
5691                                    ..self.anchor_in_excerpt(*excerpt_id, body_range.end)?,
5692                            )
5693                        }),
5694                        annotation_range: item.annotation_range.and_then(|annotation_range| {
5695                            Some(
5696                                self.anchor_in_excerpt(*excerpt_id, annotation_range.start)?
5697                                    ..self.anchor_in_excerpt(*excerpt_id, annotation_range.end)?,
5698                            )
5699                        }),
5700                    })
5701                })
5702                .collect(),
5703        ))
5704    }
5705
5706    pub fn symbols_containing<T: ToOffset>(
5707        &self,
5708        offset: T,
5709        theme: Option<&SyntaxTheme>,
5710    ) -> Option<(BufferId, Vec<OutlineItem<Anchor>>)> {
5711        let anchor = self.anchor_before(offset);
5712        let excerpt_id = anchor.excerpt_id;
5713        let excerpt = self.excerpt(excerpt_id)?;
5714        Some((
5715            excerpt.buffer_id,
5716            excerpt
5717                .buffer
5718                .symbols_containing(anchor.text_anchor, theme)
5719                .into_iter()
5720                .flatten()
5721                .flat_map(|item| {
5722                    Some(OutlineItem {
5723                        depth: item.depth,
5724                        range: self.anchor_in_excerpt(excerpt_id, item.range.start)?
5725                            ..self.anchor_in_excerpt(excerpt_id, item.range.end)?,
5726                        text: item.text,
5727                        highlight_ranges: item.highlight_ranges,
5728                        name_ranges: item.name_ranges,
5729                        body_range: item.body_range.and_then(|body_range| {
5730                            Some(
5731                                self.anchor_in_excerpt(excerpt_id, body_range.start)?
5732                                    ..self.anchor_in_excerpt(excerpt_id, body_range.end)?,
5733                            )
5734                        }),
5735                        annotation_range: item.annotation_range.and_then(|body_range| {
5736                            Some(
5737                                self.anchor_in_excerpt(excerpt_id, body_range.start)?
5738                                    ..self.anchor_in_excerpt(excerpt_id, body_range.end)?,
5739                            )
5740                        }),
5741                    })
5742                })
5743                .collect(),
5744        ))
5745    }
5746
5747    fn excerpt_locator_for_id(&self, id: ExcerptId) -> &Locator {
5748        if id == ExcerptId::min() {
5749            Locator::min_ref()
5750        } else if id == ExcerptId::max() {
5751            Locator::max_ref()
5752        } else {
5753            let mut cursor = self.excerpt_ids.cursor::<ExcerptId>(&());
5754            cursor.seek(&id, Bias::Left, &());
5755            if let Some(entry) = cursor.item() {
5756                if entry.id == id {
5757                    return &entry.locator;
5758                }
5759            }
5760            panic!("invalid excerpt id {:?}", id)
5761        }
5762    }
5763
5764    /// Returns the locators referenced by the given excerpt IDs, sorted by locator.
5765    fn excerpt_locators_for_ids(
5766        &self,
5767        ids: impl IntoIterator<Item = ExcerptId>,
5768    ) -> SmallVec<[Locator; 1]> {
5769        let mut sorted_ids = ids.into_iter().collect::<SmallVec<[_; 1]>>();
5770        sorted_ids.sort_unstable();
5771        let mut locators = SmallVec::new();
5772
5773        while sorted_ids.last() == Some(&ExcerptId::max()) {
5774            sorted_ids.pop();
5775            if let Some(mapping) = self.excerpt_ids.last() {
5776                locators.push(mapping.locator.clone());
5777            }
5778        }
5779
5780        let mut sorted_ids = sorted_ids.into_iter().dedup().peekable();
5781        if sorted_ids.peek() == Some(&ExcerptId::min()) {
5782            sorted_ids.next();
5783            if let Some(mapping) = self.excerpt_ids.first() {
5784                locators.push(mapping.locator.clone());
5785            }
5786        }
5787
5788        let mut cursor = self.excerpt_ids.cursor::<ExcerptId>(&());
5789        for id in sorted_ids {
5790            if cursor.seek_forward(&id, Bias::Left, &()) {
5791                locators.push(cursor.item().unwrap().locator.clone());
5792            } else {
5793                panic!("invalid excerpt id {:?}", id);
5794            }
5795        }
5796
5797        locators.sort_unstable();
5798        locators
5799    }
5800
5801    pub fn buffer_id_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<BufferId> {
5802        Some(self.excerpt(excerpt_id)?.buffer_id)
5803    }
5804
5805    pub fn buffer_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<&BufferSnapshot> {
5806        Some(&self.excerpt(excerpt_id)?.buffer)
5807    }
5808
5809    pub fn range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<Range<Point>> {
5810        let mut cursor = self
5811            .excerpts
5812            .cursor::<(Option<&Locator>, ExcerptDimension<Point>)>(&());
5813        let locator = self.excerpt_locator_for_id(excerpt_id);
5814        if cursor.seek(&Some(locator), Bias::Left, &()) {
5815            let start = cursor.start().1.clone();
5816            let end = cursor.end(&()).1;
5817            let mut diff_transforms = self
5818                .diff_transforms
5819                .cursor::<(ExcerptDimension<Point>, OutputDimension<Point>)>(&());
5820            diff_transforms.seek(&start, Bias::Left, &());
5821            let overshoot = start.0 - diff_transforms.start().0 .0;
5822            let start = diff_transforms.start().1 .0 + overshoot;
5823            diff_transforms.seek(&end, Bias::Right, &());
5824            let overshoot = end.0 - diff_transforms.start().0 .0;
5825            let end = diff_transforms.start().1 .0 + overshoot;
5826            Some(start..end)
5827        } else {
5828            None
5829        }
5830    }
5831
5832    pub fn buffer_range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<Range<text::Anchor>> {
5833        let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
5834        let locator = self.excerpt_locator_for_id(excerpt_id);
5835        if cursor.seek(&Some(locator), Bias::Left, &()) {
5836            if let Some(excerpt) = cursor.item() {
5837                return Some(excerpt.range.context.clone());
5838            }
5839        }
5840        None
5841    }
5842
5843    fn excerpt(&self, excerpt_id: ExcerptId) -> Option<&Excerpt> {
5844        let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
5845        let locator = self.excerpt_locator_for_id(excerpt_id);
5846        cursor.seek(&Some(locator), Bias::Left, &());
5847        if let Some(excerpt) = cursor.item() {
5848            if excerpt.id == excerpt_id {
5849                return Some(excerpt);
5850            }
5851        }
5852        None
5853    }
5854
5855    /// Returns the excerpt containing range and its offset start within the multibuffer or none if `range` spans multiple excerpts
5856    pub fn excerpt_containing<T: ToOffset>(&self, range: Range<T>) -> Option<MultiBufferExcerpt> {
5857        let range = range.start.to_offset(self)..range.end.to_offset(self);
5858        let mut cursor = self.cursor::<usize>();
5859        cursor.seek(&range.start);
5860
5861        let start_excerpt = cursor.excerpt()?;
5862        if range.end != range.start {
5863            cursor.seek_forward(&range.end);
5864            if cursor.excerpt()?.id != start_excerpt.id {
5865                return None;
5866            }
5867        }
5868
5869        cursor.seek_to_start_of_current_excerpt();
5870        let region = cursor.region()?;
5871        let offset = region.range.start;
5872        let buffer_offset = region.buffer_range.start;
5873        let excerpt_offset = cursor.excerpts.start().clone();
5874        Some(MultiBufferExcerpt {
5875            diff_transforms: cursor.diff_transforms,
5876            excerpt: start_excerpt,
5877            offset,
5878            buffer_offset,
5879            excerpt_offset,
5880        })
5881    }
5882
5883    pub fn selections_in_range<'a>(
5884        &'a self,
5885        range: &'a Range<Anchor>,
5886        include_local: bool,
5887    ) -> impl 'a + Iterator<Item = (ReplicaId, bool, CursorShape, Selection<Anchor>)> {
5888        let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&());
5889        let start_locator = self.excerpt_locator_for_id(range.start.excerpt_id);
5890        let end_locator = self.excerpt_locator_for_id(range.end.excerpt_id);
5891        cursor.seek(start_locator, Bias::Left, &());
5892        cursor
5893            .take_while(move |excerpt| excerpt.locator <= *end_locator)
5894            .flat_map(move |excerpt| {
5895                let mut query_range = excerpt.range.context.start..excerpt.range.context.end;
5896                if excerpt.id == range.start.excerpt_id {
5897                    query_range.start = range.start.text_anchor;
5898                }
5899                if excerpt.id == range.end.excerpt_id {
5900                    query_range.end = range.end.text_anchor;
5901                }
5902
5903                excerpt
5904                    .buffer
5905                    .selections_in_range(query_range, include_local)
5906                    .flat_map(move |(replica_id, line_mode, cursor_shape, selections)| {
5907                        selections.map(move |selection| {
5908                            let mut start = Anchor {
5909                                buffer_id: Some(excerpt.buffer_id),
5910                                excerpt_id: excerpt.id,
5911                                text_anchor: selection.start,
5912                                diff_base_anchor: None,
5913                            };
5914                            let mut end = Anchor {
5915                                buffer_id: Some(excerpt.buffer_id),
5916                                excerpt_id: excerpt.id,
5917                                text_anchor: selection.end,
5918                                diff_base_anchor: None,
5919                            };
5920                            if range.start.cmp(&start, self).is_gt() {
5921                                start = range.start;
5922                            }
5923                            if range.end.cmp(&end, self).is_lt() {
5924                                end = range.end;
5925                            }
5926
5927                            (
5928                                replica_id,
5929                                line_mode,
5930                                cursor_shape,
5931                                Selection {
5932                                    id: selection.id,
5933                                    start,
5934                                    end,
5935                                    reversed: selection.reversed,
5936                                    goal: selection.goal,
5937                                },
5938                            )
5939                        })
5940                    })
5941            })
5942    }
5943
5944    pub fn show_headers(&self) -> bool {
5945        self.show_headers
5946    }
5947
5948    pub fn diff_for_buffer_id(&self, buffer_id: BufferId) -> Option<&BufferDiffSnapshot> {
5949        self.diffs.get(&buffer_id)
5950    }
5951}
5952
5953#[cfg(any(test, feature = "test-support"))]
5954impl MultiBufferSnapshot {
5955    pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
5956        let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
5957        let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
5958        start..end
5959    }
5960
5961    #[cfg(any(test, feature = "test-support"))]
5962    fn check_invariants(&self) {
5963        let excerpts = self.excerpts.items(&());
5964        let excerpt_ids = self.excerpt_ids.items(&());
5965
5966        for (ix, excerpt) in excerpts.iter().enumerate() {
5967            if ix == 0 {
5968                if excerpt.locator <= Locator::min() {
5969                    panic!("invalid first excerpt locator {:?}", excerpt.locator);
5970                }
5971            } else if excerpt.locator <= excerpts[ix - 1].locator {
5972                panic!("excerpts are out-of-order: {:?}", excerpts);
5973            }
5974        }
5975
5976        for (ix, entry) in excerpt_ids.iter().enumerate() {
5977            if ix == 0 {
5978                if entry.id.cmp(&ExcerptId::min(), &self).is_le() {
5979                    panic!("invalid first excerpt id {:?}", entry.id);
5980                }
5981            } else if entry.id <= excerpt_ids[ix - 1].id {
5982                panic!("excerpt ids are out-of-order: {:?}", excerpt_ids);
5983            }
5984        }
5985
5986        if self.diff_transforms.summary().input != self.excerpts.summary().text {
5987            panic!(
5988                "incorrect input summary. expected {:?}, got {:?}. transforms: {:+?}",
5989                self.excerpts.summary().text.len,
5990                self.diff_transforms.summary().input,
5991                self.diff_transforms.items(&()),
5992            );
5993        }
5994
5995        let mut prev_transform: Option<&DiffTransform> = None;
5996        for item in self.diff_transforms.iter() {
5997            if let DiffTransform::BufferContent {
5998                summary,
5999                inserted_hunk_info,
6000            } = item
6001            {
6002                if let Some(DiffTransform::BufferContent {
6003                    inserted_hunk_info: prev_inserted_hunk_info,
6004                    ..
6005                }) = prev_transform
6006                {
6007                    if *inserted_hunk_info == *prev_inserted_hunk_info {
6008                        panic!(
6009                            "multiple adjacent buffer content transforms with is_inserted_hunk = {inserted_hunk_info:?}. transforms: {:+?}",
6010                            self.diff_transforms.items(&()));
6011                    }
6012                }
6013                if summary.len == 0 && !self.is_empty() {
6014                    panic!("empty buffer content transform");
6015                }
6016            }
6017            prev_transform = Some(item);
6018        }
6019    }
6020}
6021
6022impl<'a, D> MultiBufferCursor<'a, D>
6023where
6024    D: TextDimension + Ord + Sub<D, Output = D>,
6025{
6026    fn seek(&mut self, position: &D) {
6027        self.cached_region.take();
6028        self.diff_transforms
6029            .seek(&OutputDimension(*position), Bias::Right, &());
6030        if self.diff_transforms.item().is_none() && *position == self.diff_transforms.start().0 .0 {
6031            self.diff_transforms.prev(&());
6032        }
6033
6034        let mut excerpt_position = self.diff_transforms.start().1 .0;
6035        if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
6036            let overshoot = *position - self.diff_transforms.start().0 .0;
6037            excerpt_position.add_assign(&overshoot);
6038        }
6039
6040        self.excerpts
6041            .seek(&ExcerptDimension(excerpt_position), Bias::Right, &());
6042        if self.excerpts.item().is_none() && excerpt_position == self.excerpts.start().0 {
6043            self.excerpts.prev(&());
6044        }
6045    }
6046
6047    fn seek_forward(&mut self, position: &D) {
6048        self.cached_region.take();
6049        self.diff_transforms
6050            .seek_forward(&OutputDimension(*position), Bias::Right, &());
6051        if self.diff_transforms.item().is_none() && *position == self.diff_transforms.start().0 .0 {
6052            self.diff_transforms.prev(&());
6053        }
6054
6055        let overshoot = *position - self.diff_transforms.start().0 .0;
6056        let mut excerpt_position = self.diff_transforms.start().1 .0;
6057        if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
6058            excerpt_position.add_assign(&overshoot);
6059        }
6060
6061        self.excerpts
6062            .seek_forward(&ExcerptDimension(excerpt_position), Bias::Right, &());
6063        if self.excerpts.item().is_none() && excerpt_position == self.excerpts.start().0 {
6064            self.excerpts.prev(&());
6065        }
6066    }
6067
6068    fn seek_to_buffer_position_in_current_excerpt(&mut self, position: &D) {
6069        self.cached_region.take();
6070        if let Some(excerpt) = self.excerpts.item() {
6071            let excerpt_start = excerpt.range.context.start.summary::<D>(&excerpt.buffer);
6072            let position_in_excerpt = *position - excerpt_start;
6073            let mut excerpt_position = self.excerpts.start().0;
6074            excerpt_position.add_assign(&position_in_excerpt);
6075            self.diff_transforms
6076                .seek(&ExcerptDimension(excerpt_position), Bias::Left, &());
6077            if self.diff_transforms.item().is_none() {
6078                self.diff_transforms.next(&());
6079            }
6080        }
6081    }
6082
6083    fn next_excerpt(&mut self) {
6084        self.excerpts.next(&());
6085        self.seek_to_start_of_current_excerpt();
6086    }
6087
6088    fn prev_excerpt(&mut self) {
6089        self.excerpts.prev(&());
6090        self.seek_to_start_of_current_excerpt();
6091    }
6092
6093    fn seek_to_start_of_current_excerpt(&mut self) {
6094        self.cached_region.take();
6095        self.diff_transforms
6096            .seek(self.excerpts.start(), Bias::Left, &());
6097        if self.diff_transforms.end(&()).1 == *self.excerpts.start()
6098            && self.diff_transforms.start().1 < *self.excerpts.start()
6099            && self.diff_transforms.next_item().is_some()
6100        {
6101            self.diff_transforms.next(&());
6102        }
6103    }
6104
6105    fn next(&mut self) {
6106        self.cached_region.take();
6107        match self.diff_transforms.end(&()).1.cmp(&self.excerpts.end(&())) {
6108            cmp::Ordering::Less => self.diff_transforms.next(&()),
6109            cmp::Ordering::Greater => self.excerpts.next(&()),
6110            cmp::Ordering::Equal => {
6111                self.diff_transforms.next(&());
6112                if self.diff_transforms.end(&()).1 > self.excerpts.end(&())
6113                    || self.diff_transforms.item().is_none()
6114                {
6115                    self.excerpts.next(&());
6116                }
6117            }
6118        }
6119    }
6120
6121    fn prev(&mut self) {
6122        self.cached_region.take();
6123        match self.diff_transforms.start().1.cmp(self.excerpts.start()) {
6124            cmp::Ordering::Less => self.excerpts.prev(&()),
6125            cmp::Ordering::Greater => self.diff_transforms.prev(&()),
6126            cmp::Ordering::Equal => {
6127                self.diff_transforms.prev(&());
6128                if self.diff_transforms.start().1 < *self.excerpts.start()
6129                    || self.diff_transforms.item().is_none()
6130                {
6131                    self.excerpts.prev(&());
6132                }
6133            }
6134        }
6135    }
6136
6137    fn region(&mut self) -> Option<MultiBufferRegion<'a, D>> {
6138        if self.cached_region.is_none() {
6139            self.cached_region = self.build_region();
6140        }
6141        self.cached_region.clone()
6142    }
6143
6144    fn is_at_end_of_excerpt(&mut self) -> bool {
6145        if self.diff_transforms.end(&()).1 < self.excerpts.end(&()) {
6146            return false;
6147        } else if self.diff_transforms.end(&()).1 > self.excerpts.end(&())
6148            || self.diff_transforms.item().is_none()
6149        {
6150            return true;
6151        }
6152
6153        self.diff_transforms.next(&());
6154        let next_transform = self.diff_transforms.item();
6155        self.diff_transforms.prev(&());
6156
6157        next_transform.map_or(true, |next_transform| {
6158            matches!(next_transform, DiffTransform::BufferContent { .. })
6159        })
6160    }
6161
6162    fn main_buffer_position(&self) -> Option<D> {
6163        let excerpt = self.excerpts.item()?;
6164        let buffer = &excerpt.buffer;
6165        let buffer_context_start = excerpt.range.context.start.summary::<D>(buffer);
6166        let mut buffer_start = buffer_context_start;
6167        let overshoot = self.diff_transforms.end(&()).1 .0 - self.excerpts.start().0;
6168        buffer_start.add_assign(&overshoot);
6169        Some(buffer_start)
6170    }
6171
6172    fn build_region(&self) -> Option<MultiBufferRegion<'a, D>> {
6173        let excerpt = self.excerpts.item()?;
6174        match self.diff_transforms.item()? {
6175            DiffTransform::DeletedHunk {
6176                buffer_id,
6177                base_text_byte_range,
6178                has_trailing_newline,
6179                hunk_info,
6180                ..
6181            } => {
6182                let diff = self.diffs.get(&buffer_id)?;
6183                let buffer = diff.base_text()?;
6184                let mut rope_cursor = buffer.as_rope().cursor(0);
6185                let buffer_start = rope_cursor.summary::<D>(base_text_byte_range.start);
6186                let buffer_range_len = rope_cursor.summary::<D>(base_text_byte_range.end);
6187                let mut buffer_end = buffer_start;
6188                buffer_end.add_assign(&buffer_range_len);
6189                let start = self.diff_transforms.start().0 .0;
6190                let end = self.diff_transforms.end(&()).0 .0;
6191                return Some(MultiBufferRegion {
6192                    buffer,
6193                    excerpt,
6194                    has_trailing_newline: *has_trailing_newline,
6195                    is_main_buffer: false,
6196                    diff_hunk_status: Some(DiffHunkStatus::Removed(
6197                        hunk_info.hunk_secondary_status,
6198                    )),
6199                    buffer_range: buffer_start..buffer_end,
6200                    range: start..end,
6201                });
6202            }
6203            DiffTransform::BufferContent {
6204                inserted_hunk_info, ..
6205            } => {
6206                let buffer = &excerpt.buffer;
6207                let buffer_context_start = excerpt.range.context.start.summary::<D>(buffer);
6208
6209                let mut start = self.diff_transforms.start().0 .0;
6210                let mut buffer_start = buffer_context_start;
6211                if self.diff_transforms.start().1 < *self.excerpts.start() {
6212                    let overshoot = self.excerpts.start().0 - self.diff_transforms.start().1 .0;
6213                    start.add_assign(&overshoot);
6214                } else {
6215                    let overshoot = self.diff_transforms.start().1 .0 - self.excerpts.start().0;
6216                    buffer_start.add_assign(&overshoot);
6217                }
6218
6219                let mut end;
6220                let mut buffer_end;
6221                let has_trailing_newline;
6222                if self.diff_transforms.end(&()).1 .0 < self.excerpts.end(&()).0 {
6223                    let overshoot = self.diff_transforms.end(&()).1 .0 - self.excerpts.start().0;
6224                    end = self.diff_transforms.end(&()).0 .0;
6225                    buffer_end = buffer_context_start;
6226                    buffer_end.add_assign(&overshoot);
6227                    has_trailing_newline = false;
6228                } else {
6229                    let overshoot = self.excerpts.end(&()).0 - self.diff_transforms.start().1 .0;
6230                    end = self.diff_transforms.start().0 .0;
6231                    end.add_assign(&overshoot);
6232                    buffer_end = excerpt.range.context.end.summary::<D>(buffer);
6233                    has_trailing_newline = excerpt.has_trailing_newline;
6234                };
6235
6236                Some(MultiBufferRegion {
6237                    buffer,
6238                    excerpt,
6239                    has_trailing_newline,
6240                    is_main_buffer: true,
6241                    diff_hunk_status: inserted_hunk_info
6242                        .map(|info| DiffHunkStatus::Added(info.hunk_secondary_status)),
6243                    buffer_range: buffer_start..buffer_end,
6244                    range: start..end,
6245                })
6246            }
6247        }
6248    }
6249
6250    fn excerpt(&self) -> Option<&'a Excerpt> {
6251        self.excerpts.item()
6252    }
6253}
6254
6255impl History {
6256    fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
6257        self.transaction_depth += 1;
6258        if self.transaction_depth == 1 {
6259            let id = self.next_transaction_id.tick();
6260            self.undo_stack.push(Transaction {
6261                id,
6262                buffer_transactions: Default::default(),
6263                first_edit_at: now,
6264                last_edit_at: now,
6265                suppress_grouping: false,
6266            });
6267            Some(id)
6268        } else {
6269            None
6270        }
6271    }
6272
6273    fn end_transaction(
6274        &mut self,
6275        now: Instant,
6276        buffer_transactions: HashMap<BufferId, TransactionId>,
6277    ) -> bool {
6278        assert_ne!(self.transaction_depth, 0);
6279        self.transaction_depth -= 1;
6280        if self.transaction_depth == 0 {
6281            if buffer_transactions.is_empty() {
6282                self.undo_stack.pop();
6283                false
6284            } else {
6285                self.redo_stack.clear();
6286                let transaction = self.undo_stack.last_mut().unwrap();
6287                transaction.last_edit_at = now;
6288                for (buffer_id, transaction_id) in buffer_transactions {
6289                    transaction
6290                        .buffer_transactions
6291                        .entry(buffer_id)
6292                        .or_insert(transaction_id);
6293                }
6294                true
6295            }
6296        } else {
6297            false
6298        }
6299    }
6300
6301    fn push_transaction<'a, T>(
6302        &mut self,
6303        buffer_transactions: T,
6304        now: Instant,
6305        cx: &Context<MultiBuffer>,
6306    ) where
6307        T: IntoIterator<Item = (&'a Entity<Buffer>, &'a language::Transaction)>,
6308    {
6309        assert_eq!(self.transaction_depth, 0);
6310        let transaction = Transaction {
6311            id: self.next_transaction_id.tick(),
6312            buffer_transactions: buffer_transactions
6313                .into_iter()
6314                .map(|(buffer, transaction)| (buffer.read(cx).remote_id(), transaction.id))
6315                .collect(),
6316            first_edit_at: now,
6317            last_edit_at: now,
6318            suppress_grouping: false,
6319        };
6320        if !transaction.buffer_transactions.is_empty() {
6321            self.undo_stack.push(transaction);
6322            self.redo_stack.clear();
6323        }
6324    }
6325
6326    fn finalize_last_transaction(&mut self) {
6327        if let Some(transaction) = self.undo_stack.last_mut() {
6328            transaction.suppress_grouping = true;
6329        }
6330    }
6331
6332    fn forget(&mut self, transaction_id: TransactionId) -> Option<Transaction> {
6333        if let Some(ix) = self
6334            .undo_stack
6335            .iter()
6336            .rposition(|transaction| transaction.id == transaction_id)
6337        {
6338            Some(self.undo_stack.remove(ix))
6339        } else if let Some(ix) = self
6340            .redo_stack
6341            .iter()
6342            .rposition(|transaction| transaction.id == transaction_id)
6343        {
6344            Some(self.redo_stack.remove(ix))
6345        } else {
6346            None
6347        }
6348    }
6349
6350    fn transaction(&self, transaction_id: TransactionId) -> Option<&Transaction> {
6351        self.undo_stack
6352            .iter()
6353            .find(|transaction| transaction.id == transaction_id)
6354            .or_else(|| {
6355                self.redo_stack
6356                    .iter()
6357                    .find(|transaction| transaction.id == transaction_id)
6358            })
6359    }
6360
6361    fn transaction_mut(&mut self, transaction_id: TransactionId) -> Option<&mut Transaction> {
6362        self.undo_stack
6363            .iter_mut()
6364            .find(|transaction| transaction.id == transaction_id)
6365            .or_else(|| {
6366                self.redo_stack
6367                    .iter_mut()
6368                    .find(|transaction| transaction.id == transaction_id)
6369            })
6370    }
6371
6372    fn pop_undo(&mut self) -> Option<&mut Transaction> {
6373        assert_eq!(self.transaction_depth, 0);
6374        if let Some(transaction) = self.undo_stack.pop() {
6375            self.redo_stack.push(transaction);
6376            self.redo_stack.last_mut()
6377        } else {
6378            None
6379        }
6380    }
6381
6382    fn pop_redo(&mut self) -> Option<&mut Transaction> {
6383        assert_eq!(self.transaction_depth, 0);
6384        if let Some(transaction) = self.redo_stack.pop() {
6385            self.undo_stack.push(transaction);
6386            self.undo_stack.last_mut()
6387        } else {
6388            None
6389        }
6390    }
6391
6392    fn remove_from_undo(&mut self, transaction_id: TransactionId) -> Option<&Transaction> {
6393        let ix = self
6394            .undo_stack
6395            .iter()
6396            .rposition(|transaction| transaction.id == transaction_id)?;
6397        let transaction = self.undo_stack.remove(ix);
6398        self.redo_stack.push(transaction);
6399        self.redo_stack.last()
6400    }
6401
6402    fn group(&mut self) -> Option<TransactionId> {
6403        let mut count = 0;
6404        let mut transactions = self.undo_stack.iter();
6405        if let Some(mut transaction) = transactions.next_back() {
6406            while let Some(prev_transaction) = transactions.next_back() {
6407                if !prev_transaction.suppress_grouping
6408                    && transaction.first_edit_at - prev_transaction.last_edit_at
6409                        <= self.group_interval
6410                {
6411                    transaction = prev_transaction;
6412                    count += 1;
6413                } else {
6414                    break;
6415                }
6416            }
6417        }
6418        self.group_trailing(count)
6419    }
6420
6421    fn group_until(&mut self, transaction_id: TransactionId) {
6422        let mut count = 0;
6423        for transaction in self.undo_stack.iter().rev() {
6424            if transaction.id == transaction_id {
6425                self.group_trailing(count);
6426                break;
6427            } else if transaction.suppress_grouping {
6428                break;
6429            } else {
6430                count += 1;
6431            }
6432        }
6433    }
6434
6435    fn group_trailing(&mut self, n: usize) -> Option<TransactionId> {
6436        let new_len = self.undo_stack.len() - n;
6437        let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
6438        if let Some(last_transaction) = transactions_to_keep.last_mut() {
6439            if let Some(transaction) = transactions_to_merge.last() {
6440                last_transaction.last_edit_at = transaction.last_edit_at;
6441            }
6442            for to_merge in transactions_to_merge {
6443                for (buffer_id, transaction_id) in &to_merge.buffer_transactions {
6444                    last_transaction
6445                        .buffer_transactions
6446                        .entry(*buffer_id)
6447                        .or_insert(*transaction_id);
6448                }
6449            }
6450        }
6451
6452        self.undo_stack.truncate(new_len);
6453        self.undo_stack.last().map(|t| t.id)
6454    }
6455}
6456
6457impl Excerpt {
6458    fn new(
6459        id: ExcerptId,
6460        locator: Locator,
6461        buffer_id: BufferId,
6462        buffer: BufferSnapshot,
6463        range: ExcerptRange<text::Anchor>,
6464        has_trailing_newline: bool,
6465    ) -> Self {
6466        Excerpt {
6467            id,
6468            locator,
6469            max_buffer_row: range.context.end.to_point(&buffer).row,
6470            text_summary: buffer
6471                .text_summary_for_range::<TextSummary, _>(range.context.to_offset(&buffer)),
6472            buffer_id,
6473            buffer,
6474            range,
6475            has_trailing_newline,
6476        }
6477    }
6478
6479    fn chunks_in_range(&self, range: Range<usize>, language_aware: bool) -> ExcerptChunks {
6480        let content_start = self.range.context.start.to_offset(&self.buffer);
6481        let chunks_start = content_start + range.start;
6482        let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
6483
6484        let footer_height = if self.has_trailing_newline
6485            && range.start <= self.text_summary.len
6486            && range.end > self.text_summary.len
6487        {
6488            1
6489        } else {
6490            0
6491        };
6492
6493        let content_chunks = self.buffer.chunks(chunks_start..chunks_end, language_aware);
6494
6495        ExcerptChunks {
6496            excerpt_id: self.id,
6497            content_chunks,
6498            footer_height,
6499        }
6500    }
6501
6502    fn seek_chunks(&self, excerpt_chunks: &mut ExcerptChunks, range: Range<usize>) {
6503        let content_start = self.range.context.start.to_offset(&self.buffer);
6504        let chunks_start = content_start + range.start;
6505        let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
6506        excerpt_chunks.content_chunks.seek(chunks_start..chunks_end);
6507        excerpt_chunks.footer_height = if self.has_trailing_newline
6508            && range.start <= self.text_summary.len
6509            && range.end > self.text_summary.len
6510        {
6511            1
6512        } else {
6513            0
6514        };
6515    }
6516
6517    fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
6518        if text_anchor
6519            .cmp(&self.range.context.start, &self.buffer)
6520            .is_lt()
6521        {
6522            self.range.context.start
6523        } else if text_anchor
6524            .cmp(&self.range.context.end, &self.buffer)
6525            .is_gt()
6526        {
6527            self.range.context.end
6528        } else {
6529            text_anchor
6530        }
6531    }
6532
6533    fn contains(&self, anchor: &Anchor) -> bool {
6534        Some(self.buffer_id) == anchor.buffer_id
6535            && self
6536                .range
6537                .context
6538                .start
6539                .cmp(&anchor.text_anchor, &self.buffer)
6540                .is_le()
6541            && self
6542                .range
6543                .context
6544                .end
6545                .cmp(&anchor.text_anchor, &self.buffer)
6546                .is_ge()
6547    }
6548
6549    /// The [`Excerpt`]'s start offset in its [`Buffer`]
6550    fn buffer_start_offset(&self) -> usize {
6551        self.range.context.start.to_offset(&self.buffer)
6552    }
6553
6554    /// The [`Excerpt`]'s end offset in its [`Buffer`]
6555    fn buffer_end_offset(&self) -> usize {
6556        self.buffer_start_offset() + self.text_summary.len
6557    }
6558}
6559
6560impl<'a> MultiBufferExcerpt<'a> {
6561    pub fn id(&self) -> ExcerptId {
6562        self.excerpt.id
6563    }
6564
6565    pub fn buffer_id(&self) -> BufferId {
6566        self.excerpt.buffer_id
6567    }
6568
6569    pub fn start_anchor(&self) -> Anchor {
6570        Anchor {
6571            buffer_id: Some(self.excerpt.buffer_id),
6572            excerpt_id: self.excerpt.id,
6573            text_anchor: self.excerpt.range.context.start,
6574            diff_base_anchor: None,
6575        }
6576    }
6577
6578    pub fn end_anchor(&self) -> Anchor {
6579        Anchor {
6580            buffer_id: Some(self.excerpt.buffer_id),
6581            excerpt_id: self.excerpt.id,
6582            text_anchor: self.excerpt.range.context.end,
6583            diff_base_anchor: None,
6584        }
6585    }
6586
6587    pub fn buffer(&self) -> &'a BufferSnapshot {
6588        &self.excerpt.buffer
6589    }
6590
6591    pub fn buffer_range(&self) -> Range<usize> {
6592        self.buffer_offset
6593            ..self
6594                .excerpt
6595                .range
6596                .context
6597                .end
6598                .to_offset(&self.excerpt.buffer.text)
6599    }
6600
6601    pub fn start_offset(&self) -> usize {
6602        self.offset
6603    }
6604
6605    /// Maps an offset within the [`MultiBuffer`] to an offset within the [`Buffer`]
6606    pub fn map_offset_to_buffer(&mut self, offset: usize) -> usize {
6607        self.map_range_to_buffer(offset..offset).start
6608    }
6609
6610    /// Maps a range within the [`MultiBuffer`] to a range within the [`Buffer`]
6611    pub fn map_range_to_buffer(&mut self, range: Range<usize>) -> Range<usize> {
6612        self.diff_transforms
6613            .seek(&OutputDimension(range.start), Bias::Right, &());
6614        let start = self.map_offset_to_buffer_internal(range.start);
6615        let end = if range.end > range.start {
6616            self.diff_transforms
6617                .seek_forward(&OutputDimension(range.end), Bias::Right, &());
6618            self.map_offset_to_buffer_internal(range.end)
6619        } else {
6620            start
6621        };
6622        start..end
6623    }
6624
6625    fn map_offset_to_buffer_internal(&self, offset: usize) -> usize {
6626        let mut excerpt_offset = self.diff_transforms.start().1.clone();
6627        if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
6628            excerpt_offset.0 += offset - self.diff_transforms.start().0 .0;
6629        };
6630        let offset_in_excerpt = excerpt_offset.0.saturating_sub(self.excerpt_offset.0);
6631        self.buffer_offset + offset_in_excerpt
6632    }
6633
6634    /// Map an offset within the [`Buffer`] to an offset within the [`MultiBuffer`]
6635    pub fn map_offset_from_buffer(&mut self, buffer_offset: usize) -> usize {
6636        self.map_range_from_buffer(buffer_offset..buffer_offset)
6637            .start
6638    }
6639
6640    /// Map a range within the [`Buffer`] to a range within the [`MultiBuffer`]
6641    pub fn map_range_from_buffer(&mut self, buffer_range: Range<usize>) -> Range<usize> {
6642        let overshoot = buffer_range.start - self.buffer_offset;
6643        let excerpt_offset = ExcerptDimension(self.excerpt_offset.0 + overshoot);
6644        self.diff_transforms.seek(&excerpt_offset, Bias::Right, &());
6645        let overshoot = excerpt_offset.0 - self.diff_transforms.start().1 .0;
6646        let start = self.diff_transforms.start().0 .0 + overshoot;
6647
6648        let end = if buffer_range.end > buffer_range.start {
6649            let overshoot = buffer_range.end - self.buffer_offset;
6650            let excerpt_offset = ExcerptDimension(self.excerpt_offset.0 + overshoot);
6651            self.diff_transforms
6652                .seek_forward(&excerpt_offset, Bias::Right, &());
6653            let overshoot = excerpt_offset.0 - self.diff_transforms.start().1 .0;
6654            self.diff_transforms.start().0 .0 + overshoot
6655        } else {
6656            start
6657        };
6658
6659        start..end
6660    }
6661
6662    /// Returns true if the entirety of the given range is in the buffer's excerpt
6663    pub fn contains_buffer_range(&self, range: Range<usize>) -> bool {
6664        range.start >= self.excerpt.buffer_start_offset()
6665            && range.end <= self.excerpt.buffer_end_offset()
6666    }
6667
6668    pub fn max_buffer_row(&self) -> u32 {
6669        self.excerpt.max_buffer_row
6670    }
6671}
6672
6673impl ExcerptId {
6674    pub fn min() -> Self {
6675        Self(0)
6676    }
6677
6678    pub fn max() -> Self {
6679        Self(usize::MAX)
6680    }
6681
6682    pub fn to_proto(&self) -> u64 {
6683        self.0 as _
6684    }
6685
6686    pub fn from_proto(proto: u64) -> Self {
6687        Self(proto as _)
6688    }
6689
6690    pub fn cmp(&self, other: &Self, snapshot: &MultiBufferSnapshot) -> cmp::Ordering {
6691        let a = snapshot.excerpt_locator_for_id(*self);
6692        let b = snapshot.excerpt_locator_for_id(*other);
6693        a.cmp(b).then_with(|| self.0.cmp(&other.0))
6694    }
6695}
6696
6697impl From<ExcerptId> for usize {
6698    fn from(val: ExcerptId) -> Self {
6699        val.0
6700    }
6701}
6702
6703impl fmt::Debug for Excerpt {
6704    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6705        f.debug_struct("Excerpt")
6706            .field("id", &self.id)
6707            .field("locator", &self.locator)
6708            .field("buffer_id", &self.buffer_id)
6709            .field("range", &self.range)
6710            .field("text_summary", &self.text_summary)
6711            .field("has_trailing_newline", &self.has_trailing_newline)
6712            .finish()
6713    }
6714}
6715
6716impl sum_tree::Item for Excerpt {
6717    type Summary = ExcerptSummary;
6718
6719    fn summary(&self, _cx: &()) -> Self::Summary {
6720        let mut text = self.text_summary;
6721        if self.has_trailing_newline {
6722            text += TextSummary::from("\n");
6723        }
6724        ExcerptSummary {
6725            excerpt_id: self.id,
6726            excerpt_locator: self.locator.clone(),
6727            widest_line_number: self.max_buffer_row,
6728            text,
6729        }
6730    }
6731}
6732
6733impl sum_tree::Item for ExcerptIdMapping {
6734    type Summary = ExcerptId;
6735
6736    fn summary(&self, _cx: &()) -> Self::Summary {
6737        self.id
6738    }
6739}
6740
6741impl sum_tree::KeyedItem for ExcerptIdMapping {
6742    type Key = ExcerptId;
6743
6744    fn key(&self) -> Self::Key {
6745        self.id
6746    }
6747}
6748
6749impl DiffTransform {
6750    fn hunk_info(&self) -> Option<DiffTransformHunkInfo> {
6751        match self {
6752            DiffTransform::DeletedHunk { hunk_info, .. } => Some(*hunk_info),
6753            DiffTransform::BufferContent {
6754                inserted_hunk_info, ..
6755            } => *inserted_hunk_info,
6756        }
6757    }
6758}
6759
6760impl sum_tree::Item for DiffTransform {
6761    type Summary = DiffTransformSummary;
6762
6763    fn summary(&self, _: &<Self::Summary as sum_tree::Summary>::Context) -> Self::Summary {
6764        match self {
6765            DiffTransform::BufferContent { summary, .. } => DiffTransformSummary {
6766                input: *summary,
6767                output: *summary,
6768            },
6769            DiffTransform::DeletedHunk { summary, .. } => DiffTransformSummary {
6770                input: TextSummary::default(),
6771                output: *summary,
6772            },
6773        }
6774    }
6775}
6776
6777impl DiffTransformSummary {
6778    fn excerpt_len(&self) -> ExcerptOffset {
6779        ExcerptOffset::new(self.input.len)
6780    }
6781}
6782
6783impl sum_tree::Summary for DiffTransformSummary {
6784    type Context = ();
6785
6786    fn zero(_: &Self::Context) -> Self {
6787        DiffTransformSummary {
6788            input: TextSummary::default(),
6789            output: TextSummary::default(),
6790        }
6791    }
6792
6793    fn add_summary(&mut self, summary: &Self, _: &Self::Context) {
6794        self.input += &summary.input;
6795        self.output += &summary.output;
6796    }
6797}
6798
6799impl sum_tree::Summary for ExcerptId {
6800    type Context = ();
6801
6802    fn zero(_cx: &()) -> Self {
6803        Default::default()
6804    }
6805
6806    fn add_summary(&mut self, other: &Self, _: &()) {
6807        *self = *other;
6808    }
6809}
6810
6811impl sum_tree::Summary for ExcerptSummary {
6812    type Context = ();
6813
6814    fn zero(_cx: &()) -> Self {
6815        Default::default()
6816    }
6817
6818    fn add_summary(&mut self, summary: &Self, _: &()) {
6819        debug_assert!(summary.excerpt_locator > self.excerpt_locator);
6820        self.excerpt_locator = summary.excerpt_locator.clone();
6821        self.text.add_summary(&summary.text, &());
6822        self.widest_line_number = cmp::max(self.widest_line_number, summary.widest_line_number);
6823    }
6824}
6825
6826impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for ExcerptOffset {
6827    fn zero(_cx: &()) -> Self {
6828        Default::default()
6829    }
6830
6831    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6832        self.value += summary.text.len;
6833    }
6834}
6835
6836impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for ExcerptOffset {
6837    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
6838        Ord::cmp(&self.value, &cursor_location.text.len)
6839    }
6840}
6841
6842impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, Option<&'a Locator>> for Locator {
6843    fn cmp(&self, cursor_location: &Option<&'a Locator>, _: &()) -> cmp::Ordering {
6844        Ord::cmp(&Some(self), cursor_location)
6845    }
6846}
6847
6848impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Locator {
6849    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
6850        Ord::cmp(self, &cursor_location.excerpt_locator)
6851    }
6852}
6853
6854impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for ExcerptPoint {
6855    fn zero(_cx: &()) -> Self {
6856        Default::default()
6857    }
6858
6859    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6860        self.value += summary.text.lines;
6861    }
6862}
6863
6864impl<'a, D: TextDimension + Default> sum_tree::Dimension<'a, ExcerptSummary>
6865    for ExcerptDimension<D>
6866{
6867    fn zero(_: &()) -> Self {
6868        ExcerptDimension(D::default())
6869    }
6870
6871    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6872        self.0.add_assign(&D::from_text_summary(&summary.text))
6873    }
6874}
6875
6876impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a Locator> {
6877    fn zero(_cx: &()) -> Self {
6878        Default::default()
6879    }
6880
6881    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6882        *self = Some(&summary.excerpt_locator);
6883    }
6884}
6885
6886impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<ExcerptId> {
6887    fn zero(_cx: &()) -> Self {
6888        Default::default()
6889    }
6890
6891    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
6892        *self = Some(summary.excerpt_id);
6893    }
6894}
6895
6896#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
6897struct ExcerptDimension<T>(T);
6898
6899#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
6900struct OutputDimension<T>(T);
6901
6902impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for ExcerptOffset {
6903    fn zero(_: &()) -> Self {
6904        ExcerptOffset::new(0)
6905    }
6906
6907    fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6908        self.value += summary.input.len;
6909    }
6910}
6911
6912impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for ExcerptPoint {
6913    fn zero(_: &()) -> Self {
6914        ExcerptPoint::new(0, 0)
6915    }
6916
6917    fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6918        self.value += summary.input.lines;
6919    }
6920}
6921
6922impl<'a, D: TextDimension + Ord>
6923    sum_tree::SeekTarget<'a, DiffTransformSummary, DiffTransformSummary> for ExcerptDimension<D>
6924{
6925    fn cmp(&self, cursor_location: &DiffTransformSummary, _: &()) -> cmp::Ordering {
6926        Ord::cmp(&self.0, &D::from_text_summary(&cursor_location.input))
6927    }
6928}
6929
6930impl<'a, D: TextDimension + Ord>
6931    sum_tree::SeekTarget<'a, DiffTransformSummary, (OutputDimension<D>, ExcerptDimension<D>)>
6932    for ExcerptDimension<D>
6933{
6934    fn cmp(
6935        &self,
6936        cursor_location: &(OutputDimension<D>, ExcerptDimension<D>),
6937        _: &(),
6938    ) -> cmp::Ordering {
6939        Ord::cmp(&self.0, &cursor_location.1 .0)
6940    }
6941}
6942
6943impl<'a, D: TextDimension> sum_tree::Dimension<'a, DiffTransformSummary> for ExcerptDimension<D> {
6944    fn zero(_: &()) -> Self {
6945        ExcerptDimension(D::default())
6946    }
6947
6948    fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6949        self.0.add_assign(&D::from_text_summary(&summary.input))
6950    }
6951}
6952
6953impl<'a, D: TextDimension> sum_tree::Dimension<'a, DiffTransformSummary> for OutputDimension<D> {
6954    fn zero(_: &()) -> Self {
6955        OutputDimension(D::default())
6956    }
6957
6958    fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6959        self.0.add_assign(&D::from_text_summary(&summary.output))
6960    }
6961}
6962
6963impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for TextSummary {
6964    fn zero(_: &()) -> Self {
6965        TextSummary::default()
6966    }
6967
6968    fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6969        *self += summary.output
6970    }
6971}
6972
6973impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for usize {
6974    fn zero(_: &()) -> Self {
6975        0
6976    }
6977
6978    fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6979        *self += summary.output.len
6980    }
6981}
6982
6983impl<'a> sum_tree::Dimension<'a, DiffTransformSummary> for Point {
6984    fn zero(_: &()) -> Self {
6985        Point::new(0, 0)
6986    }
6987
6988    fn add_summary(&mut self, summary: &'a DiffTransformSummary, _: &()) {
6989        *self += summary.output.lines
6990    }
6991}
6992
6993impl<'a> MultiBufferRows<'a> {
6994    pub fn seek(&mut self, MultiBufferRow(row): MultiBufferRow) {
6995        self.point = Point::new(row, 0);
6996        self.cursor.seek(&self.point);
6997    }
6998}
6999
7000impl<'a> Iterator for MultiBufferRows<'a> {
7001    type Item = RowInfo;
7002
7003    fn next(&mut self) -> Option<Self::Item> {
7004        if self.is_empty && self.point.row == 0 {
7005            self.point += Point::new(1, 0);
7006            return Some(RowInfo {
7007                buffer_id: None,
7008                buffer_row: Some(0),
7009                multibuffer_row: Some(MultiBufferRow(0)),
7010                diff_status: None,
7011            });
7012        }
7013
7014        let mut region = self.cursor.region()?;
7015        while self.point >= region.range.end {
7016            self.cursor.next();
7017            if let Some(next_region) = self.cursor.region() {
7018                region = next_region;
7019            } else {
7020                if self.point == self.cursor.diff_transforms.end(&()).0 .0 {
7021                    let multibuffer_row = MultiBufferRow(self.point.row);
7022                    self.point += Point::new(1, 0);
7023                    let last_excerpt = self
7024                        .cursor
7025                        .excerpts
7026                        .item()
7027                        .or(self.cursor.excerpts.prev_item())?;
7028                    let last_row = last_excerpt
7029                        .range
7030                        .context
7031                        .end
7032                        .to_point(&last_excerpt.buffer)
7033                        .row;
7034                    return Some(RowInfo {
7035                        buffer_id: Some(last_excerpt.buffer_id),
7036                        buffer_row: Some(last_row),
7037                        multibuffer_row: Some(multibuffer_row),
7038                        diff_status: None,
7039                    });
7040                } else {
7041                    return None;
7042                }
7043            };
7044        }
7045
7046        let overshoot = self.point - region.range.start;
7047        let buffer_point = region.buffer_range.start + overshoot;
7048        let result = Some(RowInfo {
7049            buffer_id: Some(region.buffer.remote_id()),
7050            buffer_row: Some(buffer_point.row),
7051            multibuffer_row: Some(MultiBufferRow(self.point.row)),
7052            diff_status: region
7053                .diff_hunk_status
7054                .filter(|_| self.point < region.range.end),
7055        });
7056        self.point += Point::new(1, 0);
7057        result
7058    }
7059}
7060
7061impl<'a> MultiBufferChunks<'a> {
7062    pub fn offset(&self) -> usize {
7063        self.range.start
7064    }
7065
7066    pub fn seek(&mut self, range: Range<usize>) {
7067        self.diff_transforms.seek(&range.end, Bias::Right, &());
7068        let mut excerpt_end = self.diff_transforms.start().1;
7069        if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
7070            let overshoot = range.end - self.diff_transforms.start().0;
7071            excerpt_end.value += overshoot;
7072        }
7073
7074        self.diff_transforms.seek(&range.start, Bias::Right, &());
7075        let mut excerpt_start = self.diff_transforms.start().1;
7076        if let Some(DiffTransform::BufferContent { .. }) = self.diff_transforms.item() {
7077            let overshoot = range.start - self.diff_transforms.start().0;
7078            excerpt_start.value += overshoot;
7079        }
7080
7081        self.seek_to_excerpt_offset_range(excerpt_start..excerpt_end);
7082        self.buffer_chunk.take();
7083        self.range = range;
7084    }
7085
7086    fn seek_to_excerpt_offset_range(&mut self, new_range: Range<ExcerptOffset>) {
7087        self.excerpt_offset_range = new_range.clone();
7088        self.excerpts.seek(&new_range.start, Bias::Right, &());
7089        if let Some(excerpt) = self.excerpts.item() {
7090            let excerpt_start = *self.excerpts.start();
7091            if let Some(excerpt_chunks) = self
7092                .excerpt_chunks
7093                .as_mut()
7094                .filter(|chunks| excerpt.id == chunks.excerpt_id)
7095            {
7096                excerpt.seek_chunks(
7097                    excerpt_chunks,
7098                    (self.excerpt_offset_range.start - excerpt_start).value
7099                        ..(self.excerpt_offset_range.end - excerpt_start).value,
7100                );
7101            } else {
7102                self.excerpt_chunks = Some(excerpt.chunks_in_range(
7103                    (self.excerpt_offset_range.start - excerpt_start).value
7104                        ..(self.excerpt_offset_range.end - excerpt_start).value,
7105                    self.language_aware,
7106                ));
7107            }
7108        } else {
7109            self.excerpt_chunks = None;
7110        }
7111    }
7112
7113    fn next_excerpt_chunk(&mut self) -> Option<Chunk<'a>> {
7114        loop {
7115            if self.excerpt_offset_range.is_empty() {
7116                return None;
7117            } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
7118                self.excerpt_offset_range.start.value += chunk.text.len();
7119                return Some(chunk);
7120            } else {
7121                self.excerpts.next(&());
7122                let excerpt = self.excerpts.item()?;
7123                self.excerpt_chunks = Some(excerpt.chunks_in_range(
7124                    0..(self.excerpt_offset_range.end - *self.excerpts.start()).value,
7125                    self.language_aware,
7126                ));
7127            }
7128        }
7129    }
7130}
7131
7132impl<'a> Iterator for ReversedMultiBufferChunks<'a> {
7133    type Item = &'a str;
7134
7135    fn next(&mut self) -> Option<Self::Item> {
7136        let mut region = self.cursor.region()?;
7137        if self.offset == region.range.start {
7138            self.cursor.prev();
7139            region = self.cursor.region()?;
7140            let start_overshoot = self.start.saturating_sub(region.range.start);
7141            self.current_chunks = Some(region.buffer.reversed_chunks_in_range(
7142                region.buffer_range.start + start_overshoot..region.buffer_range.end,
7143            ));
7144        }
7145
7146        if self.offset == region.range.end && region.has_trailing_newline {
7147            self.offset -= 1;
7148            Some("\n")
7149        } else {
7150            let chunk = self.current_chunks.as_mut().unwrap().next()?;
7151            self.offset -= chunk.len();
7152            Some(chunk)
7153        }
7154    }
7155}
7156
7157impl<'a> Iterator for MultiBufferChunks<'a> {
7158    type Item = Chunk<'a>;
7159
7160    fn next(&mut self) -> Option<Chunk<'a>> {
7161        if self.range.start >= self.range.end {
7162            return None;
7163        }
7164        if self.range.start == self.diff_transforms.end(&()).0 {
7165            self.diff_transforms.next(&());
7166        }
7167
7168        let diff_transform_start = self.diff_transforms.start().0;
7169        let diff_transform_end = self.diff_transforms.end(&()).0;
7170        debug_assert!(self.range.start < diff_transform_end);
7171
7172        let diff_transform = self.diff_transforms.item()?;
7173        match diff_transform {
7174            DiffTransform::BufferContent { .. } => {
7175                let chunk = if let Some(chunk) = &mut self.buffer_chunk {
7176                    chunk
7177                } else {
7178                    let chunk = self.next_excerpt_chunk().unwrap();
7179                    self.buffer_chunk.insert(chunk)
7180                };
7181
7182                let chunk_end = self.range.start + chunk.text.len();
7183                let diff_transform_end = diff_transform_end.min(self.range.end);
7184
7185                if diff_transform_end < chunk_end {
7186                    let (before, after) =
7187                        chunk.text.split_at(diff_transform_end - self.range.start);
7188                    self.range.start = diff_transform_end;
7189                    chunk.text = after;
7190                    Some(Chunk {
7191                        text: before,
7192                        ..chunk.clone()
7193                    })
7194                } else {
7195                    self.range.start = chunk_end;
7196                    self.buffer_chunk.take()
7197                }
7198            }
7199            DiffTransform::DeletedHunk {
7200                buffer_id,
7201                base_text_byte_range,
7202                has_trailing_newline,
7203                ..
7204            } => {
7205                let base_text_start =
7206                    base_text_byte_range.start + self.range.start - diff_transform_start;
7207                let base_text_end =
7208                    base_text_byte_range.start + self.range.end - diff_transform_start;
7209                let base_text_end = base_text_end.min(base_text_byte_range.end);
7210
7211                let mut chunks = if let Some((_, mut chunks)) = self
7212                    .diff_base_chunks
7213                    .take()
7214                    .filter(|(id, _)| id == buffer_id)
7215                {
7216                    if chunks.range().start != base_text_start || chunks.range().end < base_text_end
7217                    {
7218                        chunks.seek(base_text_start..base_text_end);
7219                    }
7220                    chunks
7221                } else {
7222                    let base_buffer = &self.diffs.get(&buffer_id)?.base_text()?;
7223                    base_buffer.chunks(base_text_start..base_text_end, self.language_aware)
7224                };
7225
7226                let chunk = if let Some(chunk) = chunks.next() {
7227                    self.range.start += chunk.text.len();
7228                    self.diff_base_chunks = Some((*buffer_id, chunks));
7229                    chunk
7230                } else {
7231                    debug_assert!(has_trailing_newline);
7232                    self.range.start += "\n".len();
7233                    Chunk {
7234                        text: "\n",
7235                        ..Default::default()
7236                    }
7237                };
7238                Some(chunk)
7239            }
7240        }
7241    }
7242}
7243
7244impl<'a> MultiBufferBytes<'a> {
7245    fn consume(&mut self, len: usize) {
7246        self.range.start += len;
7247        self.chunk = &self.chunk[len..];
7248
7249        if !self.range.is_empty() && self.chunk.is_empty() {
7250            if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
7251                self.chunk = chunk;
7252            } else if self.has_trailing_newline {
7253                self.has_trailing_newline = false;
7254                self.chunk = b"\n";
7255            } else {
7256                self.cursor.next();
7257                if let Some(region) = self.cursor.region() {
7258                    let mut excerpt_bytes = region.buffer.bytes_in_range(
7259                        region.buffer_range.start
7260                            ..(region.buffer_range.start + self.range.end - region.range.start)
7261                                .min(region.buffer_range.end),
7262                    );
7263                    self.chunk = excerpt_bytes.next().unwrap_or(&[]);
7264                    self.excerpt_bytes = Some(excerpt_bytes);
7265                    self.has_trailing_newline =
7266                        region.has_trailing_newline && self.range.end >= region.range.end;
7267                    if self.chunk.is_empty() && self.has_trailing_newline {
7268                        self.has_trailing_newline = false;
7269                        self.chunk = b"\n";
7270                    }
7271                }
7272            }
7273        }
7274    }
7275}
7276
7277impl<'a> Iterator for MultiBufferBytes<'a> {
7278    type Item = &'a [u8];
7279
7280    fn next(&mut self) -> Option<Self::Item> {
7281        let chunk = self.chunk;
7282        if chunk.is_empty() {
7283            None
7284        } else {
7285            self.consume(chunk.len());
7286            Some(chunk)
7287        }
7288    }
7289}
7290
7291impl<'a> io::Read for MultiBufferBytes<'a> {
7292    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
7293        let len = cmp::min(buf.len(), self.chunk.len());
7294        buf[..len].copy_from_slice(&self.chunk[..len]);
7295        if len > 0 {
7296            self.consume(len);
7297        }
7298        Ok(len)
7299    }
7300}
7301
7302impl<'a> io::Read for ReversedMultiBufferBytes<'a> {
7303    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
7304        let len = cmp::min(buf.len(), self.chunk.len());
7305        buf[..len].copy_from_slice(&self.chunk[..len]);
7306        buf[..len].reverse();
7307        if len > 0 {
7308            self.range.end -= len;
7309            self.chunk = &self.chunk[..self.chunk.len() - len];
7310            if !self.range.is_empty() && self.chunk.is_empty() {
7311                if let Some(chunk) = self.chunks.next() {
7312                    self.chunk = chunk.as_bytes();
7313                }
7314            }
7315        }
7316        Ok(len)
7317    }
7318}
7319
7320impl<'a> Iterator for ExcerptChunks<'a> {
7321    type Item = Chunk<'a>;
7322
7323    fn next(&mut self) -> Option<Self::Item> {
7324        if let Some(chunk) = self.content_chunks.next() {
7325            return Some(chunk);
7326        }
7327
7328        if self.footer_height > 0 {
7329            let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
7330            self.footer_height = 0;
7331            return Some(Chunk {
7332                text,
7333                ..Default::default()
7334            });
7335        }
7336
7337        None
7338    }
7339}
7340
7341impl ToOffset for Point {
7342    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
7343        snapshot.point_to_offset(*self)
7344    }
7345}
7346
7347impl ToOffset for usize {
7348    #[track_caller]
7349    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
7350        assert!(*self <= snapshot.len(), "offset is out of range");
7351        *self
7352    }
7353}
7354
7355impl ToOffset for OffsetUtf16 {
7356    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
7357        snapshot.offset_utf16_to_offset(*self)
7358    }
7359}
7360
7361impl ToOffset for PointUtf16 {
7362    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
7363        snapshot.point_utf16_to_offset(*self)
7364    }
7365}
7366
7367impl ToOffsetUtf16 for OffsetUtf16 {
7368    fn to_offset_utf16(&self, _snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
7369        *self
7370    }
7371}
7372
7373impl ToOffsetUtf16 for usize {
7374    fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
7375        snapshot.offset_to_offset_utf16(*self)
7376    }
7377}
7378
7379impl ToPoint for usize {
7380    fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
7381        snapshot.offset_to_point(*self)
7382    }
7383}
7384
7385impl ToPoint for Point {
7386    fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
7387        *self
7388    }
7389}
7390
7391impl ToPointUtf16 for usize {
7392    fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
7393        snapshot.offset_to_point_utf16(*self)
7394    }
7395}
7396
7397impl ToPointUtf16 for Point {
7398    fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
7399        snapshot.point_to_point_utf16(*self)
7400    }
7401}
7402
7403impl ToPointUtf16 for PointUtf16 {
7404    fn to_point_utf16<'a>(&self, _: &MultiBufferSnapshot) -> PointUtf16 {
7405        *self
7406    }
7407}
7408
7409impl From<ExcerptId> for EntityId {
7410    fn from(id: ExcerptId) -> Self {
7411        EntityId::from(id.0 as u64)
7412    }
7413}
7414
7415pub fn build_excerpt_ranges<T>(
7416    buffer: &BufferSnapshot,
7417    ranges: &[Range<T>],
7418    context_line_count: u32,
7419) -> (Vec<ExcerptRange<Point>>, Vec<usize>)
7420where
7421    T: text::ToPoint,
7422{
7423    let max_point = buffer.max_point();
7424    let mut range_counts = Vec::new();
7425    let mut excerpt_ranges = Vec::new();
7426    let mut range_iter = ranges
7427        .iter()
7428        .map(|range| range.start.to_point(buffer)..range.end.to_point(buffer))
7429        .peekable();
7430    while let Some(range) = range_iter.next() {
7431        let excerpt_start = Point::new(range.start.row.saturating_sub(context_line_count), 0);
7432        let row = (range.end.row + context_line_count).min(max_point.row);
7433        let mut excerpt_end = Point::new(row, buffer.line_len(row));
7434
7435        let mut ranges_in_excerpt = 1;
7436
7437        while let Some(next_range) = range_iter.peek() {
7438            if next_range.start.row <= excerpt_end.row + context_line_count {
7439                let row = (next_range.end.row + context_line_count).min(max_point.row);
7440                excerpt_end = Point::new(row, buffer.line_len(row));
7441
7442                ranges_in_excerpt += 1;
7443                range_iter.next();
7444            } else {
7445                break;
7446            }
7447        }
7448
7449        excerpt_ranges.push(ExcerptRange {
7450            context: excerpt_start..excerpt_end,
7451            primary: Some(range),
7452        });
7453        range_counts.push(ranges_in_excerpt);
7454    }
7455
7456    (excerpt_ranges, range_counts)
7457}