multi_buffer.rs

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