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