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