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    #[cfg(test)]
 693    pub fn is_parsing(&self, cx: &AppContext) -> bool {
 694        self.as_singleton().unwrap().read(cx).is_parsing()
 695    }
 696
 697    fn sync(&self, cx: &AppContext) {
 698        let mut snapshot = self.snapshot.borrow_mut();
 699        let mut excerpts_to_edit = Vec::new();
 700        let mut reparsed = false;
 701        let mut diagnostics_updated = false;
 702        for buffer_state in self.buffers.values() {
 703            let buffer = buffer_state.buffer.read(cx);
 704            let buffer_edited = buffer.version().gt(&buffer_state.last_version);
 705            let buffer_reparsed = buffer.parse_count() > buffer_state.last_parse_count;
 706            let buffer_diagnostics_updated =
 707                buffer.diagnostics_update_count() > buffer_state.last_diagnostics_update_count;
 708            if buffer_edited || buffer_reparsed || buffer_diagnostics_updated {
 709                excerpts_to_edit.extend(
 710                    buffer_state
 711                        .excerpts
 712                        .iter()
 713                        .map(|excerpt_id| (excerpt_id, buffer_state, buffer_edited)),
 714                );
 715            }
 716
 717            reparsed |= buffer_reparsed;
 718            diagnostics_updated |= buffer_diagnostics_updated;
 719        }
 720        if reparsed {
 721            snapshot.parse_count += 1;
 722        }
 723        if diagnostics_updated {
 724            snapshot.diagnostics_update_count += 1;
 725        }
 726        excerpts_to_edit.sort_unstable_by_key(|(excerpt_id, _, _)| *excerpt_id);
 727
 728        let mut edits = Vec::new();
 729        let mut new_excerpts = SumTree::new();
 730        let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>();
 731
 732        for (id, buffer_state, buffer_edited) in excerpts_to_edit {
 733            new_excerpts.push_tree(cursor.slice(&Some(id), Bias::Left, &()), &());
 734            let old_excerpt = cursor.item().unwrap();
 735            let buffer = buffer_state.buffer.read(cx);
 736
 737            let mut new_excerpt;
 738            if buffer_edited {
 739                edits.extend(
 740                    buffer
 741                        .edits_since_in_range::<usize>(
 742                            old_excerpt.buffer.version(),
 743                            old_excerpt.range.clone(),
 744                        )
 745                        .map(|mut edit| {
 746                            let excerpt_old_start =
 747                                cursor.start().1 + old_excerpt.header_height as usize;
 748                            let excerpt_new_start = new_excerpts.summary().text.bytes
 749                                + old_excerpt.header_height as usize;
 750                            edit.old.start += excerpt_old_start;
 751                            edit.old.end += excerpt_old_start;
 752                            edit.new.start += excerpt_new_start;
 753                            edit.new.end += excerpt_new_start;
 754                            edit
 755                        }),
 756                );
 757
 758                new_excerpt = Excerpt::new(
 759                    id.clone(),
 760                    buffer_state.buffer.id(),
 761                    buffer.snapshot(),
 762                    old_excerpt.range.clone(),
 763                    old_excerpt.header_height,
 764                    old_excerpt.render_header.clone(),
 765                    old_excerpt.has_trailing_newline,
 766                );
 767            } else {
 768                new_excerpt = old_excerpt.clone();
 769                new_excerpt.buffer = buffer.snapshot();
 770            }
 771
 772            new_excerpts.push(new_excerpt, &());
 773            cursor.next(&());
 774        }
 775        new_excerpts.push_tree(cursor.suffix(&()), &());
 776
 777        drop(cursor);
 778        snapshot.excerpts = new_excerpts;
 779
 780        self.subscriptions.publish(edits);
 781    }
 782}
 783
 784#[cfg(any(test, feature = "test-support"))]
 785impl MultiBuffer {
 786    pub fn randomly_edit(
 787        &mut self,
 788        rng: &mut impl rand::Rng,
 789        count: usize,
 790        cx: &mut ModelContext<Self>,
 791    ) {
 792        use text::RandomCharIter;
 793
 794        let snapshot = self.read(cx);
 795        let mut old_ranges: Vec<Range<usize>> = Vec::new();
 796        for _ in 0..count {
 797            let last_end = old_ranges.last().map_or(0, |last_range| last_range.end + 1);
 798            if last_end > snapshot.len() {
 799                break;
 800            }
 801            let end_ix = snapshot.clip_offset(rng.gen_range(0..=last_end), Bias::Right);
 802            let start_ix = snapshot.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
 803            old_ranges.push(start_ix..end_ix);
 804        }
 805        let new_text_len = rng.gen_range(0..10);
 806        let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
 807        log::info!("mutating multi-buffer at {:?}: {:?}", old_ranges, new_text);
 808        drop(snapshot);
 809
 810        self.edit(old_ranges.iter().cloned(), new_text.as_str(), cx);
 811    }
 812}
 813
 814impl Entity for MultiBuffer {
 815    type Event = language::Event;
 816}
 817
 818impl MultiBufferSnapshot {
 819    pub fn text(&self) -> String {
 820        self.chunks(0..self.len(), None)
 821            .map(|chunk| chunk.text)
 822            .collect()
 823    }
 824
 825    pub fn excerpt_headers_in_range<'a>(
 826        &'a self,
 827        range: Range<u32>,
 828    ) -> impl 'a + Iterator<Item = (Range<u32>, RenderHeaderFn)> {
 829        let mut cursor = self.excerpts.cursor::<Point>();
 830        cursor.seek(&Point::new(range.start, 0), Bias::Right, &());
 831
 832        if let Some(excerpt) = cursor.item() {
 833            if range.start >= cursor.start().row + excerpt.header_height as u32 {
 834                cursor.next(&());
 835            }
 836        }
 837
 838        iter::from_fn(move || {
 839            while let Some(excerpt) = cursor.item() {
 840                if cursor.start().row >= range.end {
 841                    break;
 842                }
 843
 844                if let Some(render) = excerpt.render_header.clone() {
 845                    let start = cursor.start().row;
 846                    let end = start + excerpt.header_height as u32;
 847                    cursor.next(&());
 848                    return Some((start..end, render));
 849                } else {
 850                    cursor.next(&());
 851                }
 852            }
 853            None
 854        })
 855    }
 856
 857    pub fn reversed_chars_at<'a, T: ToOffset>(
 858        &'a self,
 859        position: T,
 860    ) -> impl Iterator<Item = char> + 'a {
 861        let mut offset = position.to_offset(self);
 862        let mut cursor = self.excerpts.cursor::<usize>();
 863        cursor.seek(&offset, Bias::Left, &());
 864        let mut excerpt_chunks = cursor.item().map(|excerpt| {
 865            let start_after_header = cursor.start() + excerpt.header_height as usize;
 866            let end_before_footer = cursor.start() + excerpt.text_summary.bytes;
 867
 868            let start = excerpt.range.start.to_offset(&excerpt.buffer);
 869            let end =
 870                start + (cmp::min(offset, end_before_footer).saturating_sub(start_after_header));
 871            excerpt.buffer.reversed_chunks_in_range(start..end)
 872        });
 873        iter::from_fn(move || {
 874            if offset == *cursor.start() {
 875                cursor.prev(&());
 876                let excerpt = cursor.item()?;
 877                excerpt_chunks = Some(
 878                    excerpt
 879                        .buffer
 880                        .reversed_chunks_in_range(excerpt.range.clone()),
 881                );
 882            }
 883
 884            let excerpt = cursor.item().unwrap();
 885            if offset <= cursor.start() + excerpt.header_height as usize {
 886                let header_height = offset - cursor.start();
 887                offset -= header_height;
 888                Some(unsafe { str::from_utf8_unchecked(&NEWLINES[..header_height]) })
 889            } else if offset == cursor.end(&()) && excerpt.has_trailing_newline {
 890                offset -= 1;
 891                Some("\n")
 892            } else {
 893                let chunk = excerpt_chunks.as_mut().unwrap().next().unwrap();
 894                offset -= chunk.len();
 895                Some(chunk)
 896            }
 897        })
 898        .flat_map(|c| c.chars().rev())
 899    }
 900
 901    pub fn chars_at<'a, T: ToOffset>(&'a self, position: T) -> impl Iterator<Item = char> + 'a {
 902        let offset = position.to_offset(self);
 903        self.text_for_range(offset..self.len())
 904            .flat_map(|chunk| chunk.chars())
 905    }
 906
 907    pub fn text_for_range<'a, T: ToOffset>(
 908        &'a self,
 909        range: Range<T>,
 910    ) -> impl Iterator<Item = &'a str> {
 911        self.chunks(range, None).map(|chunk| chunk.text)
 912    }
 913
 914    pub fn is_line_blank(&self, row: u32) -> bool {
 915        self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row)))
 916            .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
 917    }
 918
 919    pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
 920    where
 921        T: ToOffset,
 922    {
 923        let position = position.to_offset(self);
 924        position == self.clip_offset(position, Bias::Left)
 925            && self
 926                .bytes_in_range(position..self.len())
 927                .flatten()
 928                .copied()
 929                .take(needle.len())
 930                .eq(needle.bytes())
 931    }
 932
 933    fn as_singleton(&self) -> Option<&BufferSnapshot> {
 934        let mut excerpts = self.excerpts.iter();
 935        let buffer = excerpts.next().map(|excerpt| &excerpt.buffer);
 936        if excerpts.next().is_none() {
 937            buffer
 938        } else {
 939            None
 940        }
 941    }
 942
 943    pub fn len(&self) -> usize {
 944        self.excerpts.summary().text.bytes
 945    }
 946
 947    pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
 948        let mut cursor = self.excerpts.cursor::<usize>();
 949        cursor.seek(&offset, Bias::Right, &());
 950        if let Some(excerpt) = cursor.item() {
 951            let header_end = *cursor.start() + excerpt.header_height as usize;
 952            if offset < header_end {
 953                if bias == Bias::Left {
 954                    cursor.prev(&());
 955                    if let Some(excerpt) = cursor.item() {
 956                        return *cursor.start() + excerpt.text_summary.bytes;
 957                    }
 958                }
 959                header_end
 960            } else {
 961                let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
 962                let buffer_offset = excerpt
 963                    .buffer
 964                    .clip_offset(excerpt_start + (offset - header_end), bias);
 965                let offset_in_excerpt = if buffer_offset > excerpt_start {
 966                    buffer_offset - excerpt_start
 967                } else {
 968                    0
 969                };
 970                header_end + offset_in_excerpt
 971            }
 972        } else {
 973            self.excerpts.summary().text.bytes
 974        }
 975    }
 976
 977    pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
 978        let mut cursor = self.excerpts.cursor::<Point>();
 979        cursor.seek(&point, Bias::Right, &());
 980        if let Some(excerpt) = cursor.item() {
 981            let header_end = *cursor.start() + Point::new(excerpt.header_height as u32, 0);
 982            if point < header_end {
 983                if bias == Bias::Left {
 984                    cursor.prev(&());
 985                    if let Some(excerpt) = cursor.item() {
 986                        return *cursor.start() + excerpt.text_summary.lines;
 987                    }
 988                }
 989                header_end
 990            } else {
 991                let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
 992                let buffer_point = excerpt
 993                    .buffer
 994                    .clip_point(excerpt_start + (point - header_end), bias);
 995                let point_in_excerpt = if buffer_point > excerpt_start {
 996                    buffer_point - excerpt_start
 997                } else {
 998                    Point::zero()
 999                };
1000                header_end + point_in_excerpt
1001            }
1002        } else {
1003            self.excerpts.summary().text.lines
1004        }
1005    }
1006
1007    pub fn clip_point_utf16(&self, point: PointUtf16, bias: Bias) -> PointUtf16 {
1008        let mut cursor = self.excerpts.cursor::<PointUtf16>();
1009        cursor.seek(&point, Bias::Right, &());
1010        if let Some(excerpt) = cursor.item() {
1011            let header_end = *cursor.start() + PointUtf16::new(excerpt.header_height as u32, 0);
1012            if point < header_end {
1013                if bias == Bias::Left {
1014                    cursor.prev(&());
1015                    if let Some(excerpt) = cursor.item() {
1016                        return *cursor.start() + excerpt.text_summary.lines_utf16;
1017                    }
1018                }
1019                header_end
1020            } else {
1021                let excerpt_start = excerpt
1022                    .buffer
1023                    .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
1024                let buffer_point = excerpt
1025                    .buffer
1026                    .clip_point_utf16(excerpt_start + (point - header_end), bias);
1027                let point_in_excerpt = if buffer_point > excerpt_start {
1028                    buffer_point - excerpt_start
1029                } else {
1030                    PointUtf16::new(0, 0)
1031                };
1032                header_end + point_in_excerpt
1033            }
1034        } else {
1035            self.excerpts.summary().text.lines_utf16
1036        }
1037    }
1038
1039    pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> MultiBufferBytes<'a> {
1040        let range = range.start.to_offset(self)..range.end.to_offset(self);
1041        let mut excerpts = self.excerpts.cursor::<usize>();
1042        excerpts.seek(&range.start, Bias::Right, &());
1043
1044        let mut chunk = &[][..];
1045        let excerpt_bytes = if let Some(excerpt) = excerpts.item() {
1046            let mut excerpt_bytes = excerpt
1047                .bytes_in_range(range.start - excerpts.start()..range.end - excerpts.start());
1048            chunk = excerpt_bytes.next().unwrap_or(&[][..]);
1049            Some(excerpt_bytes)
1050        } else {
1051            None
1052        };
1053
1054        MultiBufferBytes {
1055            range,
1056            excerpts,
1057            excerpt_bytes,
1058            chunk,
1059        }
1060    }
1061
1062    pub fn buffer_rows<'a>(&'a self, start_row: u32) -> MultiBufferRows<'a> {
1063        let mut result = MultiBufferRows {
1064            header_height: 0,
1065            buffer_row_range: 0..0,
1066            excerpts: self.excerpts.cursor(),
1067        };
1068        result.seek(start_row);
1069        result
1070    }
1071
1072    pub fn chunks<'a, T: ToOffset>(
1073        &'a self,
1074        range: Range<T>,
1075        theme: Option<&'a SyntaxTheme>,
1076    ) -> MultiBufferChunks<'a> {
1077        let range = range.start.to_offset(self)..range.end.to_offset(self);
1078        let mut chunks = MultiBufferChunks {
1079            range: range.clone(),
1080            excerpts: self.excerpts.cursor(),
1081            excerpt_chunks: None,
1082            theme,
1083        };
1084        chunks.seek(range.start);
1085        chunks
1086    }
1087
1088    pub fn offset_to_point(&self, offset: usize) -> Point {
1089        let mut cursor = self.excerpts.cursor::<(usize, Point)>();
1090        cursor.seek(&offset, Bias::Right, &());
1091        if let Some(excerpt) = cursor.item() {
1092            let (start_offset, start_point) = cursor.start();
1093            let overshoot = offset - start_offset;
1094            let header_height = excerpt.header_height as usize;
1095            if overshoot < header_height {
1096                *start_point + Point::new(overshoot as u32, 0)
1097            } else {
1098                let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1099                let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
1100                let buffer_point = excerpt
1101                    .buffer
1102                    .offset_to_point(excerpt_start_offset + (overshoot - header_height));
1103                *start_point
1104                    + Point::new(header_height as u32, 0)
1105                    + (buffer_point - excerpt_start_point)
1106            }
1107        } else {
1108            self.excerpts.summary().text.lines
1109        }
1110    }
1111
1112    pub fn point_to_offset(&self, point: Point) -> usize {
1113        let mut cursor = self.excerpts.cursor::<(Point, usize)>();
1114        cursor.seek(&point, Bias::Right, &());
1115        if let Some(excerpt) = cursor.item() {
1116            let (start_point, start_offset) = cursor.start();
1117            let overshoot = point - start_point;
1118            let header_height = Point::new(excerpt.header_height as u32, 0);
1119            if overshoot < header_height {
1120                start_offset + overshoot.row as usize
1121            } else {
1122                let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1123                let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
1124                let buffer_offset = excerpt
1125                    .buffer
1126                    .point_to_offset(excerpt_start_point + (overshoot - header_height));
1127                *start_offset + excerpt.header_height as usize + buffer_offset
1128                    - excerpt_start_offset
1129            }
1130        } else {
1131            self.excerpts.summary().text.bytes
1132        }
1133    }
1134
1135    pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
1136        let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>();
1137        cursor.seek(&point, Bias::Right, &());
1138        if let Some(excerpt) = cursor.item() {
1139            let (start_point, start_offset) = cursor.start();
1140            let overshoot = point - start_point;
1141            let header_height = PointUtf16::new(excerpt.header_height as u32, 0);
1142            if overshoot < header_height {
1143                start_offset + overshoot.row as usize
1144            } else {
1145                let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
1146                let excerpt_start_point = excerpt
1147                    .buffer
1148                    .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
1149                let buffer_offset = excerpt
1150                    .buffer
1151                    .point_utf16_to_offset(excerpt_start_point + (overshoot - header_height));
1152                *start_offset
1153                    + excerpt.header_height as usize
1154                    + (buffer_offset - excerpt_start_offset)
1155            }
1156        } else {
1157            self.excerpts.summary().text.bytes
1158        }
1159    }
1160
1161    pub fn indent_column_for_line(&self, row: u32) -> u32 {
1162        if let Some((buffer, range)) = self.buffer_line_for_row(row) {
1163            buffer
1164                .indent_column_for_line(range.start.row)
1165                .min(range.end.column)
1166                .saturating_sub(range.start.column)
1167        } else {
1168            0
1169        }
1170    }
1171
1172    pub fn line_len(&self, row: u32) -> u32 {
1173        if let Some((_, range)) = self.buffer_line_for_row(row) {
1174            range.end.column - range.start.column
1175        } else {
1176            0
1177        }
1178    }
1179
1180    fn buffer_line_for_row(&self, row: u32) -> Option<(&BufferSnapshot, Range<Point>)> {
1181        let mut cursor = self.excerpts.cursor::<Point>();
1182        cursor.seek(&Point::new(row, 0), Bias::Right, &());
1183        if let Some(excerpt) = cursor.item() {
1184            let overshoot = row - cursor.start().row;
1185            let header_height = excerpt.header_height as u32;
1186            if overshoot >= header_height {
1187                let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
1188                let excerpt_end = excerpt.range.end.to_point(&excerpt.buffer);
1189                let buffer_row = excerpt_start.row + overshoot - header_height;
1190                let line_start = Point::new(buffer_row, 0);
1191                let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
1192                return Some((
1193                    &excerpt.buffer,
1194                    line_start.max(excerpt_start)..line_end.min(excerpt_end),
1195                ));
1196            }
1197        }
1198        None
1199    }
1200
1201    pub fn max_point(&self) -> Point {
1202        self.text_summary().lines
1203    }
1204
1205    pub fn text_summary(&self) -> TextSummary {
1206        self.excerpts.summary().text
1207    }
1208
1209    pub fn text_summary_for_range<'a, D, O>(&'a self, range: Range<O>) -> D
1210    where
1211        D: TextDimension,
1212        O: ToOffset,
1213    {
1214        let mut summary = D::default();
1215        let mut range = range.start.to_offset(self)..range.end.to_offset(self);
1216        let mut cursor = self.excerpts.cursor::<usize>();
1217        cursor.seek(&range.start, Bias::Right, &());
1218        if let Some(excerpt) = cursor.item() {
1219            let start_after_header = cursor.start() + excerpt.header_height as usize;
1220            if range.start < start_after_header {
1221                let header_len = cmp::min(range.end, start_after_header) - range.start;
1222                summary.add_assign(&D::from_text_summary(&TextSummary {
1223                    bytes: header_len,
1224                    lines: Point::new(header_len as u32, 0),
1225                    lines_utf16: PointUtf16::new(header_len as u32, 0),
1226                    first_line_chars: 0,
1227                    last_line_chars: 0,
1228                    longest_row: 0,
1229                    longest_row_chars: 0,
1230                }));
1231                range.start = start_after_header;
1232                range.end = cmp::max(range.start, range.end);
1233            }
1234
1235            let mut end_before_newline = cursor.end(&());
1236            if excerpt.has_trailing_newline {
1237                end_before_newline -= 1;
1238            }
1239
1240            let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1241            let start_in_excerpt = excerpt_start + (range.start - start_after_header);
1242            let end_in_excerpt =
1243                excerpt_start + (cmp::min(end_before_newline, range.end) - start_after_header);
1244            summary.add_assign(
1245                &excerpt
1246                    .buffer
1247                    .text_summary_for_range(start_in_excerpt..end_in_excerpt),
1248            );
1249
1250            if range.end > end_before_newline {
1251                summary.add_assign(&D::from_text_summary(&TextSummary {
1252                    bytes: 1,
1253                    lines: Point::new(1 as u32, 0),
1254                    lines_utf16: PointUtf16::new(1 as u32, 0),
1255                    first_line_chars: 0,
1256                    last_line_chars: 0,
1257                    longest_row: 0,
1258                    longest_row_chars: 0,
1259                }));
1260            }
1261
1262            cursor.next(&());
1263        }
1264
1265        if range.end > *cursor.start() {
1266            summary.add_assign(&D::from_text_summary(&cursor.summary::<_, TextSummary>(
1267                &range.end,
1268                Bias::Right,
1269                &(),
1270            )));
1271            if let Some(excerpt) = cursor.item() {
1272                let start_after_header = cursor.start() + excerpt.header_height as usize;
1273                let header_len =
1274                    cmp::min(range.end - cursor.start(), excerpt.header_height as usize);
1275                summary.add_assign(&D::from_text_summary(&TextSummary {
1276                    bytes: header_len,
1277                    lines: Point::new(header_len as u32, 0),
1278                    lines_utf16: PointUtf16::new(header_len as u32, 0),
1279                    first_line_chars: 0,
1280                    last_line_chars: 0,
1281                    longest_row: 0,
1282                    longest_row_chars: 0,
1283                }));
1284                range.end = cmp::max(start_after_header, range.end);
1285
1286                let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
1287                let end_in_excerpt = excerpt_start + (range.end - start_after_header);
1288                summary.add_assign(
1289                    &excerpt
1290                        .buffer
1291                        .text_summary_for_range(excerpt_start..end_in_excerpt),
1292                );
1293                cursor.next(&());
1294            }
1295        }
1296
1297        summary
1298    }
1299
1300    pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
1301    where
1302        D: TextDimension + Ord + Sub<D, Output = D>,
1303    {
1304        let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1305        cursor.seek(&Some(&anchor.excerpt_id), Bias::Left, &());
1306        if cursor.item().is_none() {
1307            cursor.next(&());
1308        }
1309
1310        let mut position = D::from_text_summary(&cursor.start().text);
1311        if let Some(excerpt) = cursor.item() {
1312            position.add_summary(&excerpt.header_summary(), &());
1313            if excerpt.id == anchor.excerpt_id {
1314                let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
1315                let buffer_position = anchor.text_anchor.summary::<D>(&excerpt.buffer);
1316                if buffer_position > excerpt_buffer_start {
1317                    position.add_assign(&(buffer_position - excerpt_buffer_start));
1318                }
1319            }
1320        }
1321        position
1322    }
1323
1324    pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
1325    where
1326        D: TextDimension + Ord + Sub<D, Output = D>,
1327        I: 'a + IntoIterator<Item = &'a Anchor>,
1328    {
1329        let mut anchors = anchors.into_iter().peekable();
1330        let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
1331        let mut summaries = Vec::new();
1332        while let Some(anchor) = anchors.peek() {
1333            let excerpt_id = &anchor.excerpt_id;
1334            let excerpt_anchors = iter::from_fn(|| {
1335                let anchor = anchors.peek()?;
1336                if anchor.excerpt_id == *excerpt_id {
1337                    Some(&anchors.next().unwrap().text_anchor)
1338                } else {
1339                    None
1340                }
1341            });
1342
1343            cursor.seek_forward(&Some(excerpt_id), Bias::Left, &());
1344            if cursor.item().is_none() {
1345                cursor.next(&());
1346            }
1347
1348            let mut position = D::from_text_summary(&cursor.start().text);
1349            if let Some(excerpt) = cursor.item() {
1350                position.add_summary(&excerpt.header_summary(), &());
1351                if excerpt.id == *excerpt_id {
1352                    let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
1353                    summaries.extend(
1354                        excerpt
1355                            .buffer
1356                            .summaries_for_anchors::<D, _>(excerpt_anchors)
1357                            .map(move |summary| {
1358                                let mut position = position.clone();
1359                                let excerpt_buffer_start = excerpt_buffer_start.clone();
1360                                if summary > excerpt_buffer_start {
1361                                    position.add_assign(&(summary - excerpt_buffer_start));
1362                                }
1363                                position
1364                            }),
1365                    );
1366                    continue;
1367                }
1368            }
1369
1370            summaries.extend(excerpt_anchors.map(|_| position.clone()));
1371        }
1372
1373        summaries
1374    }
1375
1376    pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
1377        self.anchor_at(position, Bias::Left)
1378    }
1379
1380    pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
1381        self.anchor_at(position, Bias::Right)
1382    }
1383
1384    pub fn anchor_at<T: ToOffset>(&self, position: T, mut bias: Bias) -> Anchor {
1385        let offset = position.to_offset(self);
1386        let mut cursor = self.excerpts.cursor::<(usize, Option<&ExcerptId>)>();
1387        cursor.seek(&offset, Bias::Right, &());
1388        if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left {
1389            cursor.prev(&());
1390        }
1391        if let Some(excerpt) = cursor.item() {
1392            let start_after_header = cursor.start().0 + excerpt.header_height as usize;
1393            let mut overshoot = offset.saturating_sub(start_after_header);
1394            if excerpt.has_trailing_newline && offset == cursor.end(&()).0 {
1395                overshoot -= 1;
1396                bias = Bias::Right;
1397            }
1398
1399            let buffer_start = excerpt.range.start.to_offset(&excerpt.buffer);
1400            let text_anchor =
1401                excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias));
1402            Anchor {
1403                excerpt_id: excerpt.id.clone(),
1404                text_anchor,
1405            }
1406        } else if offset == 0 && bias == Bias::Left {
1407            Anchor::min()
1408        } else {
1409            Anchor::max()
1410        }
1411    }
1412
1413    pub fn anchor_in_excerpt(&self, excerpt_id: ExcerptId, text_anchor: text::Anchor) -> Anchor {
1414        let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1415        cursor.seek(&Some(&excerpt_id), Bias::Left, &());
1416        if let Some(excerpt) = cursor.item() {
1417            if excerpt.id == excerpt_id {
1418                let text_anchor = excerpt.clip_anchor(text_anchor);
1419                drop(cursor);
1420                return Anchor {
1421                    excerpt_id,
1422                    text_anchor,
1423                };
1424            }
1425        }
1426        panic!("excerpt not found");
1427    }
1428
1429    pub fn parse_count(&self) -> usize {
1430        self.parse_count
1431    }
1432
1433    pub fn enclosing_bracket_ranges<T: ToOffset>(
1434        &self,
1435        range: Range<T>,
1436    ) -> Option<(Range<usize>, Range<usize>)> {
1437        let range = range.start.to_offset(self)..range.end.to_offset(self);
1438
1439        let mut cursor = self.excerpts.cursor::<usize>();
1440        cursor.seek(&range.start, Bias::Right, &());
1441        let start_excerpt = cursor.item();
1442
1443        cursor.seek(&range.end, Bias::Right, &());
1444        let end_excerpt = cursor.item();
1445
1446        start_excerpt
1447            .zip(end_excerpt)
1448            .and_then(|(start_excerpt, end_excerpt)| {
1449                if start_excerpt.id != end_excerpt.id {
1450                    return None;
1451                }
1452
1453                let excerpt_buffer_start =
1454                    start_excerpt.range.start.to_offset(&start_excerpt.buffer);
1455                let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes
1456                    - start_excerpt.header_height as usize;
1457
1458                let start_after_header = cursor.start() + start_excerpt.header_height as usize;
1459                let start_in_buffer =
1460                    excerpt_buffer_start + range.start.saturating_sub(start_after_header);
1461                let end_in_buffer =
1462                    excerpt_buffer_start + range.end.saturating_sub(start_after_header);
1463                let (mut start_bracket_range, mut end_bracket_range) = start_excerpt
1464                    .buffer
1465                    .enclosing_bracket_ranges(start_in_buffer..end_in_buffer)?;
1466
1467                if start_bracket_range.start >= excerpt_buffer_start
1468                    && end_bracket_range.end < excerpt_buffer_end
1469                {
1470                    start_bracket_range.start =
1471                        start_after_header + (start_bracket_range.start - excerpt_buffer_start);
1472                    start_bracket_range.end =
1473                        start_after_header + (start_bracket_range.end - excerpt_buffer_start);
1474                    end_bracket_range.start =
1475                        start_after_header + (end_bracket_range.start - excerpt_buffer_start);
1476                    end_bracket_range.end =
1477                        start_after_header + (end_bracket_range.end - excerpt_buffer_start);
1478                    Some((start_bracket_range, end_bracket_range))
1479                } else {
1480                    None
1481                }
1482            })
1483    }
1484
1485    pub fn diagnostics_update_count(&self) -> usize {
1486        self.diagnostics_update_count
1487    }
1488
1489    pub fn language(&self) -> Option<&Arc<Language>> {
1490        self.excerpts
1491            .iter()
1492            .next()
1493            .and_then(|excerpt| excerpt.buffer.language())
1494    }
1495
1496    pub fn diagnostic_group<'a, O>(
1497        &'a self,
1498        group_id: usize,
1499    ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
1500    where
1501        O: text::FromAnchor + 'a,
1502    {
1503        self.as_singleton().unwrap().diagnostic_group(group_id)
1504    }
1505
1506    pub fn diagnostics_in_range<'a, T, O>(
1507        &'a self,
1508        range: Range<T>,
1509    ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
1510    where
1511        T: 'a + ToOffset,
1512        O: 'a + text::FromAnchor,
1513    {
1514        let range = range.start.to_offset(self)..range.end.to_offset(self);
1515        self.as_singleton().unwrap().diagnostics_in_range(range)
1516    }
1517
1518    pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
1519        let range = range.start.to_offset(self)..range.end.to_offset(self);
1520
1521        let mut cursor = self.excerpts.cursor::<usize>();
1522        cursor.seek(&range.start, Bias::Right, &());
1523        let start_excerpt = cursor.item();
1524
1525        cursor.seek(&range.end, Bias::Right, &());
1526        let end_excerpt = cursor.item();
1527
1528        start_excerpt
1529            .zip(end_excerpt)
1530            .and_then(|(start_excerpt, end_excerpt)| {
1531                if start_excerpt.id != end_excerpt.id {
1532                    return None;
1533                }
1534
1535                let excerpt_buffer_start =
1536                    start_excerpt.range.start.to_offset(&start_excerpt.buffer);
1537                let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.bytes
1538                    - start_excerpt.header_height as usize;
1539
1540                let start_after_header = cursor.start() + start_excerpt.header_height as usize;
1541                let start_in_buffer =
1542                    excerpt_buffer_start + range.start.saturating_sub(start_after_header);
1543                let end_in_buffer =
1544                    excerpt_buffer_start + range.end.saturating_sub(start_after_header);
1545                let mut ancestor_buffer_range = start_excerpt
1546                    .buffer
1547                    .range_for_syntax_ancestor(start_in_buffer..end_in_buffer)?;
1548                ancestor_buffer_range.start =
1549                    cmp::max(ancestor_buffer_range.start, excerpt_buffer_start);
1550                ancestor_buffer_range.end = cmp::min(ancestor_buffer_range.end, excerpt_buffer_end);
1551
1552                let start =
1553                    start_after_header + (ancestor_buffer_range.start - excerpt_buffer_start);
1554                let end = start_after_header + (ancestor_buffer_range.end - excerpt_buffer_start);
1555                Some(start..end)
1556            })
1557    }
1558
1559    fn buffer_snapshot_for_excerpt<'a>(
1560        &'a self,
1561        excerpt_id: &'a ExcerptId,
1562    ) -> Option<&'a BufferSnapshot> {
1563        let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1564        cursor.seek(&Some(excerpt_id), Bias::Left, &());
1565        if let Some(excerpt) = cursor.item() {
1566            if excerpt.id == *excerpt_id {
1567                return Some(&excerpt.buffer);
1568            }
1569        }
1570        None
1571    }
1572
1573    pub fn remote_selections_in_range<'a>(
1574        &'a self,
1575        range: &'a Range<Anchor>,
1576    ) -> impl 'a + Iterator<Item = (ReplicaId, Selection<Anchor>)> {
1577        let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1578        cursor.seek(&Some(&range.start.excerpt_id), Bias::Left, &());
1579        cursor
1580            .take_while(move |excerpt| excerpt.id <= range.end.excerpt_id)
1581            .flat_map(move |excerpt| {
1582                let mut query_range = excerpt.range.start.clone()..excerpt.range.end.clone();
1583                if excerpt.id == range.start.excerpt_id {
1584                    query_range.start = range.start.text_anchor.clone();
1585                }
1586                if excerpt.id == range.end.excerpt_id {
1587                    query_range.end = range.end.text_anchor.clone();
1588                }
1589
1590                excerpt
1591                    .buffer
1592                    .remote_selections_in_range(query_range)
1593                    .flat_map(move |(replica_id, selections)| {
1594                        selections.map(move |selection| {
1595                            let mut start = Anchor {
1596                                excerpt_id: excerpt.id.clone(),
1597                                text_anchor: selection.start.clone(),
1598                            };
1599                            let mut end = Anchor {
1600                                excerpt_id: excerpt.id.clone(),
1601                                text_anchor: selection.end.clone(),
1602                            };
1603                            if range.start.cmp(&start, self).unwrap().is_gt() {
1604                                start = range.start.clone();
1605                            }
1606                            if range.end.cmp(&end, self).unwrap().is_lt() {
1607                                end = range.end.clone();
1608                            }
1609
1610                            (
1611                                replica_id,
1612                                Selection {
1613                                    id: selection.id,
1614                                    start,
1615                                    end,
1616                                    reversed: selection.reversed,
1617                                    goal: selection.goal,
1618                                },
1619                            )
1620                        })
1621                    })
1622            })
1623    }
1624}
1625
1626impl History {
1627    fn start_transaction(&mut self, now: Instant) -> Option<TransactionId> {
1628        self.transaction_depth += 1;
1629        if self.transaction_depth == 1 {
1630            let id = post_inc(&mut self.next_transaction_id);
1631            self.undo_stack.push(Transaction {
1632                id,
1633                buffer_transactions: Default::default(),
1634                first_edit_at: now,
1635                last_edit_at: now,
1636            });
1637            Some(id)
1638        } else {
1639            None
1640        }
1641    }
1642
1643    fn end_transaction(
1644        &mut self,
1645        now: Instant,
1646        buffer_transactions: HashSet<(usize, TransactionId)>,
1647    ) -> bool {
1648        assert_ne!(self.transaction_depth, 0);
1649        self.transaction_depth -= 1;
1650        if self.transaction_depth == 0 {
1651            if buffer_transactions.is_empty() {
1652                self.undo_stack.pop();
1653                false
1654            } else {
1655                let transaction = self.undo_stack.last_mut().unwrap();
1656                transaction.last_edit_at = now;
1657                transaction.buffer_transactions.extend(buffer_transactions);
1658                true
1659            }
1660        } else {
1661            false
1662        }
1663    }
1664
1665    fn pop_undo(&mut self) -> Option<&Transaction> {
1666        assert_eq!(self.transaction_depth, 0);
1667        if let Some(transaction) = self.undo_stack.pop() {
1668            self.redo_stack.push(transaction);
1669            self.redo_stack.last()
1670        } else {
1671            None
1672        }
1673    }
1674
1675    fn pop_redo(&mut self) -> Option<&Transaction> {
1676        assert_eq!(self.transaction_depth, 0);
1677        if let Some(transaction) = self.redo_stack.pop() {
1678            self.undo_stack.push(transaction);
1679            self.undo_stack.last()
1680        } else {
1681            None
1682        }
1683    }
1684
1685    fn group(&mut self) -> Option<TransactionId> {
1686        let mut new_len = self.undo_stack.len();
1687        let mut transactions = self.undo_stack.iter_mut();
1688
1689        if let Some(mut transaction) = transactions.next_back() {
1690            while let Some(prev_transaction) = transactions.next_back() {
1691                if transaction.first_edit_at - prev_transaction.last_edit_at <= self.group_interval
1692                {
1693                    transaction = prev_transaction;
1694                    new_len -= 1;
1695                } else {
1696                    break;
1697                }
1698            }
1699        }
1700
1701        let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len);
1702        if let Some(last_transaction) = transactions_to_keep.last_mut() {
1703            if let Some(transaction) = transactions_to_merge.last() {
1704                last_transaction.last_edit_at = transaction.last_edit_at;
1705            }
1706        }
1707
1708        self.undo_stack.truncate(new_len);
1709        self.undo_stack.last().map(|t| t.id)
1710    }
1711}
1712
1713impl Excerpt {
1714    fn new(
1715        id: ExcerptId,
1716        buffer_id: usize,
1717        buffer: BufferSnapshot,
1718        range: Range<text::Anchor>,
1719        header_height: u8,
1720        render_header: Option<RenderHeaderFn>,
1721        has_trailing_newline: bool,
1722    ) -> Self {
1723        let mut text_summary =
1724            buffer.text_summary_for_range::<TextSummary, _>(range.to_offset(&buffer));
1725        if header_height > 0 {
1726            text_summary.first_line_chars = 0;
1727            text_summary.lines.row += header_height as u32;
1728            text_summary.lines_utf16.row += header_height as u32;
1729            text_summary.bytes += header_height as usize;
1730            text_summary.longest_row += header_height as u32;
1731        }
1732        Excerpt {
1733            id,
1734            buffer_id,
1735            buffer,
1736            range,
1737            text_summary,
1738            header_height,
1739            render_header,
1740            has_trailing_newline,
1741        }
1742    }
1743
1744    fn header_summary(&self) -> TextSummary {
1745        TextSummary {
1746            bytes: self.header_height as usize,
1747            lines: Point::new(self.header_height as u32, 0),
1748            lines_utf16: PointUtf16::new(self.header_height as u32, 0),
1749            first_line_chars: 0,
1750            last_line_chars: 0,
1751            longest_row: 0,
1752            longest_row_chars: 0,
1753        }
1754    }
1755
1756    fn chunks_in_range<'a>(
1757        &'a self,
1758        range: Range<usize>,
1759        theme: Option<&'a SyntaxTheme>,
1760    ) -> ExcerptChunks<'a> {
1761        let content_start = self.range.start.to_offset(&self.buffer);
1762        let chunks_start = content_start + range.start.saturating_sub(self.header_height as usize);
1763        let chunks_end = content_start
1764            + cmp::min(range.end, self.text_summary.bytes)
1765                .saturating_sub(self.header_height as usize);
1766
1767        let header_height = cmp::min(
1768            (self.header_height as usize).saturating_sub(range.start),
1769            range.len(),
1770        );
1771
1772        let footer_height = if self.has_trailing_newline
1773            && range.start <= self.text_summary.bytes
1774            && range.end > self.text_summary.bytes
1775        {
1776            1
1777        } else {
1778            0
1779        };
1780
1781        let content_chunks = self.buffer.chunks(chunks_start..chunks_end, theme);
1782
1783        ExcerptChunks {
1784            header_height,
1785            content_chunks,
1786            footer_height,
1787        }
1788    }
1789
1790    fn bytes_in_range(&self, range: Range<usize>) -> ExcerptBytes {
1791        let content_start = self.range.start.to_offset(&self.buffer);
1792        let bytes_start = content_start + range.start.saturating_sub(self.header_height as usize);
1793        let bytes_end = content_start
1794            + cmp::min(range.end, self.text_summary.bytes)
1795                .saturating_sub(self.header_height as usize);
1796
1797        let header_height = cmp::min(
1798            (self.header_height as usize).saturating_sub(range.start),
1799            range.len(),
1800        );
1801
1802        let footer_height = if self.has_trailing_newline
1803            && range.start <= self.text_summary.bytes
1804            && range.end > self.text_summary.bytes
1805        {
1806            1
1807        } else {
1808            0
1809        };
1810
1811        let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end);
1812
1813        ExcerptBytes {
1814            header_height,
1815            content_bytes,
1816            footer_height,
1817        }
1818    }
1819
1820    fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
1821        if text_anchor
1822            .cmp(&self.range.start, &self.buffer)
1823            .unwrap()
1824            .is_lt()
1825        {
1826            self.range.start.clone()
1827        } else if text_anchor
1828            .cmp(&self.range.end, &self.buffer)
1829            .unwrap()
1830            .is_gt()
1831        {
1832            self.range.end.clone()
1833        } else {
1834            text_anchor
1835        }
1836    }
1837}
1838
1839impl fmt::Debug for Excerpt {
1840    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1841        f.debug_struct("Excerpt")
1842            .field("id", &self.id)
1843            .field("buffer_id", &self.buffer_id)
1844            .field("range", &self.range)
1845            .field("text_summary", &self.text_summary)
1846            .field("header_height", &self.header_height)
1847            .field("has_trailing_newline", &self.has_trailing_newline)
1848            .finish()
1849    }
1850}
1851
1852impl sum_tree::Item for Excerpt {
1853    type Summary = ExcerptSummary;
1854
1855    fn summary(&self) -> Self::Summary {
1856        let mut text = self.text_summary.clone();
1857        if self.has_trailing_newline {
1858            text += TextSummary::from("\n");
1859        }
1860        ExcerptSummary {
1861            excerpt_id: self.id.clone(),
1862            text,
1863        }
1864    }
1865}
1866
1867impl sum_tree::Summary for ExcerptSummary {
1868    type Context = ();
1869
1870    fn add_summary(&mut self, summary: &Self, _: &()) {
1871        debug_assert!(summary.excerpt_id > self.excerpt_id);
1872        self.excerpt_id = summary.excerpt_id.clone();
1873        self.text.add_summary(&summary.text, &());
1874    }
1875}
1876
1877impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
1878    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1879        *self += &summary.text;
1880    }
1881}
1882
1883impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
1884    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1885        *self += summary.text.bytes;
1886    }
1887}
1888
1889impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
1890    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
1891        Ord::cmp(self, &cursor_location.text.bytes)
1892    }
1893}
1894
1895impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Option<&'a ExcerptId> {
1896    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
1897        Ord::cmp(self, &Some(&cursor_location.excerpt_id))
1898    }
1899}
1900
1901impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
1902    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1903        *self += summary.text.lines;
1904    }
1905}
1906
1907impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
1908    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1909        *self += summary.text.lines_utf16
1910    }
1911}
1912
1913impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a ExcerptId> {
1914    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1915        *self = Some(&summary.excerpt_id);
1916    }
1917}
1918
1919impl<'a> MultiBufferRows<'a> {
1920    pub fn seek(&mut self, row: u32) {
1921        self.header_height = 0;
1922        self.buffer_row_range = 0..0;
1923
1924        self.excerpts
1925            .seek_forward(&Point::new(row, 0), Bias::Right, &());
1926        if self.excerpts.item().is_none() {
1927            self.excerpts.prev(&());
1928
1929            if self.excerpts.item().is_none() && row == 0 {
1930                self.buffer_row_range = 0..1;
1931                return;
1932            }
1933        }
1934
1935        if let Some(excerpt) = self.excerpts.item() {
1936            let overshoot = row - self.excerpts.start().row;
1937            let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer).row;
1938            let excerpt_header_height = excerpt.header_height as u32;
1939
1940            self.header_height = excerpt_header_height.saturating_sub(overshoot);
1941            self.buffer_row_range.start =
1942                excerpt_start + overshoot.saturating_sub(excerpt_header_height);
1943            self.buffer_row_range.end =
1944                excerpt_start + excerpt.text_summary.lines.row + 1 - excerpt_header_height;
1945        }
1946    }
1947}
1948
1949impl<'a> Iterator for MultiBufferRows<'a> {
1950    type Item = Option<u32>;
1951
1952    fn next(&mut self) -> Option<Self::Item> {
1953        loop {
1954            if self.header_height > 0 {
1955                self.header_height -= 1;
1956                return Some(None);
1957            }
1958            if !self.buffer_row_range.is_empty() {
1959                let row = Some(self.buffer_row_range.start);
1960                self.buffer_row_range.start += 1;
1961                return Some(row);
1962            }
1963            self.excerpts.item()?;
1964            self.excerpts.next(&());
1965            let excerpt = self.excerpts.item()?;
1966            self.header_height = excerpt.header_height as u32;
1967            self.buffer_row_range.start = excerpt.range.start.to_point(&excerpt.buffer).row;
1968            self.buffer_row_range.end =
1969                self.buffer_row_range.start + excerpt.text_summary.lines.row + 1
1970                    - self.header_height;
1971        }
1972    }
1973}
1974
1975impl<'a> MultiBufferChunks<'a> {
1976    pub fn offset(&self) -> usize {
1977        self.range.start
1978    }
1979
1980    pub fn seek(&mut self, offset: usize) {
1981        self.range.start = offset;
1982        self.excerpts.seek(&offset, Bias::Right, &());
1983        if let Some(excerpt) = self.excerpts.item() {
1984            self.excerpt_chunks = Some(excerpt.chunks_in_range(
1985                self.range.start - self.excerpts.start()..self.range.end - self.excerpts.start(),
1986                self.theme,
1987            ));
1988        } else {
1989            self.excerpt_chunks = None;
1990        }
1991    }
1992}
1993
1994impl<'a> Iterator for MultiBufferChunks<'a> {
1995    type Item = Chunk<'a>;
1996
1997    fn next(&mut self) -> Option<Self::Item> {
1998        if self.range.is_empty() {
1999            None
2000        } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() {
2001            self.range.start += chunk.text.len();
2002            Some(chunk)
2003        } else {
2004            self.excerpts.next(&());
2005            let excerpt = self.excerpts.item()?;
2006            self.excerpt_chunks = Some(
2007                excerpt.chunks_in_range(0..self.range.end - self.excerpts.start(), self.theme),
2008            );
2009            self.next()
2010        }
2011    }
2012}
2013
2014impl<'a> MultiBufferBytes<'a> {
2015    fn consume(&mut self, len: usize) {
2016        self.range.start += len;
2017        self.chunk = &self.chunk[len..];
2018
2019        if !self.range.is_empty() && self.chunk.is_empty() {
2020            if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) {
2021                self.chunk = chunk;
2022            } else {
2023                self.excerpts.next(&());
2024                if let Some(excerpt) = self.excerpts.item() {
2025                    let mut excerpt_bytes =
2026                        excerpt.bytes_in_range(0..self.range.end - self.excerpts.start());
2027                    self.chunk = excerpt_bytes.next().unwrap();
2028                    self.excerpt_bytes = Some(excerpt_bytes);
2029                }
2030            }
2031        }
2032    }
2033}
2034
2035impl<'a> Iterator for MultiBufferBytes<'a> {
2036    type Item = &'a [u8];
2037
2038    fn next(&mut self) -> Option<Self::Item> {
2039        let chunk = self.chunk;
2040        if chunk.is_empty() {
2041            None
2042        } else {
2043            self.consume(chunk.len());
2044            Some(chunk)
2045        }
2046    }
2047}
2048
2049impl<'a> io::Read for MultiBufferBytes<'a> {
2050    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2051        let len = cmp::min(buf.len(), self.chunk.len());
2052        buf[..len].copy_from_slice(&self.chunk[..len]);
2053        if len > 0 {
2054            self.consume(len);
2055        }
2056        Ok(len)
2057    }
2058}
2059
2060impl<'a> Iterator for ExcerptBytes<'a> {
2061    type Item = &'a [u8];
2062
2063    fn next(&mut self) -> Option<Self::Item> {
2064        if self.header_height > 0 {
2065            let result = &NEWLINES[..self.header_height];
2066            self.header_height = 0;
2067            return Some(result);
2068        }
2069
2070        if let Some(chunk) = self.content_bytes.next() {
2071            if !chunk.is_empty() {
2072                return Some(chunk);
2073            }
2074        }
2075
2076        if self.footer_height > 0 {
2077            let result = &NEWLINES[..self.footer_height];
2078            self.footer_height = 0;
2079            return Some(result);
2080        }
2081
2082        None
2083    }
2084}
2085
2086impl<'a> Iterator for ExcerptChunks<'a> {
2087    type Item = Chunk<'a>;
2088
2089    fn next(&mut self) -> Option<Self::Item> {
2090        if self.header_height > 0 {
2091            let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.header_height]) };
2092            self.header_height = 0;
2093            return Some(Chunk {
2094                text,
2095                ..Default::default()
2096            });
2097        }
2098
2099        if let Some(chunk) = self.content_chunks.next() {
2100            return Some(chunk);
2101        }
2102
2103        if self.footer_height > 0 {
2104            let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
2105            self.footer_height = 0;
2106            return Some(Chunk {
2107                text,
2108                ..Default::default()
2109            });
2110        }
2111
2112        None
2113    }
2114}
2115
2116impl ToOffset for Point {
2117    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
2118        snapshot.point_to_offset(*self)
2119    }
2120}
2121
2122impl ToOffset for PointUtf16 {
2123    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
2124        snapshot.point_utf16_to_offset(*self)
2125    }
2126}
2127
2128impl ToOffset for usize {
2129    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
2130        assert!(*self <= snapshot.len(), "offset is out of range");
2131        *self
2132    }
2133}
2134
2135impl ToPoint for usize {
2136    fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
2137        snapshot.offset_to_point(*self)
2138    }
2139}
2140
2141impl ToPoint for Point {
2142    fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
2143        *self
2144    }
2145}
2146
2147#[cfg(test)]
2148mod tests {
2149    use super::*;
2150    use gpui::{elements::Empty, Element, MutableAppContext};
2151    use language::{Buffer, Rope};
2152    use rand::prelude::*;
2153    use std::env;
2154    use text::{Point, RandomCharIter};
2155    use util::test::sample_text;
2156
2157    #[gpui::test]
2158    fn test_singleton_multibuffer(cx: &mut MutableAppContext) {
2159        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
2160        let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
2161
2162        let snapshot = multibuffer.read(cx).snapshot(cx);
2163        assert_eq!(snapshot.text(), buffer.read(cx).text());
2164
2165        assert_eq!(
2166            snapshot.buffer_rows(0).collect::<Vec<_>>(),
2167            (0..buffer.read(cx).row_count())
2168                .map(Some)
2169                .collect::<Vec<_>>()
2170        );
2171
2172        buffer.update(cx, |buffer, cx| buffer.edit([1..3], "XXX\n", cx));
2173        let snapshot = multibuffer.read(cx).snapshot(cx);
2174
2175        assert_eq!(snapshot.text(), buffer.read(cx).text());
2176        assert_eq!(
2177            snapshot.buffer_rows(0).collect::<Vec<_>>(),
2178            (0..buffer.read(cx).row_count())
2179                .map(Some)
2180                .collect::<Vec<_>>()
2181        );
2182    }
2183
2184    #[gpui::test]
2185    fn test_excerpt_buffer(cx: &mut MutableAppContext) {
2186        let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
2187        let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
2188        let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2189
2190        let subscription = multibuffer.update(cx, |multibuffer, cx| {
2191            let subscription = multibuffer.subscribe();
2192            multibuffer.push_excerpt(
2193                ExcerptProperties {
2194                    buffer: &buffer_1,
2195                    range: Point::new(1, 2)..Point::new(2, 5),
2196                    header_height: 2,
2197                    render_header: Some(Arc::new(|_| Empty::new().named("header 1"))),
2198                },
2199                cx,
2200            );
2201            assert_eq!(
2202                subscription.consume().into_inner(),
2203                [Edit {
2204                    old: 0..0,
2205                    new: 0..12
2206                }]
2207            );
2208
2209            multibuffer.push_excerpt(
2210                ExcerptProperties {
2211                    buffer: &buffer_1,
2212                    range: Point::new(3, 3)..Point::new(4, 4),
2213                    header_height: 1,
2214                    render_header: Some(Arc::new(|_| Empty::new().named("header 2"))),
2215                },
2216                cx,
2217            );
2218            multibuffer.push_excerpt(
2219                ExcerptProperties {
2220                    buffer: &buffer_2,
2221                    range: Point::new(3, 1)..Point::new(3, 3),
2222                    header_height: 3,
2223                    render_header: Some(Arc::new(|_| Empty::new().named("header 3"))),
2224                },
2225                cx,
2226            );
2227            assert_eq!(
2228                subscription.consume().into_inner(),
2229                [Edit {
2230                    old: 12..12,
2231                    new: 12..28
2232                }]
2233            );
2234
2235            subscription
2236        });
2237
2238        let snapshot = multibuffer.read(cx).snapshot(cx);
2239        assert_eq!(
2240            snapshot.text(),
2241            concat!(
2242                "\n",      // Preserve newlines
2243                "\n",      //
2244                "bbbb\n",  //
2245                "ccccc\n", //
2246                "\n",      //
2247                "ddd\n",   //
2248                "eeee\n",  //
2249                "\n",      //
2250                "\n",      //
2251                "\n",      //
2252                "jj"       //
2253            )
2254        );
2255        assert_eq!(
2256            snapshot.buffer_rows(0).collect::<Vec<_>>(),
2257            &[
2258                None,
2259                None,
2260                Some(1),
2261                Some(2),
2262                None,
2263                Some(3),
2264                Some(4),
2265                None,
2266                None,
2267                None,
2268                Some(3)
2269            ]
2270        );
2271        assert_eq!(
2272            snapshot.buffer_rows(2).collect::<Vec<_>>(),
2273            &[
2274                Some(1),
2275                Some(2),
2276                None,
2277                Some(3),
2278                Some(4),
2279                None,
2280                None,
2281                None,
2282                Some(3)
2283            ]
2284        );
2285        assert_eq!(snapshot.buffer_rows(10).collect::<Vec<_>>(), &[Some(3)]);
2286        assert_eq!(snapshot.buffer_rows(11).collect::<Vec<_>>(), &[]);
2287        assert_eq!(snapshot.buffer_rows(12).collect::<Vec<_>>(), &[]);
2288
2289        {
2290            let snapshot = multibuffer.read(cx).read(cx);
2291            assert_eq!(
2292                snapshot
2293                    .excerpt_headers_in_range(0..snapshot.max_point().row + 1)
2294                    .map(|(rows, render)| (rows, render(cx).name().unwrap().to_string()))
2295                    .collect::<Vec<_>>(),
2296                &[
2297                    (0..2, "header 1".into()),
2298                    (4..5, "header 2".into()),
2299                    (7..10, "header 3".into())
2300                ]
2301            );
2302
2303            assert_eq!(
2304                snapshot
2305                    .excerpt_headers_in_range(1..5)
2306                    .map(|(rows, render)| (rows, render(cx).name().unwrap().to_string()))
2307                    .collect::<Vec<_>>(),
2308                &[(0..2, "header 1".into()), (4..5, "header 2".into())]
2309            );
2310
2311            assert_eq!(
2312                snapshot
2313                    .excerpt_headers_in_range(2..8)
2314                    .map(|(rows, render)| (rows, render(cx).name().unwrap().to_string()))
2315                    .collect::<Vec<_>>(),
2316                &[(4..5, "header 2".into()), (7..10, "header 3".into())]
2317            );
2318        }
2319
2320        buffer_1.update(cx, |buffer, cx| {
2321            buffer.edit(
2322                [
2323                    Point::new(0, 0)..Point::new(0, 0),
2324                    Point::new(2, 1)..Point::new(2, 3),
2325                ],
2326                "\n",
2327                cx,
2328            );
2329        });
2330
2331        assert_eq!(
2332            multibuffer.read(cx).snapshot(cx).text(),
2333            concat!(
2334                "\n",     // Preserve newlines
2335                "\n",     //
2336                "bbbb\n", //
2337                "c\n",    //
2338                "cc\n",   //
2339                "\n",     //
2340                "ddd\n",  //
2341                "eeee\n", //
2342                "\n",     //
2343                "\n",     //
2344                "\n",     //
2345                "jj"      //
2346            )
2347        );
2348
2349        assert_eq!(
2350            subscription.consume().into_inner(),
2351            [Edit {
2352                old: 8..10,
2353                new: 8..9
2354            }]
2355        );
2356
2357        let multibuffer = multibuffer.read(cx).snapshot(cx);
2358        assert_eq!(
2359            multibuffer.clip_point(Point::new(0, 0), Bias::Left),
2360            Point::new(2, 0)
2361        );
2362        assert_eq!(
2363            multibuffer.clip_point(Point::new(0, 0), Bias::Right),
2364            Point::new(2, 0)
2365        );
2366        assert_eq!(
2367            multibuffer.clip_point(Point::new(1, 0), Bias::Left),
2368            Point::new(2, 0)
2369        );
2370        assert_eq!(
2371            multibuffer.clip_point(Point::new(1, 0), Bias::Right),
2372            Point::new(2, 0)
2373        );
2374        assert_eq!(
2375            multibuffer.clip_point(Point::new(8, 0), Bias::Left),
2376            Point::new(7, 4)
2377        );
2378        assert_eq!(
2379            multibuffer.clip_point(Point::new(8, 0), Bias::Right),
2380            Point::new(11, 0)
2381        );
2382        assert_eq!(
2383            multibuffer.clip_point(Point::new(9, 0), Bias::Left),
2384            Point::new(7, 4)
2385        );
2386        assert_eq!(
2387            multibuffer.clip_point(Point::new(9, 0), Bias::Right),
2388            Point::new(11, 0)
2389        );
2390    }
2391
2392    #[gpui::test]
2393    fn test_empty_excerpt_buffer(cx: &mut MutableAppContext) {
2394        let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2395
2396        let snapshot = multibuffer.read(cx).snapshot(cx);
2397        assert_eq!(snapshot.text(), "");
2398        assert_eq!(snapshot.buffer_rows(0).collect::<Vec<_>>(), &[Some(0)]);
2399        assert_eq!(snapshot.buffer_rows(1).collect::<Vec<_>>(), &[]);
2400    }
2401
2402    #[gpui::test]
2403    fn test_singleton_multibuffer_anchors(cx: &mut MutableAppContext) {
2404        let buffer = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
2405        let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
2406        let old_snapshot = multibuffer.read(cx).snapshot(cx);
2407        buffer.update(cx, |buffer, cx| {
2408            buffer.edit([0..0], "X", cx);
2409            buffer.edit([5..5], "Y", cx);
2410        });
2411        let new_snapshot = multibuffer.read(cx).snapshot(cx);
2412
2413        assert_eq!(old_snapshot.text(), "abcd");
2414        assert_eq!(new_snapshot.text(), "XabcdY");
2415
2416        assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0);
2417        assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1);
2418        assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5);
2419        assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6);
2420    }
2421
2422    #[gpui::test]
2423    fn test_multibuffer_anchors(cx: &mut MutableAppContext) {
2424        let buffer_1 = cx.add_model(|cx| Buffer::new(0, "abcd", cx));
2425        let buffer_2 = cx.add_model(|cx| Buffer::new(0, "efghi", cx));
2426        let multibuffer = cx.add_model(|cx| {
2427            let mut multibuffer = MultiBuffer::new(0);
2428            multibuffer.push_excerpt(
2429                ExcerptProperties {
2430                    buffer: &buffer_1,
2431                    range: 0..4,
2432                    header_height: 1,
2433                    render_header: None,
2434                },
2435                cx,
2436            );
2437            multibuffer.push_excerpt(
2438                ExcerptProperties {
2439                    buffer: &buffer_2,
2440                    range: 0..5,
2441                    header_height: 1,
2442                    render_header: None,
2443                },
2444                cx,
2445            );
2446            multibuffer
2447        });
2448        let old_snapshot = multibuffer.read(cx).snapshot(cx);
2449
2450        assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 1);
2451        assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 1);
2452        assert_eq!(Anchor::min().to_offset(&old_snapshot), 1);
2453        assert_eq!(Anchor::min().to_offset(&old_snapshot), 1);
2454        assert_eq!(Anchor::max().to_offset(&old_snapshot), 12);
2455        assert_eq!(Anchor::max().to_offset(&old_snapshot), 12);
2456
2457        buffer_1.update(cx, |buffer, cx| {
2458            buffer.edit([0..0], "W", cx);
2459            buffer.edit([5..5], "X", cx);
2460        });
2461        buffer_2.update(cx, |buffer, cx| {
2462            buffer.edit([0..0], "Y", cx);
2463            buffer.edit([6..0], "Z", cx);
2464        });
2465        let new_snapshot = multibuffer.read(cx).snapshot(cx);
2466
2467        assert_eq!(old_snapshot.text(), "\nabcd\n\nefghi");
2468        assert_eq!(new_snapshot.text(), "\nWabcdX\n\nYefghiZ");
2469
2470        assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 1);
2471        assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 2);
2472        assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 1);
2473        assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2);
2474        assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3);
2475        assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3);
2476        assert_eq!(old_snapshot.anchor_before(7).to_offset(&new_snapshot), 9);
2477        assert_eq!(old_snapshot.anchor_after(7).to_offset(&new_snapshot), 10);
2478        assert_eq!(old_snapshot.anchor_before(12).to_offset(&new_snapshot), 15);
2479        assert_eq!(old_snapshot.anchor_after(12).to_offset(&new_snapshot), 16);
2480    }
2481
2482    #[gpui::test(iterations = 100)]
2483    fn test_random_excerpts(cx: &mut MutableAppContext, mut rng: StdRng) {
2484        let operations = env::var("OPERATIONS")
2485            .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2486            .unwrap_or(10);
2487
2488        let mut buffers: Vec<ModelHandle<Buffer>> = Vec::new();
2489        let list = cx.add_model(|_| MultiBuffer::new(0));
2490        let mut excerpt_ids = Vec::new();
2491        let mut expected_excerpts = Vec::new();
2492        let mut old_versions = Vec::new();
2493
2494        for _ in 0..operations {
2495            match rng.gen_range(0..100) {
2496                0..=19 if !buffers.is_empty() => {
2497                    let buffer = buffers.choose(&mut rng).unwrap();
2498                    buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
2499                }
2500                _ => {
2501                    let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
2502                        let base_text = RandomCharIter::new(&mut rng).take(10).collect::<String>();
2503                        buffers.push(cx.add_model(|cx| Buffer::new(0, base_text, cx)));
2504                        buffers.last().unwrap()
2505                    } else {
2506                        buffers.choose(&mut rng).unwrap()
2507                    };
2508
2509                    let buffer = buffer_handle.read(cx);
2510                    let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
2511                    let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
2512                    let header_height = rng.gen_range(0..=5);
2513                    let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
2514                    log::info!(
2515                        "Pushing excerpt wih header {}, buffer {}: {:?}[{:?}] = {:?}",
2516                        header_height,
2517                        buffer_handle.id(),
2518                        buffer.text(),
2519                        start_ix..end_ix,
2520                        &buffer.text()[start_ix..end_ix]
2521                    );
2522
2523                    let excerpt_id = list.update(cx, |list, cx| {
2524                        list.push_excerpt(
2525                            ExcerptProperties {
2526                                buffer: &buffer_handle,
2527                                range: start_ix..end_ix,
2528                                header_height,
2529                                render_header: None,
2530                            },
2531                            cx,
2532                        )
2533                    });
2534                    excerpt_ids.push(excerpt_id);
2535                    expected_excerpts.push((buffer_handle.clone(), anchor_range, header_height));
2536                }
2537            }
2538
2539            if rng.gen_bool(0.3) {
2540                list.update(cx, |list, cx| {
2541                    old_versions.push((list.snapshot(cx), list.subscribe()));
2542                })
2543            }
2544
2545            let snapshot = list.read(cx).snapshot(cx);
2546
2547            let mut excerpt_starts = Vec::new();
2548            let mut expected_text = String::new();
2549            let mut expected_buffer_rows = Vec::new();
2550            for (buffer, range, header_height) in &expected_excerpts {
2551                let buffer = buffer.read(cx);
2552                let buffer_range = range.to_offset(buffer);
2553
2554                for _ in 0..*header_height {
2555                    expected_text.push('\n');
2556                    expected_buffer_rows.push(None);
2557                }
2558
2559                excerpt_starts.push(TextSummary::from(expected_text.as_str()));
2560                expected_text.extend(buffer.text_for_range(buffer_range.clone()));
2561                expected_text.push('\n');
2562
2563                let buffer_row_range = buffer.offset_to_point(buffer_range.start).row
2564                    ..=buffer.offset_to_point(buffer_range.end).row;
2565                for row in buffer_row_range {
2566                    expected_buffer_rows.push(Some(row));
2567                }
2568            }
2569            // Remove final trailing newline.
2570            if !expected_excerpts.is_empty() {
2571                expected_text.pop();
2572            }
2573
2574            assert_eq!(snapshot.text(), expected_text);
2575            log::info!("MultiBuffer text: {:?}", expected_text);
2576
2577            assert_eq!(
2578                snapshot.buffer_rows(0).collect::<Vec<_>>(),
2579                expected_buffer_rows,
2580            );
2581
2582            for _ in 0..5 {
2583                let start_row = rng.gen_range(0..=expected_buffer_rows.len());
2584                assert_eq!(
2585                    snapshot.buffer_rows(start_row as u32).collect::<Vec<_>>(),
2586                    &expected_buffer_rows[start_row..],
2587                    "buffer_rows({})",
2588                    start_row
2589                );
2590            }
2591
2592            let mut excerpt_starts = excerpt_starts.into_iter();
2593            for (buffer, range, _) in &expected_excerpts {
2594                let buffer_id = buffer.id();
2595                let buffer = buffer.read(cx);
2596                let buffer_range = range.to_offset(buffer);
2597                let buffer_start_point = buffer.offset_to_point(buffer_range.start);
2598                let buffer_start_point_utf16 =
2599                    buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
2600
2601                let excerpt_start = excerpt_starts.next().unwrap();
2602                let mut offset = excerpt_start.bytes;
2603                let mut buffer_offset = buffer_range.start;
2604                let mut point = excerpt_start.lines;
2605                let mut buffer_point = buffer_start_point;
2606                let mut point_utf16 = excerpt_start.lines_utf16;
2607                let mut buffer_point_utf16 = buffer_start_point_utf16;
2608                for ch in buffer
2609                    .snapshot()
2610                    .chunks(buffer_range.clone(), None)
2611                    .flat_map(|c| c.text.chars())
2612                {
2613                    for _ in 0..ch.len_utf8() {
2614                        let left_offset = snapshot.clip_offset(offset, Bias::Left);
2615                        let right_offset = snapshot.clip_offset(offset, Bias::Right);
2616                        let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
2617                        let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
2618                        assert_eq!(
2619                            left_offset,
2620                            excerpt_start.bytes + (buffer_left_offset - buffer_range.start),
2621                            "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
2622                            offset,
2623                            buffer_id,
2624                            buffer_offset,
2625                        );
2626                        assert_eq!(
2627                            right_offset,
2628                            excerpt_start.bytes + (buffer_right_offset - buffer_range.start),
2629                            "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
2630                            offset,
2631                            buffer_id,
2632                            buffer_offset,
2633                        );
2634
2635                        let left_point = snapshot.clip_point(point, Bias::Left);
2636                        let right_point = snapshot.clip_point(point, Bias::Right);
2637                        let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
2638                        let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
2639                        assert_eq!(
2640                            left_point,
2641                            excerpt_start.lines + (buffer_left_point - buffer_start_point),
2642                            "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
2643                            point,
2644                            buffer_id,
2645                            buffer_point,
2646                        );
2647                        assert_eq!(
2648                            right_point,
2649                            excerpt_start.lines + (buffer_right_point - buffer_start_point),
2650                            "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
2651                            point,
2652                            buffer_id,
2653                            buffer_point,
2654                        );
2655
2656                        assert_eq!(
2657                            snapshot.point_to_offset(left_point),
2658                            left_offset,
2659                            "point_to_offset({:?})",
2660                            left_point,
2661                        );
2662                        assert_eq!(
2663                            snapshot.offset_to_point(left_offset),
2664                            left_point,
2665                            "offset_to_point({:?})",
2666                            left_offset,
2667                        );
2668
2669                        offset += 1;
2670                        buffer_offset += 1;
2671                        if ch == '\n' {
2672                            point += Point::new(1, 0);
2673                            buffer_point += Point::new(1, 0);
2674                        } else {
2675                            point += Point::new(0, 1);
2676                            buffer_point += Point::new(0, 1);
2677                        }
2678                    }
2679
2680                    for _ in 0..ch.len_utf16() {
2681                        let left_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Left);
2682                        let right_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Right);
2683                        let buffer_left_point_utf16 =
2684                            buffer.clip_point_utf16(buffer_point_utf16, Bias::Left);
2685                        let buffer_right_point_utf16 =
2686                            buffer.clip_point_utf16(buffer_point_utf16, Bias::Right);
2687                        assert_eq!(
2688                            left_point_utf16,
2689                            excerpt_start.lines_utf16
2690                                + (buffer_left_point_utf16 - buffer_start_point_utf16),
2691                            "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
2692                            point_utf16,
2693                            buffer_id,
2694                            buffer_point_utf16,
2695                        );
2696                        assert_eq!(
2697                            right_point_utf16,
2698                            excerpt_start.lines_utf16
2699                                + (buffer_right_point_utf16 - buffer_start_point_utf16),
2700                            "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
2701                            point_utf16,
2702                            buffer_id,
2703                            buffer_point_utf16,
2704                        );
2705
2706                        if ch == '\n' {
2707                            point_utf16 += PointUtf16::new(1, 0);
2708                            buffer_point_utf16 += PointUtf16::new(1, 0);
2709                        } else {
2710                            point_utf16 += PointUtf16::new(0, 1);
2711                            buffer_point_utf16 += PointUtf16::new(0, 1);
2712                        }
2713                    }
2714                }
2715            }
2716
2717            for (row, line) in expected_text.split('\n').enumerate() {
2718                assert_eq!(
2719                    snapshot.line_len(row as u32),
2720                    line.len() as u32,
2721                    "line_len({}).",
2722                    row
2723                );
2724            }
2725
2726            let text_rope = Rope::from(expected_text.as_str());
2727            for _ in 0..10 {
2728                let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
2729                let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
2730
2731                assert_eq!(
2732                    snapshot
2733                        .text_for_range(start_ix..end_ix)
2734                        .collect::<String>(),
2735                    &expected_text[start_ix..end_ix],
2736                    "incorrect text for range {:?}",
2737                    start_ix..end_ix
2738                );
2739
2740                let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
2741                assert_eq!(
2742                    snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
2743                    expected_summary,
2744                    "incorrect summary for range {:?}",
2745                    start_ix..end_ix
2746                );
2747            }
2748
2749            for _ in 0..10 {
2750                let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
2751                assert_eq!(
2752                    snapshot.reversed_chars_at(end_ix).collect::<String>(),
2753                    expected_text[..end_ix].chars().rev().collect::<String>(),
2754                );
2755            }
2756
2757            for _ in 0..10 {
2758                let end_ix = rng.gen_range(0..=text_rope.len());
2759                let start_ix = rng.gen_range(0..=end_ix);
2760                assert_eq!(
2761                    snapshot
2762                        .bytes_in_range(start_ix..end_ix)
2763                        .flatten()
2764                        .copied()
2765                        .collect::<Vec<_>>(),
2766                    expected_text.as_bytes()[start_ix..end_ix].to_vec(),
2767                    "bytes_in_range({:?})",
2768                    start_ix..end_ix,
2769                );
2770            }
2771        }
2772
2773        let snapshot = list.read(cx).snapshot(cx);
2774        for (old_snapshot, subscription) in old_versions {
2775            let edits = subscription.consume().into_inner();
2776
2777            log::info!(
2778                "applying subscription edits to old text: {:?}: {:?}",
2779                old_snapshot.text(),
2780                edits,
2781            );
2782
2783            let mut text = old_snapshot.text();
2784            for edit in edits {
2785                let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
2786                text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
2787            }
2788            assert_eq!(text.to_string(), snapshot.text());
2789        }
2790    }
2791
2792    #[gpui::test]
2793    fn test_history(cx: &mut MutableAppContext) {
2794        let buffer_1 = cx.add_model(|cx| Buffer::new(0, "1234", cx));
2795        let buffer_2 = cx.add_model(|cx| Buffer::new(0, "5678", cx));
2796        let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2797        let group_interval = multibuffer.read(cx).history.group_interval;
2798        multibuffer.update(cx, |multibuffer, cx| {
2799            multibuffer.push_excerpt(
2800                ExcerptProperties {
2801                    buffer: &buffer_1,
2802                    range: 0..buffer_1.read(cx).len(),
2803                    header_height: 0,
2804                    render_header: None,
2805                },
2806                cx,
2807            );
2808            multibuffer.push_excerpt(
2809                ExcerptProperties {
2810                    buffer: &buffer_2,
2811                    range: 0..buffer_2.read(cx).len(),
2812                    header_height: 0,
2813                    render_header: None,
2814                },
2815                cx,
2816            );
2817        });
2818
2819        let mut now = Instant::now();
2820
2821        multibuffer.update(cx, |multibuffer, cx| {
2822            multibuffer.start_transaction_at(now, cx);
2823            multibuffer.edit(
2824                [
2825                    Point::new(0, 0)..Point::new(0, 0),
2826                    Point::new(1, 0)..Point::new(1, 0),
2827                ],
2828                "A",
2829                cx,
2830            );
2831            multibuffer.edit(
2832                [
2833                    Point::new(0, 1)..Point::new(0, 1),
2834                    Point::new(1, 1)..Point::new(1, 1),
2835                ],
2836                "B",
2837                cx,
2838            );
2839            multibuffer.end_transaction_at(now, cx);
2840            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2841
2842            now += 2 * group_interval;
2843            multibuffer.start_transaction_at(now, cx);
2844            multibuffer.edit([2..2], "C", cx);
2845            multibuffer.end_transaction_at(now, cx);
2846            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2847
2848            multibuffer.undo(cx);
2849            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2850
2851            multibuffer.undo(cx);
2852            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
2853
2854            multibuffer.redo(cx);
2855            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2856
2857            multibuffer.redo(cx);
2858            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2859
2860            buffer_1.update(cx, |buffer_1, cx| buffer_1.undo(cx));
2861            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2862
2863            multibuffer.undo(cx);
2864            assert_eq!(multibuffer.read(cx).text(), "1234\n5678");
2865
2866            multibuffer.redo(cx);
2867            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2868
2869            multibuffer.redo(cx);
2870            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2871
2872            multibuffer.undo(cx);
2873            assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678");
2874
2875            buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx));
2876            assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678");
2877
2878            multibuffer.undo(cx);
2879            assert_eq!(multibuffer.read(cx).text(), "C1234\n5678");
2880        });
2881    }
2882}