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