multi_buffer.rs

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