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