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