multi_buffer.rs

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