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