multi_buffer.rs

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