multi_buffer.rs

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