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