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, Selection,
  10    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: 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
  67pub trait FromAnchor: 'static {
  68    fn from_anchor(anchor: &Anchor, snapshot: &MultiBufferSnapshot) -> Self;
  69}
  70
  71#[derive(Debug)]
  72struct BufferState {
  73    buffer: ModelHandle<Buffer>,
  74    last_version: clock::Global,
  75    last_parse_count: usize,
  76    last_diagnostics_update_count: usize,
  77    excerpts: Vec<ExcerptId>,
  78}
  79
  80#[derive(Clone, Default)]
  81pub struct MultiBufferSnapshot {
  82    excerpts: SumTree<Excerpt>,
  83    parse_count: usize,
  84    diagnostics_update_count: usize,
  85    is_dirty: bool,
  86    has_conflict: bool,
  87}
  88
  89pub struct ExcerptProperties<'a, T> {
  90    pub buffer: &'a ModelHandle<Buffer>,
  91    pub range: Range<T>,
  92}
  93
  94#[derive(Clone)]
  95struct Excerpt {
  96    id: ExcerptId,
  97    buffer_id: usize,
  98    buffer: BufferSnapshot,
  99    range: Range<text::Anchor>,
 100    max_buffer_row: u32,
 101    text_summary: TextSummary,
 102    has_trailing_newline: bool,
 103}
 104
 105#[derive(Clone, Debug, Default)]
 106struct ExcerptSummary {
 107    excerpt_id: ExcerptId,
 108    max_buffer_row: u32,
 109    text: TextSummary,
 110}
 111
 112pub struct MultiBufferRows<'a> {
 113    buffer_row_range: Range<u32>,
 114    excerpts: Cursor<'a, Excerpt, Point>,
 115}
 116
 117pub struct MultiBufferChunks<'a> {
 118    range: Range<usize>,
 119    excerpts: Cursor<'a, Excerpt, usize>,
 120    excerpt_chunks: Option<ExcerptChunks<'a>>,
 121    theme: Option<&'a SyntaxTheme>,
 122}
 123
 124pub struct MultiBufferBytes<'a> {
 125    range: Range<usize>,
 126    excerpts: Cursor<'a, Excerpt, usize>,
 127    excerpt_bytes: Option<ExcerptBytes<'a>>,
 128    chunk: &'a [u8],
 129}
 130
 131struct ExcerptChunks<'a> {
 132    content_chunks: BufferChunks<'a>,
 133    footer_height: usize,
 134}
 135
 136struct ExcerptBytes<'a> {
 137    content_bytes: language::rope::Bytes<'a>,
 138    footer_height: usize,
 139}
 140
 141impl MultiBuffer {
 142    pub fn new(replica_id: ReplicaId) -> Self {
 143        Self {
 144            snapshot: Default::default(),
 145            buffers: Default::default(),
 146            subscriptions: Default::default(),
 147            singleton: false,
 148            replica_id,
 149            history: History {
 150                next_transaction_id: Default::default(),
 151                undo_stack: Default::default(),
 152                redo_stack: Default::default(),
 153                transaction_depth: 0,
 154                group_interval: Duration::from_millis(300),
 155            },
 156        }
 157    }
 158
 159    pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
 160        let mut this = Self::new(buffer.read(cx).replica_id());
 161        this.singleton = true;
 162        this.push_excerpt(
 163            ExcerptProperties {
 164                buffer: &buffer,
 165                range: text::Anchor::min()..text::Anchor::max(),
 166            },
 167            cx,
 168        );
 169        this
 170    }
 171
 172    #[cfg(any(test, feature = "test-support"))]
 173    pub fn build_simple(text: &str, cx: &mut gpui::MutableAppContext) -> ModelHandle<Self> {
 174        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
 175        cx.add_model(|cx| Self::singleton(buffer, cx))
 176    }
 177
 178    #[cfg(any(test, feature = "test-support"))]
 179    pub fn build_random(
 180        mut rng: &mut impl rand::Rng,
 181        cx: &mut gpui::MutableAppContext,
 182    ) -> ModelHandle<Self> {
 183        use rand::prelude::*;
 184        use std::env;
 185        use text::RandomCharIter;
 186
 187        let max_excerpts = env::var("MAX_EXCERPTS")
 188            .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable"))
 189            .unwrap_or(5);
 190        let excerpts = rng.gen_range(1..=max_excerpts);
 191
 192        cx.add_model(|cx| {
 193            let mut multibuffer = MultiBuffer::new(0);
 194            let mut buffers = Vec::new();
 195            for _ in 0..excerpts {
 196                let buffer_handle = if rng.gen() || buffers.is_empty() {
 197                    let text = RandomCharIter::new(&mut rng).take(10).collect::<String>();
 198                    buffers.push(cx.add_model(|cx| Buffer::new(0, text, cx)));
 199                    let buffer = buffers.last().unwrap();
 200                    log::info!(
 201                        "Creating new buffer {} with text: {:?}",
 202                        buffer.id(),
 203                        buffer.read(cx).text()
 204                    );
 205                    buffers.last().unwrap()
 206                } else {
 207                    buffers.choose(rng).unwrap()
 208                };
 209
 210                let buffer = buffer_handle.read(cx);
 211                let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
 212                let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
 213                let header_height = rng.gen_range(0..=5);
 214                log::info!(
 215                    "Inserting excerpt from buffer {} with header height {} and range {:?}: {:?}",
 216                    buffer_handle.id(),
 217                    header_height,
 218                    start_ix..end_ix,
 219                    &buffer.text()[start_ix..end_ix]
 220                );
 221
 222                multibuffer.push_excerpt(
 223                    ExcerptProperties {
 224                        buffer: buffer_handle,
 225                        range: start_ix..end_ix,
 226                    },
 227                    cx,
 228                );
 229            }
 230            multibuffer
 231        })
 232    }
 233
 234    pub fn replica_id(&self) -> ReplicaId {
 235        self.replica_id
 236    }
 237
 238    pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot {
 239        self.sync(cx);
 240        self.snapshot.borrow().clone()
 241    }
 242
 243    pub fn read(&self, cx: &AppContext) -> Ref<MultiBufferSnapshot> {
 244        self.sync(cx);
 245        self.snapshot.borrow()
 246    }
 247
 248    pub fn as_singleton(&self) -> Option<&ModelHandle<Buffer>> {
 249        if self.singleton {
 250            return Some(&self.buffers.values().next().unwrap().buffer);
 251        } else {
 252            None
 253        }
 254    }
 255
 256    pub fn subscribe(&mut self) -> Subscription {
 257        self.subscriptions.subscribe()
 258    }
 259
 260    pub fn edit<I, S, T>(&mut self, ranges: I, new_text: T, cx: &mut ModelContext<Self>)
 261    where
 262        I: IntoIterator<Item = Range<S>>,
 263        S: ToOffset,
 264        T: Into<String>,
 265    {
 266        self.edit_internal(ranges, new_text, false, cx)
 267    }
 268
 269    pub fn edit_with_autoindent<I, S, T>(
 270        &mut self,
 271        ranges: I,
 272        new_text: T,
 273        cx: &mut ModelContext<Self>,
 274    ) where
 275        I: IntoIterator<Item = Range<S>>,
 276        S: ToOffset,
 277        T: Into<String>,
 278    {
 279        self.edit_internal(ranges, new_text, true, cx)
 280    }
 281
 282    pub fn edit_internal<I, S, T>(
 283        &mut self,
 284        ranges_iter: I,
 285        new_text: T,
 286        autoindent: bool,
 287        cx: &mut ModelContext<Self>,
 288    ) where
 289        I: IntoIterator<Item = Range<S>>,
 290        S: ToOffset,
 291        T: Into<String>,
 292    {
 293        if let Some(buffer) = self.as_singleton() {
 294            let snapshot = self.read(cx);
 295            let ranges = ranges_iter
 296                .into_iter()
 297                .map(|range| range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot));
 298            return buffer.update(cx, |buffer, cx| {
 299                if autoindent {
 300                    buffer.edit_with_autoindent(ranges, new_text, cx)
 301                } else {
 302                    buffer.edit(ranges, new_text, cx)
 303                }
 304            });
 305        }
 306
 307        let snapshot = self.read(cx);
 308        let mut buffer_edits: HashMap<usize, Vec<(Range<usize>, bool)>> = Default::default();
 309        let mut cursor = snapshot.excerpts.cursor::<usize>();
 310        for range in ranges_iter {
 311            let start = range.start.to_offset(&snapshot);
 312            let end = range.end.to_offset(&snapshot);
 313            cursor.seek(&start, Bias::Right, &());
 314            if cursor.item().is_none() && start == *cursor.start() {
 315                cursor.prev(&());
 316            }
 317            let start_excerpt = cursor.item().expect("start offset out of bounds");
 318            let start_overshoot = start - cursor.start();
 319            let buffer_start =
 320                start_excerpt.range.start.to_offset(&start_excerpt.buffer) + start_overshoot;
 321
 322            cursor.seek(&end, Bias::Right, &());
 323            if cursor.item().is_none() && end == *cursor.start() {
 324                cursor.prev(&());
 325            }
 326            let end_excerpt = cursor.item().expect("end offset out of bounds");
 327            let end_overshoot = end - cursor.start();
 328            let buffer_end = end_excerpt.range.start.to_offset(&end_excerpt.buffer) + end_overshoot;
 329
 330            if start_excerpt.id == end_excerpt.id {
 331                buffer_edits
 332                    .entry(start_excerpt.buffer_id)
 333                    .or_insert(Vec::new())
 334                    .push((buffer_start..buffer_end, true));
 335            } else {
 336                let start_excerpt_range =
 337                    buffer_start..start_excerpt.range.end.to_offset(&start_excerpt.buffer);
 338                let end_excerpt_range =
 339                    end_excerpt.range.start.to_offset(&end_excerpt.buffer)..buffer_end;
 340                buffer_edits
 341                    .entry(start_excerpt.buffer_id)
 342                    .or_insert(Vec::new())
 343                    .push((start_excerpt_range, true));
 344                buffer_edits
 345                    .entry(end_excerpt.buffer_id)
 346                    .or_insert(Vec::new())
 347                    .push((end_excerpt_range, false));
 348
 349                cursor.seek(&start, Bias::Right, &());
 350                cursor.next(&());
 351                while let Some(excerpt) = cursor.item() {
 352                    if excerpt.id == end_excerpt.id {
 353                        break;
 354                    }
 355                    buffer_edits
 356                        .entry(excerpt.buffer_id)
 357                        .or_insert(Vec::new())
 358                        .push((excerpt.range.to_offset(&excerpt.buffer), false));
 359                    cursor.next(&());
 360                }
 361            }
 362        }
 363
 364        let new_text = new_text.into();
 365        for (buffer_id, mut edits) in buffer_edits {
 366            edits.sort_unstable_by_key(|(range, _)| range.start);
 367            self.buffers[&buffer_id].buffer.update(cx, |buffer, cx| {
 368                let mut edits = edits.into_iter().peekable();
 369                let mut insertions = Vec::new();
 370                let mut deletions = Vec::new();
 371                while let Some((mut range, mut is_insertion)) = edits.next() {
 372                    while let Some((next_range, next_is_insertion)) = edits.peek() {
 373                        if range.end >= next_range.start {
 374                            range.end = cmp::max(next_range.end, range.end);
 375                            is_insertion |= *next_is_insertion;
 376                            edits.next();
 377                        } else {
 378                            break;
 379                        }
 380                    }
 381
 382                    if is_insertion {
 383                        insertions.push(
 384                            buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
 385                        );
 386                    } else if !range.is_empty() {
 387                        deletions.push(
 388                            buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
 389                        );
 390                    }
 391                }
 392
 393                if autoindent {
 394                    buffer.edit_with_autoindent(deletions, "", cx);
 395                    buffer.edit_with_autoindent(insertions, new_text.clone(), cx);
 396                } else {
 397                    buffer.edit(deletions, "", cx);
 398                    buffer.edit(insertions, new_text.clone(), cx);
 399                }
 400            })
 401        }
 402    }
 403
 404    pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 405        self.start_transaction_at(Instant::now(), cx)
 406    }
 407
 408    pub(crate) fn start_transaction_at(
 409        &mut self,
 410        now: Instant,
 411        cx: &mut ModelContext<Self>,
 412    ) -> Option<TransactionId> {
 413        if let Some(buffer) = self.as_singleton() {
 414            return buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
 415        }
 416
 417        for BufferState { buffer, .. } in self.buffers.values() {
 418            buffer.update(cx, |buffer, _| buffer.start_transaction_at(now));
 419        }
 420        self.history.start_transaction(now)
 421    }
 422
 423    pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 424        self.end_transaction_at(Instant::now(), cx)
 425    }
 426
 427    pub(crate) fn end_transaction_at(
 428        &mut self,
 429        now: Instant,
 430        cx: &mut ModelContext<Self>,
 431    ) -> Option<TransactionId> {
 432        if let Some(buffer) = self.as_singleton() {
 433            return buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx));
 434        }
 435
 436        let mut buffer_transactions = HashSet::default();
 437        for BufferState { buffer, .. } in self.buffers.values() {
 438            if let Some(transaction_id) =
 439                buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
 440            {
 441                buffer_transactions.insert((buffer.id(), transaction_id));
 442            }
 443        }
 444
 445        if self.history.end_transaction(now, buffer_transactions) {
 446            let transaction_id = self.history.group().unwrap();
 447            Some(transaction_id)
 448        } else {
 449            None
 450        }
 451    }
 452
 453    pub fn set_active_selections(
 454        &mut self,
 455        selections: &[Selection<Anchor>],
 456        cx: &mut ModelContext<Self>,
 457    ) {
 458        let mut selections_by_buffer: HashMap<usize, Vec<Selection<text::Anchor>>> =
 459            Default::default();
 460        let snapshot = self.read(cx);
 461        let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();
 462        for selection in selections {
 463            cursor.seek(&Some(&selection.start.excerpt_id), Bias::Left, &());
 464            while let Some(excerpt) = cursor.item() {
 465                if excerpt.id > selection.end.excerpt_id {
 466                    break;
 467                }
 468
 469                let mut start = excerpt.range.start.clone();
 470                let mut end = excerpt.range.end.clone();
 471                if excerpt.id == selection.start.excerpt_id {
 472                    start = selection.start.text_anchor.clone();
 473                }
 474                if excerpt.id == selection.end.excerpt_id {
 475                    end = selection.end.text_anchor.clone();
 476                }
 477                selections_by_buffer
 478                    .entry(excerpt.buffer_id)
 479                    .or_default()
 480                    .push(Selection {
 481                        id: selection.id,
 482                        start,
 483                        end,
 484                        reversed: selection.reversed,
 485                        goal: selection.goal,
 486                    });
 487
 488                cursor.next(&());
 489            }
 490        }
 491
 492        for (buffer_id, mut selections) in selections_by_buffer {
 493            self.buffers[&buffer_id].buffer.update(cx, |buffer, cx| {
 494                selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap());
 495                let mut selections = selections.into_iter().peekable();
 496                let merged_selections = Arc::from_iter(iter::from_fn(|| {
 497                    let mut selection = selections.next()?;
 498                    while let Some(next_selection) = selections.peek() {
 499                        if selection
 500                            .end
 501                            .cmp(&next_selection.start, buffer)
 502                            .unwrap()
 503                            .is_ge()
 504                        {
 505                            let next_selection = selections.next().unwrap();
 506                            if next_selection
 507                                .end
 508                                .cmp(&selection.end, buffer)
 509                                .unwrap()
 510                                .is_ge()
 511                            {
 512                                selection.end = next_selection.end;
 513                            }
 514                        } else {
 515                            break;
 516                        }
 517                    }
 518                    Some(selection)
 519                }));
 520                buffer.set_active_selections(merged_selections, cx);
 521            });
 522        }
 523    }
 524
 525    pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
 526        for buffer in self.buffers.values() {
 527            buffer
 528                .buffer
 529                .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
 530        }
 531    }
 532
 533    pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 534        if let Some(buffer) = self.as_singleton() {
 535            return buffer.update(cx, |buffer, cx| buffer.undo(cx));
 536        }
 537
 538        while let Some(transaction) = self.history.pop_undo() {
 539            let mut undone = false;
 540            for (buffer_id, buffer_transaction_id) in &transaction.buffer_transactions {
 541                if let Some(BufferState { buffer, .. }) = self.buffers.get(&buffer_id) {
 542                    undone |= buffer.update(cx, |buf, cx| {
 543                        buf.undo_transaction(*buffer_transaction_id, cx)
 544                    });
 545                }
 546            }
 547
 548            if undone {
 549                return Some(transaction.id);
 550            }
 551        }
 552
 553        None
 554    }
 555
 556    pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 557        if let Some(buffer) = self.as_singleton() {
 558            return buffer.update(cx, |buffer, cx| buffer.redo(cx));
 559        }
 560
 561        while let Some(transaction) = self.history.pop_redo() {
 562            let mut redone = false;
 563            for (buffer_id, buffer_transaction_id) in &transaction.buffer_transactions {
 564                if let Some(BufferState { buffer, .. }) = self.buffers.get(&buffer_id) {
 565                    redone |= buffer.update(cx, |buf, cx| {
 566                        buf.redo_transaction(*buffer_transaction_id, cx)
 567                    });
 568                }
 569            }
 570
 571            if redone {
 572                return Some(transaction.id);
 573            }
 574        }
 575
 576        None
 577    }
 578
 579    pub fn push_excerpt<O>(
 580        &mut self,
 581        props: ExcerptProperties<O>,
 582        cx: &mut ModelContext<Self>,
 583    ) -> ExcerptId
 584    where
 585        O: text::ToOffset,
 586    {
 587        assert_eq!(self.history.transaction_depth, 0);
 588        self.sync(cx);
 589
 590        let buffer = props.buffer.clone();
 591        cx.observe(&buffer, |_, _, cx| cx.notify()).detach();
 592        cx.subscribe(&buffer, Self::on_buffer_event).detach();
 593
 594        let buffer_snapshot = buffer.read(cx).snapshot();
 595        let range = buffer_snapshot.anchor_before(&props.range.start)
 596            ..buffer_snapshot.anchor_after(&props.range.end);
 597        let last_version = buffer_snapshot.version().clone();
 598        let last_parse_count = buffer_snapshot.parse_count();
 599        let last_diagnostics_update_count = buffer_snapshot.diagnostics_update_count();
 600
 601        let mut snapshot = self.snapshot.borrow_mut();
 602        let mut prev_id = None;
 603        let edit_start = snapshot.excerpts.summary().text.bytes;
 604        snapshot.excerpts.update_last(
 605            |excerpt| {
 606                excerpt.has_trailing_newline = true;
 607                prev_id = Some(excerpt.id.clone());
 608            },
 609            &(),
 610        );
 611
 612        let id = ExcerptId::between(&prev_id.unwrap_or(ExcerptId::min()), &ExcerptId::max());
 613        let excerpt = Excerpt::new(id.clone(), buffer.id(), buffer_snapshot, range, false);
 614        snapshot.excerpts.push(excerpt, &());
 615        self.buffers
 616            .entry(props.buffer.id())
 617            .or_insert_with(|| BufferState {
 618                buffer,
 619                last_version,
 620                last_parse_count,
 621                last_diagnostics_update_count,
 622                excerpts: Default::default(),
 623            })
 624            .excerpts
 625            .push(id.clone());
 626        self.subscriptions.publish_mut([Edit {
 627            old: edit_start..edit_start,
 628            new: edit_start..snapshot.excerpts.summary().text.bytes,
 629        }]);
 630
 631        cx.notify();
 632
 633        id
 634    }
 635
 636    fn on_buffer_event(
 637        &mut self,
 638        _: ModelHandle<Buffer>,
 639        event: &Event,
 640        cx: &mut ModelContext<Self>,
 641    ) {
 642        cx.emit(event.clone());
 643    }
 644
 645    pub fn save(&mut self, cx: &mut ModelContext<Self>) -> Result<Task<Result<()>>> {
 646        let mut save_tasks = Vec::new();
 647        for BufferState { buffer, .. } in self.buffers.values() {
 648            save_tasks.push(buffer.update(cx, |buffer, cx| buffer.save(cx))?);
 649        }
 650
 651        Ok(cx.spawn(|_, _| async move {
 652            for save in save_tasks {
 653                save.await?;
 654            }
 655            Ok(())
 656        }))
 657    }
 658
 659    pub fn language<'a>(&self, cx: &'a AppContext) -> Option<&'a Arc<Language>> {
 660        self.buffers
 661            .values()
 662            .next()
 663            .and_then(|state| state.buffer.read(cx).language())
 664    }
 665
 666    pub fn file<'a>(&self, cx: &'a AppContext) -> Option<&'a dyn File> {
 667        self.as_singleton()?.read(cx).file()
 668    }
 669
 670    #[cfg(test)]
 671    pub fn is_parsing(&self, cx: &AppContext) -> bool {
 672        self.as_singleton().unwrap().read(cx).is_parsing()
 673    }
 674
 675    fn sync(&self, cx: &AppContext) {
 676        let mut snapshot = self.snapshot.borrow_mut();
 677        let mut excerpts_to_edit = Vec::new();
 678        let mut reparsed = false;
 679        let mut diagnostics_updated = false;
 680        let mut is_dirty = false;
 681        let mut has_conflict = false;
 682        for buffer_state in self.buffers.values() {
 683            let buffer = buffer_state.buffer.read(cx);
 684            let buffer_edited = buffer.version().gt(&buffer_state.last_version);
 685            let buffer_reparsed = buffer.parse_count() > buffer_state.last_parse_count;
 686            let buffer_diagnostics_updated =
 687                buffer.diagnostics_update_count() > buffer_state.last_diagnostics_update_count;
 688            if buffer_edited || buffer_reparsed || buffer_diagnostics_updated {
 689                excerpts_to_edit.extend(
 690                    buffer_state
 691                        .excerpts
 692                        .iter()
 693                        .map(|excerpt_id| (excerpt_id, buffer_state, buffer_edited)),
 694                );
 695            }
 696
 697            reparsed |= buffer_reparsed;
 698            diagnostics_updated |= buffer_diagnostics_updated;
 699            is_dirty |= buffer.is_dirty();
 700            has_conflict |= buffer.has_conflict();
 701        }
 702        if reparsed {
 703            snapshot.parse_count += 1;
 704        }
 705        if diagnostics_updated {
 706            snapshot.diagnostics_update_count += 1;
 707        }
 708        snapshot.is_dirty = is_dirty;
 709        snapshot.has_conflict = has_conflict;
 710
 711        excerpts_to_edit.sort_unstable_by_key(|(excerpt_id, _, _)| *excerpt_id);
 712
 713        let mut edits = Vec::new();
 714        let mut new_excerpts = SumTree::new();
 715        let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>();
 716
 717        for (id, buffer_state, buffer_edited) in excerpts_to_edit {
 718            new_excerpts.push_tree(cursor.slice(&Some(id), Bias::Left, &()), &());
 719            let old_excerpt = cursor.item().unwrap();
 720            let buffer = buffer_state.buffer.read(cx);
 721
 722            let mut new_excerpt;
 723            if buffer_edited {
 724                edits.extend(
 725                    buffer
 726                        .edits_since_in_range::<usize>(
 727                            old_excerpt.buffer.version(),
 728                            old_excerpt.range.clone(),
 729                        )
 730                        .map(|mut edit| {
 731                            let excerpt_old_start = cursor.start().1;
 732                            let excerpt_new_start = new_excerpts.summary().text.bytes;
 733                            edit.old.start += excerpt_old_start;
 734                            edit.old.end += excerpt_old_start;
 735                            edit.new.start += excerpt_new_start;
 736                            edit.new.end += excerpt_new_start;
 737                            edit
 738                        }),
 739                );
 740
 741                new_excerpt = Excerpt::new(
 742                    id.clone(),
 743                    buffer_state.buffer.id(),
 744                    buffer.snapshot(),
 745                    old_excerpt.range.clone(),
 746                    old_excerpt.has_trailing_newline,
 747                );
 748            } else {
 749                new_excerpt = old_excerpt.clone();
 750                new_excerpt.buffer = buffer.snapshot();
 751            }
 752
 753            new_excerpts.push(new_excerpt, &());
 754            cursor.next(&());
 755        }
 756        new_excerpts.push_tree(cursor.suffix(&()), &());
 757
 758        drop(cursor);
 759        snapshot.excerpts = new_excerpts;
 760
 761        self.subscriptions.publish(edits);
 762    }
 763}
 764
 765#[cfg(any(test, feature = "test-support"))]
 766impl MultiBuffer {
 767    pub fn randomly_edit(
 768        &mut self,
 769        rng: &mut impl rand::Rng,
 770        count: usize,
 771        cx: &mut ModelContext<Self>,
 772    ) {
 773        use text::RandomCharIter;
 774
 775        let snapshot = self.read(cx);
 776        let mut old_ranges: Vec<Range<usize>> = Vec::new();
 777        for _ in 0..count {
 778            let last_end = old_ranges.last().map_or(0, |last_range| last_range.end + 1);
 779            if last_end > snapshot.len() {
 780                break;
 781            }
 782            let end_ix = snapshot.clip_offset(rng.gen_range(0..=last_end), Bias::Right);
 783            let start_ix = snapshot.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
 784            old_ranges.push(start_ix..end_ix);
 785        }
 786        let new_text_len = rng.gen_range(0..10);
 787        let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
 788        log::info!("mutating multi-buffer at {:?}: {:?}", old_ranges, new_text);
 789        drop(snapshot);
 790
 791        self.edit(old_ranges.iter().cloned(), new_text.as_str(), cx);
 792    }
 793}
 794
 795impl Entity for MultiBuffer {
 796    type Event = language::Event;
 797}
 798
 799impl MultiBufferSnapshot {
 800    pub fn text(&self) -> String {
 801        self.chunks(0..self.len(), None)
 802            .map(|chunk| chunk.text)
 803            .collect()
 804    }
 805
 806    pub fn reversed_chars_at<'a, T: ToOffset>(
 807        &'a self,
 808        position: T,
 809    ) -> impl Iterator<Item = char> + 'a {
 810        let mut offset = position.to_offset(self);
 811        let mut cursor = self.excerpts.cursor::<usize>();
 812        cursor.seek(&offset, Bias::Left, &());
 813        let mut excerpt_chunks = cursor.item().map(|excerpt| {
 814            let end_before_footer = cursor.start() + excerpt.text_summary.bytes;
 815            let start = excerpt.range.start.to_offset(&excerpt.buffer);
 816            let end = start + (cmp::min(offset, end_before_footer) - cursor.start());
 817            excerpt.buffer.reversed_chunks_in_range(start..end)
 818        });
 819        iter::from_fn(move || {
 820            if offset == *cursor.start() {
 821                cursor.prev(&());
 822                let excerpt = cursor.item()?;
 823                excerpt_chunks = Some(
 824                    excerpt
 825                        .buffer
 826                        .reversed_chunks_in_range(excerpt.range.clone()),
 827                );
 828            }
 829
 830            let excerpt = cursor.item().unwrap();
 831            if offset == cursor.end(&()) && excerpt.has_trailing_newline {
 832                offset -= 1;
 833                Some("\n")
 834            } else {
 835                let chunk = excerpt_chunks.as_mut().unwrap().next().unwrap();
 836                offset -= chunk.len();
 837                Some(chunk)
 838            }
 839        })
 840        .flat_map(|c| c.chars().rev())
 841    }
 842
 843    pub fn chars_at<'a, T: ToOffset>(&'a self, position: T) -> impl Iterator<Item = char> + 'a {
 844        let offset = position.to_offset(self);
 845        self.text_for_range(offset..self.len())
 846            .flat_map(|chunk| chunk.chars())
 847    }
 848
 849    pub fn text_for_range<'a, T: ToOffset>(
 850        &'a self,
 851        range: Range<T>,
 852    ) -> impl Iterator<Item = &'a str> {
 853        self.chunks(range, None).map(|chunk| chunk.text)
 854    }
 855
 856    pub fn is_line_blank(&self, row: u32) -> bool {
 857        self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row)))
 858            .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
 859    }
 860
 861    pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
 862    where
 863        T: ToOffset,
 864    {
 865        let position = position.to_offset(self);
 866        position == self.clip_offset(position, Bias::Left)
 867            && self
 868                .bytes_in_range(position..self.len())
 869                .flatten()
 870                .copied()
 871                .take(needle.len())
 872                .eq(needle.bytes())
 873    }
 874
 875    fn as_singleton(&self) -> Option<&BufferSnapshot> {
 876        let mut excerpts = self.excerpts.iter();
 877        let buffer = excerpts.next().map(|excerpt| &excerpt.buffer);
 878        if excerpts.next().is_none() {
 879            buffer
 880        } else {
 881            None
 882        }
 883    }
 884
 885    pub fn len(&self) -> usize {
 886        self.excerpts.summary().text.bytes
 887    }
 888
 889    pub fn max_buffer_row(&self) -> u32 {
 890        self.excerpts.summary().max_buffer_row
 891    }
 892
 893    pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
 894        let mut cursor = self.excerpts.cursor::<usize>();
 895        cursor.seek(&offset, Bias::Right, &());
 896        let overshoot = if let Some(excerpt) = cursor.item() {
 897            let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
 898            let buffer_offset = excerpt
 899                .buffer
 900                .clip_offset(excerpt_start + (offset - cursor.start()), bias);
 901            buffer_offset.saturating_sub(excerpt_start)
 902        } else {
 903            0
 904        };
 905        cursor.start() + overshoot
 906    }
 907
 908    pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
 909        let mut cursor = self.excerpts.cursor::<Point>();
 910        cursor.seek(&point, Bias::Right, &());
 911        let overshoot = if let Some(excerpt) = cursor.item() {
 912            let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
 913            let buffer_point = excerpt
 914                .buffer
 915                .clip_point(excerpt_start + (point - cursor.start()), bias);
 916            buffer_point.saturating_sub(excerpt_start)
 917        } else {
 918            Point::zero()
 919        };
 920        *cursor.start() + overshoot
 921    }
 922
 923    pub fn clip_point_utf16(&self, point: PointUtf16, bias: Bias) -> PointUtf16 {
 924        let mut cursor = self.excerpts.cursor::<PointUtf16>();
 925        cursor.seek(&point, Bias::Right, &());
 926        let overshoot = if let Some(excerpt) = cursor.item() {
 927            let excerpt_start = excerpt
 928                .buffer
 929                .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
 930            let buffer_point = excerpt
 931                .buffer
 932                .clip_point_utf16(excerpt_start + (point - cursor.start()), bias);
 933            buffer_point.saturating_sub(excerpt_start)
 934        } else {
 935            PointUtf16::zero()
 936        };
 937        *cursor.start() + overshoot
 938    }
 939
 940    pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> MultiBufferBytes<'a> {
 941        let range = range.start.to_offset(self)..range.end.to_offset(self);
 942        let mut excerpts = self.excerpts.cursor::<usize>();
 943        excerpts.seek(&range.start, Bias::Right, &());
 944
 945        let mut chunk = &[][..];
 946        let excerpt_bytes = if let Some(excerpt) = excerpts.item() {
 947            let mut excerpt_bytes = excerpt
 948                .bytes_in_range(range.start - excerpts.start()..range.end - excerpts.start());
 949            chunk = excerpt_bytes.next().unwrap_or(&[][..]);
 950            Some(excerpt_bytes)
 951        } else {
 952            None
 953        };
 954
 955        MultiBufferBytes {
 956            range,
 957            excerpts,
 958            excerpt_bytes,
 959            chunk,
 960        }
 961    }
 962
 963    pub fn buffer_rows<'a>(&'a self, start_row: u32) -> MultiBufferRows<'a> {
 964        let mut result = MultiBufferRows {
 965            buffer_row_range: 0..0,
 966            excerpts: self.excerpts.cursor(),
 967        };
 968        result.seek(start_row);
 969        result
 970    }
 971
 972    pub fn chunks<'a, T: ToOffset>(
 973        &'a self,
 974        range: Range<T>,
 975        theme: Option<&'a SyntaxTheme>,
 976    ) -> MultiBufferChunks<'a> {
 977        let range = range.start.to_offset(self)..range.end.to_offset(self);
 978        let mut chunks = MultiBufferChunks {
 979            range: range.clone(),
 980            excerpts: self.excerpts.cursor(),
 981            excerpt_chunks: None,
 982            theme,
 983        };
 984        chunks.seek(range.start);
 985        chunks
 986    }
 987
 988    pub fn offset_to_point(&self, offset: usize) -> Point {
 989        let mut cursor = self.excerpts.cursor::<(usize, Point)>();
 990        cursor.seek(&offset, Bias::Right, &());
 991        if let Some(excerpt) = cursor.item() {
 992            let (start_offset, start_point) = cursor.start();
 993            let overshoot = offset - start_offset;
 994            let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
 995            let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
 996            let buffer_point = excerpt
 997                .buffer
 998                .offset_to_point(excerpt_start_offset + overshoot);
 999            *start_point + (buffer_point - excerpt_start_point)
1000        } else {
1001            self.excerpts.summary().text.lines
1002        }
1003    }
1004
1005    pub fn point_to_offset(&self, point: Point) -> usize {
1006        let mut cursor = self.excerpts.cursor::<(Point, usize)>();
1007        cursor.seek(&point, Bias::Right, &());
1008        if let Some(excerpt) = cursor.item() {
1009            let (start_point, start_offset) = cursor.start();
1010            let overshoot = point - start_point;
1011            let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1012            let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
1013            let buffer_offset = excerpt
1014                .buffer
1015                .point_to_offset(excerpt_start_point + overshoot);
1016            *start_offset + buffer_offset - excerpt_start_offset
1017        } else {
1018            self.excerpts.summary().text.bytes
1019        }
1020    }
1021
1022    pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
1023        let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>();
1024        cursor.seek(&point, Bias::Right, &());
1025        if let Some(excerpt) = cursor.item() {
1026            let (start_point, start_offset) = cursor.start();
1027            let overshoot = point - start_point;
1028            let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1029            let excerpt_start_point = excerpt
1030                .buffer
1031                .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
1032            let buffer_offset = excerpt
1033                .buffer
1034                .point_utf16_to_offset(excerpt_start_point + overshoot);
1035            *start_offset + (buffer_offset - excerpt_start_offset)
1036        } else {
1037            self.excerpts.summary().text.bytes
1038        }
1039    }
1040
1041    pub fn indent_column_for_line(&self, row: u32) -> u32 {
1042        if let Some((buffer, range)) = self.buffer_line_for_row(row) {
1043            buffer
1044                .indent_column_for_line(range.start.row)
1045                .min(range.end.column)
1046                .saturating_sub(range.start.column)
1047        } else {
1048            0
1049        }
1050    }
1051
1052    pub fn line_len(&self, row: u32) -> u32 {
1053        if let Some((_, range)) = self.buffer_line_for_row(row) {
1054            range.end.column - range.start.column
1055        } else {
1056            0
1057        }
1058    }
1059
1060    fn buffer_line_for_row(&self, row: u32) -> Option<(&BufferSnapshot, Range<Point>)> {
1061        let mut cursor = self.excerpts.cursor::<Point>();
1062        cursor.seek(&Point::new(row, 0), Bias::Right, &());
1063        if let Some(excerpt) = cursor.item() {
1064            let overshoot = row - cursor.start().row;
1065            let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
1066            let excerpt_end = excerpt.range.end.to_point(&excerpt.buffer);
1067            let buffer_row = excerpt_start.row + overshoot;
1068            let line_start = Point::new(buffer_row, 0);
1069            let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
1070            return Some((
1071                &excerpt.buffer,
1072                line_start.max(excerpt_start)..line_end.min(excerpt_end),
1073            ));
1074        }
1075        None
1076    }
1077
1078    pub fn max_point(&self) -> Point {
1079        self.text_summary().lines
1080    }
1081
1082    pub fn text_summary(&self) -> TextSummary {
1083        self.excerpts.summary().text
1084    }
1085
1086    pub fn text_summary_for_range<'a, D, O>(&'a self, range: Range<O>) -> D
1087    where
1088        D: TextDimension,
1089        O: ToOffset,
1090    {
1091        let mut summary = D::default();
1092        let mut range = range.start.to_offset(self)..range.end.to_offset(self);
1093        let mut cursor = self.excerpts.cursor::<usize>();
1094        cursor.seek(&range.start, Bias::Right, &());
1095        if let Some(excerpt) = cursor.item() {
1096            let mut end_before_newline = cursor.end(&());
1097            if excerpt.has_trailing_newline {
1098                end_before_newline -= 1;
1099            }
1100
1101            let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1102            let start_in_excerpt = excerpt_start + (range.start - cursor.start());
1103            let end_in_excerpt =
1104                excerpt_start + (cmp::min(end_before_newline, range.end) - cursor.start());
1105            summary.add_assign(
1106                &excerpt
1107                    .buffer
1108                    .text_summary_for_range(start_in_excerpt..end_in_excerpt),
1109            );
1110
1111            if range.end > end_before_newline {
1112                summary.add_assign(&D::from_text_summary(&TextSummary {
1113                    bytes: 1,
1114                    lines: Point::new(1 as u32, 0),
1115                    lines_utf16: PointUtf16::new(1 as u32, 0),
1116                    first_line_chars: 0,
1117                    last_line_chars: 0,
1118                    longest_row: 0,
1119                    longest_row_chars: 0,
1120                }));
1121            }
1122
1123            cursor.next(&());
1124        }
1125
1126        if range.end > *cursor.start() {
1127            summary.add_assign(&D::from_text_summary(&cursor.summary::<_, TextSummary>(
1128                &range.end,
1129                Bias::Right,
1130                &(),
1131            )));
1132            if let Some(excerpt) = cursor.item() {
1133                range.end = cmp::max(*cursor.start(), range.end);
1134
1135                let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1136                let end_in_excerpt = excerpt_start + (range.end - cursor.start());
1137                summary.add_assign(
1138                    &excerpt
1139                        .buffer
1140                        .text_summary_for_range(excerpt_start..end_in_excerpt),
1141                );
1142            }
1143        }
1144
1145        summary
1146    }
1147
1148    pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
1149    where
1150        D: TextDimension + Ord + Sub<D, Output = D>,
1151    {
1152        let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1153        cursor.seek(&Some(&anchor.excerpt_id), Bias::Left, &());
1154        if cursor.item().is_none() {
1155            cursor.next(&());
1156        }
1157
1158        let mut position = D::from_text_summary(&cursor.start().text);
1159        if let Some(excerpt) = cursor.item() {
1160            if excerpt.id == anchor.excerpt_id {
1161                let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
1162                let buffer_position = anchor.text_anchor.summary::<D>(&excerpt.buffer);
1163                if buffer_position > excerpt_buffer_start {
1164                    position.add_assign(&(buffer_position - excerpt_buffer_start));
1165                }
1166            }
1167        }
1168        position
1169    }
1170
1171    pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
1172    where
1173        D: TextDimension + Ord + Sub<D, Output = D>,
1174        I: 'a + IntoIterator<Item = &'a Anchor>,
1175    {
1176        let mut anchors = anchors.into_iter().peekable();
1177        let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1178        let mut summaries = Vec::new();
1179        while let Some(anchor) = anchors.peek() {
1180            let excerpt_id = &anchor.excerpt_id;
1181            let excerpt_anchors = iter::from_fn(|| {
1182                let anchor = anchors.peek()?;
1183                if anchor.excerpt_id == *excerpt_id {
1184                    Some(&anchors.next().unwrap().text_anchor)
1185                } else {
1186                    None
1187                }
1188            });
1189
1190            cursor.seek_forward(&Some(excerpt_id), Bias::Left, &());
1191            if cursor.item().is_none() {
1192                cursor.next(&());
1193            }
1194
1195            let position = D::from_text_summary(&cursor.start().text);
1196            if let Some(excerpt) = cursor.item() {
1197                if excerpt.id == *excerpt_id {
1198                    let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
1199                    summaries.extend(
1200                        excerpt
1201                            .buffer
1202                            .summaries_for_anchors::<D, _>(excerpt_anchors)
1203                            .map(move |summary| {
1204                                let mut position = position.clone();
1205                                let excerpt_buffer_start = excerpt_buffer_start.clone();
1206                                if summary > excerpt_buffer_start {
1207                                    position.add_assign(&(summary - excerpt_buffer_start));
1208                                }
1209                                position
1210                            }),
1211                    );
1212                    continue;
1213                }
1214            }
1215
1216            summaries.extend(excerpt_anchors.map(|_| position.clone()));
1217        }
1218
1219        summaries
1220    }
1221
1222    pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
1223        self.anchor_at(position, Bias::Left)
1224    }
1225
1226    pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
1227        self.anchor_at(position, Bias::Right)
1228    }
1229
1230    pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
1231        let offset = position.to_offset(self);
1232        let mut cursor = self.excerpts.cursor::<(usize, Option<&ExcerptId>)>();
1233        cursor.seek(&offset, Bias::Right, &());
1234        if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left {
1235            cursor.prev(&());
1236        }
1237        if let Some(excerpt) = cursor.item() {
1238            let mut overshoot = offset.saturating_sub(cursor.start().0);
1239            if excerpt.has_trailing_newline && offset == cursor.end(&()).0 {
1240                overshoot -= 1;
1241                bias = Bias::Right;
1242            }
1243
1244            let buffer_start = excerpt.range.start.to_offset(&excerpt.buffer);
1245            let text_anchor =
1246                excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
1247            Anchor {
1248                excerpt_id: excerpt.id.clone(),
1249                text_anchor,
1250            }
1251        } else if offset == 0 && bias == Bias::Left {
1252            Anchor::min()
1253        } else {
1254            Anchor::max()
1255        }
1256    }
1257
1258    pub fn anchor_in_excerpt(&self, excerpt_id: ExcerptId, text_anchor: text::Anchor) -> Anchor {
1259        let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1260        cursor.seek(&Some(&excerpt_id), Bias::Left, &());
1261        if let Some(excerpt) = cursor.item() {
1262            if excerpt.id == excerpt_id {
1263                let text_anchor = excerpt.clip_anchor(text_anchor);
1264                drop(cursor);
1265                return Anchor {
1266                    excerpt_id,
1267                    text_anchor,
1268                };
1269            }
1270        }
1271        panic!("excerpt not found");
1272    }
1273
1274    pub fn parse_count(&self) -> usize {
1275        self.parse_count
1276    }
1277
1278    pub fn enclosing_bracket_ranges<T: ToOffset>(
1279        &self,
1280        range: Range<T>,
1281    ) -> Option<(Range<usize>, Range<usize>)> {
1282        let range = range.start.to_offset(self)..range.end.to_offset(self);
1283
1284        let mut cursor = self.excerpts.cursor::<usize>();
1285        cursor.seek(&range.start, Bias::Right, &());
1286        let start_excerpt = cursor.item();
1287
1288        cursor.seek(&range.end, Bias::Right, &());
1289        let end_excerpt = cursor.item();
1290
1291        start_excerpt
1292            .zip(end_excerpt)
1293            .and_then(|(start_excerpt, end_excerpt)| {
1294                if start_excerpt.id != end_excerpt.id {
1295                    return None;
1296                }
1297
1298                let excerpt_buffer_start =
1299                    start_excerpt.range.start.to_offset(&start_excerpt.buffer);
1300                let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
1301
1302                let start_in_buffer =
1303                    excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
1304                let end_in_buffer =
1305                    excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
1306                let (mut start_bracket_range, mut end_bracket_range) = start_excerpt
1307                    .buffer
1308                    .enclosing_bracket_ranges(start_in_buffer..end_in_buffer)?;
1309
1310                if start_bracket_range.start >= excerpt_buffer_start
1311                    && end_bracket_range.end < excerpt_buffer_end
1312                {
1313                    start_bracket_range.start =
1314                        cursor.start() + (start_bracket_range.start - excerpt_buffer_start);
1315                    start_bracket_range.end =
1316                        cursor.start() + (start_bracket_range.end - excerpt_buffer_start);
1317                    end_bracket_range.start =
1318                        cursor.start() + (end_bracket_range.start - excerpt_buffer_start);
1319                    end_bracket_range.end =
1320                        cursor.start() + (end_bracket_range.end - excerpt_buffer_start);
1321                    Some((start_bracket_range, end_bracket_range))
1322                } else {
1323                    None
1324                }
1325            })
1326    }
1327
1328    pub fn diagnostics_update_count(&self) -> usize {
1329        self.diagnostics_update_count
1330    }
1331
1332    pub fn language(&self) -> Option<&Arc<Language>> {
1333        self.excerpts
1334            .iter()
1335            .next()
1336            .and_then(|excerpt| excerpt.buffer.language())
1337    }
1338
1339    pub fn is_dirty(&self) -> bool {
1340        self.is_dirty
1341    }
1342
1343    pub fn has_conflict(&self) -> bool {
1344        self.has_conflict
1345    }
1346
1347    pub fn diagnostic_group<'a, O>(
1348        &'a self,
1349        group_id: usize,
1350    ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
1351    where
1352        O: text::FromAnchor + 'a,
1353    {
1354        self.as_singleton()
1355            .into_iter()
1356            .flat_map(move |buffer| buffer.diagnostic_group(group_id))
1357    }
1358
1359    pub fn diagnostics_in_range<'a, T, O>(
1360        &'a self,
1361        range: Range<T>,
1362    ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
1363    where
1364        T: 'a + ToOffset,
1365        O: 'a + text::FromAnchor,
1366    {
1367        self.as_singleton().into_iter().flat_map(move |buffer| {
1368            buffer.diagnostics_in_range(range.start.to_offset(self)..range.end.to_offset(self))
1369        })
1370    }
1371
1372    pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
1373        let range = range.start.to_offset(self)..range.end.to_offset(self);
1374
1375        let mut cursor = self.excerpts.cursor::<usize>();
1376        cursor.seek(&range.start, Bias::Right, &());
1377        let start_excerpt = cursor.item();
1378
1379        cursor.seek(&range.end, Bias::Right, &());
1380        let end_excerpt = cursor.item();
1381
1382        start_excerpt
1383            .zip(end_excerpt)
1384            .and_then(|(start_excerpt, end_excerpt)| {
1385                if start_excerpt.id != end_excerpt.id {
1386                    return None;
1387                }
1388
1389                let excerpt_buffer_start =
1390                    start_excerpt.range.start.to_offset(&start_excerpt.buffer);
1391                let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes;
1392
1393                let start_in_buffer =
1394                    excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
1395                let end_in_buffer =
1396                    excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
1397                let mut ancestor_buffer_range = start_excerpt
1398                    .buffer
1399                    .range_for_syntax_ancestor(start_in_buffer..end_in_buffer)?;
1400                ancestor_buffer_range.start =
1401                    cmp::max(ancestor_buffer_range.start, excerpt_buffer_start);
1402                ancestor_buffer_range.end = cmp::min(ancestor_buffer_range.end, excerpt_buffer_end);
1403
1404                let start = cursor.start() + (ancestor_buffer_range.start - excerpt_buffer_start);
1405                let end = cursor.start() + (ancestor_buffer_range.end - excerpt_buffer_start);
1406                Some(start..end)
1407            })
1408    }
1409
1410    fn buffer_snapshot_for_excerpt<'a>(
1411        &'a self,
1412        excerpt_id: &'a ExcerptId,
1413    ) -> Option<&'a BufferSnapshot> {
1414        let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1415        cursor.seek(&Some(excerpt_id), Bias::Left, &());
1416        if let Some(excerpt) = cursor.item() {
1417            if excerpt.id == *excerpt_id {
1418                return Some(&excerpt.buffer);
1419            }
1420        }
1421        None
1422    }
1423
1424    pub fn remote_selections_in_range<'a>(
1425        &'a self,
1426        range: &'a Range<Anchor>,
1427    ) -> impl 'a + Iterator<Item = (ReplicaId, Selection<Anchor>)> {
1428        let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1429        cursor.seek(&Some(&range.start.excerpt_id), Bias::Left, &());
1430        cursor
1431            .take_while(move |excerpt| excerpt.id <= range.end.excerpt_id)
1432            .flat_map(move |excerpt| {
1433                let mut query_range = excerpt.range.start.clone()..excerpt.range.end.clone();
1434                if excerpt.id == range.start.excerpt_id {
1435                    query_range.start = range.start.text_anchor.clone();
1436                }
1437                if excerpt.id == range.end.excerpt_id {
1438                    query_range.end = range.end.text_anchor.clone();
1439                }
1440
1441                excerpt
1442                    .buffer
1443                    .remote_selections_in_range(query_range)
1444                    .flat_map(move |(replica_id, selections)| {
1445                        selections.map(move |selection| {
1446                            let mut start = Anchor {
1447                                excerpt_id: excerpt.id.clone(),
1448                                text_anchor: selection.start.clone(),
1449                            };
1450                            let mut end = Anchor {
1451                                excerpt_id: excerpt.id.clone(),
1452                                text_anchor: selection.end.clone(),
1453                            };
1454                            if range.start.cmp(&start, self).unwrap().is_gt() {
1455                                start = range.start.clone();
1456                            }
1457                            if range.end.cmp(&end, self).unwrap().is_lt() {
1458                                end = range.end.clone();
1459                            }
1460
1461                            (
1462                                replica_id,
1463                                Selection {
1464                                    id: selection.id,
1465                                    start,
1466                                    end,
1467                                    reversed: selection.reversed,
1468                                    goal: selection.goal,
1469                                },
1470                            )
1471                        })
1472                    })
1473            })
1474    }
1475}
1476
1477impl History {
1478    fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
1479        self.transaction_depth += 1;
1480        if self.transaction_depth == 1 {
1481            let id = post_inc(&mut self.next_transaction_id);
1482            self.undo_stack.push(Transaction {
1483                id,
1484                buffer_transactions: Default::default(),
1485                first_edit_at: now,
1486                last_edit_at: now,
1487            });
1488            Some(id)
1489        } else {
1490            None
1491        }
1492    }
1493
1494    fn end_transaction(
1495        &mut self,
1496        now: Instant,
1497        buffer_transactions: HashSet<(usize, TransactionId)>,
1498    ) -> bool {
1499        assert_ne!(self.transaction_depth, 0);
1500        self.transaction_depth -= 1;
1501        if self.transaction_depth == 0 {
1502            if buffer_transactions.is_empty() {
1503                self.undo_stack.pop();
1504                false
1505            } else {
1506                let transaction = self.undo_stack.last_mut().unwrap();
1507                transaction.last_edit_at = now;
1508                transaction.buffer_transactions.extend(buffer_transactions);
1509                true
1510            }
1511        } else {
1512            false
1513        }
1514    }
1515
1516    fn pop_undo(&mut self) -> Option<&Transaction> {
1517        assert_eq!(self.transaction_depth, 0);
1518        if let Some(transaction) = self.undo_stack.pop() {
1519            self.redo_stack.push(transaction);
1520            self.redo_stack.last()
1521        } else {
1522            None
1523        }
1524    }
1525
1526    fn pop_redo(&mut self) -> Option<&Transaction> {
1527        assert_eq!(self.transaction_depth, 0);
1528        if let Some(transaction) = self.redo_stack.pop() {
1529            self.undo_stack.push(transaction);
1530            self.undo_stack.last()
1531        } else {
1532            None
1533        }
1534    }
1535
1536    fn group(&mut self) -> Option<TransactionId> {
1537        let mut new_len = self.undo_stack.len();
1538        let mut transactions = self.undo_stack.iter_mut();
1539
1540        if let Some(mut transaction) = transactions.next_back() {
1541            while let Some(prev_transaction) = transactions.next_back() {
1542                if transaction.first_edit_at - prev_transaction.last_edit_at <= self.group_interval
1543                {
1544                    transaction = prev_transaction;
1545                    new_len -= 1;
1546                } else {
1547                    break;
1548                }
1549            }
1550        }
1551
1552        let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
1553        if let Some(last_transaction) = transactions_to_keep.last_mut() {
1554            if let Some(transaction) = transactions_to_merge.last() {
1555                last_transaction.last_edit_at = transaction.last_edit_at;
1556            }
1557        }
1558
1559        self.undo_stack.truncate(new_len);
1560        self.undo_stack.last().map(|t| t.id)
1561    }
1562}
1563
1564impl Excerpt {
1565    fn new(
1566        id: ExcerptId,
1567        buffer_id: usize,
1568        buffer: BufferSnapshot,
1569        range: Range<text::Anchor>,
1570        has_trailing_newline: bool,
1571    ) -> Self {
1572        Excerpt {
1573            id,
1574            max_buffer_row: range.end.to_point(&buffer).row,
1575            text_summary: buffer.text_summary_for_range::<TextSummary, _>(range.to_offset(&buffer)),
1576            buffer_id,
1577            buffer,
1578            range,
1579            has_trailing_newline,
1580        }
1581    }
1582
1583    fn chunks_in_range<'a>(
1584        &'a self,
1585        range: Range<usize>,
1586        theme: Option<&'a SyntaxTheme>,
1587    ) -> ExcerptChunks<'a> {
1588        let content_start = self.range.start.to_offset(&self.buffer);
1589        let chunks_start = content_start + range.start;
1590        let chunks_end = content_start + cmp::min(range.end, self.text_summary.bytes);
1591
1592        let footer_height = if self.has_trailing_newline
1593            && range.start <= self.text_summary.bytes
1594            && range.end > self.text_summary.bytes
1595        {
1596            1
1597        } else {
1598            0
1599        };
1600
1601        let content_chunks = self.buffer.chunks(chunks_start..chunks_end, theme);
1602
1603        ExcerptChunks {
1604            content_chunks,
1605            footer_height,
1606        }
1607    }
1608
1609    fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
1610        let content_start = self.range.start.to_offset(&self.buffer);
1611        let bytes_start = content_start + range.start;
1612        let bytes_end = content_start + cmp::min(range.end, self.text_summary.bytes);
1613        let footer_height = if self.has_trailing_newline
1614            && range.start <= self.text_summary.bytes
1615            && range.end > self.text_summary.bytes
1616        {
1617            1
1618        } else {
1619            0
1620        };
1621        let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
1622
1623        ExcerptBytes {
1624            content_bytes,
1625            footer_height,
1626        }
1627    }
1628
1629    fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
1630        if text_anchor
1631            .cmp(&self.range.start, &self.buffer)
1632            .unwrap()
1633            .is_lt()
1634        {
1635            self.range.start.clone()
1636        } else if text_anchor
1637            .cmp(&self.range.end, &self.buffer)
1638            .unwrap()
1639            .is_gt()
1640        {
1641            self.range.end.clone()
1642        } else {
1643            text_anchor
1644        }
1645    }
1646}
1647
1648impl fmt::Debug for Excerpt {
1649    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1650        f.debug_struct("Excerpt")
1651            .field("id", &self.id)
1652            .field("buffer_id", &self.buffer_id)
1653            .field("range", &self.range)
1654            .field("text_summary", &self.text_summary)
1655            .field("has_trailing_newline", &self.has_trailing_newline)
1656            .finish()
1657    }
1658}
1659
1660impl sum_tree::Item for Excerpt {
1661    type Summary = ExcerptSummary;
1662
1663    fn summary(&self) -> Self::Summary {
1664        let mut text = self.text_summary.clone();
1665        if self.has_trailing_newline {
1666            text += TextSummary::from("\n");
1667        }
1668        ExcerptSummary {
1669            excerpt_id: self.id.clone(),
1670            max_buffer_row: self.max_buffer_row,
1671            text,
1672        }
1673    }
1674}
1675
1676impl sum_tree::Summary for ExcerptSummary {
1677    type Context = ();
1678
1679    fn add_summary(&mut self, summary: &Self, _: &()) {
1680        debug_assert!(summary.excerpt_id > self.excerpt_id);
1681        self.excerpt_id = summary.excerpt_id.clone();
1682        self.text.add_summary(&summary.text, &());
1683        self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row);
1684    }
1685}
1686
1687impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
1688    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1689        *self += &summary.text;
1690    }
1691}
1692
1693impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
1694    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1695        *self += summary.text.bytes;
1696    }
1697}
1698
1699impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
1700    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
1701        Ord::cmp(self, &cursor_location.text.bytes)
1702    }
1703}
1704
1705impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Option<&'a ExcerptId> {
1706    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
1707        Ord::cmp(self, &Some(&cursor_location.excerpt_id))
1708    }
1709}
1710
1711impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
1712    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1713        *self += summary.text.lines;
1714    }
1715}
1716
1717impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
1718    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1719        *self += summary.text.lines_utf16
1720    }
1721}
1722
1723impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a ExcerptId> {
1724    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1725        *self = Some(&summary.excerpt_id);
1726    }
1727}
1728
1729impl<'a> MultiBufferRows<'a> {
1730    pub fn seek(&mut self, row: u32) {
1731        self.buffer_row_range = 0..0;
1732
1733        self.excerpts
1734            .seek_forward(&Point::new(row, 0), Bias::Right, &());
1735        if self.excerpts.item().is_none() {
1736            self.excerpts.prev(&());
1737
1738            if self.excerpts.item().is_none() && row == 0 {
1739                self.buffer_row_range = 0..1;
1740                return;
1741            }
1742        }
1743
1744        if let Some(excerpt) = self.excerpts.item() {
1745            let overshoot = row - self.excerpts.start().row;
1746            let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer).row;
1747            self.buffer_row_range.start = excerpt_start + overshoot;
1748            self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1;
1749        }
1750    }
1751}
1752
1753impl<'a> Iterator for MultiBufferRows<'a> {
1754    type Item = Option<u32>;
1755
1756    fn next(&mut self) -> Option<Self::Item> {
1757        loop {
1758            if !self.buffer_row_range.is_empty() {
1759                let row = Some(self.buffer_row_range.start);
1760                self.buffer_row_range.start += 1;
1761                return Some(row);
1762            }
1763            self.excerpts.item()?;
1764            self.excerpts.next(&());
1765            let excerpt = self.excerpts.item()?;
1766            self.buffer_row_range.start = excerpt.range.start.to_point(&excerpt.buffer).row;
1767            self.buffer_row_range.end =
1768                self.buffer_row_range.start + excerpt.text_summary.lines.row + 1;
1769        }
1770    }
1771}
1772
1773impl<'a> MultiBufferChunks<'a> {
1774    pub fn offset(&self) -> usize {
1775        self.range.start
1776    }
1777
1778    pub fn seek(&mut self, offset: usize) {
1779        self.range.start = offset;
1780        self.excerpts.seek(&offset, Bias::Right, &());
1781        if let Some(excerpt) = self.excerpts.item() {
1782            self.excerpt_chunks = Some(excerpt.chunks_in_range(
1783                self.range.start - self.excerpts.start()..self.range.end - self.excerpts.start(),
1784                self.theme,
1785            ));
1786        } else {
1787            self.excerpt_chunks = None;
1788        }
1789    }
1790}
1791
1792impl<'a> Iterator for MultiBufferChunks<'a> {
1793    type Item = Chunk<'a>;
1794
1795    fn next(&mut self) -> Option<Self::Item> {
1796        if self.range.is_empty() {
1797            None
1798        } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
1799            self.range.start += chunk.text.len();
1800            Some(chunk)
1801        } else {
1802            self.excerpts.next(&());
1803            let excerpt = self.excerpts.item()?;
1804            self.excerpt_chunks = Some(
1805                excerpt.chunks_in_range(0..self.range.end - self.excerpts.start(), self.theme),
1806            );
1807            self.next()
1808        }
1809    }
1810}
1811
1812impl<'a> MultiBufferBytes<'a> {
1813    fn consume(&mut self, len: usize) {
1814        self.range.start += len;
1815        self.chunk = &self.chunk[len..];
1816
1817        if !self.range.is_empty() && self.chunk.is_empty() {
1818            if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
1819                self.chunk = chunk;
1820            } else {
1821                self.excerpts.next(&());
1822                if let Some(excerpt) = self.excerpts.item() {
1823                    let mut excerpt_bytes =
1824                        excerpt.bytes_in_range(0..self.range.end - self.excerpts.start());
1825                    self.chunk = excerpt_bytes.next().unwrap();
1826                    self.excerpt_bytes = Some(excerpt_bytes);
1827                }
1828            }
1829        }
1830    }
1831}
1832
1833impl<'a> Iterator for MultiBufferBytes<'a> {
1834    type Item = &'a [u8];
1835
1836    fn next(&mut self) -> Option<Self::Item> {
1837        let chunk = self.chunk;
1838        if chunk.is_empty() {
1839            None
1840        } else {
1841            self.consume(chunk.len());
1842            Some(chunk)
1843        }
1844    }
1845}
1846
1847impl<'a> io::Read for MultiBufferBytes<'a> {
1848    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1849        let len = cmp::min(buf.len(), self.chunk.len());
1850        buf[..len].copy_from_slice(&self.chunk[..len]);
1851        if len > 0 {
1852            self.consume(len);
1853        }
1854        Ok(len)
1855    }
1856}
1857
1858impl<'a> Iterator for ExcerptBytes<'a> {
1859    type Item = &'a [u8];
1860
1861    fn next(&mut self) -> Option<Self::Item> {
1862        if let Some(chunk) = self.content_bytes.next() {
1863            if !chunk.is_empty() {
1864                return Some(chunk);
1865            }
1866        }
1867
1868        if self.footer_height > 0 {
1869            let result = &NEWLINES[..self.footer_height];
1870            self.footer_height = 0;
1871            return Some(result);
1872        }
1873
1874        None
1875    }
1876}
1877
1878impl<'a> Iterator for ExcerptChunks<'a> {
1879    type Item = Chunk<'a>;
1880
1881    fn next(&mut self) -> Option<Self::Item> {
1882        if let Some(chunk) = self.content_chunks.next() {
1883            return Some(chunk);
1884        }
1885
1886        if self.footer_height > 0 {
1887            let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
1888            self.footer_height = 0;
1889            return Some(Chunk {
1890                text,
1891                ..Default::default()
1892            });
1893        }
1894
1895        None
1896    }
1897}
1898
1899impl ToOffset for Point {
1900    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
1901        snapshot.point_to_offset(*self)
1902    }
1903}
1904
1905impl ToOffset for PointUtf16 {
1906    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
1907        snapshot.point_utf16_to_offset(*self)
1908    }
1909}
1910
1911impl ToOffset for usize {
1912    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
1913        assert!(*self <= snapshot.len(), "offset is out of range");
1914        *self
1915    }
1916}
1917
1918impl ToPoint for usize {
1919    fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
1920        snapshot.offset_to_point(*self)
1921    }
1922}
1923
1924impl ToPoint for Point {
1925    fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
1926        *self
1927    }
1928}
1929
1930#[cfg(test)]
1931mod tests {
1932    use super::*;
1933    use gpui::MutableAppContext;
1934    use language::{Buffer, Rope};
1935    use rand::prelude::*;
1936    use std::env;
1937    use text::{Point, RandomCharIter};
1938    use util::test::sample_text;
1939
1940    #[gpui::test]
1941    fn test_singleton_multibuffer(cx: &mut MutableAppContext) {
1942        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
1943        let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
1944
1945        let snapshot = multibuffer.read(cx).snapshot(cx);
1946        assert_eq!(snapshot.text(), buffer.read(cx).text());
1947
1948        assert_eq!(
1949            snapshot.buffer_rows(0).collect::<Vec<_>>(),
1950            (0..buffer.read(cx).row_count())
1951                .map(Some)
1952                .collect::<Vec<_>>()
1953        );
1954
1955        buffer.update(cx, |buffer, cx| buffer.edit([1..3], "XXX\n", cx));
1956        let snapshot = multibuffer.read(cx).snapshot(cx);
1957
1958        assert_eq!(snapshot.text(), buffer.read(cx).text());
1959        assert_eq!(
1960            snapshot.buffer_rows(0).collect::<Vec<_>>(),
1961            (0..buffer.read(cx).row_count())
1962                .map(Some)
1963                .collect::<Vec<_>>()
1964        );
1965    }
1966
1967    #[gpui::test]
1968    fn test_excerpt_buffer(cx: &mut MutableAppContext) {
1969        let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
1970        let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
1971        let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
1972
1973        let subscription = multibuffer.update(cx, |multibuffer, cx| {
1974            let subscription = multibuffer.subscribe();
1975            multibuffer.push_excerpt(
1976                ExcerptProperties {
1977                    buffer: &buffer_1,
1978                    range: Point::new(1, 2)..Point::new(2, 5),
1979                },
1980                cx,
1981            );
1982            assert_eq!(
1983                subscription.consume().into_inner(),
1984                [Edit {
1985                    old: 0..0,
1986                    new: 0..10
1987                }]
1988            );
1989
1990            multibuffer.push_excerpt(
1991                ExcerptProperties {
1992                    buffer: &buffer_1,
1993                    range: Point::new(3, 3)..Point::new(4, 4),
1994                },
1995                cx,
1996            );
1997            multibuffer.push_excerpt(
1998                ExcerptProperties {
1999                    buffer: &buffer_2,
2000                    range: Point::new(3, 1)..Point::new(3, 3),
2001                },
2002                cx,
2003            );
2004            assert_eq!(
2005                subscription.consume().into_inner(),
2006                [Edit {
2007                    old: 10..10,
2008                    new: 10..22
2009                }]
2010            );
2011
2012            subscription
2013        });
2014
2015        let snapshot = multibuffer.read(cx).snapshot(cx);
2016        assert_eq!(
2017            snapshot.text(),
2018            concat!(
2019                "bbbb\n",  // Preserve newlines
2020                "ccccc\n", //
2021                "ddd\n",   //
2022                "eeee\n",  //
2023                "jj"       //
2024            )
2025        );
2026        assert_eq!(
2027            snapshot.buffer_rows(0).collect::<Vec<_>>(),
2028            [Some(1), Some(2), Some(3), Some(4), Some(3)]
2029        );
2030        assert_eq!(
2031            snapshot.buffer_rows(2).collect::<Vec<_>>(),
2032            [Some(3), Some(4), Some(3)]
2033        );
2034        assert_eq!(snapshot.buffer_rows(4).collect::<Vec<_>>(), [Some(3)]);
2035        assert_eq!(snapshot.buffer_rows(5).collect::<Vec<_>>(), []);
2036
2037        buffer_1.update(cx, |buffer, cx| {
2038            buffer.edit(
2039                [
2040                    Point::new(0, 0)..Point::new(0, 0),
2041                    Point::new(2, 1)..Point::new(2, 3),
2042                ],
2043                "\n",
2044                cx,
2045            );
2046        });
2047
2048        assert_eq!(
2049            multibuffer.read(cx).snapshot(cx).text(),
2050            concat!(
2051                "bbbb\n", // Preserve newlines
2052                "c\n",    //
2053                "cc\n",   //
2054                "ddd\n",  //
2055                "eeee\n", //
2056                "jj"      //
2057            )
2058        );
2059
2060        assert_eq!(
2061            subscription.consume().into_inner(),
2062            [Edit {
2063                old: 6..8,
2064                new: 6..7
2065            }]
2066        );
2067
2068        let multibuffer = multibuffer.read(cx).snapshot(cx);
2069        assert_eq!(
2070            multibuffer.clip_point(Point::new(0, 5), Bias::Left),
2071            Point::new(0, 4)
2072        );
2073        assert_eq!(
2074            multibuffer.clip_point(Point::new(0, 5), Bias::Right),
2075            Point::new(0, 4)
2076        );
2077        assert_eq!(
2078            multibuffer.clip_point(Point::new(5, 1), Bias::Right),
2079            Point::new(5, 1)
2080        );
2081        assert_eq!(
2082            multibuffer.clip_point(Point::new(5, 2), Bias::Right),
2083            Point::new(5, 2)
2084        );
2085        assert_eq!(
2086            multibuffer.clip_point(Point::new(5, 3), Bias::Right),
2087            Point::new(5, 2)
2088        );
2089    }
2090
2091    #[gpui::test]
2092    fn test_empty_excerpt_buffer(cx: &mut MutableAppContext) {
2093        let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2094
2095        let snapshot = multibuffer.read(cx).snapshot(cx);
2096        assert_eq!(snapshot.text(), "");
2097        assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), &[Some(0)]);
2098        assert_eq!(snapshot.buffer_rows(1).collect::<Vec<_>>(), &[]);
2099    }
2100
2101    #[gpui::test]
2102    fn test_singleton_multibuffer_anchors(cx: &mut MutableAppContext) {
2103        let buffer = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
2104        let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
2105        let old_snapshot = multibuffer.read(cx).snapshot(cx);
2106        buffer.update(cx, |buffer, cx| {
2107            buffer.edit([0..0], "X", cx);
2108            buffer.edit([5..5], "Y", cx);
2109        });
2110        let new_snapshot = multibuffer.read(cx).snapshot(cx);
2111
2112        assert_eq!(old_snapshot.text(), "abcd");
2113        assert_eq!(new_snapshot.text(), "XabcdY");
2114
2115        assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
2116        assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
2117        assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
2118        assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
2119    }
2120
2121    #[gpui::test]
2122    fn test_multibuffer_anchors(cx: &mut MutableAppContext) {
2123        let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
2124        let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
2125        let multibuffer = cx.add_model(|cx| {
2126            let mut multibuffer = MultiBuffer::new(0);
2127            multibuffer.push_excerpt(
2128                ExcerptProperties {
2129                    buffer: &buffer_1,
2130                    range: 0..4,
2131                },
2132                cx,
2133            );
2134            multibuffer.push_excerpt(
2135                ExcerptProperties {
2136                    buffer: &buffer_2,
2137                    range: 0..5,
2138                },
2139                cx,
2140            );
2141            multibuffer
2142        });
2143        let old_snapshot = multibuffer.read(cx).snapshot(cx);
2144
2145        assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0);
2146        assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0);
2147        assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
2148        assert_eq!(Anchor::min().to_offset(&old_snapshot), 0);
2149        assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
2150        assert_eq!(Anchor::max().to_offset(&old_snapshot), 10);
2151
2152        buffer_1.update(cx, |buffer, cx| {
2153            buffer.edit([0..0], "W", cx);
2154            buffer.edit([5..5], "X", cx);
2155        });
2156        buffer_2.update(cx, |buffer, cx| {
2157            buffer.edit([0..0], "Y", cx);
2158            buffer.edit([6..0], "Z", cx);
2159        });
2160        let new_snapshot = multibuffer.read(cx).snapshot(cx);
2161
2162        assert_eq!(old_snapshot.text(), "abcd\nefghi");
2163        assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ");
2164
2165        assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
2166        assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
2167        assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2);
2168        assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
2169        assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
2170        assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
2171        assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7);
2172        assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8);
2173        assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13);
2174        assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14);
2175    }
2176
2177    #[gpui::test(iterations = 100)]
2178    fn test_random_excerpts(cx: &mut MutableAppContext, mut rng: StdRng) {
2179        let operations = env::var("OPERATIONS")
2180            .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2181            .unwrap_or(10);
2182
2183        let mut buffers: Vec<ModelHandle<Buffer>> = Vec::new();
2184        let list = cx.add_model(|_| MultiBuffer::new(0));
2185        let mut excerpt_ids = Vec::new();
2186        let mut expected_excerpts = Vec::new();
2187        let mut old_versions = Vec::new();
2188
2189        for _ in 0..operations {
2190            match rng.gen_range(0..100) {
2191                0..=19 if !buffers.is_empty() => {
2192                    let buffer = buffers.choose(&mut rng).unwrap();
2193                    buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
2194                }
2195                _ => {
2196                    let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
2197                        let base_text = RandomCharIter::new(&mut rng).take(10).collect::<String>();
2198                        buffers.push(cx.add_model(|cx| Buffer::new(0, base_text, cx)));
2199                        buffers.last().unwrap()
2200                    } else {
2201                        buffers.choose(&mut rng).unwrap()
2202                    };
2203
2204                    let buffer = buffer_handle.read(cx);
2205                    let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
2206                    let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
2207                    let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
2208                    log::info!(
2209                        "Pushing excerpt for buffer {}: {:?}[{:?}] = {:?}",
2210                        buffer_handle.id(),
2211                        buffer.text(),
2212                        start_ix..end_ix,
2213                        &buffer.text()[start_ix..end_ix]
2214                    );
2215
2216                    let excerpt_id = list.update(cx, |list, cx| {
2217                        list.push_excerpt(
2218                            ExcerptProperties {
2219                                buffer: &buffer_handle,
2220                                range: start_ix..end_ix,
2221                            },
2222                            cx,
2223                        )
2224                    });
2225                    excerpt_ids.push(excerpt_id);
2226                    expected_excerpts.push((buffer_handle.clone(), anchor_range));
2227                }
2228            }
2229
2230            if rng.gen_bool(0.3) {
2231                list.update(cx, |list, cx| {
2232                    old_versions.push((list.snapshot(cx), list.subscribe()));
2233                })
2234            }
2235
2236            let snapshot = list.read(cx).snapshot(cx);
2237
2238            let mut excerpt_starts = Vec::new();
2239            let mut expected_text = String::new();
2240            let mut expected_buffer_rows = Vec::new();
2241            for (buffer, range) in &expected_excerpts {
2242                let buffer = buffer.read(cx);
2243                let buffer_range = range.to_offset(buffer);
2244
2245                excerpt_starts.push(TextSummary::from(expected_text.as_str()));
2246                expected_text.extend(buffer.text_for_range(buffer_range.clone()));
2247                expected_text.push('\n');
2248
2249                let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
2250                    ..=buffer.offset_to_point(buffer_range.end).row;
2251                for row in buffer_row_range {
2252                    expected_buffer_rows.push(Some(row));
2253                }
2254            }
2255            // Remove final trailing newline.
2256            if !expected_excerpts.is_empty() {
2257                expected_text.pop();
2258            }
2259
2260            assert_eq!(snapshot.text(), expected_text);
2261            log::info!("MultiBuffer text: {:?}", expected_text);
2262
2263            assert_eq!(
2264                snapshot.buffer_rows(0).collect::<Vec<_>>(),
2265                expected_buffer_rows,
2266            );
2267
2268            for _ in 0..5 {
2269                let start_row = rng.gen_range(0..=expected_buffer_rows.len());
2270                assert_eq!(
2271                    snapshot.buffer_rows(start_row as u32).collect::<Vec<_>>(),
2272                    &expected_buffer_rows[start_row..],
2273                    "buffer_rows({})",
2274                    start_row
2275                );
2276            }
2277
2278            assert_eq!(
2279                snapshot.max_buffer_row(),
2280                expected_buffer_rows
2281                    .into_iter()
2282                    .filter_map(|r| r)
2283                    .max()
2284                    .unwrap()
2285            );
2286
2287            let mut excerpt_starts = excerpt_starts.into_iter();
2288            for (buffer, range) in &expected_excerpts {
2289                let buffer_id = buffer.id();
2290                let buffer = buffer.read(cx);
2291                let buffer_range = range.to_offset(buffer);
2292                let buffer_start_point = buffer.offset_to_point(buffer_range.start);
2293                let buffer_start_point_utf16 =
2294                    buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
2295
2296                let excerpt_start = excerpt_starts.next().unwrap();
2297                let mut offset = excerpt_start.bytes;
2298                let mut buffer_offset = buffer_range.start;
2299                let mut point = excerpt_start.lines;
2300                let mut buffer_point = buffer_start_point;
2301                let mut point_utf16 = excerpt_start.lines_utf16;
2302                let mut buffer_point_utf16 = buffer_start_point_utf16;
2303                for ch in buffer
2304                    .snapshot()
2305                    .chunks(buffer_range.clone(), None)
2306                    .flat_map(|c| c.text.chars())
2307                {
2308                    for _ in 0..ch.len_utf8() {
2309                        let left_offset = snapshot.clip_offset(offset, Bias::Left);
2310                        let right_offset = snapshot.clip_offset(offset, Bias::Right);
2311                        let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
2312                        let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
2313                        assert_eq!(
2314                            left_offset,
2315                            excerpt_start.bytes + (buffer_left_offset - buffer_range.start),
2316                            "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
2317                            offset,
2318                            buffer_id,
2319                            buffer_offset,
2320                        );
2321                        assert_eq!(
2322                            right_offset,
2323                            excerpt_start.bytes + (buffer_right_offset - buffer_range.start),
2324                            "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
2325                            offset,
2326                            buffer_id,
2327                            buffer_offset,
2328                        );
2329
2330                        let left_point = snapshot.clip_point(point, Bias::Left);
2331                        let right_point = snapshot.clip_point(point, Bias::Right);
2332                        let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
2333                        let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
2334                        assert_eq!(
2335                            left_point,
2336                            excerpt_start.lines + (buffer_left_point - buffer_start_point),
2337                            "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
2338                            point,
2339                            buffer_id,
2340                            buffer_point,
2341                        );
2342                        assert_eq!(
2343                            right_point,
2344                            excerpt_start.lines + (buffer_right_point - buffer_start_point),
2345                            "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
2346                            point,
2347                            buffer_id,
2348                            buffer_point,
2349                        );
2350
2351                        assert_eq!(
2352                            snapshot.point_to_offset(left_point),
2353                            left_offset,
2354                            "point_to_offset({:?})",
2355                            left_point,
2356                        );
2357                        assert_eq!(
2358                            snapshot.offset_to_point(left_offset),
2359                            left_point,
2360                            "offset_to_point({:?})",
2361                            left_offset,
2362                        );
2363
2364                        offset += 1;
2365                        buffer_offset += 1;
2366                        if ch == '\n' {
2367                            point += Point::new(1, 0);
2368                            buffer_point += Point::new(1, 0);
2369                        } else {
2370                            point += Point::new(0, 1);
2371                            buffer_point += Point::new(0, 1);
2372                        }
2373                    }
2374
2375                    for _ in 0..ch.len_utf16() {
2376                        let left_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Left);
2377                        let right_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Right);
2378                        let buffer_left_point_utf16 =
2379                            buffer.clip_point_utf16(buffer_point_utf16, Bias::Left);
2380                        let buffer_right_point_utf16 =
2381                            buffer.clip_point_utf16(buffer_point_utf16, Bias::Right);
2382                        assert_eq!(
2383                            left_point_utf16,
2384                            excerpt_start.lines_utf16
2385                                + (buffer_left_point_utf16 - buffer_start_point_utf16),
2386                            "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
2387                            point_utf16,
2388                            buffer_id,
2389                            buffer_point_utf16,
2390                        );
2391                        assert_eq!(
2392                            right_point_utf16,
2393                            excerpt_start.lines_utf16
2394                                + (buffer_right_point_utf16 - buffer_start_point_utf16),
2395                            "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
2396                            point_utf16,
2397                            buffer_id,
2398                            buffer_point_utf16,
2399                        );
2400
2401                        if ch == '\n' {
2402                            point_utf16 += PointUtf16::new(1, 0);
2403                            buffer_point_utf16 += PointUtf16::new(1, 0);
2404                        } else {
2405                            point_utf16 += PointUtf16::new(0, 1);
2406                            buffer_point_utf16 += PointUtf16::new(0, 1);
2407                        }
2408                    }
2409                }
2410            }
2411
2412            for (row, line) in expected_text.split('\n').enumerate() {
2413                assert_eq!(
2414                    snapshot.line_len(row as u32),
2415                    line.len() as u32,
2416                    "line_len({}).",
2417                    row
2418                );
2419            }
2420
2421            let text_rope = Rope::from(expected_text.as_str());
2422            for _ in 0..10 {
2423                let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
2424                let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
2425
2426                assert_eq!(
2427                    snapshot
2428                        .text_for_range(start_ix..end_ix)
2429                        .collect::<String>(),
2430                    &expected_text[start_ix..end_ix],
2431                    "incorrect text for range {:?}",
2432                    start_ix..end_ix
2433                );
2434
2435                let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
2436                assert_eq!(
2437                    snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
2438                    expected_summary,
2439                    "incorrect summary for range {:?}",
2440                    start_ix..end_ix
2441                );
2442            }
2443
2444            for _ in 0..10 {
2445                let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
2446                assert_eq!(
2447                    snapshot.reversed_chars_at(end_ix).collect::<String>(),
2448                    expected_text[..end_ix].chars().rev().collect::<String>(),
2449                );
2450            }
2451
2452            for _ in 0..10 {
2453                let end_ix = rng.gen_range(0..=text_rope.len());
2454                let start_ix = rng.gen_range(0..=end_ix);
2455                assert_eq!(
2456                    snapshot
2457                        .bytes_in_range(start_ix..end_ix)
2458                        .flatten()
2459                        .copied()
2460                        .collect::<Vec<_>>(),
2461                    expected_text.as_bytes()[start_ix..end_ix].to_vec(),
2462                    "bytes_in_range({:?})",
2463                    start_ix..end_ix,
2464                );
2465            }
2466        }
2467
2468        let snapshot = list.read(cx).snapshot(cx);
2469        for (old_snapshot, subscription) in old_versions {
2470            let edits = subscription.consume().into_inner();
2471
2472            log::info!(
2473                "applying subscription edits to old text: {:?}: {:?}",
2474                old_snapshot.text(),
2475                edits,
2476            );
2477
2478            let mut text = old_snapshot.text();
2479            for edit in edits {
2480                let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
2481                text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
2482            }
2483            assert_eq!(text.to_string(), snapshot.text());
2484        }
2485    }
2486
2487    #[gpui::test]
2488    fn test_history(cx: &mut MutableAppContext) {
2489        let buffer_1 = cx.add_model(|cx| Buffer::new(0, "1234", cx));
2490        let buffer_2 = cx.add_model(|cx| Buffer::new(0, "5678", cx));
2491        let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2492        let group_interval = multibuffer.read(cx).history.group_interval;
2493        multibuffer.update(cx, |multibuffer, cx| {
2494            multibuffer.push_excerpt(
2495                ExcerptProperties {
2496                    buffer: &buffer_1,
2497                    range: 0..buffer_1.read(cx).len(),
2498                },
2499                cx,
2500            );
2501            multibuffer.push_excerpt(
2502                ExcerptProperties {
2503                    buffer: &buffer_2,
2504                    range: 0..buffer_2.read(cx).len(),
2505                },
2506                cx,
2507            );
2508        });
2509
2510        let mut now = Instant::now();
2511
2512        multibuffer.update(cx, |multibuffer, cx| {
2513            multibuffer.start_transaction_at(now, cx);
2514            multibuffer.edit(
2515                [
2516                    Point::new(0, 0)..Point::new(0, 0),
2517                    Point::new(1, 0)..Point::new(1, 0),
2518                ],
2519                "A",
2520                cx,
2521            );
2522            multibuffer.edit(
2523                [
2524                    Point::new(0, 1)..Point::new(0, 1),
2525                    Point::new(1, 1)..Point::new(1, 1),
2526                ],
2527                "B",
2528                cx,
2529            );
2530            multibuffer.end_transaction_at(now, cx);
2531            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2532
2533            now += 2 * group_interval;
2534            multibuffer.start_transaction_at(now, cx);
2535            multibuffer.edit([2..2], "C", cx);
2536            multibuffer.end_transaction_at(now, cx);
2537            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2538
2539            multibuffer.undo(cx);
2540            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2541
2542            multibuffer.undo(cx);
2543            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
2544
2545            multibuffer.redo(cx);
2546            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2547
2548            multibuffer.redo(cx);
2549            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2550
2551            buffer_1.update(cx, |buffer_1, cx| buffer_1.undo(cx));
2552            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2553
2554            multibuffer.undo(cx);
2555            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
2556
2557            multibuffer.redo(cx);
2558            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2559
2560            multibuffer.redo(cx);
2561            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2562
2563            multibuffer.undo(cx);
2564            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2565
2566            buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
2567            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2568
2569            multibuffer.undo(cx);
2570            assert_eq!(multibuffer.read(cx).text(), "C1234\n5678");
2571        });
2572    }
2573}