multi_buffer.rs

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