multi_buffer.rs

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