multi_buffer.rs

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