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