multi_buffer.rs

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