multi_buffer.rs

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