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