multi_buffer.rs

   1mod anchor;
   2
   3pub use anchor::{Anchor, AnchorRangeExt, Offset};
   4use anyhow::{anyhow, Result};
   5use clock::ReplicaId;
   6use collections::{BTreeMap, Bound, HashMap, HashSet};
   7use futures::{channel::mpsc, SinkExt};
   8use gpui::{AppContext, EntityId, EventEmitter, Model, ModelContext, Task};
   9use itertools::Itertools;
  10use language::{
  11    language_settings::{language_settings, LanguageSettings},
  12    AutoindentMode, Buffer, BufferChunks, BufferRow, BufferSnapshot, Capability, CharClassifier,
  13    CharKind, Chunk, CursorShape, DiagnosticEntry, File, IndentGuide, IndentSize, Language,
  14    LanguageScope, OffsetRangeExt, OffsetUtf16, Outline, OutlineItem, Point, PointUtf16, Selection,
  15    TextDimension, ToOffset as _, ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _,
  16    TransactionId, Unclipped,
  17};
  18use smallvec::SmallVec;
  19use std::{
  20    any::type_name,
  21    borrow::Cow,
  22    cell::{Ref, RefCell},
  23    cmp, fmt,
  24    future::Future,
  25    io,
  26    iter::{self, FromIterator},
  27    mem,
  28    ops::{Range, RangeBounds, Sub},
  29    str,
  30    sync::Arc,
  31    time::{Duration, Instant},
  32};
  33use sum_tree::{Bias, Cursor, SumTree};
  34use text::{
  35    locator::Locator,
  36    subscription::{Subscription, Topic},
  37    BufferId, Edit, TextSummary,
  38};
  39use theme::SyntaxTheme;
  40
  41use util::post_inc;
  42
  43#[cfg(any(test, feature = "test-support"))]
  44use gpui::Context;
  45
  46const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];
  47
  48#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
  49pub struct ExcerptId(usize);
  50
  51impl From<ExcerptId> for EntityId {
  52    fn from(id: ExcerptId) -> Self {
  53        EntityId::from(id.0 as u64)
  54    }
  55}
  56
  57/// One or more [`Buffers`](Buffer) being edited in a single view.
  58///
  59/// See <https://zed.dev/features#multi-buffers>
  60pub struct MultiBuffer {
  61    /// A snapshot of the [`Excerpt`]s in the MultiBuffer.
  62    /// Use [`MultiBuffer::snapshot`] to get a up-to-date snapshot.
  63    snapshot: RefCell<MultiBufferSnapshot>,
  64    /// Contains the state of the buffers being edited
  65    buffers: RefCell<HashMap<BufferId, BufferState>>,
  66    subscriptions: Topic,
  67    /// If true, the multi-buffer only contains a single [`Buffer`] and a single [`Excerpt`]
  68    singleton: bool,
  69    history: History,
  70    title: Option<String>,
  71    capability: Capability,
  72}
  73
  74#[derive(Clone, Debug, PartialEq, Eq)]
  75pub enum Event {
  76    ExcerptsAdded {
  77        buffer: Model<Buffer>,
  78        predecessor: ExcerptId,
  79        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
  80    },
  81    ExcerptsRemoved {
  82        ids: Vec<ExcerptId>,
  83    },
  84    ExcerptsExpanded {
  85        ids: Vec<ExcerptId>,
  86    },
  87    ExcerptsEdited {
  88        ids: Vec<ExcerptId>,
  89    },
  90    Edited {
  91        singleton_buffer_edited: bool,
  92    },
  93    TransactionUndone {
  94        transaction_id: TransactionId,
  95    },
  96    Reloaded,
  97    ReloadNeeded,
  98    DiffBaseChanged,
  99    DiffUpdated {
 100        buffer: Model<Buffer>,
 101    },
 102    LanguageChanged(BufferId),
 103    CapabilityChanged,
 104    Reparsed(BufferId),
 105    Saved,
 106    FileHandleChanged,
 107    Closed,
 108    Discarded,
 109    DirtyChanged,
 110    DiagnosticsUpdated,
 111}
 112
 113/// A diff hunk, representing a range of consequent lines in a multibuffer.
 114#[derive(Debug, Clone, PartialEq, Eq)]
 115pub struct MultiBufferDiffHunk {
 116    /// The row range in the multibuffer where this diff hunk appears.
 117    pub row_range: Range<MultiBufferRow>,
 118    /// The buffer ID that this hunk belongs to.
 119    pub buffer_id: BufferId,
 120    /// The range of the underlying buffer that this hunk corresponds to.
 121    pub buffer_range: Range<text::Anchor>,
 122    /// The range within the buffer's diff base that this hunk corresponds to.
 123    pub diff_base_byte_range: Range<usize>,
 124}
 125
 126pub type MultiBufferPoint = Point;
 127
 128#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq, 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.file().map_or(false, |file| file.is_deleted());
2039            has_conflict |= buffer.has_conflict();
2040        }
2041        if edited {
2042            snapshot.edit_count += 1;
2043        }
2044        if non_text_state_updated {
2045            snapshot.non_text_state_update_count += 1;
2046        }
2047        snapshot.is_dirty = is_dirty;
2048        snapshot.has_deleted_file = has_deleted_file;
2049        snapshot.has_conflict = has_conflict;
2050
2051        excerpts_to_edit.sort_unstable_by_key(|(locator, _, _)| *locator);
2052
2053        let mut edits = Vec::new();
2054        let mut new_excerpts = SumTree::default();
2055        let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>(&());
2056
2057        for (locator, buffer, buffer_edited) in excerpts_to_edit {
2058            new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &());
2059            let old_excerpt = cursor.item().unwrap();
2060            let buffer = buffer.read(cx);
2061            let buffer_id = buffer.remote_id();
2062
2063            let mut new_excerpt;
2064            if buffer_edited {
2065                edits.extend(
2066                    buffer
2067                        .edits_since_in_range::<usize>(
2068                            old_excerpt.buffer.version(),
2069                            old_excerpt.range.context.clone(),
2070                        )
2071                        .map(|mut edit| {
2072                            let excerpt_old_start = cursor.start().1;
2073                            let excerpt_new_start = new_excerpts.summary().text.len;
2074                            edit.old.start += excerpt_old_start;
2075                            edit.old.end += excerpt_old_start;
2076                            edit.new.start += excerpt_new_start;
2077                            edit.new.end += excerpt_new_start;
2078                            edit
2079                        }),
2080                );
2081
2082                new_excerpt = Excerpt::new(
2083                    old_excerpt.id,
2084                    locator.clone(),
2085                    buffer_id,
2086                    buffer.snapshot(),
2087                    old_excerpt.range.clone(),
2088                    old_excerpt.has_trailing_newline,
2089                );
2090            } else {
2091                new_excerpt = old_excerpt.clone();
2092                new_excerpt.buffer = buffer.snapshot();
2093            }
2094
2095            new_excerpts.push(new_excerpt, &());
2096            cursor.next(&());
2097        }
2098        new_excerpts.append(cursor.suffix(&()), &());
2099
2100        drop(cursor);
2101        snapshot.excerpts = new_excerpts;
2102
2103        self.subscriptions.publish(edits);
2104    }
2105}
2106
2107#[cfg(any(test, feature = "test-support"))]
2108impl MultiBuffer {
2109    pub fn build_simple(text: &str, cx: &mut gpui::AppContext) -> Model<Self> {
2110        let buffer = cx.new_model(|cx| Buffer::local(text, cx));
2111        cx.new_model(|cx| Self::singleton(buffer, cx))
2112    }
2113
2114    pub fn build_multi<const COUNT: usize>(
2115        excerpts: [(&str, Vec<Range<Point>>); COUNT],
2116        cx: &mut gpui::AppContext,
2117    ) -> Model<Self> {
2118        let multi = cx.new_model(|_| Self::new(Capability::ReadWrite));
2119        for (text, ranges) in excerpts {
2120            let buffer = cx.new_model(|cx| Buffer::local(text, cx));
2121            let excerpt_ranges = ranges.into_iter().map(|range| ExcerptRange {
2122                context: range,
2123                primary: None,
2124            });
2125            multi.update(cx, |multi, cx| {
2126                multi.push_excerpts(buffer, excerpt_ranges, cx)
2127            });
2128        }
2129
2130        multi
2131    }
2132
2133    pub fn build_from_buffer(buffer: Model<Buffer>, cx: &mut gpui::AppContext) -> Model<Self> {
2134        cx.new_model(|cx| Self::singleton(buffer, cx))
2135    }
2136
2137    pub fn build_random(rng: &mut impl rand::Rng, cx: &mut gpui::AppContext) -> Model<Self> {
2138        cx.new_model(|cx| {
2139            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite);
2140            let mutation_count = rng.gen_range(1..=5);
2141            multibuffer.randomly_edit_excerpts(rng, mutation_count, cx);
2142            multibuffer
2143        })
2144    }
2145
2146    pub fn randomly_edit(
2147        &mut self,
2148        rng: &mut impl rand::Rng,
2149        edit_count: usize,
2150        cx: &mut ModelContext<Self>,
2151    ) {
2152        use util::RandomCharIter;
2153
2154        let snapshot = self.read(cx);
2155        let mut edits: Vec<(Range<usize>, Arc<str>)> = Vec::new();
2156        let mut last_end = None;
2157        for _ in 0..edit_count {
2158            if last_end.map_or(false, |last_end| last_end >= snapshot.len()) {
2159                break;
2160            }
2161
2162            let new_start = last_end.map_or(0, |last_end| last_end + 1);
2163            let end = snapshot.clip_offset(rng.gen_range(new_start..=snapshot.len()), Bias::Right);
2164            let start = snapshot.clip_offset(rng.gen_range(new_start..=end), Bias::Right);
2165            last_end = Some(end);
2166
2167            let mut range = start..end;
2168            if rng.gen_bool(0.2) {
2169                mem::swap(&mut range.start, &mut range.end);
2170            }
2171
2172            let new_text_len = rng.gen_range(0..10);
2173            let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
2174
2175            edits.push((range, new_text.into()));
2176        }
2177        log::info!("mutating multi-buffer with {:?}", edits);
2178        drop(snapshot);
2179
2180        self.edit(edits, None, cx);
2181    }
2182
2183    pub fn randomly_edit_excerpts(
2184        &mut self,
2185        rng: &mut impl rand::Rng,
2186        mutation_count: usize,
2187        cx: &mut ModelContext<Self>,
2188    ) {
2189        use rand::prelude::*;
2190        use std::env;
2191        use util::RandomCharIter;
2192
2193        let max_excerpts = env::var("MAX_EXCERPTS")
2194            .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))
2195            .unwrap_or(5);
2196
2197        let mut buffers = Vec::new();
2198        for _ in 0..mutation_count {
2199            if rng.gen_bool(0.05) {
2200                log::info!("Clearing multi-buffer");
2201                self.clear(cx);
2202                continue;
2203            } else if rng.gen_bool(0.1) && !self.excerpt_ids().is_empty() {
2204                let ids = self.excerpt_ids();
2205                let mut excerpts = HashSet::default();
2206                for _ in 0..rng.gen_range(0..ids.len()) {
2207                    excerpts.extend(ids.choose(rng).copied());
2208                }
2209
2210                let line_count = rng.gen_range(0..5);
2211
2212                log::info!("Expanding excerpts {excerpts:?} by {line_count} lines");
2213
2214                self.expand_excerpts(
2215                    excerpts.iter().cloned(),
2216                    line_count,
2217                    ExpandExcerptDirection::UpAndDown,
2218                    cx,
2219                );
2220                continue;
2221            }
2222
2223            let excerpt_ids = self.excerpt_ids();
2224            if excerpt_ids.is_empty() || (rng.gen() && excerpt_ids.len() < max_excerpts) {
2225                let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() {
2226                    let text = RandomCharIter::new(&mut *rng).take(10).collect::<String>();
2227                    buffers.push(cx.new_model(|cx| Buffer::local(text, cx)));
2228                    let buffer = buffers.last().unwrap().read(cx);
2229                    log::info!(
2230                        "Creating new buffer {} with text: {:?}",
2231                        buffer.remote_id(),
2232                        buffer.text()
2233                    );
2234                    buffers.last().unwrap().clone()
2235                } else {
2236                    self.buffers
2237                        .borrow()
2238                        .values()
2239                        .choose(rng)
2240                        .unwrap()
2241                        .buffer
2242                        .clone()
2243                };
2244
2245                let buffer = buffer_handle.read(cx);
2246                let buffer_text = buffer.text();
2247                let ranges = (0..rng.gen_range(0..5))
2248                    .map(|_| {
2249                        let end_ix =
2250                            buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
2251                        let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
2252                        ExcerptRange {
2253                            context: start_ix..end_ix,
2254                            primary: None,
2255                        }
2256                    })
2257                    .collect::<Vec<_>>();
2258                log::info!(
2259                    "Inserting excerpts from buffer {} and ranges {:?}: {:?}",
2260                    buffer_handle.read(cx).remote_id(),
2261                    ranges.iter().map(|r| &r.context).collect::<Vec<_>>(),
2262                    ranges
2263                        .iter()
2264                        .map(|r| &buffer_text[r.context.clone()])
2265                        .collect::<Vec<_>>()
2266                );
2267
2268                let excerpt_id = self.push_excerpts(buffer_handle.clone(), ranges, cx);
2269                log::info!("Inserted with ids: {:?}", excerpt_id);
2270            } else {
2271                let remove_count = rng.gen_range(1..=excerpt_ids.len());
2272                let mut excerpts_to_remove = excerpt_ids
2273                    .choose_multiple(rng, remove_count)
2274                    .cloned()
2275                    .collect::<Vec<_>>();
2276                let snapshot = self.snapshot.borrow();
2277                excerpts_to_remove.sort_unstable_by(|a, b| a.cmp(b, &snapshot));
2278                drop(snapshot);
2279                log::info!("Removing excerpts {:?}", excerpts_to_remove);
2280                self.remove_excerpts(excerpts_to_remove, cx);
2281            }
2282        }
2283    }
2284
2285    pub fn randomly_mutate(
2286        &mut self,
2287        rng: &mut impl rand::Rng,
2288        mutation_count: usize,
2289        cx: &mut ModelContext<Self>,
2290    ) {
2291        use rand::prelude::*;
2292
2293        if rng.gen_bool(0.7) || self.singleton {
2294            let buffer = self
2295                .buffers
2296                .borrow()
2297                .values()
2298                .choose(rng)
2299                .map(|state| state.buffer.clone());
2300
2301            if let Some(buffer) = buffer {
2302                buffer.update(cx, |buffer, cx| {
2303                    if rng.gen() {
2304                        buffer.randomly_edit(rng, mutation_count, cx);
2305                    } else {
2306                        buffer.randomly_undo_redo(rng, cx);
2307                    }
2308                });
2309            } else {
2310                self.randomly_edit(rng, mutation_count, cx);
2311            }
2312        } else {
2313            self.randomly_edit_excerpts(rng, mutation_count, cx);
2314        }
2315
2316        self.check_invariants(cx);
2317    }
2318
2319    fn check_invariants(&self, cx: &mut ModelContext<Self>) {
2320        let snapshot = self.read(cx);
2321        let excerpts = snapshot.excerpts.items(&());
2322        let excerpt_ids = snapshot.excerpt_ids.items(&());
2323
2324        for (ix, excerpt) in excerpts.iter().enumerate() {
2325            if ix == 0 {
2326                if excerpt.locator <= Locator::min() {
2327                    panic!("invalid first excerpt locator {:?}", excerpt.locator);
2328                }
2329            } else if excerpt.locator <= excerpts[ix - 1].locator {
2330                panic!("excerpts are out-of-order: {:?}", excerpts);
2331            }
2332        }
2333
2334        for (ix, entry) in excerpt_ids.iter().enumerate() {
2335            if ix == 0 {
2336                if entry.id.cmp(&ExcerptId::min(), &snapshot).is_le() {
2337                    panic!("invalid first excerpt id {:?}", entry.id);
2338                }
2339            } else if entry.id <= excerpt_ids[ix - 1].id {
2340                panic!("excerpt ids are out-of-order: {:?}", excerpt_ids);
2341            }
2342        }
2343    }
2344}
2345
2346impl EventEmitter<Event> for MultiBuffer {}
2347
2348impl MultiBufferSnapshot {
2349    pub fn text(&self) -> String {
2350        self.chunks(0..self.len(), false)
2351            .map(|chunk| chunk.text)
2352            .collect()
2353    }
2354
2355    pub fn reversed_chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
2356        let mut offset = position.to_offset(self);
2357        let mut cursor = self.excerpts.cursor::<usize>(&());
2358        cursor.seek(&offset, Bias::Left, &());
2359        let mut excerpt_chunks = cursor.item().map(|excerpt| {
2360            let end_before_footer = cursor.start() + excerpt.text_summary.len;
2361            let start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2362            let end = start + (cmp::min(offset, end_before_footer) - cursor.start());
2363            excerpt.buffer.reversed_chunks_in_range(start..end)
2364        });
2365        iter::from_fn(move || {
2366            if offset == *cursor.start() {
2367                cursor.prev(&());
2368                let excerpt = cursor.item()?;
2369                excerpt_chunks = Some(
2370                    excerpt
2371                        .buffer
2372                        .reversed_chunks_in_range(excerpt.range.context.clone()),
2373                );
2374            }
2375
2376            let excerpt = cursor.item().unwrap();
2377            if offset == cursor.end(&()) && excerpt.has_trailing_newline {
2378                offset -= 1;
2379                Some("\n")
2380            } else {
2381                let chunk = excerpt_chunks.as_mut().unwrap().next().unwrap();
2382                offset -= chunk.len();
2383                Some(chunk)
2384            }
2385        })
2386        .flat_map(|c| c.chars().rev())
2387    }
2388
2389    pub fn chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + '_ {
2390        let offset = position.to_offset(self);
2391        self.text_for_range(offset..self.len())
2392            .flat_map(|chunk| chunk.chars())
2393    }
2394
2395    pub fn text_for_range<T: ToOffset>(&self, range: Range<T>) -> impl Iterator<Item = &str> + '_ {
2396        self.chunks(range, false).map(|chunk| chunk.text)
2397    }
2398
2399    pub fn is_line_blank(&self, row: MultiBufferRow) -> bool {
2400        self.text_for_range(Point::new(row.0, 0)..Point::new(row.0, self.line_len(row)))
2401            .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
2402    }
2403
2404    pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
2405    where
2406        T: ToOffset,
2407    {
2408        let position = position.to_offset(self);
2409        position == self.clip_offset(position, Bias::Left)
2410            && self
2411                .bytes_in_range(position..self.len())
2412                .flatten()
2413                .copied()
2414                .take(needle.len())
2415                .eq(needle.bytes())
2416    }
2417
2418    pub fn surrounding_word<T: ToOffset>(
2419        &self,
2420        start: T,
2421        for_completion: bool,
2422    ) -> (Range<usize>, Option<CharKind>) {
2423        let mut start = start.to_offset(self);
2424        let mut end = start;
2425        let mut next_chars = self.chars_at(start).peekable();
2426        let mut prev_chars = self.reversed_chars_at(start).peekable();
2427
2428        let classifier = self
2429            .char_classifier_at(start)
2430            .for_completion(for_completion);
2431
2432        let word_kind = cmp::max(
2433            prev_chars.peek().copied().map(|c| classifier.kind(c)),
2434            next_chars.peek().copied().map(|c| classifier.kind(c)),
2435        );
2436
2437        for ch in prev_chars {
2438            if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
2439                start -= ch.len_utf8();
2440            } else {
2441                break;
2442            }
2443        }
2444
2445        for ch in next_chars {
2446            if Some(classifier.kind(ch)) == word_kind && ch != '\n' {
2447                end += ch.len_utf8();
2448            } else {
2449                break;
2450            }
2451        }
2452
2453        (start..end, word_kind)
2454    }
2455
2456    pub fn as_singleton(&self) -> Option<(&ExcerptId, BufferId, &BufferSnapshot)> {
2457        if self.singleton {
2458            self.excerpts
2459                .iter()
2460                .next()
2461                .map(|e| (&e.id, e.buffer_id, &e.buffer))
2462        } else {
2463            None
2464        }
2465    }
2466
2467    pub fn len(&self) -> usize {
2468        self.excerpts.summary().text.len
2469    }
2470
2471    pub fn is_empty(&self) -> bool {
2472        self.excerpts.summary().text.len == 0
2473    }
2474
2475    pub fn max_buffer_row(&self) -> MultiBufferRow {
2476        self.excerpts.summary().max_buffer_row
2477    }
2478
2479    pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
2480        if let Some((_, _, buffer)) = self.as_singleton() {
2481            return buffer.clip_offset(offset, bias);
2482        }
2483
2484        let mut cursor = self.excerpts.cursor::<usize>(&());
2485        cursor.seek(&offset, Bias::Right, &());
2486        let overshoot = if let Some(excerpt) = cursor.item() {
2487            let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2488            let buffer_offset = excerpt
2489                .buffer
2490                .clip_offset(excerpt_start + (offset - cursor.start()), bias);
2491            buffer_offset.saturating_sub(excerpt_start)
2492        } else {
2493            0
2494        };
2495        cursor.start() + overshoot
2496    }
2497
2498    pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
2499        if let Some((_, _, buffer)) = self.as_singleton() {
2500            return buffer.clip_point(point, bias);
2501        }
2502
2503        let mut cursor = self.excerpts.cursor::<Point>(&());
2504        cursor.seek(&point, Bias::Right, &());
2505        let overshoot = if let Some(excerpt) = cursor.item() {
2506            let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
2507            let buffer_point = excerpt
2508                .buffer
2509                .clip_point(excerpt_start + (point - cursor.start()), bias);
2510            buffer_point.saturating_sub(excerpt_start)
2511        } else {
2512            Point::zero()
2513        };
2514        *cursor.start() + overshoot
2515    }
2516
2517    pub fn clip_offset_utf16(&self, offset: OffsetUtf16, bias: Bias) -> OffsetUtf16 {
2518        if let Some((_, _, buffer)) = self.as_singleton() {
2519            return buffer.clip_offset_utf16(offset, bias);
2520        }
2521
2522        let mut cursor = self.excerpts.cursor::<OffsetUtf16>(&());
2523        cursor.seek(&offset, Bias::Right, &());
2524        let overshoot = if let Some(excerpt) = cursor.item() {
2525            let excerpt_start = excerpt.range.context.start.to_offset_utf16(&excerpt.buffer);
2526            let buffer_offset = excerpt
2527                .buffer
2528                .clip_offset_utf16(excerpt_start + (offset - cursor.start()), bias);
2529            OffsetUtf16(buffer_offset.0.saturating_sub(excerpt_start.0))
2530        } else {
2531            OffsetUtf16(0)
2532        };
2533        *cursor.start() + overshoot
2534    }
2535
2536    pub fn clip_point_utf16(&self, point: Unclipped<PointUtf16>, bias: Bias) -> PointUtf16 {
2537        if let Some((_, _, buffer)) = self.as_singleton() {
2538            return buffer.clip_point_utf16(point, bias);
2539        }
2540
2541        let mut cursor = self.excerpts.cursor::<PointUtf16>(&());
2542        cursor.seek(&point.0, Bias::Right, &());
2543        let overshoot = if let Some(excerpt) = cursor.item() {
2544            let excerpt_start = excerpt
2545                .buffer
2546                .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
2547            let buffer_point = excerpt
2548                .buffer
2549                .clip_point_utf16(Unclipped(excerpt_start + (point.0 - cursor.start())), bias);
2550            buffer_point.saturating_sub(excerpt_start)
2551        } else {
2552            PointUtf16::zero()
2553        };
2554        *cursor.start() + overshoot
2555    }
2556
2557    pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> MultiBufferBytes {
2558        let range = range.start.to_offset(self)..range.end.to_offset(self);
2559        let mut excerpts = self.excerpts.cursor::<usize>(&());
2560        excerpts.seek(&range.start, Bias::Right, &());
2561
2562        let mut chunk = &[][..];
2563        let excerpt_bytes = if let Some(excerpt) = excerpts.item() {
2564            let mut excerpt_bytes = excerpt
2565                .bytes_in_range(range.start - excerpts.start()..range.end - excerpts.start());
2566            chunk = excerpt_bytes.next().unwrap_or(&[][..]);
2567            Some(excerpt_bytes)
2568        } else {
2569            None
2570        };
2571        MultiBufferBytes {
2572            range,
2573            excerpts,
2574            excerpt_bytes,
2575            chunk,
2576        }
2577    }
2578
2579    pub fn reversed_bytes_in_range<T: ToOffset>(
2580        &self,
2581        range: Range<T>,
2582    ) -> ReversedMultiBufferBytes {
2583        let range = range.start.to_offset(self)..range.end.to_offset(self);
2584        let mut excerpts = self.excerpts.cursor::<usize>(&());
2585        excerpts.seek(&range.end, Bias::Left, &());
2586
2587        let mut chunk = &[][..];
2588        let excerpt_bytes = if let Some(excerpt) = excerpts.item() {
2589            let mut excerpt_bytes = excerpt.reversed_bytes_in_range(
2590                range.start.saturating_sub(*excerpts.start())..range.end - *excerpts.start(),
2591            );
2592            chunk = excerpt_bytes.next().unwrap_or(&[][..]);
2593            Some(excerpt_bytes)
2594        } else {
2595            None
2596        };
2597
2598        ReversedMultiBufferBytes {
2599            range,
2600            excerpts,
2601            excerpt_bytes,
2602            chunk,
2603        }
2604    }
2605
2606    pub fn buffer_rows(&self, start_row: MultiBufferRow) -> MultiBufferRows {
2607        let mut result = MultiBufferRows {
2608            buffer_row_range: 0..0,
2609            excerpts: self.excerpts.cursor(&()),
2610        };
2611        result.seek(start_row);
2612        result
2613    }
2614
2615    pub fn chunks<T: ToOffset>(&self, range: Range<T>, language_aware: bool) -> MultiBufferChunks {
2616        let range = range.start.to_offset(self)..range.end.to_offset(self);
2617        let mut chunks = MultiBufferChunks {
2618            range: range.clone(),
2619            excerpts: self.excerpts.cursor(&()),
2620            excerpt_chunks: None,
2621            language_aware,
2622        };
2623        chunks.seek(range);
2624        chunks
2625    }
2626
2627    pub fn offset_to_point(&self, offset: usize) -> Point {
2628        if let Some((_, _, buffer)) = self.as_singleton() {
2629            return buffer.offset_to_point(offset);
2630        }
2631
2632        let mut cursor = self.excerpts.cursor::<(usize, Point)>(&());
2633        cursor.seek(&offset, Bias::Right, &());
2634        if let Some(excerpt) = cursor.item() {
2635            let (start_offset, start_point) = cursor.start();
2636            let overshoot = offset - start_offset;
2637            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2638            let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
2639            let buffer_point = excerpt
2640                .buffer
2641                .offset_to_point(excerpt_start_offset + overshoot);
2642            *start_point + (buffer_point - excerpt_start_point)
2643        } else {
2644            self.excerpts.summary().text.lines
2645        }
2646    }
2647
2648    pub fn offset_to_point_utf16(&self, offset: usize) -> PointUtf16 {
2649        if let Some((_, _, buffer)) = self.as_singleton() {
2650            return buffer.offset_to_point_utf16(offset);
2651        }
2652
2653        let mut cursor = self.excerpts.cursor::<(usize, PointUtf16)>(&());
2654        cursor.seek(&offset, Bias::Right, &());
2655        if let Some(excerpt) = cursor.item() {
2656            let (start_offset, start_point) = cursor.start();
2657            let overshoot = offset - start_offset;
2658            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2659            let excerpt_start_point = excerpt.range.context.start.to_point_utf16(&excerpt.buffer);
2660            let buffer_point = excerpt
2661                .buffer
2662                .offset_to_point_utf16(excerpt_start_offset + overshoot);
2663            *start_point + (buffer_point - excerpt_start_point)
2664        } else {
2665            self.excerpts.summary().text.lines_utf16()
2666        }
2667    }
2668
2669    pub fn point_to_point_utf16(&self, point: Point) -> PointUtf16 {
2670        if let Some((_, _, buffer)) = self.as_singleton() {
2671            return buffer.point_to_point_utf16(point);
2672        }
2673
2674        let mut cursor = self.excerpts.cursor::<(Point, PointUtf16)>(&());
2675        cursor.seek(&point, Bias::Right, &());
2676        if let Some(excerpt) = cursor.item() {
2677            let (start_offset, start_point) = cursor.start();
2678            let overshoot = point - start_offset;
2679            let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
2680            let excerpt_start_point_utf16 =
2681                excerpt.range.context.start.to_point_utf16(&excerpt.buffer);
2682            let buffer_point = excerpt
2683                .buffer
2684                .point_to_point_utf16(excerpt_start_point + overshoot);
2685            *start_point + (buffer_point - excerpt_start_point_utf16)
2686        } else {
2687            self.excerpts.summary().text.lines_utf16()
2688        }
2689    }
2690
2691    pub fn point_to_offset(&self, point: Point) -> usize {
2692        if let Some((_, _, buffer)) = self.as_singleton() {
2693            return buffer.point_to_offset(point);
2694        }
2695
2696        let mut cursor = self.excerpts.cursor::<(Point, usize)>(&());
2697        cursor.seek(&point, Bias::Right, &());
2698        if let Some(excerpt) = cursor.item() {
2699            let (start_point, start_offset) = cursor.start();
2700            let overshoot = point - start_point;
2701            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2702            let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer);
2703            let buffer_offset = excerpt
2704                .buffer
2705                .point_to_offset(excerpt_start_point + overshoot);
2706            *start_offset + buffer_offset - excerpt_start_offset
2707        } else {
2708            self.excerpts.summary().text.len
2709        }
2710    }
2711
2712    pub fn offset_utf16_to_offset(&self, offset_utf16: OffsetUtf16) -> usize {
2713        if let Some((_, _, buffer)) = self.as_singleton() {
2714            return buffer.offset_utf16_to_offset(offset_utf16);
2715        }
2716
2717        let mut cursor = self.excerpts.cursor::<(OffsetUtf16, usize)>(&());
2718        cursor.seek(&offset_utf16, Bias::Right, &());
2719        if let Some(excerpt) = cursor.item() {
2720            let (start_offset_utf16, start_offset) = cursor.start();
2721            let overshoot = offset_utf16 - start_offset_utf16;
2722            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2723            let excerpt_start_offset_utf16 =
2724                excerpt.buffer.offset_to_offset_utf16(excerpt_start_offset);
2725            let buffer_offset = excerpt
2726                .buffer
2727                .offset_utf16_to_offset(excerpt_start_offset_utf16 + overshoot);
2728            *start_offset + (buffer_offset - excerpt_start_offset)
2729        } else {
2730            self.excerpts.summary().text.len
2731        }
2732    }
2733
2734    pub fn offset_to_offset_utf16(&self, offset: usize) -> OffsetUtf16 {
2735        if let Some((_, _, buffer)) = self.as_singleton() {
2736            return buffer.offset_to_offset_utf16(offset);
2737        }
2738
2739        let mut cursor = self.excerpts.cursor::<(usize, OffsetUtf16)>(&());
2740        cursor.seek(&offset, Bias::Right, &());
2741        if let Some(excerpt) = cursor.item() {
2742            let (start_offset, start_offset_utf16) = cursor.start();
2743            let overshoot = offset - start_offset;
2744            let excerpt_start_offset_utf16 =
2745                excerpt.range.context.start.to_offset_utf16(&excerpt.buffer);
2746            let excerpt_start_offset = excerpt
2747                .buffer
2748                .offset_utf16_to_offset(excerpt_start_offset_utf16);
2749            let buffer_offset_utf16 = excerpt
2750                .buffer
2751                .offset_to_offset_utf16(excerpt_start_offset + overshoot);
2752            *start_offset_utf16 + (buffer_offset_utf16 - excerpt_start_offset_utf16)
2753        } else {
2754            self.excerpts.summary().text.len_utf16
2755        }
2756    }
2757
2758    pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
2759        if let Some((_, _, buffer)) = self.as_singleton() {
2760            return buffer.point_utf16_to_offset(point);
2761        }
2762
2763        let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>(&());
2764        cursor.seek(&point, Bias::Right, &());
2765        if let Some(excerpt) = cursor.item() {
2766            let (start_point, start_offset) = cursor.start();
2767            let overshoot = point - start_point;
2768            let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer);
2769            let excerpt_start_point = excerpt
2770                .buffer
2771                .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer));
2772            let buffer_offset = excerpt
2773                .buffer
2774                .point_utf16_to_offset(excerpt_start_point + overshoot);
2775            *start_offset + (buffer_offset - excerpt_start_offset)
2776        } else {
2777            self.excerpts.summary().text.len
2778        }
2779    }
2780
2781    pub fn point_to_buffer_offset<T: ToOffset>(
2782        &self,
2783        point: T,
2784    ) -> Option<(&BufferSnapshot, usize)> {
2785        let offset = point.to_offset(self);
2786        let mut cursor = self.excerpts.cursor::<usize>(&());
2787        cursor.seek(&offset, Bias::Right, &());
2788        if cursor.item().is_none() {
2789            cursor.prev(&());
2790        }
2791
2792        cursor.item().map(|excerpt| {
2793            let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2794            let buffer_point = excerpt_start + offset - *cursor.start();
2795            (&excerpt.buffer, buffer_point)
2796        })
2797    }
2798
2799    pub fn suggested_indents(
2800        &self,
2801        rows: impl IntoIterator<Item = u32>,
2802        cx: &AppContext,
2803    ) -> BTreeMap<MultiBufferRow, IndentSize> {
2804        let mut result = BTreeMap::new();
2805
2806        let mut rows_for_excerpt = Vec::new();
2807        let mut cursor = self.excerpts.cursor::<Point>(&());
2808        let mut rows = rows.into_iter().peekable();
2809        let mut prev_row = u32::MAX;
2810        let mut prev_language_indent_size = IndentSize::default();
2811
2812        while let Some(row) = rows.next() {
2813            cursor.seek(&Point::new(row, 0), Bias::Right, &());
2814            let excerpt = match cursor.item() {
2815                Some(excerpt) => excerpt,
2816                _ => continue,
2817            };
2818
2819            // Retrieve the language and indent size once for each disjoint region being indented.
2820            let single_indent_size = if row.saturating_sub(1) == prev_row {
2821                prev_language_indent_size
2822            } else {
2823                excerpt
2824                    .buffer
2825                    .language_indent_size_at(Point::new(row, 0), cx)
2826            };
2827            prev_language_indent_size = single_indent_size;
2828            prev_row = row;
2829
2830            let start_buffer_row = excerpt.range.context.start.to_point(&excerpt.buffer).row;
2831            let start_multibuffer_row = cursor.start().row;
2832
2833            rows_for_excerpt.push(row);
2834            while let Some(next_row) = rows.peek().copied() {
2835                if cursor.end(&()).row > next_row {
2836                    rows_for_excerpt.push(next_row);
2837                    rows.next();
2838                } else {
2839                    break;
2840                }
2841            }
2842
2843            let buffer_rows = rows_for_excerpt
2844                .drain(..)
2845                .map(|row| start_buffer_row + row - start_multibuffer_row);
2846            let buffer_indents = excerpt
2847                .buffer
2848                .suggested_indents(buffer_rows, single_indent_size);
2849            let multibuffer_indents = buffer_indents.into_iter().map(|(row, indent)| {
2850                (
2851                    MultiBufferRow(start_multibuffer_row + row - start_buffer_row),
2852                    indent,
2853                )
2854            });
2855            result.extend(multibuffer_indents);
2856        }
2857
2858        result
2859    }
2860
2861    pub fn indent_size_for_line(&self, row: MultiBufferRow) -> IndentSize {
2862        if let Some((buffer, range)) = self.buffer_line_for_row(row) {
2863            let mut size = buffer.indent_size_for_line(range.start.row);
2864            size.len = size
2865                .len
2866                .min(range.end.column)
2867                .saturating_sub(range.start.column);
2868            size
2869        } else {
2870            IndentSize::spaces(0)
2871        }
2872    }
2873
2874    pub fn indent_and_comment_for_line(&self, row: MultiBufferRow, cx: &AppContext) -> String {
2875        let mut indent = self.indent_size_for_line(row).chars().collect::<String>();
2876
2877        if self.settings_at(0, cx).extend_comment_on_newline {
2878            if let Some(language_scope) = self.language_scope_at(Point::new(row.0, 0)) {
2879                let delimiters = language_scope.line_comment_prefixes();
2880                for delimiter in delimiters {
2881                    if *self
2882                        .chars_at(Point::new(row.0, indent.len() as u32))
2883                        .take(delimiter.chars().count())
2884                        .collect::<String>()
2885                        .as_str()
2886                        == **delimiter
2887                    {
2888                        indent.push_str(&delimiter);
2889                        break;
2890                    }
2891                }
2892            }
2893        }
2894
2895        indent
2896    }
2897
2898    pub fn prev_non_blank_row(&self, mut row: MultiBufferRow) -> Option<MultiBufferRow> {
2899        while row.0 > 0 {
2900            row.0 -= 1;
2901            if !self.is_line_blank(row) {
2902                return Some(row);
2903            }
2904        }
2905        None
2906    }
2907
2908    pub fn line_len(&self, row: MultiBufferRow) -> u32 {
2909        if let Some((_, range)) = self.buffer_line_for_row(row) {
2910            range.end.column - range.start.column
2911        } else {
2912            0
2913        }
2914    }
2915
2916    pub fn buffer_line_for_row(
2917        &self,
2918        row: MultiBufferRow,
2919    ) -> Option<(&BufferSnapshot, Range<Point>)> {
2920        let mut cursor = self.excerpts.cursor::<Point>(&());
2921        let point = Point::new(row.0, 0);
2922        cursor.seek(&point, Bias::Right, &());
2923        if cursor.item().is_none() && *cursor.start() == point {
2924            cursor.prev(&());
2925        }
2926        if let Some(excerpt) = cursor.item() {
2927            let overshoot = row.0 - cursor.start().row;
2928            let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer);
2929            let excerpt_end = excerpt.range.context.end.to_point(&excerpt.buffer);
2930            let buffer_row = excerpt_start.row + overshoot;
2931            let line_start = Point::new(buffer_row, 0);
2932            let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
2933            return Some((
2934                &excerpt.buffer,
2935                line_start.max(excerpt_start)..line_end.min(excerpt_end),
2936            ));
2937        }
2938        None
2939    }
2940
2941    pub fn max_point(&self) -> Point {
2942        self.text_summary().lines
2943    }
2944
2945    pub fn text_summary(&self) -> TextSummary {
2946        self.excerpts.summary().text.clone()
2947    }
2948
2949    pub fn text_summary_for_range<D, O>(&self, range: Range<O>) -> D
2950    where
2951        D: TextDimension,
2952        O: ToOffset,
2953    {
2954        let mut summary = D::zero(&());
2955        let mut range = range.start.to_offset(self)..range.end.to_offset(self);
2956        let mut cursor = self.excerpts.cursor::<usize>(&());
2957        cursor.seek(&range.start, Bias::Right, &());
2958        if let Some(excerpt) = cursor.item() {
2959            let mut end_before_newline = cursor.end(&());
2960            if excerpt.has_trailing_newline {
2961                end_before_newline -= 1;
2962            }
2963
2964            let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2965            let start_in_excerpt = excerpt_start + (range.start - cursor.start());
2966            let end_in_excerpt =
2967                excerpt_start + (cmp::min(end_before_newline, range.end) - cursor.start());
2968            summary.add_assign(
2969                &excerpt
2970                    .buffer
2971                    .text_summary_for_range(start_in_excerpt..end_in_excerpt),
2972            );
2973
2974            if range.end > end_before_newline {
2975                summary.add_assign(&D::from_text_summary(&TextSummary::from("\n")));
2976            }
2977
2978            cursor.next(&());
2979        }
2980
2981        if range.end > *cursor.start() {
2982            summary.add_assign(&D::from_text_summary(&cursor.summary::<_, TextSummary>(
2983                &range.end,
2984                Bias::Right,
2985                &(),
2986            )));
2987            if let Some(excerpt) = cursor.item() {
2988                range.end = cmp::max(*cursor.start(), range.end);
2989
2990                let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
2991                let end_in_excerpt = excerpt_start + (range.end - cursor.start());
2992                summary.add_assign(
2993                    &excerpt
2994                        .buffer
2995                        .text_summary_for_range(excerpt_start..end_in_excerpt),
2996                );
2997            }
2998        }
2999
3000        summary
3001    }
3002
3003    pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
3004    where
3005        D: TextDimension + Ord + Sub<D, Output = D>,
3006    {
3007        let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&());
3008        let locator = self.excerpt_locator_for_id(anchor.excerpt_id);
3009
3010        cursor.seek(locator, Bias::Left, &());
3011        if cursor.item().is_none() {
3012            cursor.next(&());
3013        }
3014
3015        let mut position = D::from_text_summary(&cursor.start().text);
3016        if let Some(excerpt) = cursor.item() {
3017            if excerpt.id == anchor.excerpt_id {
3018                let excerpt_buffer_start =
3019                    excerpt.range.context.start.summary::<D>(&excerpt.buffer);
3020                let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(&excerpt.buffer);
3021                let buffer_position = cmp::min(
3022                    excerpt_buffer_end,
3023                    anchor.text_anchor.summary::<D>(&excerpt.buffer),
3024                );
3025                if buffer_position > excerpt_buffer_start {
3026                    position.add_assign(&(buffer_position - excerpt_buffer_start));
3027                }
3028            }
3029        }
3030        position
3031    }
3032
3033    pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
3034    where
3035        D: TextDimension + Ord + Sub<D, Output = D>,
3036        I: 'a + IntoIterator<Item = &'a Anchor>,
3037    {
3038        if let Some((_, _, buffer)) = self.as_singleton() {
3039            return buffer
3040                .summaries_for_anchors(anchors.into_iter().map(|a| &a.text_anchor))
3041                .collect();
3042        }
3043
3044        let mut anchors = anchors.into_iter().peekable();
3045        let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&());
3046        let mut summaries = Vec::new();
3047        while let Some(anchor) = anchors.peek() {
3048            let excerpt_id = anchor.excerpt_id;
3049            let excerpt_anchors = iter::from_fn(|| {
3050                let anchor = anchors.peek()?;
3051                if anchor.excerpt_id == excerpt_id {
3052                    Some(&anchors.next().unwrap().text_anchor)
3053                } else {
3054                    None
3055                }
3056            });
3057
3058            let locator = self.excerpt_locator_for_id(excerpt_id);
3059            cursor.seek_forward(locator, Bias::Left, &());
3060            if cursor.item().is_none() {
3061                cursor.next(&());
3062            }
3063
3064            let position = D::from_text_summary(&cursor.start().text);
3065            if let Some(excerpt) = cursor.item() {
3066                if excerpt.id == excerpt_id {
3067                    let excerpt_buffer_start =
3068                        excerpt.range.context.start.summary::<D>(&excerpt.buffer);
3069                    let excerpt_buffer_end =
3070                        excerpt.range.context.end.summary::<D>(&excerpt.buffer);
3071                    summaries.extend(
3072                        excerpt
3073                            .buffer
3074                            .summaries_for_anchors::<D, _>(excerpt_anchors)
3075                            .map(move |summary| {
3076                                let summary = cmp::min(excerpt_buffer_end.clone(), summary);
3077                                let mut position = position.clone();
3078                                let excerpt_buffer_start = excerpt_buffer_start.clone();
3079                                if summary > excerpt_buffer_start {
3080                                    position.add_assign(&(summary - excerpt_buffer_start));
3081                                }
3082                                position
3083                            }),
3084                    );
3085                    continue;
3086                }
3087            }
3088
3089            summaries.extend(excerpt_anchors.map(|_| position.clone()));
3090        }
3091
3092        summaries
3093    }
3094
3095    pub fn dimensions_from_points<'a, D>(
3096        &'a self,
3097        points: impl 'a + IntoIterator<Item = Point>,
3098    ) -> impl 'a + Iterator<Item = D>
3099    where
3100        D: TextDimension,
3101    {
3102        let mut cursor = self.excerpts.cursor::<TextSummary>(&());
3103        let mut memoized_source_start: Option<Point> = None;
3104        let mut points = points.into_iter();
3105        std::iter::from_fn(move || {
3106            let point = points.next()?;
3107
3108            // Clear the memoized source start if the point is in a different excerpt than previous.
3109            if memoized_source_start.map_or(false, |_| point >= cursor.end(&()).lines) {
3110                memoized_source_start = None;
3111            }
3112
3113            // Now determine where the excerpt containing the point starts in its source buffer.
3114            // We'll use this value to calculate overshoot next.
3115            let source_start = if let Some(source_start) = memoized_source_start {
3116                source_start
3117            } else {
3118                cursor.seek_forward(&point, Bias::Right, &());
3119                if let Some(excerpt) = cursor.item() {
3120                    let source_start = excerpt.range.context.start.to_point(&excerpt.buffer);
3121                    memoized_source_start = Some(source_start);
3122                    source_start
3123                } else {
3124                    return Some(D::from_text_summary(cursor.start()));
3125                }
3126            };
3127
3128            // First, assume the output dimension is at least the start of the excerpt containing the point
3129            let mut output = D::from_text_summary(cursor.start());
3130
3131            // If the point lands within its excerpt, calculate and add the overshoot in dimension D.
3132            if let Some(excerpt) = cursor.item() {
3133                let overshoot = point - cursor.start().lines;
3134                if !overshoot.is_zero() {
3135                    let end_in_excerpt = source_start + overshoot;
3136                    output.add_assign(
3137                        &excerpt
3138                            .buffer
3139                            .text_summary_for_range::<D, _>(source_start..end_in_excerpt),
3140                    );
3141                }
3142            }
3143            Some(output)
3144        })
3145    }
3146
3147    pub fn refresh_anchors<'a, I>(&'a self, anchors: I) -> Vec<(usize, Anchor, bool)>
3148    where
3149        I: 'a + IntoIterator<Item = &'a Anchor>,
3150    {
3151        let mut anchors = anchors.into_iter().enumerate().peekable();
3152        let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
3153        cursor.next(&());
3154
3155        let mut result = Vec::new();
3156
3157        while let Some((_, anchor)) = anchors.peek() {
3158            let old_excerpt_id = anchor.excerpt_id;
3159
3160            // Find the location where this anchor's excerpt should be.
3161            let old_locator = self.excerpt_locator_for_id(old_excerpt_id);
3162            cursor.seek_forward(&Some(old_locator), Bias::Left, &());
3163
3164            if cursor.item().is_none() {
3165                cursor.next(&());
3166            }
3167
3168            let next_excerpt = cursor.item();
3169            let prev_excerpt = cursor.prev_item();
3170
3171            // Process all of the anchors for this excerpt.
3172            while let Some((_, anchor)) = anchors.peek() {
3173                if anchor.excerpt_id != old_excerpt_id {
3174                    break;
3175                }
3176                let (anchor_ix, anchor) = anchors.next().unwrap();
3177                let mut anchor = *anchor;
3178
3179                // Leave min and max anchors unchanged if invalid or
3180                // if the old excerpt still exists at this location
3181                let mut kept_position = next_excerpt
3182                    .map_or(false, |e| e.id == old_excerpt_id && e.contains(&anchor))
3183                    || old_excerpt_id == ExcerptId::max()
3184                    || old_excerpt_id == ExcerptId::min();
3185
3186                // If the old excerpt no longer exists at this location, then attempt to
3187                // find an equivalent position for this anchor in an adjacent excerpt.
3188                if !kept_position {
3189                    for excerpt in [next_excerpt, prev_excerpt].iter().filter_map(|e| *e) {
3190                        if excerpt.contains(&anchor) {
3191                            anchor.excerpt_id = excerpt.id;
3192                            kept_position = true;
3193                            break;
3194                        }
3195                    }
3196                }
3197
3198                // If there's no adjacent excerpt that contains the anchor's position,
3199                // then report that the anchor has lost its position.
3200                if !kept_position {
3201                    anchor = if let Some(excerpt) = next_excerpt {
3202                        let mut text_anchor = excerpt
3203                            .range
3204                            .context
3205                            .start
3206                            .bias(anchor.text_anchor.bias, &excerpt.buffer);
3207                        if text_anchor
3208                            .cmp(&excerpt.range.context.end, &excerpt.buffer)
3209                            .is_gt()
3210                        {
3211                            text_anchor = excerpt.range.context.end;
3212                        }
3213                        Anchor {
3214                            buffer_id: Some(excerpt.buffer_id),
3215                            excerpt_id: excerpt.id,
3216                            text_anchor,
3217                        }
3218                    } else if let Some(excerpt) = prev_excerpt {
3219                        let mut text_anchor = excerpt
3220                            .range
3221                            .context
3222                            .end
3223                            .bias(anchor.text_anchor.bias, &excerpt.buffer);
3224                        if text_anchor
3225                            .cmp(&excerpt.range.context.start, &excerpt.buffer)
3226                            .is_lt()
3227                        {
3228                            text_anchor = excerpt.range.context.start;
3229                        }
3230                        Anchor {
3231                            buffer_id: Some(excerpt.buffer_id),
3232                            excerpt_id: excerpt.id,
3233                            text_anchor,
3234                        }
3235                    } else if anchor.text_anchor.bias == Bias::Left {
3236                        Anchor::min()
3237                    } else {
3238                        Anchor::max()
3239                    };
3240                }
3241
3242                result.push((anchor_ix, anchor, kept_position));
3243            }
3244        }
3245        result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self));
3246        result
3247    }
3248
3249    pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
3250        self.anchor_at(position, Bias::Left)
3251    }
3252
3253    pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
3254        self.anchor_at(position, Bias::Right)
3255    }
3256
3257    pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
3258        let offset = position.to_offset(self);
3259        if let Some((excerpt_id, buffer_id, buffer)) = self.as_singleton() {
3260            return Anchor {
3261                buffer_id: Some(buffer_id),
3262                excerpt_id: *excerpt_id,
3263                text_anchor: buffer.anchor_at(offset, bias),
3264            };
3265        }
3266
3267        let mut cursor = self.excerpts.cursor::<(usize, Option<ExcerptId>)>(&());
3268        cursor.seek(&offset, Bias::Right, &());
3269        if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left {
3270            cursor.prev(&());
3271        }
3272        if let Some(excerpt) = cursor.item() {
3273            let mut overshoot = offset.saturating_sub(cursor.start().0);
3274            if excerpt.has_trailing_newline && offset == cursor.end(&()).0 {
3275                overshoot -= 1;
3276                bias = Bias::Right;
3277            }
3278
3279            let buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
3280            let text_anchor =
3281                excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
3282            Anchor {
3283                buffer_id: Some(excerpt.buffer_id),
3284                excerpt_id: excerpt.id,
3285                text_anchor,
3286            }
3287        } else if offset == 0 && bias == Bias::Left {
3288            Anchor::min()
3289        } else {
3290            Anchor::max()
3291        }
3292    }
3293
3294    /// Returns an anchor for the given excerpt and text anchor,
3295    /// returns None if the excerpt_id is no longer valid.
3296    pub fn anchor_in_excerpt(
3297        &self,
3298        excerpt_id: ExcerptId,
3299        text_anchor: text::Anchor,
3300    ) -> Option<Anchor> {
3301        let locator = self.excerpt_locator_for_id(excerpt_id);
3302        let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
3303        cursor.seek(locator, Bias::Left, &());
3304        if let Some(excerpt) = cursor.item() {
3305            if excerpt.id == excerpt_id {
3306                let text_anchor = excerpt.clip_anchor(text_anchor);
3307                drop(cursor);
3308                return Some(Anchor {
3309                    buffer_id: Some(excerpt.buffer_id),
3310                    excerpt_id,
3311                    text_anchor,
3312                });
3313            }
3314        }
3315        None
3316    }
3317
3318    pub fn context_range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<Range<text::Anchor>> {
3319        Some(self.excerpt(excerpt_id)?.range.context.clone())
3320    }
3321
3322    pub fn can_resolve(&self, anchor: &Anchor) -> bool {
3323        if anchor.excerpt_id == ExcerptId::min() || anchor.excerpt_id == ExcerptId::max() {
3324            true
3325        } else if let Some(excerpt) = self.excerpt(anchor.excerpt_id) {
3326            excerpt.buffer.can_resolve(&anchor.text_anchor)
3327        } else {
3328            false
3329        }
3330    }
3331
3332    pub fn excerpts(
3333        &self,
3334    ) -> impl Iterator<Item = (ExcerptId, &BufferSnapshot, ExcerptRange<text::Anchor>)> {
3335        self.excerpts
3336            .iter()
3337            .map(|excerpt| (excerpt.id, &excerpt.buffer, excerpt.range.clone()))
3338    }
3339
3340    fn excerpts_for_range<T: ToOffset>(
3341        &self,
3342        range: Range<T>,
3343    ) -> impl Iterator<Item = (&Excerpt, usize)> + '_ {
3344        let range = range.start.to_offset(self)..range.end.to_offset(self);
3345
3346        let mut cursor = self.excerpts.cursor::<usize>(&());
3347        cursor.seek(&range.start, Bias::Right, &());
3348        cursor.prev(&());
3349
3350        iter::from_fn(move || {
3351            cursor.next(&());
3352            if cursor.start() < &range.end {
3353                cursor.item().map(|item| (item, *cursor.start()))
3354            } else {
3355                None
3356            }
3357        })
3358    }
3359
3360    pub fn excerpt_boundaries_in_range<R, T>(
3361        &self,
3362        range: R,
3363    ) -> impl Iterator<Item = ExcerptBoundary> + '_
3364    where
3365        R: RangeBounds<T>,
3366        T: ToOffset,
3367    {
3368        let start_offset;
3369        let start = match range.start_bound() {
3370            Bound::Included(start) => {
3371                start_offset = start.to_offset(self);
3372                Bound::Included(start_offset)
3373            }
3374            Bound::Excluded(start) => {
3375                start_offset = start.to_offset(self);
3376                Bound::Excluded(start_offset)
3377            }
3378            Bound::Unbounded => {
3379                start_offset = 0;
3380                Bound::Unbounded
3381            }
3382        };
3383        let end = match range.end_bound() {
3384            Bound::Included(end) => Bound::Included(end.to_offset(self)),
3385            Bound::Excluded(end) => Bound::Excluded(end.to_offset(self)),
3386            Bound::Unbounded => Bound::Unbounded,
3387        };
3388        let bounds = (start, end);
3389
3390        let mut cursor = self.excerpts.cursor::<(usize, Point)>(&());
3391        cursor.seek(&start_offset, Bias::Right, &());
3392        if cursor.item().is_none() {
3393            cursor.prev(&());
3394        }
3395        if !bounds.contains(&cursor.start().0) {
3396            cursor.next(&());
3397        }
3398
3399        let mut visited_end = false;
3400        std::iter::from_fn(move || {
3401            if self.singleton {
3402                None
3403            } else if bounds.contains(&cursor.start().0) {
3404                let next = cursor.item().map(|excerpt| ExcerptInfo {
3405                    id: excerpt.id,
3406                    buffer: excerpt.buffer.clone(),
3407                    buffer_id: excerpt.buffer_id,
3408                    range: excerpt.range.clone(),
3409                });
3410
3411                if next.is_none() {
3412                    if visited_end {
3413                        return None;
3414                    } else {
3415                        visited_end = true;
3416                    }
3417                }
3418
3419                let prev = cursor.prev_item().map(|prev_excerpt| ExcerptInfo {
3420                    id: prev_excerpt.id,
3421                    buffer: prev_excerpt.buffer.clone(),
3422                    buffer_id: prev_excerpt.buffer_id,
3423                    range: prev_excerpt.range.clone(),
3424                });
3425                let row = MultiBufferRow(cursor.start().1.row);
3426
3427                cursor.next(&());
3428
3429                Some(ExcerptBoundary { row, prev, next })
3430            } else {
3431                None
3432            }
3433        })
3434    }
3435
3436    pub fn edit_count(&self) -> usize {
3437        self.edit_count
3438    }
3439
3440    pub fn non_text_state_update_count(&self) -> usize {
3441        self.non_text_state_update_count
3442    }
3443
3444    /// Returns the smallest enclosing bracket ranges containing the given range or
3445    /// None if no brackets contain range or the range is not contained in a single
3446    /// excerpt
3447    ///
3448    /// Can optionally pass a range_filter to filter the ranges of brackets to consider
3449    pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
3450        &self,
3451        range: Range<T>,
3452        range_filter: Option<&dyn Fn(Range<usize>, Range<usize>) -> bool>,
3453    ) -> Option<(Range<usize>, Range<usize>)> {
3454        let range = range.start.to_offset(self)..range.end.to_offset(self);
3455        let excerpt = self.excerpt_containing(range.clone())?;
3456
3457        // Filter to ranges contained in the excerpt
3458        let range_filter = |open: Range<usize>, close: Range<usize>| -> bool {
3459            excerpt.contains_buffer_range(open.start..close.end)
3460                && range_filter.map_or(true, |filter| {
3461                    filter(
3462                        excerpt.map_range_from_buffer(open),
3463                        excerpt.map_range_from_buffer(close),
3464                    )
3465                })
3466        };
3467
3468        let (open, close) = excerpt.buffer().innermost_enclosing_bracket_ranges(
3469            excerpt.map_range_to_buffer(range),
3470            Some(&range_filter),
3471        )?;
3472
3473        Some((
3474            excerpt.map_range_from_buffer(open),
3475            excerpt.map_range_from_buffer(close),
3476        ))
3477    }
3478
3479    /// Returns enclosing bracket ranges containing the given range or returns None if the range is
3480    /// not contained in a single excerpt
3481    pub fn enclosing_bracket_ranges<T: ToOffset>(
3482        &self,
3483        range: Range<T>,
3484    ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + '_> {
3485        let range = range.start.to_offset(self)..range.end.to_offset(self);
3486        let excerpt = self.excerpt_containing(range.clone())?;
3487
3488        Some(
3489            excerpt
3490                .buffer()
3491                .enclosing_bracket_ranges(excerpt.map_range_to_buffer(range))
3492                .filter_map(move |(open, close)| {
3493                    if excerpt.contains_buffer_range(open.start..close.end) {
3494                        Some((
3495                            excerpt.map_range_from_buffer(open),
3496                            excerpt.map_range_from_buffer(close),
3497                        ))
3498                    } else {
3499                        None
3500                    }
3501                }),
3502        )
3503    }
3504
3505    /// Returns bracket range pairs overlapping the given `range` or returns None if the `range` is
3506    /// not contained in a single excerpt
3507    pub fn bracket_ranges<T: ToOffset>(
3508        &self,
3509        range: Range<T>,
3510    ) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + '_> {
3511        let range = range.start.to_offset(self)..range.end.to_offset(self);
3512        let excerpt = self.excerpt_containing(range.clone())?;
3513
3514        Some(
3515            excerpt
3516                .buffer()
3517                .bracket_ranges(excerpt.map_range_to_buffer(range))
3518                .filter_map(move |(start_bracket_range, close_bracket_range)| {
3519                    let buffer_range = start_bracket_range.start..close_bracket_range.end;
3520                    if excerpt.contains_buffer_range(buffer_range) {
3521                        Some((
3522                            excerpt.map_range_from_buffer(start_bracket_range),
3523                            excerpt.map_range_from_buffer(close_bracket_range),
3524                        ))
3525                    } else {
3526                        None
3527                    }
3528                }),
3529        )
3530    }
3531
3532    pub fn redacted_ranges<'a, T: ToOffset>(
3533        &'a self,
3534        range: Range<T>,
3535        redaction_enabled: impl Fn(Option<&Arc<dyn File>>) -> bool + 'a,
3536    ) -> impl Iterator<Item = Range<usize>> + 'a {
3537        let range = range.start.to_offset(self)..range.end.to_offset(self);
3538        self.excerpts_for_range(range.clone())
3539            .filter(move |&(excerpt, _)| redaction_enabled(excerpt.buffer.file()))
3540            .flat_map(move |(excerpt, excerpt_offset)| {
3541                let excerpt_buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
3542
3543                excerpt
3544                    .buffer
3545                    .redacted_ranges(excerpt.range.context.clone())
3546                    .map(move |mut redacted_range| {
3547                        // Re-base onto the excerpts coordinates in the multibuffer
3548                        redacted_range.start = excerpt_offset
3549                            + redacted_range.start.saturating_sub(excerpt_buffer_start);
3550                        redacted_range.end = excerpt_offset
3551                            + redacted_range.end.saturating_sub(excerpt_buffer_start);
3552
3553                        redacted_range
3554                    })
3555                    .skip_while(move |redacted_range| redacted_range.end < range.start)
3556                    .take_while(move |redacted_range| redacted_range.start < range.end)
3557            })
3558    }
3559
3560    pub fn runnable_ranges(
3561        &self,
3562        range: Range<Anchor>,
3563    ) -> impl Iterator<Item = language::RunnableRange> + '_ {
3564        let range = range.start.to_offset(self)..range.end.to_offset(self);
3565        self.excerpts_for_range(range.clone())
3566            .flat_map(move |(excerpt, excerpt_offset)| {
3567                let excerpt_buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
3568
3569                excerpt
3570                    .buffer
3571                    .runnable_ranges(excerpt.range.context.clone())
3572                    .filter_map(move |mut runnable| {
3573                        // Re-base onto the excerpts coordinates in the multibuffer
3574                        //
3575                        // The node matching our runnables query might partially overlap with
3576                        // the provided range. If the run indicator is outside of excerpt bounds, do not actually show it.
3577                        if runnable.run_range.start < excerpt_buffer_start {
3578                            return None;
3579                        }
3580                        if language::ToPoint::to_point(&runnable.run_range.end, &excerpt.buffer).row
3581                            > excerpt.max_buffer_row
3582                        {
3583                            return None;
3584                        }
3585                        runnable.run_range.start =
3586                            excerpt_offset + runnable.run_range.start - excerpt_buffer_start;
3587                        runnable.run_range.end =
3588                            excerpt_offset + runnable.run_range.end - excerpt_buffer_start;
3589                        Some(runnable)
3590                    })
3591                    .skip_while(move |runnable| runnable.run_range.end < range.start)
3592                    .take_while(move |runnable| runnable.run_range.start < range.end)
3593            })
3594    }
3595
3596    pub fn indent_guides_in_range(
3597        &self,
3598        range: Range<Anchor>,
3599        ignore_disabled_for_language: bool,
3600        cx: &AppContext,
3601    ) -> Vec<MultiBufferIndentGuide> {
3602        // Fast path for singleton buffers, we can skip the conversion between offsets.
3603        if let Some((_, _, snapshot)) = self.as_singleton() {
3604            return snapshot
3605                .indent_guides_in_range(
3606                    range.start.text_anchor..range.end.text_anchor,
3607                    ignore_disabled_for_language,
3608                    cx,
3609                )
3610                .into_iter()
3611                .map(|guide| MultiBufferIndentGuide {
3612                    multibuffer_row_range: MultiBufferRow(guide.start_row)
3613                        ..MultiBufferRow(guide.end_row),
3614                    buffer: guide,
3615                })
3616                .collect();
3617        }
3618
3619        let range = range.start.to_offset(self)..range.end.to_offset(self);
3620
3621        self.excerpts_for_range(range.clone())
3622            .flat_map(move |(excerpt, excerpt_offset)| {
3623                let excerpt_buffer_start_row =
3624                    excerpt.range.context.start.to_point(&excerpt.buffer).row;
3625                let excerpt_offset_row = crate::ToPoint::to_point(&excerpt_offset, self).row;
3626
3627                excerpt
3628                    .buffer
3629                    .indent_guides_in_range(
3630                        excerpt.range.context.clone(),
3631                        ignore_disabled_for_language,
3632                        cx,
3633                    )
3634                    .into_iter()
3635                    .map(move |indent_guide| {
3636                        let start_row = excerpt_offset_row
3637                            + (indent_guide.start_row - excerpt_buffer_start_row);
3638                        let end_row =
3639                            excerpt_offset_row + (indent_guide.end_row - excerpt_buffer_start_row);
3640
3641                        MultiBufferIndentGuide {
3642                            multibuffer_row_range: MultiBufferRow(start_row)
3643                                ..MultiBufferRow(end_row),
3644                            buffer: indent_guide,
3645                        }
3646                    })
3647            })
3648            .collect()
3649    }
3650
3651    pub fn trailing_excerpt_update_count(&self) -> usize {
3652        self.trailing_excerpt_update_count
3653    }
3654
3655    pub fn file_at<T: ToOffset>(&self, point: T) -> Option<&Arc<dyn File>> {
3656        self.point_to_buffer_offset(point)
3657            .and_then(|(buffer, _)| buffer.file())
3658    }
3659
3660    pub fn language_at<T: ToOffset>(&self, point: T) -> Option<&Arc<Language>> {
3661        self.point_to_buffer_offset(point)
3662            .and_then(|(buffer, offset)| buffer.language_at(offset))
3663    }
3664
3665    pub fn settings_at<'a, T: ToOffset>(
3666        &'a self,
3667        point: T,
3668        cx: &'a AppContext,
3669    ) -> Cow<'a, LanguageSettings> {
3670        let mut language = None;
3671        let mut file = None;
3672        if let Some((buffer, offset)) = self.point_to_buffer_offset(point) {
3673            language = buffer.language_at(offset);
3674            file = buffer.file();
3675        }
3676        language_settings(language.map(|l| l.name()), file, cx)
3677    }
3678
3679    pub fn language_scope_at<T: ToOffset>(&self, point: T) -> Option<LanguageScope> {
3680        self.point_to_buffer_offset(point)
3681            .and_then(|(buffer, offset)| buffer.language_scope_at(offset))
3682    }
3683
3684    pub fn char_classifier_at<T: ToOffset>(&self, point: T) -> CharClassifier {
3685        self.point_to_buffer_offset(point)
3686            .map(|(buffer, offset)| buffer.char_classifier_at(offset))
3687            .unwrap_or_default()
3688    }
3689
3690    pub fn language_indent_size_at<T: ToOffset>(
3691        &self,
3692        position: T,
3693        cx: &AppContext,
3694    ) -> Option<IndentSize> {
3695        let (buffer_snapshot, offset) = self.point_to_buffer_offset(position)?;
3696        Some(buffer_snapshot.language_indent_size_at(offset, cx))
3697    }
3698
3699    pub fn is_dirty(&self) -> bool {
3700        self.is_dirty
3701    }
3702
3703    pub fn has_deleted_file(&self) -> bool {
3704        self.has_deleted_file
3705    }
3706
3707    pub fn has_conflict(&self) -> bool {
3708        self.has_conflict
3709    }
3710
3711    pub fn has_diagnostics(&self) -> bool {
3712        self.excerpts
3713            .iter()
3714            .any(|excerpt| excerpt.buffer.has_diagnostics())
3715    }
3716
3717    pub fn diagnostic_group<'a, O>(
3718        &'a self,
3719        group_id: usize,
3720    ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
3721    where
3722        O: text::FromAnchor + 'a,
3723    {
3724        self.as_singleton()
3725            .into_iter()
3726            .flat_map(move |(_, _, buffer)| buffer.diagnostic_group(group_id))
3727    }
3728
3729    pub fn diagnostics_in_range<'a, T, O>(
3730        &'a self,
3731        range: Range<T>,
3732        reversed: bool,
3733    ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
3734    where
3735        T: 'a + ToOffset,
3736        O: 'a + text::FromAnchor + Ord,
3737    {
3738        self.as_singleton()
3739            .into_iter()
3740            .flat_map(move |(_, _, buffer)| {
3741                buffer.diagnostics_in_range(
3742                    range.start.to_offset(self)..range.end.to_offset(self),
3743                    reversed,
3744                )
3745            })
3746    }
3747
3748    pub fn has_git_diffs(&self) -> bool {
3749        for excerpt in self.excerpts.iter() {
3750            if excerpt.buffer.has_git_diff() {
3751                return true;
3752            }
3753        }
3754        false
3755    }
3756
3757    pub fn git_diff_hunks_in_range_rev(
3758        &self,
3759        row_range: Range<MultiBufferRow>,
3760    ) -> impl Iterator<Item = MultiBufferDiffHunk> + '_ {
3761        let mut cursor = self.excerpts.cursor::<Point>(&());
3762
3763        cursor.seek(&Point::new(row_range.end.0, 0), Bias::Left, &());
3764        if cursor.item().is_none() {
3765            cursor.prev(&());
3766        }
3767
3768        std::iter::from_fn(move || {
3769            let excerpt = cursor.item()?;
3770            let multibuffer_start = *cursor.start();
3771            let multibuffer_end = multibuffer_start + excerpt.text_summary.lines;
3772            if multibuffer_start.row >= row_range.end.0 {
3773                return None;
3774            }
3775
3776            let mut buffer_start = excerpt.range.context.start;
3777            let mut buffer_end = excerpt.range.context.end;
3778            let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
3779            let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
3780
3781            if row_range.start.0 > multibuffer_start.row {
3782                let buffer_start_point =
3783                    excerpt_start_point + Point::new(row_range.start.0 - multibuffer_start.row, 0);
3784                buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
3785            }
3786
3787            if row_range.end.0 < multibuffer_end.row {
3788                let buffer_end_point =
3789                    excerpt_start_point + Point::new(row_range.end.0 - multibuffer_start.row, 0);
3790                buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
3791            }
3792
3793            let buffer_hunks = excerpt
3794                .buffer
3795                .git_diff_hunks_intersecting_range_rev(buffer_start..buffer_end)
3796                .map(move |hunk| {
3797                    let start = multibuffer_start.row
3798                        + hunk.row_range.start.saturating_sub(excerpt_start_point.row);
3799                    let end = multibuffer_start.row
3800                        + hunk
3801                            .row_range
3802                            .end
3803                            .min(excerpt_end_point.row + 1)
3804                            .saturating_sub(excerpt_start_point.row);
3805
3806                    MultiBufferDiffHunk {
3807                        row_range: MultiBufferRow(start)..MultiBufferRow(end),
3808                        diff_base_byte_range: hunk.diff_base_byte_range.clone(),
3809                        buffer_range: hunk.buffer_range.clone(),
3810                        buffer_id: excerpt.buffer_id,
3811                    }
3812                });
3813
3814            cursor.prev(&());
3815
3816            Some(buffer_hunks)
3817        })
3818        .flatten()
3819    }
3820
3821    pub fn git_diff_hunks_in_range(
3822        &self,
3823        row_range: Range<MultiBufferRow>,
3824    ) -> impl Iterator<Item = MultiBufferDiffHunk> + '_ {
3825        let mut cursor = self.excerpts.cursor::<Point>(&());
3826
3827        cursor.seek(&Point::new(row_range.start.0, 0), Bias::Left, &());
3828
3829        std::iter::from_fn(move || {
3830            let excerpt = cursor.item()?;
3831            let multibuffer_start = *cursor.start();
3832            let multibuffer_end = multibuffer_start + excerpt.text_summary.lines;
3833            let mut buffer_start = excerpt.range.context.start;
3834            let mut buffer_end = excerpt.range.context.end;
3835
3836            let excerpt_rows = match multibuffer_start.row.cmp(&row_range.end.0) {
3837                cmp::Ordering::Less => {
3838                    let excerpt_start_point = buffer_start.to_point(&excerpt.buffer);
3839                    let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines;
3840
3841                    if row_range.start.0 > multibuffer_start.row {
3842                        let buffer_start_point = excerpt_start_point
3843                            + Point::new(row_range.start.0 - multibuffer_start.row, 0);
3844                        buffer_start = excerpt.buffer.anchor_before(buffer_start_point);
3845                    }
3846
3847                    if row_range.end.0 < multibuffer_end.row {
3848                        let buffer_end_point = excerpt_start_point
3849                            + Point::new(row_range.end.0 - multibuffer_start.row, 0);
3850                        buffer_end = excerpt.buffer.anchor_before(buffer_end_point);
3851                    }
3852                    excerpt_start_point.row..excerpt_end_point.row
3853                }
3854                cmp::Ordering::Equal if row_range.end.0 == 0 => {
3855                    buffer_end = buffer_start;
3856                    0..0
3857                }
3858                cmp::Ordering::Greater | cmp::Ordering::Equal => return None,
3859            };
3860
3861            let buffer_hunks = excerpt
3862                .buffer
3863                .git_diff_hunks_intersecting_range(buffer_start..buffer_end)
3864                .map(move |hunk| {
3865                    let buffer_range = if excerpt_rows.start == 0 && excerpt_rows.end == 0 {
3866                        MultiBufferRow(0)..MultiBufferRow(1)
3867                    } else {
3868                        let start = multibuffer_start.row
3869                            + hunk.row_range.start.saturating_sub(excerpt_rows.start);
3870                        let end = multibuffer_start.row
3871                            + hunk
3872                                .row_range
3873                                .end
3874                                .min(excerpt_rows.end + 1)
3875                                .saturating_sub(excerpt_rows.start);
3876                        MultiBufferRow(start)..MultiBufferRow(end)
3877                    };
3878                    MultiBufferDiffHunk {
3879                        row_range: buffer_range,
3880                        diff_base_byte_range: hunk.diff_base_byte_range.clone(),
3881                        buffer_range: hunk.buffer_range.clone(),
3882                        buffer_id: excerpt.buffer_id,
3883                    }
3884                });
3885
3886            cursor.next(&());
3887
3888            Some(buffer_hunks)
3889        })
3890        .flatten()
3891    }
3892
3893    pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
3894        let range = range.start.to_offset(self)..range.end.to_offset(self);
3895        let excerpt = self.excerpt_containing(range.clone())?;
3896
3897        let ancestor_buffer_range = excerpt
3898            .buffer()
3899            .range_for_syntax_ancestor(excerpt.map_range_to_buffer(range))?;
3900
3901        Some(excerpt.map_range_from_buffer(ancestor_buffer_range))
3902    }
3903
3904    pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
3905        let (excerpt_id, _, buffer) = self.as_singleton()?;
3906        let outline = buffer.outline(theme)?;
3907        Some(Outline::new(
3908            outline
3909                .items
3910                .into_iter()
3911                .flat_map(|item| {
3912                    Some(OutlineItem {
3913                        depth: item.depth,
3914                        range: self.anchor_in_excerpt(*excerpt_id, item.range.start)?
3915                            ..self.anchor_in_excerpt(*excerpt_id, item.range.end)?,
3916                        text: item.text,
3917                        highlight_ranges: item.highlight_ranges,
3918                        name_ranges: item.name_ranges,
3919                        body_range: item.body_range.and_then(|body_range| {
3920                            Some(
3921                                self.anchor_in_excerpt(*excerpt_id, body_range.start)?
3922                                    ..self.anchor_in_excerpt(*excerpt_id, body_range.end)?,
3923                            )
3924                        }),
3925                        annotation_range: item.annotation_range.and_then(|annotation_range| {
3926                            Some(
3927                                self.anchor_in_excerpt(*excerpt_id, annotation_range.start)?
3928                                    ..self.anchor_in_excerpt(*excerpt_id, annotation_range.end)?,
3929                            )
3930                        }),
3931                    })
3932                })
3933                .collect(),
3934        ))
3935    }
3936
3937    pub fn symbols_containing<T: ToOffset>(
3938        &self,
3939        offset: T,
3940        theme: Option<&SyntaxTheme>,
3941    ) -> Option<(BufferId, Vec<OutlineItem<Anchor>>)> {
3942        let anchor = self.anchor_before(offset);
3943        let excerpt_id = anchor.excerpt_id;
3944        let excerpt = self.excerpt(excerpt_id)?;
3945        Some((
3946            excerpt.buffer_id,
3947            excerpt
3948                .buffer
3949                .symbols_containing(anchor.text_anchor, theme)
3950                .into_iter()
3951                .flatten()
3952                .flat_map(|item| {
3953                    Some(OutlineItem {
3954                        depth: item.depth,
3955                        range: self.anchor_in_excerpt(excerpt_id, item.range.start)?
3956                            ..self.anchor_in_excerpt(excerpt_id, item.range.end)?,
3957                        text: item.text,
3958                        highlight_ranges: item.highlight_ranges,
3959                        name_ranges: item.name_ranges,
3960                        body_range: item.body_range.and_then(|body_range| {
3961                            Some(
3962                                self.anchor_in_excerpt(excerpt_id, body_range.start)?
3963                                    ..self.anchor_in_excerpt(excerpt_id, body_range.end)?,
3964                            )
3965                        }),
3966                        annotation_range: item.annotation_range.and_then(|body_range| {
3967                            Some(
3968                                self.anchor_in_excerpt(excerpt_id, body_range.start)?
3969                                    ..self.anchor_in_excerpt(excerpt_id, body_range.end)?,
3970                            )
3971                        }),
3972                    })
3973                })
3974                .collect(),
3975        ))
3976    }
3977
3978    fn excerpt_locator_for_id(&self, id: ExcerptId) -> &Locator {
3979        if id == ExcerptId::min() {
3980            Locator::min_ref()
3981        } else if id == ExcerptId::max() {
3982            Locator::max_ref()
3983        } else {
3984            let mut cursor = self.excerpt_ids.cursor::<ExcerptId>(&());
3985            cursor.seek(&id, Bias::Left, &());
3986            if let Some(entry) = cursor.item() {
3987                if entry.id == id {
3988                    return &entry.locator;
3989                }
3990            }
3991            panic!("invalid excerpt id {:?}", id)
3992        }
3993    }
3994
3995    /// Returns the locators referenced by the given excerpt IDs, sorted by locator.
3996    fn excerpt_locators_for_ids(
3997        &self,
3998        ids: impl IntoIterator<Item = ExcerptId>,
3999    ) -> SmallVec<[Locator; 1]> {
4000        let mut sorted_ids = ids.into_iter().collect::<SmallVec<[_; 1]>>();
4001        sorted_ids.sort_unstable();
4002        let mut locators = SmallVec::new();
4003
4004        while sorted_ids.last() == Some(&ExcerptId::max()) {
4005            sorted_ids.pop();
4006            if let Some(mapping) = self.excerpt_ids.last() {
4007                locators.push(mapping.locator.clone());
4008            }
4009        }
4010
4011        let mut sorted_ids = sorted_ids.into_iter().dedup().peekable();
4012        if sorted_ids.peek() == Some(&ExcerptId::min()) {
4013            sorted_ids.next();
4014            if let Some(mapping) = self.excerpt_ids.first() {
4015                locators.push(mapping.locator.clone());
4016            }
4017        }
4018
4019        let mut cursor = self.excerpt_ids.cursor::<ExcerptId>(&());
4020        for id in sorted_ids {
4021            if cursor.seek_forward(&id, Bias::Left, &()) {
4022                locators.push(cursor.item().unwrap().locator.clone());
4023            } else {
4024                panic!("invalid excerpt id {:?}", id);
4025            }
4026        }
4027
4028        locators.sort_unstable();
4029        locators
4030    }
4031
4032    pub fn buffer_id_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<BufferId> {
4033        Some(self.excerpt(excerpt_id)?.buffer_id)
4034    }
4035
4036    pub fn buffer_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<&BufferSnapshot> {
4037        Some(&self.excerpt(excerpt_id)?.buffer)
4038    }
4039
4040    pub fn range_for_excerpt<'a, T: sum_tree::Dimension<'a, ExcerptSummary>>(
4041        &'a self,
4042        excerpt_id: ExcerptId,
4043    ) -> Option<Range<T>> {
4044        let mut cursor = self.excerpts.cursor::<(Option<&Locator>, T)>(&());
4045        let locator = self.excerpt_locator_for_id(excerpt_id);
4046        if cursor.seek(&Some(locator), Bias::Left, &()) {
4047            let start = cursor.start().1.clone();
4048            let end = cursor.end(&()).1;
4049            Some(start..end)
4050        } else {
4051            None
4052        }
4053    }
4054
4055    fn excerpt(&self, excerpt_id: ExcerptId) -> Option<&Excerpt> {
4056        let mut cursor = self.excerpts.cursor::<Option<&Locator>>(&());
4057        let locator = self.excerpt_locator_for_id(excerpt_id);
4058        cursor.seek(&Some(locator), Bias::Left, &());
4059        if let Some(excerpt) = cursor.item() {
4060            if excerpt.id == excerpt_id {
4061                return Some(excerpt);
4062            }
4063        }
4064        None
4065    }
4066
4067    /// Returns the excerpt containing range and its offset start within the multibuffer or none if `range` spans multiple excerpts
4068    pub fn excerpt_containing<T: ToOffset>(&self, range: Range<T>) -> Option<MultiBufferExcerpt> {
4069        let range = range.start.to_offset(self)..range.end.to_offset(self);
4070
4071        let mut cursor = self.excerpts.cursor::<usize>(&());
4072        cursor.seek(&range.start, Bias::Right, &());
4073        let start_excerpt = cursor.item()?;
4074
4075        if range.start == range.end {
4076            return Some(MultiBufferExcerpt::new(start_excerpt, *cursor.start()));
4077        }
4078
4079        cursor.seek(&range.end, Bias::Right, &());
4080        let end_excerpt = cursor.item()?;
4081
4082        if start_excerpt.id == end_excerpt.id {
4083            Some(MultiBufferExcerpt::new(start_excerpt, *cursor.start()))
4084        } else {
4085            None
4086        }
4087    }
4088
4089    // Takes an iterator over anchor ranges and returns a new iterator over anchor ranges that don't
4090    // span across excerpt boundaries.
4091    pub fn split_ranges<'a, I>(&'a self, ranges: I) -> impl Iterator<Item = Range<Anchor>> + 'a
4092    where
4093        I: IntoIterator<Item = Range<Anchor>> + 'a,
4094    {
4095        let mut ranges = ranges.into_iter().map(|range| range.to_offset(self));
4096        let mut cursor = self.excerpts.cursor::<usize>(&());
4097        cursor.next(&());
4098        let mut current_range = ranges.next();
4099        iter::from_fn(move || {
4100            let range = current_range.clone()?;
4101            if range.start >= cursor.end(&()) {
4102                cursor.seek_forward(&range.start, Bias::Right, &());
4103                if range.start == self.len() {
4104                    cursor.prev(&());
4105                }
4106            }
4107
4108            let excerpt = cursor.item()?;
4109            let range_start_in_excerpt = cmp::max(range.start, *cursor.start());
4110            let range_end_in_excerpt = if excerpt.has_trailing_newline {
4111                cmp::min(range.end, cursor.end(&()) - 1)
4112            } else {
4113                cmp::min(range.end, cursor.end(&()))
4114            };
4115            let buffer_range = MultiBufferExcerpt::new(excerpt, *cursor.start())
4116                .map_range_to_buffer(range_start_in_excerpt..range_end_in_excerpt);
4117
4118            let subrange_start_anchor = Anchor {
4119                buffer_id: Some(excerpt.buffer_id),
4120                excerpt_id: excerpt.id,
4121                text_anchor: excerpt.buffer.anchor_before(buffer_range.start),
4122            };
4123            let subrange_end_anchor = Anchor {
4124                buffer_id: Some(excerpt.buffer_id),
4125                excerpt_id: excerpt.id,
4126                text_anchor: excerpt.buffer.anchor_after(buffer_range.end),
4127            };
4128
4129            if range.end > cursor.end(&()) {
4130                cursor.next(&());
4131            } else {
4132                current_range = ranges.next();
4133            }
4134
4135            Some(subrange_start_anchor..subrange_end_anchor)
4136        })
4137    }
4138
4139    /// Returns excerpts overlapping the given ranges. If range spans multiple excerpts returns one range for each excerpt
4140    ///
4141    /// The ranges are specified in the coordinate space of the multibuffer, not the individual excerpted buffers.
4142    /// Each returned excerpt's range is in the coordinate space of its source buffer.
4143    pub fn excerpts_in_ranges(
4144        &self,
4145        ranges: impl IntoIterator<Item = Range<Anchor>>,
4146    ) -> impl Iterator<Item = (ExcerptId, &BufferSnapshot, Range<usize>)> {
4147        let mut ranges = ranges.into_iter().map(|range| range.to_offset(self));
4148        let mut cursor = self.excerpts.cursor::<usize>(&());
4149        cursor.next(&());
4150        let mut current_range = ranges.next();
4151        iter::from_fn(move || {
4152            let range = current_range.clone()?;
4153            if range.start >= cursor.end(&()) {
4154                cursor.seek_forward(&range.start, Bias::Right, &());
4155                if range.start == self.len() {
4156                    cursor.prev(&());
4157                }
4158            }
4159
4160            let excerpt = cursor.item()?;
4161            let range_start_in_excerpt = cmp::max(range.start, *cursor.start());
4162            let range_end_in_excerpt = if excerpt.has_trailing_newline {
4163                cmp::min(range.end, cursor.end(&()) - 1)
4164            } else {
4165                cmp::min(range.end, cursor.end(&()))
4166            };
4167            let buffer_range = MultiBufferExcerpt::new(excerpt, *cursor.start())
4168                .map_range_to_buffer(range_start_in_excerpt..range_end_in_excerpt);
4169
4170            if range.end > cursor.end(&()) {
4171                cursor.next(&());
4172            } else {
4173                current_range = ranges.next();
4174            }
4175
4176            Some((excerpt.id, &excerpt.buffer, buffer_range))
4177        })
4178    }
4179
4180    pub fn selections_in_range<'a>(
4181        &'a self,
4182        range: &'a Range<Anchor>,
4183        include_local: bool,
4184    ) -> impl 'a + Iterator<Item = (ReplicaId, bool, CursorShape, Selection<Anchor>)> {
4185        let mut cursor = self.excerpts.cursor::<ExcerptSummary>(&());
4186        let start_locator = self.excerpt_locator_for_id(range.start.excerpt_id);
4187        let end_locator = self.excerpt_locator_for_id(range.end.excerpt_id);
4188        cursor.seek(start_locator, Bias::Left, &());
4189        cursor
4190            .take_while(move |excerpt| excerpt.locator <= *end_locator)
4191            .flat_map(move |excerpt| {
4192                let mut query_range = excerpt.range.context.start..excerpt.range.context.end;
4193                if excerpt.id == range.start.excerpt_id {
4194                    query_range.start = range.start.text_anchor;
4195                }
4196                if excerpt.id == range.end.excerpt_id {
4197                    query_range.end = range.end.text_anchor;
4198                }
4199
4200                excerpt
4201                    .buffer
4202                    .selections_in_range(query_range, include_local)
4203                    .flat_map(move |(replica_id, line_mode, cursor_shape, selections)| {
4204                        selections.map(move |selection| {
4205                            let mut start = Anchor {
4206                                buffer_id: Some(excerpt.buffer_id),
4207                                excerpt_id: excerpt.id,
4208                                text_anchor: selection.start,
4209                            };
4210                            let mut end = Anchor {
4211                                buffer_id: Some(excerpt.buffer_id),
4212                                excerpt_id: excerpt.id,
4213                                text_anchor: selection.end,
4214                            };
4215                            if range.start.cmp(&start, self).is_gt() {
4216                                start = range.start;
4217                            }
4218                            if range.end.cmp(&end, self).is_lt() {
4219                                end = range.end;
4220                            }
4221
4222                            (
4223                                replica_id,
4224                                line_mode,
4225                                cursor_shape,
4226                                Selection {
4227                                    id: selection.id,
4228                                    start,
4229                                    end,
4230                                    reversed: selection.reversed,
4231                                    goal: selection.goal,
4232                                },
4233                            )
4234                        })
4235                    })
4236            })
4237    }
4238
4239    pub fn show_headers(&self) -> bool {
4240        self.show_headers
4241    }
4242}
4243
4244#[cfg(any(test, feature = "test-support"))]
4245impl MultiBufferSnapshot {
4246    pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
4247        let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
4248        let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
4249        start..end
4250    }
4251}
4252
4253impl History {
4254    fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
4255        self.transaction_depth += 1;
4256        if self.transaction_depth == 1 {
4257            let id = self.next_transaction_id.tick();
4258            self.undo_stack.push(Transaction {
4259                id,
4260                buffer_transactions: Default::default(),
4261                first_edit_at: now,
4262                last_edit_at: now,
4263                suppress_grouping: false,
4264            });
4265            Some(id)
4266        } else {
4267            None
4268        }
4269    }
4270
4271    fn end_transaction(
4272        &mut self,
4273        now: Instant,
4274        buffer_transactions: HashMap<BufferId, TransactionId>,
4275    ) -> bool {
4276        assert_ne!(self.transaction_depth, 0);
4277        self.transaction_depth -= 1;
4278        if self.transaction_depth == 0 {
4279            if buffer_transactions.is_empty() {
4280                self.undo_stack.pop();
4281                false
4282            } else {
4283                self.redo_stack.clear();
4284                let transaction = self.undo_stack.last_mut().unwrap();
4285                transaction.last_edit_at = now;
4286                for (buffer_id, transaction_id) in buffer_transactions {
4287                    transaction
4288                        .buffer_transactions
4289                        .entry(buffer_id)
4290                        .or_insert(transaction_id);
4291                }
4292                true
4293            }
4294        } else {
4295            false
4296        }
4297    }
4298
4299    fn push_transaction<'a, T>(
4300        &mut self,
4301        buffer_transactions: T,
4302        now: Instant,
4303        cx: &ModelContext<MultiBuffer>,
4304    ) where
4305        T: IntoIterator<Item = (&'a Model<Buffer>, &'a language::Transaction)>,
4306    {
4307        assert_eq!(self.transaction_depth, 0);
4308        let transaction = Transaction {
4309            id: self.next_transaction_id.tick(),
4310            buffer_transactions: buffer_transactions
4311                .into_iter()
4312                .map(|(buffer, transaction)| (buffer.read(cx).remote_id(), transaction.id))
4313                .collect(),
4314            first_edit_at: now,
4315            last_edit_at: now,
4316            suppress_grouping: false,
4317        };
4318        if !transaction.buffer_transactions.is_empty() {
4319            self.undo_stack.push(transaction);
4320            self.redo_stack.clear();
4321        }
4322    }
4323
4324    fn finalize_last_transaction(&mut self) {
4325        if let Some(transaction) = self.undo_stack.last_mut() {
4326            transaction.suppress_grouping = true;
4327        }
4328    }
4329
4330    fn forget(&mut self, transaction_id: TransactionId) -> Option<Transaction> {
4331        if let Some(ix) = self
4332            .undo_stack
4333            .iter()
4334            .rposition(|transaction| transaction.id == transaction_id)
4335        {
4336            Some(self.undo_stack.remove(ix))
4337        } else if let Some(ix) = self
4338            .redo_stack
4339            .iter()
4340            .rposition(|transaction| transaction.id == transaction_id)
4341        {
4342            Some(self.redo_stack.remove(ix))
4343        } else {
4344            None
4345        }
4346    }
4347
4348    fn transaction(&self, transaction_id: TransactionId) -> Option<&Transaction> {
4349        self.undo_stack
4350            .iter()
4351            .find(|transaction| transaction.id == transaction_id)
4352            .or_else(|| {
4353                self.redo_stack
4354                    .iter()
4355                    .find(|transaction| transaction.id == transaction_id)
4356            })
4357    }
4358
4359    fn transaction_mut(&mut self, transaction_id: TransactionId) -> Option<&mut Transaction> {
4360        self.undo_stack
4361            .iter_mut()
4362            .find(|transaction| transaction.id == transaction_id)
4363            .or_else(|| {
4364                self.redo_stack
4365                    .iter_mut()
4366                    .find(|transaction| transaction.id == transaction_id)
4367            })
4368    }
4369
4370    fn pop_undo(&mut self) -> Option<&mut Transaction> {
4371        assert_eq!(self.transaction_depth, 0);
4372        if let Some(transaction) = self.undo_stack.pop() {
4373            self.redo_stack.push(transaction);
4374            self.redo_stack.last_mut()
4375        } else {
4376            None
4377        }
4378    }
4379
4380    fn pop_redo(&mut self) -> Option<&mut Transaction> {
4381        assert_eq!(self.transaction_depth, 0);
4382        if let Some(transaction) = self.redo_stack.pop() {
4383            self.undo_stack.push(transaction);
4384            self.undo_stack.last_mut()
4385        } else {
4386            None
4387        }
4388    }
4389
4390    fn remove_from_undo(&mut self, transaction_id: TransactionId) -> Option<&Transaction> {
4391        let ix = self
4392            .undo_stack
4393            .iter()
4394            .rposition(|transaction| transaction.id == transaction_id)?;
4395        let transaction = self.undo_stack.remove(ix);
4396        self.redo_stack.push(transaction);
4397        self.redo_stack.last()
4398    }
4399
4400    fn group(&mut self) -> Option<TransactionId> {
4401        let mut count = 0;
4402        let mut transactions = self.undo_stack.iter();
4403        if let Some(mut transaction) = transactions.next_back() {
4404            while let Some(prev_transaction) = transactions.next_back() {
4405                if !prev_transaction.suppress_grouping
4406                    && transaction.first_edit_at - prev_transaction.last_edit_at
4407                        <= self.group_interval
4408                {
4409                    transaction = prev_transaction;
4410                    count += 1;
4411                } else {
4412                    break;
4413                }
4414            }
4415        }
4416        self.group_trailing(count)
4417    }
4418
4419    fn group_until(&mut self, transaction_id: TransactionId) {
4420        let mut count = 0;
4421        for transaction in self.undo_stack.iter().rev() {
4422            if transaction.id == transaction_id {
4423                self.group_trailing(count);
4424                break;
4425            } else if transaction.suppress_grouping {
4426                break;
4427            } else {
4428                count += 1;
4429            }
4430        }
4431    }
4432
4433    fn group_trailing(&mut self, n: usize) -> Option<TransactionId> {
4434        let new_len = self.undo_stack.len() - n;
4435        let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
4436        if let Some(last_transaction) = transactions_to_keep.last_mut() {
4437            if let Some(transaction) = transactions_to_merge.last() {
4438                last_transaction.last_edit_at = transaction.last_edit_at;
4439            }
4440            for to_merge in transactions_to_merge {
4441                for (buffer_id, transaction_id) in &to_merge.buffer_transactions {
4442                    last_transaction
4443                        .buffer_transactions
4444                        .entry(*buffer_id)
4445                        .or_insert(*transaction_id);
4446                }
4447            }
4448        }
4449
4450        self.undo_stack.truncate(new_len);
4451        self.undo_stack.last().map(|t| t.id)
4452    }
4453}
4454
4455impl Excerpt {
4456    fn new(
4457        id: ExcerptId,
4458        locator: Locator,
4459        buffer_id: BufferId,
4460        buffer: BufferSnapshot,
4461        range: ExcerptRange<text::Anchor>,
4462        has_trailing_newline: bool,
4463    ) -> Self {
4464        Excerpt {
4465            id,
4466            locator,
4467            max_buffer_row: range.context.end.to_point(&buffer).row,
4468            text_summary: buffer
4469                .text_summary_for_range::<TextSummary, _>(range.context.to_offset(&buffer)),
4470            buffer_id,
4471            buffer,
4472            range,
4473            has_trailing_newline,
4474        }
4475    }
4476
4477    fn chunks_in_range(&self, range: Range<usize>, language_aware: bool) -> ExcerptChunks {
4478        let content_start = self.range.context.start.to_offset(&self.buffer);
4479        let chunks_start = content_start + range.start;
4480        let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
4481
4482        let footer_height = if self.has_trailing_newline
4483            && range.start <= self.text_summary.len
4484            && range.end > self.text_summary.len
4485        {
4486            1
4487        } else {
4488            0
4489        };
4490
4491        let content_chunks = self.buffer.chunks(chunks_start..chunks_end, language_aware);
4492
4493        ExcerptChunks {
4494            excerpt_id: self.id,
4495            content_chunks,
4496            footer_height,
4497        }
4498    }
4499
4500    fn seek_chunks(&self, excerpt_chunks: &mut ExcerptChunks, range: Range<usize>) {
4501        let content_start = self.range.context.start.to_offset(&self.buffer);
4502        let chunks_start = content_start + range.start;
4503        let chunks_end = content_start + cmp::min(range.end, self.text_summary.len);
4504        excerpt_chunks.content_chunks.seek(chunks_start..chunks_end);
4505        excerpt_chunks.footer_height = if self.has_trailing_newline
4506            && range.start <= self.text_summary.len
4507            && range.end > self.text_summary.len
4508        {
4509            1
4510        } else {
4511            0
4512        };
4513    }
4514
4515    fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
4516        let content_start = self.range.context.start.to_offset(&self.buffer);
4517        let bytes_start = content_start + range.start;
4518        let bytes_end = content_start + cmp::min(range.end, self.text_summary.len);
4519        let footer_height = if self.has_trailing_newline
4520            && range.start <= self.text_summary.len
4521            && range.end > self.text_summary.len
4522        {
4523            1
4524        } else {
4525            0
4526        };
4527        let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
4528
4529        ExcerptBytes {
4530            content_bytes,
4531            padding_height: footer_height,
4532            reversed: false,
4533        }
4534    }
4535
4536    fn reversed_bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
4537        let content_start = self.range.context.start.to_offset(&self.buffer);
4538        let bytes_start = content_start + range.start;
4539        let bytes_end = content_start + cmp::min(range.end, self.text_summary.len);
4540        let footer_height = if self.has_trailing_newline
4541            && range.start <= self.text_summary.len
4542            && range.end > self.text_summary.len
4543        {
4544            1
4545        } else {
4546            0
4547        };
4548        let content_bytes = self.buffer.reversed_bytes_in_range(bytes_start..bytes_end);
4549
4550        ExcerptBytes {
4551            content_bytes,
4552            padding_height: footer_height,
4553            reversed: true,
4554        }
4555    }
4556
4557    fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
4558        if text_anchor
4559            .cmp(&self.range.context.start, &self.buffer)
4560            .is_lt()
4561        {
4562            self.range.context.start
4563        } else if text_anchor
4564            .cmp(&self.range.context.end, &self.buffer)
4565            .is_gt()
4566        {
4567            self.range.context.end
4568        } else {
4569            text_anchor
4570        }
4571    }
4572
4573    fn contains(&self, anchor: &Anchor) -> bool {
4574        Some(self.buffer_id) == anchor.buffer_id
4575            && self
4576                .range
4577                .context
4578                .start
4579                .cmp(&anchor.text_anchor, &self.buffer)
4580                .is_le()
4581            && self
4582                .range
4583                .context
4584                .end
4585                .cmp(&anchor.text_anchor, &self.buffer)
4586                .is_ge()
4587    }
4588
4589    /// The [`Excerpt`]'s start offset in its [`Buffer`]
4590    fn buffer_start_offset(&self) -> usize {
4591        self.range.context.start.to_offset(&self.buffer)
4592    }
4593
4594    /// The [`Excerpt`]'s end offset in its [`Buffer`]
4595    fn buffer_end_offset(&self) -> usize {
4596        self.buffer_start_offset() + self.text_summary.len
4597    }
4598}
4599
4600impl<'a> MultiBufferExcerpt<'a> {
4601    fn new(excerpt: &'a Excerpt, excerpt_offset: usize) -> Self {
4602        MultiBufferExcerpt {
4603            excerpt,
4604            excerpt_offset,
4605        }
4606    }
4607
4608    pub fn buffer(&self) -> &'a BufferSnapshot {
4609        &self.excerpt.buffer
4610    }
4611
4612    /// Maps an offset within the [`MultiBuffer`] to an offset within the [`Buffer`]
4613    pub fn map_offset_to_buffer(&self, offset: usize) -> usize {
4614        self.excerpt.buffer_start_offset() + offset.saturating_sub(self.excerpt_offset)
4615    }
4616
4617    /// Maps a range within the [`MultiBuffer`] to a range within the [`Buffer`]
4618    pub fn map_range_to_buffer(&self, range: Range<usize>) -> Range<usize> {
4619        self.map_offset_to_buffer(range.start)..self.map_offset_to_buffer(range.end)
4620    }
4621
4622    /// Map an offset within the [`Buffer`] to an offset within the [`MultiBuffer`]
4623    pub fn map_offset_from_buffer(&self, buffer_offset: usize) -> usize {
4624        let mut buffer_offset_in_excerpt =
4625            buffer_offset.saturating_sub(self.excerpt.buffer_start_offset());
4626        buffer_offset_in_excerpt =
4627            cmp::min(buffer_offset_in_excerpt, self.excerpt.text_summary.len);
4628
4629        self.excerpt_offset + buffer_offset_in_excerpt
4630    }
4631
4632    /// Map a range within the [`Buffer`] to a range within the [`MultiBuffer`]
4633    pub fn map_range_from_buffer(&self, buffer_range: Range<usize>) -> Range<usize> {
4634        self.map_offset_from_buffer(buffer_range.start)
4635            ..self.map_offset_from_buffer(buffer_range.end)
4636    }
4637
4638    /// Returns true if the entirety of the given range is in the buffer's excerpt
4639    pub fn contains_buffer_range(&self, range: Range<usize>) -> bool {
4640        range.start >= self.excerpt.buffer_start_offset()
4641            && range.end <= self.excerpt.buffer_end_offset()
4642    }
4643}
4644
4645impl ExcerptId {
4646    pub fn min() -> Self {
4647        Self(0)
4648    }
4649
4650    pub fn max() -> Self {
4651        Self(usize::MAX)
4652    }
4653
4654    pub fn to_proto(&self) -> u64 {
4655        self.0 as _
4656    }
4657
4658    pub fn from_proto(proto: u64) -> Self {
4659        Self(proto as _)
4660    }
4661
4662    pub fn cmp(&self, other: &Self, snapshot: &MultiBufferSnapshot) -> cmp::Ordering {
4663        let a = snapshot.excerpt_locator_for_id(*self);
4664        let b = snapshot.excerpt_locator_for_id(*other);
4665        a.cmp(b).then_with(|| self.0.cmp(&other.0))
4666    }
4667}
4668
4669impl From<ExcerptId> for usize {
4670    fn from(val: ExcerptId) -> Self {
4671        val.0
4672    }
4673}
4674
4675impl fmt::Debug for Excerpt {
4676    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4677        f.debug_struct("Excerpt")
4678            .field("id", &self.id)
4679            .field("locator", &self.locator)
4680            .field("buffer_id", &self.buffer_id)
4681            .field("range", &self.range)
4682            .field("text_summary", &self.text_summary)
4683            .field("has_trailing_newline", &self.has_trailing_newline)
4684            .finish()
4685    }
4686}
4687
4688impl sum_tree::Item for Excerpt {
4689    type Summary = ExcerptSummary;
4690
4691    fn summary(&self, _cx: &()) -> Self::Summary {
4692        let mut text = self.text_summary.clone();
4693        if self.has_trailing_newline {
4694            text += TextSummary::from("\n");
4695        }
4696        ExcerptSummary {
4697            excerpt_id: self.id,
4698            excerpt_locator: self.locator.clone(),
4699            max_buffer_row: MultiBufferRow(self.max_buffer_row),
4700            text,
4701        }
4702    }
4703}
4704
4705impl sum_tree::Item for ExcerptIdMapping {
4706    type Summary = ExcerptId;
4707
4708    fn summary(&self, _cx: &()) -> Self::Summary {
4709        self.id
4710    }
4711}
4712
4713impl sum_tree::KeyedItem for ExcerptIdMapping {
4714    type Key = ExcerptId;
4715
4716    fn key(&self) -> Self::Key {
4717        self.id
4718    }
4719}
4720
4721impl sum_tree::Summary for ExcerptId {
4722    type Context = ();
4723
4724    fn zero(_cx: &()) -> Self {
4725        Default::default()
4726    }
4727
4728    fn add_summary(&mut self, other: &Self, _: &()) {
4729        *self = *other;
4730    }
4731}
4732
4733impl sum_tree::Summary for ExcerptSummary {
4734    type Context = ();
4735
4736    fn zero(_cx: &()) -> Self {
4737        Default::default()
4738    }
4739
4740    fn add_summary(&mut self, summary: &Self, _: &()) {
4741        debug_assert!(summary.excerpt_locator > self.excerpt_locator);
4742        self.excerpt_locator = summary.excerpt_locator.clone();
4743        self.text.add_summary(&summary.text, &());
4744        self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row);
4745    }
4746}
4747
4748impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
4749    fn zero(_cx: &()) -> Self {
4750        Default::default()
4751    }
4752
4753    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4754        *self += &summary.text;
4755    }
4756}
4757
4758impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
4759    fn zero(_cx: &()) -> Self {
4760        Default::default()
4761    }
4762
4763    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4764        *self += summary.text.len;
4765    }
4766}
4767
4768impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
4769    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
4770        Ord::cmp(self, &cursor_location.text.len)
4771    }
4772}
4773
4774impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, TextSummary> for Point {
4775    fn cmp(&self, cursor_location: &TextSummary, _: &()) -> cmp::Ordering {
4776        Ord::cmp(self, &cursor_location.lines)
4777    }
4778}
4779
4780impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, Option<&'a Locator>> for Locator {
4781    fn cmp(&self, cursor_location: &Option<&'a Locator>, _: &()) -> cmp::Ordering {
4782        Ord::cmp(&Some(self), cursor_location)
4783    }
4784}
4785
4786impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Locator {
4787    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
4788        Ord::cmp(self, &cursor_location.excerpt_locator)
4789    }
4790}
4791
4792impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for OffsetUtf16 {
4793    fn zero(_cx: &()) -> Self {
4794        Default::default()
4795    }
4796
4797    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4798        *self += summary.text.len_utf16;
4799    }
4800}
4801
4802impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
4803    fn zero(_cx: &()) -> Self {
4804        Default::default()
4805    }
4806
4807    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4808        *self += summary.text.lines;
4809    }
4810}
4811
4812impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
4813    fn zero(_cx: &()) -> Self {
4814        Default::default()
4815    }
4816
4817    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4818        *self += summary.text.lines_utf16()
4819    }
4820}
4821
4822impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a Locator> {
4823    fn zero(_cx: &()) -> Self {
4824        Default::default()
4825    }
4826
4827    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4828        *self = Some(&summary.excerpt_locator);
4829    }
4830}
4831
4832impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<ExcerptId> {
4833    fn zero(_cx: &()) -> Self {
4834        Default::default()
4835    }
4836
4837    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
4838        *self = Some(summary.excerpt_id);
4839    }
4840}
4841
4842impl<'a> MultiBufferRows<'a> {
4843    pub fn seek(&mut self, row: MultiBufferRow) {
4844        self.buffer_row_range = 0..0;
4845
4846        self.excerpts
4847            .seek_forward(&Point::new(row.0, 0), Bias::Right, &());
4848        if self.excerpts.item().is_none() {
4849            self.excerpts.prev(&());
4850
4851            if self.excerpts.item().is_none() && row.0 == 0 {
4852                self.buffer_row_range = 0..1;
4853                return;
4854            }
4855        }
4856
4857        if let Some(excerpt) = self.excerpts.item() {
4858            let overshoot = row.0 - self.excerpts.start().row;
4859            let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
4860            self.buffer_row_range.start = excerpt_start + overshoot;
4861            self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
4862        }
4863    }
4864}
4865
4866impl<'a> Iterator for MultiBufferRows<'a> {
4867    type Item = Option<u32>;
4868
4869    fn next(&mut self) -> Option<Self::Item> {
4870        loop {
4871            if !self.buffer_row_range.is_empty() {
4872                let row = Some(self.buffer_row_range.start);
4873                self.buffer_row_range.start += 1;
4874                return Some(row);
4875            }
4876            self.excerpts.item()?;
4877            self.excerpts.next(&());
4878            let excerpt = self.excerpts.item()?;
4879            self.buffer_row_range.start = excerpt.range.context.start.to_point(&excerpt.buffer).row;
4880            self.buffer_row_range.end =
4881                self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
4882        }
4883    }
4884}
4885
4886impl<'a> MultiBufferChunks<'a> {
4887    pub fn offset(&self) -> usize {
4888        self.range.start
4889    }
4890
4891    pub fn seek(&mut self, new_range: Range<usize>) {
4892        self.range = new_range.clone();
4893        self.excerpts.seek(&new_range.start, Bias::Right, &());
4894        if let Some(excerpt) = self.excerpts.item() {
4895            let excerpt_start = self.excerpts.start();
4896            if let Some(excerpt_chunks) = self
4897                .excerpt_chunks
4898                .as_mut()
4899                .filter(|chunks| excerpt.id == chunks.excerpt_id)
4900            {
4901                excerpt.seek_chunks(
4902                    excerpt_chunks,
4903                    self.range.start - excerpt_start..self.range.end - excerpt_start,
4904                );
4905            } else {
4906                self.excerpt_chunks = Some(excerpt.chunks_in_range(
4907                    self.range.start - excerpt_start..self.range.end - excerpt_start,
4908                    self.language_aware,
4909                ));
4910            }
4911        } else {
4912            self.excerpt_chunks = None;
4913        }
4914    }
4915}
4916
4917impl<'a> Iterator for MultiBufferChunks<'a> {
4918    type Item = Chunk<'a>;
4919
4920    fn next(&mut self) -> Option<Self::Item> {
4921        if self.range.is_empty() {
4922            None
4923        } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
4924            self.range.start += chunk.text.len();
4925            Some(chunk)
4926        } else {
4927            self.excerpts.next(&());
4928            let excerpt = self.excerpts.item()?;
4929            self.excerpt_chunks = Some(excerpt.chunks_in_range(
4930                0..self.range.end - self.excerpts.start(),
4931                self.language_aware,
4932            ));
4933            self.next()
4934        }
4935    }
4936}
4937
4938impl<'a> MultiBufferBytes<'a> {
4939    fn consume(&mut self, len: usize) {
4940        self.range.start += len;
4941        self.chunk = &self.chunk[len..];
4942
4943        if !self.range.is_empty() && self.chunk.is_empty() {
4944            if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
4945                self.chunk = chunk;
4946            } else {
4947                self.excerpts.next(&());
4948                if let Some(excerpt) = self.excerpts.item() {
4949                    let mut excerpt_bytes =
4950                        excerpt.bytes_in_range(0..self.range.end - self.excerpts.start());
4951                    self.chunk = excerpt_bytes.next().unwrap();
4952                    self.excerpt_bytes = Some(excerpt_bytes);
4953                }
4954            }
4955        }
4956    }
4957}
4958
4959impl<'a> Iterator for MultiBufferBytes<'a> {
4960    type Item = &'a [u8];
4961
4962    fn next(&mut self) -> Option<Self::Item> {
4963        let chunk = self.chunk;
4964        if chunk.is_empty() {
4965            None
4966        } else {
4967            self.consume(chunk.len());
4968            Some(chunk)
4969        }
4970    }
4971}
4972
4973impl<'a> io::Read for MultiBufferBytes<'a> {
4974    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
4975        let len = cmp::min(buf.len(), self.chunk.len());
4976        buf[..len].copy_from_slice(&self.chunk[..len]);
4977        if len > 0 {
4978            self.consume(len);
4979        }
4980        Ok(len)
4981    }
4982}
4983
4984impl<'a> ReversedMultiBufferBytes<'a> {
4985    fn consume(&mut self, len: usize) {
4986        self.range.end -= len;
4987        self.chunk = &self.chunk[..self.chunk.len() - len];
4988
4989        if !self.range.is_empty() && self.chunk.is_empty() {
4990            if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
4991                self.chunk = chunk;
4992            } else {
4993                self.excerpts.prev(&());
4994                if let Some(excerpt) = self.excerpts.item() {
4995                    let mut excerpt_bytes = excerpt.reversed_bytes_in_range(
4996                        self.range.start.saturating_sub(*self.excerpts.start())..usize::MAX,
4997                    );
4998                    self.chunk = excerpt_bytes.next().unwrap();
4999                    self.excerpt_bytes = Some(excerpt_bytes);
5000                }
5001            }
5002        }
5003    }
5004}
5005
5006impl<'a> io::Read for ReversedMultiBufferBytes<'a> {
5007    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
5008        let len = cmp::min(buf.len(), self.chunk.len());
5009        buf[..len].copy_from_slice(&self.chunk[..len]);
5010        buf[..len].reverse();
5011        if len > 0 {
5012            self.consume(len);
5013        }
5014        Ok(len)
5015    }
5016}
5017impl<'a> Iterator for ExcerptBytes<'a> {
5018    type Item = &'a [u8];
5019
5020    fn next(&mut self) -> Option<Self::Item> {
5021        if self.reversed && self.padding_height > 0 {
5022            let result = &NEWLINES[..self.padding_height];
5023            self.padding_height = 0;
5024            return Some(result);
5025        }
5026
5027        if let Some(chunk) = self.content_bytes.next() {
5028            if !chunk.is_empty() {
5029                return Some(chunk);
5030            }
5031        }
5032
5033        if self.padding_height > 0 {
5034            let result = &NEWLINES[..self.padding_height];
5035            self.padding_height = 0;
5036            return Some(result);
5037        }
5038
5039        None
5040    }
5041}
5042
5043impl<'a> Iterator for ExcerptChunks<'a> {
5044    type Item = Chunk<'a>;
5045
5046    fn next(&mut self) -> Option<Self::Item> {
5047        if let Some(chunk) = self.content_chunks.next() {
5048            return Some(chunk);
5049        }
5050
5051        if self.footer_height > 0 {
5052            let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
5053            self.footer_height = 0;
5054            return Some(Chunk {
5055                text,
5056                ..Default::default()
5057            });
5058        }
5059
5060        None
5061    }
5062}
5063
5064impl ToOffset for Point {
5065    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
5066        snapshot.point_to_offset(*self)
5067    }
5068}
5069
5070impl ToOffset for usize {
5071    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
5072        assert!(*self <= snapshot.len(), "offset is out of range");
5073        *self
5074    }
5075}
5076
5077impl ToOffset for OffsetUtf16 {
5078    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
5079        snapshot.offset_utf16_to_offset(*self)
5080    }
5081}
5082
5083impl ToOffset for PointUtf16 {
5084    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
5085        snapshot.point_utf16_to_offset(*self)
5086    }
5087}
5088
5089impl ToOffsetUtf16 for OffsetUtf16 {
5090    fn to_offset_utf16(&self, _snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
5091        *self
5092    }
5093}
5094
5095impl ToOffsetUtf16 for usize {
5096    fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
5097        snapshot.offset_to_offset_utf16(*self)
5098    }
5099}
5100
5101impl ToPoint for usize {
5102    fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
5103        snapshot.offset_to_point(*self)
5104    }
5105}
5106
5107impl ToPoint for Point {
5108    fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
5109        *self
5110    }
5111}
5112
5113impl ToPointUtf16 for usize {
5114    fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
5115        snapshot.offset_to_point_utf16(*self)
5116    }
5117}
5118
5119impl ToPointUtf16 for Point {
5120    fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 {
5121        snapshot.point_to_point_utf16(*self)
5122    }
5123}
5124
5125impl ToPointUtf16 for PointUtf16 {
5126    fn to_point_utf16<'a>(&self, _: &MultiBufferSnapshot) -> PointUtf16 {
5127        *self
5128    }
5129}
5130
5131pub fn build_excerpt_ranges<T>(
5132    buffer: &BufferSnapshot,
5133    ranges: &[Range<T>],
5134    context_line_count: u32,
5135) -> (Vec<ExcerptRange<Point>>, Vec<usize>)
5136where
5137    T: text::ToPoint,
5138{
5139    let max_point = buffer.max_point();
5140    let mut range_counts = Vec::new();
5141    let mut excerpt_ranges = Vec::new();
5142    let mut range_iter = ranges
5143        .iter()
5144        .map(|range| range.start.to_point(buffer)..range.end.to_point(buffer))
5145        .peekable();
5146    while let Some(range) = range_iter.next() {
5147        let excerpt_start = Point::new(range.start.row.saturating_sub(context_line_count), 0);
5148        let row = (range.end.row + context_line_count).min(max_point.row);
5149        let mut excerpt_end = Point::new(row, buffer.line_len(row));
5150
5151        let mut ranges_in_excerpt = 1;
5152
5153        while let Some(next_range) = range_iter.peek() {
5154            if next_range.start.row <= excerpt_end.row + context_line_count {
5155                let row = (next_range.end.row + context_line_count).min(max_point.row);
5156                excerpt_end = Point::new(row, buffer.line_len(row));
5157
5158                ranges_in_excerpt += 1;
5159                range_iter.next();
5160            } else {
5161                break;
5162            }
5163        }
5164
5165        excerpt_ranges.push(ExcerptRange {
5166            context: excerpt_start..excerpt_end,
5167            primary: Some(range),
5168        });
5169        range_counts.push(ranges_in_excerpt);
5170    }
5171
5172    (excerpt_ranges, range_counts)
5173}
5174
5175#[cfg(test)]
5176mod tests {
5177    use super::*;
5178    use gpui::{AppContext, Context, TestAppContext};
5179    use language::{Buffer, Rope};
5180    use parking_lot::RwLock;
5181    use rand::prelude::*;
5182    use settings::SettingsStore;
5183    use std::env;
5184    use util::test::sample_text;
5185
5186    #[ctor::ctor]
5187    fn init_logger() {
5188        if std::env::var("RUST_LOG").is_ok() {
5189            env_logger::init();
5190        }
5191    }
5192
5193    #[gpui::test]
5194    fn test_singleton(cx: &mut AppContext) {
5195        let buffer = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
5196        let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
5197
5198        let snapshot = multibuffer.read(cx).snapshot(cx);
5199        assert_eq!(snapshot.text(), buffer.read(cx).text());
5200
5201        assert_eq!(
5202            snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
5203            (0..buffer.read(cx).row_count())
5204                .map(Some)
5205                .collect::<Vec<_>>()
5206        );
5207
5208        buffer.update(cx, |buffer, cx| buffer.edit([(1..3, "XXX\n")], None, cx));
5209        let snapshot = multibuffer.read(cx).snapshot(cx);
5210
5211        assert_eq!(snapshot.text(), buffer.read(cx).text());
5212        assert_eq!(
5213            snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
5214            (0..buffer.read(cx).row_count())
5215                .map(Some)
5216                .collect::<Vec<_>>()
5217        );
5218    }
5219
5220    #[gpui::test]
5221    fn test_remote(cx: &mut AppContext) {
5222        let host_buffer = cx.new_model(|cx| Buffer::local("a", cx));
5223        let guest_buffer = cx.new_model(|cx| {
5224            let state = host_buffer.read(cx).to_proto(cx);
5225            let ops = cx
5226                .background_executor()
5227                .block(host_buffer.read(cx).serialize_ops(None, cx));
5228            let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
5229            buffer.apply_ops(
5230                ops.into_iter()
5231                    .map(|op| language::proto::deserialize_operation(op).unwrap()),
5232                cx,
5233            );
5234            buffer
5235        });
5236        let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(guest_buffer.clone(), cx));
5237        let snapshot = multibuffer.read(cx).snapshot(cx);
5238        assert_eq!(snapshot.text(), "a");
5239
5240        guest_buffer.update(cx, |buffer, cx| buffer.edit([(1..1, "b")], None, cx));
5241        let snapshot = multibuffer.read(cx).snapshot(cx);
5242        assert_eq!(snapshot.text(), "ab");
5243
5244        guest_buffer.update(cx, |buffer, cx| buffer.edit([(2..2, "c")], None, cx));
5245        let snapshot = multibuffer.read(cx).snapshot(cx);
5246        assert_eq!(snapshot.text(), "abc");
5247    }
5248
5249    #[gpui::test]
5250    fn test_excerpt_boundaries_and_clipping(cx: &mut AppContext) {
5251        let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
5252        let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx));
5253        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
5254
5255        let events = Arc::new(RwLock::new(Vec::<Event>::new()));
5256        multibuffer.update(cx, |_, cx| {
5257            let events = events.clone();
5258            cx.subscribe(&multibuffer, move |_, _, event, _| {
5259                if let Event::Edited { .. } = event {
5260                    events.write().push(event.clone())
5261                }
5262            })
5263            .detach();
5264        });
5265
5266        let subscription = multibuffer.update(cx, |multibuffer, cx| {
5267            let subscription = multibuffer.subscribe();
5268            multibuffer.push_excerpts(
5269                buffer_1.clone(),
5270                [ExcerptRange {
5271                    context: Point::new(1, 2)..Point::new(2, 5),
5272                    primary: None,
5273                }],
5274                cx,
5275            );
5276            assert_eq!(
5277                subscription.consume().into_inner(),
5278                [Edit {
5279                    old: 0..0,
5280                    new: 0..10
5281                }]
5282            );
5283
5284            multibuffer.push_excerpts(
5285                buffer_1.clone(),
5286                [ExcerptRange {
5287                    context: Point::new(3, 3)..Point::new(4, 4),
5288                    primary: None,
5289                }],
5290                cx,
5291            );
5292            multibuffer.push_excerpts(
5293                buffer_2.clone(),
5294                [ExcerptRange {
5295                    context: Point::new(3, 1)..Point::new(3, 3),
5296                    primary: None,
5297                }],
5298                cx,
5299            );
5300            assert_eq!(
5301                subscription.consume().into_inner(),
5302                [Edit {
5303                    old: 10..10,
5304                    new: 10..22
5305                }]
5306            );
5307
5308            subscription
5309        });
5310
5311        // Adding excerpts emits an edited event.
5312        assert_eq!(
5313            events.read().as_slice(),
5314            &[
5315                Event::Edited {
5316                    singleton_buffer_edited: false
5317                },
5318                Event::Edited {
5319                    singleton_buffer_edited: false
5320                },
5321                Event::Edited {
5322                    singleton_buffer_edited: false
5323                }
5324            ]
5325        );
5326
5327        let snapshot = multibuffer.read(cx).snapshot(cx);
5328        assert_eq!(
5329            snapshot.text(),
5330            concat!(
5331                "bbbb\n",  // Preserve newlines
5332                "ccccc\n", //
5333                "ddd\n",   //
5334                "eeee\n",  //
5335                "jj"       //
5336            )
5337        );
5338        assert_eq!(
5339            snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
5340            [Some(1), Some(2), Some(3), Some(4), Some(3)]
5341        );
5342        assert_eq!(
5343            snapshot.buffer_rows(MultiBufferRow(2)).collect::<Vec<_>>(),
5344            [Some(3), Some(4), Some(3)]
5345        );
5346        assert_eq!(
5347            snapshot.buffer_rows(MultiBufferRow(4)).collect::<Vec<_>>(),
5348            [Some(3)]
5349        );
5350        assert_eq!(
5351            snapshot.buffer_rows(MultiBufferRow(5)).collect::<Vec<_>>(),
5352            []
5353        );
5354
5355        assert_eq!(
5356            boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot),
5357            &[
5358                (MultiBufferRow(0), "bbbb\nccccc".to_string(), true),
5359                (MultiBufferRow(2), "ddd\neeee".to_string(), false),
5360                (MultiBufferRow(4), "jj".to_string(), true),
5361            ]
5362        );
5363        assert_eq!(
5364            boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot),
5365            &[(MultiBufferRow(0), "bbbb\nccccc".to_string(), true)]
5366        );
5367        assert_eq!(
5368            boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot),
5369            &[]
5370        );
5371        assert_eq!(
5372            boundaries_in_range(Point::new(1, 0)..Point::new(2, 0), &snapshot),
5373            &[]
5374        );
5375        assert_eq!(
5376            boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
5377            &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)]
5378        );
5379        assert_eq!(
5380            boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot),
5381            &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)]
5382        );
5383        assert_eq!(
5384            boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot),
5385            &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)]
5386        );
5387        assert_eq!(
5388            boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot),
5389            &[(MultiBufferRow(4), "jj".to_string(), true)]
5390        );
5391        assert_eq!(
5392            boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot),
5393            &[]
5394        );
5395
5396        buffer_1.update(cx, |buffer, cx| {
5397            let text = "\n";
5398            buffer.edit(
5399                [
5400                    (Point::new(0, 0)..Point::new(0, 0), text),
5401                    (Point::new(2, 1)..Point::new(2, 3), text),
5402                ],
5403                None,
5404                cx,
5405            );
5406        });
5407
5408        let snapshot = multibuffer.read(cx).snapshot(cx);
5409        assert_eq!(
5410            snapshot.text(),
5411            concat!(
5412                "bbbb\n", // Preserve newlines
5413                "c\n",    //
5414                "cc\n",   //
5415                "ddd\n",  //
5416                "eeee\n", //
5417                "jj"      //
5418            )
5419        );
5420
5421        assert_eq!(
5422            subscription.consume().into_inner(),
5423            [Edit {
5424                old: 6..8,
5425                new: 6..7
5426            }]
5427        );
5428
5429        let snapshot = multibuffer.read(cx).snapshot(cx);
5430        assert_eq!(
5431            snapshot.clip_point(Point::new(0, 5), Bias::Left),
5432            Point::new(0, 4)
5433        );
5434        assert_eq!(
5435            snapshot.clip_point(Point::new(0, 5), Bias::Right),
5436            Point::new(0, 4)
5437        );
5438        assert_eq!(
5439            snapshot.clip_point(Point::new(5, 1), Bias::Right),
5440            Point::new(5, 1)
5441        );
5442        assert_eq!(
5443            snapshot.clip_point(Point::new(5, 2), Bias::Right),
5444            Point::new(5, 2)
5445        );
5446        assert_eq!(
5447            snapshot.clip_point(Point::new(5, 3), Bias::Right),
5448            Point::new(5, 2)
5449        );
5450
5451        let snapshot = multibuffer.update(cx, |multibuffer, cx| {
5452            let (buffer_2_excerpt_id, _) =
5453                multibuffer.excerpts_for_buffer(&buffer_2, cx)[0].clone();
5454            multibuffer.remove_excerpts([buffer_2_excerpt_id], cx);
5455            multibuffer.snapshot(cx)
5456        });
5457
5458        assert_eq!(
5459            snapshot.text(),
5460            concat!(
5461                "bbbb\n", // Preserve newlines
5462                "c\n",    //
5463                "cc\n",   //
5464                "ddd\n",  //
5465                "eeee",   //
5466            )
5467        );
5468
5469        fn boundaries_in_range(
5470            range: Range<Point>,
5471            snapshot: &MultiBufferSnapshot,
5472        ) -> Vec<(MultiBufferRow, String, bool)> {
5473            snapshot
5474                .excerpt_boundaries_in_range(range)
5475                .filter_map(|boundary| {
5476                    let starts_new_buffer = boundary.starts_new_buffer();
5477                    boundary.next.map(|next| {
5478                        (
5479                            boundary.row,
5480                            next.buffer
5481                                .text_for_range(next.range.context)
5482                                .collect::<String>(),
5483                            starts_new_buffer,
5484                        )
5485                    })
5486                })
5487                .collect::<Vec<_>>()
5488        }
5489    }
5490
5491    #[gpui::test]
5492    fn test_excerpt_events(cx: &mut AppContext) {
5493        let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(10, 3, 'a'), cx));
5494        let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(10, 3, 'm'), cx));
5495
5496        let leader_multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
5497        let follower_multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
5498        let follower_edit_event_count = Arc::new(RwLock::new(0));
5499
5500        follower_multibuffer.update(cx, |_, cx| {
5501            let follower_edit_event_count = follower_edit_event_count.clone();
5502            cx.subscribe(
5503                &leader_multibuffer,
5504                move |follower, _, event, cx| match event.clone() {
5505                    Event::ExcerptsAdded {
5506                        buffer,
5507                        predecessor,
5508                        excerpts,
5509                    } => follower.insert_excerpts_with_ids_after(predecessor, buffer, excerpts, cx),
5510                    Event::ExcerptsRemoved { ids } => follower.remove_excerpts(ids, cx),
5511                    Event::Edited { .. } => {
5512                        *follower_edit_event_count.write() += 1;
5513                    }
5514                    _ => {}
5515                },
5516            )
5517            .detach();
5518        });
5519
5520        leader_multibuffer.update(cx, |leader, cx| {
5521            leader.push_excerpts(
5522                buffer_1.clone(),
5523                [
5524                    ExcerptRange {
5525                        context: 0..8,
5526                        primary: None,
5527                    },
5528                    ExcerptRange {
5529                        context: 12..16,
5530                        primary: None,
5531                    },
5532                ],
5533                cx,
5534            );
5535            leader.insert_excerpts_after(
5536                leader.excerpt_ids()[0],
5537                buffer_2.clone(),
5538                [
5539                    ExcerptRange {
5540                        context: 0..5,
5541                        primary: None,
5542                    },
5543                    ExcerptRange {
5544                        context: 10..15,
5545                        primary: None,
5546                    },
5547                ],
5548                cx,
5549            )
5550        });
5551        assert_eq!(
5552            leader_multibuffer.read(cx).snapshot(cx).text(),
5553            follower_multibuffer.read(cx).snapshot(cx).text(),
5554        );
5555        assert_eq!(*follower_edit_event_count.read(), 2);
5556
5557        leader_multibuffer.update(cx, |leader, cx| {
5558            let excerpt_ids = leader.excerpt_ids();
5559            leader.remove_excerpts([excerpt_ids[1], excerpt_ids[3]], cx);
5560        });
5561        assert_eq!(
5562            leader_multibuffer.read(cx).snapshot(cx).text(),
5563            follower_multibuffer.read(cx).snapshot(cx).text(),
5564        );
5565        assert_eq!(*follower_edit_event_count.read(), 3);
5566
5567        // Removing an empty set of excerpts is a noop.
5568        leader_multibuffer.update(cx, |leader, cx| {
5569            leader.remove_excerpts([], cx);
5570        });
5571        assert_eq!(
5572            leader_multibuffer.read(cx).snapshot(cx).text(),
5573            follower_multibuffer.read(cx).snapshot(cx).text(),
5574        );
5575        assert_eq!(*follower_edit_event_count.read(), 3);
5576
5577        // Adding an empty set of excerpts is a noop.
5578        leader_multibuffer.update(cx, |leader, cx| {
5579            leader.push_excerpts::<usize>(buffer_2.clone(), [], cx);
5580        });
5581        assert_eq!(
5582            leader_multibuffer.read(cx).snapshot(cx).text(),
5583            follower_multibuffer.read(cx).snapshot(cx).text(),
5584        );
5585        assert_eq!(*follower_edit_event_count.read(), 3);
5586
5587        leader_multibuffer.update(cx, |leader, cx| {
5588            leader.clear(cx);
5589        });
5590        assert_eq!(
5591            leader_multibuffer.read(cx).snapshot(cx).text(),
5592            follower_multibuffer.read(cx).snapshot(cx).text(),
5593        );
5594        assert_eq!(*follower_edit_event_count.read(), 4);
5595    }
5596
5597    #[gpui::test]
5598    fn test_expand_excerpts(cx: &mut AppContext) {
5599        let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
5600        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
5601
5602        multibuffer.update(cx, |multibuffer, cx| {
5603            multibuffer.push_excerpts_with_context_lines(
5604                buffer.clone(),
5605                vec![
5606                    // Note that in this test, this first excerpt
5607                    // does not contain a new line
5608                    Point::new(3, 2)..Point::new(3, 3),
5609                    Point::new(7, 1)..Point::new(7, 3),
5610                    Point::new(15, 0)..Point::new(15, 0),
5611                ],
5612                1,
5613                cx,
5614            )
5615        });
5616
5617        let snapshot = multibuffer.read(cx).snapshot(cx);
5618
5619        assert_eq!(
5620            snapshot.text(),
5621            concat!(
5622                "ccc\n", //
5623                "ddd\n", //
5624                "eee",   //
5625                "\n",    // End of excerpt
5626                "ggg\n", //
5627                "hhh\n", //
5628                "iii",   //
5629                "\n",    // End of excerpt
5630                "ooo\n", //
5631                "ppp\n", //
5632                "qqq",   // End of excerpt
5633            )
5634        );
5635        drop(snapshot);
5636
5637        multibuffer.update(cx, |multibuffer, cx| {
5638            multibuffer.expand_excerpts(
5639                multibuffer.excerpt_ids(),
5640                1,
5641                ExpandExcerptDirection::UpAndDown,
5642                cx,
5643            )
5644        });
5645
5646        let snapshot = multibuffer.read(cx).snapshot(cx);
5647
5648        // Expanding context lines causes the line containing 'fff' to appear in two different excerpts.
5649        // We don't attempt to merge them, because removing the excerpt could create inconsistency with other layers
5650        // that are tracking excerpt ids.
5651        assert_eq!(
5652            snapshot.text(),
5653            concat!(
5654                "bbb\n", //
5655                "ccc\n", //
5656                "ddd\n", //
5657                "eee\n", //
5658                "fff\n", // End of excerpt
5659                "fff\n", //
5660                "ggg\n", //
5661                "hhh\n", //
5662                "iii\n", //
5663                "jjj\n", // End of excerpt
5664                "nnn\n", //
5665                "ooo\n", //
5666                "ppp\n", //
5667                "qqq\n", //
5668                "rrr",   // End of excerpt
5669            )
5670        );
5671    }
5672
5673    #[gpui::test]
5674    fn test_push_excerpts_with_context_lines(cx: &mut AppContext) {
5675        let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
5676        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
5677        let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
5678            multibuffer.push_excerpts_with_context_lines(
5679                buffer.clone(),
5680                vec![
5681                    // Note that in this test, this first excerpt
5682                    // does contain a new line
5683                    Point::new(3, 2)..Point::new(4, 2),
5684                    Point::new(7, 1)..Point::new(7, 3),
5685                    Point::new(15, 0)..Point::new(15, 0),
5686                ],
5687                2,
5688                cx,
5689            )
5690        });
5691
5692        let snapshot = multibuffer.read(cx).snapshot(cx);
5693        assert_eq!(
5694            snapshot.text(),
5695            concat!(
5696                "bbb\n", // Preserve newlines
5697                "ccc\n", //
5698                "ddd\n", //
5699                "eee\n", //
5700                "fff\n", //
5701                "ggg\n", //
5702                "hhh\n", //
5703                "iii\n", //
5704                "jjj\n", //
5705                "nnn\n", //
5706                "ooo\n", //
5707                "ppp\n", //
5708                "qqq\n", //
5709                "rrr",   //
5710            )
5711        );
5712
5713        assert_eq!(
5714            anchor_ranges
5715                .iter()
5716                .map(|range| range.to_point(&snapshot))
5717                .collect::<Vec<_>>(),
5718            vec![
5719                Point::new(2, 2)..Point::new(3, 2),
5720                Point::new(6, 1)..Point::new(6, 3),
5721                Point::new(11, 0)..Point::new(11, 0)
5722            ]
5723        );
5724    }
5725
5726    #[gpui::test(iterations = 100)]
5727    async fn test_push_multiple_excerpts_with_context_lines(cx: &mut TestAppContext) {
5728        let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
5729        let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(15, 4, 'a'), cx));
5730        let snapshot_1 = buffer_1.update(cx, |buffer, _| buffer.snapshot());
5731        let snapshot_2 = buffer_2.update(cx, |buffer, _| buffer.snapshot());
5732        let ranges_1 = vec![
5733            snapshot_1.anchor_before(Point::new(3, 2))..snapshot_1.anchor_before(Point::new(4, 2)),
5734            snapshot_1.anchor_before(Point::new(7, 1))..snapshot_1.anchor_before(Point::new(7, 3)),
5735            snapshot_1.anchor_before(Point::new(15, 0))
5736                ..snapshot_1.anchor_before(Point::new(15, 0)),
5737        ];
5738        let ranges_2 = vec![
5739            snapshot_2.anchor_before(Point::new(2, 1))..snapshot_2.anchor_before(Point::new(3, 1)),
5740            snapshot_2.anchor_before(Point::new(10, 0))
5741                ..snapshot_2.anchor_before(Point::new(10, 2)),
5742        ];
5743
5744        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
5745        let anchor_ranges = multibuffer
5746            .update(cx, |multibuffer, cx| {
5747                multibuffer.push_multiple_excerpts_with_context_lines(
5748                    vec![(buffer_1.clone(), ranges_1), (buffer_2.clone(), ranges_2)],
5749                    2,
5750                    cx,
5751                )
5752            })
5753            .await;
5754
5755        let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx));
5756        assert_eq!(
5757            snapshot.text(),
5758            concat!(
5759                "bbb\n", // buffer_1
5760                "ccc\n", //
5761                "ddd\n", // <-- excerpt 1
5762                "eee\n", // <-- excerpt 1
5763                "fff\n", //
5764                "ggg\n", //
5765                "hhh\n", // <-- excerpt 2
5766                "iii\n", //
5767                "jjj\n", //
5768                //
5769                "nnn\n", //
5770                "ooo\n", //
5771                "ppp\n", // <-- excerpt 3
5772                "qqq\n", //
5773                "rrr\n", //
5774                //
5775                "aaaa\n", // buffer 2
5776                "bbbb\n", //
5777                "cccc\n", // <-- excerpt 4
5778                "dddd\n", // <-- excerpt 4
5779                "eeee\n", //
5780                "ffff\n", //
5781                //
5782                "iiii\n", //
5783                "jjjj\n", //
5784                "kkkk\n", // <-- excerpt 5
5785                "llll\n", //
5786                "mmmm",   //
5787            )
5788        );
5789
5790        assert_eq!(
5791            anchor_ranges
5792                .iter()
5793                .map(|range| range.to_point(&snapshot))
5794                .collect::<Vec<_>>(),
5795            vec![
5796                Point::new(2, 2)..Point::new(3, 2),
5797                Point::new(6, 1)..Point::new(6, 3),
5798                Point::new(11, 0)..Point::new(11, 0),
5799                Point::new(16, 1)..Point::new(17, 1),
5800                Point::new(22, 0)..Point::new(22, 2)
5801            ]
5802        );
5803    }
5804
5805    #[gpui::test]
5806    fn test_empty_multibuffer(cx: &mut AppContext) {
5807        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
5808
5809        let snapshot = multibuffer.read(cx).snapshot(cx);
5810        assert_eq!(snapshot.text(), "");
5811        assert_eq!(
5812            snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
5813            &[Some(0)]
5814        );
5815        assert_eq!(
5816            snapshot.buffer_rows(MultiBufferRow(1)).collect::<Vec<_>>(),
5817            &[]
5818        );
5819    }
5820
5821    #[gpui::test]
5822    fn test_singleton_multibuffer_anchors(cx: &mut AppContext) {
5823        let buffer = cx.new_model(|cx| Buffer::local("abcd", cx));
5824        let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
5825        let old_snapshot = multibuffer.read(cx).snapshot(cx);
5826        buffer.update(cx, |buffer, cx| {
5827            buffer.edit([(0..0, "X")], None, cx);
5828            buffer.edit([(5..5, "Y")], None, cx);
5829        });
5830        let new_snapshot = multibuffer.read(cx).snapshot(cx);
5831
5832        assert_eq!(old_snapshot.text(), "abcd");
5833        assert_eq!(new_snapshot.text(), "XabcdY");
5834
5835        assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
5836        assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
5837        assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
5838        assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
5839    }
5840
5841    #[gpui::test]
5842    fn test_multibuffer_anchors(cx: &mut AppContext) {
5843        let buffer_1 = cx.new_model(|cx| Buffer::local("abcd", cx));
5844        let buffer_2 = cx.new_model(|cx| Buffer::local("efghi", cx));
5845        let multibuffer = cx.new_model(|cx| {
5846            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite);
5847            multibuffer.push_excerpts(
5848                buffer_1.clone(),
5849                [ExcerptRange {
5850                    context: 0..4,
5851                    primary: None,
5852                }],
5853                cx,
5854            );
5855            multibuffer.push_excerpts(
5856                buffer_2.clone(),
5857                [ExcerptRange {
5858                    context: 0..5,
5859                    primary: None,
5860                }],
5861                cx,
5862            );
5863            multibuffer
5864        });
5865        let old_snapshot = multibuffer.read(cx).snapshot(cx);
5866
5867        assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
5868        assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
5869        assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
5870        assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
5871        assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
5872        assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
5873
5874        buffer_1.update(cx, |buffer, cx| {
5875            buffer.edit([(0..0, "W")], None, cx);
5876            buffer.edit([(5..5, "X")], None, cx);
5877        });
5878        buffer_2.update(cx, |buffer, cx| {
5879            buffer.edit([(0..0, "Y")], None, cx);
5880            buffer.edit([(6..6, "Z")], None, cx);
5881        });
5882        let new_snapshot = multibuffer.read(cx).snapshot(cx);
5883
5884        assert_eq!(old_snapshot.text(), "abcd\nefghi");
5885        assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
5886
5887        assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
5888        assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
5889        assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
5890        assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
5891        assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
5892        assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
5893        assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
5894        assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
5895        assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
5896        assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
5897    }
5898
5899    #[gpui::test]
5900    fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut AppContext) {
5901        let buffer_1 = cx.new_model(|cx| Buffer::local("abcd", cx));
5902        let buffer_2 = cx.new_model(|cx| Buffer::local("ABCDEFGHIJKLMNOP", cx));
5903        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
5904
5905        // Create an insertion id in buffer 1 that doesn't exist in buffer 2.
5906        // Add an excerpt from buffer 1 that spans this new insertion.
5907        buffer_1.update(cx, |buffer, cx| buffer.edit([(4..4, "123")], None, cx));
5908        let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| {
5909            multibuffer
5910                .push_excerpts(
5911                    buffer_1.clone(),
5912                    [ExcerptRange {
5913                        context: 0..7,
5914                        primary: None,
5915                    }],
5916                    cx,
5917                )
5918                .pop()
5919                .unwrap()
5920        });
5921
5922        let snapshot_1 = multibuffer.read(cx).snapshot(cx);
5923        assert_eq!(snapshot_1.text(), "abcd123");
5924
5925        // Replace the buffer 1 excerpt with new excerpts from buffer 2.
5926        let (excerpt_id_2, excerpt_id_3) = multibuffer.update(cx, |multibuffer, cx| {
5927            multibuffer.remove_excerpts([excerpt_id_1], cx);
5928            let mut ids = multibuffer
5929                .push_excerpts(
5930                    buffer_2.clone(),
5931                    [
5932                        ExcerptRange {
5933                            context: 0..4,
5934                            primary: None,
5935                        },
5936                        ExcerptRange {
5937                            context: 6..10,
5938                            primary: None,
5939                        },
5940                        ExcerptRange {
5941                            context: 12..16,
5942                            primary: None,
5943                        },
5944                    ],
5945                    cx,
5946                )
5947                .into_iter();
5948            (ids.next().unwrap(), ids.next().unwrap())
5949        });
5950        let snapshot_2 = multibuffer.read(cx).snapshot(cx);
5951        assert_eq!(snapshot_2.text(), "ABCD\nGHIJ\nMNOP");
5952
5953        // The old excerpt id doesn't get reused.
5954        assert_ne!(excerpt_id_2, excerpt_id_1);
5955
5956        // Resolve some anchors from the previous snapshot in the new snapshot.
5957        // The current excerpts are from a different buffer, so we don't attempt to
5958        // resolve the old text anchor in the new buffer.
5959        assert_eq!(
5960            snapshot_2.summary_for_anchor::<usize>(&snapshot_1.anchor_before(2)),
5961            0
5962        );
5963        assert_eq!(
5964            snapshot_2.summaries_for_anchors::<usize, _>(&[
5965                snapshot_1.anchor_before(2),
5966                snapshot_1.anchor_after(3)
5967            ]),
5968            vec![0, 0]
5969        );
5970
5971        // Refresh anchors from the old snapshot. The return value indicates that both
5972        // anchors lost their original excerpt.
5973        let refresh =
5974            snapshot_2.refresh_anchors(&[snapshot_1.anchor_before(2), snapshot_1.anchor_after(3)]);
5975        assert_eq!(
5976            refresh,
5977            &[
5978                (0, snapshot_2.anchor_before(0), false),
5979                (1, snapshot_2.anchor_after(0), false),
5980            ]
5981        );
5982
5983        // Replace the middle excerpt with a smaller excerpt in buffer 2,
5984        // that intersects the old excerpt.
5985        let excerpt_id_5 = multibuffer.update(cx, |multibuffer, cx| {
5986            multibuffer.remove_excerpts([excerpt_id_3], cx);
5987            multibuffer
5988                .insert_excerpts_after(
5989                    excerpt_id_2,
5990                    buffer_2.clone(),
5991                    [ExcerptRange {
5992                        context: 5..8,
5993                        primary: None,
5994                    }],
5995                    cx,
5996                )
5997                .pop()
5998                .unwrap()
5999        });
6000
6001        let snapshot_3 = multibuffer.read(cx).snapshot(cx);
6002        assert_eq!(snapshot_3.text(), "ABCD\nFGH\nMNOP");
6003        assert_ne!(excerpt_id_5, excerpt_id_3);
6004
6005        // Resolve some anchors from the previous snapshot in the new snapshot.
6006        // The third anchor can't be resolved, since its excerpt has been removed,
6007        // so it resolves to the same position as its predecessor.
6008        let anchors = [
6009            snapshot_2.anchor_before(0),
6010            snapshot_2.anchor_after(2),
6011            snapshot_2.anchor_after(6),
6012            snapshot_2.anchor_after(14),
6013        ];
6014        assert_eq!(
6015            snapshot_3.summaries_for_anchors::<usize, _>(&anchors),
6016            &[0, 2, 9, 13]
6017        );
6018
6019        let new_anchors = snapshot_3.refresh_anchors(&anchors);
6020        assert_eq!(
6021            new_anchors.iter().map(|a| (a.0, a.2)).collect::<Vec<_>>(),
6022            &[(0, true), (1, true), (2, true), (3, true)]
6023        );
6024        assert_eq!(
6025            snapshot_3.summaries_for_anchors::<usize, _>(new_anchors.iter().map(|a| &a.1)),
6026            &[0, 2, 7, 13]
6027        );
6028    }
6029
6030    #[gpui::test(iterations = 100)]
6031    fn test_random_multibuffer(cx: &mut AppContext, mut rng: StdRng) {
6032        let operations = env::var("OPERATIONS")
6033            .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
6034            .unwrap_or(10);
6035
6036        let mut buffers: Vec<Model<Buffer>> = Vec::new();
6037        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
6038        let mut excerpt_ids = Vec::<ExcerptId>::new();
6039        let mut expected_excerpts = Vec::<(Model<Buffer>, Range<text::Anchor>)>::new();
6040        let mut anchors = Vec::new();
6041        let mut old_versions = Vec::new();
6042
6043        for _ in 0..operations {
6044            match rng.gen_range(0..100) {
6045                0..=14 if !buffers.is_empty() => {
6046                    let buffer = buffers.choose(&mut rng).unwrap();
6047                    buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
6048                }
6049                15..=19 if !expected_excerpts.is_empty() => {
6050                    multibuffer.update(cx, |multibuffer, cx| {
6051                        let ids = multibuffer.excerpt_ids();
6052                        let mut excerpts = HashSet::default();
6053                        for _ in 0..rng.gen_range(0..ids.len()) {
6054                            excerpts.extend(ids.choose(&mut rng).copied());
6055                        }
6056
6057                        let line_count = rng.gen_range(0..5);
6058
6059                        let excerpt_ixs = excerpts
6060                            .iter()
6061                            .map(|id| excerpt_ids.iter().position(|i| i == id).unwrap())
6062                            .collect::<Vec<_>>();
6063                        log::info!("Expanding excerpts {excerpt_ixs:?} by {line_count} lines");
6064                        multibuffer.expand_excerpts(
6065                            excerpts.iter().cloned(),
6066                            line_count,
6067                            ExpandExcerptDirection::UpAndDown,
6068                            cx,
6069                        );
6070
6071                        if line_count > 0 {
6072                            for id in excerpts {
6073                                let excerpt_ix = excerpt_ids.iter().position(|&i| i == id).unwrap();
6074                                let (buffer, range) = &mut expected_excerpts[excerpt_ix];
6075                                let snapshot = buffer.read(cx).snapshot();
6076                                let mut point_range = range.to_point(&snapshot);
6077                                point_range.start =
6078                                    Point::new(point_range.start.row.saturating_sub(line_count), 0);
6079                                point_range.end = snapshot.clip_point(
6080                                    Point::new(point_range.end.row + line_count, 0),
6081                                    Bias::Left,
6082                                );
6083                                point_range.end.column = snapshot.line_len(point_range.end.row);
6084                                *range = snapshot.anchor_before(point_range.start)
6085                                    ..snapshot.anchor_after(point_range.end);
6086                            }
6087                        }
6088                    });
6089                }
6090                20..=29 if !expected_excerpts.is_empty() => {
6091                    let mut ids_to_remove = vec![];
6092                    for _ in 0..rng.gen_range(1..=3) {
6093                        if expected_excerpts.is_empty() {
6094                            break;
6095                        }
6096
6097                        let ix = rng.gen_range(0..expected_excerpts.len());
6098                        ids_to_remove.push(excerpt_ids.remove(ix));
6099                        let (buffer, range) = expected_excerpts.remove(ix);
6100                        let buffer = buffer.read(cx);
6101                        log::info!(
6102                            "Removing excerpt {}: {:?}",
6103                            ix,
6104                            buffer
6105                                .text_for_range(range.to_offset(buffer))
6106                                .collect::<String>(),
6107                        );
6108                    }
6109                    let snapshot = multibuffer.read(cx).read(cx);
6110                    ids_to_remove.sort_unstable_by(|a, b| a.cmp(b, &snapshot));
6111                    drop(snapshot);
6112                    multibuffer.update(cx, |multibuffer, cx| {
6113                        multibuffer.remove_excerpts(ids_to_remove, cx)
6114                    });
6115                }
6116                30..=39 if !expected_excerpts.is_empty() => {
6117                    let multibuffer = multibuffer.read(cx).read(cx);
6118                    let offset =
6119                        multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left);
6120                    let bias = if rng.gen() { Bias::Left } else { Bias::Right };
6121                    log::info!("Creating anchor at {} with bias {:?}", offset, bias);
6122                    anchors.push(multibuffer.anchor_at(offset, bias));
6123                    anchors.sort_by(|a, b| a.cmp(b, &multibuffer));
6124                }
6125                40..=44 if !anchors.is_empty() => {
6126                    let multibuffer = multibuffer.read(cx).read(cx);
6127                    let prev_len = anchors.len();
6128                    anchors = multibuffer
6129                        .refresh_anchors(&anchors)
6130                        .into_iter()
6131                        .map(|a| a.1)
6132                        .collect();
6133
6134                    // Ensure the newly-refreshed anchors point to a valid excerpt and don't
6135                    // overshoot its boundaries.
6136                    assert_eq!(anchors.len(), prev_len);
6137                    for anchor in &anchors {
6138                        if anchor.excerpt_id == ExcerptId::min()
6139                            || anchor.excerpt_id == ExcerptId::max()
6140                        {
6141                            continue;
6142                        }
6143
6144                        let excerpt = multibuffer.excerpt(anchor.excerpt_id).unwrap();
6145                        assert_eq!(excerpt.id, anchor.excerpt_id);
6146                        assert!(excerpt.contains(anchor));
6147                    }
6148                }
6149                _ => {
6150                    let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
6151                        let base_text = util::RandomCharIter::new(&mut rng)
6152                            .take(25)
6153                            .collect::<String>();
6154
6155                        buffers.push(cx.new_model(|cx| Buffer::local(base_text, cx)));
6156                        buffers.last().unwrap()
6157                    } else {
6158                        buffers.choose(&mut rng).unwrap()
6159                    };
6160
6161                    let buffer = buffer_handle.read(cx);
6162                    let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
6163                    let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
6164                    let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
6165                    let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len());
6166                    let prev_excerpt_id = excerpt_ids
6167                        .get(prev_excerpt_ix)
6168                        .cloned()
6169                        .unwrap_or_else(ExcerptId::max);
6170                    let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len());
6171
6172                    log::info!(
6173                        "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}",
6174                        excerpt_ix,
6175                        expected_excerpts.len(),
6176                        buffer_handle.read(cx).remote_id(),
6177                        buffer.text(),
6178                        start_ix..end_ix,
6179                        &buffer.text()[start_ix..end_ix]
6180                    );
6181
6182                    let excerpt_id = multibuffer.update(cx, |multibuffer, cx| {
6183                        multibuffer
6184                            .insert_excerpts_after(
6185                                prev_excerpt_id,
6186                                buffer_handle.clone(),
6187                                [ExcerptRange {
6188                                    context: start_ix..end_ix,
6189                                    primary: None,
6190                                }],
6191                                cx,
6192                            )
6193                            .pop()
6194                            .unwrap()
6195                    });
6196
6197                    excerpt_ids.insert(excerpt_ix, excerpt_id);
6198                    expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range));
6199                }
6200            }
6201
6202            if rng.gen_bool(0.3) {
6203                multibuffer.update(cx, |multibuffer, cx| {
6204                    old_versions.push((multibuffer.snapshot(cx), multibuffer.subscribe()));
6205                })
6206            }
6207
6208            let snapshot = multibuffer.read(cx).snapshot(cx);
6209
6210            let mut excerpt_starts = Vec::new();
6211            let mut expected_text = String::new();
6212            let mut expected_buffer_rows = Vec::new();
6213            for (buffer, range) in &expected_excerpts {
6214                let buffer = buffer.read(cx);
6215                let buffer_range = range.to_offset(buffer);
6216
6217                excerpt_starts.push(TextSummary::from(expected_text.as_str()));
6218                expected_text.extend(buffer.text_for_range(buffer_range.clone()));
6219                expected_text.push('\n');
6220
6221                let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
6222                    ..=buffer.offset_to_point(buffer_range.end).row;
6223                for row in buffer_row_range {
6224                    expected_buffer_rows.push(Some(row));
6225                }
6226            }
6227            // Remove final trailing newline.
6228            if !expected_excerpts.is_empty() {
6229                expected_text.pop();
6230            }
6231
6232            // Always report one buffer row
6233            if expected_buffer_rows.is_empty() {
6234                expected_buffer_rows.push(Some(0));
6235            }
6236
6237            assert_eq!(snapshot.text(), expected_text);
6238            log::info!("MultiBuffer text: {:?}", expected_text);
6239
6240            assert_eq!(
6241                snapshot.buffer_rows(MultiBufferRow(0)).collect::<Vec<_>>(),
6242                expected_buffer_rows,
6243            );
6244
6245            for _ in 0..5 {
6246                let start_row = rng.gen_range(0..=expected_buffer_rows.len());
6247                assert_eq!(
6248                    snapshot
6249                        .buffer_rows(MultiBufferRow(start_row as u32))
6250                        .collect::<Vec<_>>(),
6251                    &expected_buffer_rows[start_row..],
6252                    "buffer_rows({})",
6253                    start_row
6254                );
6255            }
6256
6257            assert_eq!(
6258                snapshot.max_buffer_row().0,
6259                expected_buffer_rows.into_iter().flatten().max().unwrap()
6260            );
6261
6262            let mut excerpt_starts = excerpt_starts.into_iter();
6263            for (buffer, range) in &expected_excerpts {
6264                let buffer = buffer.read(cx);
6265                let buffer_id = buffer.remote_id();
6266                let buffer_range = range.to_offset(buffer);
6267                let buffer_start_point = buffer.offset_to_point(buffer_range.start);
6268                let buffer_start_point_utf16 =
6269                    buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
6270
6271                let excerpt_start = excerpt_starts.next().unwrap();
6272                let mut offset = excerpt_start.len;
6273                let mut buffer_offset = buffer_range.start;
6274                let mut point = excerpt_start.lines;
6275                let mut buffer_point = buffer_start_point;
6276                let mut point_utf16 = excerpt_start.lines_utf16();
6277                let mut buffer_point_utf16 = buffer_start_point_utf16;
6278                for ch in buffer
6279                    .snapshot()
6280                    .chunks(buffer_range.clone(), false)
6281                    .flat_map(|c| c.text.chars())
6282                {
6283                    for _ in 0..ch.len_utf8() {
6284                        let left_offset = snapshot.clip_offset(offset, Bias::Left);
6285                        let right_offset = snapshot.clip_offset(offset, Bias::Right);
6286                        let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
6287                        let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
6288                        assert_eq!(
6289                            left_offset,
6290                            excerpt_start.len + (buffer_left_offset - buffer_range.start),
6291                            "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
6292                            offset,
6293                            buffer_id,
6294                            buffer_offset,
6295                        );
6296                        assert_eq!(
6297                            right_offset,
6298                            excerpt_start.len + (buffer_right_offset - buffer_range.start),
6299                            "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
6300                            offset,
6301                            buffer_id,
6302                            buffer_offset,
6303                        );
6304
6305                        let left_point = snapshot.clip_point(point, Bias::Left);
6306                        let right_point = snapshot.clip_point(point, Bias::Right);
6307                        let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
6308                        let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
6309                        assert_eq!(
6310                            left_point,
6311                            excerpt_start.lines + (buffer_left_point - buffer_start_point),
6312                            "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
6313                            point,
6314                            buffer_id,
6315                            buffer_point,
6316                        );
6317                        assert_eq!(
6318                            right_point,
6319                            excerpt_start.lines + (buffer_right_point - buffer_start_point),
6320                            "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
6321                            point,
6322                            buffer_id,
6323                            buffer_point,
6324                        );
6325
6326                        assert_eq!(
6327                            snapshot.point_to_offset(left_point),
6328                            left_offset,
6329                            "point_to_offset({:?})",
6330                            left_point,
6331                        );
6332                        assert_eq!(
6333                            snapshot.offset_to_point(left_offset),
6334                            left_point,
6335                            "offset_to_point({:?})",
6336                            left_offset,
6337                        );
6338
6339                        offset += 1;
6340                        buffer_offset += 1;
6341                        if ch == '\n' {
6342                            point += Point::new(1, 0);
6343                            buffer_point += Point::new(1, 0);
6344                        } else {
6345                            point += Point::new(0, 1);
6346                            buffer_point += Point::new(0, 1);
6347                        }
6348                    }
6349
6350                    for _ in 0..ch.len_utf16() {
6351                        let left_point_utf16 =
6352                            snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Left);
6353                        let right_point_utf16 =
6354                            snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Right);
6355                        let buffer_left_point_utf16 =
6356                            buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Left);
6357                        let buffer_right_point_utf16 =
6358                            buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Right);
6359                        assert_eq!(
6360                            left_point_utf16,
6361                            excerpt_start.lines_utf16()
6362                                + (buffer_left_point_utf16 - buffer_start_point_utf16),
6363                            "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
6364                            point_utf16,
6365                            buffer_id,
6366                            buffer_point_utf16,
6367                        );
6368                        assert_eq!(
6369                            right_point_utf16,
6370                            excerpt_start.lines_utf16()
6371                                + (buffer_right_point_utf16 - buffer_start_point_utf16),
6372                            "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
6373                            point_utf16,
6374                            buffer_id,
6375                            buffer_point_utf16,
6376                        );
6377
6378                        if ch == '\n' {
6379                            point_utf16 += PointUtf16::new(1, 0);
6380                            buffer_point_utf16 += PointUtf16::new(1, 0);
6381                        } else {
6382                            point_utf16 += PointUtf16::new(0, 1);
6383                            buffer_point_utf16 += PointUtf16::new(0, 1);
6384                        }
6385                    }
6386                }
6387            }
6388
6389            for (row, line) in expected_text.split('\n').enumerate() {
6390                assert_eq!(
6391                    snapshot.line_len(MultiBufferRow(row as u32)),
6392                    line.len() as u32,
6393                    "line_len({}).",
6394                    row
6395                );
6396            }
6397
6398            let text_rope = Rope::from(expected_text.as_str());
6399            for _ in 0..10 {
6400                let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
6401                let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
6402
6403                let text_for_range = snapshot
6404                    .text_for_range(start_ix..end_ix)
6405                    .collect::<String>();
6406                assert_eq!(
6407                    text_for_range,
6408                    &expected_text[start_ix..end_ix],
6409                    "incorrect text for range {:?}",
6410                    start_ix..end_ix
6411                );
6412
6413                let excerpted_buffer_ranges = multibuffer
6414                    .read(cx)
6415                    .range_to_buffer_ranges(start_ix..end_ix, cx);
6416                let excerpted_buffers_text = excerpted_buffer_ranges
6417                    .iter()
6418                    .map(|(buffer, buffer_range, _)| {
6419                        buffer
6420                            .read(cx)
6421                            .text_for_range(buffer_range.clone())
6422                            .collect::<String>()
6423                    })
6424                    .collect::<Vec<_>>()
6425                    .join("\n");
6426                assert_eq!(excerpted_buffers_text, text_for_range);
6427                if !expected_excerpts.is_empty() {
6428                    assert!(!excerpted_buffer_ranges.is_empty());
6429                }
6430
6431                let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
6432                assert_eq!(
6433                    snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
6434                    expected_summary,
6435                    "incorrect summary for range {:?}",
6436                    start_ix..end_ix
6437                );
6438            }
6439
6440            // Anchor resolution
6441            let summaries = snapshot.summaries_for_anchors::<usize, _>(&anchors);
6442            assert_eq!(anchors.len(), summaries.len());
6443            for (anchor, resolved_offset) in anchors.iter().zip(summaries) {
6444                assert!(resolved_offset <= snapshot.len());
6445                assert_eq!(
6446                    snapshot.summary_for_anchor::<usize>(anchor),
6447                    resolved_offset
6448                );
6449            }
6450
6451            for _ in 0..10 {
6452                let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
6453                assert_eq!(
6454                    snapshot.reversed_chars_at(end_ix).collect::<String>(),
6455                    expected_text[..end_ix].chars().rev().collect::<String>(),
6456                );
6457            }
6458
6459            for _ in 0..10 {
6460                let end_ix = rng.gen_range(0..=text_rope.len());
6461                let start_ix = rng.gen_range(0..=end_ix);
6462                assert_eq!(
6463                    snapshot
6464                        .bytes_in_range(start_ix..end_ix)
6465                        .flatten()
6466                        .copied()
6467                        .collect::<Vec<_>>(),
6468                    expected_text.as_bytes()[start_ix..end_ix].to_vec(),
6469                    "bytes_in_range({:?})",
6470                    start_ix..end_ix,
6471                );
6472            }
6473        }
6474
6475        let snapshot = multibuffer.read(cx).snapshot(cx);
6476        for (old_snapshot, subscription) in old_versions {
6477            let edits = subscription.consume().into_inner();
6478
6479            log::info!(
6480                "applying subscription edits to old text: {:?}: {:?}",
6481                old_snapshot.text(),
6482                edits,
6483            );
6484
6485            let mut text = old_snapshot.text();
6486            for edit in edits {
6487                let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
6488                text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
6489            }
6490            assert_eq!(text.to_string(), snapshot.text());
6491        }
6492    }
6493
6494    #[gpui::test]
6495    fn test_history(cx: &mut AppContext) {
6496        let test_settings = SettingsStore::test(cx);
6497        cx.set_global(test_settings);
6498        let group_interval: Duration = Duration::from_millis(1);
6499        let buffer_1 = cx.new_model(|cx| {
6500            let mut buf = Buffer::local("1234", cx);
6501            buf.set_group_interval(group_interval);
6502            buf
6503        });
6504        let buffer_2 = cx.new_model(|cx| {
6505            let mut buf = Buffer::local("5678", cx);
6506            buf.set_group_interval(group_interval);
6507            buf
6508        });
6509        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
6510        multibuffer.update(cx, |this, _| {
6511            this.history.group_interval = group_interval;
6512        });
6513        multibuffer.update(cx, |multibuffer, cx| {
6514            multibuffer.push_excerpts(
6515                buffer_1.clone(),
6516                [ExcerptRange {
6517                    context: 0..buffer_1.read(cx).len(),
6518                    primary: None,
6519                }],
6520                cx,
6521            );
6522            multibuffer.push_excerpts(
6523                buffer_2.clone(),
6524                [ExcerptRange {
6525                    context: 0..buffer_2.read(cx).len(),
6526                    primary: None,
6527                }],
6528                cx,
6529            );
6530        });
6531
6532        let mut now = Instant::now();
6533
6534        multibuffer.update(cx, |multibuffer, cx| {
6535            let transaction_1 = multibuffer.start_transaction_at(now, cx).unwrap();
6536            multibuffer.edit(
6537                [
6538                    (Point::new(0, 0)..Point::new(0, 0), "A"),
6539                    (Point::new(1, 0)..Point::new(1, 0), "A"),
6540                ],
6541                None,
6542                cx,
6543            );
6544            multibuffer.edit(
6545                [
6546                    (Point::new(0, 1)..Point::new(0, 1), "B"),
6547                    (Point::new(1, 1)..Point::new(1, 1), "B"),
6548                ],
6549                None,
6550                cx,
6551            );
6552            multibuffer.end_transaction_at(now, cx);
6553            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
6554
6555            // Verify edited ranges for transaction 1
6556            assert_eq!(
6557                multibuffer.edited_ranges_for_transaction(transaction_1, cx),
6558                &[
6559                    Point::new(0, 0)..Point::new(0, 2),
6560                    Point::new(1, 0)..Point::new(1, 2)
6561                ]
6562            );
6563
6564            // Edit buffer 1 through the multibuffer
6565            now += 2 * group_interval;
6566            multibuffer.start_transaction_at(now, cx);
6567            multibuffer.edit([(2..2, "C")], None, cx);
6568            multibuffer.end_transaction_at(now, cx);
6569            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
6570
6571            // Edit buffer 1 independently
6572            buffer_1.update(cx, |buffer_1, cx| {
6573                buffer_1.start_transaction_at(now);
6574                buffer_1.edit([(3..3, "D")], None, cx);
6575                buffer_1.end_transaction_at(now, cx);
6576
6577                now += 2 * group_interval;
6578                buffer_1.start_transaction_at(now);
6579                buffer_1.edit([(4..4, "E")], None, cx);
6580                buffer_1.end_transaction_at(now, cx);
6581            });
6582            assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
6583
6584            // An undo in the multibuffer undoes the multibuffer transaction
6585            // and also any individual buffer edits that have occurred since
6586            // that transaction.
6587            multibuffer.undo(cx);
6588            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
6589
6590            multibuffer.undo(cx);
6591            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
6592
6593            multibuffer.redo(cx);
6594            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
6595
6596            multibuffer.redo(cx);
6597            assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678");
6598
6599            // Undo buffer 2 independently.
6600            buffer_2.update(cx, |buffer_2, cx| buffer_2.undo(cx));
6601            assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\n5678");
6602
6603            // An undo in the multibuffer undoes the components of the
6604            // the last multibuffer transaction that are not already undone.
6605            multibuffer.undo(cx);
6606            assert_eq!(multibuffer.read(cx).text(), "AB1234\n5678");
6607
6608            multibuffer.undo(cx);
6609            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
6610
6611            multibuffer.redo(cx);
6612            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
6613
6614            buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
6615            assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
6616
6617            // Redo stack gets cleared after an edit.
6618            now += 2 * group_interval;
6619            multibuffer.start_transaction_at(now, cx);
6620            multibuffer.edit([(0..0, "X")], None, cx);
6621            multibuffer.end_transaction_at(now, cx);
6622            assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
6623            multibuffer.redo(cx);
6624            assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
6625            multibuffer.undo(cx);
6626            assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678");
6627            multibuffer.undo(cx);
6628            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
6629
6630            // Transactions can be grouped manually.
6631            multibuffer.redo(cx);
6632            multibuffer.redo(cx);
6633            assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
6634            multibuffer.group_until_transaction(transaction_1, cx);
6635            multibuffer.undo(cx);
6636            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
6637            multibuffer.redo(cx);
6638            assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678");
6639        });
6640    }
6641
6642    #[gpui::test]
6643    fn test_excerpts_in_ranges_no_ranges(cx: &mut AppContext) {
6644        let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
6645        let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx));
6646        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
6647        multibuffer.update(cx, |multibuffer, cx| {
6648            multibuffer.push_excerpts(
6649                buffer_1.clone(),
6650                [ExcerptRange {
6651                    context: 0..buffer_1.read(cx).len(),
6652                    primary: None,
6653                }],
6654                cx,
6655            );
6656            multibuffer.push_excerpts(
6657                buffer_2.clone(),
6658                [ExcerptRange {
6659                    context: 0..buffer_2.read(cx).len(),
6660                    primary: None,
6661                }],
6662                cx,
6663            );
6664        });
6665
6666        let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx));
6667
6668        let mut excerpts = snapshot.excerpts_in_ranges(iter::from_fn(|| None));
6669
6670        assert!(excerpts.next().is_none());
6671    }
6672
6673    fn validate_excerpts(
6674        actual: &[(ExcerptId, BufferId, Range<Anchor>)],
6675        expected: &Vec<(ExcerptId, BufferId, Range<Anchor>)>,
6676    ) {
6677        assert_eq!(actual.len(), expected.len());
6678
6679        actual
6680            .iter()
6681            .zip(expected)
6682            .map(|(actual, expected)| {
6683                assert_eq!(actual.0, expected.0);
6684                assert_eq!(actual.1, expected.1);
6685                assert_eq!(actual.2.start, expected.2.start);
6686                assert_eq!(actual.2.end, expected.2.end);
6687            })
6688            .collect_vec();
6689    }
6690
6691    fn map_range_from_excerpt(
6692        snapshot: &MultiBufferSnapshot,
6693        excerpt_id: ExcerptId,
6694        excerpt_buffer: &BufferSnapshot,
6695        range: Range<usize>,
6696    ) -> Range<Anchor> {
6697        snapshot
6698            .anchor_in_excerpt(excerpt_id, excerpt_buffer.anchor_before(range.start))
6699            .unwrap()
6700            ..snapshot
6701                .anchor_in_excerpt(excerpt_id, excerpt_buffer.anchor_after(range.end))
6702                .unwrap()
6703    }
6704
6705    fn make_expected_excerpt_info(
6706        snapshot: &MultiBufferSnapshot,
6707        cx: &mut AppContext,
6708        excerpt_id: ExcerptId,
6709        buffer: &Model<Buffer>,
6710        range: Range<usize>,
6711    ) -> (ExcerptId, BufferId, Range<Anchor>) {
6712        (
6713            excerpt_id,
6714            buffer.read(cx).remote_id(),
6715            map_range_from_excerpt(snapshot, excerpt_id, &buffer.read(cx).snapshot(), range),
6716        )
6717    }
6718
6719    #[gpui::test]
6720    fn test_excerpts_in_ranges_range_inside_the_excerpt(cx: &mut AppContext) {
6721        let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
6722        let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx));
6723        let buffer_len = buffer_1.read(cx).len();
6724        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
6725        let mut expected_excerpt_id = ExcerptId(0);
6726
6727        multibuffer.update(cx, |multibuffer, cx| {
6728            expected_excerpt_id = multibuffer.push_excerpts(
6729                buffer_1.clone(),
6730                [ExcerptRange {
6731                    context: 0..buffer_1.read(cx).len(),
6732                    primary: None,
6733                }],
6734                cx,
6735            )[0];
6736            multibuffer.push_excerpts(
6737                buffer_2.clone(),
6738                [ExcerptRange {
6739                    context: 0..buffer_2.read(cx).len(),
6740                    primary: None,
6741                }],
6742                cx,
6743            );
6744        });
6745
6746        let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx));
6747
6748        let range = snapshot
6749            .anchor_in_excerpt(expected_excerpt_id, buffer_1.read(cx).anchor_before(1))
6750            .unwrap()
6751            ..snapshot
6752                .anchor_in_excerpt(
6753                    expected_excerpt_id,
6754                    buffer_1.read(cx).anchor_after(buffer_len / 2),
6755                )
6756                .unwrap();
6757
6758        let expected_excerpts = vec![make_expected_excerpt_info(
6759            &snapshot,
6760            cx,
6761            expected_excerpt_id,
6762            &buffer_1,
6763            1..(buffer_len / 2),
6764        )];
6765
6766        let excerpts = snapshot
6767            .excerpts_in_ranges(vec![range.clone()].into_iter())
6768            .map(|(excerpt_id, buffer, actual_range)| {
6769                (
6770                    excerpt_id,
6771                    buffer.remote_id(),
6772                    map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range),
6773                )
6774            })
6775            .collect_vec();
6776
6777        validate_excerpts(&excerpts, &expected_excerpts);
6778    }
6779
6780    #[gpui::test]
6781    fn test_excerpts_in_ranges_range_crosses_excerpts_boundary(cx: &mut AppContext) {
6782        let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
6783        let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx));
6784        let buffer_len = buffer_1.read(cx).len();
6785        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
6786        let mut excerpt_1_id = ExcerptId(0);
6787        let mut excerpt_2_id = ExcerptId(0);
6788
6789        multibuffer.update(cx, |multibuffer, cx| {
6790            excerpt_1_id = multibuffer.push_excerpts(
6791                buffer_1.clone(),
6792                [ExcerptRange {
6793                    context: 0..buffer_1.read(cx).len(),
6794                    primary: None,
6795                }],
6796                cx,
6797            )[0];
6798            excerpt_2_id = multibuffer.push_excerpts(
6799                buffer_2.clone(),
6800                [ExcerptRange {
6801                    context: 0..buffer_2.read(cx).len(),
6802                    primary: None,
6803                }],
6804                cx,
6805            )[0];
6806        });
6807
6808        let snapshot = multibuffer.read(cx).snapshot(cx);
6809
6810        let expected_range = snapshot
6811            .anchor_in_excerpt(
6812                excerpt_1_id,
6813                buffer_1.read(cx).anchor_before(buffer_len / 2),
6814            )
6815            .unwrap()
6816            ..snapshot
6817                .anchor_in_excerpt(excerpt_2_id, buffer_2.read(cx).anchor_after(buffer_len / 2))
6818                .unwrap();
6819
6820        let expected_excerpts = vec![
6821            make_expected_excerpt_info(
6822                &snapshot,
6823                cx,
6824                excerpt_1_id,
6825                &buffer_1,
6826                (buffer_len / 2)..buffer_len,
6827            ),
6828            make_expected_excerpt_info(&snapshot, cx, excerpt_2_id, &buffer_2, 0..buffer_len / 2),
6829        ];
6830
6831        let excerpts = snapshot
6832            .excerpts_in_ranges(vec![expected_range.clone()].into_iter())
6833            .map(|(excerpt_id, buffer, actual_range)| {
6834                (
6835                    excerpt_id,
6836                    buffer.remote_id(),
6837                    map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range),
6838                )
6839            })
6840            .collect_vec();
6841
6842        validate_excerpts(&excerpts, &expected_excerpts);
6843    }
6844
6845    #[gpui::test]
6846    fn test_excerpts_in_ranges_range_encloses_excerpt(cx: &mut AppContext) {
6847        let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
6848        let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx));
6849        let buffer_3 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'r'), cx));
6850        let buffer_len = buffer_1.read(cx).len();
6851        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
6852        let mut excerpt_1_id = ExcerptId(0);
6853        let mut excerpt_2_id = ExcerptId(0);
6854        let mut excerpt_3_id = ExcerptId(0);
6855
6856        multibuffer.update(cx, |multibuffer, cx| {
6857            excerpt_1_id = multibuffer.push_excerpts(
6858                buffer_1.clone(),
6859                [ExcerptRange {
6860                    context: 0..buffer_1.read(cx).len(),
6861                    primary: None,
6862                }],
6863                cx,
6864            )[0];
6865            excerpt_2_id = multibuffer.push_excerpts(
6866                buffer_2.clone(),
6867                [ExcerptRange {
6868                    context: 0..buffer_2.read(cx).len(),
6869                    primary: None,
6870                }],
6871                cx,
6872            )[0];
6873            excerpt_3_id = multibuffer.push_excerpts(
6874                buffer_3.clone(),
6875                [ExcerptRange {
6876                    context: 0..buffer_3.read(cx).len(),
6877                    primary: None,
6878                }],
6879                cx,
6880            )[0];
6881        });
6882
6883        let snapshot = multibuffer.read(cx).snapshot(cx);
6884
6885        let expected_range = snapshot
6886            .anchor_in_excerpt(
6887                excerpt_1_id,
6888                buffer_1.read(cx).anchor_before(buffer_len / 2),
6889            )
6890            .unwrap()
6891            ..snapshot
6892                .anchor_in_excerpt(excerpt_3_id, buffer_3.read(cx).anchor_after(buffer_len / 2))
6893                .unwrap();
6894
6895        let expected_excerpts = vec![
6896            make_expected_excerpt_info(
6897                &snapshot,
6898                cx,
6899                excerpt_1_id,
6900                &buffer_1,
6901                (buffer_len / 2)..buffer_len,
6902            ),
6903            make_expected_excerpt_info(&snapshot, cx, excerpt_2_id, &buffer_2, 0..buffer_len),
6904            make_expected_excerpt_info(&snapshot, cx, excerpt_3_id, &buffer_3, 0..buffer_len / 2),
6905        ];
6906
6907        let excerpts = snapshot
6908            .excerpts_in_ranges(vec![expected_range.clone()].into_iter())
6909            .map(|(excerpt_id, buffer, actual_range)| {
6910                (
6911                    excerpt_id,
6912                    buffer.remote_id(),
6913                    map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range),
6914                )
6915            })
6916            .collect_vec();
6917
6918        validate_excerpts(&excerpts, &expected_excerpts);
6919    }
6920
6921    #[gpui::test]
6922    fn test_excerpts_in_ranges_multiple_ranges(cx: &mut AppContext) {
6923        let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
6924        let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx));
6925        let buffer_len = buffer_1.read(cx).len();
6926        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
6927        let mut excerpt_1_id = ExcerptId(0);
6928        let mut excerpt_2_id = ExcerptId(0);
6929
6930        multibuffer.update(cx, |multibuffer, cx| {
6931            excerpt_1_id = multibuffer.push_excerpts(
6932                buffer_1.clone(),
6933                [ExcerptRange {
6934                    context: 0..buffer_1.read(cx).len(),
6935                    primary: None,
6936                }],
6937                cx,
6938            )[0];
6939            excerpt_2_id = multibuffer.push_excerpts(
6940                buffer_2.clone(),
6941                [ExcerptRange {
6942                    context: 0..buffer_2.read(cx).len(),
6943                    primary: None,
6944                }],
6945                cx,
6946            )[0];
6947        });
6948
6949        let snapshot = multibuffer.read(cx).snapshot(cx);
6950
6951        let ranges = vec![
6952            1..(buffer_len / 4),
6953            (buffer_len / 3)..(buffer_len / 2),
6954            (buffer_len / 4 * 3)..(buffer_len),
6955        ];
6956
6957        let expected_excerpts = ranges
6958            .iter()
6959            .map(|range| {
6960                make_expected_excerpt_info(&snapshot, cx, excerpt_1_id, &buffer_1, range.clone())
6961            })
6962            .collect_vec();
6963
6964        let ranges = ranges.into_iter().map(|range| {
6965            map_range_from_excerpt(
6966                &snapshot,
6967                excerpt_1_id,
6968                &buffer_1.read(cx).snapshot(),
6969                range,
6970            )
6971        });
6972
6973        let excerpts = snapshot
6974            .excerpts_in_ranges(ranges)
6975            .map(|(excerpt_id, buffer, actual_range)| {
6976                (
6977                    excerpt_id,
6978                    buffer.remote_id(),
6979                    map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range),
6980                )
6981            })
6982            .collect_vec();
6983
6984        validate_excerpts(&excerpts, &expected_excerpts);
6985    }
6986
6987    #[gpui::test]
6988    fn test_excerpts_in_ranges_range_ends_at_excerpt_end(cx: &mut AppContext) {
6989        let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
6990        let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx));
6991        let buffer_len = buffer_1.read(cx).len();
6992        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
6993        let mut excerpt_1_id = ExcerptId(0);
6994        let mut excerpt_2_id = ExcerptId(0);
6995
6996        multibuffer.update(cx, |multibuffer, cx| {
6997            excerpt_1_id = multibuffer.push_excerpts(
6998                buffer_1.clone(),
6999                [ExcerptRange {
7000                    context: 0..buffer_1.read(cx).len(),
7001                    primary: None,
7002                }],
7003                cx,
7004            )[0];
7005            excerpt_2_id = multibuffer.push_excerpts(
7006                buffer_2.clone(),
7007                [ExcerptRange {
7008                    context: 0..buffer_2.read(cx).len(),
7009                    primary: None,
7010                }],
7011                cx,
7012            )[0];
7013        });
7014
7015        let snapshot = multibuffer.read(cx).snapshot(cx);
7016
7017        let ranges = [0..buffer_len, (buffer_len / 3)..(buffer_len / 2)];
7018
7019        let expected_excerpts = vec![
7020            make_expected_excerpt_info(&snapshot, cx, excerpt_1_id, &buffer_1, ranges[0].clone()),
7021            make_expected_excerpt_info(&snapshot, cx, excerpt_2_id, &buffer_2, ranges[1].clone()),
7022        ];
7023
7024        let ranges = [
7025            map_range_from_excerpt(
7026                &snapshot,
7027                excerpt_1_id,
7028                &buffer_1.read(cx).snapshot(),
7029                ranges[0].clone(),
7030            ),
7031            map_range_from_excerpt(
7032                &snapshot,
7033                excerpt_2_id,
7034                &buffer_2.read(cx).snapshot(),
7035                ranges[1].clone(),
7036            ),
7037        ];
7038
7039        let excerpts = snapshot
7040            .excerpts_in_ranges(ranges.into_iter())
7041            .map(|(excerpt_id, buffer, actual_range)| {
7042                (
7043                    excerpt_id,
7044                    buffer.remote_id(),
7045                    map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range),
7046                )
7047            })
7048            .collect_vec();
7049
7050        validate_excerpts(&excerpts, &expected_excerpts);
7051    }
7052
7053    #[gpui::test]
7054    fn test_split_ranges(cx: &mut AppContext) {
7055        let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
7056        let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx));
7057        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
7058        multibuffer.update(cx, |multibuffer, cx| {
7059            multibuffer.push_excerpts(
7060                buffer_1.clone(),
7061                [ExcerptRange {
7062                    context: 0..buffer_1.read(cx).len(),
7063                    primary: None,
7064                }],
7065                cx,
7066            );
7067            multibuffer.push_excerpts(
7068                buffer_2.clone(),
7069                [ExcerptRange {
7070                    context: 0..buffer_2.read(cx).len(),
7071                    primary: None,
7072                }],
7073                cx,
7074            );
7075        });
7076
7077        let snapshot = multibuffer.read(cx).snapshot(cx);
7078
7079        let buffer_1_len = buffer_1.read(cx).len();
7080        let buffer_2_len = buffer_2.read(cx).len();
7081        let buffer_1_midpoint = buffer_1_len / 2;
7082        let buffer_2_start = buffer_1_len + '\n'.len_utf8();
7083        let buffer_2_midpoint = buffer_2_start + buffer_2_len / 2;
7084        let total_len = buffer_2_start + buffer_2_len;
7085
7086        let input_ranges = [
7087            0..buffer_1_midpoint,
7088            buffer_1_midpoint..buffer_2_midpoint,
7089            buffer_2_midpoint..total_len,
7090        ]
7091        .map(|range| snapshot.anchor_before(range.start)..snapshot.anchor_after(range.end));
7092
7093        let actual_ranges = snapshot
7094            .split_ranges(input_ranges.into_iter())
7095            .map(|range| range.to_offset(&snapshot))
7096            .collect::<Vec<_>>();
7097
7098        let expected_ranges = vec![
7099            0..buffer_1_midpoint,
7100            buffer_1_midpoint..buffer_1_len,
7101            buffer_2_start..buffer_2_midpoint,
7102            buffer_2_midpoint..total_len,
7103        ];
7104
7105        assert_eq!(actual_ranges, expected_ranges);
7106    }
7107
7108    #[gpui::test]
7109    fn test_split_ranges_single_range_spanning_three_excerpts(cx: &mut AppContext) {
7110        let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
7111        let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx));
7112        let buffer_3 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'm'), cx));
7113        let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
7114        multibuffer.update(cx, |multibuffer, cx| {
7115            multibuffer.push_excerpts(
7116                buffer_1.clone(),
7117                [ExcerptRange {
7118                    context: 0..buffer_1.read(cx).len(),
7119                    primary: None,
7120                }],
7121                cx,
7122            );
7123            multibuffer.push_excerpts(
7124                buffer_2.clone(),
7125                [ExcerptRange {
7126                    context: 0..buffer_2.read(cx).len(),
7127                    primary: None,
7128                }],
7129                cx,
7130            );
7131            multibuffer.push_excerpts(
7132                buffer_3.clone(),
7133                [ExcerptRange {
7134                    context: 0..buffer_3.read(cx).len(),
7135                    primary: None,
7136                }],
7137                cx,
7138            );
7139        });
7140
7141        let snapshot = multibuffer.read(cx).snapshot(cx);
7142
7143        let buffer_1_len = buffer_1.read(cx).len();
7144        let buffer_2_len = buffer_2.read(cx).len();
7145        let buffer_3_len = buffer_3.read(cx).len();
7146        let buffer_2_start = buffer_1_len + '\n'.len_utf8();
7147        let buffer_3_start = buffer_2_start + buffer_2_len + '\n'.len_utf8();
7148        let buffer_1_midpoint = buffer_1_len / 2;
7149        let buffer_3_midpoint = buffer_3_start + buffer_3_len / 2;
7150
7151        let input_range =
7152            snapshot.anchor_before(buffer_1_midpoint)..snapshot.anchor_after(buffer_3_midpoint);
7153
7154        let actual_ranges = snapshot
7155            .split_ranges(std::iter::once(input_range))
7156            .map(|range| range.to_offset(&snapshot))
7157            .collect::<Vec<_>>();
7158
7159        let expected_ranges = vec![
7160            buffer_1_midpoint..buffer_1_len,
7161            buffer_2_start..buffer_2_start + buffer_2_len,
7162            buffer_3_start..buffer_3_midpoint,
7163        ];
7164
7165        assert_eq!(actual_ranges, expected_ranges);
7166    }
7167}