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