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