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