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