multi_buffer.rs

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