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