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