multi_buffer.rs

   1mod anchor;
   2
   3pub use anchor::{Anchor, AnchorRangeExt};
   4use anyhow::Result;
   5use clock::ReplicaId;
   6use collections::{HashMap, HashSet};
   7use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
   8use language::{
   9    Buffer, BufferChunks, BufferSnapshot, Chunk, DiagnosticEntry, Event, File, Language, Outline,
  10    OutlineItem, Selection, ToOffset as _, ToPoint as _, TransactionId,
  11};
  12use std::{
  13    cell::{Ref, RefCell},
  14    cmp, fmt, io,
  15    iter::{self, FromIterator},
  16    ops::{Range, Sub},
  17    str,
  18    sync::Arc,
  19    time::{Duration, Instant},
  20};
  21use sum_tree::{Bias, Cursor, SumTree};
  22use text::{
  23    locator::Locator,
  24    rope::TextDimension,
  25    subscription::{Subscription, Topic},
  26    AnchorRangeExt as _, Edit, Point, PointUtf16, TextSummary,
  27};
  28use theme::SyntaxTheme;
  29use util::post_inc;
  30
  31const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize];
  32
  33pub type ExcerptId = Locator;
  34
  35pub struct MultiBuffer {
  36    snapshot: RefCell<MultiBufferSnapshot>,
  37    buffers: RefCell<HashMap<usize, BufferState>>,
  38    subscriptions: Topic,
  39    singleton: bool,
  40    replica_id: ReplicaId,
  41    history: History,
  42}
  43
  44struct History {
  45    next_transaction_id: usize,
  46    undo_stack: Vec<Transaction>,
  47    redo_stack: Vec<Transaction>,
  48    transaction_depth: usize,
  49    group_interval: Duration,
  50}
  51
  52struct Transaction {
  53    id: usize,
  54    buffer_transactions: HashSet<(usize, text::TransactionId)>,
  55    first_edit_at: Instant,
  56    last_edit_at: Instant,
  57}
  58
  59pub trait ToOffset: 'static + fmt::Debug {
  60    fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
  61}
  62
  63pub trait ToPoint: 'static + fmt::Debug {
  64    fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point;
  65}
  66
  67struct BufferState {
  68    buffer: ModelHandle<Buffer>,
  69    last_version: clock::Global,
  70    last_parse_count: usize,
  71    last_selections_update_count: usize,
  72    last_diagnostics_update_count: usize,
  73    excerpts: Vec<ExcerptId>,
  74    _subscriptions: [gpui::Subscription; 2],
  75}
  76
  77#[derive(Clone, Default)]
  78pub struct MultiBufferSnapshot {
  79    excerpts: SumTree<Excerpt>,
  80    parse_count: usize,
  81    diagnostics_update_count: usize,
  82    is_dirty: bool,
  83    has_conflict: bool,
  84}
  85
  86pub struct ExcerptProperties<'a, T> {
  87    pub buffer: &'a ModelHandle<Buffer>,
  88    pub range: Range<T>,
  89}
  90
  91#[derive(Clone)]
  92struct Excerpt {
  93    id: ExcerptId,
  94    buffer_id: usize,
  95    buffer: BufferSnapshot,
  96    range: Range<text::Anchor>,
  97    max_buffer_row: u32,
  98    text_summary: TextSummary,
  99    has_trailing_newline: bool,
 100}
 101
 102#[derive(Clone, Debug, Default)]
 103struct ExcerptSummary {
 104    excerpt_id: ExcerptId,
 105    max_buffer_row: u32,
 106    text: TextSummary,
 107}
 108
 109pub struct MultiBufferRows<'a> {
 110    buffer_row_range: Range<u32>,
 111    excerpts: Cursor<'a, Excerpt, Point>,
 112}
 113
 114pub struct MultiBufferChunks<'a> {
 115    range: Range<usize>,
 116    excerpts: Cursor<'a, Excerpt, usize>,
 117    excerpt_chunks: Option<ExcerptChunks<'a>>,
 118    theme: Option<&'a SyntaxTheme>,
 119}
 120
 121pub struct MultiBufferBytes<'a> {
 122    range: Range<usize>,
 123    excerpts: Cursor<'a, Excerpt, usize>,
 124    excerpt_bytes: Option<ExcerptBytes<'a>>,
 125    chunk: &'a [u8],
 126}
 127
 128struct ExcerptChunks<'a> {
 129    content_chunks: BufferChunks<'a>,
 130    footer_height: usize,
 131}
 132
 133struct ExcerptBytes<'a> {
 134    content_bytes: language::rope::Bytes<'a>,
 135    footer_height: usize,
 136}
 137
 138impl MultiBuffer {
 139    pub fn new(replica_id: ReplicaId) -> Self {
 140        Self {
 141            snapshot: Default::default(),
 142            buffers: Default::default(),
 143            subscriptions: Default::default(),
 144            singleton: false,
 145            replica_id,
 146            history: History {
 147                next_transaction_id: Default::default(),
 148                undo_stack: Default::default(),
 149                redo_stack: Default::default(),
 150                transaction_depth: 0,
 151                group_interval: Duration::from_millis(300),
 152            },
 153        }
 154    }
 155
 156    pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
 157        let mut this = Self::new(buffer.read(cx).replica_id());
 158        this.singleton = true;
 159        this.push_excerpt(
 160            ExcerptProperties {
 161                buffer: &buffer,
 162                range: text::Anchor::min()..text::Anchor::max(),
 163            },
 164            cx,
 165        );
 166        this
 167    }
 168
 169    #[cfg(any(test, feature = "test-support"))]
 170    pub fn build_simple(text: &str, cx: &mut gpui::MutableAppContext) -> ModelHandle<Self> {
 171        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
 172        cx.add_model(|cx| Self::singleton(buffer, cx))
 173    }
 174
 175    #[cfg(any(test, feature = "test-support"))]
 176    pub fn build_random(
 177        mut rng: &mut impl rand::Rng,
 178        cx: &mut gpui::MutableAppContext,
 179    ) -> ModelHandle<Self> {
 180        use rand::prelude::*;
 181        use std::env;
 182        use text::RandomCharIter;
 183
 184        let max_excerpts = env::var("MAX_EXCERPTS")
 185            .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))
 186            .unwrap_or(5);
 187        let excerpts = rng.gen_range(1..=max_excerpts);
 188
 189        cx.add_model(|cx| {
 190            let mut multibuffer = MultiBuffer::new(0);
 191            let mut buffers = Vec::new();
 192            for _ in 0..excerpts {
 193                let buffer_handle = if rng.gen() || buffers.is_empty() {
 194                    let text = RandomCharIter::new(&mut rng).take(10).collect::<String>();
 195                    buffers.push(cx.add_model(|cx| Buffer::new(0, text, cx)));
 196                    let buffer = buffers.last().unwrap();
 197                    log::info!(
 198                        "Creating new buffer {} with text: {:?}",
 199                        buffer.id(),
 200                        buffer.read(cx).text()
 201                    );
 202                    buffers.last().unwrap()
 203                } else {
 204                    buffers.choose(rng).unwrap()
 205                };
 206
 207                let buffer = buffer_handle.read(cx);
 208                let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
 209                let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
 210                let header_height = rng.gen_range(0..=5);
 211                log::info!(
 212                    "Inserting excerpt from buffer {} with header height {} and range {:?}: {:?}",
 213                    buffer_handle.id(),
 214                    header_height,
 215                    start_ix..end_ix,
 216                    &buffer.text()[start_ix..end_ix]
 217                );
 218
 219                multibuffer.push_excerpt(
 220                    ExcerptProperties {
 221                        buffer: buffer_handle,
 222                        range: start_ix..end_ix,
 223                    },
 224                    cx,
 225                );
 226            }
 227            multibuffer
 228        })
 229    }
 230
 231    pub fn replica_id(&self) -> ReplicaId {
 232        self.replica_id
 233    }
 234
 235    pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot {
 236        self.sync(cx);
 237        self.snapshot.borrow().clone()
 238    }
 239
 240    pub fn read(&self, cx: &AppContext) -> Ref<MultiBufferSnapshot> {
 241        self.sync(cx);
 242        self.snapshot.borrow()
 243    }
 244
 245    pub fn as_singleton(&self) -> Option<ModelHandle<Buffer>> {
 246        if self.singleton {
 247            return Some(
 248                self.buffers
 249                    .borrow()
 250                    .values()
 251                    .next()
 252                    .unwrap()
 253                    .buffer
 254                    .clone(),
 255            );
 256        } else {
 257            None
 258        }
 259    }
 260
 261    pub fn subscribe(&mut self) -> Subscription {
 262        self.subscriptions.subscribe()
 263    }
 264
 265    pub fn edit<I, S, T>(&mut self, ranges: I, new_text: T, cx: &mut ModelContext<Self>)
 266    where
 267        I: IntoIterator<Item = Range<S>>,
 268        S: ToOffset,
 269        T: Into<String>,
 270    {
 271        self.edit_internal(ranges, new_text, false, cx)
 272    }
 273
 274    pub fn edit_with_autoindent<I, S, T>(
 275        &mut self,
 276        ranges: I,
 277        new_text: T,
 278        cx: &mut ModelContext<Self>,
 279    ) where
 280        I: IntoIterator<Item = Range<S>>,
 281        S: ToOffset,
 282        T: Into<String>,
 283    {
 284        self.edit_internal(ranges, new_text, true, cx)
 285    }
 286
 287    pub fn edit_internal<I, S, T>(
 288        &mut self,
 289        ranges_iter: I,
 290        new_text: T,
 291        autoindent: bool,
 292        cx: &mut ModelContext<Self>,
 293    ) where
 294        I: IntoIterator<Item = Range<S>>,
 295        S: ToOffset,
 296        T: Into<String>,
 297    {
 298        if let Some(buffer) = self.as_singleton() {
 299            let snapshot = self.read(cx);
 300            let ranges = ranges_iter
 301                .into_iter()
 302                .map(|range| range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot));
 303            return buffer.update(cx, |buffer, cx| {
 304                if autoindent {
 305                    buffer.edit_with_autoindent(ranges, new_text, cx)
 306                } else {
 307                    buffer.edit(ranges, new_text, cx)
 308                }
 309            });
 310        }
 311
 312        let snapshot = self.read(cx);
 313        let mut buffer_edits: HashMap<usize, Vec<(Range<usize>, bool)>> = Default::default();
 314        let mut cursor = snapshot.excerpts.cursor::<usize>();
 315        for range in ranges_iter {
 316            let start = range.start.to_offset(&snapshot);
 317            let end = range.end.to_offset(&snapshot);
 318            cursor.seek(&start, Bias::Right, &());
 319            if cursor.item().is_none() && start == *cursor.start() {
 320                cursor.prev(&());
 321            }
 322            let start_excerpt = cursor.item().expect("start offset out of bounds");
 323            let start_overshoot = start - cursor.start();
 324            let buffer_start =
 325                start_excerpt.range.start.to_offset(&start_excerpt.buffer) + start_overshoot;
 326
 327            cursor.seek(&end, Bias::Right, &());
 328            if cursor.item().is_none() && end == *cursor.start() {
 329                cursor.prev(&());
 330            }
 331            let end_excerpt = cursor.item().expect("end offset out of bounds");
 332            let end_overshoot = end - cursor.start();
 333            let buffer_end = end_excerpt.range.start.to_offset(&end_excerpt.buffer) + end_overshoot;
 334
 335            if start_excerpt.id == end_excerpt.id {
 336                buffer_edits
 337                    .entry(start_excerpt.buffer_id)
 338                    .or_insert(Vec::new())
 339                    .push((buffer_start..buffer_end, true));
 340            } else {
 341                let start_excerpt_range =
 342                    buffer_start..start_excerpt.range.end.to_offset(&start_excerpt.buffer);
 343                let end_excerpt_range =
 344                    end_excerpt.range.start.to_offset(&end_excerpt.buffer)..buffer_end;
 345                buffer_edits
 346                    .entry(start_excerpt.buffer_id)
 347                    .or_insert(Vec::new())
 348                    .push((start_excerpt_range, true));
 349                buffer_edits
 350                    .entry(end_excerpt.buffer_id)
 351                    .or_insert(Vec::new())
 352                    .push((end_excerpt_range, false));
 353
 354                cursor.seek(&start, Bias::Right, &());
 355                cursor.next(&());
 356                while let Some(excerpt) = cursor.item() {
 357                    if excerpt.id == end_excerpt.id {
 358                        break;
 359                    }
 360                    buffer_edits
 361                        .entry(excerpt.buffer_id)
 362                        .or_insert(Vec::new())
 363                        .push((excerpt.range.to_offset(&excerpt.buffer), false));
 364                    cursor.next(&());
 365                }
 366            }
 367        }
 368
 369        let new_text = new_text.into();
 370        for (buffer_id, mut edits) in buffer_edits {
 371            edits.sort_unstable_by_key(|(range, _)| range.start);
 372            self.buffers.borrow()[&buffer_id]
 373                .buffer
 374                .update(cx, |buffer, cx| {
 375                    let mut edits = edits.into_iter().peekable();
 376                    let mut insertions = Vec::new();
 377                    let mut deletions = Vec::new();
 378                    while let Some((mut range, mut is_insertion)) = edits.next() {
 379                        while let Some((next_range, next_is_insertion)) = edits.peek() {
 380                            if range.end >= next_range.start {
 381                                range.end = cmp::max(next_range.end, range.end);
 382                                is_insertion |= *next_is_insertion;
 383                                edits.next();
 384                            } else {
 385                                break;
 386                            }
 387                        }
 388
 389                        if is_insertion {
 390                            insertions.push(
 391                                buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
 392                            );
 393                        } else if !range.is_empty() {
 394                            deletions.push(
 395                                buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
 396                            );
 397                        }
 398                    }
 399
 400                    if autoindent {
 401                        buffer.edit_with_autoindent(deletions, "", cx);
 402                        buffer.edit_with_autoindent(insertions, new_text.clone(), cx);
 403                    } else {
 404                        buffer.edit(deletions, "", cx);
 405                        buffer.edit(insertions, new_text.clone(), cx);
 406                    }
 407                })
 408        }
 409    }
 410
 411    pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 412        self.start_transaction_at(Instant::now(), cx)
 413    }
 414
 415    pub(crate) fn start_transaction_at(
 416        &mut self,
 417        now: Instant,
 418        cx: &mut ModelContext<Self>,
 419    ) -> Option<TransactionId> {
 420        if let Some(buffer) = self.as_singleton() {
 421            return buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
 422        }
 423
 424        for BufferState { buffer, .. } in self.buffers.borrow().values() {
 425            buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
 426        }
 427        self.history.start_transaction(now)
 428    }
 429
 430    pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 431        self.end_transaction_at(Instant::now(), cx)
 432    }
 433
 434    pub(crate) fn end_transaction_at(
 435        &mut self,
 436        now: Instant,
 437        cx: &mut ModelContext<Self>,
 438    ) -> Option<TransactionId> {
 439        if let Some(buffer) = self.as_singleton() {
 440            return buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx));
 441        }
 442
 443        let mut buffer_transactions = HashSet::default();
 444        for BufferState { buffer, .. } in self.buffers.borrow().values() {
 445            if let Some(transaction_id) =
 446                buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
 447            {
 448                buffer_transactions.insert((buffer.id(), transaction_id));
 449            }
 450        }
 451
 452        if self.history.end_transaction(now, buffer_transactions) {
 453            let transaction_id = self.history.group().unwrap();
 454            Some(transaction_id)
 455        } else {
 456            None
 457        }
 458    }
 459
 460    pub fn avoid_grouping_next_transaction(&mut self, cx: &mut ModelContext<Self>) {
 461        for BufferState { buffer, .. } in self.buffers.borrow().values() {
 462            buffer.update(cx, |buffer, _| buffer.avoid_grouping_next_transaction());
 463        }
 464    }
 465
 466    pub fn set_active_selections(
 467        &mut self,
 468        selections: &[Selection<Anchor>],
 469        cx: &mut ModelContext<Self>,
 470    ) {
 471        let mut selections_by_buffer: HashMap<usize, Vec<Selection<text::Anchor>>> =
 472            Default::default();
 473        let snapshot = self.read(cx);
 474        let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();
 475        for selection in selections {
 476            cursor.seek(&Some(&selection.start.excerpt_id), Bias::Left, &());
 477            while let Some(excerpt) = cursor.item() {
 478                if excerpt.id > selection.end.excerpt_id {
 479                    break;
 480                }
 481
 482                let mut start = excerpt.range.start.clone();
 483                let mut end = excerpt.range.end.clone();
 484                if excerpt.id == selection.start.excerpt_id {
 485                    start = selection.start.text_anchor.clone();
 486                }
 487                if excerpt.id == selection.end.excerpt_id {
 488                    end = selection.end.text_anchor.clone();
 489                }
 490                selections_by_buffer
 491                    .entry(excerpt.buffer_id)
 492                    .or_default()
 493                    .push(Selection {
 494                        id: selection.id,
 495                        start,
 496                        end,
 497                        reversed: selection.reversed,
 498                        goal: selection.goal,
 499                    });
 500
 501                cursor.next(&());
 502            }
 503        }
 504
 505        for (buffer_id, buffer_state) in self.buffers.borrow().iter() {
 506            if !selections_by_buffer.contains_key(buffer_id) {
 507                buffer_state
 508                    .buffer
 509                    .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
 510            }
 511        }
 512
 513        for (buffer_id, mut selections) in selections_by_buffer {
 514            self.buffers.borrow()[&buffer_id]
 515                .buffer
 516                .update(cx, |buffer, cx| {
 517                    selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap());
 518                    let mut selections = selections.into_iter().peekable();
 519                    let merged_selections = Arc::from_iter(iter::from_fn(|| {
 520                        let mut selection = selections.next()?;
 521                        while let Some(next_selection) = selections.peek() {
 522                            if selection
 523                                .end
 524                                .cmp(&next_selection.start, buffer)
 525                                .unwrap()
 526                                .is_ge()
 527                            {
 528                                let next_selection = selections.next().unwrap();
 529                                if next_selection
 530                                    .end
 531                                    .cmp(&selection.end, buffer)
 532                                    .unwrap()
 533                                    .is_ge()
 534                                {
 535                                    selection.end = next_selection.end;
 536                                }
 537                            } else {
 538                                break;
 539                            }
 540                        }
 541                        Some(selection)
 542                    }));
 543                    buffer.set_active_selections(merged_selections, cx);
 544                });
 545        }
 546    }
 547
 548    pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
 549        for buffer in self.buffers.borrow().values() {
 550            buffer
 551                .buffer
 552                .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
 553        }
 554    }
 555
 556    pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 557        if let Some(buffer) = self.as_singleton() {
 558            return buffer.update(cx, |buffer, cx| buffer.undo(cx));
 559        }
 560
 561        while let Some(transaction) = self.history.pop_undo() {
 562            let mut undone = false;
 563            for (buffer_id, buffer_transaction_id) in &transaction.buffer_transactions {
 564                if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(&buffer_id) {
 565                    undone |= buffer.update(cx, |buf, cx| {
 566                        buf.undo_transaction(*buffer_transaction_id, cx)
 567                    });
 568                }
 569            }
 570
 571            if undone {
 572                return Some(transaction.id);
 573            }
 574        }
 575
 576        None
 577    }
 578
 579    pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 580        if let Some(buffer) = self.as_singleton() {
 581            return buffer.update(cx, |buffer, cx| buffer.redo(cx));
 582        }
 583
 584        while let Some(transaction) = self.history.pop_redo() {
 585            let mut redone = false;
 586            for (buffer_id, buffer_transaction_id) in &transaction.buffer_transactions {
 587                if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(&buffer_id) {
 588                    redone |= buffer.update(cx, |buf, cx| {
 589                        buf.redo_transaction(*buffer_transaction_id, cx)
 590                    });
 591                }
 592            }
 593
 594            if redone {
 595                return Some(transaction.id);
 596            }
 597        }
 598
 599        None
 600    }
 601
 602    pub fn push_excerpt<O>(
 603        &mut self,
 604        props: ExcerptProperties<O>,
 605        cx: &mut ModelContext<Self>,
 606    ) -> ExcerptId
 607    where
 608        O: text::ToOffset,
 609    {
 610        self.insert_excerpt_after(&ExcerptId::max(), props, cx)
 611    }
 612
 613    pub fn insert_excerpt_after<O>(
 614        &mut self,
 615        prev_excerpt_id: &ExcerptId,
 616        props: ExcerptProperties<O>,
 617        cx: &mut ModelContext<Self>,
 618    ) -> ExcerptId
 619    where
 620        O: text::ToOffset,
 621    {
 622        assert_eq!(self.history.transaction_depth, 0);
 623        self.sync(cx);
 624
 625        let buffer_snapshot = props.buffer.read(cx).snapshot();
 626        let range = buffer_snapshot.anchor_before(&props.range.start)
 627            ..buffer_snapshot.anchor_after(&props.range.end);
 628        let mut snapshot = self.snapshot.borrow_mut();
 629        let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();
 630        let mut new_excerpts = cursor.slice(&Some(prev_excerpt_id), Bias::Right, &());
 631
 632        let mut prev_id = ExcerptId::min();
 633        let edit_start = new_excerpts.summary().text.bytes;
 634        new_excerpts.update_last(
 635            |excerpt| {
 636                excerpt.has_trailing_newline = true;
 637                prev_id = excerpt.id.clone();
 638            },
 639            &(),
 640        );
 641
 642        let mut next_id = ExcerptId::max();
 643        if let Some(next_excerpt) = cursor.item() {
 644            next_id = next_excerpt.id.clone();
 645        }
 646
 647        let id = ExcerptId::between(&prev_id, &next_id);
 648
 649        let mut buffers = self.buffers.borrow_mut();
 650        let buffer_state = buffers
 651            .entry(props.buffer.id())
 652            .or_insert_with(|| BufferState {
 653                last_version: buffer_snapshot.version().clone(),
 654                last_parse_count: buffer_snapshot.parse_count(),
 655                last_selections_update_count: buffer_snapshot.selections_update_count(),
 656                last_diagnostics_update_count: buffer_snapshot.diagnostics_update_count(),
 657                excerpts: Default::default(),
 658                _subscriptions: [
 659                    cx.observe(&props.buffer, |_, _, cx| cx.notify()),
 660                    cx.subscribe(&props.buffer, Self::on_buffer_event),
 661                ],
 662                buffer: props.buffer.clone(),
 663            });
 664        if let Err(ix) = buffer_state.excerpts.binary_search(&id) {
 665            buffer_state.excerpts.insert(ix, id.clone());
 666        }
 667
 668        let excerpt = Excerpt::new(
 669            id.clone(),
 670            props.buffer.id(),
 671            buffer_snapshot,
 672            range,
 673            cursor.item().is_some(),
 674        );
 675        new_excerpts.push(excerpt, &());
 676        let edit_end = new_excerpts.summary().text.bytes;
 677
 678        new_excerpts.push_tree(cursor.suffix(&()), &());
 679        drop(cursor);
 680        snapshot.excerpts = new_excerpts;
 681
 682        self.subscriptions.publish_mut([Edit {
 683            old: edit_start..edit_start,
 684            new: edit_start..edit_end,
 685        }]);
 686
 687        cx.notify();
 688        id
 689    }
 690
 691    pub fn excerpt_ids_for_buffer(&self, buffer: &ModelHandle<Buffer>) -> Vec<ExcerptId> {
 692        self.buffers
 693            .borrow()
 694            .get(&buffer.id())
 695            .map_or(Vec::new(), |state| state.excerpts.clone())
 696    }
 697
 698    pub fn excerpted_buffers<'a, T: ToOffset>(
 699        &'a self,
 700        range: Range<T>,
 701        cx: &AppContext,
 702    ) -> Vec<(ModelHandle<Buffer>, Range<usize>)> {
 703        let snapshot = self.snapshot(cx);
 704        let start = range.start.to_offset(&snapshot);
 705        let end = range.end.to_offset(&snapshot);
 706
 707        let mut result = Vec::new();
 708        let mut cursor = snapshot.excerpts.cursor::<usize>();
 709        cursor.seek(&start, Bias::Right, &());
 710        while let Some(excerpt) = cursor.item() {
 711            if *cursor.start() > end {
 712                break;
 713            }
 714
 715            let mut end_before_newline = cursor.end(&());
 716            if excerpt.has_trailing_newline {
 717                end_before_newline -= 1;
 718            }
 719            let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
 720            let start = excerpt_start + (cmp::max(start, *cursor.start()) - *cursor.start());
 721            let end = excerpt_start + (cmp::min(end, end_before_newline) - *cursor.start());
 722            let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone();
 723            result.push((buffer, start..end));
 724            cursor.next(&());
 725        }
 726
 727        result
 728    }
 729
 730    pub fn remove_excerpts<'a>(
 731        &mut self,
 732        excerpt_ids: impl IntoIterator<Item = &'a ExcerptId>,
 733        cx: &mut ModelContext<Self>,
 734    ) {
 735        let mut buffers = self.buffers.borrow_mut();
 736        let mut snapshot = self.snapshot.borrow_mut();
 737        let mut new_excerpts = SumTree::new();
 738        let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>();
 739        let mut edits = Vec::new();
 740        let mut excerpt_ids = excerpt_ids.into_iter().peekable();
 741
 742        while let Some(mut excerpt_id) = excerpt_ids.next() {
 743            // Seek to the next excerpt to remove, preserving any preceding excerpts.
 744            new_excerpts.push_tree(cursor.slice(&Some(excerpt_id), Bias::Left, &()), &());
 745            if let Some(mut excerpt) = cursor.item() {
 746                if excerpt.id != *excerpt_id {
 747                    continue;
 748                }
 749                let mut old_start = cursor.start().1;
 750
 751                // Skip over the removed excerpt.
 752                loop {
 753                    if let Some(buffer_state) = buffers.get_mut(&excerpt.buffer_id) {
 754                        buffer_state.excerpts.retain(|id| id != excerpt_id);
 755                        if buffer_state.excerpts.is_empty() {
 756                            buffers.remove(&excerpt.buffer_id);
 757                        }
 758                    }
 759                    cursor.next(&());
 760
 761                    // Skip over any subsequent excerpts that are also removed.
 762                    if let Some(&next_excerpt_id) = excerpt_ids.peek() {
 763                        if let Some(next_excerpt) = cursor.item() {
 764                            if next_excerpt.id == *next_excerpt_id {
 765                                excerpt = next_excerpt;
 766                                excerpt_id = excerpt_ids.next().unwrap();
 767                                continue;
 768                            }
 769                        }
 770                    }
 771
 772                    break;
 773                }
 774
 775                // When removing the last excerpt, remove the trailing newline from
 776                // the previous excerpt.
 777                if cursor.item().is_none() && old_start > 0 {
 778                    old_start -= 1;
 779                    new_excerpts.update_last(|e| e.has_trailing_newline = false, &());
 780                }
 781
 782                // Push an edit for the removal of this run of excerpts.
 783                let old_end = cursor.start().1;
 784                let new_start = new_excerpts.summary().text.bytes;
 785                edits.push(Edit {
 786                    old: old_start..old_end,
 787                    new: new_start..new_start,
 788                });
 789            }
 790        }
 791        new_excerpts.push_tree(cursor.suffix(&()), &());
 792        drop(cursor);
 793        snapshot.excerpts = new_excerpts;
 794        self.subscriptions.publish_mut(edits);
 795        cx.notify();
 796    }
 797
 798    pub fn text_anchor_for_position<'a, T: ToOffset>(
 799        &'a self,
 800        position: T,
 801        cx: &AppContext,
 802    ) -> (ModelHandle<Buffer>, language::Anchor) {
 803        let snapshot = self.read(cx);
 804        let anchor = snapshot.anchor_before(position);
 805        (
 806            self.buffers.borrow()[&anchor.buffer_id].buffer.clone(),
 807            anchor.text_anchor,
 808        )
 809    }
 810
 811    fn on_buffer_event(
 812        &mut self,
 813        _: ModelHandle<Buffer>,
 814        event: &Event,
 815        cx: &mut ModelContext<Self>,
 816    ) {
 817        cx.emit(event.clone());
 818    }
 819
 820    pub fn format(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
 821        let mut format_tasks = Vec::new();
 822        for BufferState { buffer, .. } in self.buffers.borrow().values() {
 823            format_tasks.push(buffer.update(cx, |buffer, cx| buffer.format(cx)));
 824        }
 825
 826        cx.spawn(|_, _| async move {
 827            for format in format_tasks {
 828                format.await?;
 829            }
 830            Ok(())
 831        })
 832    }
 833
 834    pub fn save(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
 835        let mut save_tasks = Vec::new();
 836        for BufferState { buffer, .. } in self.buffers.borrow().values() {
 837            save_tasks.push(buffer.update(cx, |buffer, cx| buffer.save(cx)));
 838        }
 839
 840        cx.spawn(|_, _| async move {
 841            for save in save_tasks {
 842                save.await?;
 843            }
 844            Ok(())
 845        })
 846    }
 847
 848    pub fn language<'a>(&self, cx: &'a AppContext) -> Option<&'a Arc<Language>> {
 849        self.buffers
 850            .borrow()
 851            .values()
 852            .next()
 853            .and_then(|state| state.buffer.read(cx).language())
 854    }
 855
 856    pub fn file<'a>(&self, cx: &'a AppContext) -> Option<&'a dyn File> {
 857        self.as_singleton()?.read(cx).file()
 858    }
 859
 860    #[cfg(test)]
 861    pub fn is_parsing(&self, cx: &AppContext) -> bool {
 862        self.as_singleton().unwrap().read(cx).is_parsing()
 863    }
 864
 865    fn sync(&self, cx: &AppContext) {
 866        let mut snapshot = self.snapshot.borrow_mut();
 867        let mut excerpts_to_edit = Vec::new();
 868        let mut reparsed = false;
 869        let mut diagnostics_updated = false;
 870        let mut is_dirty = false;
 871        let mut has_conflict = false;
 872        let mut buffers = self.buffers.borrow_mut();
 873        for buffer_state in buffers.values_mut() {
 874            let buffer = buffer_state.buffer.read(cx);
 875            let version = buffer.version();
 876            let parse_count = buffer.parse_count();
 877            let selections_update_count = buffer.selections_update_count();
 878            let diagnostics_update_count = buffer.diagnostics_update_count();
 879
 880            let buffer_edited = version.changed_since(&buffer_state.last_version);
 881            let buffer_reparsed = parse_count > buffer_state.last_parse_count;
 882            let buffer_selections_updated =
 883                selections_update_count > buffer_state.last_selections_update_count;
 884            let buffer_diagnostics_updated =
 885                diagnostics_update_count > buffer_state.last_diagnostics_update_count;
 886            if buffer_edited
 887                || buffer_reparsed
 888                || buffer_selections_updated
 889                || buffer_diagnostics_updated
 890            {
 891                buffer_state.last_version = version;
 892                buffer_state.last_parse_count = parse_count;
 893                buffer_state.last_selections_update_count = selections_update_count;
 894                buffer_state.last_diagnostics_update_count = diagnostics_update_count;
 895                excerpts_to_edit.extend(
 896                    buffer_state
 897                        .excerpts
 898                        .iter()
 899                        .map(|excerpt_id| (excerpt_id, buffer_state.buffer.clone(), buffer_edited)),
 900                );
 901            }
 902
 903            reparsed |= buffer_reparsed;
 904            diagnostics_updated |= buffer_diagnostics_updated;
 905            is_dirty |= buffer.is_dirty();
 906            has_conflict |= buffer.has_conflict();
 907        }
 908        if reparsed {
 909            snapshot.parse_count += 1;
 910        }
 911        if diagnostics_updated {
 912            snapshot.diagnostics_update_count += 1;
 913        }
 914        snapshot.is_dirty = is_dirty;
 915        snapshot.has_conflict = has_conflict;
 916
 917        excerpts_to_edit.sort_unstable_by_key(|(excerpt_id, _, _)| *excerpt_id);
 918
 919        let mut edits = Vec::new();
 920        let mut new_excerpts = SumTree::new();
 921        let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>();
 922
 923        for (id, buffer, buffer_edited) in excerpts_to_edit {
 924            new_excerpts.push_tree(cursor.slice(&Some(id), Bias::Left, &()), &());
 925            let old_excerpt = cursor.item().unwrap();
 926            let buffer_id = buffer.id();
 927            let buffer = buffer.read(cx);
 928
 929            let mut new_excerpt;
 930            if buffer_edited {
 931                edits.extend(
 932                    buffer
 933                        .edits_since_in_range::<usize>(
 934                            old_excerpt.buffer.version(),
 935                            old_excerpt.range.clone(),
 936                        )
 937                        .map(|mut edit| {
 938                            let excerpt_old_start = cursor.start().1;
 939                            let excerpt_new_start = new_excerpts.summary().text.bytes;
 940                            edit.old.start += excerpt_old_start;
 941                            edit.old.end += excerpt_old_start;
 942                            edit.new.start += excerpt_new_start;
 943                            edit.new.end += excerpt_new_start;
 944                            edit
 945                        }),
 946                );
 947
 948                new_excerpt = Excerpt::new(
 949                    id.clone(),
 950                    buffer_id,
 951                    buffer.snapshot(),
 952                    old_excerpt.range.clone(),
 953                    old_excerpt.has_trailing_newline,
 954                );
 955            } else {
 956                new_excerpt = old_excerpt.clone();
 957                new_excerpt.buffer = buffer.snapshot();
 958            }
 959
 960            new_excerpts.push(new_excerpt, &());
 961            cursor.next(&());
 962        }
 963        new_excerpts.push_tree(cursor.suffix(&()), &());
 964
 965        drop(cursor);
 966        snapshot.excerpts = new_excerpts;
 967
 968        self.subscriptions.publish(edits);
 969    }
 970}
 971
 972#[cfg(any(test, feature = "test-support"))]
 973impl MultiBuffer {
 974    pub fn randomly_edit(
 975        &mut self,
 976        rng: &mut impl rand::Rng,
 977        count: usize,
 978        cx: &mut ModelContext<Self>,
 979    ) {
 980        use text::RandomCharIter;
 981
 982        let snapshot = self.read(cx);
 983        let mut old_ranges: Vec<Range<usize>> = Vec::new();
 984        for _ in 0..count {
 985            let last_end = old_ranges.last().map_or(0, |last_range| last_range.end + 1);
 986            if last_end > snapshot.len() {
 987                break;
 988            }
 989            let end_ix = snapshot.clip_offset(rng.gen_range(0..=last_end), Bias::Right);
 990            let start_ix = snapshot.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
 991            old_ranges.push(start_ix..end_ix);
 992        }
 993        let new_text_len = rng.gen_range(0..10);
 994        let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
 995        log::info!("mutating multi-buffer at {:?}: {:?}", old_ranges, new_text);
 996        drop(snapshot);
 997
 998        self.edit(old_ranges.iter().cloned(), new_text.as_str(), cx);
 999    }
1000}
1001
1002impl Entity for MultiBuffer {
1003    type Event = language::Event;
1004}
1005
1006impl MultiBufferSnapshot {
1007    pub fn text(&self) -> String {
1008        self.chunks(0..self.len(), None)
1009            .map(|chunk| chunk.text)
1010            .collect()
1011    }
1012
1013    pub fn reversed_chars_at<'a, T: ToOffset>(
1014        &'a self,
1015        position: T,
1016    ) -> impl Iterator<Item = char> + 'a {
1017        let mut offset = position.to_offset(self);
1018        let mut cursor = self.excerpts.cursor::<usize>();
1019        cursor.seek(&offset, Bias::Left, &());
1020        let mut excerpt_chunks = cursor.item().map(|excerpt| {
1021            let end_before_footer = cursor.start() + excerpt.text_summary.bytes;
1022            let start = excerpt.range.start.to_offset(&excerpt.buffer);
1023            let end = start + (cmp::min(offset, end_before_footer) - cursor.start());
1024            excerpt.buffer.reversed_chunks_in_range(start..end)
1025        });
1026        iter::from_fn(move || {
1027            if offset == *cursor.start() {
1028                cursor.prev(&());
1029                let excerpt = cursor.item()?;
1030                excerpt_chunks = Some(
1031                    excerpt
1032                        .buffer
1033                        .reversed_chunks_in_range(excerpt.range.clone()),
1034                );
1035            }
1036
1037            let excerpt = cursor.item().unwrap();
1038            if offset == cursor.end(&()) && excerpt.has_trailing_newline {
1039                offset -= 1;
1040                Some("\n")
1041            } else {
1042                let chunk = excerpt_chunks.as_mut().unwrap().next().unwrap();
1043                offset -= chunk.len();
1044                Some(chunk)
1045            }
1046        })
1047        .flat_map(|c| c.chars().rev())
1048    }
1049
1050    pub fn chars_at<'a, T: ToOffset>(&'a self, position: T) -> impl Iterator<Item = char> + 'a {
1051        let offset = position.to_offset(self);
1052        self.text_for_range(offset..self.len())
1053            .flat_map(|chunk| chunk.chars())
1054    }
1055
1056    pub fn text_for_range<'a, T: ToOffset>(
1057        &'a self,
1058        range: Range<T>,
1059    ) -> impl Iterator<Item = &'a str> {
1060        self.chunks(range, None).map(|chunk| chunk.text)
1061    }
1062
1063    pub fn is_line_blank(&self, row: u32) -> bool {
1064        self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row)))
1065            .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
1066    }
1067
1068    pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
1069    where
1070        T: ToOffset,
1071    {
1072        let position = position.to_offset(self);
1073        position == self.clip_offset(position, Bias::Left)
1074            && self
1075                .bytes_in_range(position..self.len())
1076                .flatten()
1077                .copied()
1078                .take(needle.len())
1079                .eq(needle.bytes())
1080    }
1081
1082    fn as_singleton(&self) -> Option<&BufferSnapshot> {
1083        let mut excerpts = self.excerpts.iter();
1084        let buffer = excerpts.next().map(|excerpt| &excerpt.buffer);
1085        if excerpts.next().is_none() {
1086            buffer
1087        } else {
1088            None
1089        }
1090    }
1091
1092    pub fn len(&self) -> usize {
1093        self.excerpts.summary().text.bytes
1094    }
1095
1096    pub fn max_buffer_row(&self) -> u32 {
1097        self.excerpts.summary().max_buffer_row
1098    }
1099
1100    pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
1101        let mut cursor = self.excerpts.cursor::<usize>();
1102        cursor.seek(&offset, Bias::Right, &());
1103        let overshoot = if let Some(excerpt) = cursor.item() {
1104            let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1105            let buffer_offset = excerpt
1106                .buffer
1107                .clip_offset(excerpt_start + (offset - cursor.start()), bias);
1108            buffer_offset.saturating_sub(excerpt_start)
1109        } else {
1110            0
1111        };
1112        cursor.start() + overshoot
1113    }
1114
1115    pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
1116        let mut cursor = self.excerpts.cursor::<Point>();
1117        cursor.seek(&point, Bias::Right, &());
1118        let overshoot = if let Some(excerpt) = cursor.item() {
1119            let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
1120            let buffer_point = excerpt
1121                .buffer
1122                .clip_point(excerpt_start + (point - cursor.start()), bias);
1123            buffer_point.saturating_sub(excerpt_start)
1124        } else {
1125            Point::zero()
1126        };
1127        *cursor.start() + overshoot
1128    }
1129
1130    pub fn clip_point_utf16(&self, point: PointUtf16, bias: Bias) -> PointUtf16 {
1131        let mut cursor = self.excerpts.cursor::<PointUtf16>();
1132        cursor.seek(&point, Bias::Right, &());
1133        let overshoot = if let Some(excerpt) = cursor.item() {
1134            let excerpt_start = excerpt
1135                .buffer
1136                .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
1137            let buffer_point = excerpt
1138                .buffer
1139                .clip_point_utf16(excerpt_start + (point - cursor.start()), bias);
1140            buffer_point.saturating_sub(excerpt_start)
1141        } else {
1142            PointUtf16::zero()
1143        };
1144        *cursor.start() + overshoot
1145    }
1146
1147    pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> MultiBufferBytes<'a> {
1148        let range = range.start.to_offset(self)..range.end.to_offset(self);
1149        let mut excerpts = self.excerpts.cursor::<usize>();
1150        excerpts.seek(&range.start, Bias::Right, &());
1151
1152        let mut chunk = &[][..];
1153        let excerpt_bytes = if let Some(excerpt) = excerpts.item() {
1154            let mut excerpt_bytes = excerpt
1155                .bytes_in_range(range.start - excerpts.start()..range.end - excerpts.start());
1156            chunk = excerpt_bytes.next().unwrap_or(&[][..]);
1157            Some(excerpt_bytes)
1158        } else {
1159            None
1160        };
1161
1162        MultiBufferBytes {
1163            range,
1164            excerpts,
1165            excerpt_bytes,
1166            chunk,
1167        }
1168    }
1169
1170    pub fn buffer_rows<'a>(&'a self, start_row: u32) -> MultiBufferRows<'a> {
1171        let mut result = MultiBufferRows {
1172            buffer_row_range: 0..0,
1173            excerpts: self.excerpts.cursor(),
1174        };
1175        result.seek(start_row);
1176        result
1177    }
1178
1179    pub fn chunks<'a, T: ToOffset>(
1180        &'a self,
1181        range: Range<T>,
1182        theme: Option<&'a SyntaxTheme>,
1183    ) -> MultiBufferChunks<'a> {
1184        let range = range.start.to_offset(self)..range.end.to_offset(self);
1185        let mut chunks = MultiBufferChunks {
1186            range: range.clone(),
1187            excerpts: self.excerpts.cursor(),
1188            excerpt_chunks: None,
1189            theme,
1190        };
1191        chunks.seek(range.start);
1192        chunks
1193    }
1194
1195    pub fn offset_to_point(&self, offset: usize) -> Point {
1196        let mut cursor = self.excerpts.cursor::<(usize, Point)>();
1197        cursor.seek(&offset, Bias::Right, &());
1198        if let Some(excerpt) = cursor.item() {
1199            let (start_offset, start_point) = cursor.start();
1200            let overshoot = offset - start_offset;
1201            let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1202            let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
1203            let buffer_point = excerpt
1204                .buffer
1205                .offset_to_point(excerpt_start_offset + overshoot);
1206            *start_point + (buffer_point - excerpt_start_point)
1207        } else {
1208            self.excerpts.summary().text.lines
1209        }
1210    }
1211
1212    pub fn point_to_offset(&self, point: Point) -> usize {
1213        let mut cursor = self.excerpts.cursor::<(Point, usize)>();
1214        cursor.seek(&point, Bias::Right, &());
1215        if let Some(excerpt) = cursor.item() {
1216            let (start_point, start_offset) = cursor.start();
1217            let overshoot = point - start_point;
1218            let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1219            let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
1220            let buffer_offset = excerpt
1221                .buffer
1222                .point_to_offset(excerpt_start_point + overshoot);
1223            *start_offset + buffer_offset - excerpt_start_offset
1224        } else {
1225            self.excerpts.summary().text.bytes
1226        }
1227    }
1228
1229    pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
1230        let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>();
1231        cursor.seek(&point, Bias::Right, &());
1232        if let Some(excerpt) = cursor.item() {
1233            let (start_point, start_offset) = cursor.start();
1234            let overshoot = point - start_point;
1235            let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1236            let excerpt_start_point = excerpt
1237                .buffer
1238                .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
1239            let buffer_offset = excerpt
1240                .buffer
1241                .point_utf16_to_offset(excerpt_start_point + overshoot);
1242            *start_offset + (buffer_offset - excerpt_start_offset)
1243        } else {
1244            self.excerpts.summary().text.bytes
1245        }
1246    }
1247
1248    pub fn indent_column_for_line(&self, row: u32) -> u32 {
1249        if let Some((buffer, range)) = self.buffer_line_for_row(row) {
1250            buffer
1251                .indent_column_for_line(range.start.row)
1252                .min(range.end.column)
1253                .saturating_sub(range.start.column)
1254        } else {
1255            0
1256        }
1257    }
1258
1259    pub fn line_len(&self, row: u32) -> u32 {
1260        if let Some((_, range)) = self.buffer_line_for_row(row) {
1261            range.end.column - range.start.column
1262        } else {
1263            0
1264        }
1265    }
1266
1267    fn buffer_line_for_row(&self, row: u32) -> Option<(&BufferSnapshot, Range<Point>)> {
1268        let mut cursor = self.excerpts.cursor::<Point>();
1269        cursor.seek(&Point::new(row, 0), Bias::Right, &());
1270        if let Some(excerpt) = cursor.item() {
1271            let overshoot = row - cursor.start().row;
1272            let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
1273            let excerpt_end = excerpt.range.end.to_point(&excerpt.buffer);
1274            let buffer_row = excerpt_start.row + overshoot;
1275            let line_start = Point::new(buffer_row, 0);
1276            let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
1277            return Some((
1278                &excerpt.buffer,
1279                line_start.max(excerpt_start)..line_end.min(excerpt_end),
1280            ));
1281        }
1282        None
1283    }
1284
1285    pub fn max_point(&self) -> Point {
1286        self.text_summary().lines
1287    }
1288
1289    pub fn text_summary(&self) -> TextSummary {
1290        self.excerpts.summary().text
1291    }
1292
1293    pub fn text_summary_for_range<'a, D, O>(&'a self, range: Range<O>) -> D
1294    where
1295        D: TextDimension,
1296        O: ToOffset,
1297    {
1298        let mut summary = D::default();
1299        let mut range = range.start.to_offset(self)..range.end.to_offset(self);
1300        let mut cursor = self.excerpts.cursor::<usize>();
1301        cursor.seek(&range.start, Bias::Right, &());
1302        if let Some(excerpt) = cursor.item() {
1303            let mut end_before_newline = cursor.end(&());
1304            if excerpt.has_trailing_newline {
1305                end_before_newline -= 1;
1306            }
1307
1308            let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1309            let start_in_excerpt = excerpt_start + (range.start - cursor.start());
1310            let end_in_excerpt =
1311                excerpt_start + (cmp::min(end_before_newline, range.end) - cursor.start());
1312            summary.add_assign(
1313                &excerpt
1314                    .buffer
1315                    .text_summary_for_range(start_in_excerpt..end_in_excerpt),
1316            );
1317
1318            if range.end > end_before_newline {
1319                summary.add_assign(&D::from_text_summary(&TextSummary {
1320                    bytes: 1,
1321                    lines: Point::new(1 as u32, 0),
1322                    lines_utf16: PointUtf16::new(1 as u32, 0),
1323                    first_line_chars: 0,
1324                    last_line_chars: 0,
1325                    longest_row: 0,
1326                    longest_row_chars: 0,
1327                }));
1328            }
1329
1330            cursor.next(&());
1331        }
1332
1333        if range.end > *cursor.start() {
1334            summary.add_assign(&D::from_text_summary(&cursor.summary::<_, TextSummary>(
1335                &range.end,
1336                Bias::Right,
1337                &(),
1338            )));
1339            if let Some(excerpt) = cursor.item() {
1340                range.end = cmp::max(*cursor.start(), range.end);
1341
1342                let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1343                let end_in_excerpt = excerpt_start + (range.end - cursor.start());
1344                summary.add_assign(
1345                    &excerpt
1346                        .buffer
1347                        .text_summary_for_range(excerpt_start..end_in_excerpt),
1348                );
1349            }
1350        }
1351
1352        summary
1353    }
1354
1355    pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
1356    where
1357        D: TextDimension + Ord + Sub<D, Output = D>,
1358    {
1359        let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1360        cursor.seek(&Some(&anchor.excerpt_id), Bias::Left, &());
1361        if cursor.item().is_none() {
1362            cursor.next(&());
1363        }
1364
1365        let mut position = D::from_text_summary(&cursor.start().text);
1366        if let Some(excerpt) = cursor.item() {
1367            if excerpt.id == anchor.excerpt_id && excerpt.buffer_id == anchor.buffer_id {
1368                let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
1369                let excerpt_buffer_end = excerpt.range.end.summary::<D>(&excerpt.buffer);
1370                let buffer_position = cmp::min(
1371                    excerpt_buffer_end,
1372                    anchor.text_anchor.summary::<D>(&excerpt.buffer),
1373                );
1374                if buffer_position > excerpt_buffer_start {
1375                    position.add_assign(&(buffer_position - excerpt_buffer_start));
1376                }
1377            }
1378        }
1379        position
1380    }
1381
1382    pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
1383    where
1384        D: TextDimension + Ord + Sub<D, Output = D>,
1385        I: 'a + IntoIterator<Item = &'a Anchor>,
1386    {
1387        let mut anchors = anchors.into_iter().peekable();
1388        let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1389        let mut summaries = Vec::new();
1390        while let Some(anchor) = anchors.peek() {
1391            let excerpt_id = &anchor.excerpt_id;
1392            let buffer_id = anchor.buffer_id;
1393            let excerpt_anchors = iter::from_fn(|| {
1394                let anchor = anchors.peek()?;
1395                if anchor.excerpt_id == *excerpt_id && anchor.buffer_id == buffer_id {
1396                    Some(&anchors.next().unwrap().text_anchor)
1397                } else {
1398                    None
1399                }
1400            });
1401
1402            cursor.seek_forward(&Some(excerpt_id), Bias::Left, &());
1403            if cursor.item().is_none() {
1404                cursor.next(&());
1405            }
1406
1407            let position = D::from_text_summary(&cursor.start().text);
1408            if let Some(excerpt) = cursor.item() {
1409                if excerpt.id == *excerpt_id && excerpt.buffer_id == buffer_id {
1410                    let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
1411                    let excerpt_buffer_end = excerpt.range.end.summary::<D>(&excerpt.buffer);
1412                    summaries.extend(
1413                        excerpt
1414                            .buffer
1415                            .summaries_for_anchors::<D, _>(excerpt_anchors)
1416                            .map(move |summary| {
1417                                let summary = cmp::min(excerpt_buffer_end.clone(), summary);
1418                                let mut position = position.clone();
1419                                let excerpt_buffer_start = excerpt_buffer_start.clone();
1420                                if summary > excerpt_buffer_start {
1421                                    position.add_assign(&(summary - excerpt_buffer_start));
1422                                }
1423                                position
1424                            }),
1425                    );
1426                    continue;
1427                }
1428            }
1429
1430            summaries.extend(excerpt_anchors.map(|_| position.clone()));
1431        }
1432
1433        summaries
1434    }
1435
1436    pub fn refresh_anchors<'a, I>(&'a self, anchors: I) -> Vec<(usize, Anchor, bool)>
1437    where
1438        I: 'a + IntoIterator<Item = &'a Anchor>,
1439    {
1440        let mut anchors = anchors.into_iter().enumerate().peekable();
1441        let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1442        let mut result = Vec::new();
1443        while let Some((_, anchor)) = anchors.peek() {
1444            let old_excerpt_id = &anchor.excerpt_id;
1445
1446            // Find the location where this anchor's excerpt should be.
1447            cursor.seek_forward(&Some(old_excerpt_id), Bias::Left, &());
1448            if cursor.item().is_none() {
1449                cursor.next(&());
1450            }
1451
1452            let next_excerpt = cursor.item();
1453            let prev_excerpt = cursor.prev_item();
1454
1455            // Process all of the anchors for this excerpt.
1456            while let Some((_, anchor)) = anchors.peek() {
1457                if anchor.excerpt_id != *old_excerpt_id {
1458                    break;
1459                }
1460                let mut kept_position = false;
1461                let (anchor_ix, anchor) = anchors.next().unwrap();
1462                let mut anchor = anchor.clone();
1463
1464                // Leave min and max anchors unchanged.
1465                if *old_excerpt_id == ExcerptId::max() || *old_excerpt_id == ExcerptId::min() {
1466                    kept_position = true;
1467                }
1468                // If the old excerpt still exists at this location, then leave
1469                // the anchor unchanged.
1470                else if next_excerpt.map_or(false, |excerpt| {
1471                    excerpt.id == *old_excerpt_id && excerpt.contains(&anchor)
1472                }) {
1473                    kept_position = true;
1474                }
1475                // If the old excerpt no longer exists at this location, then attempt to
1476                // find an equivalent position for this anchor in an adjacent excerpt.
1477                else {
1478                    for excerpt in [next_excerpt, prev_excerpt].iter().filter_map(|e| *e) {
1479                        if excerpt.contains(&anchor) {
1480                            anchor.excerpt_id = excerpt.id.clone();
1481                            kept_position = true;
1482                            break;
1483                        }
1484                    }
1485                }
1486                // If there's no adjacent excerpt that contains the anchor's position,
1487                // then report that the anchor has lost its position.
1488                if !kept_position {
1489                    anchor = if let Some(excerpt) = next_excerpt {
1490                        let mut text_anchor = excerpt
1491                            .range
1492                            .start
1493                            .bias(anchor.text_anchor.bias, &excerpt.buffer);
1494                        if text_anchor
1495                            .cmp(&excerpt.range.end, &excerpt.buffer)
1496                            .unwrap()
1497                            .is_gt()
1498                        {
1499                            text_anchor = excerpt.range.end.clone();
1500                        }
1501                        Anchor {
1502                            buffer_id: excerpt.buffer_id,
1503                            excerpt_id: excerpt.id.clone(),
1504                            text_anchor,
1505                        }
1506                    } else if let Some(excerpt) = prev_excerpt {
1507                        let mut text_anchor = excerpt
1508                            .range
1509                            .end
1510                            .bias(anchor.text_anchor.bias, &excerpt.buffer);
1511                        if text_anchor
1512                            .cmp(&excerpt.range.start, &excerpt.buffer)
1513                            .unwrap()
1514                            .is_lt()
1515                        {
1516                            text_anchor = excerpt.range.start.clone();
1517                        }
1518                        Anchor {
1519                            buffer_id: excerpt.buffer_id,
1520                            excerpt_id: excerpt.id.clone(),
1521                            text_anchor,
1522                        }
1523                    } else if anchor.text_anchor.bias == Bias::Left {
1524                        Anchor::min()
1525                    } else {
1526                        Anchor::max()
1527                    };
1528                }
1529
1530                result.push((anchor_ix, anchor, kept_position));
1531            }
1532        }
1533        result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self).unwrap());
1534        result
1535    }
1536
1537    pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
1538        self.anchor_at(position, Bias::Left)
1539    }
1540
1541    pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
1542        self.anchor_at(position, Bias::Right)
1543    }
1544
1545    pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
1546        let offset = position.to_offset(self);
1547        let mut cursor = self.excerpts.cursor::<(usize, Option<&ExcerptId>)>();
1548        cursor.seek(&offset, Bias::Right, &());
1549        if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left {
1550            cursor.prev(&());
1551        }
1552        if let Some(excerpt) = cursor.item() {
1553            let mut overshoot = offset.saturating_sub(cursor.start().0);
1554            if excerpt.has_trailing_newline && offset == cursor.end(&()).0 {
1555                overshoot -= 1;
1556                bias = Bias::Right;
1557            }
1558
1559            let buffer_start = excerpt.range.start.to_offset(&excerpt.buffer);
1560            let text_anchor =
1561                excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
1562            Anchor {
1563                buffer_id: excerpt.buffer_id,
1564                excerpt_id: excerpt.id.clone(),
1565                text_anchor,
1566            }
1567        } else if offset == 0 && bias == Bias::Left {
1568            Anchor::min()
1569        } else {
1570            Anchor::max()
1571        }
1572    }
1573
1574    pub fn anchor_in_excerpt(&self, excerpt_id: ExcerptId, text_anchor: text::Anchor) -> Anchor {
1575        let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1576        cursor.seek(&Some(&excerpt_id), Bias::Left, &());
1577        if let Some(excerpt) = cursor.item() {
1578            if excerpt.id == excerpt_id {
1579                let text_anchor = excerpt.clip_anchor(text_anchor);
1580                drop(cursor);
1581                return Anchor {
1582                    buffer_id: excerpt.buffer_id,
1583                    excerpt_id,
1584                    text_anchor,
1585                };
1586            }
1587        }
1588        panic!("excerpt not found");
1589    }
1590
1591    pub fn can_resolve(&self, anchor: &Anchor) -> bool {
1592        if anchor.excerpt_id == ExcerptId::min() || anchor.excerpt_id == ExcerptId::max() {
1593            true
1594        } else if let Some((buffer_id, buffer_snapshot)) =
1595            self.buffer_snapshot_for_excerpt(&anchor.excerpt_id)
1596        {
1597            anchor.buffer_id == buffer_id && buffer_snapshot.can_resolve(&anchor.text_anchor)
1598        } else {
1599            false
1600        }
1601    }
1602
1603    pub fn range_contains_excerpt_boundary<T: ToOffset>(&self, range: Range<T>) -> bool {
1604        let start = range.start.to_offset(self);
1605        let end = range.end.to_offset(self);
1606        let mut cursor = self.excerpts.cursor::<(usize, Option<&ExcerptId>)>();
1607        cursor.seek(&start, Bias::Right, &());
1608        let start_id = cursor
1609            .item()
1610            .or_else(|| cursor.prev_item())
1611            .map(|excerpt| &excerpt.id);
1612        cursor.seek_forward(&end, Bias::Right, &());
1613        let end_id = cursor
1614            .item()
1615            .or_else(|| cursor.prev_item())
1616            .map(|excerpt| &excerpt.id);
1617        start_id != end_id
1618    }
1619
1620    pub fn parse_count(&self) -> usize {
1621        self.parse_count
1622    }
1623
1624    pub fn enclosing_bracket_ranges<T: ToOffset>(
1625        &self,
1626        range: Range<T>,
1627    ) -> Option<(Range<usize>, Range<usize>)> {
1628        let range = range.start.to_offset(self)..range.end.to_offset(self);
1629
1630        let mut cursor = self.excerpts.cursor::<usize>();
1631        cursor.seek(&range.start, Bias::Right, &());
1632        let start_excerpt = cursor.item();
1633
1634        cursor.seek(&range.end, Bias::Right, &());
1635        let end_excerpt = cursor.item();
1636
1637        start_excerpt
1638            .zip(end_excerpt)
1639            .and_then(|(start_excerpt, end_excerpt)| {
1640                if start_excerpt.id != end_excerpt.id {
1641                    return None;
1642                }
1643
1644                let excerpt_buffer_start =
1645                    start_excerpt.range.start.to_offset(&start_excerpt.buffer);
1646                let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
1647
1648                let start_in_buffer =
1649                    excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
1650                let end_in_buffer =
1651                    excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
1652                let (mut start_bracket_range, mut end_bracket_range) = start_excerpt
1653                    .buffer
1654                    .enclosing_bracket_ranges(start_in_buffer..end_in_buffer)?;
1655
1656                if start_bracket_range.start >= excerpt_buffer_start
1657                    && end_bracket_range.end < excerpt_buffer_end
1658                {
1659                    start_bracket_range.start =
1660                        cursor.start() + (start_bracket_range.start - excerpt_buffer_start);
1661                    start_bracket_range.end =
1662                        cursor.start() + (start_bracket_range.end - excerpt_buffer_start);
1663                    end_bracket_range.start =
1664                        cursor.start() + (end_bracket_range.start - excerpt_buffer_start);
1665                    end_bracket_range.end =
1666                        cursor.start() + (end_bracket_range.end - excerpt_buffer_start);
1667                    Some((start_bracket_range, end_bracket_range))
1668                } else {
1669                    None
1670                }
1671            })
1672    }
1673
1674    pub fn diagnostics_update_count(&self) -> usize {
1675        self.diagnostics_update_count
1676    }
1677
1678    pub fn language(&self) -> Option<&Arc<Language>> {
1679        self.excerpts
1680            .iter()
1681            .next()
1682            .and_then(|excerpt| excerpt.buffer.language())
1683    }
1684
1685    pub fn is_dirty(&self) -> bool {
1686        self.is_dirty
1687    }
1688
1689    pub fn has_conflict(&self) -> bool {
1690        self.has_conflict
1691    }
1692
1693    pub fn diagnostic_group<'a, O>(
1694        &'a self,
1695        group_id: usize,
1696    ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
1697    where
1698        O: text::FromAnchor + 'a,
1699    {
1700        self.as_singleton()
1701            .into_iter()
1702            .flat_map(move |buffer| buffer.diagnostic_group(group_id))
1703    }
1704
1705    pub fn diagnostics_in_range<'a, T, O>(
1706        &'a self,
1707        range: Range<T>,
1708    ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
1709    where
1710        T: 'a + ToOffset,
1711        O: 'a + text::FromAnchor,
1712    {
1713        self.as_singleton().into_iter().flat_map(move |buffer| {
1714            buffer.diagnostics_in_range(range.start.to_offset(self)..range.end.to_offset(self))
1715        })
1716    }
1717
1718    pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
1719        let range = range.start.to_offset(self)..range.end.to_offset(self);
1720
1721        let mut cursor = self.excerpts.cursor::<usize>();
1722        cursor.seek(&range.start, Bias::Right, &());
1723        let start_excerpt = cursor.item();
1724
1725        cursor.seek(&range.end, Bias::Right, &());
1726        let end_excerpt = cursor.item();
1727
1728        start_excerpt
1729            .zip(end_excerpt)
1730            .and_then(|(start_excerpt, end_excerpt)| {
1731                if start_excerpt.id != end_excerpt.id {
1732                    return None;
1733                }
1734
1735                let excerpt_buffer_start =
1736                    start_excerpt.range.start.to_offset(&start_excerpt.buffer);
1737                let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
1738
1739                let start_in_buffer =
1740                    excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
1741                let end_in_buffer =
1742                    excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
1743                let mut ancestor_buffer_range = start_excerpt
1744                    .buffer
1745                    .range_for_syntax_ancestor(start_in_buffer..end_in_buffer)?;
1746                ancestor_buffer_range.start =
1747                    cmp::max(ancestor_buffer_range.start, excerpt_buffer_start);
1748                ancestor_buffer_range.end = cmp::min(ancestor_buffer_range.end, excerpt_buffer_end);
1749
1750                let start = cursor.start() + (ancestor_buffer_range.start - excerpt_buffer_start);
1751                let end = cursor.start() + (ancestor_buffer_range.end - excerpt_buffer_start);
1752                Some(start..end)
1753            })
1754    }
1755
1756    pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
1757        let buffer = self.as_singleton()?;
1758        let outline = buffer.outline(theme)?;
1759        let excerpt_id = &self.excerpts.iter().next().unwrap().id;
1760        Some(Outline::new(
1761            outline
1762                .items
1763                .into_iter()
1764                .map(|item| OutlineItem {
1765                    depth: item.depth,
1766                    range: self.anchor_in_excerpt(excerpt_id.clone(), item.range.start)
1767                        ..self.anchor_in_excerpt(excerpt_id.clone(), item.range.end),
1768                    text: item.text,
1769                    highlight_ranges: item.highlight_ranges,
1770                    name_ranges: item.name_ranges,
1771                })
1772                .collect(),
1773        ))
1774    }
1775
1776    fn buffer_snapshot_for_excerpt<'a>(
1777        &'a self,
1778        excerpt_id: &'a ExcerptId,
1779    ) -> Option<(usize, &'a BufferSnapshot)> {
1780        let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1781        cursor.seek(&Some(excerpt_id), Bias::Left, &());
1782        if let Some(excerpt) = cursor.item() {
1783            if excerpt.id == *excerpt_id {
1784                return Some((excerpt.buffer_id, &excerpt.buffer));
1785            }
1786        }
1787        None
1788    }
1789
1790    pub fn remote_selections_in_range<'a>(
1791        &'a self,
1792        range: &'a Range<Anchor>,
1793    ) -> impl 'a + Iterator<Item = (ReplicaId, Selection<Anchor>)> {
1794        let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1795        cursor.seek(&Some(&range.start.excerpt_id), Bias::Left, &());
1796        cursor
1797            .take_while(move |excerpt| excerpt.id <= range.end.excerpt_id)
1798            .flat_map(move |excerpt| {
1799                let mut query_range = excerpt.range.start.clone()..excerpt.range.end.clone();
1800                if excerpt.id == range.start.excerpt_id {
1801                    query_range.start = range.start.text_anchor.clone();
1802                }
1803                if excerpt.id == range.end.excerpt_id {
1804                    query_range.end = range.end.text_anchor.clone();
1805                }
1806
1807                excerpt
1808                    .buffer
1809                    .remote_selections_in_range(query_range)
1810                    .flat_map(move |(replica_id, selections)| {
1811                        selections.map(move |selection| {
1812                            let mut start = Anchor {
1813                                buffer_id: excerpt.buffer_id,
1814                                excerpt_id: excerpt.id.clone(),
1815                                text_anchor: selection.start.clone(),
1816                            };
1817                            let mut end = Anchor {
1818                                buffer_id: excerpt.buffer_id,
1819                                excerpt_id: excerpt.id.clone(),
1820                                text_anchor: selection.end.clone(),
1821                            };
1822                            if range.start.cmp(&start, self).unwrap().is_gt() {
1823                                start = range.start.clone();
1824                            }
1825                            if range.end.cmp(&end, self).unwrap().is_lt() {
1826                                end = range.end.clone();
1827                            }
1828
1829                            (
1830                                replica_id,
1831                                Selection {
1832                                    id: selection.id,
1833                                    start,
1834                                    end,
1835                                    reversed: selection.reversed,
1836                                    goal: selection.goal,
1837                                },
1838                            )
1839                        })
1840                    })
1841            })
1842    }
1843}
1844
1845impl History {
1846    fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
1847        self.transaction_depth += 1;
1848        if self.transaction_depth == 1 {
1849            let id = post_inc(&mut self.next_transaction_id);
1850            self.undo_stack.push(Transaction {
1851                id,
1852                buffer_transactions: Default::default(),
1853                first_edit_at: now,
1854                last_edit_at: now,
1855            });
1856            Some(id)
1857        } else {
1858            None
1859        }
1860    }
1861
1862    fn end_transaction(
1863        &mut self,
1864        now: Instant,
1865        buffer_transactions: HashSet<(usize, TransactionId)>,
1866    ) -> bool {
1867        assert_ne!(self.transaction_depth, 0);
1868        self.transaction_depth -= 1;
1869        if self.transaction_depth == 0 {
1870            if buffer_transactions.is_empty() {
1871                self.undo_stack.pop();
1872                false
1873            } else {
1874                let transaction = self.undo_stack.last_mut().unwrap();
1875                transaction.last_edit_at = now;
1876                transaction.buffer_transactions.extend(buffer_transactions);
1877                true
1878            }
1879        } else {
1880            false
1881        }
1882    }
1883
1884    fn pop_undo(&mut self) -> Option<&Transaction> {
1885        assert_eq!(self.transaction_depth, 0);
1886        if let Some(transaction) = self.undo_stack.pop() {
1887            self.redo_stack.push(transaction);
1888            self.redo_stack.last()
1889        } else {
1890            None
1891        }
1892    }
1893
1894    fn pop_redo(&mut self) -> Option<&Transaction> {
1895        assert_eq!(self.transaction_depth, 0);
1896        if let Some(transaction) = self.redo_stack.pop() {
1897            self.undo_stack.push(transaction);
1898            self.undo_stack.last()
1899        } else {
1900            None
1901        }
1902    }
1903
1904    fn group(&mut self) -> Option<TransactionId> {
1905        let mut new_len = self.undo_stack.len();
1906        let mut transactions = self.undo_stack.iter_mut();
1907
1908        if let Some(mut transaction) = transactions.next_back() {
1909            while let Some(prev_transaction) = transactions.next_back() {
1910                if transaction.first_edit_at - prev_transaction.last_edit_at <= self.group_interval
1911                {
1912                    transaction = prev_transaction;
1913                    new_len -= 1;
1914                } else {
1915                    break;
1916                }
1917            }
1918        }
1919
1920        let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
1921        if let Some(last_transaction) = transactions_to_keep.last_mut() {
1922            if let Some(transaction) = transactions_to_merge.last() {
1923                last_transaction.last_edit_at = transaction.last_edit_at;
1924            }
1925        }
1926
1927        self.undo_stack.truncate(new_len);
1928        self.undo_stack.last().map(|t| t.id)
1929    }
1930}
1931
1932impl Excerpt {
1933    fn new(
1934        id: ExcerptId,
1935        buffer_id: usize,
1936        buffer: BufferSnapshot,
1937        range: Range<text::Anchor>,
1938        has_trailing_newline: bool,
1939    ) -> Self {
1940        Excerpt {
1941            id,
1942            max_buffer_row: range.end.to_point(&buffer).row,
1943            text_summary: buffer.text_summary_for_range::<TextSummary, _>(range.to_offset(&buffer)),
1944            buffer_id,
1945            buffer,
1946            range,
1947            has_trailing_newline,
1948        }
1949    }
1950
1951    fn chunks_in_range<'a>(
1952        &'a self,
1953        range: Range<usize>,
1954        theme: Option<&'a SyntaxTheme>,
1955    ) -> ExcerptChunks<'a> {
1956        let content_start = self.range.start.to_offset(&self.buffer);
1957        let chunks_start = content_start + range.start;
1958        let chunks_end = content_start + cmp::min(range.end, self.text_summary.bytes);
1959
1960        let footer_height = if self.has_trailing_newline
1961            && range.start <= self.text_summary.bytes
1962            && range.end > self.text_summary.bytes
1963        {
1964            1
1965        } else {
1966            0
1967        };
1968
1969        let content_chunks = self.buffer.chunks(chunks_start..chunks_end, theme);
1970
1971        ExcerptChunks {
1972            content_chunks,
1973            footer_height,
1974        }
1975    }
1976
1977    fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
1978        let content_start = self.range.start.to_offset(&self.buffer);
1979        let bytes_start = content_start + range.start;
1980        let bytes_end = content_start + cmp::min(range.end, self.text_summary.bytes);
1981        let footer_height = if self.has_trailing_newline
1982            && range.start <= self.text_summary.bytes
1983            && range.end > self.text_summary.bytes
1984        {
1985            1
1986        } else {
1987            0
1988        };
1989        let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
1990
1991        ExcerptBytes {
1992            content_bytes,
1993            footer_height,
1994        }
1995    }
1996
1997    fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
1998        if text_anchor
1999            .cmp(&self.range.start, &self.buffer)
2000            .unwrap()
2001            .is_lt()
2002        {
2003            self.range.start.clone()
2004        } else if text_anchor
2005            .cmp(&self.range.end, &self.buffer)
2006            .unwrap()
2007            .is_gt()
2008        {
2009            self.range.end.clone()
2010        } else {
2011            text_anchor
2012        }
2013    }
2014
2015    fn contains(&self, anchor: &Anchor) -> bool {
2016        self.buffer_id == anchor.buffer_id
2017            && self
2018                .range
2019                .start
2020                .cmp(&anchor.text_anchor, &self.buffer)
2021                .unwrap()
2022                .is_le()
2023            && self
2024                .range
2025                .end
2026                .cmp(&anchor.text_anchor, &self.buffer)
2027                .unwrap()
2028                .is_ge()
2029    }
2030}
2031
2032impl fmt::Debug for Excerpt {
2033    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2034        f.debug_struct("Excerpt")
2035            .field("id", &self.id)
2036            .field("buffer_id", &self.buffer_id)
2037            .field("range", &self.range)
2038            .field("text_summary", &self.text_summary)
2039            .field("has_trailing_newline", &self.has_trailing_newline)
2040            .finish()
2041    }
2042}
2043
2044impl sum_tree::Item for Excerpt {
2045    type Summary = ExcerptSummary;
2046
2047    fn summary(&self) -> Self::Summary {
2048        let mut text = self.text_summary.clone();
2049        if self.has_trailing_newline {
2050            text += TextSummary::from("\n");
2051        }
2052        ExcerptSummary {
2053            excerpt_id: self.id.clone(),
2054            max_buffer_row: self.max_buffer_row,
2055            text,
2056        }
2057    }
2058}
2059
2060impl sum_tree::Summary for ExcerptSummary {
2061    type Context = ();
2062
2063    fn add_summary(&mut self, summary: &Self, _: &()) {
2064        debug_assert!(summary.excerpt_id > self.excerpt_id);
2065        self.excerpt_id = summary.excerpt_id.clone();
2066        self.text.add_summary(&summary.text, &());
2067        self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row);
2068    }
2069}
2070
2071impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
2072    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2073        *self += &summary.text;
2074    }
2075}
2076
2077impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
2078    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2079        *self += summary.text.bytes;
2080    }
2081}
2082
2083impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
2084    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
2085        Ord::cmp(self, &cursor_location.text.bytes)
2086    }
2087}
2088
2089impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Option<&'a ExcerptId> {
2090    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
2091        Ord::cmp(self, &Some(&cursor_location.excerpt_id))
2092    }
2093}
2094
2095impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
2096    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2097        *self += summary.text.lines;
2098    }
2099}
2100
2101impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
2102    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2103        *self += summary.text.lines_utf16
2104    }
2105}
2106
2107impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a ExcerptId> {
2108    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
2109        *self = Some(&summary.excerpt_id);
2110    }
2111}
2112
2113impl<'a> MultiBufferRows<'a> {
2114    pub fn seek(&mut self, row: u32) {
2115        self.buffer_row_range = 0..0;
2116
2117        self.excerpts
2118            .seek_forward(&Point::new(row, 0), Bias::Right, &());
2119        if self.excerpts.item().is_none() {
2120            self.excerpts.prev(&());
2121
2122            if self.excerpts.item().is_none() && row == 0 {
2123                self.buffer_row_range = 0..1;
2124                return;
2125            }
2126        }
2127
2128        if let Some(excerpt) = self.excerpts.item() {
2129            let overshoot = row - self.excerpts.start().row;
2130            let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer).row;
2131            self.buffer_row_range.start = excerpt_start + overshoot;
2132            self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
2133        }
2134    }
2135}
2136
2137impl<'a> Iterator for MultiBufferRows<'a> {
2138    type Item = Option<u32>;
2139
2140    fn next(&mut self) -> Option<Self::Item> {
2141        loop {
2142            if !self.buffer_row_range.is_empty() {
2143                let row = Some(self.buffer_row_range.start);
2144                self.buffer_row_range.start += 1;
2145                return Some(row);
2146            }
2147            self.excerpts.item()?;
2148            self.excerpts.next(&());
2149            let excerpt = self.excerpts.item()?;
2150            self.buffer_row_range.start = excerpt.range.start.to_point(&excerpt.buffer).row;
2151            self.buffer_row_range.end =
2152                self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
2153        }
2154    }
2155}
2156
2157impl<'a> MultiBufferChunks<'a> {
2158    pub fn offset(&self) -> usize {
2159        self.range.start
2160    }
2161
2162    pub fn seek(&mut self, offset: usize) {
2163        self.range.start = offset;
2164        self.excerpts.seek(&offset, Bias::Right, &());
2165        if let Some(excerpt) = self.excerpts.item() {
2166            self.excerpt_chunks = Some(excerpt.chunks_in_range(
2167                self.range.start - self.excerpts.start()..self.range.end - self.excerpts.start(),
2168                self.theme,
2169            ));
2170        } else {
2171            self.excerpt_chunks = None;
2172        }
2173    }
2174}
2175
2176impl<'a> Iterator for MultiBufferChunks<'a> {
2177    type Item = Chunk<'a>;
2178
2179    fn next(&mut self) -> Option<Self::Item> {
2180        if self.range.is_empty() {
2181            None
2182        } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
2183            self.range.start += chunk.text.len();
2184            Some(chunk)
2185        } else {
2186            self.excerpts.next(&());
2187            let excerpt = self.excerpts.item()?;
2188            self.excerpt_chunks = Some(
2189                excerpt.chunks_in_range(0..self.range.end - self.excerpts.start(), self.theme),
2190            );
2191            self.next()
2192        }
2193    }
2194}
2195
2196impl<'a> MultiBufferBytes<'a> {
2197    fn consume(&mut self, len: usize) {
2198        self.range.start += len;
2199        self.chunk = &self.chunk[len..];
2200
2201        if !self.range.is_empty() && self.chunk.is_empty() {
2202            if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
2203                self.chunk = chunk;
2204            } else {
2205                self.excerpts.next(&());
2206                if let Some(excerpt) = self.excerpts.item() {
2207                    let mut excerpt_bytes =
2208                        excerpt.bytes_in_range(0..self.range.end - self.excerpts.start());
2209                    self.chunk = excerpt_bytes.next().unwrap();
2210                    self.excerpt_bytes = Some(excerpt_bytes);
2211                }
2212            }
2213        }
2214    }
2215}
2216
2217impl<'a> Iterator for MultiBufferBytes<'a> {
2218    type Item = &'a [u8];
2219
2220    fn next(&mut self) -> Option<Self::Item> {
2221        let chunk = self.chunk;
2222        if chunk.is_empty() {
2223            None
2224        } else {
2225            self.consume(chunk.len());
2226            Some(chunk)
2227        }
2228    }
2229}
2230
2231impl<'a> io::Read for MultiBufferBytes<'a> {
2232    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2233        let len = cmp::min(buf.len(), self.chunk.len());
2234        buf[..len].copy_from_slice(&self.chunk[..len]);
2235        if len > 0 {
2236            self.consume(len);
2237        }
2238        Ok(len)
2239    }
2240}
2241
2242impl<'a> Iterator for ExcerptBytes<'a> {
2243    type Item = &'a [u8];
2244
2245    fn next(&mut self) -> Option<Self::Item> {
2246        if let Some(chunk) = self.content_bytes.next() {
2247            if !chunk.is_empty() {
2248                return Some(chunk);
2249            }
2250        }
2251
2252        if self.footer_height > 0 {
2253            let result = &NEWLINES[..self.footer_height];
2254            self.footer_height = 0;
2255            return Some(result);
2256        }
2257
2258        None
2259    }
2260}
2261
2262impl<'a> Iterator for ExcerptChunks<'a> {
2263    type Item = Chunk<'a>;
2264
2265    fn next(&mut self) -> Option<Self::Item> {
2266        if let Some(chunk) = self.content_chunks.next() {
2267            return Some(chunk);
2268        }
2269
2270        if self.footer_height > 0 {
2271            let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
2272            self.footer_height = 0;
2273            return Some(Chunk {
2274                text,
2275                ..Default::default()
2276            });
2277        }
2278
2279        None
2280    }
2281}
2282
2283impl ToOffset for Point {
2284    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
2285        snapshot.point_to_offset(*self)
2286    }
2287}
2288
2289impl ToOffset for PointUtf16 {
2290    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
2291        snapshot.point_utf16_to_offset(*self)
2292    }
2293}
2294
2295impl ToOffset for usize {
2296    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
2297        assert!(*self <= snapshot.len(), "offset is out of range");
2298        *self
2299    }
2300}
2301
2302impl ToPoint for usize {
2303    fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
2304        snapshot.offset_to_point(*self)
2305    }
2306}
2307
2308impl ToPoint for Point {
2309    fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
2310        *self
2311    }
2312}
2313
2314#[cfg(test)]
2315mod tests {
2316    use super::*;
2317    use gpui::MutableAppContext;
2318    use language::{Buffer, Rope};
2319    use rand::prelude::*;
2320    use std::env;
2321    use text::{Point, RandomCharIter};
2322    use util::test::sample_text;
2323
2324    #[gpui::test]
2325    fn test_singleton_multibuffer(cx: &mut MutableAppContext) {
2326        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
2327        let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
2328
2329        let snapshot = multibuffer.read(cx).snapshot(cx);
2330        assert_eq!(snapshot.text(), buffer.read(cx).text());
2331
2332        assert_eq!(
2333            snapshot.buffer_rows(0).collect::<Vec<_>>(),
2334            (0..buffer.read(cx).row_count())
2335                .map(Some)
2336                .collect::<Vec<_>>()
2337        );
2338
2339        buffer.update(cx, |buffer, cx| buffer.edit([1..3], "XXX\n", cx));
2340        let snapshot = multibuffer.read(cx).snapshot(cx);
2341
2342        assert_eq!(snapshot.text(), buffer.read(cx).text());
2343        assert_eq!(
2344            snapshot.buffer_rows(0).collect::<Vec<_>>(),
2345            (0..buffer.read(cx).row_count())
2346                .map(Some)
2347                .collect::<Vec<_>>()
2348        );
2349    }
2350
2351    #[gpui::test]
2352    fn test_remote_multibuffer(cx: &mut MutableAppContext) {
2353        let host_buffer = cx.add_model(|cx| Buffer::new(0, "a", cx));
2354        let guest_buffer = cx.add_model(|cx| {
2355            let message = host_buffer.read(cx).to_proto();
2356            Buffer::from_proto(1, message, None, cx).unwrap()
2357        });
2358        let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(guest_buffer.clone(), cx));
2359        let snapshot = multibuffer.read(cx).snapshot(cx);
2360        assert_eq!(snapshot.text(), "a");
2361
2362        guest_buffer.update(cx, |buffer, cx| buffer.edit([1..1], "b", cx));
2363        let snapshot = multibuffer.read(cx).snapshot(cx);
2364        assert_eq!(snapshot.text(), "ab");
2365
2366        guest_buffer.update(cx, |buffer, cx| buffer.edit([2..2], "c", cx));
2367        let snapshot = multibuffer.read(cx).snapshot(cx);
2368        assert_eq!(snapshot.text(), "abc");
2369    }
2370
2371    #[gpui::test]
2372    fn test_excerpt_buffer(cx: &mut MutableAppContext) {
2373        let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
2374        let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
2375        let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2376
2377        let subscription = multibuffer.update(cx, |multibuffer, cx| {
2378            let subscription = multibuffer.subscribe();
2379            multibuffer.push_excerpt(
2380                ExcerptProperties {
2381                    buffer: &buffer_1,
2382                    range: Point::new(1, 2)..Point::new(2, 5),
2383                },
2384                cx,
2385            );
2386            assert_eq!(
2387                subscription.consume().into_inner(),
2388                [Edit {
2389                    old: 0..0,
2390                    new: 0..10
2391                }]
2392            );
2393
2394            multibuffer.push_excerpt(
2395                ExcerptProperties {
2396                    buffer: &buffer_1,
2397                    range: Point::new(3, 3)..Point::new(4, 4),
2398                },
2399                cx,
2400            );
2401            multibuffer.push_excerpt(
2402                ExcerptProperties {
2403                    buffer: &buffer_2,
2404                    range: Point::new(3, 1)..Point::new(3, 3),
2405                },
2406                cx,
2407            );
2408            assert_eq!(
2409                subscription.consume().into_inner(),
2410                [Edit {
2411                    old: 10..10,
2412                    new: 10..22
2413                }]
2414            );
2415
2416            subscription
2417        });
2418
2419        let snapshot = multibuffer.read(cx).snapshot(cx);
2420        assert_eq!(
2421            snapshot.text(),
2422            concat!(
2423                "bbbb\n",  // Preserve newlines
2424                "ccccc\n", //
2425                "ddd\n",   //
2426                "eeee\n",  //
2427                "jj"       //
2428            )
2429        );
2430        assert_eq!(
2431            snapshot.buffer_rows(0).collect::<Vec<_>>(),
2432            [Some(1), Some(2), Some(3), Some(4), Some(3)]
2433        );
2434        assert_eq!(
2435            snapshot.buffer_rows(2).collect::<Vec<_>>(),
2436            [Some(3), Some(4), Some(3)]
2437        );
2438        assert_eq!(snapshot.buffer_rows(4).collect::<Vec<_>>(), [Some(3)]);
2439        assert_eq!(snapshot.buffer_rows(5).collect::<Vec<_>>(), []);
2440        assert!(!snapshot.range_contains_excerpt_boundary(Point::new(1, 0)..Point::new(1, 5)));
2441        assert!(snapshot.range_contains_excerpt_boundary(Point::new(1, 0)..Point::new(2, 0)));
2442        assert!(snapshot.range_contains_excerpt_boundary(Point::new(1, 0)..Point::new(4, 0)));
2443        assert!(!snapshot.range_contains_excerpt_boundary(Point::new(2, 0)..Point::new(3, 0)));
2444        assert!(!snapshot.range_contains_excerpt_boundary(Point::new(4, 0)..Point::new(4, 2)));
2445        assert!(!snapshot.range_contains_excerpt_boundary(Point::new(4, 2)..Point::new(4, 2)));
2446
2447        buffer_1.update(cx, |buffer, cx| {
2448            buffer.edit(
2449                [
2450                    Point::new(0, 0)..Point::new(0, 0),
2451                    Point::new(2, 1)..Point::new(2, 3),
2452                ],
2453                "\n",
2454                cx,
2455            );
2456        });
2457
2458        let snapshot = multibuffer.read(cx).snapshot(cx);
2459        assert_eq!(
2460            snapshot.text(),
2461            concat!(
2462                "bbbb\n", // Preserve newlines
2463                "c\n",    //
2464                "cc\n",   //
2465                "ddd\n",  //
2466                "eeee\n", //
2467                "jj"      //
2468            )
2469        );
2470
2471        assert_eq!(
2472            subscription.consume().into_inner(),
2473            [Edit {
2474                old: 6..8,
2475                new: 6..7
2476            }]
2477        );
2478
2479        let snapshot = multibuffer.read(cx).snapshot(cx);
2480        assert_eq!(
2481            snapshot.clip_point(Point::new(0, 5), Bias::Left),
2482            Point::new(0, 4)
2483        );
2484        assert_eq!(
2485            snapshot.clip_point(Point::new(0, 5), Bias::Right),
2486            Point::new(0, 4)
2487        );
2488        assert_eq!(
2489            snapshot.clip_point(Point::new(5, 1), Bias::Right),
2490            Point::new(5, 1)
2491        );
2492        assert_eq!(
2493            snapshot.clip_point(Point::new(5, 2), Bias::Right),
2494            Point::new(5, 2)
2495        );
2496        assert_eq!(
2497            snapshot.clip_point(Point::new(5, 3), Bias::Right),
2498            Point::new(5, 2)
2499        );
2500
2501        let snapshot = multibuffer.update(cx, |multibuffer, cx| {
2502            let buffer_2_excerpt_id = multibuffer.excerpt_ids_for_buffer(&buffer_2)[0].clone();
2503            multibuffer.remove_excerpts(&[buffer_2_excerpt_id], cx);
2504            multibuffer.snapshot(cx)
2505        });
2506
2507        assert_eq!(
2508            snapshot.text(),
2509            concat!(
2510                "bbbb\n", // Preserve newlines
2511                "c\n",    //
2512                "cc\n",   //
2513                "ddd\n",  //
2514                "eeee",   //
2515            )
2516        );
2517    }
2518
2519    #[gpui::test]
2520    fn test_empty_excerpt_buffer(cx: &mut MutableAppContext) {
2521        let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2522
2523        let snapshot = multibuffer.read(cx).snapshot(cx);
2524        assert_eq!(snapshot.text(), "");
2525        assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), &[Some(0)]);
2526        assert_eq!(snapshot.buffer_rows(1).collect::<Vec<_>>(), &[]);
2527    }
2528
2529    #[gpui::test]
2530    fn test_singleton_multibuffer_anchors(cx: &mut MutableAppContext) {
2531        let buffer = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
2532        let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
2533        let old_snapshot = multibuffer.read(cx).snapshot(cx);
2534        buffer.update(cx, |buffer, cx| {
2535            buffer.edit([0..0], "X", cx);
2536            buffer.edit([5..5], "Y", cx);
2537        });
2538        let new_snapshot = multibuffer.read(cx).snapshot(cx);
2539
2540        assert_eq!(old_snapshot.text(), "abcd");
2541        assert_eq!(new_snapshot.text(), "XabcdY");
2542
2543        assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
2544        assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
2545        assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
2546        assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
2547    }
2548
2549    #[gpui::test]
2550    fn test_multibuffer_anchors(cx: &mut MutableAppContext) {
2551        let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
2552        let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
2553        let multibuffer = cx.add_model(|cx| {
2554            let mut multibuffer = MultiBuffer::new(0);
2555            multibuffer.push_excerpt(
2556                ExcerptProperties {
2557                    buffer: &buffer_1,
2558                    range: 0..4,
2559                },
2560                cx,
2561            );
2562            multibuffer.push_excerpt(
2563                ExcerptProperties {
2564                    buffer: &buffer_2,
2565                    range: 0..5,
2566                },
2567                cx,
2568            );
2569            multibuffer
2570        });
2571        let old_snapshot = multibuffer.read(cx).snapshot(cx);
2572
2573        assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
2574        assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
2575        assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
2576        assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
2577        assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
2578        assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
2579
2580        buffer_1.update(cx, |buffer, cx| {
2581            buffer.edit([0..0], "W", cx);
2582            buffer.edit([5..5], "X", cx);
2583        });
2584        buffer_2.update(cx, |buffer, cx| {
2585            buffer.edit([0..0], "Y", cx);
2586            buffer.edit([6..0], "Z", cx);
2587        });
2588        let new_snapshot = multibuffer.read(cx).snapshot(cx);
2589
2590        assert_eq!(old_snapshot.text(), "abcd\nefghi");
2591        assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
2592
2593        assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
2594        assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
2595        assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
2596        assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
2597        assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
2598        assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
2599        assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
2600        assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
2601        assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
2602        assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
2603    }
2604
2605    #[gpui::test]
2606    fn test_multibuffer_resolving_anchors_after_replacing_their_excerpts(
2607        cx: &mut MutableAppContext,
2608    ) {
2609        let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
2610        let buffer_2 = cx.add_model(|cx| Buffer::new(0, "ABCDEFGHIJKLMNOP", cx));
2611        let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2612
2613        // Create an insertion id in buffer 1 that doesn't exist in buffer 2.
2614        // Add an excerpt from buffer 1 that spans this new insertion.
2615        buffer_1.update(cx, |buffer, cx| buffer.edit([4..4], "123", cx));
2616        let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| {
2617            multibuffer.push_excerpt(
2618                ExcerptProperties {
2619                    buffer: &buffer_1,
2620                    range: 0..7,
2621                },
2622                cx,
2623            )
2624        });
2625
2626        let snapshot_1 = multibuffer.read(cx).snapshot(cx);
2627        assert_eq!(snapshot_1.text(), "abcd123");
2628
2629        // Replace the buffer 1 excerpt with new excerpts from buffer 2.
2630        let (excerpt_id_2, excerpt_id_3, _) = multibuffer.update(cx, |multibuffer, cx| {
2631            multibuffer.remove_excerpts([&excerpt_id_1], cx);
2632            (
2633                multibuffer.push_excerpt(
2634                    ExcerptProperties {
2635                        buffer: &buffer_2,
2636                        range: 0..4,
2637                    },
2638                    cx,
2639                ),
2640                multibuffer.push_excerpt(
2641                    ExcerptProperties {
2642                        buffer: &buffer_2,
2643                        range: 6..10,
2644                    },
2645                    cx,
2646                ),
2647                multibuffer.push_excerpt(
2648                    ExcerptProperties {
2649                        buffer: &buffer_2,
2650                        range: 12..16,
2651                    },
2652                    cx,
2653                ),
2654            )
2655        });
2656        let snapshot_2 = multibuffer.read(cx).snapshot(cx);
2657        assert_eq!(snapshot_2.text(), "ABCD\nGHIJ\nMNOP");
2658
2659        // The old excerpt id has been reused.
2660        assert_eq!(excerpt_id_2, excerpt_id_1);
2661
2662        // Resolve some anchors from the previous snapshot in the new snapshot.
2663        // Although there is still an excerpt with the same id, it is for
2664        // a different buffer, so we don't attempt to resolve the old text
2665        // anchor in the new buffer.
2666        assert_eq!(
2667            snapshot_2.summary_for_anchor::<usize>(&snapshot_1.anchor_before(2)),
2668            0
2669        );
2670        assert_eq!(
2671            snapshot_2.summaries_for_anchors::<usize, _>(&[
2672                snapshot_1.anchor_before(2),
2673                snapshot_1.anchor_after(3)
2674            ]),
2675            vec![0, 0]
2676        );
2677        let refresh =
2678            snapshot_2.refresh_anchors(&[snapshot_1.anchor_before(2), snapshot_1.anchor_after(3)]);
2679        assert_eq!(
2680            refresh,
2681            &[
2682                (0, snapshot_2.anchor_before(0), false),
2683                (1, snapshot_2.anchor_after(0), false),
2684            ]
2685        );
2686
2687        // Replace the middle excerpt with a smaller excerpt in buffer 2,
2688        // that intersects the old excerpt.
2689        let excerpt_id_5 = multibuffer.update(cx, |multibuffer, cx| {
2690            multibuffer.remove_excerpts([&excerpt_id_3], cx);
2691            multibuffer.insert_excerpt_after(
2692                &excerpt_id_3,
2693                ExcerptProperties {
2694                    buffer: &buffer_2,
2695                    range: 5..8,
2696                },
2697                cx,
2698            )
2699        });
2700
2701        let snapshot_3 = multibuffer.read(cx).snapshot(cx);
2702        assert_eq!(snapshot_3.text(), "ABCD\nFGH\nMNOP");
2703        assert_ne!(excerpt_id_5, excerpt_id_3);
2704
2705        // Resolve some anchors from the previous snapshot in the new snapshot.
2706        // The anchor in the middle excerpt snaps to the beginning of the
2707        // excerpt, since it is not
2708        let anchors = [
2709            snapshot_2.anchor_before(0),
2710            snapshot_2.anchor_after(2),
2711            snapshot_2.anchor_after(6),
2712            snapshot_2.anchor_after(14),
2713        ];
2714        assert_eq!(
2715            snapshot_3.summaries_for_anchors::<usize, _>(&anchors),
2716            &[0, 2, 9, 13]
2717        );
2718
2719        let new_anchors = snapshot_3.refresh_anchors(&anchors);
2720        assert_eq!(
2721            new_anchors.iter().map(|a| (a.0, a.2)).collect::<Vec<_>>(),
2722            &[(0, true), (1, true), (2, true), (3, true)]
2723        );
2724        assert_eq!(
2725            snapshot_3.summaries_for_anchors::<usize, _>(new_anchors.iter().map(|a| &a.1)),
2726            &[0, 2, 7, 13]
2727        );
2728    }
2729
2730    #[gpui::test(iterations = 100)]
2731    fn test_random_multibuffer(cx: &mut MutableAppContext, mut rng: StdRng) {
2732        let operations = env::var("OPERATIONS")
2733            .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2734            .unwrap_or(10);
2735
2736        let mut buffers: Vec<ModelHandle<Buffer>> = Vec::new();
2737        let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2738        let mut excerpt_ids = Vec::new();
2739        let mut expected_excerpts = Vec::<(ModelHandle<Buffer>, Range<text::Anchor>)>::new();
2740        let mut anchors = Vec::new();
2741        let mut old_versions = Vec::new();
2742
2743        for _ in 0..operations {
2744            match rng.gen_range(0..100) {
2745                0..=19 if !buffers.is_empty() => {
2746                    let buffer = buffers.choose(&mut rng).unwrap();
2747                    buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
2748                }
2749                20..=29 if !expected_excerpts.is_empty() => {
2750                    let mut ids_to_remove = vec![];
2751                    for _ in 0..rng.gen_range(1..=3) {
2752                        if expected_excerpts.is_empty() {
2753                            break;
2754                        }
2755
2756                        let ix = rng.gen_range(0..expected_excerpts.len());
2757                        ids_to_remove.push(excerpt_ids.remove(ix));
2758                        let (buffer, range) = expected_excerpts.remove(ix);
2759                        let buffer = buffer.read(cx);
2760                        log::info!(
2761                            "Removing excerpt {}: {:?}",
2762                            ix,
2763                            buffer
2764                                .text_for_range(range.to_offset(&buffer))
2765                                .collect::<String>(),
2766                        );
2767                    }
2768                    ids_to_remove.sort_unstable();
2769                    multibuffer.update(cx, |multibuffer, cx| {
2770                        multibuffer.remove_excerpts(&ids_to_remove, cx)
2771                    });
2772                }
2773                30..=39 if !expected_excerpts.is_empty() => {
2774                    let multibuffer = multibuffer.read(cx).read(cx);
2775                    let offset =
2776                        multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left);
2777                    let bias = if rng.gen() { Bias::Left } else { Bias::Right };
2778                    log::info!("Creating anchor at {} with bias {:?}", offset, bias);
2779                    anchors.push(multibuffer.anchor_at(offset, bias));
2780                    anchors.sort_by(|a, b| a.cmp(&b, &multibuffer).unwrap());
2781                }
2782                40..=44 if !anchors.is_empty() => {
2783                    let multibuffer = multibuffer.read(cx).read(cx);
2784
2785                    anchors = multibuffer
2786                        .refresh_anchors(&anchors)
2787                        .into_iter()
2788                        .map(|a| a.1)
2789                        .collect();
2790
2791                    // Ensure anchors point to a valid excerpt after refreshing them.
2792                    let mut cursor = multibuffer.excerpts.cursor::<Option<&ExcerptId>>();
2793                    for anchor in &anchors {
2794                        if anchor.excerpt_id == ExcerptId::min()
2795                            || anchor.excerpt_id == ExcerptId::max()
2796                        {
2797                            continue;
2798                        }
2799
2800                        cursor.seek_forward(&Some(&anchor.excerpt_id), Bias::Left, &());
2801                        let excerpt = cursor.item().unwrap();
2802                        assert_eq!(excerpt.id, anchor.excerpt_id);
2803                        assert!(excerpt.contains(anchor));
2804                    }
2805                }
2806                _ => {
2807                    let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
2808                        let base_text = RandomCharIter::new(&mut rng).take(10).collect::<String>();
2809                        buffers.push(cx.add_model(|cx| Buffer::new(0, base_text, cx)));
2810                        buffers.last().unwrap()
2811                    } else {
2812                        buffers.choose(&mut rng).unwrap()
2813                    };
2814
2815                    let buffer = buffer_handle.read(cx);
2816                    let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
2817                    let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
2818                    let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
2819                    let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len());
2820                    let prev_excerpt_id = excerpt_ids
2821                        .get(prev_excerpt_ix)
2822                        .cloned()
2823                        .unwrap_or(ExcerptId::max());
2824                    let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len());
2825
2826                    log::info!(
2827                        "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}",
2828                        excerpt_ix,
2829                        expected_excerpts.len(),
2830                        buffer_handle.id(),
2831                        buffer.text(),
2832                        start_ix..end_ix,
2833                        &buffer.text()[start_ix..end_ix]
2834                    );
2835
2836                    let excerpt_id = multibuffer.update(cx, |multibuffer, cx| {
2837                        multibuffer.insert_excerpt_after(
2838                            &prev_excerpt_id,
2839                            ExcerptProperties {
2840                                buffer: &buffer_handle,
2841                                range: start_ix..end_ix,
2842                            },
2843                            cx,
2844                        )
2845                    });
2846
2847                    excerpt_ids.insert(excerpt_ix, excerpt_id);
2848                    expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range));
2849                }
2850            }
2851
2852            if rng.gen_bool(0.3) {
2853                multibuffer.update(cx, |multibuffer, cx| {
2854                    old_versions.push((multibuffer.snapshot(cx), multibuffer.subscribe()));
2855                })
2856            }
2857
2858            let snapshot = multibuffer.read(cx).snapshot(cx);
2859
2860            let mut excerpt_starts = Vec::new();
2861            let mut expected_text = String::new();
2862            let mut expected_buffer_rows = Vec::new();
2863            for (buffer, range) in &expected_excerpts {
2864                let buffer = buffer.read(cx);
2865                let buffer_range = range.to_offset(buffer);
2866
2867                excerpt_starts.push(TextSummary::from(expected_text.as_str()));
2868                expected_text.extend(buffer.text_for_range(buffer_range.clone()));
2869                expected_text.push('\n');
2870
2871                let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
2872                    ..=buffer.offset_to_point(buffer_range.end).row;
2873                for row in buffer_row_range {
2874                    expected_buffer_rows.push(Some(row));
2875                }
2876            }
2877            // Remove final trailing newline.
2878            if !expected_excerpts.is_empty() {
2879                expected_text.pop();
2880            }
2881
2882            // Always report one buffer row
2883            if expected_buffer_rows.is_empty() {
2884                expected_buffer_rows.push(Some(0));
2885            }
2886
2887            assert_eq!(snapshot.text(), expected_text);
2888            log::info!("MultiBuffer text: {:?}", expected_text);
2889
2890            assert_eq!(
2891                snapshot.buffer_rows(0).collect::<Vec<_>>(),
2892                expected_buffer_rows,
2893            );
2894
2895            for _ in 0..5 {
2896                let start_row = rng.gen_range(0..=expected_buffer_rows.len());
2897                assert_eq!(
2898                    snapshot.buffer_rows(start_row as u32).collect::<Vec<_>>(),
2899                    &expected_buffer_rows[start_row..],
2900                    "buffer_rows({})",
2901                    start_row
2902                );
2903            }
2904
2905            assert_eq!(
2906                snapshot.max_buffer_row(),
2907                expected_buffer_rows
2908                    .into_iter()
2909                    .filter_map(|r| r)
2910                    .max()
2911                    .unwrap()
2912            );
2913
2914            let mut excerpt_starts = excerpt_starts.into_iter();
2915            for (buffer, range) in &expected_excerpts {
2916                let buffer_id = buffer.id();
2917                let buffer = buffer.read(cx);
2918                let buffer_range = range.to_offset(buffer);
2919                let buffer_start_point = buffer.offset_to_point(buffer_range.start);
2920                let buffer_start_point_utf16 =
2921                    buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
2922
2923                let excerpt_start = excerpt_starts.next().unwrap();
2924                let mut offset = excerpt_start.bytes;
2925                let mut buffer_offset = buffer_range.start;
2926                let mut point = excerpt_start.lines;
2927                let mut buffer_point = buffer_start_point;
2928                let mut point_utf16 = excerpt_start.lines_utf16;
2929                let mut buffer_point_utf16 = buffer_start_point_utf16;
2930                for ch in buffer
2931                    .snapshot()
2932                    .chunks(buffer_range.clone(), None)
2933                    .flat_map(|c| c.text.chars())
2934                {
2935                    for _ in 0..ch.len_utf8() {
2936                        let left_offset = snapshot.clip_offset(offset, Bias::Left);
2937                        let right_offset = snapshot.clip_offset(offset, Bias::Right);
2938                        let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
2939                        let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
2940                        assert_eq!(
2941                            left_offset,
2942                            excerpt_start.bytes + (buffer_left_offset - buffer_range.start),
2943                            "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
2944                            offset,
2945                            buffer_id,
2946                            buffer_offset,
2947                        );
2948                        assert_eq!(
2949                            right_offset,
2950                            excerpt_start.bytes + (buffer_right_offset - buffer_range.start),
2951                            "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
2952                            offset,
2953                            buffer_id,
2954                            buffer_offset,
2955                        );
2956
2957                        let left_point = snapshot.clip_point(point, Bias::Left);
2958                        let right_point = snapshot.clip_point(point, Bias::Right);
2959                        let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
2960                        let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
2961                        assert_eq!(
2962                            left_point,
2963                            excerpt_start.lines + (buffer_left_point - buffer_start_point),
2964                            "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
2965                            point,
2966                            buffer_id,
2967                            buffer_point,
2968                        );
2969                        assert_eq!(
2970                            right_point,
2971                            excerpt_start.lines + (buffer_right_point - buffer_start_point),
2972                            "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
2973                            point,
2974                            buffer_id,
2975                            buffer_point,
2976                        );
2977
2978                        assert_eq!(
2979                            snapshot.point_to_offset(left_point),
2980                            left_offset,
2981                            "point_to_offset({:?})",
2982                            left_point,
2983                        );
2984                        assert_eq!(
2985                            snapshot.offset_to_point(left_offset),
2986                            left_point,
2987                            "offset_to_point({:?})",
2988                            left_offset,
2989                        );
2990
2991                        offset += 1;
2992                        buffer_offset += 1;
2993                        if ch == '\n' {
2994                            point += Point::new(1, 0);
2995                            buffer_point += Point::new(1, 0);
2996                        } else {
2997                            point += Point::new(0, 1);
2998                            buffer_point += Point::new(0, 1);
2999                        }
3000                    }
3001
3002                    for _ in 0..ch.len_utf16() {
3003                        let left_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Left);
3004                        let right_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Right);
3005                        let buffer_left_point_utf16 =
3006                            buffer.clip_point_utf16(buffer_point_utf16, Bias::Left);
3007                        let buffer_right_point_utf16 =
3008                            buffer.clip_point_utf16(buffer_point_utf16, Bias::Right);
3009                        assert_eq!(
3010                            left_point_utf16,
3011                            excerpt_start.lines_utf16
3012                                + (buffer_left_point_utf16 - buffer_start_point_utf16),
3013                            "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
3014                            point_utf16,
3015                            buffer_id,
3016                            buffer_point_utf16,
3017                        );
3018                        assert_eq!(
3019                            right_point_utf16,
3020                            excerpt_start.lines_utf16
3021                                + (buffer_right_point_utf16 - buffer_start_point_utf16),
3022                            "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
3023                            point_utf16,
3024                            buffer_id,
3025                            buffer_point_utf16,
3026                        );
3027
3028                        if ch == '\n' {
3029                            point_utf16 += PointUtf16::new(1, 0);
3030                            buffer_point_utf16 += PointUtf16::new(1, 0);
3031                        } else {
3032                            point_utf16 += PointUtf16::new(0, 1);
3033                            buffer_point_utf16 += PointUtf16::new(0, 1);
3034                        }
3035                    }
3036                }
3037            }
3038
3039            for (row, line) in expected_text.split('\n').enumerate() {
3040                assert_eq!(
3041                    snapshot.line_len(row as u32),
3042                    line.len() as u32,
3043                    "line_len({}).",
3044                    row
3045                );
3046            }
3047
3048            let text_rope = Rope::from(expected_text.as_str());
3049            for _ in 0..10 {
3050                let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
3051                let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
3052
3053                let text_for_range = snapshot
3054                    .text_for_range(start_ix..end_ix)
3055                    .collect::<String>();
3056                assert_eq!(
3057                    text_for_range,
3058                    &expected_text[start_ix..end_ix],
3059                    "incorrect text for range {:?}",
3060                    start_ix..end_ix
3061                );
3062
3063                let excerpted_buffer_ranges =
3064                    multibuffer.read(cx).excerpted_buffers(start_ix..end_ix, cx);
3065                let excerpted_buffers_text = excerpted_buffer_ranges
3066                    .into_iter()
3067                    .map(|(buffer, buffer_range)| {
3068                        buffer
3069                            .read(cx)
3070                            .text_for_range(buffer_range)
3071                            .collect::<String>()
3072                    })
3073                    .collect::<Vec<_>>()
3074                    .join("\n");
3075                assert_eq!(excerpted_buffers_text, text_for_range);
3076
3077                let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
3078                assert_eq!(
3079                    snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
3080                    expected_summary,
3081                    "incorrect summary for range {:?}",
3082                    start_ix..end_ix
3083                );
3084            }
3085
3086            // Anchor resolution
3087            for (anchor, resolved_offset) in anchors
3088                .iter()
3089                .zip(snapshot.summaries_for_anchors::<usize, _>(&anchors))
3090            {
3091                assert!(resolved_offset <= snapshot.len());
3092                assert_eq!(
3093                    snapshot.summary_for_anchor::<usize>(anchor),
3094                    resolved_offset
3095                );
3096            }
3097
3098            for _ in 0..10 {
3099                let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
3100                assert_eq!(
3101                    snapshot.reversed_chars_at(end_ix).collect::<String>(),
3102                    expected_text[..end_ix].chars().rev().collect::<String>(),
3103                );
3104            }
3105
3106            for _ in 0..10 {
3107                let end_ix = rng.gen_range(0..=text_rope.len());
3108                let start_ix = rng.gen_range(0..=end_ix);
3109                assert_eq!(
3110                    snapshot
3111                        .bytes_in_range(start_ix..end_ix)
3112                        .flatten()
3113                        .copied()
3114                        .collect::<Vec<_>>(),
3115                    expected_text.as_bytes()[start_ix..end_ix].to_vec(),
3116                    "bytes_in_range({:?})",
3117                    start_ix..end_ix,
3118                );
3119            }
3120        }
3121
3122        let snapshot = multibuffer.read(cx).snapshot(cx);
3123        for (old_snapshot, subscription) in old_versions {
3124            let edits = subscription.consume().into_inner();
3125
3126            log::info!(
3127                "applying subscription edits to old text: {:?}: {:?}",
3128                old_snapshot.text(),
3129                edits,
3130            );
3131
3132            let mut text = old_snapshot.text();
3133            for edit in edits {
3134                let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
3135                text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
3136            }
3137            assert_eq!(text.to_string(), snapshot.text());
3138        }
3139    }
3140
3141    #[gpui::test]
3142    fn test_history(cx: &mut MutableAppContext) {
3143        let buffer_1 = cx.add_model(|cx| Buffer::new(0, "1234", cx));
3144        let buffer_2 = cx.add_model(|cx| Buffer::new(0, "5678", cx));
3145        let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
3146        let group_interval = multibuffer.read(cx).history.group_interval;
3147        multibuffer.update(cx, |multibuffer, cx| {
3148            multibuffer.push_excerpt(
3149                ExcerptProperties {
3150                    buffer: &buffer_1,
3151                    range: 0..buffer_1.read(cx).len(),
3152                },
3153                cx,
3154            );
3155            multibuffer.push_excerpt(
3156                ExcerptProperties {
3157                    buffer: &buffer_2,
3158                    range: 0..buffer_2.read(cx).len(),
3159                },
3160                cx,
3161            );
3162        });
3163
3164        let mut now = Instant::now();
3165
3166        multibuffer.update(cx, |multibuffer, cx| {
3167            multibuffer.start_transaction_at(now, cx);
3168            multibuffer.edit(
3169                [
3170                    Point::new(0, 0)..Point::new(0, 0),
3171                    Point::new(1, 0)..Point::new(1, 0),
3172                ],
3173                "A",
3174                cx,
3175            );
3176            multibuffer.edit(
3177                [
3178                    Point::new(0, 1)..Point::new(0, 1),
3179                    Point::new(1, 1)..Point::new(1, 1),
3180                ],
3181                "B",
3182                cx,
3183            );
3184            multibuffer.end_transaction_at(now, cx);
3185            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
3186
3187            now += 2 * group_interval;
3188            multibuffer.start_transaction_at(now, cx);
3189            multibuffer.edit([2..2], "C", cx);
3190            multibuffer.end_transaction_at(now, cx);
3191            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
3192
3193            multibuffer.undo(cx);
3194            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
3195
3196            multibuffer.undo(cx);
3197            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
3198
3199            multibuffer.redo(cx);
3200            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
3201
3202            multibuffer.redo(cx);
3203            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
3204
3205            buffer_1.update(cx, |buffer_1, cx| buffer_1.undo(cx));
3206            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
3207
3208            multibuffer.undo(cx);
3209            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
3210
3211            multibuffer.redo(cx);
3212            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
3213
3214            multibuffer.redo(cx);
3215            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
3216
3217            multibuffer.undo(cx);
3218            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
3219
3220            buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
3221            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
3222
3223            multibuffer.undo(cx);
3224            assert_eq!(multibuffer.read(cx).text(), "C1234\n5678");
3225        });
3226    }
3227}