multi_buffer.rs

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