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