multi_buffer.rs

   1mod anchor;
   2
   3pub use anchor::{Anchor, AnchorRangeExt};
   4use anyhow::Result;
   5use clock::ReplicaId;
   6use collections::HashMap;
   7use gpui::{AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, 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, io,
  15    iter::{FromIterator, Peekable},
  16    ops::{Range, Sub},
  17    sync::Arc,
  18    time::{Duration, Instant, SystemTime},
  19};
  20use sum_tree::{Bias, Cursor, SumTree};
  21use text::{
  22    locator::Locator,
  23    rope::TextDimension,
  24    subscription::{Subscription, Topic},
  25    AnchorRangeExt as _, Edit, Point, PointUtf16, TextSummary,
  26};
  27use theme::SyntaxTheme;
  28
  29const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize];
  30
  31pub type ExcerptId = Locator;
  32
  33pub struct MultiBuffer {
  34    snapshot: RefCell<MultiBufferSnapshot>,
  35    buffers: HashMap<usize, BufferState>,
  36    subscriptions: Topic,
  37    singleton: bool,
  38    replica_id: ReplicaId,
  39}
  40
  41pub trait ToOffset: 'static {
  42    fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize;
  43}
  44
  45pub trait ToPoint: 'static {
  46    fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point;
  47}
  48
  49pub trait FromAnchor: 'static {
  50    fn from_anchor(anchor: &Anchor, snapshot: &MultiBufferSnapshot) -> Self;
  51}
  52
  53#[derive(Debug)]
  54struct BufferState {
  55    buffer: ModelHandle<Buffer>,
  56    last_version: clock::Global,
  57    last_parse_count: usize,
  58    last_diagnostics_update_count: usize,
  59    excerpts: Vec<ExcerptId>,
  60}
  61
  62#[derive(Clone, Default)]
  63pub struct MultiBufferSnapshot {
  64    excerpts: SumTree<Excerpt>,
  65}
  66
  67pub struct ExcerptProperties<'a, T> {
  68    buffer: &'a ModelHandle<Buffer>,
  69    range: Range<T>,
  70    header_height: u8,
  71}
  72
  73#[derive(Clone)]
  74struct Excerpt {
  75    id: ExcerptId,
  76    buffer_id: usize,
  77    buffer: BufferSnapshot,
  78    range: Range<text::Anchor>,
  79    text_summary: TextSummary,
  80    header_height: u8,
  81    has_trailing_newline: bool,
  82}
  83
  84#[derive(Clone, Debug, Default)]
  85struct ExcerptSummary {
  86    excerpt_id: ExcerptId,
  87    text: TextSummary,
  88}
  89
  90pub struct MultiBufferChunks<'a> {
  91    range: Range<usize>,
  92    cursor: Cursor<'a, Excerpt, usize>,
  93    header_height: u8,
  94    has_trailing_newline: bool,
  95    excerpt_chunks: Option<BufferChunks<'a>>,
  96    theme: Option<&'a SyntaxTheme>,
  97}
  98
  99pub struct MultiBufferBytes<'a> {
 100    chunks: Peekable<MultiBufferChunks<'a>>,
 101}
 102
 103impl MultiBuffer {
 104    pub fn new(replica_id: ReplicaId) -> Self {
 105        Self {
 106            snapshot: Default::default(),
 107            buffers: Default::default(),
 108            subscriptions: Default::default(),
 109            singleton: false,
 110            replica_id,
 111        }
 112    }
 113
 114    pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
 115        let mut this = Self::new(buffer.read(cx).replica_id());
 116        this.singleton = true;
 117        this.push_excerpt(
 118            ExcerptProperties {
 119                buffer: &buffer,
 120                range: text::Anchor::min()..text::Anchor::max(),
 121                header_height: 0,
 122            },
 123            cx,
 124        );
 125        this
 126    }
 127
 128    pub fn build_simple(text: &str, cx: &mut MutableAppContext) -> ModelHandle<Self> {
 129        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
 130        cx.add_model(|cx| Self::singleton(buffer, cx))
 131    }
 132
 133    pub fn replica_id(&self) -> ReplicaId {
 134        self.replica_id
 135    }
 136
 137    pub fn transaction_group_interval(&self, cx: &AppContext) -> Duration {
 138        self.as_singleton()
 139            .unwrap()
 140            .read(cx)
 141            .transaction_group_interval()
 142    }
 143
 144    pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot {
 145        self.sync(cx);
 146        self.snapshot.borrow().clone()
 147    }
 148
 149    pub fn read(&self, cx: &AppContext) -> Ref<MultiBufferSnapshot> {
 150        self.sync(cx);
 151        self.snapshot.borrow()
 152    }
 153
 154    pub fn as_singleton(&self) -> Option<&ModelHandle<Buffer>> {
 155        if self.buffers.len() == 1 {
 156            return Some(&self.buffers.values().next().unwrap().buffer);
 157        } else {
 158            None
 159        }
 160    }
 161
 162    pub fn subscribe(&mut self) -> Subscription {
 163        self.subscriptions.subscribe()
 164    }
 165
 166    pub fn edit<I, S, T>(&mut self, ranges_iter: I, new_text: T, cx: &mut ModelContext<Self>)
 167    where
 168        I: IntoIterator<Item = Range<S>>,
 169        S: ToOffset,
 170        T: Into<String>,
 171    {
 172        self.edit_internal(ranges_iter, new_text, false, cx)
 173    }
 174
 175    pub fn edit_with_autoindent<I, S, T>(
 176        &mut self,
 177        ranges_iter: I,
 178        new_text: T,
 179        cx: &mut ModelContext<Self>,
 180    ) where
 181        I: IntoIterator<Item = Range<S>>,
 182        S: ToOffset,
 183        T: Into<String>,
 184    {
 185        self.edit_internal(ranges_iter, new_text, true, cx)
 186    }
 187
 188    pub fn edit_internal<I, S, T>(
 189        &mut self,
 190        ranges_iter: I,
 191        new_text: T,
 192        autoindent: bool,
 193        cx: &mut ModelContext<Self>,
 194    ) where
 195        I: IntoIterator<Item = Range<S>>,
 196        S: ToOffset,
 197        T: Into<String>,
 198    {
 199        let snapshot = self.read(cx);
 200        let mut buffer_edits: HashMap<usize, Vec<(Range<usize>, bool)>> = Default::default();
 201        let mut cursor = snapshot.excerpts.cursor::<usize>();
 202        for range in ranges_iter {
 203            let start = range.start.to_offset(&snapshot);
 204            let end = range.end.to_offset(&snapshot);
 205            cursor.seek(&start, Bias::Right, &());
 206            let start_excerpt = cursor.item().expect("start offset out of bounds");
 207            let start_overshoot =
 208                (start - cursor.start()).saturating_sub(start_excerpt.header_height as usize);
 209            let buffer_start =
 210                start_excerpt.range.start.to_offset(&start_excerpt.buffer) + start_overshoot;
 211
 212            cursor.seek(&end, Bias::Right, &());
 213            let end_excerpt = cursor.item().expect("end offset out of bounds");
 214            let end_overshoot =
 215                (end - cursor.start()).saturating_sub(end_excerpt.header_height as usize);
 216            let buffer_end = end_excerpt.range.start.to_offset(&end_excerpt.buffer) + end_overshoot;
 217
 218            if start_excerpt.id == end_excerpt.id {
 219                buffer_edits
 220                    .entry(start_excerpt.buffer_id)
 221                    .or_insert(Vec::new())
 222                    .push((buffer_start..buffer_end, true));
 223            } else {
 224                let start_excerpt_range =
 225                    buffer_start..start_excerpt.range.end.to_offset(&start_excerpt.buffer);
 226                let end_excerpt_range =
 227                    end_excerpt.range.start.to_offset(&end_excerpt.buffer)..buffer_end;
 228                buffer_edits
 229                    .entry(start_excerpt.buffer_id)
 230                    .or_insert(Vec::new())
 231                    .push((start_excerpt_range, true));
 232                buffer_edits
 233                    .entry(end_excerpt.buffer_id)
 234                    .or_insert(Vec::new())
 235                    .push((end_excerpt_range, false));
 236
 237                cursor.seek(&start, Bias::Right, &());
 238                cursor.next(&());
 239                while let Some(excerpt) = cursor.item() {
 240                    if excerpt.id == end_excerpt.id {
 241                        break;
 242                    }
 243
 244                    let excerpt_range = start_excerpt.range.end.to_offset(&start_excerpt.buffer)
 245                        ..start_excerpt.range.end.to_offset(&start_excerpt.buffer);
 246                    buffer_edits
 247                        .entry(excerpt.buffer_id)
 248                        .or_insert(Vec::new())
 249                        .push((excerpt_range, false));
 250                    cursor.next(&());
 251                }
 252            }
 253        }
 254
 255        let new_text = new_text.into();
 256        for (buffer_id, mut edits) in buffer_edits {
 257            edits.sort_unstable_by_key(|(range, _)| range.start);
 258            self.buffers[&buffer_id].buffer.update(cx, |buffer, cx| {
 259                let mut edits = edits.into_iter().peekable();
 260                let mut insertions = Vec::new();
 261                let mut deletions = Vec::new();
 262                while let Some((mut range, mut is_insertion)) = edits.next() {
 263                    while let Some((next_range, next_is_insertion)) = edits.peek() {
 264                        if range.end >= next_range.start {
 265                            range.end = cmp::max(next_range.end, range.end);
 266                            is_insertion |= *next_is_insertion;
 267                            edits.next();
 268                        } else {
 269                            break;
 270                        }
 271                    }
 272
 273                    if is_insertion {
 274                        insertions.push(
 275                            buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
 276                        );
 277                    } else {
 278                        deletions.push(
 279                            buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
 280                        );
 281                    }
 282                }
 283
 284                if autoindent {
 285                    buffer.edit_with_autoindent(deletions, "", cx);
 286                    buffer.edit_with_autoindent(insertions, new_text.clone(), cx);
 287                } else {
 288                    buffer.edit(deletions, "", cx);
 289                    buffer.edit(insertions, new_text.clone(), cx);
 290                }
 291            })
 292        }
 293    }
 294
 295    pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 296        self.start_transaction_at(Instant::now(), cx)
 297    }
 298
 299    pub(crate) fn start_transaction_at(
 300        &mut self,
 301        now: Instant,
 302        cx: &mut ModelContext<Self>,
 303    ) -> Option<TransactionId> {
 304        // TODO
 305        self.as_singleton()
 306            .unwrap()
 307            .update(cx, |buffer, _| buffer.start_transaction_at(now))
 308    }
 309
 310    pub fn end_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 311        // TODO
 312        self.as_singleton()
 313            .unwrap()
 314            .update(cx, |buffer, cx| buffer.end_transaction(cx))
 315    }
 316
 317    pub(crate) fn end_transaction_at(
 318        &mut self,
 319        now: Instant,
 320        cx: &mut ModelContext<Self>,
 321    ) -> Option<TransactionId> {
 322        // TODO
 323        self.as_singleton()
 324            .unwrap()
 325            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
 326    }
 327
 328    pub fn set_active_selections(
 329        &mut self,
 330        selections: &[Selection<Anchor>],
 331        cx: &mut ModelContext<Self>,
 332    ) {
 333        // TODO
 334        let this = self.read(cx);
 335        self.as_singleton().unwrap().update(cx, |buffer, cx| {
 336            let buffer_snapshot = buffer.snapshot();
 337            let selections = selections.iter().map(|selection| Selection {
 338                id: selection.id,
 339                start: buffer_snapshot.anchor_before(selection.start.to_offset(&this)),
 340                end: buffer_snapshot.anchor_before(selection.end.to_offset(&this)),
 341                reversed: selection.reversed,
 342                goal: selection.goal,
 343            });
 344            buffer.set_active_selections(Arc::from_iter(selections), cx);
 345        });
 346    }
 347
 348    pub fn remove_active_selections(&mut self, cx: &mut ModelContext<Self>) {
 349        for buffer in self.buffers.values() {
 350            buffer
 351                .buffer
 352                .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
 353        }
 354    }
 355
 356    pub fn undo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 357        // TODO
 358        self.as_singleton()
 359            .unwrap()
 360            .update(cx, |buffer, cx| buffer.undo(cx))
 361    }
 362
 363    pub fn redo(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
 364        // TODO
 365        self.as_singleton()
 366            .unwrap()
 367            .update(cx, |buffer, cx| buffer.redo(cx))
 368    }
 369
 370    pub fn push_excerpt<O>(
 371        &mut self,
 372        props: ExcerptProperties<O>,
 373        cx: &mut ModelContext<Self>,
 374    ) -> ExcerptId
 375    where
 376        O: text::ToOffset,
 377    {
 378        self.sync(cx);
 379
 380        let buffer = &props.buffer;
 381        cx.subscribe(buffer, Self::on_buffer_event).detach();
 382
 383        let buffer = props.buffer.read(cx);
 384        let range = buffer.anchor_before(&props.range.start)..buffer.anchor_after(&props.range.end);
 385        let mut snapshot = self.snapshot.borrow_mut();
 386        let prev_id = snapshot.excerpts.last().map(|e| &e.id);
 387        let id = ExcerptId::between(prev_id.unwrap_or(&ExcerptId::min()), &ExcerptId::max());
 388
 389        let edit_start = snapshot.excerpts.summary().text.bytes;
 390        let excerpt = Excerpt::new(
 391            id.clone(),
 392            props.buffer.id(),
 393            buffer.snapshot(),
 394            range,
 395            props.header_height,
 396            !self.singleton,
 397        );
 398        let edit = Edit {
 399            old: edit_start..edit_start,
 400            new: edit_start..edit_start + excerpt.text_summary.bytes,
 401        };
 402        snapshot.excerpts.push(excerpt, &());
 403        self.buffers
 404            .entry(props.buffer.id())
 405            .or_insert_with(|| BufferState {
 406                buffer: props.buffer.clone(),
 407                last_version: buffer.version(),
 408                last_parse_count: buffer.parse_count(),
 409                last_diagnostics_update_count: buffer.diagnostics_update_count(),
 410                excerpts: Default::default(),
 411            })
 412            .excerpts
 413            .push(id.clone());
 414
 415        self.subscriptions.publish_mut([edit]);
 416
 417        id
 418    }
 419
 420    fn on_buffer_event(
 421        &mut self,
 422        _: ModelHandle<Buffer>,
 423        event: &Event,
 424        cx: &mut ModelContext<Self>,
 425    ) {
 426        cx.emit(event.clone());
 427    }
 428
 429    pub fn save(
 430        &mut self,
 431        cx: &mut ModelContext<Self>,
 432    ) -> Result<Task<Result<(clock::Global, SystemTime)>>> {
 433        self.as_singleton()
 434            .unwrap()
 435            .update(cx, |buffer, cx| buffer.save(cx))
 436    }
 437
 438    pub fn language<'a>(&self, cx: &'a AppContext) -> Option<&'a Arc<Language>> {
 439        self.as_singleton().unwrap().read(cx).language()
 440    }
 441
 442    pub fn file<'a>(&self, cx: &'a AppContext) -> Option<&'a dyn File> {
 443        self.as_singleton()
 444            .and_then(|buffer| buffer.read(cx).file())
 445    }
 446
 447    pub fn is_dirty(&self, cx: &AppContext) -> bool {
 448        self.as_singleton().unwrap().read(cx).is_dirty()
 449    }
 450
 451    pub fn has_conflict(&self, cx: &AppContext) -> bool {
 452        self.as_singleton().unwrap().read(cx).has_conflict()
 453    }
 454
 455    pub fn is_parsing(&self, cx: &AppContext) -> bool {
 456        self.as_singleton().unwrap().read(cx).is_parsing()
 457    }
 458
 459    fn sync(&self, cx: &AppContext) {
 460        let mut snapshot = self.snapshot.borrow_mut();
 461        let mut excerpts_to_edit = Vec::new();
 462        for buffer_state in self.buffers.values() {
 463            let buffer = buffer_state.buffer.read(cx);
 464            let buffer_changed = buffer.version().gt(&buffer_state.last_version);
 465            if buffer_changed
 466                || buffer.parse_count() > buffer_state.last_parse_count
 467                || buffer.diagnostics_update_count() > buffer_state.last_diagnostics_update_count
 468            {
 469                excerpts_to_edit.extend(
 470                    buffer_state
 471                        .excerpts
 472                        .iter()
 473                        .map(|excerpt_id| (excerpt_id, buffer_state, buffer_changed)),
 474                );
 475            }
 476        }
 477        excerpts_to_edit.sort_unstable_by_key(|(excerpt_id, _, _)| *excerpt_id);
 478
 479        let mut edits = Vec::new();
 480        let mut new_excerpts = SumTree::new();
 481        let mut cursor = snapshot.excerpts.cursor::<(Option<&ExcerptId>, usize)>();
 482
 483        for (id, buffer_state, buffer_changed) in excerpts_to_edit {
 484            new_excerpts.push_tree(cursor.slice(&Some(id), Bias::Left, &()), &());
 485            let old_excerpt = cursor.item().unwrap();
 486            let buffer = buffer_state.buffer.read(cx);
 487
 488            let mut new_excerpt;
 489            if buffer_changed {
 490                edits.extend(
 491                    buffer
 492                        .edits_since_in_range::<usize>(
 493                            old_excerpt.buffer.version(),
 494                            old_excerpt.range.clone(),
 495                        )
 496                        .map(|mut edit| {
 497                            let excerpt_old_start =
 498                                cursor.start().1 + old_excerpt.header_height as usize;
 499                            let excerpt_new_start = new_excerpts.summary().text.bytes
 500                                + old_excerpt.header_height as usize;
 501                            edit.old.start += excerpt_old_start;
 502                            edit.old.end += excerpt_old_start;
 503                            edit.new.start += excerpt_new_start;
 504                            edit.new.end += excerpt_new_start;
 505                            edit
 506                        }),
 507                );
 508
 509                new_excerpt = Excerpt::new(
 510                    id.clone(),
 511                    buffer_state.buffer.id(),
 512                    buffer.snapshot(),
 513                    old_excerpt.range.clone(),
 514                    old_excerpt.header_height,
 515                    !self.singleton,
 516                );
 517            } else {
 518                new_excerpt = old_excerpt.clone();
 519                new_excerpt.buffer = buffer.snapshot();
 520            }
 521
 522            new_excerpts.push(new_excerpt, &());
 523            cursor.next(&());
 524        }
 525        new_excerpts.push_tree(cursor.suffix(&()), &());
 526
 527        drop(cursor);
 528        snapshot.excerpts = new_excerpts;
 529
 530        self.subscriptions.publish(edits);
 531    }
 532}
 533
 534#[cfg(any(test, feature = "test-support"))]
 535impl MultiBuffer {
 536    pub fn randomly_edit<R: rand::Rng>(
 537        &mut self,
 538        rng: &mut R,
 539        count: usize,
 540        cx: &mut ModelContext<Self>,
 541    ) {
 542        self.as_singleton()
 543            .unwrap()
 544            .update(cx, |buffer, cx| buffer.randomly_edit(rng, count, cx));
 545        self.sync(cx);
 546    }
 547}
 548
 549impl Entity for MultiBuffer {
 550    type Event = language::Event;
 551}
 552
 553impl MultiBufferSnapshot {
 554    pub fn text(&self) -> String {
 555        self.chunks(0..self.len(), None)
 556            .map(|chunk| chunk.text)
 557            .collect()
 558    }
 559
 560    pub fn reversed_chars_at<'a, T: ToOffset>(
 561        &'a self,
 562        position: T,
 563    ) -> impl Iterator<Item = char> + 'a {
 564        // TODO
 565        let offset = position.to_offset(self);
 566        self.as_singleton().unwrap().reversed_chars_at(offset)
 567    }
 568
 569    pub fn chars_at<'a, T: ToOffset>(&'a self, position: T) -> impl Iterator<Item = char> + 'a {
 570        let offset = position.to_offset(self);
 571        self.text_for_range(offset..self.len())
 572            .flat_map(|chunk| chunk.chars())
 573    }
 574
 575    pub fn text_for_range<'a, T: ToOffset>(
 576        &'a self,
 577        range: Range<T>,
 578    ) -> impl Iterator<Item = &'a str> {
 579        self.chunks(range, None).map(|chunk| chunk.text)
 580    }
 581
 582    pub fn is_line_blank(&self, row: u32) -> bool {
 583        self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row)))
 584            .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
 585    }
 586
 587    pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
 588    where
 589        T: ToOffset,
 590    {
 591        let offset = position.to_offset(self);
 592        self.as_singleton().unwrap().contains_str_at(offset, needle)
 593    }
 594
 595    fn as_singleton(&self) -> Option<&BufferSnapshot> {
 596        let mut excerpts = self.excerpts.iter();
 597        let buffer = excerpts.next().map(|excerpt| &excerpt.buffer);
 598        if excerpts.next().is_none() {
 599            buffer
 600        } else {
 601            None
 602        }
 603    }
 604
 605    pub fn len(&self) -> usize {
 606        self.excerpts.summary().text.bytes
 607    }
 608
 609    pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
 610        let mut cursor = self.excerpts.cursor::<usize>();
 611        cursor.seek(&offset, Bias::Right, &());
 612        if let Some(excerpt) = cursor.item() {
 613            let start_after_header = *cursor.start() + excerpt.header_height as usize;
 614            if offset < start_after_header {
 615                *cursor.start()
 616            } else {
 617                let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
 618                let buffer_offset = excerpt
 619                    .buffer
 620                    .clip_offset(excerpt_start + (offset - start_after_header), bias);
 621                let offset_in_excerpt = if buffer_offset > excerpt_start {
 622                    buffer_offset - excerpt_start
 623                } else {
 624                    0
 625                };
 626                start_after_header + offset_in_excerpt
 627            }
 628        } else {
 629            self.excerpts.summary().text.bytes
 630        }
 631    }
 632
 633    pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
 634        let mut cursor = self.excerpts.cursor::<Point>();
 635        cursor.seek(&point, Bias::Right, &());
 636        if let Some(excerpt) = cursor.item() {
 637            let start_after_header = *cursor.start() + Point::new(excerpt.header_height as u32, 0);
 638            if point < start_after_header {
 639                *cursor.start()
 640            } else {
 641                let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
 642                let buffer_point = excerpt
 643                    .buffer
 644                    .clip_point(excerpt_start + (point - start_after_header), bias);
 645                let point_in_excerpt = if buffer_point > excerpt_start {
 646                    buffer_point - excerpt_start
 647                } else {
 648                    Point::zero()
 649                };
 650                start_after_header + point_in_excerpt
 651            }
 652        } else {
 653            self.excerpts.summary().text.lines
 654        }
 655    }
 656
 657    pub fn clip_point_utf16(&self, point: PointUtf16, bias: Bias) -> PointUtf16 {
 658        let mut cursor = self.excerpts.cursor::<PointUtf16>();
 659        cursor.seek(&point, Bias::Right, &());
 660        if let Some(excerpt) = cursor.item() {
 661            let start_after_header =
 662                *cursor.start() + PointUtf16::new(excerpt.header_height as u32, 0);
 663            if point < start_after_header {
 664                *cursor.start()
 665            } else {
 666                let excerpt_start = excerpt
 667                    .buffer
 668                    .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
 669                let buffer_point = excerpt
 670                    .buffer
 671                    .clip_point_utf16(excerpt_start + (point - start_after_header), bias);
 672                let point_in_excerpt = if buffer_point > excerpt_start {
 673                    buffer_point - excerpt_start
 674                } else {
 675                    PointUtf16::new(0, 0)
 676                };
 677                start_after_header + point_in_excerpt
 678            }
 679        } else {
 680            self.excerpts.summary().text.lines_utf16
 681        }
 682    }
 683
 684    pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> MultiBufferBytes<'a> {
 685        MultiBufferBytes {
 686            chunks: self.chunks(range, None).peekable(),
 687        }
 688    }
 689
 690    pub fn chunks<'a, T: ToOffset>(
 691        &'a self,
 692        range: Range<T>,
 693        theme: Option<&'a SyntaxTheme>,
 694    ) -> MultiBufferChunks<'a> {
 695        let mut result = MultiBufferChunks {
 696            range: 0..range.end.to_offset(self),
 697            cursor: self.excerpts.cursor::<usize>(),
 698            header_height: 0,
 699            excerpt_chunks: None,
 700            has_trailing_newline: false,
 701            theme,
 702        };
 703        result.seek(range.start.to_offset(self));
 704        result
 705    }
 706
 707    pub fn offset_to_point(&self, offset: usize) -> Point {
 708        let mut cursor = self.excerpts.cursor::<(usize, Point)>();
 709        cursor.seek(&offset, Bias::Right, &());
 710        if let Some(excerpt) = cursor.item() {
 711            let (start_offset, start_point) = cursor.start();
 712            let overshoot = offset - start_offset;
 713            let header_height = excerpt.header_height as usize;
 714            if overshoot < header_height {
 715                *start_point
 716            } else {
 717                let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
 718                let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
 719                let buffer_point = excerpt
 720                    .buffer
 721                    .offset_to_point(excerpt_start_offset + (overshoot - header_height));
 722                *start_point
 723                    + Point::new(header_height as u32, 0)
 724                    + (buffer_point - excerpt_start_point)
 725            }
 726        } else {
 727            self.excerpts.summary().text.lines
 728        }
 729    }
 730
 731    pub fn point_to_offset(&self, point: Point) -> usize {
 732        let mut cursor = self.excerpts.cursor::<(Point, usize)>();
 733        cursor.seek(&point, Bias::Right, &());
 734        if let Some(excerpt) = cursor.item() {
 735            let (start_point, start_offset) = cursor.start();
 736            let overshoot = point - start_point;
 737            let header_height = Point::new(excerpt.header_height as u32, 0);
 738            if overshoot < header_height {
 739                *start_offset
 740            } else {
 741                let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
 742                let excerpt_start_point = excerpt.range.start.to_point(&excerpt.buffer);
 743                let buffer_offset = excerpt
 744                    .buffer
 745                    .point_to_offset(excerpt_start_point + (overshoot - header_height));
 746                *start_offset + excerpt.header_height as usize + buffer_offset
 747                    - excerpt_start_offset
 748            }
 749        } else {
 750            self.excerpts.summary().text.bytes
 751        }
 752    }
 753
 754    pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize {
 755        let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>();
 756        cursor.seek(&point, Bias::Right, &());
 757        if let Some(excerpt) = cursor.item() {
 758            let (start_point, start_offset) = cursor.start();
 759            let overshoot = point - start_point;
 760            let header_height = PointUtf16::new(excerpt.header_height as u32, 0);
 761            if overshoot < header_height {
 762                *start_offset
 763            } else {
 764                let excerpt_start_offset = excerpt.range.start.to_offset(&excerpt.buffer);
 765                let excerpt_start_point = excerpt
 766                    .buffer
 767                    .offset_to_point_utf16(excerpt.range.start.to_offset(&excerpt.buffer));
 768                let buffer_offset = excerpt
 769                    .buffer
 770                    .point_utf16_to_offset(excerpt_start_point + (overshoot - header_height));
 771                *start_offset
 772                    + excerpt.header_height as usize
 773                    + (buffer_offset - excerpt_start_offset)
 774            }
 775        } else {
 776            self.excerpts.summary().text.bytes
 777        }
 778    }
 779
 780    pub fn indent_column_for_line(&self, row: u32) -> u32 {
 781        if let Some((buffer, range)) = self.buffer_line_for_row(row) {
 782            buffer
 783                .indent_column_for_line(range.start.row)
 784                .min(range.end.column)
 785                .saturating_sub(range.start.column)
 786        } else {
 787            0
 788        }
 789    }
 790
 791    pub fn line_len(&self, row: u32) -> u32 {
 792        if let Some((_, range)) = self.buffer_line_for_row(row) {
 793            range.end.column - range.start.column
 794        } else {
 795            0
 796        }
 797    }
 798
 799    fn buffer_line_for_row(&self, row: u32) -> Option<(&BufferSnapshot, Range<Point>)> {
 800        let mut cursor = self.excerpts.cursor::<Point>();
 801        cursor.seek(&Point::new(row, 0), Bias::Right, &());
 802        if let Some(excerpt) = cursor.item() {
 803            let overshoot = row - cursor.start().row;
 804            let header_height = excerpt.header_height as u32;
 805            if overshoot >= header_height {
 806                let excerpt_start = excerpt.range.start.to_point(&excerpt.buffer);
 807                let excerpt_end = excerpt.range.end.to_point(&excerpt.buffer);
 808                let buffer_row = excerpt_start.row + overshoot - header_height;
 809                let line_start = Point::new(buffer_row, 0);
 810                let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row));
 811                return Some((
 812                    &excerpt.buffer,
 813                    line_start.max(excerpt_start)..line_end.min(excerpt_end),
 814                ));
 815            }
 816        }
 817        None
 818    }
 819
 820    pub fn max_point(&self) -> Point {
 821        self.text_summary().lines
 822    }
 823
 824    pub fn text_summary(&self) -> TextSummary {
 825        self.excerpts.summary().text
 826    }
 827
 828    pub fn text_summary_for_range<'a, D, O>(&'a self, range: Range<O>) -> D
 829    where
 830        D: TextDimension,
 831        O: ToOffset,
 832    {
 833        let mut summary = D::default();
 834        let mut range = range.start.to_offset(self)..range.end.to_offset(self);
 835        let mut cursor = self.excerpts.cursor::<usize>();
 836        cursor.seek(&range.start, Bias::Right, &());
 837        if let Some(excerpt) = cursor.item() {
 838            let start_after_header = cursor.start() + excerpt.header_height as usize;
 839            if range.start < start_after_header {
 840                let header_len = cmp::min(range.end, start_after_header) - range.start;
 841                summary.add_assign(&D::from_text_summary(&TextSummary {
 842                    bytes: header_len,
 843                    lines: Point::new(header_len as u32, 0),
 844                    lines_utf16: PointUtf16::new(header_len as u32, 0),
 845                    first_line_chars: 0,
 846                    last_line_chars: 0,
 847                    longest_row: 0,
 848                    longest_row_chars: 0,
 849                }));
 850                range.start = start_after_header;
 851                range.end = cmp::max(range.start, range.end);
 852            }
 853
 854            let mut end_before_newline = cursor.end(&());
 855            if excerpt.has_trailing_newline {
 856                end_before_newline -= 1;
 857            }
 858
 859            let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
 860            let start_in_excerpt = excerpt_start + (range.start - start_after_header);
 861            let end_in_excerpt =
 862                excerpt_start + (cmp::min(end_before_newline, range.end) - start_after_header);
 863            summary.add_assign(
 864                &excerpt
 865                    .buffer
 866                    .text_summary_for_range(start_in_excerpt..end_in_excerpt),
 867            );
 868
 869            if range.end > end_before_newline {
 870                summary.add_assign(&D::from_text_summary(&TextSummary {
 871                    bytes: 1,
 872                    lines: Point::new(1 as u32, 0),
 873                    lines_utf16: PointUtf16::new(1 as u32, 0),
 874                    first_line_chars: 0,
 875                    last_line_chars: 0,
 876                    longest_row: 0,
 877                    longest_row_chars: 0,
 878                }));
 879            }
 880
 881            cursor.next(&());
 882        }
 883
 884        if range.end > *cursor.start() {
 885            summary.add_assign(&D::from_text_summary(&cursor.summary::<_, TextSummary>(
 886                &range.end,
 887                Bias::Right,
 888                &(),
 889            )));
 890            if let Some(excerpt) = cursor.item() {
 891                let start_after_header = cursor.start() + excerpt.header_height as usize;
 892                let header_len =
 893                    cmp::min(range.end - cursor.start(), excerpt.header_height as usize);
 894                summary.add_assign(&D::from_text_summary(&TextSummary {
 895                    bytes: header_len,
 896                    lines: Point::new(header_len as u32, 0),
 897                    lines_utf16: PointUtf16::new(header_len as u32, 0),
 898                    first_line_chars: 0,
 899                    last_line_chars: 0,
 900                    longest_row: 0,
 901                    longest_row_chars: 0,
 902                }));
 903                range.end = cmp::max(start_after_header, range.end);
 904
 905                let excerpt_start = excerpt.range.start.to_offset(&excerpt.buffer);
 906                let end_in_excerpt = excerpt_start + (range.end - start_after_header);
 907                summary.add_assign(
 908                    &excerpt
 909                        .buffer
 910                        .text_summary_for_range(excerpt_start..end_in_excerpt),
 911                );
 912                cursor.next(&());
 913            }
 914        }
 915
 916        summary
 917    }
 918
 919    pub fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
 920    where
 921        D: TextDimension + Ord + Sub<D, Output = D>,
 922    {
 923        let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
 924        cursor.seek(&Some(&anchor.excerpt_id), Bias::Left, &());
 925        if let Some(excerpt) = cursor.item() {
 926            if excerpt.id == anchor.excerpt_id {
 927                let mut excerpt_start = D::from_text_summary(&cursor.start().text);
 928                excerpt_start.add_summary(&excerpt.header_summary(), &());
 929                let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
 930                let buffer_point = anchor.text_anchor.summary::<D>(&excerpt.buffer);
 931                if buffer_point > excerpt_buffer_start {
 932                    excerpt_start.add_assign(&(buffer_point - excerpt_buffer_start));
 933                }
 934                return excerpt_start;
 935            }
 936        }
 937        D::from_text_summary(&cursor.start().text)
 938    }
 939
 940    pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec<D>
 941    where
 942        D: TextDimension + Ord + Sub<D, Output = D>,
 943        I: 'a + IntoIterator<Item = &'a Anchor>,
 944    {
 945        let mut anchors = anchors.into_iter().peekable();
 946        let mut cursor = self.excerpts.cursor::<ExcerptSummary>();
 947        let mut summaries = Vec::new();
 948        while let Some(anchor) = anchors.peek() {
 949            let excerpt_id = &anchor.excerpt_id;
 950            let excerpt_anchors = std::iter::from_fn(|| {
 951                let anchor = anchors.peek()?;
 952                if anchor.excerpt_id == *excerpt_id {
 953                    Some(&anchors.next().unwrap().text_anchor)
 954                } else {
 955                    None
 956                }
 957            });
 958
 959            cursor.seek_forward(&Some(excerpt_id), Bias::Left, &());
 960            if let Some(excerpt) = cursor.item() {
 961                if excerpt.id == *excerpt_id {
 962                    let mut excerpt_start = D::from_text_summary(&cursor.start().text);
 963                    excerpt_start.add_summary(&excerpt.header_summary(), &());
 964                    let excerpt_buffer_start = excerpt.range.start.summary::<D>(&excerpt.buffer);
 965                    summaries.extend(
 966                        excerpt
 967                            .buffer
 968                            .summaries_for_anchors::<D, _>(excerpt_anchors)
 969                            .map(move |summary| {
 970                                let mut excerpt_start = excerpt_start.clone();
 971                                let excerpt_buffer_start = excerpt_buffer_start.clone();
 972                                if summary > excerpt_buffer_start {
 973                                    excerpt_start.add_assign(&(summary - excerpt_buffer_start));
 974                                }
 975                                excerpt_start
 976                            }),
 977                    );
 978                    continue;
 979                }
 980            }
 981
 982            let summary = D::from_text_summary(&cursor.start().text);
 983            summaries.extend(excerpt_anchors.map(|_| summary.clone()));
 984        }
 985
 986        summaries
 987    }
 988
 989    pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
 990        self.anchor_at(position, Bias::Left)
 991    }
 992
 993    pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
 994        self.anchor_at(position, Bias::Right)
 995    }
 996
 997    pub fn anchor_at<T: ToOffset>(&self, position: T, bias: Bias) -> Anchor {
 998        let offset = position.to_offset(self);
 999        let mut cursor = self.excerpts.cursor::<(usize, Option<&ExcerptId>)>();
1000        cursor.seek(&offset, bias, &());
1001        if let Some(excerpt) = cursor.item() {
1002            let overshoot =
1003                (offset - cursor.start().0).saturating_sub(excerpt.header_height as usize);
1004            let buffer_start = excerpt.range.start.to_offset(&excerpt.buffer);
1005            Anchor {
1006                excerpt_id: excerpt.id.clone(),
1007                text_anchor: excerpt.buffer.anchor_at(buffer_start + overshoot, bias),
1008            }
1009        } else if offset == 0 && bias == Bias::Left {
1010            Anchor::min()
1011        } else {
1012            Anchor::max()
1013        }
1014    }
1015
1016    pub fn parse_count(&self) -> usize {
1017        self.as_singleton().unwrap().parse_count()
1018    }
1019
1020    pub fn enclosing_bracket_ranges<T: ToOffset>(
1021        &self,
1022        range: Range<T>,
1023    ) -> Option<(Range<usize>, Range<usize>)> {
1024        let range = range.start.to_offset(self)..range.end.to_offset(self);
1025        self.as_singleton().unwrap().enclosing_bracket_ranges(range)
1026    }
1027
1028    pub fn diagnostics_update_count(&self) -> usize {
1029        self.as_singleton().unwrap().diagnostics_update_count()
1030    }
1031
1032    pub fn language(&self) -> Option<&Arc<Language>> {
1033        self.as_singleton().unwrap().language()
1034    }
1035
1036    pub fn diagnostic_group<'a, O>(
1037        &'a self,
1038        group_id: usize,
1039    ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
1040    where
1041        O: text::FromAnchor + 'a,
1042    {
1043        self.as_singleton().unwrap().diagnostic_group(group_id)
1044    }
1045
1046    pub fn diagnostics_in_range<'a, T, O>(
1047        &'a self,
1048        range: Range<T>,
1049    ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
1050    where
1051        T: 'a + ToOffset,
1052        O: 'a + text::FromAnchor,
1053    {
1054        let range = range.start.to_offset(self)..range.end.to_offset(self);
1055        self.as_singleton().unwrap().diagnostics_in_range(range)
1056    }
1057
1058    pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
1059        let range = range.start.to_offset(self)..range.end.to_offset(self);
1060        self.as_singleton()
1061            .unwrap()
1062            .range_for_syntax_ancestor(range)
1063    }
1064
1065    fn buffer_snapshot_for_excerpt<'a>(
1066        &'a self,
1067        excerpt_id: &'a ExcerptId,
1068    ) -> Option<&'a BufferSnapshot> {
1069        let mut cursor = self.excerpts.cursor::<Option<&ExcerptId>>();
1070        cursor.seek(&Some(excerpt_id), Bias::Left, &());
1071        if let Some(excerpt) = cursor.item() {
1072            if excerpt.id == *excerpt_id {
1073                return Some(&excerpt.buffer);
1074            }
1075        }
1076        None
1077    }
1078
1079    pub fn remote_selections_in_range<'a>(
1080        &'a self,
1081        range: Range<Anchor>,
1082    ) -> impl 'a + Iterator<Item = (ReplicaId, impl 'a + Iterator<Item = Selection<Anchor>>)> {
1083        // TODO
1084        let excerpt_id = self.excerpts.first().unwrap().id.clone();
1085        self.as_singleton()
1086            .unwrap()
1087            .remote_selections_in_range(range.start.text_anchor..range.end.text_anchor)
1088            .map(move |(replica_id, selections)| {
1089                let excerpt_id = excerpt_id.clone();
1090                (
1091                    replica_id,
1092                    selections.map(move |s| Selection {
1093                        id: s.id,
1094                        start: Anchor {
1095                            excerpt_id: excerpt_id.clone(),
1096                            text_anchor: s.start.clone(),
1097                        },
1098                        end: Anchor {
1099                            excerpt_id: excerpt_id.clone(),
1100                            text_anchor: s.end.clone(),
1101                        },
1102                        reversed: s.reversed,
1103                        goal: s.goal,
1104                    }),
1105                )
1106            })
1107    }
1108}
1109
1110impl Excerpt {
1111    fn new(
1112        id: ExcerptId,
1113        buffer_id: usize,
1114        buffer: BufferSnapshot,
1115        range: Range<text::Anchor>,
1116        header_height: u8,
1117        has_trailing_newline: bool,
1118    ) -> Self {
1119        let mut text_summary =
1120            buffer.text_summary_for_range::<TextSummary, _>(range.to_offset(&buffer));
1121        if header_height > 0 {
1122            text_summary.first_line_chars = 0;
1123            text_summary.lines.row += header_height as u32;
1124            text_summary.lines_utf16.row += header_height as u32;
1125            text_summary.bytes += header_height as usize;
1126            text_summary.longest_row += header_height as u32;
1127        }
1128        if has_trailing_newline {
1129            text_summary.last_line_chars = 0;
1130            text_summary.lines.row += 1;
1131            text_summary.lines.column = 0;
1132            text_summary.lines_utf16.row += 1;
1133            text_summary.lines_utf16.column = 0;
1134            text_summary.bytes += 1;
1135        }
1136
1137        Excerpt {
1138            id,
1139            buffer_id,
1140            buffer,
1141            range,
1142            text_summary,
1143            header_height,
1144            has_trailing_newline,
1145        }
1146    }
1147
1148    fn header_summary(&self) -> TextSummary {
1149        TextSummary {
1150            bytes: self.header_height as usize,
1151            lines: Point::new(self.header_height as u32, 0),
1152            lines_utf16: PointUtf16::new(self.header_height as u32, 0),
1153            first_line_chars: 0,
1154            last_line_chars: 0,
1155            longest_row: 0,
1156            longest_row_chars: 0,
1157        }
1158    }
1159}
1160
1161impl sum_tree::Item for Excerpt {
1162    type Summary = ExcerptSummary;
1163
1164    fn summary(&self) -> Self::Summary {
1165        ExcerptSummary {
1166            excerpt_id: self.id.clone(),
1167            text: self.text_summary.clone(),
1168        }
1169    }
1170}
1171
1172impl sum_tree::Summary for ExcerptSummary {
1173    type Context = ();
1174
1175    fn add_summary(&mut self, summary: &Self, _: &()) {
1176        debug_assert!(summary.excerpt_id > self.excerpt_id);
1177        self.excerpt_id = summary.excerpt_id.clone();
1178        self.text.add_summary(&summary.text, &());
1179    }
1180}
1181
1182impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary {
1183    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1184        *self += &summary.text;
1185    }
1186}
1187
1188impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize {
1189    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1190        *self += summary.text.bytes;
1191    }
1192}
1193
1194impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize {
1195    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
1196        Ord::cmp(self, &cursor_location.text.bytes)
1197    }
1198}
1199
1200impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Option<&'a ExcerptId> {
1201    fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering {
1202        Ord::cmp(self, &Some(&cursor_location.excerpt_id))
1203    }
1204}
1205
1206impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point {
1207    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1208        *self += summary.text.lines;
1209    }
1210}
1211
1212impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 {
1213    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1214        *self += summary.text.lines_utf16
1215    }
1216}
1217
1218impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a ExcerptId> {
1219    fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) {
1220        *self = Some(&summary.excerpt_id);
1221    }
1222}
1223
1224impl<'a> MultiBufferChunks<'a> {
1225    pub fn offset(&self) -> usize {
1226        self.range.start
1227    }
1228
1229    pub fn seek(&mut self, offset: usize) {
1230        self.range.start = offset;
1231        self.cursor.seek_forward(&offset, Bias::Right, &());
1232        self.header_height = 0;
1233        self.excerpt_chunks = None;
1234        if let Some(excerpt) = self.cursor.item() {
1235            let buffer_range = excerpt.range.to_offset(&excerpt.buffer);
1236            self.header_height = excerpt.header_height;
1237            self.has_trailing_newline = excerpt.has_trailing_newline;
1238
1239            let buffer_start;
1240            let start_overshoot = self.range.start - self.cursor.start();
1241            if start_overshoot < excerpt.header_height as usize {
1242                self.header_height -= start_overshoot as u8;
1243                buffer_start = buffer_range.start;
1244            } else {
1245                buffer_start =
1246                    buffer_range.start + start_overshoot - excerpt.header_height as usize;
1247                self.header_height = 0;
1248            }
1249
1250            let buffer_end;
1251            let end_overshoot = self.range.end - self.cursor.start();
1252            if end_overshoot < excerpt.header_height as usize {
1253                self.header_height -= excerpt.header_height - end_overshoot as u8;
1254                buffer_end = buffer_start;
1255            } else {
1256                buffer_end = cmp::min(
1257                    buffer_range.end,
1258                    buffer_range.start + end_overshoot - excerpt.header_height as usize,
1259                );
1260            }
1261
1262            self.excerpt_chunks = Some(excerpt.buffer.chunks(buffer_start..buffer_end, self.theme));
1263        }
1264    }
1265}
1266
1267impl<'a> Iterator for MultiBufferChunks<'a> {
1268    type Item = Chunk<'a>;
1269
1270    fn next(&mut self) -> Option<Self::Item> {
1271        loop {
1272            if self.header_height > 0 {
1273                let chunk = Chunk {
1274                    text: unsafe {
1275                        std::str::from_utf8_unchecked(&NEWLINES[..self.header_height as usize])
1276                    },
1277                    ..Default::default()
1278                };
1279                self.range.start += self.header_height as usize;
1280                self.header_height = 0;
1281                return Some(chunk);
1282            }
1283
1284            if let Some(excerpt_chunks) = self.excerpt_chunks.as_mut() {
1285                if let Some(chunk) = excerpt_chunks.next() {
1286                    self.range.start += chunk.text.len();
1287                    return Some(chunk);
1288                }
1289                self.excerpt_chunks.take();
1290                if self.has_trailing_newline && self.cursor.end(&()) <= self.range.end {
1291                    self.range.start += 1;
1292                    return Some(Chunk {
1293                        text: "\n",
1294                        ..Default::default()
1295                    });
1296                }
1297            }
1298
1299            self.cursor.next(&());
1300            if *self.cursor.start() >= self.range.end {
1301                return None;
1302            }
1303
1304            let excerpt = self.cursor.item()?;
1305            let buffer_range = excerpt.range.to_offset(&excerpt.buffer);
1306
1307            let buffer_end = cmp::min(
1308                buffer_range.end,
1309                buffer_range.start + self.range.end
1310                    - excerpt.header_height as usize
1311                    - self.cursor.start(),
1312            );
1313
1314            self.header_height = excerpt.header_height;
1315            self.has_trailing_newline = excerpt.has_trailing_newline;
1316            self.excerpt_chunks = Some(
1317                excerpt
1318                    .buffer
1319                    .chunks(buffer_range.start..buffer_end, self.theme),
1320            );
1321        }
1322    }
1323}
1324
1325impl<'a> Iterator for MultiBufferBytes<'a> {
1326    type Item = &'a [u8];
1327
1328    fn next(&mut self) -> Option<Self::Item> {
1329        self.chunks.next().map(|chunk| chunk.text.as_bytes())
1330    }
1331}
1332
1333impl<'a> io::Read for MultiBufferBytes<'a> {
1334    fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
1335        todo!()
1336    }
1337}
1338
1339impl ToOffset for Point {
1340    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
1341        snapshot.point_to_offset(*self)
1342    }
1343}
1344
1345impl ToOffset for PointUtf16 {
1346    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
1347        snapshot.point_utf16_to_offset(*self)
1348    }
1349}
1350
1351impl ToOffset for usize {
1352    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
1353        assert!(*self <= snapshot.len(), "offset is out of range");
1354        *self
1355    }
1356}
1357
1358impl ToPoint for usize {
1359    fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
1360        snapshot.offset_to_point(*self)
1361    }
1362}
1363
1364impl ToPoint for Point {
1365    fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point {
1366        *self
1367    }
1368}
1369
1370#[cfg(test)]
1371mod tests {
1372    use super::*;
1373    use gpui::MutableAppContext;
1374    use language::Buffer;
1375    use rand::prelude::*;
1376    use std::env;
1377    use text::{Point, RandomCharIter};
1378    use util::test::sample_text;
1379
1380    #[gpui::test]
1381    fn test_singleton_multibuffer(cx: &mut MutableAppContext) {
1382        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
1383        let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
1384        assert_eq!(
1385            multibuffer.read(cx).snapshot(cx).text(),
1386            buffer.read(cx).text()
1387        );
1388
1389        buffer.update(cx, |buffer, cx| buffer.edit([1..3], "XXX", cx));
1390        assert_eq!(
1391            multibuffer.read(cx).snapshot(cx).text(),
1392            buffer.read(cx).text()
1393        );
1394    }
1395
1396    #[gpui::test]
1397    fn test_excerpt_buffer(cx: &mut MutableAppContext) {
1398        let buffer_1 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx));
1399        let buffer_2 = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'g'), cx));
1400
1401        let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
1402
1403        let subscription = multibuffer.update(cx, |multibuffer, cx| {
1404            let subscription = multibuffer.subscribe();
1405            multibuffer.push_excerpt(
1406                ExcerptProperties {
1407                    buffer: &buffer_1,
1408                    range: Point::new(1, 2)..Point::new(2, 5),
1409                    header_height: 2,
1410                },
1411                cx,
1412            );
1413            assert_eq!(
1414                subscription.consume().into_inner(),
1415                [Edit {
1416                    old: 0..0,
1417                    new: 0..13
1418                }]
1419            );
1420
1421            multibuffer.push_excerpt(
1422                ExcerptProperties {
1423                    buffer: &buffer_1,
1424                    range: Point::new(3, 3)..Point::new(4, 4),
1425                    header_height: 1,
1426                },
1427                cx,
1428            );
1429            multibuffer.push_excerpt(
1430                ExcerptProperties {
1431                    buffer: &buffer_2,
1432                    range: Point::new(3, 1)..Point::new(3, 3),
1433                    header_height: 3,
1434                },
1435                cx,
1436            );
1437            assert_eq!(
1438                subscription.consume().into_inner(),
1439                [Edit {
1440                    old: 13..13,
1441                    new: 13..29
1442                }]
1443            );
1444
1445            subscription
1446        });
1447
1448        assert_eq!(
1449            multibuffer.read(cx).snapshot(cx).text(),
1450            concat!(
1451                "\n",      // Preserve newlines
1452                "\n",      //
1453                "bbbb\n",  //
1454                "ccccc\n", //
1455                "\n",      //
1456                "ddd\n",   //
1457                "eeee\n",  //
1458                "\n",      //
1459                "\n",      //
1460                "\n",      //
1461                "jj\n"     //
1462            )
1463        );
1464
1465        buffer_1.update(cx, |buffer, cx| {
1466            buffer.edit(
1467                [
1468                    Point::new(0, 0)..Point::new(0, 0),
1469                    Point::new(2, 1)..Point::new(2, 3),
1470                ],
1471                "\n",
1472                cx,
1473            );
1474        });
1475
1476        assert_eq!(
1477            multibuffer.read(cx).snapshot(cx).text(),
1478            concat!(
1479                "\n",     // Preserve newlines
1480                "\n",     //
1481                "bbbb\n", //
1482                "c\n",    //
1483                "cc\n",   //
1484                "\n",     //
1485                "ddd\n",  //
1486                "eeee\n", //
1487                "\n",     //
1488                "\n",     //
1489                "\n",     //
1490                "jj\n"    //
1491            )
1492        );
1493
1494        assert_eq!(
1495            subscription.consume().into_inner(),
1496            [Edit {
1497                old: 8..10,
1498                new: 8..9
1499            }]
1500        );
1501    }
1502
1503    #[gpui::test(iterations = 100)]
1504    fn test_random_excerpts(cx: &mut MutableAppContext, mut rng: StdRng) {
1505        let operations = env::var("OPERATIONS")
1506            .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1507            .unwrap_or(10);
1508
1509        let mut buffers: Vec<ModelHandle<Buffer>> = Vec::new();
1510        let list = cx.add_model(|_| MultiBuffer::new(0));
1511        let mut excerpt_ids = Vec::new();
1512        let mut expected_excerpts = Vec::new();
1513        let mut old_versions = Vec::new();
1514
1515        for _ in 0..operations {
1516            match rng.gen_range(0..100) {
1517                0..=19 if !buffers.is_empty() => {
1518                    let buffer = buffers.choose(&mut rng).unwrap();
1519                    buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 1, cx));
1520                }
1521                _ => {
1522                    let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
1523                        let base_text = RandomCharIter::new(&mut rng).take(10).collect::<String>();
1524                        buffers.push(cx.add_model(|cx| Buffer::new(0, base_text, cx)));
1525                        buffers.last().unwrap()
1526                    } else {
1527                        buffers.choose(&mut rng).unwrap()
1528                    };
1529
1530                    let buffer = buffer_handle.read(cx);
1531                    let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
1532                    let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
1533                    let header_height = rng.gen_range(0..=5);
1534                    let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
1535                    log::info!(
1536                        "Pushing excerpt wih header {}, buffer {}: {:?}[{:?}] = {:?}",
1537                        header_height,
1538                        buffer_handle.id(),
1539                        buffer.text(),
1540                        start_ix..end_ix,
1541                        &buffer.text()[start_ix..end_ix]
1542                    );
1543
1544                    let excerpt_id = list.update(cx, |list, cx| {
1545                        list.push_excerpt(
1546                            ExcerptProperties {
1547                                buffer: &buffer_handle,
1548                                range: start_ix..end_ix,
1549                                header_height,
1550                            },
1551                            cx,
1552                        )
1553                    });
1554                    excerpt_ids.push(excerpt_id);
1555                    expected_excerpts.push((buffer_handle.clone(), anchor_range, header_height));
1556                }
1557            }
1558
1559            if rng.gen_bool(0.3) {
1560                list.update(cx, |list, cx| {
1561                    old_versions.push((list.snapshot(cx), list.subscribe()));
1562                })
1563            }
1564
1565            let snapshot = list.read(cx).snapshot(cx);
1566
1567            let mut excerpt_starts = Vec::new();
1568            let mut expected_text = String::new();
1569            for (buffer, range, header_height) in &expected_excerpts {
1570                let buffer = buffer.read(cx);
1571                let buffer_range = range.to_offset(buffer);
1572
1573                for _ in 0..*header_height {
1574                    expected_text.push('\n');
1575                }
1576
1577                excerpt_starts.push(TextSummary::from(expected_text.as_str()));
1578                expected_text.extend(buffer.text_for_range(buffer_range.clone()));
1579                expected_text.push('\n');
1580            }
1581
1582            assert_eq!(snapshot.text(), expected_text);
1583
1584            let mut excerpt_starts = excerpt_starts.into_iter();
1585            for (buffer, range, _) in &expected_excerpts {
1586                let buffer_id = buffer.id();
1587                let buffer = buffer.read(cx);
1588                let buffer_range = range.to_offset(buffer);
1589                let buffer_start_point = buffer.offset_to_point(buffer_range.start);
1590                let buffer_start_point_utf16 =
1591                    buffer.text_summary_for_range::<PointUtf16, _>(0..buffer_range.start);
1592
1593                let excerpt_start = excerpt_starts.next().unwrap();
1594                let mut offset = excerpt_start.bytes;
1595                let mut buffer_offset = buffer_range.start;
1596                let mut point = excerpt_start.lines;
1597                let mut buffer_point = buffer_start_point;
1598                let mut point_utf16 = excerpt_start.lines_utf16;
1599                let mut buffer_point_utf16 = buffer_start_point_utf16;
1600                for byte in buffer.bytes_in_range(buffer_range.clone()).flatten() {
1601                    let left_offset = snapshot.clip_offset(offset, Bias::Left);
1602                    let right_offset = snapshot.clip_offset(offset, Bias::Right);
1603                    let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left);
1604                    let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right);
1605                    assert_eq!(
1606                        left_offset,
1607                        excerpt_start.bytes + (buffer_left_offset - buffer_range.start),
1608                        "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}",
1609                        offset,
1610                        buffer_id,
1611                        buffer_offset,
1612                    );
1613                    assert_eq!(
1614                        right_offset,
1615                        excerpt_start.bytes + (buffer_right_offset - buffer_range.start),
1616                        "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}",
1617                        offset,
1618                        buffer_id,
1619                        buffer_offset,
1620                    );
1621
1622                    let left_point = snapshot.clip_point(point, Bias::Left);
1623                    let right_point = snapshot.clip_point(point, Bias::Right);
1624                    let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left);
1625                    let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right);
1626                    assert_eq!(
1627                        left_point,
1628                        excerpt_start.lines + (buffer_left_point - buffer_start_point),
1629                        "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}",
1630                        point,
1631                        buffer_id,
1632                        buffer_point,
1633                    );
1634                    assert_eq!(
1635                        right_point,
1636                        excerpt_start.lines + (buffer_right_point - buffer_start_point),
1637                        "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}",
1638                        point,
1639                        buffer_id,
1640                        buffer_point,
1641                    );
1642
1643                    let left_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Left);
1644                    let right_point_utf16 = snapshot.clip_point_utf16(point_utf16, Bias::Right);
1645                    let buffer_left_point_utf16 =
1646                        buffer.clip_point_utf16(buffer_point_utf16, Bias::Left);
1647                    let buffer_right_point_utf16 =
1648                        buffer.clip_point_utf16(buffer_point_utf16, Bias::Right);
1649                    assert_eq!(
1650                        left_point_utf16,
1651                        excerpt_start.lines_utf16
1652                            + (buffer_left_point_utf16 - buffer_start_point_utf16),
1653                        "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}",
1654                        point_utf16,
1655                        buffer_id,
1656                        buffer_point_utf16,
1657                    );
1658                    assert_eq!(
1659                        right_point_utf16,
1660                        excerpt_start.lines_utf16
1661                            + (buffer_right_point_utf16 - buffer_start_point_utf16),
1662                        "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}",
1663                        point_utf16,
1664                        buffer_id,
1665                        buffer_point_utf16,
1666                    );
1667
1668                    assert_eq!(
1669                        snapshot.point_to_offset(left_point),
1670                        left_offset,
1671                        "point_to_offset({:?})",
1672                        left_point,
1673                    );
1674                    assert_eq!(
1675                        snapshot.offset_to_point(left_offset),
1676                        left_point,
1677                        "offset_to_point({:?})",
1678                        left_offset,
1679                    );
1680
1681                    offset += 1;
1682                    buffer_offset += 1;
1683                    if *byte == b'\n' {
1684                        point += Point::new(1, 0);
1685                        point_utf16 += PointUtf16::new(1, 0);
1686                        buffer_point += Point::new(1, 0);
1687                        buffer_point_utf16 += PointUtf16::new(1, 0);
1688                    } else {
1689                        point += Point::new(0, 1);
1690                        point_utf16 += PointUtf16::new(0, 1);
1691                        buffer_point += Point::new(0, 1);
1692                        buffer_point_utf16 += PointUtf16::new(0, 1);
1693                    }
1694                }
1695            }
1696
1697            for (row, line) in expected_text.split('\n').enumerate() {
1698                assert_eq!(
1699                    snapshot.line_len(row as u32),
1700                    line.len() as u32,
1701                    "line_len({}).",
1702                    row
1703                );
1704            }
1705
1706            for _ in 0..10 {
1707                let end_ix = snapshot.clip_offset(rng.gen_range(0..=snapshot.len()), Bias::Right);
1708                let start_ix = snapshot.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
1709
1710                assert_eq!(
1711                    snapshot
1712                        .text_for_range(start_ix..end_ix)
1713                        .collect::<String>(),
1714                    &expected_text[start_ix..end_ix],
1715                    "incorrect text for range {:?}",
1716                    start_ix..end_ix
1717                );
1718
1719                let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]);
1720                assert_eq!(
1721                    snapshot.text_summary_for_range::<TextSummary, _>(start_ix..end_ix),
1722                    expected_summary,
1723                    "incorrect summary for range {:?}",
1724                    start_ix..end_ix
1725                );
1726            }
1727        }
1728
1729        let snapshot = list.read(cx).snapshot(cx);
1730        for (old_snapshot, subscription) in old_versions {
1731            let edits = subscription.consume().into_inner();
1732
1733            log::info!(
1734                "applying edits since old text: {:?}: {:?}",
1735                old_snapshot.text(),
1736                edits,
1737            );
1738
1739            let mut text = old_snapshot.text();
1740            for edit in edits {
1741                let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
1742                text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
1743            }
1744            assert_eq!(text.to_string(), snapshot.text());
1745        }
1746    }
1747}