multi_buffer.rs

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