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