From e192aefed3258c07237971be9620ee9ff99017bd Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 23 Sep 2024 14:57:13 -0600 Subject: [PATCH] Checkpoint Co-Authored-By: Nathan --- crates/multi_buffer2/src/anchor2.rs | 57 +- crates/multi_buffer2/src/multi_buffer2.rs | 7602 ++++++++++----------- 2 files changed, 3678 insertions(+), 3981 deletions(-) diff --git a/crates/multi_buffer2/src/anchor2.rs b/crates/multi_buffer2/src/anchor2.rs index c594503548..867c136f13 100644 --- a/crates/multi_buffer2/src/anchor2.rs +++ b/crates/multi_buffer2/src/anchor2.rs @@ -1,17 +1,16 @@ -use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToOffsetUtf16, ToPoint}; +use super::{MultiBufferSnapshot, ToOffset, ToOffsetUtf16, ToPoint}; use language::{OffsetUtf16, Point, TextDimension}; use std::{ cmp::Ordering, ops::{Range, Sub}, }; use sum_tree::Bias; -use text::BufferId; #[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)] -pub struct Anchor { - pub buffer_id: Option, - pub excerpt_id: ExcerptId, - pub text_anchor: text::Anchor, +pub enum Anchor { + Start, + End, + Text(text::Anchor), } impl Anchor { @@ -34,18 +33,19 @@ impl Anchor { } pub fn cmp(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering { - let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id, snapshot); - if excerpt_id_cmp.is_eq() { - if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() { - Ordering::Equal - } else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) { - self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer) - } else { - Ordering::Equal - } - } else { - excerpt_id_cmp - } + todo!() + // let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id, snapshot); + // if excerpt_id_cmp.is_eq() { + // if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() { + // Ordering::Equal + // } else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) { + // self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer) + // } else { + // Ordering::Equal + // } + // } else { + // excerpt_id_cmp + // } } pub fn bias(&self) -> Bias { @@ -89,16 +89,17 @@ impl Anchor { } pub fn is_valid(&self, snapshot: &MultiBufferSnapshot) -> bool { - if *self == Anchor::min() || *self == Anchor::max() { - true - } else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) { - excerpt.contains(self) - && (self.text_anchor == excerpt.range.context.start - || self.text_anchor == excerpt.range.context.end - || self.text_anchor.is_valid(&excerpt.buffer)) - } else { - false - } + todo!() + // if *self == Anchor::min() || *self == Anchor::max() { + // true + // } else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) { + // excerpt.contains(self) + // && (self.text_anchor == excerpt.range.context.start + // || self.text_anchor == excerpt.range.context.end + // || self.text_anchor.is_valid(&excerpt.buffer)) + // } else { + // false + // } } } diff --git a/crates/multi_buffer2/src/multi_buffer2.rs b/crates/multi_buffer2/src/multi_buffer2.rs index 189352e4dd..ce48a40349 100644 --- a/crates/multi_buffer2/src/multi_buffer2.rs +++ b/crates/multi_buffer2/src/multi_buffer2.rs @@ -3,10 +3,9 @@ mod anchor2; pub use anchor2::{Anchor, AnchorRangeExt, Offset}; use anyhow::{anyhow, Result}; use clock::ReplicaId; -use collections::{BTreeMap, Bound, HashMap, HashSet}; +use collections::{BTreeMap, HashMap, HashSet}; use futures::{channel::mpsc, SinkExt}; -use gpui::{AppContext, EntityId, EventEmitter, Model, ModelContext}; -use itertools::Itertools; +use gpui::{AppContext, EventEmitter, Model, ModelContext}; use language::{ language_settings::{language_settings, LanguageSettings}, AutoindentMode, Buffer, BufferChunks, BufferRow, BufferSnapshot, Capability, CharClassifier, @@ -15,7 +14,6 @@ use language::{ TextDimension, ToOffset as _, ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _, TransactionId, Unclipped, }; -use smallvec::SmallVec; use std::{ any::type_name, borrow::Cow, @@ -23,9 +21,10 @@ use std::{ cmp, fmt, future::Future, io, - iter::{self, FromIterator}, + iter::{self}, mem, ops::{Range, RangeBounds, Sub}, + path::PathBuf, str, sync::Arc, time::{Duration, Instant}, @@ -38,22 +37,11 @@ use text::{ }; use theme::SyntaxTheme; -use util::post_inc; - #[cfg(any(test, feature = "test-support"))] use gpui::Context; const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize]; -#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct ExcerptId(usize); - -impl From for EntityId { - fn from(id: ExcerptId) -> Self { - EntityId::from(id.0 as u64) - } -} - /// One or more [`Buffers`](Buffer) being edited in a single view. /// /// See @@ -73,31 +61,11 @@ pub struct MultiBuffer { #[derive(Clone, Debug, PartialEq, Eq)] pub enum Event { - ExcerptsAdded { - buffer: Model, - predecessor: ExcerptId, - excerpts: Vec<(ExcerptId, ExcerptRange)>, - }, - ExcerptsRemoved { - ids: Vec, - }, - ExcerptsExpanded { - ids: Vec, - }, - ExcerptsEdited { - ids: Vec, - }, - Edited { - singleton_buffer_edited: bool, - }, - TransactionUndone { - transaction_id: TransactionId, - }, + Edited { singleton_buffer_edited: bool }, + TransactionUndone { transaction_id: TransactionId }, Reloaded, DiffBaseChanged, - DiffUpdated { - buffer: Model, - }, + DiffUpdated { buffer: Model }, LanguageChanged(BufferId), CapabilityChanged, Reparsed(BufferId), @@ -180,7 +148,8 @@ struct BufferState { pub struct MultiBufferSnapshot { singleton: bool, excerpts: SumTree, - excerpt_ids: SumTree, + // todo! + // excerpt_ids: SumTree, trailing_excerpt_update_count: usize, non_text_state_update_count: usize, edit_count: usize, @@ -190,7 +159,6 @@ pub struct MultiBufferSnapshot { } pub struct ExcerptInfo { - pub id: ExcerptId, pub buffer: BufferSnapshot, pub buffer_id: BufferId, pub range: ExcerptRange, @@ -199,7 +167,6 @@ pub struct ExcerptInfo { impl std::fmt::Debug for ExcerptInfo { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(type_name::()) - .field("id", &self.id) .field("buffer_id", &self.buffer_id) .field("range", &self.range) .finish() @@ -228,12 +195,6 @@ impl ExcerptBoundary { /// A slice into a [`Buffer`] that is being edited in a [`MultiBuffer`]. #[derive(Clone)] struct Excerpt { - /// The unique identifier for this excerpt - id: ExcerptId, - /// The location of the excerpt in the [`MultiBuffer`] - locator: Locator, - /// The buffer being excerpted - buffer_id: BufferId, /// A snapshot of the buffer being excerpted buffer: BufferSnapshot, /// The range of the buffer to be shown in the excerpt @@ -255,12 +216,6 @@ pub struct MultiBufferExcerpt<'a> { excerpt_offset: usize, } -#[derive(Clone, Debug)] -struct ExcerptIdMapping { - id: ExcerptId, - locator: Locator, -} - /// A range of text from a single [`Buffer`], to be shown as an [`Excerpt`]. /// These ranges are relative to the buffer itself #[derive(Clone, Debug, Eq, PartialEq)] @@ -272,11 +227,10 @@ pub struct ExcerptRange { pub primary: Option>, } -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct ExcerptSummary { - excerpt_id: ExcerptId, - /// The location of the last [`Excerpt`] being summarized - excerpt_locator: Locator, + path: Option, + buffer_id: BufferId, /// The maximum row of the [`Excerpt`]s being summarized max_buffer_row: MultiBufferRow, text: TextSummary, @@ -310,7 +264,6 @@ pub struct ReversedMultiBufferBytes<'a> { } struct ExcerptChunks<'a> { - excerpt_id: ExcerptId, content_chunks: BufferChunks<'a>, footer_height: usize, } @@ -525,227 +478,228 @@ impl MultiBuffer { S: ToOffset, T: Into>, { - if self.read_only() { - return; - } - if self.buffers.borrow().is_empty() { - return; - } + todo!() + // if self.read_only() { + // return; + // } + // if self.buffers.borrow().is_empty() { + // return; + // } - let snapshot = self.read(cx); - let edits = edits.into_iter().map(|(range, new_text)| { - let mut range = range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot); - if range.start > range.end { - mem::swap(&mut range.start, &mut range.end); - } - (range, new_text) - }); + // let snapshot = self.read(cx); + // let edits = edits.into_iter().map(|(range, new_text)| { + // let mut range = range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot); + // if range.start > range.end { + // mem::swap(&mut range.start, &mut range.end); + // } + // (range, new_text) + // }); - if let Some(buffer) = self.as_singleton() { - buffer.update(cx, |buffer, cx| { - buffer.edit(edits, autoindent_mode, cx); - }); - cx.emit(Event::ExcerptsEdited { - ids: self.excerpt_ids(), - }); - return; - } + // if let Some(buffer) = self.as_singleton() { + // buffer.update(cx, |buffer, cx| { + // buffer.edit(edits, autoindent_mode, cx); + // }); + // cx.emit(Event::ExcerptsEdited { + // ids: self.excerpt_ids(), + // }); + // return; + // } - let original_indent_columns = match &mut autoindent_mode { - Some(AutoindentMode::Block { - original_indent_columns, - }) => mem::take(original_indent_columns), - _ => Default::default(), - }; + // let original_indent_columns = match &mut autoindent_mode { + // Some(AutoindentMode::Block { + // original_indent_columns, + // }) => mem::take(original_indent_columns), + // _ => Default::default(), + // }; - struct BufferEdit { - range: Range, - new_text: Arc, - is_insertion: bool, - original_indent_column: u32, - } - let mut buffer_edits: HashMap> = Default::default(); - let mut edited_excerpt_ids = Vec::new(); - let mut cursor = snapshot.excerpts.cursor::(&()); - for (ix, (range, new_text)) in edits.enumerate() { - let new_text: Arc = new_text.into(); - let original_indent_column = original_indent_columns.get(ix).copied().unwrap_or(0); - cursor.seek(&range.start, Bias::Right, &()); - if cursor.item().is_none() && range.start == *cursor.start() { - cursor.prev(&()); - } - let start_excerpt = cursor.item().expect("start offset out of bounds"); - let start_overshoot = range.start - cursor.start(); - let buffer_start = start_excerpt - .range - .context - .start - .to_offset(&start_excerpt.buffer) - + start_overshoot; - edited_excerpt_ids.push(start_excerpt.id); + // struct BufferEdit { + // range: Range, + // new_text: Arc, + // is_insertion: bool, + // original_indent_column: u32, + // } + // let mut buffer_edits: HashMap> = Default::default(); + // let mut edited_excerpt_ids = Vec::new(); + // let mut cursor = snapshot.excerpts.cursor::(&()); + // for (ix, (range, new_text)) in edits.enumerate() { + // let new_text: Arc = new_text.into(); + // let original_indent_column = original_indent_columns.get(ix).copied().unwrap_or(0); + // cursor.seek(&range.start, Bias::Right, &()); + // if cursor.item().is_none() && range.start == *cursor.start() { + // cursor.prev(&()); + // } + // let start_excerpt = cursor.item().expect("start offset out of bounds"); + // let start_overshoot = range.start - cursor.start(); + // let buffer_start = start_excerpt + // .range + // .context + // .start + // .to_offset(&start_excerpt.buffer) + // + start_overshoot; + // edited_excerpt_ids.push(start_excerpt.id); - cursor.seek(&range.end, Bias::Right, &()); - if cursor.item().is_none() && range.end == *cursor.start() { - cursor.prev(&()); - } - let end_excerpt = cursor.item().expect("end offset out of bounds"); - let end_overshoot = range.end - cursor.start(); - let buffer_end = end_excerpt - .range - .context - .start - .to_offset(&end_excerpt.buffer) - + end_overshoot; + // cursor.seek(&range.end, Bias::Right, &()); + // if cursor.item().is_none() && range.end == *cursor.start() { + // cursor.prev(&()); + // } + // let end_excerpt = cursor.item().expect("end offset out of bounds"); + // let end_overshoot = range.end - cursor.start(); + // let buffer_end = end_excerpt + // .range + // .context + // .start + // .to_offset(&end_excerpt.buffer) + // + end_overshoot; - if start_excerpt.id == end_excerpt.id { - buffer_edits - .entry(start_excerpt.buffer_id) - .or_default() - .push(BufferEdit { - range: buffer_start..buffer_end, - new_text, - is_insertion: true, - original_indent_column, - }); - } else { - edited_excerpt_ids.push(end_excerpt.id); - let start_excerpt_range = buffer_start - ..start_excerpt - .range - .context - .end - .to_offset(&start_excerpt.buffer); - let end_excerpt_range = end_excerpt - .range - .context - .start - .to_offset(&end_excerpt.buffer) - ..buffer_end; - buffer_edits - .entry(start_excerpt.buffer_id) - .or_default() - .push(BufferEdit { - range: start_excerpt_range, - new_text: new_text.clone(), - is_insertion: true, - original_indent_column, - }); - buffer_edits - .entry(end_excerpt.buffer_id) - .or_default() - .push(BufferEdit { - range: end_excerpt_range, - new_text: new_text.clone(), - is_insertion: false, - original_indent_column, - }); + // if start_excerpt.id == end_excerpt.id { + // buffer_edits + // .entry(start_excerpt.buffer_id) + // .or_default() + // .push(BufferEdit { + // range: buffer_start..buffer_end, + // new_text, + // is_insertion: true, + // original_indent_column, + // }); + // } else { + // edited_excerpt_ids.push(end_excerpt.id); + // let start_excerpt_range = buffer_start + // ..start_excerpt + // .range + // .context + // .end + // .to_offset(&start_excerpt.buffer); + // let end_excerpt_range = end_excerpt + // .range + // .context + // .start + // .to_offset(&end_excerpt.buffer) + // ..buffer_end; + // buffer_edits + // .entry(start_excerpt.buffer_id) + // .or_default() + // .push(BufferEdit { + // range: start_excerpt_range, + // new_text: new_text.clone(), + // is_insertion: true, + // original_indent_column, + // }); + // buffer_edits + // .entry(end_excerpt.buffer_id) + // .or_default() + // .push(BufferEdit { + // range: end_excerpt_range, + // new_text: new_text.clone(), + // is_insertion: false, + // original_indent_column, + // }); - cursor.seek(&range.start, Bias::Right, &()); - cursor.next(&()); - while let Some(excerpt) = cursor.item() { - if excerpt.id == end_excerpt.id { - break; - } - buffer_edits - .entry(excerpt.buffer_id) - .or_default() - .push(BufferEdit { - range: excerpt.range.context.to_offset(&excerpt.buffer), - new_text: new_text.clone(), - is_insertion: false, - original_indent_column, - }); - edited_excerpt_ids.push(excerpt.id); - cursor.next(&()); - } - } - } + // cursor.seek(&range.start, Bias::Right, &()); + // cursor.next(&()); + // while let Some(excerpt) = cursor.item() { + // if excerpt.id == end_excerpt.id { + // break; + // } + // buffer_edits + // .entry(excerpt.buffer_id) + // .or_default() + // .push(BufferEdit { + // range: excerpt.range.context.to_offset(&excerpt.buffer), + // new_text: new_text.clone(), + // is_insertion: false, + // original_indent_column, + // }); + // edited_excerpt_ids.push(excerpt.id); + // cursor.next(&()); + // } + // } + // } - drop(cursor); - drop(snapshot); - // Non-generic part of edit, hoisted out to avoid blowing up LLVM IR. - fn tail( - this: &mut MultiBuffer, - buffer_edits: HashMap>, - autoindent_mode: Option, - edited_excerpt_ids: Vec, - cx: &mut ModelContext, - ) { - for (buffer_id, mut edits) in buffer_edits { - edits.sort_unstable_by_key(|edit| edit.range.start); - this.buffers.borrow()[&buffer_id] - .buffer - .update(cx, |buffer, cx| { - let mut edits = edits.into_iter().peekable(); - let mut insertions = Vec::new(); - let mut original_indent_columns = Vec::new(); - let mut deletions = Vec::new(); - let empty_str: Arc = Arc::default(); - while let Some(BufferEdit { - mut range, - new_text, - mut is_insertion, - original_indent_column, - }) = edits.next() - { - while let Some(BufferEdit { - range: next_range, - is_insertion: next_is_insertion, - .. - }) = edits.peek() - { - if range.end >= next_range.start { - range.end = cmp::max(next_range.end, range.end); - is_insertion |= *next_is_insertion; - edits.next(); - } else { - break; - } - } + // drop(cursor); + // drop(snapshot); + // // Non-generic part of edit, hoisted out to avoid blowing up LLVM IR. + // fn tail( + // this: &mut MultiBuffer, + // buffer_edits: HashMap>, + // autoindent_mode: Option, + // edited_excerpt_ids: Vec, + // cx: &mut ModelContext, + // ) { + // for (buffer_id, mut edits) in buffer_edits { + // edits.sort_unstable_by_key(|edit| edit.range.start); + // this.buffers.borrow()[&buffer_id] + // .buffer + // .update(cx, |buffer, cx| { + // let mut edits = edits.into_iter().peekable(); + // let mut insertions = Vec::new(); + // let mut original_indent_columns = Vec::new(); + // let mut deletions = Vec::new(); + // let empty_str: Arc = Arc::default(); + // while let Some(BufferEdit { + // mut range, + // new_text, + // mut is_insertion, + // original_indent_column, + // }) = edits.next() + // { + // while let Some(BufferEdit { + // range: next_range, + // is_insertion: next_is_insertion, + // .. + // }) = edits.peek() + // { + // if range.end >= next_range.start { + // range.end = cmp::max(next_range.end, range.end); + // is_insertion |= *next_is_insertion; + // edits.next(); + // } else { + // break; + // } + // } - if is_insertion { - original_indent_columns.push(original_indent_column); - insertions.push(( - buffer.anchor_before(range.start) - ..buffer.anchor_before(range.end), - new_text.clone(), - )); - } else if !range.is_empty() { - deletions.push(( - buffer.anchor_before(range.start) - ..buffer.anchor_before(range.end), - empty_str.clone(), - )); - } - } + // if is_insertion { + // original_indent_columns.push(original_indent_column); + // insertions.push(( + // buffer.anchor_before(range.start) + // ..buffer.anchor_before(range.end), + // new_text.clone(), + // )); + // } else if !range.is_empty() { + // deletions.push(( + // buffer.anchor_before(range.start) + // ..buffer.anchor_before(range.end), + // empty_str.clone(), + // )); + // } + // } - let deletion_autoindent_mode = - if let Some(AutoindentMode::Block { .. }) = autoindent_mode { - Some(AutoindentMode::Block { - original_indent_columns: Default::default(), - }) - } else { - None - }; - let insertion_autoindent_mode = - if let Some(AutoindentMode::Block { .. }) = autoindent_mode { - Some(AutoindentMode::Block { - original_indent_columns, - }) - } else { - None - }; + // let deletion_autoindent_mode = + // if let Some(AutoindentMode::Block { .. }) = autoindent_mode { + // Some(AutoindentMode::Block { + // original_indent_columns: Default::default(), + // }) + // } else { + // None + // }; + // let insertion_autoindent_mode = + // if let Some(AutoindentMode::Block { .. }) = autoindent_mode { + // Some(AutoindentMode::Block { + // original_indent_columns, + // }) + // } else { + // None + // }; - buffer.edit(deletions, deletion_autoindent_mode, cx); - buffer.edit(insertions, insertion_autoindent_mode, cx); - }) - } + // buffer.edit(deletions, deletion_autoindent_mode, cx); + // buffer.edit(insertions, insertion_autoindent_mode, cx); + // }) + // } - cx.emit(Event::ExcerptsEdited { - ids: edited_excerpt_ids, - }); - } - tail(self, buffer_edits, autoindent_mode, edited_excerpt_ids, cx); + // cx.emit(Event::ExcerptsEdited { + // ids: edited_excerpt_ids, + // }); + // } + // tail(self, buffer_edits, autoindent_mode, edited_excerpt_ids, cx); } // Inserts newlines at the given position to create an empty line, returning the start of the new line. @@ -764,8 +718,7 @@ impl MultiBuffer { buffer.insert_empty_line(multibuffer_point, space_above, space_below, cx) }) } else { - let (buffer, buffer_point, _) = - self.point_to_buffer_point(multibuffer_point, cx).unwrap(); + let (buffer, buffer_point) = self.point_to_buffer_point(multibuffer_point, cx).unwrap(); self.start_transaction(cx); let empty_line_start = buffer.update(cx, |buffer, cx| { buffer.insert_empty_line(buffer_point, space_above, space_below, cx) @@ -832,58 +785,59 @@ impl MultiBuffer { where D: TextDimension + Ord + Sub, { - if let Some(buffer) = self.as_singleton() { - return buffer - .read(cx) - .edited_ranges_for_transaction_id(transaction_id) - .collect::>(); - } + todo!() + // if let Some(buffer) = self.as_singleton() { + // return buffer + // .read(cx) + // .edited_ranges_for_transaction_id(transaction_id) + // .collect::>(); + // } - let Some(transaction) = self.history.transaction(transaction_id) else { - return Vec::new(); - }; + // let Some(transaction) = self.history.transaction(transaction_id) else { + // return Vec::new(); + // }; - let mut ranges = Vec::new(); - let snapshot = self.read(cx); - let buffers = self.buffers.borrow(); - let mut cursor = snapshot.excerpts.cursor::(&()); + // let mut ranges = Vec::new(); + // let snapshot = self.read(cx); + // let buffers = self.buffers.borrow(); + // let mut cursor = snapshot.excerpts.cursor::(&()); - for (buffer_id, buffer_transaction) in &transaction.buffer_transactions { - let Some(buffer_state) = buffers.get(buffer_id) else { - continue; - }; + // for (buffer_id, buffer_transaction) in &transaction.buffer_transactions { + // let Some(buffer_state) = buffers.get(buffer_id) else { + // continue; + // }; - let buffer = buffer_state.buffer.read(cx); - for range in buffer.edited_ranges_for_transaction_id::(*buffer_transaction) { - for excerpt_id in &buffer_state.excerpts { - cursor.seek(excerpt_id, Bias::Left, &()); - if let Some(excerpt) = cursor.item() { - if excerpt.locator == *excerpt_id { - let excerpt_buffer_start = - excerpt.range.context.start.summary::(buffer); - let excerpt_buffer_end = excerpt.range.context.end.summary::(buffer); - let excerpt_range = excerpt_buffer_start.clone()..excerpt_buffer_end; - if excerpt_range.contains(&range.start) - && excerpt_range.contains(&range.end) - { - let excerpt_start = D::from_text_summary(&cursor.start().text); + // let buffer = buffer_state.buffer.read(cx); + // for range in buffer.edited_ranges_for_transaction_id::(*buffer_transaction) { + // for excerpt_id in &buffer_state.excerpts { + // cursor.seek(excerpt_id, Bias::Left, &()); + // if let Some(excerpt) = cursor.item() { + // if excerpt.locator == *excerpt_id { + // let excerpt_buffer_start = + // excerpt.range.context.start.summary::(buffer); + // let excerpt_buffer_end = excerpt.range.context.end.summary::(buffer); + // let excerpt_range = excerpt_buffer_start.clone()..excerpt_buffer_end; + // if excerpt_range.contains(&range.start) + // && excerpt_range.contains(&range.end) + // { + // let excerpt_start = D::from_text_summary(&cursor.start().text); - let mut start = excerpt_start.clone(); - start.add_assign(&(range.start - excerpt_buffer_start.clone())); - let mut end = excerpt_start; - end.add_assign(&(range.end - excerpt_buffer_start)); + // let mut start = excerpt_start.clone(); + // start.add_assign(&(range.start - excerpt_buffer_start.clone())); + // let mut end = excerpt_start; + // end.add_assign(&(range.end - excerpt_buffer_start)); - ranges.push(start..end); - break; - } - } - } - } - } - } + // ranges.push(start..end); + // break; + // } + // } + // } + // } + // } + // } - ranges.sort_by_key(|range| range.start.clone()); - ranges + // ranges.sort_by_key(|range| range.start.clone()); + // ranges } pub fn merge_transactions( @@ -959,74 +913,75 @@ impl MultiBuffer { cursor_shape: CursorShape, cx: &mut ModelContext, ) { - let mut selections_by_buffer: HashMap>> = - Default::default(); - let snapshot = self.read(cx); - let mut cursor = snapshot.excerpts.cursor::>(&()); - for selection in selections { - let start_locator = snapshot.excerpt_locator_for_id(selection.start.excerpt_id); - let end_locator = snapshot.excerpt_locator_for_id(selection.end.excerpt_id); + todo!() + // let mut selections_by_buffer: HashMap>> = + // Default::default(); + // let snapshot = self.read(cx); + // let mut cursor = snapshot.excerpts.cursor::>(&()); + // for selection in selections { + // let start_locator = snapshot.excerpt_locator_for_id(selection.start.excerpt_id); + // let end_locator = snapshot.excerpt_locator_for_id(selection.end.excerpt_id); - cursor.seek(&Some(start_locator), Bias::Left, &()); - while let Some(excerpt) = cursor.item() { - if excerpt.locator > *end_locator { - break; - } + // cursor.seek(&Some(start_locator), Bias::Left, &()); + // while let Some(excerpt) = cursor.item() { + // if excerpt.locator > *end_locator { + // break; + // } - let mut start = excerpt.range.context.start; - let mut end = excerpt.range.context.end; - if excerpt.id == selection.start.excerpt_id { - start = selection.start.text_anchor; - } - if excerpt.id == selection.end.excerpt_id { - end = selection.end.text_anchor; - } - selections_by_buffer - .entry(excerpt.buffer_id) - .or_default() - .push(Selection { - id: selection.id, - start, - end, - reversed: selection.reversed, - goal: selection.goal, - }); + // let mut start = excerpt.range.context.start; + // let mut end = excerpt.range.context.end; + // if excerpt.id == selection.start.excerpt_id { + // start = selection.start.text_anchor; + // } + // if excerpt.id == selection.end.excerpt_id { + // end = selection.end.text_anchor; + // } + // selections_by_buffer + // .entry(excerpt.buffer_id) + // .or_default() + // .push(Selection { + // id: selection.id, + // start, + // end, + // reversed: selection.reversed, + // goal: selection.goal, + // }); - cursor.next(&()); - } - } + // cursor.next(&()); + // } + // } - for (buffer_id, buffer_state) in self.buffers.borrow().iter() { - if !selections_by_buffer.contains_key(buffer_id) { - buffer_state - .buffer - .update(cx, |buffer, cx| buffer.remove_active_selections(cx)); - } - } + // for (buffer_id, buffer_state) in self.buffers.borrow().iter() { + // if !selections_by_buffer.contains_key(buffer_id) { + // buffer_state + // .buffer + // .update(cx, |buffer, cx| buffer.remove_active_selections(cx)); + // } + // } - for (buffer_id, mut selections) in selections_by_buffer { - self.buffers.borrow()[&buffer_id] - .buffer - .update(cx, |buffer, cx| { - selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer)); - let mut selections = selections.into_iter().peekable(); - let merged_selections = Arc::from_iter(iter::from_fn(|| { - let mut selection = selections.next()?; - while let Some(next_selection) = selections.peek() { - if selection.end.cmp(&next_selection.start, buffer).is_ge() { - let next_selection = selections.next().unwrap(); - if next_selection.end.cmp(&selection.end, buffer).is_ge() { - selection.end = next_selection.end; - } - } else { - break; - } - } - Some(selection) - })); - buffer.set_active_selections(merged_selections, line_mode, cursor_shape, cx); - }); - } + // for (buffer_id, mut selections) in selections_by_buffer { + // self.buffers.borrow()[&buffer_id] + // .buffer + // .update(cx, |buffer, cx| { + // selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer)); + // let mut selections = selections.into_iter().peekable(); + // let merged_selections = Arc::from_iter(iter::from_fn(|| { + // let mut selection = selections.next()?; + // while let Some(next_selection) = selections.peek() { + // if selection.end.cmp(&next_selection.start, buffer).is_ge() { + // let next_selection = selections.next().unwrap(); + // if next_selection.end.cmp(&selection.end, buffer).is_ge() { + // selection.end = next_selection.end; + // } + // } else { + // break; + // } + // } + // Some(selection) + // })); + // buffer.set_active_selections(merged_selections, line_mode, cursor_shape, cx); + // }); + // } } pub fn remove_active_selections(&mut self, cx: &mut ModelContext) { @@ -1138,297 +1093,299 @@ impl MultiBuffer { context_line_count: u32, cx: &mut ModelContext, ) -> mpsc::Receiver> { - let (buffer_id, buffer_snapshot) = - buffer.update(cx, |buffer, _| (buffer.remote_id(), buffer.snapshot())); + todo!() + // let (buffer_id, buffer_snapshot) = + // buffer.update(cx, |buffer, _| (buffer.remote_id(), buffer.snapshot())); - let (mut tx, rx) = mpsc::channel(256); - cx.spawn(move |this, mut cx| async move { - let mut excerpt_ranges = Vec::new(); - let mut range_counts = Vec::new(); - cx.background_executor() - .scoped(|scope| { - scope.spawn(async { - let (ranges, counts) = - build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count); - excerpt_ranges = ranges; - range_counts = counts; - }); - }) - .await; + // let (mut tx, rx) = mpsc::channel(256); + // cx.spawn(move |this, mut cx| async move { + // let mut excerpt_ranges = Vec::new(); + // let mut range_counts = Vec::new(); + // cx.background_executor() + // .scoped(|scope| { + // scope.spawn(async { + // let (ranges, counts) = + // build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count); + // excerpt_ranges = ranges; + // range_counts = counts; + // }); + // }) + // .await; - let mut ranges = ranges.into_iter(); - let mut range_counts = range_counts.into_iter(); - for excerpt_ranges in excerpt_ranges.chunks(100) { - let excerpt_ids = match this.update(&mut cx, |this, cx| { - this.push_excerpts(buffer.clone(), excerpt_ranges.iter().cloned(), cx) - }) { - Ok(excerpt_ids) => excerpt_ids, - Err(_) => return, - }; + // let mut ranges = ranges.into_iter(); + // let mut range_counts = range_counts.into_iter(); + // for excerpt_ranges in excerpt_ranges.chunks(100) { + // let excerpt_ids = match this.update(&mut cx, |this, cx| { + // this.push_excerpts(buffer.clone(), excerpt_ranges.iter().cloned(), cx) + // }) { + // Ok(excerpt_ids) => excerpt_ids, + // Err(_) => return, + // }; - for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.by_ref()) - { - for range in ranges.by_ref().take(range_count) { - let start = Anchor { - buffer_id: Some(buffer_id), - excerpt_id, - text_anchor: range.start, - }; - let end = Anchor { - buffer_id: Some(buffer_id), - excerpt_id, - text_anchor: range.end, - }; - if tx.send(start..end).await.is_err() { - break; - } - } - } - } - }) - .detach(); + // for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.by_ref()) + // { + // for range in ranges.by_ref().take(range_count) { + // let start = Anchor { + // buffer_id: Some(buffer_id), + // excerpt_id, + // text_anchor: range.start, + // }; + // let end = Anchor { + // buffer_id: Some(buffer_id), + // excerpt_id, + // text_anchor: range.end, + // }; + // if tx.send(start..end).await.is_err() { + // break; + // } + // } + // } + // } + // }) + // .detach(); - rx + // rx } - pub fn push_excerpts( + pub fn insert_excerpts( &mut self, buffer: Model, ranges: impl IntoIterator>, cx: &mut ModelContext, - ) -> Vec - where - O: text::ToOffset, - { - self.insert_excerpts_after(ExcerptId::max(), buffer, ranges, cx) - } - - pub fn push_excerpts_with_context_lines( - &mut self, - buffer: Model, - ranges: Vec>, - context_line_count: u32, - cx: &mut ModelContext, - ) -> Vec> - where - O: text::ToPoint + text::ToOffset, - { - let buffer_id = buffer.read(cx).remote_id(); - let buffer_snapshot = buffer.read(cx).snapshot(); - let (excerpt_ranges, range_counts) = - build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count); - - let excerpt_ids = self.push_excerpts(buffer, excerpt_ranges, cx); - - let mut anchor_ranges = Vec::new(); - let mut ranges = ranges.into_iter(); - for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.into_iter()) { - anchor_ranges.extend(ranges.by_ref().take(range_count).map(|range| { - let start = Anchor { - buffer_id: Some(buffer_id), - excerpt_id, - text_anchor: buffer_snapshot.anchor_after(range.start), - }; - let end = Anchor { - buffer_id: Some(buffer_id), - excerpt_id, - text_anchor: buffer_snapshot.anchor_after(range.end), - }; - start..end - })) - } - anchor_ranges - } - - pub fn insert_excerpts_after( - &mut self, - prev_excerpt_id: ExcerptId, - buffer: Model, - ranges: impl IntoIterator>, - cx: &mut ModelContext, - ) -> Vec - where - O: text::ToOffset, - { - let mut ids = Vec::new(); - let mut next_excerpt_id = - if let Some(last_entry) = self.snapshot.borrow().excerpt_ids.last() { - last_entry.id.0 + 1 - } else { - 1 - }; - self.insert_excerpts_with_ids_after( - prev_excerpt_id, - buffer, - ranges.into_iter().map(|range| { - let id = ExcerptId(post_inc(&mut next_excerpt_id)); - ids.push(id); - (id, range) - }), - cx, - ); - ids - } - - pub fn insert_excerpts_with_ids_after( - &mut self, - prev_excerpt_id: ExcerptId, - buffer: Model, - ranges: impl IntoIterator)>, - cx: &mut ModelContext, ) where O: text::ToOffset, { - assert_eq!(self.history.transaction_depth, 0); - let mut ranges = ranges.into_iter().peekable(); - if ranges.peek().is_none() { - return Default::default(); - } - - self.sync(cx); - - let buffer_id = buffer.read(cx).remote_id(); - let buffer_snapshot = buffer.read(cx).snapshot(); - - let mut buffers = self.buffers.borrow_mut(); - let buffer_state = buffers.entry(buffer_id).or_insert_with(|| BufferState { - last_version: buffer_snapshot.version().clone(), - last_non_text_state_update_count: buffer_snapshot.non_text_state_update_count(), - excerpts: Default::default(), - _subscriptions: [ - cx.observe(&buffer, |_, _, cx| cx.notify()), - cx.subscribe(&buffer, Self::on_buffer_event), - ], - buffer: buffer.clone(), - }); - - let mut snapshot = self.snapshot.borrow_mut(); - - let mut prev_locator = snapshot.excerpt_locator_for_id(prev_excerpt_id).clone(); - let mut new_excerpt_ids = mem::take(&mut snapshot.excerpt_ids); - let mut cursor = snapshot.excerpts.cursor::>(&()); - let mut new_excerpts = cursor.slice(&prev_locator, Bias::Right, &()); - prev_locator = cursor.start().unwrap_or(Locator::min_ref()).clone(); - - let edit_start = new_excerpts.summary().text.len; - new_excerpts.update_last( - |excerpt| { - excerpt.has_trailing_newline = true; - }, - &(), - ); - - let next_locator = if let Some(excerpt) = cursor.item() { - excerpt.locator.clone() - } else { - Locator::max() - }; - - let mut excerpts = Vec::new(); - while let Some((id, range)) = ranges.next() { - let locator = Locator::between(&prev_locator, &next_locator); - if let Err(ix) = buffer_state.excerpts.binary_search(&locator) { - buffer_state.excerpts.insert(ix, locator.clone()); - } - let range = ExcerptRange { - context: buffer_snapshot.anchor_before(&range.context.start) - ..buffer_snapshot.anchor_after(&range.context.end), - primary: range.primary.map(|primary| { - buffer_snapshot.anchor_before(&primary.start) - ..buffer_snapshot.anchor_after(&primary.end) - }), - }; - excerpts.push((id, range.clone())); - let excerpt = Excerpt::new( - id, - locator.clone(), - buffer_id, - buffer_snapshot.clone(), - range, - ranges.peek().is_some() || cursor.item().is_some(), - ); - new_excerpts.push(excerpt, &()); - prev_locator = locator.clone(); - - if let Some(last_mapping_entry) = new_excerpt_ids.last() { - assert!(id > last_mapping_entry.id, "excerpt ids must be increasing"); - } - new_excerpt_ids.push(ExcerptIdMapping { id, locator }, &()); - } - - let edit_end = new_excerpts.summary().text.len; - - let suffix = cursor.suffix(&()); - let changed_trailing_excerpt = suffix.is_empty(); - new_excerpts.append(suffix, &()); - drop(cursor); - snapshot.excerpts = new_excerpts; - snapshot.excerpt_ids = new_excerpt_ids; - if changed_trailing_excerpt { - snapshot.trailing_excerpt_update_count += 1; - } - - self.subscriptions.publish_mut([Edit { - old: edit_start..edit_start, - new: edit_start..edit_end, - }]); - cx.emit(Event::Edited { - singleton_buffer_edited: false, - }); - cx.emit(Event::ExcerptsAdded { - buffer, - predecessor: prev_excerpt_id, - excerpts, - }); - cx.notify(); + todo!() } - pub fn clear(&mut self, cx: &mut ModelContext) { - self.sync(cx); - let ids = self.excerpt_ids(); - self.buffers.borrow_mut().clear(); - let mut snapshot = self.snapshot.borrow_mut(); - let prev_len = snapshot.len(); - snapshot.excerpts = Default::default(); - snapshot.trailing_excerpt_update_count += 1; - snapshot.is_dirty = false; - snapshot.has_conflict = false; + // pub fn push_excerpts_with_context_lines( + // &mut self, + // buffer: Model, + // ranges: Vec>, + // context_line_count: u32, + // cx: &mut ModelContext, + // ) -> Vec> + // where + // O: text::ToPoint + text::ToOffset, + // { + // let buffer_id = buffer.read(cx).remote_id(); + // let buffer_snapshot = buffer.read(cx).snapshot(); + // let (excerpt_ranges, range_counts) = + // build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count); - self.subscriptions.publish_mut([Edit { - old: 0..prev_len, - new: 0..0, - }]); - cx.emit(Event::Edited { - singleton_buffer_edited: false, - }); - cx.emit(Event::ExcerptsRemoved { ids }); - cx.notify(); + // let excerpt_ids = self.push_excerpts(buffer, excerpt_ranges, cx); + + // let mut anchor_ranges = Vec::new(); + // let mut ranges = ranges.into_iter(); + // for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.into_iter()) { + // anchor_ranges.extend(ranges.by_ref().take(range_count).map(|range| { + // let start = Anchor { + // buffer_id: Some(buffer_id), + // excerpt_id, + // text_anchor: buffer_snapshot.anchor_after(range.start), + // }; + // let end = Anchor { + // buffer_id: Some(buffer_id), + // excerpt_id, + // text_anchor: buffer_snapshot.anchor_after(range.end), + // }; + // start..end + // })) + // } + // anchor_ranges + // } + + // pub fn insert_excerpts_after( + // &mut self, + // prev_excerpt_id: ExcerptId, + // buffer: Model, + // ranges: impl IntoIterator>, + // cx: &mut ModelContext, + // ) -> Vec + // where + // O: text::ToOffset, + // { + // let mut ids = Vec::new(); + // let mut next_excerpt_id = + // if let Some(last_entry) = self.snapshot.borrow().excerpt_ids.last() { + // last_entry.id.0 + 1 + // } else { + // 1 + // }; + // self.insert_excerpts_with_ids_after( + // prev_excerpt_id, + // buffer, + // ranges.into_iter().map(|range| { + // let id = ExcerptId(post_inc(&mut next_excerpt_id)); + // ids.push(id); + // (id, range) + // }), + // cx, + // ); + // ids + // } + + // pub fn insert_excerpts_with_ids_after( + // &mut self, + // prev_excerpt_id: ExcerptId, + // buffer: Model, + // ranges: impl IntoIterator)>, + // cx: &mut ModelContext, + // ) where + // O: text::ToOffset, + // { + // assert_eq!(self.history.transaction_depth, 0); + // let mut ranges = ranges.into_iter().peekable(); + // if ranges.peek().is_none() { + // return Default::default(); + // } + + // self.sync(cx); + + // let buffer_id = buffer.read(cx).remote_id(); + // let buffer_snapshot = buffer.read(cx).snapshot(); + + // let mut buffers = self.buffers.borrow_mut(); + // let buffer_state = buffers.entry(buffer_id).or_insert_with(|| BufferState { + // last_version: buffer_snapshot.version().clone(), + // last_non_text_state_update_count: buffer_snapshot.non_text_state_update_count(), + // excerpts: Default::default(), + // _subscriptions: [ + // cx.observe(&buffer, |_, _, cx| cx.notify()), + // cx.subscribe(&buffer, Self::on_buffer_event), + // ], + // buffer: buffer.clone(), + // }); + + // let mut snapshot = self.snapshot.borrow_mut(); + + // let mut prev_locator = snapshot.excerpt_locator_for_id(prev_excerpt_id).clone(); + // let mut new_excerpt_ids = mem::take(&mut snapshot.excerpt_ids); + // let mut cursor = snapshot.excerpts.cursor::>(&()); + // let mut new_excerpts = cursor.slice(&prev_locator, Bias::Right, &()); + // prev_locator = cursor.start().unwrap_or(Locator::min_ref()).clone(); + + // let edit_start = new_excerpts.summary().text.len; + // new_excerpts.update_last( + // |excerpt| { + // excerpt.has_trailing_newline = true; + // }, + // &(), + // ); + + // let next_locator = if let Some(excerpt) = cursor.item() { + // excerpt.locator.clone() + // } else { + // Locator::max() + // }; + + // let mut excerpts = Vec::new(); + // while let Some((id, range)) = ranges.next() { + // let locator = Locator::between(&prev_locator, &next_locator); + // if let Err(ix) = buffer_state.excerpts.binary_search(&locator) { + // buffer_state.excerpts.insert(ix, locator.clone()); + // } + // let range = ExcerptRange { + // context: buffer_snapshot.anchor_before(&range.context.start) + // ..buffer_snapshot.anchor_after(&range.context.end), + // primary: range.primary.map(|primary| { + // buffer_snapshot.anchor_before(&primary.start) + // ..buffer_snapshot.anchor_after(&primary.end) + // }), + // }; + // excerpts.push((id, range.clone())); + // let excerpt = Excerpt::new( + // id, + // locator.clone(), + // buffer_id, + // buffer_snapshot.clone(), + // range, + // ranges.peek().is_some() || cursor.item().is_some(), + // ); + // new_excerpts.push(excerpt, &()); + // prev_locator = locator.clone(); + + // if let Some(last_mapping_entry) = new_excerpt_ids.last() { + // assert!(id > last_mapping_entry.id, "excerpt ids must be increasing"); + // } + // new_excerpt_ids.push(ExcerptIdMapping { id, locator }, &()); + // } + + // let edit_end = new_excerpts.summary().text.len; + + // let suffix = cursor.suffix(&()); + // let changed_trailing_excerpt = suffix.is_empty(); + // new_excerpts.append(suffix, &()); + // drop(cursor); + // snapshot.excerpts = new_excerpts; + // snapshot.excerpt_ids = new_excerpt_ids; + // if changed_trailing_excerpt { + // snapshot.trailing_excerpt_update_count += 1; + // } + + // self.subscriptions.publish_mut([Edit { + // old: edit_start..edit_start, + // new: edit_start..edit_end, + // }]); + // cx.emit(Event::Edited { + // singleton_buffer_edited: false, + // }); + // cx.emit(Event::ExcerptsAdded { + // buffer, + // predecessor: prev_excerpt_id, + // excerpts, + // }); + // cx.notify(); + // } + + pub fn clear(&mut self, cx: &mut ModelContext) { + todo!() + // self.sync(cx); + // let ids = self.excerpt_ids(); + // self.buffers.borrow_mut().clear(); + // let mut snapshot = self.snapshot.borrow_mut(); + // let prev_len = snapshot.len(); + // snapshot.excerpts = Default::default(); + // snapshot.trailing_excerpt_update_count += 1; + // snapshot.is_dirty = false; + // snapshot.has_conflict = false; + + // self.subscriptions.publish_mut([Edit { + // old: 0..prev_len, + // new: 0..0, + // }]); + // cx.emit(Event::Edited { + // singleton_buffer_edited: false, + // }); + // cx.emit(Event::ExcerptsRemoved { ids }); + // cx.notify(); } pub fn excerpts_for_buffer( &self, buffer: &Model, cx: &AppContext, - ) -> Vec<(ExcerptId, ExcerptRange)> { - let mut excerpts = Vec::new(); - let snapshot = self.read(cx); - let buffers = self.buffers.borrow(); - let mut cursor = snapshot.excerpts.cursor::>(&()); - for locator in buffers - .get(&buffer.read(cx).remote_id()) - .map(|state| &state.excerpts) - .into_iter() - .flatten() - { - cursor.seek_forward(&Some(locator), Bias::Left, &()); - if let Some(excerpt) = cursor.item() { - if excerpt.locator == *locator { - excerpts.push((excerpt.id, excerpt.range.clone())); - } - } - } + ) -> Vec> { + todo!() + // let mut excerpts = Vec::new(); + // let snapshot = self.read(cx); + // let buffers = self.buffers.borrow(); + // let mut cursor = snapshot.excerpts.cursor::>(&()); + // for locator in buffers + // .get(&buffer.read(cx).remote_id()) + // .map(|state| &state.excerpts) + // .into_iter() + // .flatten() + // { + // cursor.seek_forward(&Some(locator), Bias::Left, &()); + // if let Some(excerpt) = cursor.item() { + // if excerpt.locator == *locator { + // excerpts.push((excerpt.id, excerpt.range.clone())); + // } + // } + // } - excerpts + // excerpts } pub fn excerpt_buffer_ids(&self) -> Vec { @@ -1436,16 +1393,7 @@ impl MultiBuffer { .borrow() .excerpts .iter() - .map(|entry| entry.buffer_id) - .collect() - } - - pub fn excerpt_ids(&self) -> Vec { - self.snapshot - .borrow() - .excerpts - .iter() - .map(|entry| entry.id) + .map(|entry| entry.range.context.start.buffer_id()) .collect() } @@ -1453,27 +1401,28 @@ impl MultiBuffer { &self, position: impl ToOffset, cx: &AppContext, - ) -> Option<(ExcerptId, Model, Range)> { - let snapshot = self.read(cx); - let position = position.to_offset(&snapshot); + ) -> Option<(Model, Range)> { + todo!() + // let snapshot = self.read(cx); + // let position = position.to_offset(&snapshot); - let mut cursor = snapshot.excerpts.cursor::(&()); - cursor.seek(&position, Bias::Right, &()); - cursor - .item() - .or_else(|| snapshot.excerpts.last()) - .map(|excerpt| { - ( - excerpt.id, - self.buffers - .borrow() - .get(&excerpt.buffer_id) - .unwrap() - .buffer - .clone(), - excerpt.range.context.clone(), - ) - }) + // let mut cursor = snapshot.excerpts.cursor::(&()); + // cursor.seek(&position, Bias::Right, &()); + // cursor + // .item() + // .or_else(|| snapshot.excerpts.last()) + // .map(|excerpt| { + // ( + // excerpt.id, + // self.buffers + // .borrow() + // .get(&excerpt.buffer_id) + // .unwrap() + // .buffer + // .clone(), + // excerpt.range.context.clone(), + // ) + // }) } // If point is at the end of the buffer, the last excerpt is returned @@ -1481,22 +1430,23 @@ impl MultiBuffer { &self, point: T, cx: &AppContext, - ) -> Option<(Model, usize, ExcerptId)> { - let snapshot = self.read(cx); - let offset = point.to_offset(&snapshot); - let mut cursor = snapshot.excerpts.cursor::(&()); - cursor.seek(&offset, Bias::Right, &()); - if cursor.item().is_none() { - cursor.prev(&()); - } + ) -> Option<(Model, usize)> { + todo!() + // let snapshot = self.read(cx); + // let offset = point.to_offset(&snapshot); + // let mut cursor = snapshot.excerpts.cursor::(&()); + // cursor.seek(&offset, Bias::Right, &()); + // if cursor.item().is_none() { + // cursor.prev(&()); + // } - cursor.item().map(|excerpt| { - let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer); - let buffer_point = excerpt_start + offset - *cursor.start(); - let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone(); + // cursor.item().map(|excerpt| { + // let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer); + // let buffer_point = excerpt_start + offset - *cursor.start(); + // let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone(); - (buffer, buffer_point, excerpt.id) - }) + // (buffer, buffer_point, excerpt.id) + // }) } // If point is at the end of the buffer, the last excerpt is returned @@ -1504,179 +1454,182 @@ impl MultiBuffer { &self, point: T, cx: &AppContext, - ) -> Option<(Model, Point, ExcerptId)> { - let snapshot = self.read(cx); - let point = point.to_point(&snapshot); - let mut cursor = snapshot.excerpts.cursor::(&()); - cursor.seek(&point, Bias::Right, &()); - if cursor.item().is_none() { - cursor.prev(&()); - } + ) -> Option<(Model, Point)> { + todo!() + // let snapshot = self.read(cx); + // let point = point.to_point(&snapshot); + // let mut cursor = snapshot.excerpts.cursor::(&()); + // cursor.seek(&point, Bias::Right, &()); + // if cursor.item().is_none() { + // cursor.prev(&()); + // } - cursor.item().map(|excerpt| { - let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer); - let buffer_point = excerpt_start + point - *cursor.start(); - let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone(); + // cursor.item().map(|excerpt| { + // let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer); + // let buffer_point = excerpt_start + point - *cursor.start(); + // let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone(); - (buffer, buffer_point, excerpt.id) - }) + // (buffer, buffer_point, excerpt.id) + // }) } pub fn range_to_buffer_ranges( &self, range: Range, cx: &AppContext, - ) -> Vec<(Model, Range, ExcerptId)> { - let snapshot = self.read(cx); - let start = range.start.to_offset(&snapshot); - let end = range.end.to_offset(&snapshot); + ) -> Vec<(Model, Range)> { + todo!() + // let snapshot = self.read(cx); + // let start = range.start.to_offset(&snapshot); + // let end = range.end.to_offset(&snapshot); - let mut result = Vec::new(); - let mut cursor = snapshot.excerpts.cursor::(&()); - cursor.seek(&start, Bias::Right, &()); - if cursor.item().is_none() { - cursor.prev(&()); - } + // let mut result = Vec::new(); + // let mut cursor = snapshot.excerpts.cursor::(&()); + // cursor.seek(&start, Bias::Right, &()); + // if cursor.item().is_none() { + // cursor.prev(&()); + // } - while let Some(excerpt) = cursor.item() { - if *cursor.start() > end { - break; - } + // while let Some(excerpt) = cursor.item() { + // if *cursor.start() > end { + // break; + // } - let mut end_before_newline = cursor.end(&()); - if excerpt.has_trailing_newline { - end_before_newline -= 1; - } - let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer); - let start = excerpt_start + (cmp::max(start, *cursor.start()) - *cursor.start()); - let end = excerpt_start + (cmp::min(end, end_before_newline) - *cursor.start()); - let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone(); - result.push((buffer, start..end, excerpt.id)); - cursor.next(&()); - } + // let mut end_before_newline = cursor.end(&()); + // if excerpt.has_trailing_newline { + // end_before_newline -= 1; + // } + // let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer); + // let start = excerpt_start + (cmp::max(start, *cursor.start()) - *cursor.start()); + // let end = excerpt_start + (cmp::min(end, end_before_newline) - *cursor.start()); + // let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone(); + // result.push((buffer, start..end, excerpt.id)); + // cursor.next(&()); + // } - result + // result } - pub fn remove_excerpts( - &mut self, - excerpt_ids: impl IntoIterator, - cx: &mut ModelContext, - ) { - self.sync(cx); - let ids = excerpt_ids.into_iter().collect::>(); - if ids.is_empty() { - return; - } + // pub fn remove_excerpts( + // &mut self, + // excerpt_ids: impl IntoIterator, + // cx: &mut ModelContext, + // ) { + // self.sync(cx); + // let ids = excerpt_ids.into_iter().collect::>(); + // if ids.is_empty() { + // return; + // } - let mut buffers = self.buffers.borrow_mut(); - let mut snapshot = self.snapshot.borrow_mut(); - let mut new_excerpts = SumTree::default(); - let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>(&()); - let mut edits = Vec::new(); - let mut excerpt_ids = ids.iter().copied().peekable(); + // let mut buffers = self.buffers.borrow_mut(); + // let mut snapshot = self.snapshot.borrow_mut(); + // let mut new_excerpts = SumTree::default(); + // let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>(&()); + // let mut edits = Vec::new(); + // let mut excerpt_ids = ids.iter().copied().peekable(); - while let Some(excerpt_id) = excerpt_ids.next() { - // Seek to the next excerpt to remove, preserving any preceding excerpts. - let locator = snapshot.excerpt_locator_for_id(excerpt_id); - new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &()); + // while let Some(excerpt_id) = excerpt_ids.next() { + // // Seek to the next excerpt to remove, preserving any preceding excerpts. + // let locator = snapshot.excerpt_locator_for_id(excerpt_id); + // new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &()); - if let Some(mut excerpt) = cursor.item() { - if excerpt.id != excerpt_id { - continue; - } - let mut old_start = cursor.start().1; + // if let Some(mut excerpt) = cursor.item() { + // if excerpt.id != excerpt_id { + // continue; + // } + // let mut old_start = cursor.start().1; - // Skip over the removed excerpt. - 'remove_excerpts: loop { - if let Some(buffer_state) = buffers.get_mut(&excerpt.buffer_id) { - buffer_state.excerpts.retain(|l| l != &excerpt.locator); - if buffer_state.excerpts.is_empty() { - buffers.remove(&excerpt.buffer_id); - } - } - cursor.next(&()); + // // Skip over the removed excerpt. + // 'remove_excerpts: loop { + // if let Some(buffer_state) = buffers.get_mut(&excerpt.buffer_id) { + // buffer_state.excerpts.retain(|l| l != &excerpt.locator); + // if buffer_state.excerpts.is_empty() { + // buffers.remove(&excerpt.buffer_id); + // } + // } + // cursor.next(&()); - // Skip over any subsequent excerpts that are also removed. - if let Some(&next_excerpt_id) = excerpt_ids.peek() { - let next_locator = snapshot.excerpt_locator_for_id(next_excerpt_id); - if let Some(next_excerpt) = cursor.item() { - if next_excerpt.locator == *next_locator { - excerpt_ids.next(); - excerpt = next_excerpt; - continue 'remove_excerpts; - } - } - } + // // Skip over any subsequent excerpts that are also removed. + // if let Some(&next_excerpt_id) = excerpt_ids.peek() { + // let next_locator = snapshot.excerpt_locator_for_id(next_excerpt_id); + // if let Some(next_excerpt) = cursor.item() { + // if next_excerpt.locator == *next_locator { + // excerpt_ids.next(); + // excerpt = next_excerpt; + // continue 'remove_excerpts; + // } + // } + // } - break; - } + // break; + // } - // When removing the last excerpt, remove the trailing newline from - // the previous excerpt. - if cursor.item().is_none() && old_start > 0 { - old_start -= 1; - new_excerpts.update_last(|e| e.has_trailing_newline = false, &()); - } + // // When removing the last excerpt, remove the trailing newline from + // // the previous excerpt. + // if cursor.item().is_none() && old_start > 0 { + // old_start -= 1; + // new_excerpts.update_last(|e| e.has_trailing_newline = false, &()); + // } - // Push an edit for the removal of this run of excerpts. - let old_end = cursor.start().1; - let new_start = new_excerpts.summary().text.len; - edits.push(Edit { - old: old_start..old_end, - new: new_start..new_start, - }); - } - } - let suffix = cursor.suffix(&()); - let changed_trailing_excerpt = suffix.is_empty(); - new_excerpts.append(suffix, &()); - drop(cursor); - snapshot.excerpts = new_excerpts; + // // Push an edit for the removal of this run of excerpts. + // let old_end = cursor.start().1; + // let new_start = new_excerpts.summary().text.len; + // edits.push(Edit { + // old: old_start..old_end, + // new: new_start..new_start, + // }); + // } + // } + // let suffix = cursor.suffix(&()); + // let changed_trailing_excerpt = suffix.is_empty(); + // new_excerpts.append(suffix, &()); + // drop(cursor); + // snapshot.excerpts = new_excerpts; - if changed_trailing_excerpt { - snapshot.trailing_excerpt_update_count += 1; - } + // if changed_trailing_excerpt { + // snapshot.trailing_excerpt_update_count += 1; + // } - self.subscriptions.publish_mut(edits); - cx.emit(Event::Edited { - singleton_buffer_edited: false, - }); - cx.emit(Event::ExcerptsRemoved { ids }); - cx.notify(); - } + // self.subscriptions.publish_mut(edits); + // cx.emit(Event::Edited { + // singleton_buffer_edited: false, + // }); + // cx.emit(Event::ExcerptsRemoved { ids }); + // cx.notify(); + // } pub fn wait_for_anchors<'a>( &self, anchors: impl 'a + Iterator, cx: &mut ModelContext, ) -> impl 'static + Future> { - let borrow = self.buffers.borrow(); - let mut error = None; - let mut futures = Vec::new(); - for anchor in anchors { - if let Some(buffer_id) = anchor.buffer_id { - if let Some(buffer) = borrow.get(&buffer_id) { - buffer.buffer.update(cx, |buffer, _| { - futures.push(buffer.wait_for_anchors([anchor.text_anchor])) - }); - } else { - error = Some(anyhow!( - "buffer {buffer_id} is not part of this multi-buffer" - )); - break; - } - } - } - async move { - if let Some(error) = error { - Err(error)?; - } - for future in futures { - future.await?; - } - Ok(()) - } + async move { todo!() } + // let borrow = self.buffers.borrow(); + // let mut error = None; + // let mut futures = Vec::new(); + // for anchor in anchors { + // if let Some(buffer_id) = anchor.buffer_id { + // if let Some(buffer) = borrow.get(&buffer_id) { + // buffer.buffer.update(cx, |buffer, _| { + // futures.push(buffer.wait_for_anchors([anchor.text_anchor])) + // }); + // } else { + // error = Some(anyhow!( + // "buffer {buffer_id} is not part of this multi-buffer" + // )); + // break; + // } + // } + // } + // async move { + // if let Some(error) = error { + // Err(error)?; + // } + // for future in futures { + // future.await?; + // } + // Ok(()) + // } } pub fn text_anchor_for_position( @@ -1684,15 +1637,16 @@ impl MultiBuffer { position: T, cx: &AppContext, ) -> Option<(Model, language::Anchor)> { - let snapshot = self.read(cx); - let anchor = snapshot.anchor_before(position); - let buffer = self - .buffers - .borrow() - .get(&anchor.buffer_id?)? - .buffer - .clone(); - Some((buffer, anchor.text_anchor)) + todo!() + // let snapshot = self.read(cx); + // let anchor = snapshot.anchor_before(position); + // let buffer = self + // .buffers + // .borrow() + // .get(&anchor.buffer_id?)? + // .buffer + // .clone(); + // Some((buffer, anchor.text_anchor)) } fn on_buffer_event( @@ -1744,8 +1698,9 @@ impl MultiBuffer { } pub fn language_at(&self, point: T, cx: &AppContext) -> Option> { - self.point_to_buffer_offset(point, cx) - .and_then(|(buffer, offset, _)| buffer.read(cx).language_at(offset)) + todo!() + // self.point_to_buffer_offset(point, cx) + // .and_then(|(buffer, offset, _)| buffer.read(cx).language_at(offset)) } pub fn settings_at<'a, T: ToOffset>( @@ -1753,14 +1708,15 @@ impl MultiBuffer { point: T, cx: &'a AppContext, ) -> &'a LanguageSettings { - let mut language = None; - let mut file = None; - if let Some((buffer, offset, _)) = self.point_to_buffer_offset(point, cx) { - let buffer = buffer.read(cx); - language = buffer.language_at(offset); - file = buffer.file(); - } - language_settings(language.as_ref(), file, cx) + todo!() + // let mut language = None; + // let mut file = None; + // if let Some((buffer, offset, _)) = self.point_to_buffer_offset(point, cx) { + // let buffer = buffer.read(cx); + // language = buffer.language_at(offset); + // file = buffer.file(); + // } + // language_settings(language.as_ref(), file, cx) } pub fn for_each_buffer(&self, mut f: impl FnMut(&Model)) { @@ -1811,260 +1767,195 @@ impl MultiBuffer { self.as_singleton().unwrap().read(cx).is_parsing() } - pub fn resize_excerpt( - &mut self, - id: ExcerptId, - range: Range, - cx: &mut ModelContext, - ) { - self.sync(cx); + // pub fn expand_excerpts( + // &mut self, + // ids: impl IntoIterator, + // line_count: u32, + // direction: ExpandExcerptDirection, + // cx: &mut ModelContext, + // ) { + // if line_count == 0 { + // return; + // } + // self.sync(cx); - let snapshot = self.snapshot(cx); - let locator = snapshot.excerpt_locator_for_id(id); - let mut new_excerpts = SumTree::default(); - let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>(&()); - let mut edits = Vec::>::new(); + // let ids = ids.into_iter().collect::>(); + // let snapshot = self.snapshot(cx); + // let locators = snapshot.excerpt_locators_for_ids(ids.iter().copied()); + // let mut new_excerpts = SumTree::default(); + // let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>(&()); + // let mut edits = Vec::>::new(); - let prefix = cursor.slice(&Some(locator), Bias::Left, &()); - new_excerpts.append(prefix, &()); + // for locator in &locators { + // let prefix = cursor.slice(&Some(locator), Bias::Left, &()); + // new_excerpts.append(prefix, &()); - let mut excerpt = cursor.item().unwrap().clone(); - let old_text_len = excerpt.text_summary.len; + // let mut excerpt = cursor.item().unwrap().clone(); + // let old_text_len = excerpt.text_summary.len; - excerpt.range.context.start = range.start; - excerpt.range.context.end = range.end; - excerpt.max_buffer_row = range.end.to_point(&excerpt.buffer).row; + // let up_line_count = if direction.should_expand_up() { + // line_count + // } else { + // 0 + // }; - excerpt.text_summary = excerpt - .buffer - .text_summary_for_range(excerpt.range.context.clone()); + // let start_row = excerpt + // .range + // .context + // .start + // .to_point(&excerpt.buffer) + // .row + // .saturating_sub(up_line_count); + // let start_point = Point::new(start_row, 0); + // excerpt.range.context.start = excerpt.buffer.anchor_before(start_point); - let new_start_offset = new_excerpts.summary().text.len; - let old_start_offset = cursor.start().1; - let edit = Edit { - old: old_start_offset..old_start_offset + old_text_len, - new: new_start_offset..new_start_offset + excerpt.text_summary.len, - }; + // let down_line_count = if direction.should_expand_down() { + // line_count + // } else { + // 0 + // }; - if let Some(last_edit) = edits.last_mut() { - if last_edit.old.end == edit.old.start { - last_edit.old.end = edit.old.end; - last_edit.new.end = edit.new.end; - } else { - edits.push(edit); - } - } else { - edits.push(edit); - } + // let mut end_point = excerpt.buffer.clip_point( + // excerpt.range.context.end.to_point(&excerpt.buffer) + // + Point::new(down_line_count, 0), + // Bias::Left, + // ); + // end_point.column = excerpt.buffer.line_len(end_point.row); + // excerpt.range.context.end = excerpt.buffer.anchor_after(end_point); + // excerpt.max_buffer_row = end_point.row; - new_excerpts.push(excerpt, &()); + // excerpt.text_summary = excerpt + // .buffer + // .text_summary_for_range(excerpt.range.context.clone()); - cursor.next(&()); + // let new_start_offset = new_excerpts.summary().text.len; + // let old_start_offset = cursor.start().1; + // let edit = Edit { + // old: old_start_offset..old_start_offset + old_text_len, + // new: new_start_offset..new_start_offset + excerpt.text_summary.len, + // }; - new_excerpts.append(cursor.suffix(&()), &()); + // if let Some(last_edit) = edits.last_mut() { + // if last_edit.old.end == edit.old.start { + // last_edit.old.end = edit.old.end; + // last_edit.new.end = edit.new.end; + // } else { + // edits.push(edit); + // } + // } else { + // edits.push(edit); + // } - drop(cursor); - self.snapshot.borrow_mut().excerpts = new_excerpts; + // new_excerpts.push(excerpt, &()); - self.subscriptions.publish_mut(edits); - cx.emit(Event::Edited { - singleton_buffer_edited: false, - }); - cx.emit(Event::ExcerptsExpanded { ids: vec![id] }); - cx.notify(); - } + // cursor.next(&()); + // } - pub fn expand_excerpts( - &mut self, - ids: impl IntoIterator, - line_count: u32, - direction: ExpandExcerptDirection, - cx: &mut ModelContext, - ) { - if line_count == 0 { - return; - } - self.sync(cx); + // new_excerpts.append(cursor.suffix(&()), &()); - let ids = ids.into_iter().collect::>(); - let snapshot = self.snapshot(cx); - let locators = snapshot.excerpt_locators_for_ids(ids.iter().copied()); - let mut new_excerpts = SumTree::default(); - let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>(&()); - let mut edits = Vec::>::new(); + // drop(cursor); + // self.snapshot.borrow_mut().excerpts = new_excerpts; - for locator in &locators { - let prefix = cursor.slice(&Some(locator), Bias::Left, &()); - new_excerpts.append(prefix, &()); - - let mut excerpt = cursor.item().unwrap().clone(); - let old_text_len = excerpt.text_summary.len; - - let up_line_count = if direction.should_expand_up() { - line_count - } else { - 0 - }; - - let start_row = excerpt - .range - .context - .start - .to_point(&excerpt.buffer) - .row - .saturating_sub(up_line_count); - let start_point = Point::new(start_row, 0); - excerpt.range.context.start = excerpt.buffer.anchor_before(start_point); - - let down_line_count = if direction.should_expand_down() { - line_count - } else { - 0 - }; - - let mut end_point = excerpt.buffer.clip_point( - excerpt.range.context.end.to_point(&excerpt.buffer) - + Point::new(down_line_count, 0), - Bias::Left, - ); - end_point.column = excerpt.buffer.line_len(end_point.row); - excerpt.range.context.end = excerpt.buffer.anchor_after(end_point); - excerpt.max_buffer_row = end_point.row; - - excerpt.text_summary = excerpt - .buffer - .text_summary_for_range(excerpt.range.context.clone()); - - let new_start_offset = new_excerpts.summary().text.len; - let old_start_offset = cursor.start().1; - let edit = Edit { - old: old_start_offset..old_start_offset + old_text_len, - new: new_start_offset..new_start_offset + excerpt.text_summary.len, - }; - - if let Some(last_edit) = edits.last_mut() { - if last_edit.old.end == edit.old.start { - last_edit.old.end = edit.old.end; - last_edit.new.end = edit.new.end; - } else { - edits.push(edit); - } - } else { - edits.push(edit); - } - - new_excerpts.push(excerpt, &()); - - cursor.next(&()); - } - - new_excerpts.append(cursor.suffix(&()), &()); - - drop(cursor); - self.snapshot.borrow_mut().excerpts = new_excerpts; - - self.subscriptions.publish_mut(edits); - cx.emit(Event::Edited { - singleton_buffer_edited: false, - }); - cx.emit(Event::ExcerptsExpanded { ids }); - cx.notify(); - } + // self.subscriptions.publish_mut(edits); + // cx.emit(Event::Edited { + // singleton_buffer_edited: false, + // }); + // cx.emit(Event::ExcerptsExpanded { ids }); + // cx.notify(); + // } fn sync(&self, cx: &AppContext) { - let mut snapshot = self.snapshot.borrow_mut(); - let mut excerpts_to_edit = Vec::new(); - let mut non_text_state_updated = false; - let mut is_dirty = false; - let mut has_conflict = false; - let mut edited = false; - let mut buffers = self.buffers.borrow_mut(); - for buffer_state in buffers.values_mut() { - let buffer = buffer_state.buffer.read(cx); - let version = buffer.version(); - let non_text_state_update_count = buffer.non_text_state_update_count(); + todo!() + // let mut snapshot = self.snapshot.borrow_mut(); + // let mut excerpts_to_edit = Vec::new(); + // let mut non_text_state_updated = false; + // let mut is_dirty = false; + // let mut has_conflict = false; + // let mut edited = false; + // let mut buffers = self.buffers.borrow_mut(); + // for buffer_state in buffers.values_mut() { + // let buffer = buffer_state.buffer.read(cx); + // let version = buffer.version(); + // let non_text_state_update_count = buffer.non_text_state_update_count(); - let buffer_edited = version.changed_since(&buffer_state.last_version); - let buffer_non_text_state_updated = - non_text_state_update_count > buffer_state.last_non_text_state_update_count; - if buffer_edited || buffer_non_text_state_updated { - buffer_state.last_version = version; - buffer_state.last_non_text_state_update_count = non_text_state_update_count; - excerpts_to_edit.extend( - buffer_state - .excerpts - .iter() - .map(|locator| (locator, buffer_state.buffer.clone(), buffer_edited)), - ); - } + // let buffer_edited = version.changed_since(&buffer_state.last_version); + // let buffer_non_text_state_updated = + // non_text_state_update_count > buffer_state.last_non_text_state_update_count; + // if buffer_edited || buffer_non_text_state_updated { + // buffer_state.last_version = version; + // buffer_state.last_non_text_state_update_count = non_text_state_update_count; + // excerpts_to_edit.extend( + // buffer_state + // .excerpts + // .iter() + // .map(|locator| (locator, buffer_state.buffer.clone(), buffer_edited)), + // ); + // } - edited |= buffer_edited; - non_text_state_updated |= buffer_non_text_state_updated; - is_dirty |= buffer.is_dirty(); - has_conflict |= buffer.has_conflict(); - } - if edited { - snapshot.edit_count += 1; - } - if non_text_state_updated { - snapshot.non_text_state_update_count += 1; - } - snapshot.is_dirty = is_dirty; - snapshot.has_conflict = has_conflict; + // edited |= buffer_edited; + // non_text_state_updated |= buffer_non_text_state_updated; + // is_dirty |= buffer.is_dirty(); + // has_conflict |= buffer.has_conflict(); + // } + // if edited { + // snapshot.edit_count += 1; + // } + // if non_text_state_updated { + // snapshot.non_text_state_update_count += 1; + // } + // snapshot.is_dirty = is_dirty; + // snapshot.has_conflict = has_conflict; - excerpts_to_edit.sort_unstable_by_key(|(locator, _, _)| *locator); + // excerpts_to_edit.sort_unstable_by_key(|(locator, _, _)| *locator); - let mut edits = Vec::new(); - let mut new_excerpts = SumTree::default(); - let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>(&()); + // let mut edits = Vec::new(); + // let mut new_excerpts = SumTree::default(); + // let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>(&()); - for (locator, buffer, buffer_edited) in excerpts_to_edit { - new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &()); - let old_excerpt = cursor.item().unwrap(); - let buffer = buffer.read(cx); - let buffer_id = buffer.remote_id(); + // for (locator, buffer, buffer_edited) in excerpts_to_edit { + // new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &()); + // let old_excerpt = cursor.item().unwrap(); + // let buffer = buffer.read(cx); + // let buffer_id = buffer.remote_id(); - let mut new_excerpt; - if buffer_edited { - edits.extend( - buffer - .edits_since_in_range::( - old_excerpt.buffer.version(), - old_excerpt.range.context.clone(), - ) - .map(|mut edit| { - let excerpt_old_start = cursor.start().1; - let excerpt_new_start = new_excerpts.summary().text.len; - edit.old.start += excerpt_old_start; - edit.old.end += excerpt_old_start; - edit.new.start += excerpt_new_start; - edit.new.end += excerpt_new_start; - edit - }), - ); + // let mut new_excerpt; + // if buffer_edited { + // edits.extend( + // buffer + // .edits_since_in_range::( + // old_excerpt.buffer.version(), + // old_excerpt.range.context.clone(), + // ) + // .map(|mut edit| { + // let excerpt_old_start = cursor.start().1; + // let excerpt_new_start = new_excerpts.summary().text.len; + // edit.old.start += excerpt_old_start; + // edit.old.end += excerpt_old_start; + // edit.new.start += excerpt_new_start; + // edit.new.end += excerpt_new_start; + // edit + // }), + // ); - new_excerpt = Excerpt::new( - old_excerpt.id, - locator.clone(), - buffer_id, - buffer.snapshot(), - old_excerpt.range.clone(), - old_excerpt.has_trailing_newline, - ); - } else { - new_excerpt = old_excerpt.clone(); - new_excerpt.buffer = buffer.snapshot(); - } + // new_excerpt = Excerpt::new( + // buffer.snapshot(), + // old_excerpt.range.clone(), + // old_excerpt.has_trailing_newline, + // ); + // } else { + // new_excerpt = old_excerpt.clone(); + // new_excerpt.buffer = buffer.snapshot(); + // } - new_excerpts.push(new_excerpt, &()); - cursor.next(&()); - } - new_excerpts.append(cursor.suffix(&()), &()); + // new_excerpts.push(new_excerpt, &()); + // cursor.next(&()); + // } + // new_excerpts.append(cursor.suffix(&()), &()); - drop(cursor); - snapshot.excerpts = new_excerpts; + // drop(cursor); + // snapshot.excerpts = new_excerpts; - self.subscriptions.publish(edits); + // self.subscriptions.publish(edits); } } @@ -2087,7 +1978,7 @@ impl MultiBuffer { primary: None, }); multi.update(cx, |multi, cx| { - multi.push_excerpts(buffer, excerpt_ranges, cx) + multi.insert_excerpts(buffer, excerpt_ranges, cx) }); } @@ -2150,100 +2041,101 @@ impl MultiBuffer { mutation_count: usize, cx: &mut ModelContext, ) { - use rand::prelude::*; - use std::env; - use util::RandomCharIter; + todo!() + // use rand::prelude::*; + // use std::env; + // use util::RandomCharIter; - let max_excerpts = env::var("MAX_EXCERPTS") - .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable")) - .unwrap_or(5); + // let max_excerpts = env::var("MAX_EXCERPTS") + // .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable")) + // .unwrap_or(5); - let mut buffers = Vec::new(); - for _ in 0..mutation_count { - if rng.gen_bool(0.05) { - log::info!("Clearing multi-buffer"); - self.clear(cx); - continue; - } else if rng.gen_bool(0.1) && !self.excerpt_ids().is_empty() { - let ids = self.excerpt_ids(); - let mut excerpts = HashSet::default(); - for _ in 0..rng.gen_range(0..ids.len()) { - excerpts.extend(ids.choose(rng).copied()); - } + // let mut buffers = Vec::new(); + // for _ in 0..mutation_count { + // if rng.gen_bool(0.05) { + // log::info!("Clearing multi-buffer"); + // self.clear(cx); + // continue; + // } else if rng.gen_bool(0.1) && !self.excerpt_ids().is_empty() { + // let ids = self.excerpt_ids(); + // let mut excerpts = HashSet::default(); + // for _ in 0..rng.gen_range(0..ids.len()) { + // excerpts.extend(ids.choose(rng).copied()); + // } - let line_count = rng.gen_range(0..5); + // let line_count = rng.gen_range(0..5); - log::info!("Expanding excerpts {excerpts:?} by {line_count} lines"); + // log::info!("Expanding excerpts {excerpts:?} by {line_count} lines"); - self.expand_excerpts( - excerpts.iter().cloned(), - line_count, - ExpandExcerptDirection::UpAndDown, - cx, - ); - continue; - } + // self.expand_excerpts( + // excerpts.iter().cloned(), + // line_count, + // ExpandExcerptDirection::UpAndDown, + // cx, + // ); + // continue; + // } - let excerpt_ids = self.excerpt_ids(); - if excerpt_ids.is_empty() || (rng.gen() && excerpt_ids.len() < max_excerpts) { - let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() { - let text = RandomCharIter::new(&mut *rng).take(10).collect::(); - buffers.push(cx.new_model(|cx| Buffer::local(text, cx))); - let buffer = buffers.last().unwrap().read(cx); - log::info!( - "Creating new buffer {} with text: {:?}", - buffer.remote_id(), - buffer.text() - ); - buffers.last().unwrap().clone() - } else { - self.buffers - .borrow() - .values() - .choose(rng) - .unwrap() - .buffer - .clone() - }; + // let excerpt_ids = self.excerpt_ids(); + // if excerpt_ids.is_empty() || (rng.gen() && excerpt_ids.len() < max_excerpts) { + // let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() { + // let text = RandomCharIter::new(&mut *rng).take(10).collect::(); + // buffers.push(cx.new_model(|cx| Buffer::local(text, cx))); + // let buffer = buffers.last().unwrap().read(cx); + // log::info!( + // "Creating new buffer {} with text: {:?}", + // buffer.remote_id(), + // buffer.text() + // ); + // buffers.last().unwrap().clone() + // } else { + // self.buffers + // .borrow() + // .values() + // .choose(rng) + // .unwrap() + // .buffer + // .clone() + // }; - let buffer = buffer_handle.read(cx); - let buffer_text = buffer.text(); - let ranges = (0..rng.gen_range(0..5)) - .map(|_| { - let end_ix = - buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right); - let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left); - ExcerptRange { - context: start_ix..end_ix, - primary: None, - } - }) - .collect::>(); - log::info!( - "Inserting excerpts from buffer {} and ranges {:?}: {:?}", - buffer_handle.read(cx).remote_id(), - ranges.iter().map(|r| &r.context).collect::>(), - ranges - .iter() - .map(|r| &buffer_text[r.context.clone()]) - .collect::>() - ); + // let buffer = buffer_handle.read(cx); + // let buffer_text = buffer.text(); + // let ranges = (0..rng.gen_range(0..5)) + // .map(|_| { + // let end_ix = + // buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right); + // let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left); + // ExcerptRange { + // context: start_ix..end_ix, + // primary: None, + // } + // }) + // .collect::>(); + // log::info!( + // "Inserting excerpts from buffer {} and ranges {:?}: {:?}", + // buffer_handle.read(cx).remote_id(), + // ranges.iter().map(|r| &r.context).collect::>(), + // ranges + // .iter() + // .map(|r| &buffer_text[r.context.clone()]) + // .collect::>() + // ); - let excerpt_id = self.push_excerpts(buffer_handle.clone(), ranges, cx); - log::info!("Inserted with ids: {:?}", excerpt_id); - } else { - let remove_count = rng.gen_range(1..=excerpt_ids.len()); - let mut excerpts_to_remove = excerpt_ids - .choose_multiple(rng, remove_count) - .cloned() - .collect::>(); - let snapshot = self.snapshot.borrow(); - excerpts_to_remove.sort_unstable_by(|a, b| a.cmp(b, &snapshot)); - drop(snapshot); - log::info!("Removing excerpts {:?}", excerpts_to_remove); - self.remove_excerpts(excerpts_to_remove, cx); - } - } + // let excerpt_id = self.push_excerpts(buffer_handle.clone(), ranges, cx); + // log::info!("Inserted with ids: {:?}", excerpt_id); + // } else { + // let remove_count = rng.gen_range(1..=excerpt_ids.len()); + // let mut excerpts_to_remove = excerpt_ids + // .choose_multiple(rng, remove_count) + // .cloned() + // .collect::>(); + // let snapshot = self.snapshot.borrow(); + // excerpts_to_remove.sort_unstable_by(|a, b| a.cmp(b, &snapshot)); + // drop(snapshot); + // log::info!("Removing excerpts {:?}", excerpts_to_remove); + // self.remove_excerpts(excerpts_to_remove, cx); + // } + // } } pub fn randomly_mutate( @@ -2281,29 +2173,30 @@ impl MultiBuffer { } fn check_invariants(&self, cx: &mut ModelContext) { - let snapshot = self.read(cx); - let excerpts = snapshot.excerpts.items(&()); - let excerpt_ids = snapshot.excerpt_ids.items(&()); + todo!() + // let snapshot = self.read(cx); + // let excerpts = snapshot.excerpts.items(&()); + // let excerpt_ids = snapshot.excerpt_ids.items(&()); - for (ix, excerpt) in excerpts.iter().enumerate() { - if ix == 0 { - if excerpt.locator <= Locator::min() { - panic!("invalid first excerpt locator {:?}", excerpt.locator); - } - } else if excerpt.locator <= excerpts[ix - 1].locator { - panic!("excerpts are out-of-order: {:?}", excerpts); - } - } + // for (ix, excerpt) in excerpts.iter().enumerate() { + // if ix == 0 { + // if excerpt.locator <= Locator::min() { + // panic!("invalid first excerpt locator {:?}", excerpt.locator); + // } + // } else if excerpt.locator <= excerpts[ix - 1].locator { + // panic!("excerpts are out-of-order: {:?}", excerpts); + // } + // } - for (ix, entry) in excerpt_ids.iter().enumerate() { - if ix == 0 { - if entry.id.cmp(&ExcerptId::min(), &snapshot).is_le() { - panic!("invalid first excerpt id {:?}", entry.id); - } - } else if entry.id <= excerpt_ids[ix - 1].id { - panic!("excerpt ids are out-of-order: {:?}", excerpt_ids); - } - } + // for (ix, entry) in excerpt_ids.iter().enumerate() { + // if ix == 0 { + // if entry.id.cmp(&ExcerptId::min(), &snapshot).is_le() { + // panic!("invalid first excerpt id {:?}", entry.id); + // } + // } else if entry.id <= excerpt_ids[ix - 1].id { + // panic!("excerpt ids are out-of-order: {:?}", excerpt_ids); + // } + // } } } @@ -2417,12 +2310,9 @@ impl MultiBufferSnapshot { (start..end, word_kind) } - pub fn as_singleton(&self) -> Option<(&ExcerptId, BufferId, &BufferSnapshot)> { + pub fn as_singleton(&self) -> Option<&BufferSnapshot> { if self.singleton { - self.excerpts - .iter() - .next() - .map(|e| (&e.id, e.buffer_id, &e.buffer)) + self.excerpts.iter().next().map(|e| &e.buffer) } else { None } @@ -2441,7 +2331,7 @@ impl MultiBufferSnapshot { } pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize { - if let Some((_, _, buffer)) = self.as_singleton() { + if let Some(buffer) = self.as_singleton() { return buffer.clip_offset(offset, bias); } @@ -2460,7 +2350,7 @@ impl MultiBufferSnapshot { } pub fn clip_point(&self, point: Point, bias: Bias) -> Point { - if let Some((_, _, buffer)) = self.as_singleton() { + if let Some(buffer) = self.as_singleton() { return buffer.clip_point(point, bias); } @@ -2479,7 +2369,7 @@ impl MultiBufferSnapshot { } pub fn clip_offset_utf16(&self, offset: OffsetUtf16, bias: Bias) -> OffsetUtf16 { - if let Some((_, _, buffer)) = self.as_singleton() { + if let Some(buffer) = self.as_singleton() { return buffer.clip_offset_utf16(offset, bias); } @@ -2498,7 +2388,7 @@ impl MultiBufferSnapshot { } pub fn clip_point_utf16(&self, point: Unclipped, bias: Bias) -> PointUtf16 { - if let Some((_, _, buffer)) = self.as_singleton() { + if let Some(buffer) = self.as_singleton() { return buffer.clip_point_utf16(point, bias); } @@ -2589,7 +2479,7 @@ impl MultiBufferSnapshot { } pub fn offset_to_point(&self, offset: usize) -> Point { - if let Some((_, _, buffer)) = self.as_singleton() { + if let Some(buffer) = self.as_singleton() { return buffer.offset_to_point(offset); } @@ -2610,7 +2500,7 @@ impl MultiBufferSnapshot { } pub fn offset_to_point_utf16(&self, offset: usize) -> PointUtf16 { - if let Some((_, _, buffer)) = self.as_singleton() { + if let Some(buffer) = self.as_singleton() { return buffer.offset_to_point_utf16(offset); } @@ -2631,7 +2521,7 @@ impl MultiBufferSnapshot { } pub fn point_to_point_utf16(&self, point: Point) -> PointUtf16 { - if let Some((_, _, buffer)) = self.as_singleton() { + if let Some(buffer) = self.as_singleton() { return buffer.point_to_point_utf16(point); } @@ -2653,7 +2543,7 @@ impl MultiBufferSnapshot { } pub fn point_to_offset(&self, point: Point) -> usize { - if let Some((_, _, buffer)) = self.as_singleton() { + if let Some(buffer) = self.as_singleton() { return buffer.point_to_offset(point); } @@ -2674,7 +2564,7 @@ impl MultiBufferSnapshot { } pub fn offset_utf16_to_offset(&self, offset_utf16: OffsetUtf16) -> usize { - if let Some((_, _, buffer)) = self.as_singleton() { + if let Some(buffer) = self.as_singleton() { return buffer.offset_utf16_to_offset(offset_utf16); } @@ -2696,7 +2586,7 @@ impl MultiBufferSnapshot { } pub fn offset_to_offset_utf16(&self, offset: usize) -> OffsetUtf16 { - if let Some((_, _, buffer)) = self.as_singleton() { + if let Some(buffer) = self.as_singleton() { return buffer.offset_to_offset_utf16(offset); } @@ -2720,7 +2610,7 @@ impl MultiBufferSnapshot { } pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize { - if let Some((_, _, buffer)) = self.as_singleton() { + if let Some(buffer) = self.as_singleton() { return buffer.point_utf16_to_offset(point); } @@ -2944,30 +2834,31 @@ impl MultiBufferSnapshot { where D: TextDimension + Ord + Sub, { - let mut cursor = self.excerpts.cursor::(&()); - let locator = self.excerpt_locator_for_id(anchor.excerpt_id); + todo!() + // let mut cursor = self.excerpts.cursor::(&()); + // let locator = self.excerpt_locator_for_id(anchor.excerpt_id); - cursor.seek(locator, Bias::Left, &()); - if cursor.item().is_none() { - cursor.next(&()); - } + // cursor.seek(locator, Bias::Left, &()); + // if cursor.item().is_none() { + // cursor.next(&()); + // } - let mut position = D::from_text_summary(&cursor.start().text); - if let Some(excerpt) = cursor.item() { - if excerpt.id == anchor.excerpt_id { - let excerpt_buffer_start = - excerpt.range.context.start.summary::(&excerpt.buffer); - let excerpt_buffer_end = excerpt.range.context.end.summary::(&excerpt.buffer); - let buffer_position = cmp::min( - excerpt_buffer_end, - anchor.text_anchor.summary::(&excerpt.buffer), - ); - if buffer_position > excerpt_buffer_start { - position.add_assign(&(buffer_position - excerpt_buffer_start)); - } - } - } - position + // let mut position = D::from_text_summary(&cursor.start().text); + // if let Some(excerpt) = cursor.item() { + // if excerpt.id == anchor.excerpt_id { + // let excerpt_buffer_start = + // excerpt.range.context.start.summary::(&excerpt.buffer); + // let excerpt_buffer_end = excerpt.range.context.end.summary::(&excerpt.buffer); + // let buffer_position = cmp::min( + // excerpt_buffer_end, + // anchor.text_anchor.summary::(&excerpt.buffer), + // ); + // if buffer_position > excerpt_buffer_start { + // position.add_assign(&(buffer_position - excerpt_buffer_start)); + // } + // } + // } + // position } pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec @@ -2975,61 +2866,62 @@ impl MultiBufferSnapshot { D: TextDimension + Ord + Sub, I: 'a + IntoIterator, { - if let Some((_, _, buffer)) = self.as_singleton() { - return buffer - .summaries_for_anchors(anchors.into_iter().map(|a| &a.text_anchor)) - .collect(); - } + todo!() + // if let Some((_, _, buffer)) = self.as_singleton() { + // return buffer + // .summaries_for_anchors(anchors.into_iter().map(|a| &a.text_anchor)) + // .collect(); + // } - let mut anchors = anchors.into_iter().peekable(); - let mut cursor = self.excerpts.cursor::(&()); - let mut summaries = Vec::new(); - while let Some(anchor) = anchors.peek() { - let excerpt_id = anchor.excerpt_id; - let excerpt_anchors = iter::from_fn(|| { - let anchor = anchors.peek()?; - if anchor.excerpt_id == excerpt_id { - Some(&anchors.next().unwrap().text_anchor) - } else { - None - } - }); + // let mut anchors = anchors.into_iter().peekable(); + // let mut cursor = self.excerpts.cursor::(&()); + // let mut summaries = Vec::new(); + // while let Some(anchor) = anchors.peek() { + // let excerpt_id = anchor.excerpt_id; + // let excerpt_anchors = iter::from_fn(|| { + // let anchor = anchors.peek()?; + // if anchor.excerpt_id == excerpt_id { + // Some(&anchors.next().unwrap().text_anchor) + // } else { + // None + // } + // }); - let locator = self.excerpt_locator_for_id(excerpt_id); - cursor.seek_forward(locator, Bias::Left, &()); - if cursor.item().is_none() { - cursor.next(&()); - } + // let locator = self.excerpt_locator_for_id(excerpt_id); + // cursor.seek_forward(locator, Bias::Left, &()); + // if cursor.item().is_none() { + // cursor.next(&()); + // } - let position = D::from_text_summary(&cursor.start().text); - if let Some(excerpt) = cursor.item() { - if excerpt.id == excerpt_id { - let excerpt_buffer_start = - excerpt.range.context.start.summary::(&excerpt.buffer); - let excerpt_buffer_end = - excerpt.range.context.end.summary::(&excerpt.buffer); - summaries.extend( - excerpt - .buffer - .summaries_for_anchors::(excerpt_anchors) - .map(move |summary| { - let summary = cmp::min(excerpt_buffer_end.clone(), summary); - let mut position = position.clone(); - let excerpt_buffer_start = excerpt_buffer_start.clone(); - if summary > excerpt_buffer_start { - position.add_assign(&(summary - excerpt_buffer_start)); - } - position - }), - ); - continue; - } - } + // let position = D::from_text_summary(&cursor.start().text); + // if let Some(excerpt) = cursor.item() { + // if excerpt.id == excerpt_id { + // let excerpt_buffer_start = + // excerpt.range.context.start.summary::(&excerpt.buffer); + // let excerpt_buffer_end = + // excerpt.range.context.end.summary::(&excerpt.buffer); + // summaries.extend( + // excerpt + // .buffer + // .summaries_for_anchors::(excerpt_anchors) + // .map(move |summary| { + // let summary = cmp::min(excerpt_buffer_end.clone(), summary); + // let mut position = position.clone(); + // let excerpt_buffer_start = excerpt_buffer_start.clone(); + // if summary > excerpt_buffer_start { + // position.add_assign(&(summary - excerpt_buffer_start)); + // } + // position + // }), + // ); + // continue; + // } + // } - summaries.extend(excerpt_anchors.map(|_| position.clone())); - } + // summaries.extend(excerpt_anchors.map(|_| position.clone())); + // } - summaries + // summaries } pub fn refresh_anchors<'a, I>(&'a self, _anchors: I) -> Vec<(usize, Anchor, bool)> @@ -3144,86 +3036,60 @@ impl MultiBufferSnapshot { } pub fn anchor_at(&self, position: T, mut bias: Bias) -> Anchor { - let offset = position.to_offset(self); - if let Some((excerpt_id, buffer_id, buffer)) = self.as_singleton() { - return Anchor { - buffer_id: Some(buffer_id), - excerpt_id: *excerpt_id, - text_anchor: buffer.anchor_at(offset, bias), - }; - } + todo!() + // let offset = position.to_offset(self); + // if let Some((excerpt_id, buffer_id, buffer)) = self.as_singleton() { + // return Anchor { + // buffer_id: Some(buffer_id), + // excerpt_id: *excerpt_id, + // text_anchor: buffer.anchor_at(offset, bias), + // }; + // } - let mut cursor = self.excerpts.cursor::<(usize, Option)>(&()); - cursor.seek(&offset, Bias::Right, &()); - if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left { - cursor.prev(&()); - } - if let Some(excerpt) = cursor.item() { - let mut overshoot = offset.saturating_sub(cursor.start().0); - if excerpt.has_trailing_newline && offset == cursor.end(&()).0 { - overshoot -= 1; - bias = Bias::Right; - } + // let mut cursor = self.excerpts.cursor::<(usize, Option)>(&()); + // cursor.seek(&offset, Bias::Right, &()); + // if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left { + // cursor.prev(&()); + // } + // if let Some(excerpt) = cursor.item() { + // let mut overshoot = offset.saturating_sub(cursor.start().0); + // if excerpt.has_trailing_newline && offset == cursor.end(&()).0 { + // overshoot -= 1; + // bias = Bias::Right; + // } - let buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer); - let text_anchor = - excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias)); - Anchor { - buffer_id: Some(excerpt.buffer_id), - excerpt_id: excerpt.id, - text_anchor, - } - } else if offset == 0 && bias == Bias::Left { - Anchor::min() - } else { - Anchor::max() - } - } - - /// Returns an anchor for the given excerpt and text anchor, - /// returns None if the excerpt_id is no longer valid. - pub fn anchor_in_excerpt( - &self, - excerpt_id: ExcerptId, - text_anchor: text::Anchor, - ) -> Option { - let locator = self.excerpt_locator_for_id(excerpt_id); - let mut cursor = self.excerpts.cursor::>(&()); - cursor.seek(locator, Bias::Left, &()); - if let Some(excerpt) = cursor.item() { - if excerpt.id == excerpt_id { - let text_anchor = excerpt.clip_anchor(text_anchor); - drop(cursor); - return Some(Anchor { - buffer_id: Some(excerpt.buffer_id), - excerpt_id, - text_anchor, - }); - } - } - None - } - - pub fn context_range_for_excerpt(&self, excerpt_id: ExcerptId) -> Option> { - Some(self.excerpt(excerpt_id)?.range.context.clone()) + // let buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer); + // let text_anchor = + // excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias)); + // Anchor { + // buffer_id: Some(excerpt.buffer_id), + // excerpt_id: excerpt.id, + // text_anchor, + // } + // } else if offset == 0 && bias == Bias::Left { + // Anchor::min() + // } else { + // Anchor::max() + // } } pub fn can_resolve(&self, anchor: &Anchor) -> bool { - if anchor.excerpt_id == ExcerptId::min() || anchor.excerpt_id == ExcerptId::max() { - true - } else if let Some(excerpt) = self.excerpt(anchor.excerpt_id) { - excerpt.buffer.can_resolve(&anchor.text_anchor) - } else { - false - } + todo!() + // if anchor.excerpt_id == ExcerptId::min() || anchor.excerpt_id == ExcerptId::max() { + // true + // } else if let Some(excerpt) = self.excerpt(anchor.excerpt_id) { + // excerpt.buffer.can_resolve(&anchor.text_anchor) + // } else { + // false + // } } - pub fn excerpts( - &self, - ) -> impl Iterator)> { - self.excerpts - .iter() - .map(|excerpt| (excerpt.id, &excerpt.buffer, excerpt.range.clone())) + pub fn excerpts(&self) -> impl Iterator)> { + todo!(); + std::iter::empty() + // self.excerpts + // .iter() + // .map(|excerpt| (excerpt.id, &excerpt.buffer, excerpt.range.clone())) } fn excerpts_for_range( @@ -3254,72 +3120,75 @@ impl MultiBufferSnapshot { R: RangeBounds, T: ToOffset, { - let start_offset; - let start = match range.start_bound() { - Bound::Included(start) => { - start_offset = start.to_offset(self); - Bound::Included(start_offset) - } - Bound::Excluded(start) => { - start_offset = start.to_offset(self); - Bound::Excluded(start_offset) - } - Bound::Unbounded => { - start_offset = 0; - Bound::Unbounded - } - }; - let end = match range.end_bound() { - Bound::Included(end) => Bound::Included(end.to_offset(self)), - Bound::Excluded(end) => Bound::Excluded(end.to_offset(self)), - Bound::Unbounded => Bound::Unbounded, - }; - let bounds = (start, end); + todo!(); + std::iter::empty() - let mut cursor = self.excerpts.cursor::<(usize, Point)>(&()); - cursor.seek(&start_offset, Bias::Right, &()); - if cursor.item().is_none() { - cursor.prev(&()); - } - if !bounds.contains(&cursor.start().0) { - cursor.next(&()); - } + // let start_offset; + // let start = match range.start_bound() { + // Bound::Included(start) => { + // start_offset = start.to_offset(self); + // Bound::Included(start_offset) + // } + // Bound::Excluded(start) => { + // start_offset = start.to_offset(self); + // Bound::Excluded(start_offset) + // } + // Bound::Unbounded => { + // start_offset = 0; + // Bound::Unbounded + // } + // }; + // let end = match range.end_bound() { + // Bound::Included(end) => Bound::Included(end.to_offset(self)), + // Bound::Excluded(end) => Bound::Excluded(end.to_offset(self)), + // Bound::Unbounded => Bound::Unbounded, + // }; + // let bounds = (start, end); - let mut visited_end = false; - std::iter::from_fn(move || { - if self.singleton { - None - } else if bounds.contains(&cursor.start().0) { - let next = cursor.item().map(|excerpt| ExcerptInfo { - id: excerpt.id, - buffer: excerpt.buffer.clone(), - buffer_id: excerpt.buffer_id, - range: excerpt.range.clone(), - }); + // let mut cursor = self.excerpts.cursor::<(usize, Point)>(&()); + // cursor.seek(&start_offset, Bias::Right, &()); + // if cursor.item().is_none() { + // cursor.prev(&()); + // } + // if !bounds.contains(&cursor.start().0) { + // cursor.next(&()); + // } - if next.is_none() { - if visited_end { - return None; - } else { - visited_end = true; - } - } + // let mut visited_end = false; + // std::iter::from_fn(move || { + // if self.singleton { + // None + // } else if bounds.contains(&cursor.start().0) { + // let next = cursor.item().map(|excerpt| ExcerptInfo { + // id: excerpt.id, + // buffer: excerpt.buffer.clone(), + // buffer_id: excerpt.buffer_id, + // range: excerpt.range.clone(), + // }); - let prev = cursor.prev_item().map(|prev_excerpt| ExcerptInfo { - id: prev_excerpt.id, - buffer: prev_excerpt.buffer.clone(), - buffer_id: prev_excerpt.buffer_id, - range: prev_excerpt.range.clone(), - }); - let row = MultiBufferRow(cursor.start().1.row); + // if next.is_none() { + // if visited_end { + // return None; + // } else { + // visited_end = true; + // } + // } - cursor.next(&()); + // let prev = cursor.prev_item().map(|prev_excerpt| ExcerptInfo { + // id: prev_excerpt.id, + // buffer: prev_excerpt.buffer.clone(), + // buffer_id: prev_excerpt.buffer_id, + // range: prev_excerpt.range.clone(), + // }); + // let row = MultiBufferRow(cursor.start().1.row); - Some(ExcerptBoundary { row, prev, next }) - } else { - None - } - }) + // cursor.next(&()); + + // Some(ExcerptBoundary { row, prev, next }) + // } else { + // None + // } + // }) } pub fn edit_count(&self) -> usize { @@ -3488,53 +3357,54 @@ impl MultiBufferSnapshot { ignore_disabled_for_language: bool, cx: &AppContext, ) -> Vec { - // Fast path for singleton buffers, we can skip the conversion between offsets. - if let Some((_, _, snapshot)) = self.as_singleton() { - return snapshot - .indent_guides_in_range( - range.start.text_anchor..range.end.text_anchor, - ignore_disabled_for_language, - cx, - ) - .into_iter() - .map(|guide| MultiBufferIndentGuide { - multibuffer_row_range: MultiBufferRow(guide.start_row) - ..MultiBufferRow(guide.end_row), - buffer: guide, - }) - .collect(); - } + todo!() + // // Fast path for singleton buffers, we can skip the conversion between offsets. + // if let Some((_, _, snapshot)) = self.as_singleton() { + // return snapshot + // .indent_guides_in_range( + // range.start.text_anchor..range.end.text_anchor, + // ignore_disabled_for_language, + // cx, + // ) + // .into_iter() + // .map(|guide| MultiBufferIndentGuide { + // multibuffer_row_range: MultiBufferRow(guide.start_row) + // ..MultiBufferRow(guide.end_row), + // buffer: guide, + // }) + // .collect(); + // } - let range = range.start.to_offset(self)..range.end.to_offset(self); + // let range = range.start.to_offset(self)..range.end.to_offset(self); - self.excerpts_for_range(range.clone()) - .flat_map(move |(excerpt, excerpt_offset)| { - let excerpt_buffer_start_row = - excerpt.range.context.start.to_point(&excerpt.buffer).row; - let excerpt_offset_row = crate::ToPoint::to_point(&excerpt_offset, self).row; + // self.excerpts_for_range(range.clone()) + // .flat_map(move |(excerpt, excerpt_offset)| { + // let excerpt_buffer_start_row = + // excerpt.range.context.start.to_point(&excerpt.buffer).row; + // let excerpt_offset_row = crate::ToPoint::to_point(&excerpt_offset, self).row; - excerpt - .buffer - .indent_guides_in_range( - excerpt.range.context.clone(), - ignore_disabled_for_language, - cx, - ) - .into_iter() - .map(move |indent_guide| { - let start_row = excerpt_offset_row - + (indent_guide.start_row - excerpt_buffer_start_row); - let end_row = - excerpt_offset_row + (indent_guide.end_row - excerpt_buffer_start_row); + // excerpt + // .buffer + // .indent_guides_in_range( + // excerpt.range.context.clone(), + // ignore_disabled_for_language, + // cx, + // ) + // .into_iter() + // .map(move |indent_guide| { + // let start_row = excerpt_offset_row + // + (indent_guide.start_row - excerpt_buffer_start_row); + // let end_row = + // excerpt_offset_row + (indent_guide.end_row - excerpt_buffer_start_row); - MultiBufferIndentGuide { - multibuffer_row_range: MultiBufferRow(start_row) - ..MultiBufferRow(end_row), - buffer: indent_guide, - } - }) - }) - .collect() + // MultiBufferIndentGuide { + // multibuffer_row_range: MultiBufferRow(start_row) + // ..MultiBufferRow(end_row), + // buffer: indent_guide, + // } + // }) + // }) + // .collect() } pub fn trailing_excerpt_update_count(&self) -> usize { @@ -3608,7 +3478,7 @@ impl MultiBufferSnapshot { { self.as_singleton() .into_iter() - .flat_map(move |(_, _, buffer)| buffer.diagnostic_group(group_id)) + .flat_map(move |buffer| buffer.diagnostic_group(group_id)) } pub fn diagnostics_in_range<'a, T, O>( @@ -3620,14 +3490,12 @@ impl MultiBufferSnapshot { T: 'a + ToOffset, O: 'a + text::FromAnchor + Ord, { - self.as_singleton() - .into_iter() - .flat_map(move |(_, _, buffer)| { - buffer.diagnostics_in_range( - range.start.to_offset(self)..range.end.to_offset(self), - reversed, - ) - }) + self.as_singleton().into_iter().flat_map(move |buffer| { + buffer.diagnostics_in_range( + range.start.to_offset(self)..range.end.to_offset(self), + reversed, + ) + }) } pub fn has_git_diffs(&self) -> bool { @@ -3643,136 +3511,140 @@ impl MultiBufferSnapshot { &self, row_range: Range, ) -> impl Iterator + '_ { - let mut cursor = self.excerpts.cursor::(&()); + todo!(); + std::iter::empty() + // let mut cursor = self.excerpts.cursor::(&()); - cursor.seek(&Point::new(row_range.end.0, 0), Bias::Left, &()); - if cursor.item().is_none() { - cursor.prev(&()); - } + // cursor.seek(&Point::new(row_range.end.0, 0), Bias::Left, &()); + // if cursor.item().is_none() { + // cursor.prev(&()); + // } - std::iter::from_fn(move || { - let excerpt = cursor.item()?; - let multibuffer_start = *cursor.start(); - let multibuffer_end = multibuffer_start + excerpt.text_summary.lines; - if multibuffer_start.row >= row_range.end.0 { - return None; - } + // std::iter::from_fn(move || { + // let excerpt = cursor.item()?; + // let multibuffer_start = *cursor.start(); + // let multibuffer_end = multibuffer_start + excerpt.text_summary.lines; + // if multibuffer_start.row >= row_range.end.0 { + // return None; + // } - let mut buffer_start = excerpt.range.context.start; - let mut buffer_end = excerpt.range.context.end; - let excerpt_start_point = buffer_start.to_point(&excerpt.buffer); - let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines; + // let mut buffer_start = excerpt.range.context.start; + // let mut buffer_end = excerpt.range.context.end; + // let excerpt_start_point = buffer_start.to_point(&excerpt.buffer); + // let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines; - if row_range.start.0 > multibuffer_start.row { - let buffer_start_point = - excerpt_start_point + Point::new(row_range.start.0 - multibuffer_start.row, 0); - buffer_start = excerpt.buffer.anchor_before(buffer_start_point); - } + // if row_range.start.0 > multibuffer_start.row { + // let buffer_start_point = + // excerpt_start_point + Point::new(row_range.start.0 - multibuffer_start.row, 0); + // buffer_start = excerpt.buffer.anchor_before(buffer_start_point); + // } - if row_range.end.0 < multibuffer_end.row { - let buffer_end_point = - excerpt_start_point + Point::new(row_range.end.0 - multibuffer_start.row, 0); - buffer_end = excerpt.buffer.anchor_before(buffer_end_point); - } + // if row_range.end.0 < multibuffer_end.row { + // let buffer_end_point = + // excerpt_start_point + Point::new(row_range.end.0 - multibuffer_start.row, 0); + // buffer_end = excerpt.buffer.anchor_before(buffer_end_point); + // } - let buffer_hunks = excerpt - .buffer - .git_diff_hunks_intersecting_range_rev(buffer_start..buffer_end) - .map(move |hunk| { - let start = multibuffer_start.row - + hunk.row_range.start.saturating_sub(excerpt_start_point.row); - let end = multibuffer_start.row - + hunk - .row_range - .end - .min(excerpt_end_point.row + 1) - .saturating_sub(excerpt_start_point.row); + // let buffer_hunks = excerpt + // .buffer + // .git_diff_hunks_intersecting_range_rev(buffer_start..buffer_end) + // .map(move |hunk| { + // let start = multibuffer_start.row + // + hunk.row_range.start.saturating_sub(excerpt_start_point.row); + // let end = multibuffer_start.row + // + hunk + // .row_range + // .end + // .min(excerpt_end_point.row + 1) + // .saturating_sub(excerpt_start_point.row); - MultiBufferDiffHunk { - row_range: MultiBufferRow(start)..MultiBufferRow(end), - diff_base_byte_range: hunk.diff_base_byte_range.clone(), - buffer_range: hunk.buffer_range.clone(), - buffer_id: excerpt.buffer_id, - } - }); + // MultiBufferDiffHunk { + // row_range: MultiBufferRow(start)..MultiBufferRow(end), + // diff_base_byte_range: hunk.diff_base_byte_range.clone(), + // buffer_range: hunk.buffer_range.clone(), + // buffer_id: excerpt.buffer_id, + // } + // }); - cursor.prev(&()); + // cursor.prev(&()); - Some(buffer_hunks) - }) - .flatten() + // Some(buffer_hunks) + // }) + // .flatten() } pub fn git_diff_hunks_in_range( &self, row_range: Range, ) -> impl Iterator + '_ { - let mut cursor = self.excerpts.cursor::(&()); + todo!(); + std::iter::empty() + // let mut cursor = self.excerpts.cursor::(&()); - cursor.seek(&Point::new(row_range.start.0, 0), Bias::Left, &()); + // cursor.seek(&Point::new(row_range.start.0, 0), Bias::Left, &()); - std::iter::from_fn(move || { - let excerpt = cursor.item()?; - let multibuffer_start = *cursor.start(); - let multibuffer_end = multibuffer_start + excerpt.text_summary.lines; - let mut buffer_start = excerpt.range.context.start; - let mut buffer_end = excerpt.range.context.end; + // std::iter::from_fn(move || { + // let excerpt = cursor.item()?; + // let multibuffer_start = *cursor.start(); + // let multibuffer_end = multibuffer_start + excerpt.text_summary.lines; + // let mut buffer_start = excerpt.range.context.start; + // let mut buffer_end = excerpt.range.context.end; - let excerpt_rows = match multibuffer_start.row.cmp(&row_range.end.0) { - cmp::Ordering::Less => { - let excerpt_start_point = buffer_start.to_point(&excerpt.buffer); - let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines; + // let excerpt_rows = match multibuffer_start.row.cmp(&row_range.end.0) { + // cmp::Ordering::Less => { + // let excerpt_start_point = buffer_start.to_point(&excerpt.buffer); + // let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines; - if row_range.start.0 > multibuffer_start.row { - let buffer_start_point = excerpt_start_point - + Point::new(row_range.start.0 - multibuffer_start.row, 0); - buffer_start = excerpt.buffer.anchor_before(buffer_start_point); - } + // if row_range.start.0 > multibuffer_start.row { + // let buffer_start_point = excerpt_start_point + // + Point::new(row_range.start.0 - multibuffer_start.row, 0); + // buffer_start = excerpt.buffer.anchor_before(buffer_start_point); + // } - if row_range.end.0 < multibuffer_end.row { - let buffer_end_point = excerpt_start_point - + Point::new(row_range.end.0 - multibuffer_start.row, 0); - buffer_end = excerpt.buffer.anchor_before(buffer_end_point); - } - excerpt_start_point.row..excerpt_end_point.row - } - cmp::Ordering::Equal if row_range.end.0 == 0 => { - buffer_end = buffer_start; - 0..0 - } - cmp::Ordering::Greater | cmp::Ordering::Equal => return None, - }; + // if row_range.end.0 < multibuffer_end.row { + // let buffer_end_point = excerpt_start_point + // + Point::new(row_range.end.0 - multibuffer_start.row, 0); + // buffer_end = excerpt.buffer.anchor_before(buffer_end_point); + // } + // excerpt_start_point.row..excerpt_end_point.row + // } + // cmp::Ordering::Equal if row_range.end.0 == 0 => { + // buffer_end = buffer_start; + // 0..0 + // } + // cmp::Ordering::Greater | cmp::Ordering::Equal => return None, + // }; - let buffer_hunks = excerpt - .buffer - .git_diff_hunks_intersecting_range(buffer_start..buffer_end) - .map(move |hunk| { - let buffer_range = if excerpt_rows.start == 0 && excerpt_rows.end == 0 { - MultiBufferRow(0)..MultiBufferRow(1) - } else { - let start = multibuffer_start.row - + hunk.row_range.start.saturating_sub(excerpt_rows.start); - let end = multibuffer_start.row - + hunk - .row_range - .end - .min(excerpt_rows.end + 1) - .saturating_sub(excerpt_rows.start); - MultiBufferRow(start)..MultiBufferRow(end) - }; - MultiBufferDiffHunk { - row_range: buffer_range, - diff_base_byte_range: hunk.diff_base_byte_range.clone(), - buffer_range: hunk.buffer_range.clone(), - buffer_id: excerpt.buffer_id, - } - }); + // let buffer_hunks = excerpt + // .buffer + // .git_diff_hunks_intersecting_range(buffer_start..buffer_end) + // .map(move |hunk| { + // let buffer_range = if excerpt_rows.start == 0 && excerpt_rows.end == 0 { + // MultiBufferRow(0)..MultiBufferRow(1) + // } else { + // let start = multibuffer_start.row + // + hunk.row_range.start.saturating_sub(excerpt_rows.start); + // let end = multibuffer_start.row + // + hunk + // .row_range + // .end + // .min(excerpt_rows.end + 1) + // .saturating_sub(excerpt_rows.start); + // MultiBufferRow(start)..MultiBufferRow(end) + // }; + // MultiBufferDiffHunk { + // row_range: buffer_range, + // diff_base_byte_range: hunk.diff_base_byte_range.clone(), + // buffer_range: hunk.buffer_range.clone(), + // buffer_id: excerpt.buffer_id, + // } + // }); - cursor.next(&()); + // cursor.next(&()); - Some(buffer_hunks) - }) - .flatten() + // Some(buffer_hunks) + // }) + // .flatten() } pub fn range_for_syntax_ancestor(&self, range: Range) -> Option> { @@ -3787,36 +3659,37 @@ impl MultiBufferSnapshot { } pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option> { - let (excerpt_id, _, buffer) = self.as_singleton()?; - let outline = buffer.outline(theme)?; - Some(Outline::new( - outline - .items - .into_iter() - .flat_map(|item| { - Some(OutlineItem { - depth: item.depth, - range: self.anchor_in_excerpt(*excerpt_id, item.range.start)? - ..self.anchor_in_excerpt(*excerpt_id, item.range.end)?, - text: item.text, - highlight_ranges: item.highlight_ranges, - name_ranges: item.name_ranges, - body_range: item.body_range.and_then(|body_range| { - Some( - self.anchor_in_excerpt(*excerpt_id, body_range.start)? - ..self.anchor_in_excerpt(*excerpt_id, body_range.end)?, - ) - }), - annotation_range: item.annotation_range.and_then(|annotation_range| { - Some( - self.anchor_in_excerpt(*excerpt_id, annotation_range.start)? - ..self.anchor_in_excerpt(*excerpt_id, annotation_range.end)?, - ) - }), - }) - }) - .collect(), - )) + todo!() + // let (excerpt_id, _, buffer) = self.as_singleton()?; + // let outline = buffer.outline(theme)?; + // Some(Outline::new( + // outline + // .items + // .into_iter() + // .flat_map(|item| { + // Some(OutlineItem { + // depth: item.depth, + // range: self.anchor_in_excerpt(*excerpt_id, item.range.start)? + // ..self.anchor_in_excerpt(*excerpt_id, item.range.end)?, + // text: item.text, + // highlight_ranges: item.highlight_ranges, + // name_ranges: item.name_ranges, + // body_range: item.body_range.and_then(|body_range| { + // Some( + // self.anchor_in_excerpt(*excerpt_id, body_range.start)? + // ..self.anchor_in_excerpt(*excerpt_id, body_range.end)?, + // ) + // }), + // annotation_range: item.annotation_range.and_then(|annotation_range| { + // Some( + // self.anchor_in_excerpt(*excerpt_id, annotation_range.start)? + // ..self.anchor_in_excerpt(*excerpt_id, annotation_range.end)?, + // ) + // }), + // }) + // }) + // .collect(), + // )) } pub fn symbols_containing( @@ -3824,151 +3697,64 @@ impl MultiBufferSnapshot { offset: T, theme: Option<&SyntaxTheme>, ) -> Option<(BufferId, Vec>)> { - let anchor = self.anchor_before(offset); - let excerpt_id = anchor.excerpt_id; - let excerpt = self.excerpt(excerpt_id)?; - Some(( - excerpt.buffer_id, - excerpt - .buffer - .symbols_containing(anchor.text_anchor, theme) - .into_iter() - .flatten() - .flat_map(|item| { - Some(OutlineItem { - depth: item.depth, - range: self.anchor_in_excerpt(excerpt_id, item.range.start)? - ..self.anchor_in_excerpt(excerpt_id, item.range.end)?, - text: item.text, - highlight_ranges: item.highlight_ranges, - name_ranges: item.name_ranges, - body_range: item.body_range.and_then(|body_range| { - Some( - self.anchor_in_excerpt(excerpt_id, body_range.start)? - ..self.anchor_in_excerpt(excerpt_id, body_range.end)?, - ) - }), - annotation_range: item.annotation_range.and_then(|body_range| { - Some( - self.anchor_in_excerpt(excerpt_id, body_range.start)? - ..self.anchor_in_excerpt(excerpt_id, body_range.end)?, - ) - }), - }) - }) - .collect(), - )) - } - - fn excerpt_locator_for_id(&self, id: ExcerptId) -> &Locator { - if id == ExcerptId::min() { - Locator::min_ref() - } else if id == ExcerptId::max() { - Locator::max_ref() - } else { - let mut cursor = self.excerpt_ids.cursor::(&()); - cursor.seek(&id, Bias::Left, &()); - if let Some(entry) = cursor.item() { - if entry.id == id { - return &entry.locator; - } - } - panic!("invalid excerpt id {:?}", id) - } - } - - /// Returns the locators referenced by the given excerpt IDs, sorted by locator. - fn excerpt_locators_for_ids( - &self, - ids: impl IntoIterator, - ) -> SmallVec<[Locator; 1]> { - let mut sorted_ids = ids.into_iter().collect::>(); - sorted_ids.sort_unstable(); - let mut locators = SmallVec::new(); - - while sorted_ids.last() == Some(&ExcerptId::max()) { - sorted_ids.pop(); - if let Some(mapping) = self.excerpt_ids.last() { - locators.push(mapping.locator.clone()); - } - } - - let mut sorted_ids = sorted_ids.into_iter().dedup().peekable(); - if sorted_ids.peek() == Some(&ExcerptId::min()) { - sorted_ids.next(); - if let Some(mapping) = self.excerpt_ids.first() { - locators.push(mapping.locator.clone()); - } - } - - let mut cursor = self.excerpt_ids.cursor::(&()); - for id in sorted_ids { - if cursor.seek_forward(&id, Bias::Left, &()) { - locators.push(cursor.item().unwrap().locator.clone()); - } else { - panic!("invalid excerpt id {:?}", id); - } - } - - locators.sort_unstable(); - locators - } - - pub fn buffer_id_for_excerpt(&self, excerpt_id: ExcerptId) -> Option { - Some(self.excerpt(excerpt_id)?.buffer_id) - } - - pub fn buffer_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<&BufferSnapshot> { - Some(&self.excerpt(excerpt_id)?.buffer) - } - - pub fn range_for_excerpt<'a, T: sum_tree::Dimension<'a, ExcerptSummary>>( - &'a self, - excerpt_id: ExcerptId, - ) -> Option> { - let mut cursor = self.excerpts.cursor::<(Option<&Locator>, T)>(&()); - let locator = self.excerpt_locator_for_id(excerpt_id); - if cursor.seek(&Some(locator), Bias::Left, &()) { - let start = cursor.start().1.clone(); - let end = cursor.end(&()).1; - Some(start..end) - } else { - None - } - } - - fn excerpt(&self, excerpt_id: ExcerptId) -> Option<&Excerpt> { - let mut cursor = self.excerpts.cursor::>(&()); - let locator = self.excerpt_locator_for_id(excerpt_id); - cursor.seek(&Some(locator), Bias::Left, &()); - if let Some(excerpt) = cursor.item() { - if excerpt.id == excerpt_id { - return Some(excerpt); - } - } - None + todo!() + // let anchor = self.anchor_before(offset); + // let excerpt_id = anchor.excerpt_id; + // let excerpt = self.excerpt(excerpt_id)?; + // Some(( + // excerpt.buffer_id, + // excerpt + // .buffer + // .symbols_containing(anchor.text_anchor, theme) + // .into_iter() + // .flatten() + // .flat_map(|item| { + // Some(OutlineItem { + // depth: item.depth, + // range: self.anchor_in_excerpt(excerpt_id, item.range.start)? + // ..self.anchor_in_excerpt(excerpt_id, item.range.end)?, + // text: item.text, + // highlight_ranges: item.highlight_ranges, + // name_ranges: item.name_ranges, + // body_range: item.body_range.and_then(|body_range| { + // Some( + // self.anchor_in_excerpt(excerpt_id, body_range.start)? + // ..self.anchor_in_excerpt(excerpt_id, body_range.end)?, + // ) + // }), + // annotation_range: item.annotation_range.and_then(|body_range| { + // Some( + // self.anchor_in_excerpt(excerpt_id, body_range.start)? + // ..self.anchor_in_excerpt(excerpt_id, body_range.end)?, + // ) + // }), + // }) + // }) + // .collect(), + // )) } /// Returns the excerpt containing range and its offset start within the multibuffer or none if `range` spans multiple excerpts pub fn excerpt_containing(&self, range: Range) -> Option { - let range = range.start.to_offset(self)..range.end.to_offset(self); + todo!() + // let range = range.start.to_offset(self)..range.end.to_offset(self); - let mut cursor = self.excerpts.cursor::(&()); - cursor.seek(&range.start, Bias::Right, &()); - let start_excerpt = cursor.item()?; + // let mut cursor = self.excerpts.cursor::(&()); + // cursor.seek(&range.start, Bias::Right, &()); + // let start_excerpt = cursor.item()?; - if range.start == range.end { - return Some(MultiBufferExcerpt::new(start_excerpt, *cursor.start())); - } + // if range.start == range.end { + // return Some(MultiBufferExcerpt::new(start_excerpt, *cursor.start())); + // } - cursor.seek(&range.end, Bias::Right, &()); - let end_excerpt = cursor.item()?; + // cursor.seek(&range.end, Bias::Right, &()); + // let end_excerpt = cursor.item()?; - if start_excerpt.id == end_excerpt.id { - Some(MultiBufferExcerpt::new(start_excerpt, *cursor.start())) - } else { - None - } + // if start_excerpt.id == end_excerpt.id { + // Some(MultiBufferExcerpt::new(start_excerpt, *cursor.start())) + // } else { + // None + // } } // Takes an iterator over anchor ranges and returns a new iterator over anchor ranges that don't @@ -3977,48 +3763,50 @@ impl MultiBufferSnapshot { where I: IntoIterator> + 'a, { - let mut ranges = ranges.into_iter().map(|range| range.to_offset(self)); - let mut cursor = self.excerpts.cursor::(&()); - cursor.next(&()); - let mut current_range = ranges.next(); - iter::from_fn(move || { - let range = current_range.clone()?; - if range.start >= cursor.end(&()) { - cursor.seek_forward(&range.start, Bias::Right, &()); - if range.start == self.len() { - cursor.prev(&()); - } - } + todo!(); + std::iter::empty() + // let mut ranges = ranges.into_iter().map(|range| range.to_offset(self)); + // let mut cursor = self.excerpts.cursor::(&()); + // cursor.next(&()); + // let mut current_range = ranges.next(); + // iter::from_fn(move || { + // let range = current_range.clone()?; + // if range.start >= cursor.end(&()) { + // cursor.seek_forward(&range.start, Bias::Right, &()); + // if range.start == self.len() { + // cursor.prev(&()); + // } + // } - let excerpt = cursor.item()?; - let range_start_in_excerpt = cmp::max(range.start, *cursor.start()); - let range_end_in_excerpt = if excerpt.has_trailing_newline { - cmp::min(range.end, cursor.end(&()) - 1) - } else { - cmp::min(range.end, cursor.end(&())) - }; - let buffer_range = MultiBufferExcerpt::new(excerpt, *cursor.start()) - .map_range_to_buffer(range_start_in_excerpt..range_end_in_excerpt); + // let excerpt = cursor.item()?; + // let range_start_in_excerpt = cmp::max(range.start, *cursor.start()); + // let range_end_in_excerpt = if excerpt.has_trailing_newline { + // cmp::min(range.end, cursor.end(&()) - 1) + // } else { + // cmp::min(range.end, cursor.end(&())) + // }; + // let buffer_range = MultiBufferExcerpt::new(excerpt, *cursor.start()) + // .map_range_to_buffer(range_start_in_excerpt..range_end_in_excerpt); - let subrange_start_anchor = Anchor { - buffer_id: Some(excerpt.buffer_id), - excerpt_id: excerpt.id, - text_anchor: excerpt.buffer.anchor_before(buffer_range.start), - }; - let subrange_end_anchor = Anchor { - buffer_id: Some(excerpt.buffer_id), - excerpt_id: excerpt.id, - text_anchor: excerpt.buffer.anchor_after(buffer_range.end), - }; + // let subrange_start_anchor = Anchor { + // buffer_id: Some(excerpt.buffer_id), + // excerpt_id: excerpt.id, + // text_anchor: excerpt.buffer.anchor_before(buffer_range.start), + // }; + // let subrange_end_anchor = Anchor { + // buffer_id: Some(excerpt.buffer_id), + // excerpt_id: excerpt.id, + // text_anchor: excerpt.buffer.anchor_after(buffer_range.end), + // }; - if range.end > cursor.end(&()) { - cursor.next(&()); - } else { - current_range = ranges.next(); - } + // if range.end > cursor.end(&()) { + // cursor.next(&()); + // } else { + // current_range = ranges.next(); + // } - Some(subrange_start_anchor..subrange_end_anchor) - }) + // Some(subrange_start_anchor..subrange_end_anchor) + // }) } /// Returns excerpts overlapping the given ranges. If range spans multiple excerpts returns one range for each excerpt @@ -4028,38 +3816,40 @@ impl MultiBufferSnapshot { pub fn excerpts_in_ranges( &self, ranges: impl IntoIterator>, - ) -> impl Iterator)> { - let mut ranges = ranges.into_iter().map(|range| range.to_offset(self)); - let mut cursor = self.excerpts.cursor::(&()); - cursor.next(&()); - let mut current_range = ranges.next(); - iter::from_fn(move || { - let range = current_range.clone()?; - if range.start >= cursor.end(&()) { - cursor.seek_forward(&range.start, Bias::Right, &()); - if range.start == self.len() { - cursor.prev(&()); - } - } + ) -> impl Iterator)> { + todo!(); + std::iter::empty() + // let mut ranges = ranges.into_iter().map(|range| range.to_offset(self)); + // let mut cursor = self.excerpts.cursor::(&()); + // cursor.next(&()); + // let mut current_range = ranges.next(); + // iter::from_fn(move || { + // let range = current_range.clone()?; + // if range.start >= cursor.end(&()) { + // cursor.seek_forward(&range.start, Bias::Right, &()); + // if range.start == self.len() { + // cursor.prev(&()); + // } + // } - let excerpt = cursor.item()?; - let range_start_in_excerpt = cmp::max(range.start, *cursor.start()); - let range_end_in_excerpt = if excerpt.has_trailing_newline { - cmp::min(range.end, cursor.end(&()) - 1) - } else { - cmp::min(range.end, cursor.end(&())) - }; - let buffer_range = MultiBufferExcerpt::new(excerpt, *cursor.start()) - .map_range_to_buffer(range_start_in_excerpt..range_end_in_excerpt); + // let excerpt = cursor.item()?; + // let range_start_in_excerpt = cmp::max(range.start, *cursor.start()); + // let range_end_in_excerpt = if excerpt.has_trailing_newline { + // cmp::min(range.end, cursor.end(&()) - 1) + // } else { + // cmp::min(range.end, cursor.end(&())) + // }; + // let buffer_range = MultiBufferExcerpt::new(excerpt, *cursor.start()) + // .map_range_to_buffer(range_start_in_excerpt..range_end_in_excerpt); - if range.end > cursor.end(&()) { - cursor.next(&()); - } else { - current_range = ranges.next(); - } + // if range.end > cursor.end(&()) { + // cursor.next(&()); + // } else { + // current_range = ranges.next(); + // } - Some((excerpt.id, &excerpt.buffer, buffer_range)) - }) + // Some((excerpt.id, &excerpt.buffer, buffer_range)) + // }) } pub fn selections_in_range<'a>( @@ -4067,58 +3857,60 @@ impl MultiBufferSnapshot { range: &'a Range, include_local: bool, ) -> impl 'a + Iterator)> { - let mut cursor = self.excerpts.cursor::(&()); - let start_locator = self.excerpt_locator_for_id(range.start.excerpt_id); - let end_locator = self.excerpt_locator_for_id(range.end.excerpt_id); - cursor.seek(start_locator, Bias::Left, &()); - cursor - .take_while(move |excerpt| excerpt.locator <= *end_locator) - .flat_map(move |excerpt| { - let mut query_range = excerpt.range.context.start..excerpt.range.context.end; - if excerpt.id == range.start.excerpt_id { - query_range.start = range.start.text_anchor; - } - if excerpt.id == range.end.excerpt_id { - query_range.end = range.end.text_anchor; - } + todo!(); + std::iter::empty() + // let mut cursor = self.excerpts.cursor::(&()); + // let start_locator = self.excerpt_locator_for_id(range.start.excerpt_id); + // let end_locator = self.excerpt_locator_for_id(range.end.excerpt_id); + // cursor.seek(start_locator, Bias::Left, &()); + // cursor + // .take_while(move |excerpt| excerpt.locator <= *end_locator) + // .flat_map(move |excerpt| { + // let mut query_range = excerpt.range.context.start..excerpt.range.context.end; + // if excerpt.id == range.start.excerpt_id { + // query_range.start = range.start.text_anchor; + // } + // if excerpt.id == range.end.excerpt_id { + // query_range.end = range.end.text_anchor; + // } - excerpt - .buffer - .selections_in_range(query_range, include_local) - .flat_map(move |(replica_id, line_mode, cursor_shape, selections)| { - selections.map(move |selection| { - let mut start = Anchor { - buffer_id: Some(excerpt.buffer_id), - excerpt_id: excerpt.id, - text_anchor: selection.start, - }; - let mut end = Anchor { - buffer_id: Some(excerpt.buffer_id), - excerpt_id: excerpt.id, - text_anchor: selection.end, - }; - if range.start.cmp(&start, self).is_gt() { - start = range.start; - } - if range.end.cmp(&end, self).is_lt() { - end = range.end; - } + // excerpt + // .buffer + // .selections_in_range(query_range, include_local) + // .flat_map(move |(replica_id, line_mode, cursor_shape, selections)| { + // selections.map(move |selection| { + // let mut start = Anchor { + // buffer_id: Some(excerpt.buffer_id), + // excerpt_id: excerpt.id, + // text_anchor: selection.start, + // }; + // let mut end = Anchor { + // buffer_id: Some(excerpt.buffer_id), + // excerpt_id: excerpt.id, + // text_anchor: selection.end, + // }; + // if range.start.cmp(&start, self).is_gt() { + // start = range.start; + // } + // if range.end.cmp(&end, self).is_lt() { + // end = range.end; + // } - ( - replica_id, - line_mode, - cursor_shape, - Selection { - id: selection.id, - start, - end, - reversed: selection.reversed, - goal: selection.goal, - }, - ) - }) - }) - }) + // ( + // replica_id, + // line_mode, + // cursor_shape, + // Selection { + // id: selection.id, + // start, + // end, + // reversed: selection.reversed, + // goal: selection.goal, + // }, + // ) + // }) + // }) + // }) } pub fn show_headers(&self) -> bool { @@ -4339,20 +4131,14 @@ impl History { impl Excerpt { fn new( - id: ExcerptId, - locator: Locator, - buffer_id: BufferId, buffer: BufferSnapshot, range: ExcerptRange, has_trailing_newline: bool, ) -> Self { Excerpt { - id, - locator, max_buffer_row: range.context.end.to_point(&buffer).row, text_summary: buffer .text_summary_for_range::(range.context.to_offset(&buffer)), - buffer_id, buffer, range, has_trailing_newline, @@ -4376,7 +4162,6 @@ impl Excerpt { let content_chunks = self.buffer.chunks(chunks_start..chunks_end, language_aware); ExcerptChunks { - excerpt_id: self.id, content_chunks, footer_height, } @@ -4456,19 +4241,20 @@ impl Excerpt { } fn contains(&self, anchor: &Anchor) -> bool { - Some(self.buffer_id) == anchor.buffer_id - && self - .range - .context - .start - .cmp(&anchor.text_anchor, &self.buffer) - .is_le() - && self - .range - .context - .end - .cmp(&anchor.text_anchor, &self.buffer) - .is_ge() + todo!() + // Some(self.buffer_id) == anchor.buffer_id + // && self + // .range + // .context + // .start + // .cmp(&anchor.text_anchor, &self.buffer) + // .is_le() + // && self + // .range + // .context + // .end + // .cmp(&anchor.text_anchor, &self.buffer) + // .is_ge() } /// The [`Excerpt`]'s start offset in its [`Buffer`] @@ -4527,42 +4313,9 @@ impl<'a> MultiBufferExcerpt<'a> { } } -impl ExcerptId { - pub fn min() -> Self { - Self(0) - } - - pub fn max() -> Self { - Self(usize::MAX) - } - - pub fn to_proto(&self) -> u64 { - self.0 as _ - } - - pub fn from_proto(proto: u64) -> Self { - Self(proto as _) - } - - pub fn cmp(&self, other: &Self, snapshot: &MultiBufferSnapshot) -> cmp::Ordering { - let a = snapshot.excerpt_locator_for_id(*self); - let b = snapshot.excerpt_locator_for_id(*other); - a.cmp(b).then_with(|| self.0.cmp(&other.0)) - } -} - -impl From for usize { - fn from(val: ExcerptId) -> Self { - val.0 - } -} - impl fmt::Debug for Excerpt { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Excerpt") - .field("id", &self.id) - .field("locator", &self.locator) - .field("buffer_id", &self.buffer_id) .field("range", &self.range) .field("text_summary", &self.text_summary) .field("has_trailing_newline", &self.has_trailing_newline) @@ -4578,40 +4331,13 @@ impl sum_tree::Item for Excerpt { if self.has_trailing_newline { text += TextSummary::from("\n"); } - ExcerptSummary { - excerpt_id: self.id, - excerpt_locator: self.locator.clone(), - max_buffer_row: MultiBufferRow(self.max_buffer_row), - text, - } - } -} - -impl sum_tree::Item for ExcerptIdMapping { - type Summary = ExcerptId; - - fn summary(&self) -> Self::Summary { - self.id - } -} - -impl sum_tree::KeyedItem for ExcerptIdMapping { - type Key = ExcerptId; - - fn key(&self) -> Self::Key { - self.id - } -} - -impl sum_tree::Summary for ExcerptId { - type Context = (); - - fn zero(_cx: &()) -> Self { - Default::default() - } - - fn add_summary(&mut self, other: &Self, _: &()) { - *self = *other; + // ExcerptSummary { + // excerpt_id: self.id, + // excerpt_locator: self.locator.clone(), + // max_buffer_row: MultiBufferRow(self.max_buffer_row), + // text, + // } + todo!() } } @@ -4619,14 +4345,15 @@ impl sum_tree::Summary for ExcerptSummary { type Context = (); fn zero(_cx: &()) -> Self { - Default::default() + todo!() } fn add_summary(&mut self, summary: &Self, _: &()) { - debug_assert!(summary.excerpt_locator > self.excerpt_locator); - self.excerpt_locator = summary.excerpt_locator.clone(); - self.text.add_summary(&summary.text, &()); - self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row); + todo!() + // debug_assert!(summary.excerpt_locator > self.excerpt_locator); + // self.excerpt_locator = summary.excerpt_locator.clone(); + // self.text.add_summary(&summary.text, &()); + // self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row); } } @@ -4656,18 +4383,6 @@ impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize { } } -impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, Option<&'a Locator>> for Locator { - fn cmp(&self, cursor_location: &Option<&'a Locator>, _: &()) -> cmp::Ordering { - Ord::cmp(&Some(self), cursor_location) - } -} - -impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Locator { - fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering { - Ord::cmp(self, &cursor_location.excerpt_locator) - } -} - impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for OffsetUtf16 { fn zero(_cx: &()) -> Self { Default::default() @@ -4698,26 +4413,6 @@ impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 { } } -impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a Locator> { - fn zero(_cx: &()) -> Self { - Default::default() - } - - fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) { - *self = Some(&summary.excerpt_locator); - } -} - -impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option { - fn zero(_cx: &()) -> Self { - Default::default() - } - - fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) { - *self = Some(summary.excerpt_id); - } -} - impl<'a> MultiBufferRows<'a> { pub fn seek(&mut self, row: MultiBufferRow) { self.buffer_row_range = 0..0; @@ -4768,28 +4463,29 @@ impl<'a> MultiBufferChunks<'a> { } pub fn seek(&mut self, new_range: Range) { - self.range = new_range.clone(); - self.excerpts.seek(&new_range.start, Bias::Right, &()); - if let Some(excerpt) = self.excerpts.item() { - let excerpt_start = self.excerpts.start(); - if let Some(excerpt_chunks) = self - .excerpt_chunks - .as_mut() - .filter(|chunks| excerpt.id == chunks.excerpt_id) - { - excerpt.seek_chunks( - excerpt_chunks, - self.range.start - excerpt_start..self.range.end - excerpt_start, - ); - } else { - self.excerpt_chunks = Some(excerpt.chunks_in_range( - self.range.start - excerpt_start..self.range.end - excerpt_start, - self.language_aware, - )); - } - } else { - self.excerpt_chunks = None; - } + todo!() + // self.range = new_range.clone(); + // self.excerpts.seek(&new_range.start, Bias::Right, &()); + // if let Some(excerpt) = self.excerpts.item() { + // let excerpt_start = self.excerpts.start(); + // if let Some(excerpt_chunks) = self + // .excerpt_chunks + // .as_mut() + // .filter(|chunks| excerpt.id == chunks.excerpt_id) + // { + // excerpt.seek_chunks( + // excerpt_chunks, + // self.range.start - excerpt_start..self.range.end - excerpt_start, + // ); + // } else { + // self.excerpt_chunks = Some(excerpt.chunks_in_range( + // self.range.start - excerpt_start..self.range.end - excerpt_start, + // self.language_aware, + // )); + // } + // } else { + // self.excerpt_chunks = None; + // } } } @@ -5051,1959 +4747,1959 @@ where (excerpt_ranges, range_counts) } -#[cfg(test)] -mod tests { - use super::*; - use futures::StreamExt; - use gpui::{AppContext, Context, TestAppContext}; - use language::{Buffer, Rope}; - use parking_lot::RwLock; - use rand::prelude::*; - use settings::SettingsStore; - use std::env; - use util::test::sample_text; - - #[ctor::ctor] - fn init_logger() { - if std::env::var("RUST_LOG").is_ok() { - env_logger::init(); - } - } - - #[gpui::test] - fn test_singleton(cx: &mut AppContext) { - let buffer = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); - let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx)); - - let snapshot = multibuffer.read(cx).snapshot(cx); - assert_eq!(snapshot.text(), buffer.read(cx).text()); - - assert_eq!( - snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), - (0..buffer.read(cx).row_count()) - .map(Some) - .collect::>() - ); - - buffer.update(cx, |buffer, cx| buffer.edit([(1..3, "XXX\n")], None, cx)); - let snapshot = multibuffer.read(cx).snapshot(cx); - - assert_eq!(snapshot.text(), buffer.read(cx).text()); - assert_eq!( - snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), - (0..buffer.read(cx).row_count()) - .map(Some) - .collect::>() - ); - } - - #[gpui::test] - fn test_remote(cx: &mut AppContext) { - let host_buffer = cx.new_model(|cx| Buffer::local("a", cx)); - let guest_buffer = cx.new_model(|cx| { - let state = host_buffer.read(cx).to_proto(cx); - let ops = cx - .background_executor() - .block(host_buffer.read(cx).serialize_ops(None, cx)); - let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap(); - buffer.apply_ops( - ops.into_iter() - .map(|op| language::proto::deserialize_operation(op).unwrap()), - cx, - ); - buffer - }); - let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(guest_buffer.clone(), cx)); - let snapshot = multibuffer.read(cx).snapshot(cx); - assert_eq!(snapshot.text(), "a"); - - guest_buffer.update(cx, |buffer, cx| buffer.edit([(1..1, "b")], None, cx)); - let snapshot = multibuffer.read(cx).snapshot(cx); - assert_eq!(snapshot.text(), "ab"); - - guest_buffer.update(cx, |buffer, cx| buffer.edit([(2..2, "c")], None, cx)); - let snapshot = multibuffer.read(cx).snapshot(cx); - assert_eq!(snapshot.text(), "abc"); - } - - #[gpui::test] - fn test_excerpt_boundaries_and_clipping(cx: &mut AppContext) { - let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - - let events = Arc::new(RwLock::new(Vec::::new())); - multibuffer.update(cx, |_, cx| { - let events = events.clone(); - cx.subscribe(&multibuffer, move |_, _, event, _| { - if let Event::Edited { .. } = event { - events.write().push(event.clone()) - } - }) - .detach(); - }); - - let subscription = multibuffer.update(cx, |multibuffer, cx| { - let subscription = multibuffer.subscribe(); - multibuffer.push_excerpts( - buffer_1.clone(), - [ExcerptRange { - context: Point::new(1, 2)..Point::new(2, 5), - primary: None, - }], - cx, - ); - assert_eq!( - subscription.consume().into_inner(), - [Edit { - old: 0..0, - new: 0..10 - }] - ); - - multibuffer.push_excerpts( - buffer_1.clone(), - [ExcerptRange { - context: Point::new(3, 3)..Point::new(4, 4), - primary: None, - }], - cx, - ); - multibuffer.push_excerpts( - buffer_2.clone(), - [ExcerptRange { - context: Point::new(3, 1)..Point::new(3, 3), - primary: None, - }], - cx, - ); - assert_eq!( - subscription.consume().into_inner(), - [Edit { - old: 10..10, - new: 10..22 - }] - ); - - subscription - }); - - // Adding excerpts emits an edited event. - assert_eq!( - events.read().as_slice(), - &[ - Event::Edited { - singleton_buffer_edited: false - }, - Event::Edited { - singleton_buffer_edited: false - }, - Event::Edited { - singleton_buffer_edited: false - } - ] - ); - - let snapshot = multibuffer.read(cx).snapshot(cx); - assert_eq!( - snapshot.text(), - concat!( - "bbbb\n", // Preserve newlines - "ccccc\n", // - "ddd\n", // - "eeee\n", // - "jj" // - ) - ); - assert_eq!( - snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), - [Some(1), Some(2), Some(3), Some(4), Some(3)] - ); - assert_eq!( - snapshot.buffer_rows(MultiBufferRow(2)).collect::>(), - [Some(3), Some(4), Some(3)] - ); - assert_eq!( - snapshot.buffer_rows(MultiBufferRow(4)).collect::>(), - [Some(3)] - ); - assert_eq!( - snapshot.buffer_rows(MultiBufferRow(5)).collect::>(), - [] - ); - - assert_eq!( - boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot), - &[ - (MultiBufferRow(0), "bbbb\nccccc".to_string(), true), - (MultiBufferRow(2), "ddd\neeee".to_string(), false), - (MultiBufferRow(4), "jj".to_string(), true), - ] - ); - assert_eq!( - boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot), - &[(MultiBufferRow(0), "bbbb\nccccc".to_string(), true)] - ); - assert_eq!( - boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot), - &[] - ); - assert_eq!( - boundaries_in_range(Point::new(1, 0)..Point::new(2, 0), &snapshot), - &[] - ); - assert_eq!( - boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot), - &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)] - ); - assert_eq!( - boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot), - &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)] - ); - assert_eq!( - boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot), - &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)] - ); - assert_eq!( - boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot), - &[(MultiBufferRow(4), "jj".to_string(), true)] - ); - assert_eq!( - boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot), - &[] - ); - - buffer_1.update(cx, |buffer, cx| { - let text = "\n"; - buffer.edit( - [ - (Point::new(0, 0)..Point::new(0, 0), text), - (Point::new(2, 1)..Point::new(2, 3), text), - ], - None, - cx, - ); - }); - - let snapshot = multibuffer.read(cx).snapshot(cx); - assert_eq!( - snapshot.text(), - concat!( - "bbbb\n", // Preserve newlines - "c\n", // - "cc\n", // - "ddd\n", // - "eeee\n", // - "jj" // - ) - ); - - assert_eq!( - subscription.consume().into_inner(), - [Edit { - old: 6..8, - new: 6..7 - }] - ); - - let snapshot = multibuffer.read(cx).snapshot(cx); - assert_eq!( - snapshot.clip_point(Point::new(0, 5), Bias::Left), - Point::new(0, 4) - ); - assert_eq!( - snapshot.clip_point(Point::new(0, 5), Bias::Right), - Point::new(0, 4) - ); - assert_eq!( - snapshot.clip_point(Point::new(5, 1), Bias::Right), - Point::new(5, 1) - ); - assert_eq!( - snapshot.clip_point(Point::new(5, 2), Bias::Right), - Point::new(5, 2) - ); - assert_eq!( - snapshot.clip_point(Point::new(5, 3), Bias::Right), - Point::new(5, 2) - ); - - let snapshot = multibuffer.update(cx, |multibuffer, cx| { - let (buffer_2_excerpt_id, _) = - multibuffer.excerpts_for_buffer(&buffer_2, cx)[0].clone(); - multibuffer.remove_excerpts([buffer_2_excerpt_id], cx); - multibuffer.snapshot(cx) - }); - - assert_eq!( - snapshot.text(), - concat!( - "bbbb\n", // Preserve newlines - "c\n", // - "cc\n", // - "ddd\n", // - "eeee", // - ) - ); - - fn boundaries_in_range( - range: Range, - snapshot: &MultiBufferSnapshot, - ) -> Vec<(MultiBufferRow, String, bool)> { - snapshot - .excerpt_boundaries_in_range(range) - .filter_map(|boundary| { - let starts_new_buffer = boundary.starts_new_buffer(); - boundary.next.map(|next| { - ( - boundary.row, - next.buffer - .text_for_range(next.range.context) - .collect::(), - starts_new_buffer, - ) - }) - }) - .collect::>() - } - } - - #[gpui::test] - fn test_excerpt_events(cx: &mut AppContext) { - let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(10, 3, 'a'), cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(10, 3, 'm'), cx)); - - let leader_multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - let follower_multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - let follower_edit_event_count = Arc::new(RwLock::new(0)); - - follower_multibuffer.update(cx, |_, cx| { - let follower_edit_event_count = follower_edit_event_count.clone(); - cx.subscribe( - &leader_multibuffer, - move |follower, _, event, cx| match event.clone() { - Event::ExcerptsAdded { - buffer, - predecessor, - excerpts, - } => follower.insert_excerpts_with_ids_after(predecessor, buffer, excerpts, cx), - Event::ExcerptsRemoved { ids } => follower.remove_excerpts(ids, cx), - Event::Edited { .. } => { - *follower_edit_event_count.write() += 1; - } - _ => {} - }, - ) - .detach(); - }); - - leader_multibuffer.update(cx, |leader, cx| { - leader.push_excerpts( - buffer_1.clone(), - [ - ExcerptRange { - context: 0..8, - primary: None, - }, - ExcerptRange { - context: 12..16, - primary: None, - }, - ], - cx, - ); - leader.insert_excerpts_after( - leader.excerpt_ids()[0], - buffer_2.clone(), - [ - ExcerptRange { - context: 0..5, - primary: None, - }, - ExcerptRange { - context: 10..15, - primary: None, - }, - ], - cx, - ) - }); - assert_eq!( - leader_multibuffer.read(cx).snapshot(cx).text(), - follower_multibuffer.read(cx).snapshot(cx).text(), - ); - assert_eq!(*follower_edit_event_count.read(), 2); - - leader_multibuffer.update(cx, |leader, cx| { - let excerpt_ids = leader.excerpt_ids(); - leader.remove_excerpts([excerpt_ids[1], excerpt_ids[3]], cx); - }); - assert_eq!( - leader_multibuffer.read(cx).snapshot(cx).text(), - follower_multibuffer.read(cx).snapshot(cx).text(), - ); - assert_eq!(*follower_edit_event_count.read(), 3); - - // Removing an empty set of excerpts is a noop. - leader_multibuffer.update(cx, |leader, cx| { - leader.remove_excerpts([], cx); - }); - assert_eq!( - leader_multibuffer.read(cx).snapshot(cx).text(), - follower_multibuffer.read(cx).snapshot(cx).text(), - ); - assert_eq!(*follower_edit_event_count.read(), 3); - - // Adding an empty set of excerpts is a noop. - leader_multibuffer.update(cx, |leader, cx| { - leader.push_excerpts::(buffer_2.clone(), [], cx); - }); - assert_eq!( - leader_multibuffer.read(cx).snapshot(cx).text(), - follower_multibuffer.read(cx).snapshot(cx).text(), - ); - assert_eq!(*follower_edit_event_count.read(), 3); - - leader_multibuffer.update(cx, |leader, cx| { - leader.clear(cx); - }); - assert_eq!( - leader_multibuffer.read(cx).snapshot(cx).text(), - follower_multibuffer.read(cx).snapshot(cx).text(), - ); - assert_eq!(*follower_edit_event_count.read(), 4); - } - - #[gpui::test] - fn test_expand_excerpts(cx: &mut AppContext) { - let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx)); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - - multibuffer.update(cx, |multibuffer, cx| { - multibuffer.push_excerpts_with_context_lines( - buffer.clone(), - vec![ - // Note that in this test, this first excerpt - // does not contain a new line - Point::new(3, 2)..Point::new(3, 3), - Point::new(7, 1)..Point::new(7, 3), - Point::new(15, 0)..Point::new(15, 0), - ], - 1, - cx, - ) - }); - - let snapshot = multibuffer.read(cx).snapshot(cx); - - assert_eq!( - snapshot.text(), - concat!( - "ccc\n", // - "ddd\n", // - "eee", // - "\n", // End of excerpt - "ggg\n", // - "hhh\n", // - "iii", // - "\n", // End of excerpt - "ooo\n", // - "ppp\n", // - "qqq", // End of excerpt - ) - ); - drop(snapshot); - - multibuffer.update(cx, |multibuffer, cx| { - multibuffer.expand_excerpts( - multibuffer.excerpt_ids(), - 1, - ExpandExcerptDirection::UpAndDown, - cx, - ) - }); - - let snapshot = multibuffer.read(cx).snapshot(cx); - - // Expanding context lines causes the line containing 'fff' to appear in two different excerpts. - // We don't attempt to merge them, because removing the excerpt could create inconsistency with other layers - // that are tracking excerpt ids. - assert_eq!( - snapshot.text(), - concat!( - "bbb\n", // - "ccc\n", // - "ddd\n", // - "eee\n", // - "fff\n", // End of excerpt - "fff\n", // - "ggg\n", // - "hhh\n", // - "iii\n", // - "jjj\n", // End of excerpt - "nnn\n", // - "ooo\n", // - "ppp\n", // - "qqq\n", // - "rrr", // End of excerpt - ) - ); - } - - #[gpui::test] - fn test_push_excerpts_with_context_lines(cx: &mut AppContext) { - let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx)); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| { - multibuffer.push_excerpts_with_context_lines( - buffer.clone(), - vec![ - // Note that in this test, this first excerpt - // does contain a new line - Point::new(3, 2)..Point::new(4, 2), - Point::new(7, 1)..Point::new(7, 3), - Point::new(15, 0)..Point::new(15, 0), - ], - 2, - cx, - ) - }); - - let snapshot = multibuffer.read(cx).snapshot(cx); - assert_eq!( - snapshot.text(), - concat!( - "bbb\n", // Preserve newlines - "ccc\n", // - "ddd\n", // - "eee\n", // - "fff\n", // - "ggg\n", // - "hhh\n", // - "iii\n", // - "jjj\n", // - "nnn\n", // - "ooo\n", // - "ppp\n", // - "qqq\n", // - "rrr", // - ) - ); - - assert_eq!( - anchor_ranges - .iter() - .map(|range| range.to_point(&snapshot)) - .collect::>(), - vec![ - Point::new(2, 2)..Point::new(3, 2), - Point::new(6, 1)..Point::new(6, 3), - Point::new(11, 0)..Point::new(11, 0) - ] - ); - } - - #[gpui::test] - async fn test_stream_excerpts_with_context_lines(cx: &mut TestAppContext) { - let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx)); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| { - let snapshot = buffer.read(cx); - let ranges = vec![ - snapshot.anchor_before(Point::new(3, 2))..snapshot.anchor_before(Point::new(4, 2)), - snapshot.anchor_before(Point::new(7, 1))..snapshot.anchor_before(Point::new(7, 3)), - snapshot.anchor_before(Point::new(15, 0)) - ..snapshot.anchor_before(Point::new(15, 0)), - ]; - multibuffer.stream_excerpts_with_context_lines(buffer.clone(), ranges, 2, cx) - }); - - let anchor_ranges = anchor_ranges.collect::>().await; - - let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx)); - assert_eq!( - snapshot.text(), - concat!( - "bbb\n", // - "ccc\n", // - "ddd\n", // - "eee\n", // - "fff\n", // - "ggg\n", // - "hhh\n", // - "iii\n", // - "jjj\n", // - "nnn\n", // - "ooo\n", // - "ppp\n", // - "qqq\n", // - "rrr", // - ) - ); - - assert_eq!( - anchor_ranges - .iter() - .map(|range| range.to_point(&snapshot)) - .collect::>(), - vec![ - Point::new(2, 2)..Point::new(3, 2), - Point::new(6, 1)..Point::new(6, 3), - Point::new(11, 0)..Point::new(11, 0) - ] - ); - } - - #[gpui::test] - fn test_empty_multibuffer(cx: &mut AppContext) { - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - - let snapshot = multibuffer.read(cx).snapshot(cx); - assert_eq!(snapshot.text(), ""); - assert_eq!( - snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), - &[Some(0)] - ); - assert_eq!( - snapshot.buffer_rows(MultiBufferRow(1)).collect::>(), - &[] - ); - } - - #[gpui::test] - fn test_singleton_multibuffer_anchors(cx: &mut AppContext) { - let buffer = cx.new_model(|cx| Buffer::local("abcd", cx)); - let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx)); - let old_snapshot = multibuffer.read(cx).snapshot(cx); - buffer.update(cx, |buffer, cx| { - buffer.edit([(0..0, "X")], None, cx); - buffer.edit([(5..5, "Y")], None, cx); - }); - let new_snapshot = multibuffer.read(cx).snapshot(cx); - - assert_eq!(old_snapshot.text(), "abcd"); - assert_eq!(new_snapshot.text(), "XabcdY"); - - assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0); - assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1); - assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5); - assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6); - } - - #[gpui::test] - fn test_multibuffer_anchors(cx: &mut AppContext) { - let buffer_1 = cx.new_model(|cx| Buffer::local("abcd", cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local("efghi", cx)); - let multibuffer = cx.new_model(|cx| { - let mut multibuffer = MultiBuffer::new(Capability::ReadWrite); - multibuffer.push_excerpts( - buffer_1.clone(), - [ExcerptRange { - context: 0..4, - primary: None, - }], - cx, - ); - multibuffer.push_excerpts( - buffer_2.clone(), - [ExcerptRange { - context: 0..5, - primary: None, - }], - cx, - ); - multibuffer - }); - let old_snapshot = multibuffer.read(cx).snapshot(cx); - - assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0); - assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0); - assert_eq!(Anchor::min().to_offset(&old_snapshot), 0); - assert_eq!(Anchor::min().to_offset(&old_snapshot), 0); - assert_eq!(Anchor::max().to_offset(&old_snapshot), 10); - assert_eq!(Anchor::max().to_offset(&old_snapshot), 10); - - buffer_1.update(cx, |buffer, cx| { - buffer.edit([(0..0, "W")], None, cx); - buffer.edit([(5..5, "X")], None, cx); - }); - buffer_2.update(cx, |buffer, cx| { - buffer.edit([(0..0, "Y")], None, cx); - buffer.edit([(6..6, "Z")], None, cx); - }); - let new_snapshot = multibuffer.read(cx).snapshot(cx); - - assert_eq!(old_snapshot.text(), "abcd\nefghi"); - assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ"); - - assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0); - assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1); - assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2); - assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2); - assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3); - assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3); - assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7); - assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8); - assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13); - assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14); - } - - #[gpui::test] - fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut AppContext) { - let buffer_1 = cx.new_model(|cx| Buffer::local("abcd", cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local("ABCDEFGHIJKLMNOP", cx)); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - - // Create an insertion id in buffer 1 that doesn't exist in buffer 2. - // Add an excerpt from buffer 1 that spans this new insertion. - buffer_1.update(cx, |buffer, cx| buffer.edit([(4..4, "123")], None, cx)); - let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| { - multibuffer - .push_excerpts( - buffer_1.clone(), - [ExcerptRange { - context: 0..7, - primary: None, - }], - cx, - ) - .pop() - .unwrap() - }); - - let snapshot_1 = multibuffer.read(cx).snapshot(cx); - assert_eq!(snapshot_1.text(), "abcd123"); - - // Replace the buffer 1 excerpt with new excerpts from buffer 2. - let (excerpt_id_2, excerpt_id_3) = multibuffer.update(cx, |multibuffer, cx| { - multibuffer.remove_excerpts([excerpt_id_1], cx); - let mut ids = multibuffer - .push_excerpts( - buffer_2.clone(), - [ - ExcerptRange { - context: 0..4, - primary: None, - }, - ExcerptRange { - context: 6..10, - primary: None, - }, - ExcerptRange { - context: 12..16, - primary: None, - }, - ], - cx, - ) - .into_iter(); - (ids.next().unwrap(), ids.next().unwrap()) - }); - let snapshot_2 = multibuffer.read(cx).snapshot(cx); - assert_eq!(snapshot_2.text(), "ABCD\nGHIJ\nMNOP"); - - // The old excerpt id doesn't get reused. - assert_ne!(excerpt_id_2, excerpt_id_1); - - // Resolve some anchors from the previous snapshot in the new snapshot. - // The current excerpts are from a different buffer, so we don't attempt to - // resolve the old text anchor in the new buffer. - assert_eq!( - snapshot_2.summary_for_anchor::(&snapshot_1.anchor_before(2)), - 0 - ); - assert_eq!( - snapshot_2.summaries_for_anchors::(&[ - snapshot_1.anchor_before(2), - snapshot_1.anchor_after(3) - ]), - vec![0, 0] - ); - - // Refresh anchors from the old snapshot. The return value indicates that both - // anchors lost their original excerpt. - let refresh = - snapshot_2.refresh_anchors(&[snapshot_1.anchor_before(2), snapshot_1.anchor_after(3)]); - assert_eq!( - refresh, - &[ - (0, snapshot_2.anchor_before(0), false), - (1, snapshot_2.anchor_after(0), false), - ] - ); - - // Replace the middle excerpt with a smaller excerpt in buffer 2, - // that intersects the old excerpt. - let excerpt_id_5 = multibuffer.update(cx, |multibuffer, cx| { - multibuffer.remove_excerpts([excerpt_id_3], cx); - multibuffer - .insert_excerpts_after( - excerpt_id_2, - buffer_2.clone(), - [ExcerptRange { - context: 5..8, - primary: None, - }], - cx, - ) - .pop() - .unwrap() - }); - - let snapshot_3 = multibuffer.read(cx).snapshot(cx); - assert_eq!(snapshot_3.text(), "ABCD\nFGH\nMNOP"); - assert_ne!(excerpt_id_5, excerpt_id_3); - - // Resolve some anchors from the previous snapshot in the new snapshot. - // The third anchor can't be resolved, since its excerpt has been removed, - // so it resolves to the same position as its predecessor. - let anchors = [ - snapshot_2.anchor_before(0), - snapshot_2.anchor_after(2), - snapshot_2.anchor_after(6), - snapshot_2.anchor_after(14), - ]; - assert_eq!( - snapshot_3.summaries_for_anchors::(&anchors), - &[0, 2, 9, 13] - ); - - let new_anchors = snapshot_3.refresh_anchors(&anchors); - assert_eq!( - new_anchors.iter().map(|a| (a.0, a.2)).collect::>(), - &[(0, true), (1, true), (2, true), (3, true)] - ); - assert_eq!( - snapshot_3.summaries_for_anchors::(new_anchors.iter().map(|a| &a.1)), - &[0, 2, 7, 13] - ); - } - - #[gpui::test(iterations = 100)] - fn test_random_multibuffer(cx: &mut AppContext, mut rng: StdRng) { - let operations = env::var("OPERATIONS") - .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) - .unwrap_or(10); - - let mut buffers: Vec> = Vec::new(); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - let mut excerpt_ids = Vec::::new(); - let mut expected_excerpts = Vec::<(Model, Range)>::new(); - let mut anchors = Vec::new(); - let mut old_versions = Vec::new(); - - for _ in 0..operations { - match rng.gen_range(0..100) { - 0..=14 if !buffers.is_empty() => { - let buffer = buffers.choose(&mut rng).unwrap(); - buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx)); - } - 15..=19 if !expected_excerpts.is_empty() => { - multibuffer.update(cx, |multibuffer, cx| { - let ids = multibuffer.excerpt_ids(); - let mut excerpts = HashSet::default(); - for _ in 0..rng.gen_range(0..ids.len()) { - excerpts.extend(ids.choose(&mut rng).copied()); - } - - let line_count = rng.gen_range(0..5); - - let excerpt_ixs = excerpts - .iter() - .map(|id| excerpt_ids.iter().position(|i| i == id).unwrap()) - .collect::>(); - log::info!("Expanding excerpts {excerpt_ixs:?} by {line_count} lines"); - multibuffer.expand_excerpts( - excerpts.iter().cloned(), - line_count, - ExpandExcerptDirection::UpAndDown, - cx, - ); - - if line_count > 0 { - for id in excerpts { - let excerpt_ix = excerpt_ids.iter().position(|&i| i == id).unwrap(); - let (buffer, range) = &mut expected_excerpts[excerpt_ix]; - let snapshot = buffer.read(cx).snapshot(); - let mut point_range = range.to_point(&snapshot); - point_range.start = - Point::new(point_range.start.row.saturating_sub(line_count), 0); - point_range.end = snapshot.clip_point( - Point::new(point_range.end.row + line_count, 0), - Bias::Left, - ); - point_range.end.column = snapshot.line_len(point_range.end.row); - *range = snapshot.anchor_before(point_range.start) - ..snapshot.anchor_after(point_range.end); - } - } - }); - } - 20..=29 if !expected_excerpts.is_empty() => { - let mut ids_to_remove = vec![]; - for _ in 0..rng.gen_range(1..=3) { - if expected_excerpts.is_empty() { - break; - } - - let ix = rng.gen_range(0..expected_excerpts.len()); - ids_to_remove.push(excerpt_ids.remove(ix)); - let (buffer, range) = expected_excerpts.remove(ix); - let buffer = buffer.read(cx); - log::info!( - "Removing excerpt {}: {:?}", - ix, - buffer - .text_for_range(range.to_offset(buffer)) - .collect::(), - ); - } - let snapshot = multibuffer.read(cx).read(cx); - ids_to_remove.sort_unstable_by(|a, b| a.cmp(b, &snapshot)); - drop(snapshot); - multibuffer.update(cx, |multibuffer, cx| { - multibuffer.remove_excerpts(ids_to_remove, cx) - }); - } - 30..=39 if !expected_excerpts.is_empty() => { - let multibuffer = multibuffer.read(cx).read(cx); - let offset = - multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left); - let bias = if rng.gen() { Bias::Left } else { Bias::Right }; - log::info!("Creating anchor at {} with bias {:?}", offset, bias); - anchors.push(multibuffer.anchor_at(offset, bias)); - anchors.sort_by(|a, b| a.cmp(b, &multibuffer)); - } - 40..=44 if !anchors.is_empty() => { - let multibuffer = multibuffer.read(cx).read(cx); - let prev_len = anchors.len(); - anchors = multibuffer - .refresh_anchors(&anchors) - .into_iter() - .map(|a| a.1) - .collect(); - - // Ensure the newly-refreshed anchors point to a valid excerpt and don't - // overshoot its boundaries. - assert_eq!(anchors.len(), prev_len); - for anchor in &anchors { - if anchor.excerpt_id == ExcerptId::min() - || anchor.excerpt_id == ExcerptId::max() - { - continue; - } - - let excerpt = multibuffer.excerpt(anchor.excerpt_id).unwrap(); - assert_eq!(excerpt.id, anchor.excerpt_id); - assert!(excerpt.contains(anchor)); - } - } - _ => { - let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) { - let base_text = util::RandomCharIter::new(&mut rng) - .take(25) - .collect::(); - - buffers.push(cx.new_model(|cx| Buffer::local(base_text, cx))); - buffers.last().unwrap() - } else { - buffers.choose(&mut rng).unwrap() - }; - - let buffer = buffer_handle.read(cx); - let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right); - let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left); - let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix); - let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len()); - let prev_excerpt_id = excerpt_ids - .get(prev_excerpt_ix) - .cloned() - .unwrap_or_else(ExcerptId::max); - let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len()); - - log::info!( - "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}", - excerpt_ix, - expected_excerpts.len(), - buffer_handle.read(cx).remote_id(), - buffer.text(), - start_ix..end_ix, - &buffer.text()[start_ix..end_ix] - ); - - let excerpt_id = multibuffer.update(cx, |multibuffer, cx| { - multibuffer - .insert_excerpts_after( - prev_excerpt_id, - buffer_handle.clone(), - [ExcerptRange { - context: start_ix..end_ix, - primary: None, - }], - cx, - ) - .pop() - .unwrap() - }); - - excerpt_ids.insert(excerpt_ix, excerpt_id); - expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range)); - } - } - - if rng.gen_bool(0.3) { - multibuffer.update(cx, |multibuffer, cx| { - old_versions.push((multibuffer.snapshot(cx), multibuffer.subscribe())); - }) - } - - let snapshot = multibuffer.read(cx).snapshot(cx); - - let mut excerpt_starts = Vec::new(); - let mut expected_text = String::new(); - let mut expected_buffer_rows = Vec::new(); - for (buffer, range) in &expected_excerpts { - let buffer = buffer.read(cx); - let buffer_range = range.to_offset(buffer); - - excerpt_starts.push(TextSummary::from(expected_text.as_str())); - expected_text.extend(buffer.text_for_range(buffer_range.clone())); - expected_text.push('\n'); - - let buffer_row_range = buffer.offset_to_point(buffer_range.start).row - ..=buffer.offset_to_point(buffer_range.end).row; - for row in buffer_row_range { - expected_buffer_rows.push(Some(row)); - } - } - // Remove final trailing newline. - if !expected_excerpts.is_empty() { - expected_text.pop(); - } - - // Always report one buffer row - if expected_buffer_rows.is_empty() { - expected_buffer_rows.push(Some(0)); - } - - assert_eq!(snapshot.text(), expected_text); - log::info!("MultiBuffer text: {:?}", expected_text); - - assert_eq!( - snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), - expected_buffer_rows, - ); - - for _ in 0..5 { - let start_row = rng.gen_range(0..=expected_buffer_rows.len()); - assert_eq!( - snapshot - .buffer_rows(MultiBufferRow(start_row as u32)) - .collect::>(), - &expected_buffer_rows[start_row..], - "buffer_rows({})", - start_row - ); - } - - assert_eq!( - snapshot.max_buffer_row().0, - expected_buffer_rows.into_iter().flatten().max().unwrap() - ); - - let mut excerpt_starts = excerpt_starts.into_iter(); - for (buffer, range) in &expected_excerpts { - let buffer = buffer.read(cx); - let buffer_id = buffer.remote_id(); - let buffer_range = range.to_offset(buffer); - let buffer_start_point = buffer.offset_to_point(buffer_range.start); - let buffer_start_point_utf16 = - buffer.text_summary_for_range::(0..buffer_range.start); - - let excerpt_start = excerpt_starts.next().unwrap(); - let mut offset = excerpt_start.len; - let mut buffer_offset = buffer_range.start; - let mut point = excerpt_start.lines; - let mut buffer_point = buffer_start_point; - let mut point_utf16 = excerpt_start.lines_utf16(); - let mut buffer_point_utf16 = buffer_start_point_utf16; - for ch in buffer - .snapshot() - .chunks(buffer_range.clone(), false) - .flat_map(|c| c.text.chars()) - { - for _ in 0..ch.len_utf8() { - let left_offset = snapshot.clip_offset(offset, Bias::Left); - let right_offset = snapshot.clip_offset(offset, Bias::Right); - let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left); - let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right); - assert_eq!( - left_offset, - excerpt_start.len + (buffer_left_offset - buffer_range.start), - "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}", - offset, - buffer_id, - buffer_offset, - ); - assert_eq!( - right_offset, - excerpt_start.len + (buffer_right_offset - buffer_range.start), - "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}", - offset, - buffer_id, - buffer_offset, - ); - - let left_point = snapshot.clip_point(point, Bias::Left); - let right_point = snapshot.clip_point(point, Bias::Right); - let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left); - let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right); - assert_eq!( - left_point, - excerpt_start.lines + (buffer_left_point - buffer_start_point), - "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}", - point, - buffer_id, - buffer_point, - ); - assert_eq!( - right_point, - excerpt_start.lines + (buffer_right_point - buffer_start_point), - "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}", - point, - buffer_id, - buffer_point, - ); - - assert_eq!( - snapshot.point_to_offset(left_point), - left_offset, - "point_to_offset({:?})", - left_point, - ); - assert_eq!( - snapshot.offset_to_point(left_offset), - left_point, - "offset_to_point({:?})", - left_offset, - ); - - offset += 1; - buffer_offset += 1; - if ch == '\n' { - point += Point::new(1, 0); - buffer_point += Point::new(1, 0); - } else { - point += Point::new(0, 1); - buffer_point += Point::new(0, 1); - } - } - - for _ in 0..ch.len_utf16() { - let left_point_utf16 = - snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Left); - let right_point_utf16 = - snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Right); - let buffer_left_point_utf16 = - buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Left); - let buffer_right_point_utf16 = - buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Right); - assert_eq!( - left_point_utf16, - excerpt_start.lines_utf16() - + (buffer_left_point_utf16 - buffer_start_point_utf16), - "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}", - point_utf16, - buffer_id, - buffer_point_utf16, - ); - assert_eq!( - right_point_utf16, - excerpt_start.lines_utf16() - + (buffer_right_point_utf16 - buffer_start_point_utf16), - "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}", - point_utf16, - buffer_id, - buffer_point_utf16, - ); - - if ch == '\n' { - point_utf16 += PointUtf16::new(1, 0); - buffer_point_utf16 += PointUtf16::new(1, 0); - } else { - point_utf16 += PointUtf16::new(0, 1); - buffer_point_utf16 += PointUtf16::new(0, 1); - } - } - } - } - - for (row, line) in expected_text.split('\n').enumerate() { - assert_eq!( - snapshot.line_len(MultiBufferRow(row as u32)), - line.len() as u32, - "line_len({}).", - row - ); - } - - let text_rope = Rope::from(expected_text.as_str()); - for _ in 0..10 { - let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right); - let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left); - - let text_for_range = snapshot - .text_for_range(start_ix..end_ix) - .collect::(); - assert_eq!( - text_for_range, - &expected_text[start_ix..end_ix], - "incorrect text for range {:?}", - start_ix..end_ix - ); - - let excerpted_buffer_ranges = multibuffer - .read(cx) - .range_to_buffer_ranges(start_ix..end_ix, cx); - let excerpted_buffers_text = excerpted_buffer_ranges - .iter() - .map(|(buffer, buffer_range, _)| { - buffer - .read(cx) - .text_for_range(buffer_range.clone()) - .collect::() - }) - .collect::>() - .join("\n"); - assert_eq!(excerpted_buffers_text, text_for_range); - if !expected_excerpts.is_empty() { - assert!(!excerpted_buffer_ranges.is_empty()); - } - - let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]); - assert_eq!( - snapshot.text_summary_for_range::(start_ix..end_ix), - expected_summary, - "incorrect summary for range {:?}", - start_ix..end_ix - ); - } - - // Anchor resolution - let summaries = snapshot.summaries_for_anchors::(&anchors); - assert_eq!(anchors.len(), summaries.len()); - for (anchor, resolved_offset) in anchors.iter().zip(summaries) { - assert!(resolved_offset <= snapshot.len()); - assert_eq!( - snapshot.summary_for_anchor::(anchor), - resolved_offset - ); - } - - for _ in 0..10 { - let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right); - assert_eq!( - snapshot.reversed_chars_at(end_ix).collect::(), - expected_text[..end_ix].chars().rev().collect::(), - ); - } - - for _ in 0..10 { - let end_ix = rng.gen_range(0..=text_rope.len()); - let start_ix = rng.gen_range(0..=end_ix); - assert_eq!( - snapshot - .bytes_in_range(start_ix..end_ix) - .flatten() - .copied() - .collect::>(), - expected_text.as_bytes()[start_ix..end_ix].to_vec(), - "bytes_in_range({:?})", - start_ix..end_ix, - ); - } - } - - let snapshot = multibuffer.read(cx).snapshot(cx); - for (old_snapshot, subscription) in old_versions { - let edits = subscription.consume().into_inner(); - - log::info!( - "applying subscription edits to old text: {:?}: {:?}", - old_snapshot.text(), - edits, - ); - - let mut text = old_snapshot.text(); - for edit in edits { - let new_text: String = snapshot.text_for_range(edit.new.clone()).collect(); - text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text); - } - assert_eq!(text.to_string(), snapshot.text()); - } - } - - #[gpui::test] - fn test_history(cx: &mut AppContext) { - let test_settings = SettingsStore::test(cx); - cx.set_global(test_settings); - - let buffer_1 = cx.new_model(|cx| Buffer::local("1234", cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local("5678", cx)); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - let group_interval = multibuffer.read(cx).history.group_interval; - multibuffer.update(cx, |multibuffer, cx| { - multibuffer.push_excerpts( - buffer_1.clone(), - [ExcerptRange { - context: 0..buffer_1.read(cx).len(), - primary: None, - }], - cx, - ); - multibuffer.push_excerpts( - buffer_2.clone(), - [ExcerptRange { - context: 0..buffer_2.read(cx).len(), - primary: None, - }], - cx, - ); - }); - - let mut now = Instant::now(); - - multibuffer.update(cx, |multibuffer, cx| { - let transaction_1 = multibuffer.start_transaction_at(now, cx).unwrap(); - multibuffer.edit( - [ - (Point::new(0, 0)..Point::new(0, 0), "A"), - (Point::new(1, 0)..Point::new(1, 0), "A"), - ], - None, - cx, - ); - multibuffer.edit( - [ - (Point::new(0, 1)..Point::new(0, 1), "B"), - (Point::new(1, 1)..Point::new(1, 1), "B"), - ], - None, - cx, - ); - multibuffer.end_transaction_at(now, cx); - assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678"); - - // Verify edited ranges for transaction 1 - assert_eq!( - multibuffer.edited_ranges_for_transaction(transaction_1, cx), - &[ - Point::new(0, 0)..Point::new(0, 2), - Point::new(1, 0)..Point::new(1, 2) - ] - ); - - // Edit buffer 1 through the multibuffer - now += 2 * group_interval; - multibuffer.start_transaction_at(now, cx); - multibuffer.edit([(2..2, "C")], None, cx); - multibuffer.end_transaction_at(now, cx); - assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678"); - - // Edit buffer 1 independently - buffer_1.update(cx, |buffer_1, cx| { - buffer_1.start_transaction_at(now); - buffer_1.edit([(3..3, "D")], None, cx); - buffer_1.end_transaction_at(now, cx); - - now += 2 * group_interval; - buffer_1.start_transaction_at(now); - buffer_1.edit([(4..4, "E")], None, cx); - buffer_1.end_transaction_at(now, cx); - }); - assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678"); - - // An undo in the multibuffer undoes the multibuffer transaction - // and also any individual buffer edits that have occurred since - // that transaction. - multibuffer.undo(cx); - assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678"); - - multibuffer.undo(cx); - assert_eq!(multibuffer.read(cx).text(), "1234\n5678"); - - multibuffer.redo(cx); - assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678"); - - multibuffer.redo(cx); - assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678"); - - // Undo buffer 2 independently. - buffer_2.update(cx, |buffer_2, cx| buffer_2.undo(cx)); - assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\n5678"); - - // An undo in the multibuffer undoes the components of the - // the last multibuffer transaction that are not already undone. - multibuffer.undo(cx); - assert_eq!(multibuffer.read(cx).text(), "AB1234\n5678"); - - multibuffer.undo(cx); - assert_eq!(multibuffer.read(cx).text(), "1234\n5678"); - - multibuffer.redo(cx); - assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678"); - - buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx)); - assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678"); - - // Redo stack gets cleared after an edit. - now += 2 * group_interval; - multibuffer.start_transaction_at(now, cx); - multibuffer.edit([(0..0, "X")], None, cx); - multibuffer.end_transaction_at(now, cx); - assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); - multibuffer.redo(cx); - assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); - multibuffer.undo(cx); - assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678"); - multibuffer.undo(cx); - assert_eq!(multibuffer.read(cx).text(), "1234\n5678"); - - // Transactions can be grouped manually. - multibuffer.redo(cx); - multibuffer.redo(cx); - assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); - multibuffer.group_until_transaction(transaction_1, cx); - multibuffer.undo(cx); - assert_eq!(multibuffer.read(cx).text(), "1234\n5678"); - multibuffer.redo(cx); - assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); - }); - } - - #[gpui::test] - fn test_excerpts_in_ranges_no_ranges(cx: &mut AppContext) { - let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - multibuffer.update(cx, |multibuffer, cx| { - multibuffer.push_excerpts( - buffer_1.clone(), - [ExcerptRange { - context: 0..buffer_1.read(cx).len(), - primary: None, - }], - cx, - ); - multibuffer.push_excerpts( - buffer_2.clone(), - [ExcerptRange { - context: 0..buffer_2.read(cx).len(), - primary: None, - }], - cx, - ); - }); - - let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx)); - - let mut excerpts = snapshot.excerpts_in_ranges(iter::from_fn(|| None)); - - assert!(excerpts.next().is_none()); - } - - fn validate_excerpts( - actual: &[(ExcerptId, BufferId, Range)], - expected: &Vec<(ExcerptId, BufferId, Range)>, - ) { - assert_eq!(actual.len(), expected.len()); - - actual - .iter() - .zip(expected) - .map(|(actual, expected)| { - assert_eq!(actual.0, expected.0); - assert_eq!(actual.1, expected.1); - assert_eq!(actual.2.start, expected.2.start); - assert_eq!(actual.2.end, expected.2.end); - }) - .collect_vec(); - } - - fn map_range_from_excerpt( - snapshot: &MultiBufferSnapshot, - excerpt_id: ExcerptId, - excerpt_buffer: &BufferSnapshot, - range: Range, - ) -> Range { - snapshot - .anchor_in_excerpt(excerpt_id, excerpt_buffer.anchor_before(range.start)) - .unwrap() - ..snapshot - .anchor_in_excerpt(excerpt_id, excerpt_buffer.anchor_after(range.end)) - .unwrap() - } - - fn make_expected_excerpt_info( - snapshot: &MultiBufferSnapshot, - cx: &mut AppContext, - excerpt_id: ExcerptId, - buffer: &Model, - range: Range, - ) -> (ExcerptId, BufferId, Range) { - ( - excerpt_id, - buffer.read(cx).remote_id(), - map_range_from_excerpt(snapshot, excerpt_id, &buffer.read(cx).snapshot(), range), - ) - } - - #[gpui::test] - fn test_excerpts_in_ranges_range_inside_the_excerpt(cx: &mut AppContext) { - let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); - let buffer_len = buffer_1.read(cx).len(); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - let mut expected_excerpt_id = ExcerptId(0); - - multibuffer.update(cx, |multibuffer, cx| { - expected_excerpt_id = multibuffer.push_excerpts( - buffer_1.clone(), - [ExcerptRange { - context: 0..buffer_1.read(cx).len(), - primary: None, - }], - cx, - )[0]; - multibuffer.push_excerpts( - buffer_2.clone(), - [ExcerptRange { - context: 0..buffer_2.read(cx).len(), - primary: None, - }], - cx, - ); - }); - - let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx)); - - let range = snapshot - .anchor_in_excerpt(expected_excerpt_id, buffer_1.read(cx).anchor_before(1)) - .unwrap() - ..snapshot - .anchor_in_excerpt( - expected_excerpt_id, - buffer_1.read(cx).anchor_after(buffer_len / 2), - ) - .unwrap(); - - let expected_excerpts = vec![make_expected_excerpt_info( - &snapshot, - cx, - expected_excerpt_id, - &buffer_1, - 1..(buffer_len / 2), - )]; - - let excerpts = snapshot - .excerpts_in_ranges(vec![range.clone()].into_iter()) - .map(|(excerpt_id, buffer, actual_range)| { - ( - excerpt_id, - buffer.remote_id(), - map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range), - ) - }) - .collect_vec(); - - validate_excerpts(&excerpts, &expected_excerpts); - } - - #[gpui::test] - fn test_excerpts_in_ranges_range_crosses_excerpts_boundary(cx: &mut AppContext) { - let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); - let buffer_len = buffer_1.read(cx).len(); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - let mut excerpt_1_id = ExcerptId(0); - let mut excerpt_2_id = ExcerptId(0); - - multibuffer.update(cx, |multibuffer, cx| { - excerpt_1_id = multibuffer.push_excerpts( - buffer_1.clone(), - [ExcerptRange { - context: 0..buffer_1.read(cx).len(), - primary: None, - }], - cx, - )[0]; - excerpt_2_id = multibuffer.push_excerpts( - buffer_2.clone(), - [ExcerptRange { - context: 0..buffer_2.read(cx).len(), - primary: None, - }], - cx, - )[0]; - }); - - let snapshot = multibuffer.read(cx).snapshot(cx); - - let expected_range = snapshot - .anchor_in_excerpt( - excerpt_1_id, - buffer_1.read(cx).anchor_before(buffer_len / 2), - ) - .unwrap() - ..snapshot - .anchor_in_excerpt(excerpt_2_id, buffer_2.read(cx).anchor_after(buffer_len / 2)) - .unwrap(); - - let expected_excerpts = vec![ - make_expected_excerpt_info( - &snapshot, - cx, - excerpt_1_id, - &buffer_1, - (buffer_len / 2)..buffer_len, - ), - make_expected_excerpt_info(&snapshot, cx, excerpt_2_id, &buffer_2, 0..buffer_len / 2), - ]; - - let excerpts = snapshot - .excerpts_in_ranges(vec![expected_range.clone()].into_iter()) - .map(|(excerpt_id, buffer, actual_range)| { - ( - excerpt_id, - buffer.remote_id(), - map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range), - ) - }) - .collect_vec(); - - validate_excerpts(&excerpts, &expected_excerpts); - } - - #[gpui::test] - fn test_excerpts_in_ranges_range_encloses_excerpt(cx: &mut AppContext) { - let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); - let buffer_3 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'r'), cx)); - let buffer_len = buffer_1.read(cx).len(); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - let mut excerpt_1_id = ExcerptId(0); - let mut excerpt_2_id = ExcerptId(0); - let mut excerpt_3_id = ExcerptId(0); - - multibuffer.update(cx, |multibuffer, cx| { - excerpt_1_id = multibuffer.push_excerpts( - buffer_1.clone(), - [ExcerptRange { - context: 0..buffer_1.read(cx).len(), - primary: None, - }], - cx, - )[0]; - excerpt_2_id = multibuffer.push_excerpts( - buffer_2.clone(), - [ExcerptRange { - context: 0..buffer_2.read(cx).len(), - primary: None, - }], - cx, - )[0]; - excerpt_3_id = multibuffer.push_excerpts( - buffer_3.clone(), - [ExcerptRange { - context: 0..buffer_3.read(cx).len(), - primary: None, - }], - cx, - )[0]; - }); - - let snapshot = multibuffer.read(cx).snapshot(cx); - - let expected_range = snapshot - .anchor_in_excerpt( - excerpt_1_id, - buffer_1.read(cx).anchor_before(buffer_len / 2), - ) - .unwrap() - ..snapshot - .anchor_in_excerpt(excerpt_3_id, buffer_3.read(cx).anchor_after(buffer_len / 2)) - .unwrap(); - - let expected_excerpts = vec![ - make_expected_excerpt_info( - &snapshot, - cx, - excerpt_1_id, - &buffer_1, - (buffer_len / 2)..buffer_len, - ), - make_expected_excerpt_info(&snapshot, cx, excerpt_2_id, &buffer_2, 0..buffer_len), - make_expected_excerpt_info(&snapshot, cx, excerpt_3_id, &buffer_3, 0..buffer_len / 2), - ]; - - let excerpts = snapshot - .excerpts_in_ranges(vec![expected_range.clone()].into_iter()) - .map(|(excerpt_id, buffer, actual_range)| { - ( - excerpt_id, - buffer.remote_id(), - map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range), - ) - }) - .collect_vec(); - - validate_excerpts(&excerpts, &expected_excerpts); - } - - #[gpui::test] - fn test_excerpts_in_ranges_multiple_ranges(cx: &mut AppContext) { - let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); - let buffer_len = buffer_1.read(cx).len(); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - let mut excerpt_1_id = ExcerptId(0); - let mut excerpt_2_id = ExcerptId(0); - - multibuffer.update(cx, |multibuffer, cx| { - excerpt_1_id = multibuffer.push_excerpts( - buffer_1.clone(), - [ExcerptRange { - context: 0..buffer_1.read(cx).len(), - primary: None, - }], - cx, - )[0]; - excerpt_2_id = multibuffer.push_excerpts( - buffer_2.clone(), - [ExcerptRange { - context: 0..buffer_2.read(cx).len(), - primary: None, - }], - cx, - )[0]; - }); - - let snapshot = multibuffer.read(cx).snapshot(cx); - - let ranges = vec![ - 1..(buffer_len / 4), - (buffer_len / 3)..(buffer_len / 2), - (buffer_len / 4 * 3)..(buffer_len), - ]; - - let expected_excerpts = ranges - .iter() - .map(|range| { - make_expected_excerpt_info(&snapshot, cx, excerpt_1_id, &buffer_1, range.clone()) - }) - .collect_vec(); - - let ranges = ranges.into_iter().map(|range| { - map_range_from_excerpt( - &snapshot, - excerpt_1_id, - &buffer_1.read(cx).snapshot(), - range, - ) - }); - - let excerpts = snapshot - .excerpts_in_ranges(ranges) - .map(|(excerpt_id, buffer, actual_range)| { - ( - excerpt_id, - buffer.remote_id(), - map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range), - ) - }) - .collect_vec(); - - validate_excerpts(&excerpts, &expected_excerpts); - } - - #[gpui::test] - fn test_excerpts_in_ranges_range_ends_at_excerpt_end(cx: &mut AppContext) { - let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); - let buffer_len = buffer_1.read(cx).len(); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - let mut excerpt_1_id = ExcerptId(0); - let mut excerpt_2_id = ExcerptId(0); - - multibuffer.update(cx, |multibuffer, cx| { - excerpt_1_id = multibuffer.push_excerpts( - buffer_1.clone(), - [ExcerptRange { - context: 0..buffer_1.read(cx).len(), - primary: None, - }], - cx, - )[0]; - excerpt_2_id = multibuffer.push_excerpts( - buffer_2.clone(), - [ExcerptRange { - context: 0..buffer_2.read(cx).len(), - primary: None, - }], - cx, - )[0]; - }); - - let snapshot = multibuffer.read(cx).snapshot(cx); - - let ranges = [0..buffer_len, (buffer_len / 3)..(buffer_len / 2)]; - - let expected_excerpts = vec![ - make_expected_excerpt_info(&snapshot, cx, excerpt_1_id, &buffer_1, ranges[0].clone()), - make_expected_excerpt_info(&snapshot, cx, excerpt_2_id, &buffer_2, ranges[1].clone()), - ]; - - let ranges = [ - map_range_from_excerpt( - &snapshot, - excerpt_1_id, - &buffer_1.read(cx).snapshot(), - ranges[0].clone(), - ), - map_range_from_excerpt( - &snapshot, - excerpt_2_id, - &buffer_2.read(cx).snapshot(), - ranges[1].clone(), - ), - ]; - - let excerpts = snapshot - .excerpts_in_ranges(ranges.into_iter()) - .map(|(excerpt_id, buffer, actual_range)| { - ( - excerpt_id, - buffer.remote_id(), - map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range), - ) - }) - .collect_vec(); - - validate_excerpts(&excerpts, &expected_excerpts); - } - - #[gpui::test] - fn test_split_ranges(cx: &mut AppContext) { - let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - multibuffer.update(cx, |multibuffer, cx| { - multibuffer.push_excerpts( - buffer_1.clone(), - [ExcerptRange { - context: 0..buffer_1.read(cx).len(), - primary: None, - }], - cx, - ); - multibuffer.push_excerpts( - buffer_2.clone(), - [ExcerptRange { - context: 0..buffer_2.read(cx).len(), - primary: None, - }], - cx, - ); - }); - - let snapshot = multibuffer.read(cx).snapshot(cx); - - let buffer_1_len = buffer_1.read(cx).len(); - let buffer_2_len = buffer_2.read(cx).len(); - let buffer_1_midpoint = buffer_1_len / 2; - let buffer_2_start = buffer_1_len + '\n'.len_utf8(); - let buffer_2_midpoint = buffer_2_start + buffer_2_len / 2; - let total_len = buffer_2_start + buffer_2_len; - - let input_ranges = [ - 0..buffer_1_midpoint, - buffer_1_midpoint..buffer_2_midpoint, - buffer_2_midpoint..total_len, - ] - .map(|range| snapshot.anchor_before(range.start)..snapshot.anchor_after(range.end)); - - let actual_ranges = snapshot - .split_ranges(input_ranges.into_iter()) - .map(|range| range.to_offset(&snapshot)) - .collect::>(); - - let expected_ranges = vec![ - 0..buffer_1_midpoint, - buffer_1_midpoint..buffer_1_len, - buffer_2_start..buffer_2_midpoint, - buffer_2_midpoint..total_len, - ]; - - assert_eq!(actual_ranges, expected_ranges); - } - - #[gpui::test] - fn test_split_ranges_single_range_spanning_three_excerpts(cx: &mut AppContext) { - let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); - let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); - let buffer_3 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'm'), cx)); - let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); - multibuffer.update(cx, |multibuffer, cx| { - multibuffer.push_excerpts( - buffer_1.clone(), - [ExcerptRange { - context: 0..buffer_1.read(cx).len(), - primary: None, - }], - cx, - ); - multibuffer.push_excerpts( - buffer_2.clone(), - [ExcerptRange { - context: 0..buffer_2.read(cx).len(), - primary: None, - }], - cx, - ); - multibuffer.push_excerpts( - buffer_3.clone(), - [ExcerptRange { - context: 0..buffer_3.read(cx).len(), - primary: None, - }], - cx, - ); - }); - - let snapshot = multibuffer.read(cx).snapshot(cx); - - let buffer_1_len = buffer_1.read(cx).len(); - let buffer_2_len = buffer_2.read(cx).len(); - let buffer_3_len = buffer_3.read(cx).len(); - let buffer_2_start = buffer_1_len + '\n'.len_utf8(); - let buffer_3_start = buffer_2_start + buffer_2_len + '\n'.len_utf8(); - let buffer_1_midpoint = buffer_1_len / 2; - let buffer_3_midpoint = buffer_3_start + buffer_3_len / 2; - - let input_range = - snapshot.anchor_before(buffer_1_midpoint)..snapshot.anchor_after(buffer_3_midpoint); - - let actual_ranges = snapshot - .split_ranges(std::iter::once(input_range)) - .map(|range| range.to_offset(&snapshot)) - .collect::>(); - - let expected_ranges = vec![ - buffer_1_midpoint..buffer_1_len, - buffer_2_start..buffer_2_start + buffer_2_len, - buffer_3_start..buffer_3_midpoint, - ]; - - assert_eq!(actual_ranges, expected_ranges); - } -} +// #[cfg(test)] +// mod tests { +// use super::*; +// use futures::StreamExt; +// use gpui::{AppContext, Context, TestAppContext}; +// use language::{Buffer, Rope}; +// use parking_lot::RwLock; +// use rand::prelude::*; +// use settings::SettingsStore; +// use std::env; +// use util::test::sample_text; + +// #[ctor::ctor] +// fn init_logger() { +// if std::env::var("RUST_LOG").is_ok() { +// env_logger::init(); +// } +// } + +// #[gpui::test] +// fn test_singleton(cx: &mut AppContext) { +// let buffer = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); +// let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx)); + +// let snapshot = multibuffer.read(cx).snapshot(cx); +// assert_eq!(snapshot.text(), buffer.read(cx).text()); + +// assert_eq!( +// snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), +// (0..buffer.read(cx).row_count()) +// .map(Some) +// .collect::>() +// ); + +// buffer.update(cx, |buffer, cx| buffer.edit([(1..3, "XXX\n")], None, cx)); +// let snapshot = multibuffer.read(cx).snapshot(cx); + +// assert_eq!(snapshot.text(), buffer.read(cx).text()); +// assert_eq!( +// snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), +// (0..buffer.read(cx).row_count()) +// .map(Some) +// .collect::>() +// ); +// } + +// #[gpui::test] +// fn test_remote(cx: &mut AppContext) { +// let host_buffer = cx.new_model(|cx| Buffer::local("a", cx)); +// let guest_buffer = cx.new_model(|cx| { +// let state = host_buffer.read(cx).to_proto(cx); +// let ops = cx +// .background_executor() +// .block(host_buffer.read(cx).serialize_ops(None, cx)); +// let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap(); +// buffer.apply_ops( +// ops.into_iter() +// .map(|op| language::proto::deserialize_operation(op).unwrap()), +// cx, +// ); +// buffer +// }); +// let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(guest_buffer.clone(), cx)); +// let snapshot = multibuffer.read(cx).snapshot(cx); +// assert_eq!(snapshot.text(), "a"); + +// guest_buffer.update(cx, |buffer, cx| buffer.edit([(1..1, "b")], None, cx)); +// let snapshot = multibuffer.read(cx).snapshot(cx); +// assert_eq!(snapshot.text(), "ab"); + +// guest_buffer.update(cx, |buffer, cx| buffer.edit([(2..2, "c")], None, cx)); +// let snapshot = multibuffer.read(cx).snapshot(cx); +// assert_eq!(snapshot.text(), "abc"); +// } + +// #[gpui::test] +// fn test_excerpt_boundaries_and_clipping(cx: &mut AppContext) { +// let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); +// let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); + +// let events = Arc::new(RwLock::new(Vec::::new())); +// multibuffer.update(cx, |_, cx| { +// let events = events.clone(); +// cx.subscribe(&multibuffer, move |_, _, event, _| { +// if let Event::Edited { .. } = event { +// events.write().push(event.clone()) +// } +// }) +// .detach(); +// }); + +// let subscription = multibuffer.update(cx, |multibuffer, cx| { +// let subscription = multibuffer.subscribe(); +// multibuffer.push_excerpts( +// buffer_1.clone(), +// [ExcerptRange { +// context: Point::new(1, 2)..Point::new(2, 5), +// primary: None, +// }], +// cx, +// ); +// assert_eq!( +// subscription.consume().into_inner(), +// [Edit { +// old: 0..0, +// new: 0..10 +// }] +// ); + +// multibuffer.push_excerpts( +// buffer_1.clone(), +// [ExcerptRange { +// context: Point::new(3, 3)..Point::new(4, 4), +// primary: None, +// }], +// cx, +// ); +// multibuffer.push_excerpts( +// buffer_2.clone(), +// [ExcerptRange { +// context: Point::new(3, 1)..Point::new(3, 3), +// primary: None, +// }], +// cx, +// ); +// assert_eq!( +// subscription.consume().into_inner(), +// [Edit { +// old: 10..10, +// new: 10..22 +// }] +// ); + +// subscription +// }); + +// // Adding excerpts emits an edited event. +// assert_eq!( +// events.read().as_slice(), +// &[ +// Event::Edited { +// singleton_buffer_edited: false +// }, +// Event::Edited { +// singleton_buffer_edited: false +// }, +// Event::Edited { +// singleton_buffer_edited: false +// } +// ] +// ); + +// let snapshot = multibuffer.read(cx).snapshot(cx); +// assert_eq!( +// snapshot.text(), +// concat!( +// "bbbb\n", // Preserve newlines +// "ccccc\n", // +// "ddd\n", // +// "eeee\n", // +// "jj" // +// ) +// ); +// assert_eq!( +// snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), +// [Some(1), Some(2), Some(3), Some(4), Some(3)] +// ); +// assert_eq!( +// snapshot.buffer_rows(MultiBufferRow(2)).collect::>(), +// [Some(3), Some(4), Some(3)] +// ); +// assert_eq!( +// snapshot.buffer_rows(MultiBufferRow(4)).collect::>(), +// [Some(3)] +// ); +// assert_eq!( +// snapshot.buffer_rows(MultiBufferRow(5)).collect::>(), +// [] +// ); + +// assert_eq!( +// boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot), +// &[ +// (MultiBufferRow(0), "bbbb\nccccc".to_string(), true), +// (MultiBufferRow(2), "ddd\neeee".to_string(), false), +// (MultiBufferRow(4), "jj".to_string(), true), +// ] +// ); +// assert_eq!( +// boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot), +// &[(MultiBufferRow(0), "bbbb\nccccc".to_string(), true)] +// ); +// assert_eq!( +// boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot), +// &[] +// ); +// assert_eq!( +// boundaries_in_range(Point::new(1, 0)..Point::new(2, 0), &snapshot), +// &[] +// ); +// assert_eq!( +// boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot), +// &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)] +// ); +// assert_eq!( +// boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot), +// &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)] +// ); +// assert_eq!( +// boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot), +// &[(MultiBufferRow(2), "ddd\neeee".to_string(), false)] +// ); +// assert_eq!( +// boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot), +// &[(MultiBufferRow(4), "jj".to_string(), true)] +// ); +// assert_eq!( +// boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot), +// &[] +// ); + +// buffer_1.update(cx, |buffer, cx| { +// let text = "\n"; +// buffer.edit( +// [ +// (Point::new(0, 0)..Point::new(0, 0), text), +// (Point::new(2, 1)..Point::new(2, 3), text), +// ], +// None, +// cx, +// ); +// }); + +// let snapshot = multibuffer.read(cx).snapshot(cx); +// assert_eq!( +// snapshot.text(), +// concat!( +// "bbbb\n", // Preserve newlines +// "c\n", // +// "cc\n", // +// "ddd\n", // +// "eeee\n", // +// "jj" // +// ) +// ); + +// assert_eq!( +// subscription.consume().into_inner(), +// [Edit { +// old: 6..8, +// new: 6..7 +// }] +// ); + +// let snapshot = multibuffer.read(cx).snapshot(cx); +// assert_eq!( +// snapshot.clip_point(Point::new(0, 5), Bias::Left), +// Point::new(0, 4) +// ); +// assert_eq!( +// snapshot.clip_point(Point::new(0, 5), Bias::Right), +// Point::new(0, 4) +// ); +// assert_eq!( +// snapshot.clip_point(Point::new(5, 1), Bias::Right), +// Point::new(5, 1) +// ); +// assert_eq!( +// snapshot.clip_point(Point::new(5, 2), Bias::Right), +// Point::new(5, 2) +// ); +// assert_eq!( +// snapshot.clip_point(Point::new(5, 3), Bias::Right), +// Point::new(5, 2) +// ); + +// let snapshot = multibuffer.update(cx, |multibuffer, cx| { +// let (buffer_2_excerpt_id, _) = +// multibuffer.excerpts_for_buffer(&buffer_2, cx)[0].clone(); +// multibuffer.remove_excerpts([buffer_2_excerpt_id], cx); +// multibuffer.snapshot(cx) +// }); + +// assert_eq!( +// snapshot.text(), +// concat!( +// "bbbb\n", // Preserve newlines +// "c\n", // +// "cc\n", // +// "ddd\n", // +// "eeee", // +// ) +// ); + +// fn boundaries_in_range( +// range: Range, +// snapshot: &MultiBufferSnapshot, +// ) -> Vec<(MultiBufferRow, String, bool)> { +// snapshot +// .excerpt_boundaries_in_range(range) +// .filter_map(|boundary| { +// let starts_new_buffer = boundary.starts_new_buffer(); +// boundary.next.map(|next| { +// ( +// boundary.row, +// next.buffer +// .text_for_range(next.range.context) +// .collect::(), +// starts_new_buffer, +// ) +// }) +// }) +// .collect::>() +// } +// } + +// #[gpui::test] +// fn test_excerpt_events(cx: &mut AppContext) { +// let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(10, 3, 'a'), cx)); +// let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(10, 3, 'm'), cx)); + +// let leader_multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// let follower_multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// let follower_edit_event_count = Arc::new(RwLock::new(0)); + +// follower_multibuffer.update(cx, |_, cx| { +// let follower_edit_event_count = follower_edit_event_count.clone(); +// cx.subscribe( +// &leader_multibuffer, +// move |follower, _, event, cx| match event.clone() { +// Event::ExcerptsAdded { +// buffer, +// predecessor, +// excerpts, +// } => follower.insert_excerpts_with_ids_after(predecessor, buffer, excerpts, cx), +// Event::ExcerptsRemoved { ids } => follower.remove_excerpts(ids, cx), +// Event::Edited { .. } => { +// *follower_edit_event_count.write() += 1; +// } +// _ => {} +// }, +// ) +// .detach(); +// }); + +// leader_multibuffer.update(cx, |leader, cx| { +// leader.push_excerpts( +// buffer_1.clone(), +// [ +// ExcerptRange { +// context: 0..8, +// primary: None, +// }, +// ExcerptRange { +// context: 12..16, +// primary: None, +// }, +// ], +// cx, +// ); +// leader.insert_excerpts_after( +// leader.excerpt_ids()[0], +// buffer_2.clone(), +// [ +// ExcerptRange { +// context: 0..5, +// primary: None, +// }, +// ExcerptRange { +// context: 10..15, +// primary: None, +// }, +// ], +// cx, +// ) +// }); +// assert_eq!( +// leader_multibuffer.read(cx).snapshot(cx).text(), +// follower_multibuffer.read(cx).snapshot(cx).text(), +// ); +// assert_eq!(*follower_edit_event_count.read(), 2); + +// leader_multibuffer.update(cx, |leader, cx| { +// let excerpt_ids = leader.excerpt_ids(); +// leader.remove_excerpts([excerpt_ids[1], excerpt_ids[3]], cx); +// }); +// assert_eq!( +// leader_multibuffer.read(cx).snapshot(cx).text(), +// follower_multibuffer.read(cx).snapshot(cx).text(), +// ); +// assert_eq!(*follower_edit_event_count.read(), 3); + +// // Removing an empty set of excerpts is a noop. +// leader_multibuffer.update(cx, |leader, cx| { +// leader.remove_excerpts([], cx); +// }); +// assert_eq!( +// leader_multibuffer.read(cx).snapshot(cx).text(), +// follower_multibuffer.read(cx).snapshot(cx).text(), +// ); +// assert_eq!(*follower_edit_event_count.read(), 3); + +// // Adding an empty set of excerpts is a noop. +// leader_multibuffer.update(cx, |leader, cx| { +// leader.push_excerpts::(buffer_2.clone(), [], cx); +// }); +// assert_eq!( +// leader_multibuffer.read(cx).snapshot(cx).text(), +// follower_multibuffer.read(cx).snapshot(cx).text(), +// ); +// assert_eq!(*follower_edit_event_count.read(), 3); + +// leader_multibuffer.update(cx, |leader, cx| { +// leader.clear(cx); +// }); +// assert_eq!( +// leader_multibuffer.read(cx).snapshot(cx).text(), +// follower_multibuffer.read(cx).snapshot(cx).text(), +// ); +// assert_eq!(*follower_edit_event_count.read(), 4); +// } + +// #[gpui::test] +// fn test_expand_excerpts(cx: &mut AppContext) { +// let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx)); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); + +// multibuffer.update(cx, |multibuffer, cx| { +// multibuffer.push_excerpts_with_context_lines( +// buffer.clone(), +// vec![ +// // Note that in this test, this first excerpt +// // does not contain a new line +// Point::new(3, 2)..Point::new(3, 3), +// Point::new(7, 1)..Point::new(7, 3), +// Point::new(15, 0)..Point::new(15, 0), +// ], +// 1, +// cx, +// ) +// }); + +// let snapshot = multibuffer.read(cx).snapshot(cx); + +// assert_eq!( +// snapshot.text(), +// concat!( +// "ccc\n", // +// "ddd\n", // +// "eee", // +// "\n", // End of excerpt +// "ggg\n", // +// "hhh\n", // +// "iii", // +// "\n", // End of excerpt +// "ooo\n", // +// "ppp\n", // +// "qqq", // End of excerpt +// ) +// ); +// drop(snapshot); + +// multibuffer.update(cx, |multibuffer, cx| { +// multibuffer.expand_excerpts( +// multibuffer.excerpt_ids(), +// 1, +// ExpandExcerptDirection::UpAndDown, +// cx, +// ) +// }); + +// let snapshot = multibuffer.read(cx).snapshot(cx); + +// // Expanding context lines causes the line containing 'fff' to appear in two different excerpts. +// // We don't attempt to merge them, because removing the excerpt could create inconsistency with other layers +// // that are tracking excerpt ids. +// assert_eq!( +// snapshot.text(), +// concat!( +// "bbb\n", // +// "ccc\n", // +// "ddd\n", // +// "eee\n", // +// "fff\n", // End of excerpt +// "fff\n", // +// "ggg\n", // +// "hhh\n", // +// "iii\n", // +// "jjj\n", // End of excerpt +// "nnn\n", // +// "ooo\n", // +// "ppp\n", // +// "qqq\n", // +// "rrr", // End of excerpt +// ) +// ); +// } + +// #[gpui::test] +// fn test_push_excerpts_with_context_lines(cx: &mut AppContext) { +// let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx)); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| { +// multibuffer.push_excerpts_with_context_lines( +// buffer.clone(), +// vec![ +// // Note that in this test, this first excerpt +// // does contain a new line +// Point::new(3, 2)..Point::new(4, 2), +// Point::new(7, 1)..Point::new(7, 3), +// Point::new(15, 0)..Point::new(15, 0), +// ], +// 2, +// cx, +// ) +// }); + +// let snapshot = multibuffer.read(cx).snapshot(cx); +// assert_eq!( +// snapshot.text(), +// concat!( +// "bbb\n", // Preserve newlines +// "ccc\n", // +// "ddd\n", // +// "eee\n", // +// "fff\n", // +// "ggg\n", // +// "hhh\n", // +// "iii\n", // +// "jjj\n", // +// "nnn\n", // +// "ooo\n", // +// "ppp\n", // +// "qqq\n", // +// "rrr", // +// ) +// ); + +// assert_eq!( +// anchor_ranges +// .iter() +// .map(|range| range.to_point(&snapshot)) +// .collect::>(), +// vec![ +// Point::new(2, 2)..Point::new(3, 2), +// Point::new(6, 1)..Point::new(6, 3), +// Point::new(11, 0)..Point::new(11, 0) +// ] +// ); +// } + +// #[gpui::test] +// async fn test_stream_excerpts_with_context_lines(cx: &mut TestAppContext) { +// let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx)); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| { +// let snapshot = buffer.read(cx); +// let ranges = vec![ +// snapshot.anchor_before(Point::new(3, 2))..snapshot.anchor_before(Point::new(4, 2)), +// snapshot.anchor_before(Point::new(7, 1))..snapshot.anchor_before(Point::new(7, 3)), +// snapshot.anchor_before(Point::new(15, 0)) +// ..snapshot.anchor_before(Point::new(15, 0)), +// ]; +// multibuffer.stream_excerpts_with_context_lines(buffer.clone(), ranges, 2, cx) +// }); + +// let anchor_ranges = anchor_ranges.collect::>().await; + +// let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx)); +// assert_eq!( +// snapshot.text(), +// concat!( +// "bbb\n", // +// "ccc\n", // +// "ddd\n", // +// "eee\n", // +// "fff\n", // +// "ggg\n", // +// "hhh\n", // +// "iii\n", // +// "jjj\n", // +// "nnn\n", // +// "ooo\n", // +// "ppp\n", // +// "qqq\n", // +// "rrr", // +// ) +// ); + +// assert_eq!( +// anchor_ranges +// .iter() +// .map(|range| range.to_point(&snapshot)) +// .collect::>(), +// vec![ +// Point::new(2, 2)..Point::new(3, 2), +// Point::new(6, 1)..Point::new(6, 3), +// Point::new(11, 0)..Point::new(11, 0) +// ] +// ); +// } + +// #[gpui::test] +// fn test_empty_multibuffer(cx: &mut AppContext) { +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); + +// let snapshot = multibuffer.read(cx).snapshot(cx); +// assert_eq!(snapshot.text(), ""); +// assert_eq!( +// snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), +// &[Some(0)] +// ); +// assert_eq!( +// snapshot.buffer_rows(MultiBufferRow(1)).collect::>(), +// &[] +// ); +// } + +// #[gpui::test] +// fn test_singleton_multibuffer_anchors(cx: &mut AppContext) { +// let buffer = cx.new_model(|cx| Buffer::local("abcd", cx)); +// let multibuffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx)); +// let old_snapshot = multibuffer.read(cx).snapshot(cx); +// buffer.update(cx, |buffer, cx| { +// buffer.edit([(0..0, "X")], None, cx); +// buffer.edit([(5..5, "Y")], None, cx); +// }); +// let new_snapshot = multibuffer.read(cx).snapshot(cx); + +// assert_eq!(old_snapshot.text(), "abcd"); +// assert_eq!(new_snapshot.text(), "XabcdY"); + +// assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0); +// assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1); +// assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5); +// assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6); +// } + +// #[gpui::test] +// fn test_multibuffer_anchors(cx: &mut AppContext) { +// let buffer_1 = cx.new_model(|cx| Buffer::local("abcd", cx)); +// let buffer_2 = cx.new_model(|cx| Buffer::local("efghi", cx)); +// let multibuffer = cx.new_model(|cx| { +// let mut multibuffer = MultiBuffer::new(Capability::ReadWrite); +// multibuffer.push_excerpts( +// buffer_1.clone(), +// [ExcerptRange { +// context: 0..4, +// primary: None, +// }], +// cx, +// ); +// multibuffer.push_excerpts( +// buffer_2.clone(), +// [ExcerptRange { +// context: 0..5, +// primary: None, +// }], +// cx, +// ); +// multibuffer +// }); +// let old_snapshot = multibuffer.read(cx).snapshot(cx); + +// assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0); +// assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0); +// assert_eq!(Anchor::min().to_offset(&old_snapshot), 0); +// assert_eq!(Anchor::min().to_offset(&old_snapshot), 0); +// assert_eq!(Anchor::max().to_offset(&old_snapshot), 10); +// assert_eq!(Anchor::max().to_offset(&old_snapshot), 10); + +// buffer_1.update(cx, |buffer, cx| { +// buffer.edit([(0..0, "W")], None, cx); +// buffer.edit([(5..5, "X")], None, cx); +// }); +// buffer_2.update(cx, |buffer, cx| { +// buffer.edit([(0..0, "Y")], None, cx); +// buffer.edit([(6..6, "Z")], None, cx); +// }); +// let new_snapshot = multibuffer.read(cx).snapshot(cx); + +// assert_eq!(old_snapshot.text(), "abcd\nefghi"); +// assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ"); + +// assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0); +// assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1); +// assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2); +// assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2); +// assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3); +// assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3); +// assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7); +// assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8); +// assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13); +// assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14); +// } + +// #[gpui::test] +// fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut AppContext) { +// let buffer_1 = cx.new_model(|cx| Buffer::local("abcd", cx)); +// let buffer_2 = cx.new_model(|cx| Buffer::local("ABCDEFGHIJKLMNOP", cx)); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); + +// // Create an insertion id in buffer 1 that doesn't exist in buffer 2. +// // Add an excerpt from buffer 1 that spans this new insertion. +// buffer_1.update(cx, |buffer, cx| buffer.edit([(4..4, "123")], None, cx)); +// let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| { +// multibuffer +// .push_excerpts( +// buffer_1.clone(), +// [ExcerptRange { +// context: 0..7, +// primary: None, +// }], +// cx, +// ) +// .pop() +// .unwrap() +// }); + +// let snapshot_1 = multibuffer.read(cx).snapshot(cx); +// assert_eq!(snapshot_1.text(), "abcd123"); + +// // Replace the buffer 1 excerpt with new excerpts from buffer 2. +// let (excerpt_id_2, excerpt_id_3) = multibuffer.update(cx, |multibuffer, cx| { +// multibuffer.remove_excerpts([excerpt_id_1], cx); +// let mut ids = multibuffer +// .push_excerpts( +// buffer_2.clone(), +// [ +// ExcerptRange { +// context: 0..4, +// primary: None, +// }, +// ExcerptRange { +// context: 6..10, +// primary: None, +// }, +// ExcerptRange { +// context: 12..16, +// primary: None, +// }, +// ], +// cx, +// ) +// .into_iter(); +// (ids.next().unwrap(), ids.next().unwrap()) +// }); +// let snapshot_2 = multibuffer.read(cx).snapshot(cx); +// assert_eq!(snapshot_2.text(), "ABCD\nGHIJ\nMNOP"); + +// // The old excerpt id doesn't get reused. +// assert_ne!(excerpt_id_2, excerpt_id_1); + +// // Resolve some anchors from the previous snapshot in the new snapshot. +// // The current excerpts are from a different buffer, so we don't attempt to +// // resolve the old text anchor in the new buffer. +// assert_eq!( +// snapshot_2.summary_for_anchor::(&snapshot_1.anchor_before(2)), +// 0 +// ); +// assert_eq!( +// snapshot_2.summaries_for_anchors::(&[ +// snapshot_1.anchor_before(2), +// snapshot_1.anchor_after(3) +// ]), +// vec![0, 0] +// ); + +// // Refresh anchors from the old snapshot. The return value indicates that both +// // anchors lost their original excerpt. +// let refresh = +// snapshot_2.refresh_anchors(&[snapshot_1.anchor_before(2), snapshot_1.anchor_after(3)]); +// assert_eq!( +// refresh, +// &[ +// (0, snapshot_2.anchor_before(0), false), +// (1, snapshot_2.anchor_after(0), false), +// ] +// ); + +// // Replace the middle excerpt with a smaller excerpt in buffer 2, +// // that intersects the old excerpt. +// let excerpt_id_5 = multibuffer.update(cx, |multibuffer, cx| { +// multibuffer.remove_excerpts([excerpt_id_3], cx); +// multibuffer +// .insert_excerpts_after( +// excerpt_id_2, +// buffer_2.clone(), +// [ExcerptRange { +// context: 5..8, +// primary: None, +// }], +// cx, +// ) +// .pop() +// .unwrap() +// }); + +// let snapshot_3 = multibuffer.read(cx).snapshot(cx); +// assert_eq!(snapshot_3.text(), "ABCD\nFGH\nMNOP"); +// assert_ne!(excerpt_id_5, excerpt_id_3); + +// // Resolve some anchors from the previous snapshot in the new snapshot. +// // The third anchor can't be resolved, since its excerpt has been removed, +// // so it resolves to the same position as its predecessor. +// let anchors = [ +// snapshot_2.anchor_before(0), +// snapshot_2.anchor_after(2), +// snapshot_2.anchor_after(6), +// snapshot_2.anchor_after(14), +// ]; +// assert_eq!( +// snapshot_3.summaries_for_anchors::(&anchors), +// &[0, 2, 9, 13] +// ); + +// let new_anchors = snapshot_3.refresh_anchors(&anchors); +// assert_eq!( +// new_anchors.iter().map(|a| (a.0, a.2)).collect::>(), +// &[(0, true), (1, true), (2, true), (3, true)] +// ); +// assert_eq!( +// snapshot_3.summaries_for_anchors::(new_anchors.iter().map(|a| &a.1)), +// &[0, 2, 7, 13] +// ); +// } + +// #[gpui::test(iterations = 100)] +// fn test_random_multibuffer(cx: &mut AppContext, mut rng: StdRng) { +// let operations = env::var("OPERATIONS") +// .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) +// .unwrap_or(10); + +// let mut buffers: Vec> = Vec::new(); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// let mut excerpt_ids = Vec::::new(); +// let mut expected_excerpts = Vec::<(Model, Range)>::new(); +// let mut anchors = Vec::new(); +// let mut old_versions = Vec::new(); + +// for _ in 0..operations { +// match rng.gen_range(0..100) { +// 0..=14 if !buffers.is_empty() => { +// let buffer = buffers.choose(&mut rng).unwrap(); +// buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx)); +// } +// 15..=19 if !expected_excerpts.is_empty() => { +// multibuffer.update(cx, |multibuffer, cx| { +// let ids = multibuffer.excerpt_ids(); +// let mut excerpts = HashSet::default(); +// for _ in 0..rng.gen_range(0..ids.len()) { +// excerpts.extend(ids.choose(&mut rng).copied()); +// } + +// let line_count = rng.gen_range(0..5); + +// let excerpt_ixs = excerpts +// .iter() +// .map(|id| excerpt_ids.iter().position(|i| i == id).unwrap()) +// .collect::>(); +// log::info!("Expanding excerpts {excerpt_ixs:?} by {line_count} lines"); +// multibuffer.expand_excerpts( +// excerpts.iter().cloned(), +// line_count, +// ExpandExcerptDirection::UpAndDown, +// cx, +// ); + +// if line_count > 0 { +// for id in excerpts { +// let excerpt_ix = excerpt_ids.iter().position(|&i| i == id).unwrap(); +// let (buffer, range) = &mut expected_excerpts[excerpt_ix]; +// let snapshot = buffer.read(cx).snapshot(); +// let mut point_range = range.to_point(&snapshot); +// point_range.start = +// Point::new(point_range.start.row.saturating_sub(line_count), 0); +// point_range.end = snapshot.clip_point( +// Point::new(point_range.end.row + line_count, 0), +// Bias::Left, +// ); +// point_range.end.column = snapshot.line_len(point_range.end.row); +// *range = snapshot.anchor_before(point_range.start) +// ..snapshot.anchor_after(point_range.end); +// } +// } +// }); +// } +// 20..=29 if !expected_excerpts.is_empty() => { +// let mut ids_to_remove = vec![]; +// for _ in 0..rng.gen_range(1..=3) { +// if expected_excerpts.is_empty() { +// break; +// } + +// let ix = rng.gen_range(0..expected_excerpts.len()); +// ids_to_remove.push(excerpt_ids.remove(ix)); +// let (buffer, range) = expected_excerpts.remove(ix); +// let buffer = buffer.read(cx); +// log::info!( +// "Removing excerpt {}: {:?}", +// ix, +// buffer +// .text_for_range(range.to_offset(buffer)) +// .collect::(), +// ); +// } +// let snapshot = multibuffer.read(cx).read(cx); +// ids_to_remove.sort_unstable_by(|a, b| a.cmp(b, &snapshot)); +// drop(snapshot); +// multibuffer.update(cx, |multibuffer, cx| { +// multibuffer.remove_excerpts(ids_to_remove, cx) +// }); +// } +// 30..=39 if !expected_excerpts.is_empty() => { +// let multibuffer = multibuffer.read(cx).read(cx); +// let offset = +// multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left); +// let bias = if rng.gen() { Bias::Left } else { Bias::Right }; +// log::info!("Creating anchor at {} with bias {:?}", offset, bias); +// anchors.push(multibuffer.anchor_at(offset, bias)); +// anchors.sort_by(|a, b| a.cmp(b, &multibuffer)); +// } +// 40..=44 if !anchors.is_empty() => { +// let multibuffer = multibuffer.read(cx).read(cx); +// let prev_len = anchors.len(); +// anchors = multibuffer +// .refresh_anchors(&anchors) +// .into_iter() +// .map(|a| a.1) +// .collect(); + +// // Ensure the newly-refreshed anchors point to a valid excerpt and don't +// // overshoot its boundaries. +// assert_eq!(anchors.len(), prev_len); +// for anchor in &anchors { +// if anchor.excerpt_id == ExcerptId::min() +// || anchor.excerpt_id == ExcerptId::max() +// { +// continue; +// } + +// let excerpt = multibuffer.excerpt(anchor.excerpt_id).unwrap(); +// assert_eq!(excerpt.id, anchor.excerpt_id); +// assert!(excerpt.contains(anchor)); +// } +// } +// _ => { +// let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) { +// let base_text = util::RandomCharIter::new(&mut rng) +// .take(25) +// .collect::(); + +// buffers.push(cx.new_model(|cx| Buffer::local(base_text, cx))); +// buffers.last().unwrap() +// } else { +// buffers.choose(&mut rng).unwrap() +// }; + +// let buffer = buffer_handle.read(cx); +// let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right); +// let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left); +// let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix); +// let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len()); +// let prev_excerpt_id = excerpt_ids +// .get(prev_excerpt_ix) +// .cloned() +// .unwrap_or_else(ExcerptId::max); +// let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len()); + +// log::info!( +// "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}", +// excerpt_ix, +// expected_excerpts.len(), +// buffer_handle.read(cx).remote_id(), +// buffer.text(), +// start_ix..end_ix, +// &buffer.text()[start_ix..end_ix] +// ); + +// let excerpt_id = multibuffer.update(cx, |multibuffer, cx| { +// multibuffer +// .insert_excerpts_after( +// prev_excerpt_id, +// buffer_handle.clone(), +// [ExcerptRange { +// context: start_ix..end_ix, +// primary: None, +// }], +// cx, +// ) +// .pop() +// .unwrap() +// }); + +// excerpt_ids.insert(excerpt_ix, excerpt_id); +// expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range)); +// } +// } + +// if rng.gen_bool(0.3) { +// multibuffer.update(cx, |multibuffer, cx| { +// old_versions.push((multibuffer.snapshot(cx), multibuffer.subscribe())); +// }) +// } + +// let snapshot = multibuffer.read(cx).snapshot(cx); + +// let mut excerpt_starts = Vec::new(); +// let mut expected_text = String::new(); +// let mut expected_buffer_rows = Vec::new(); +// for (buffer, range) in &expected_excerpts { +// let buffer = buffer.read(cx); +// let buffer_range = range.to_offset(buffer); + +// excerpt_starts.push(TextSummary::from(expected_text.as_str())); +// expected_text.extend(buffer.text_for_range(buffer_range.clone())); +// expected_text.push('\n'); + +// let buffer_row_range = buffer.offset_to_point(buffer_range.start).row +// ..=buffer.offset_to_point(buffer_range.end).row; +// for row in buffer_row_range { +// expected_buffer_rows.push(Some(row)); +// } +// } +// // Remove final trailing newline. +// if !expected_excerpts.is_empty() { +// expected_text.pop(); +// } + +// // Always report one buffer row +// if expected_buffer_rows.is_empty() { +// expected_buffer_rows.push(Some(0)); +// } + +// assert_eq!(snapshot.text(), expected_text); +// log::info!("MultiBuffer text: {:?}", expected_text); + +// assert_eq!( +// snapshot.buffer_rows(MultiBufferRow(0)).collect::>(), +// expected_buffer_rows, +// ); + +// for _ in 0..5 { +// let start_row = rng.gen_range(0..=expected_buffer_rows.len()); +// assert_eq!( +// snapshot +// .buffer_rows(MultiBufferRow(start_row as u32)) +// .collect::>(), +// &expected_buffer_rows[start_row..], +// "buffer_rows({})", +// start_row +// ); +// } + +// assert_eq!( +// snapshot.max_buffer_row().0, +// expected_buffer_rows.into_iter().flatten().max().unwrap() +// ); + +// let mut excerpt_starts = excerpt_starts.into_iter(); +// for (buffer, range) in &expected_excerpts { +// let buffer = buffer.read(cx); +// let buffer_id = buffer.remote_id(); +// let buffer_range = range.to_offset(buffer); +// let buffer_start_point = buffer.offset_to_point(buffer_range.start); +// let buffer_start_point_utf16 = +// buffer.text_summary_for_range::(0..buffer_range.start); + +// let excerpt_start = excerpt_starts.next().unwrap(); +// let mut offset = excerpt_start.len; +// let mut buffer_offset = buffer_range.start; +// let mut point = excerpt_start.lines; +// let mut buffer_point = buffer_start_point; +// let mut point_utf16 = excerpt_start.lines_utf16(); +// let mut buffer_point_utf16 = buffer_start_point_utf16; +// for ch in buffer +// .snapshot() +// .chunks(buffer_range.clone(), false) +// .flat_map(|c| c.text.chars()) +// { +// for _ in 0..ch.len_utf8() { +// let left_offset = snapshot.clip_offset(offset, Bias::Left); +// let right_offset = snapshot.clip_offset(offset, Bias::Right); +// let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left); +// let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right); +// assert_eq!( +// left_offset, +// excerpt_start.len + (buffer_left_offset - buffer_range.start), +// "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}", +// offset, +// buffer_id, +// buffer_offset, +// ); +// assert_eq!( +// right_offset, +// excerpt_start.len + (buffer_right_offset - buffer_range.start), +// "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}", +// offset, +// buffer_id, +// buffer_offset, +// ); + +// let left_point = snapshot.clip_point(point, Bias::Left); +// let right_point = snapshot.clip_point(point, Bias::Right); +// let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left); +// let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right); +// assert_eq!( +// left_point, +// excerpt_start.lines + (buffer_left_point - buffer_start_point), +// "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}", +// point, +// buffer_id, +// buffer_point, +// ); +// assert_eq!( +// right_point, +// excerpt_start.lines + (buffer_right_point - buffer_start_point), +// "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}", +// point, +// buffer_id, +// buffer_point, +// ); + +// assert_eq!( +// snapshot.point_to_offset(left_point), +// left_offset, +// "point_to_offset({:?})", +// left_point, +// ); +// assert_eq!( +// snapshot.offset_to_point(left_offset), +// left_point, +// "offset_to_point({:?})", +// left_offset, +// ); + +// offset += 1; +// buffer_offset += 1; +// if ch == '\n' { +// point += Point::new(1, 0); +// buffer_point += Point::new(1, 0); +// } else { +// point += Point::new(0, 1); +// buffer_point += Point::new(0, 1); +// } +// } + +// for _ in 0..ch.len_utf16() { +// let left_point_utf16 = +// snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Left); +// let right_point_utf16 = +// snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Right); +// let buffer_left_point_utf16 = +// buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Left); +// let buffer_right_point_utf16 = +// buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Right); +// assert_eq!( +// left_point_utf16, +// excerpt_start.lines_utf16() +// + (buffer_left_point_utf16 - buffer_start_point_utf16), +// "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}", +// point_utf16, +// buffer_id, +// buffer_point_utf16, +// ); +// assert_eq!( +// right_point_utf16, +// excerpt_start.lines_utf16() +// + (buffer_right_point_utf16 - buffer_start_point_utf16), +// "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}", +// point_utf16, +// buffer_id, +// buffer_point_utf16, +// ); + +// if ch == '\n' { +// point_utf16 += PointUtf16::new(1, 0); +// buffer_point_utf16 += PointUtf16::new(1, 0); +// } else { +// point_utf16 += PointUtf16::new(0, 1); +// buffer_point_utf16 += PointUtf16::new(0, 1); +// } +// } +// } +// } + +// for (row, line) in expected_text.split('\n').enumerate() { +// assert_eq!( +// snapshot.line_len(MultiBufferRow(row as u32)), +// line.len() as u32, +// "line_len({}).", +// row +// ); +// } + +// let text_rope = Rope::from(expected_text.as_str()); +// for _ in 0..10 { +// let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right); +// let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left); + +// let text_for_range = snapshot +// .text_for_range(start_ix..end_ix) +// .collect::(); +// assert_eq!( +// text_for_range, +// &expected_text[start_ix..end_ix], +// "incorrect text for range {:?}", +// start_ix..end_ix +// ); + +// let excerpted_buffer_ranges = multibuffer +// .read(cx) +// .range_to_buffer_ranges(start_ix..end_ix, cx); +// let excerpted_buffers_text = excerpted_buffer_ranges +// .iter() +// .map(|(buffer, buffer_range, _)| { +// buffer +// .read(cx) +// .text_for_range(buffer_range.clone()) +// .collect::() +// }) +// .collect::>() +// .join("\n"); +// assert_eq!(excerpted_buffers_text, text_for_range); +// if !expected_excerpts.is_empty() { +// assert!(!excerpted_buffer_ranges.is_empty()); +// } + +// let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]); +// assert_eq!( +// snapshot.text_summary_for_range::(start_ix..end_ix), +// expected_summary, +// "incorrect summary for range {:?}", +// start_ix..end_ix +// ); +// } + +// // Anchor resolution +// let summaries = snapshot.summaries_for_anchors::(&anchors); +// assert_eq!(anchors.len(), summaries.len()); +// for (anchor, resolved_offset) in anchors.iter().zip(summaries) { +// assert!(resolved_offset <= snapshot.len()); +// assert_eq!( +// snapshot.summary_for_anchor::(anchor), +// resolved_offset +// ); +// } + +// for _ in 0..10 { +// let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right); +// assert_eq!( +// snapshot.reversed_chars_at(end_ix).collect::(), +// expected_text[..end_ix].chars().rev().collect::(), +// ); +// } + +// for _ in 0..10 { +// let end_ix = rng.gen_range(0..=text_rope.len()); +// let start_ix = rng.gen_range(0..=end_ix); +// assert_eq!( +// snapshot +// .bytes_in_range(start_ix..end_ix) +// .flatten() +// .copied() +// .collect::>(), +// expected_text.as_bytes()[start_ix..end_ix].to_vec(), +// "bytes_in_range({:?})", +// start_ix..end_ix, +// ); +// } +// } + +// let snapshot = multibuffer.read(cx).snapshot(cx); +// for (old_snapshot, subscription) in old_versions { +// let edits = subscription.consume().into_inner(); + +// log::info!( +// "applying subscription edits to old text: {:?}: {:?}", +// old_snapshot.text(), +// edits, +// ); + +// let mut text = old_snapshot.text(); +// for edit in edits { +// let new_text: String = snapshot.text_for_range(edit.new.clone()).collect(); +// text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text); +// } +// assert_eq!(text.to_string(), snapshot.text()); +// } +// } + +// #[gpui::test] +// fn test_history(cx: &mut AppContext) { +// let test_settings = SettingsStore::test(cx); +// cx.set_global(test_settings); + +// let buffer_1 = cx.new_model(|cx| Buffer::local("1234", cx)); +// let buffer_2 = cx.new_model(|cx| Buffer::local("5678", cx)); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// let group_interval = multibuffer.read(cx).history.group_interval; +// multibuffer.update(cx, |multibuffer, cx| { +// multibuffer.push_excerpts( +// buffer_1.clone(), +// [ExcerptRange { +// context: 0..buffer_1.read(cx).len(), +// primary: None, +// }], +// cx, +// ); +// multibuffer.push_excerpts( +// buffer_2.clone(), +// [ExcerptRange { +// context: 0..buffer_2.read(cx).len(), +// primary: None, +// }], +// cx, +// ); +// }); + +// let mut now = Instant::now(); + +// multibuffer.update(cx, |multibuffer, cx| { +// let transaction_1 = multibuffer.start_transaction_at(now, cx).unwrap(); +// multibuffer.edit( +// [ +// (Point::new(0, 0)..Point::new(0, 0), "A"), +// (Point::new(1, 0)..Point::new(1, 0), "A"), +// ], +// None, +// cx, +// ); +// multibuffer.edit( +// [ +// (Point::new(0, 1)..Point::new(0, 1), "B"), +// (Point::new(1, 1)..Point::new(1, 1), "B"), +// ], +// None, +// cx, +// ); +// multibuffer.end_transaction_at(now, cx); +// assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678"); + +// // Verify edited ranges for transaction 1 +// assert_eq!( +// multibuffer.edited_ranges_for_transaction(transaction_1, cx), +// &[ +// Point::new(0, 0)..Point::new(0, 2), +// Point::new(1, 0)..Point::new(1, 2) +// ] +// ); + +// // Edit buffer 1 through the multibuffer +// now += 2 * group_interval; +// multibuffer.start_transaction_at(now, cx); +// multibuffer.edit([(2..2, "C")], None, cx); +// multibuffer.end_transaction_at(now, cx); +// assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678"); + +// // Edit buffer 1 independently +// buffer_1.update(cx, |buffer_1, cx| { +// buffer_1.start_transaction_at(now); +// buffer_1.edit([(3..3, "D")], None, cx); +// buffer_1.end_transaction_at(now, cx); + +// now += 2 * group_interval; +// buffer_1.start_transaction_at(now); +// buffer_1.edit([(4..4, "E")], None, cx); +// buffer_1.end_transaction_at(now, cx); +// }); +// assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678"); + +// // An undo in the multibuffer undoes the multibuffer transaction +// // and also any individual buffer edits that have occurred since +// // that transaction. +// multibuffer.undo(cx); +// assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678"); + +// multibuffer.undo(cx); +// assert_eq!(multibuffer.read(cx).text(), "1234\n5678"); + +// multibuffer.redo(cx); +// assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678"); + +// multibuffer.redo(cx); +// assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678"); + +// // Undo buffer 2 independently. +// buffer_2.update(cx, |buffer_2, cx| buffer_2.undo(cx)); +// assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\n5678"); + +// // An undo in the multibuffer undoes the components of the +// // the last multibuffer transaction that are not already undone. +// multibuffer.undo(cx); +// assert_eq!(multibuffer.read(cx).text(), "AB1234\n5678"); + +// multibuffer.undo(cx); +// assert_eq!(multibuffer.read(cx).text(), "1234\n5678"); + +// multibuffer.redo(cx); +// assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678"); + +// buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx)); +// assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678"); + +// // Redo stack gets cleared after an edit. +// now += 2 * group_interval; +// multibuffer.start_transaction_at(now, cx); +// multibuffer.edit([(0..0, "X")], None, cx); +// multibuffer.end_transaction_at(now, cx); +// assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); +// multibuffer.redo(cx); +// assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); +// multibuffer.undo(cx); +// assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678"); +// multibuffer.undo(cx); +// assert_eq!(multibuffer.read(cx).text(), "1234\n5678"); + +// // Transactions can be grouped manually. +// multibuffer.redo(cx); +// multibuffer.redo(cx); +// assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); +// multibuffer.group_until_transaction(transaction_1, cx); +// multibuffer.undo(cx); +// assert_eq!(multibuffer.read(cx).text(), "1234\n5678"); +// multibuffer.redo(cx); +// assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); +// }); +// } + +// #[gpui::test] +// fn test_excerpts_in_ranges_no_ranges(cx: &mut AppContext) { +// let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); +// let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// multibuffer.update(cx, |multibuffer, cx| { +// multibuffer.push_excerpts( +// buffer_1.clone(), +// [ExcerptRange { +// context: 0..buffer_1.read(cx).len(), +// primary: None, +// }], +// cx, +// ); +// multibuffer.push_excerpts( +// buffer_2.clone(), +// [ExcerptRange { +// context: 0..buffer_2.read(cx).len(), +// primary: None, +// }], +// cx, +// ); +// }); + +// let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx)); + +// let mut excerpts = snapshot.excerpts_in_ranges(iter::from_fn(|| None)); + +// assert!(excerpts.next().is_none()); +// } + +// fn validate_excerpts( +// actual: &[(ExcerptId, BufferId, Range)], +// expected: &Vec<(ExcerptId, BufferId, Range)>, +// ) { +// assert_eq!(actual.len(), expected.len()); + +// actual +// .iter() +// .zip(expected) +// .map(|(actual, expected)| { +// assert_eq!(actual.0, expected.0); +// assert_eq!(actual.1, expected.1); +// assert_eq!(actual.2.start, expected.2.start); +// assert_eq!(actual.2.end, expected.2.end); +// }) +// .collect_vec(); +// } + +// fn map_range_from_excerpt( +// snapshot: &MultiBufferSnapshot, +// excerpt_id: ExcerptId, +// excerpt_buffer: &BufferSnapshot, +// range: Range, +// ) -> Range { +// snapshot +// .anchor_in_excerpt(excerpt_id, excerpt_buffer.anchor_before(range.start)) +// .unwrap() +// ..snapshot +// .anchor_in_excerpt(excerpt_id, excerpt_buffer.anchor_after(range.end)) +// .unwrap() +// } + +// fn make_expected_excerpt_info( +// snapshot: &MultiBufferSnapshot, +// cx: &mut AppContext, +// excerpt_id: ExcerptId, +// buffer: &Model, +// range: Range, +// ) -> (ExcerptId, BufferId, Range) { +// ( +// excerpt_id, +// buffer.read(cx).remote_id(), +// map_range_from_excerpt(snapshot, excerpt_id, &buffer.read(cx).snapshot(), range), +// ) +// } + +// #[gpui::test] +// fn test_excerpts_in_ranges_range_inside_the_excerpt(cx: &mut AppContext) { +// let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); +// let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); +// let buffer_len = buffer_1.read(cx).len(); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// let mut expected_excerpt_id = ExcerptId(0); + +// multibuffer.update(cx, |multibuffer, cx| { +// expected_excerpt_id = multibuffer.push_excerpts( +// buffer_1.clone(), +// [ExcerptRange { +// context: 0..buffer_1.read(cx).len(), +// primary: None, +// }], +// cx, +// )[0]; +// multibuffer.push_excerpts( +// buffer_2.clone(), +// [ExcerptRange { +// context: 0..buffer_2.read(cx).len(), +// primary: None, +// }], +// cx, +// ); +// }); + +// let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx)); + +// let range = snapshot +// .anchor_in_excerpt(expected_excerpt_id, buffer_1.read(cx).anchor_before(1)) +// .unwrap() +// ..snapshot +// .anchor_in_excerpt( +// expected_excerpt_id, +// buffer_1.read(cx).anchor_after(buffer_len / 2), +// ) +// .unwrap(); + +// let expected_excerpts = vec![make_expected_excerpt_info( +// &snapshot, +// cx, +// expected_excerpt_id, +// &buffer_1, +// 1..(buffer_len / 2), +// )]; + +// let excerpts = snapshot +// .excerpts_in_ranges(vec![range.clone()].into_iter()) +// .map(|(excerpt_id, buffer, actual_range)| { +// ( +// excerpt_id, +// buffer.remote_id(), +// map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range), +// ) +// }) +// .collect_vec(); + +// validate_excerpts(&excerpts, &expected_excerpts); +// } + +// #[gpui::test] +// fn test_excerpts_in_ranges_range_crosses_excerpts_boundary(cx: &mut AppContext) { +// let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); +// let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); +// let buffer_len = buffer_1.read(cx).len(); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// let mut excerpt_1_id = ExcerptId(0); +// let mut excerpt_2_id = ExcerptId(0); + +// multibuffer.update(cx, |multibuffer, cx| { +// excerpt_1_id = multibuffer.push_excerpts( +// buffer_1.clone(), +// [ExcerptRange { +// context: 0..buffer_1.read(cx).len(), +// primary: None, +// }], +// cx, +// )[0]; +// excerpt_2_id = multibuffer.push_excerpts( +// buffer_2.clone(), +// [ExcerptRange { +// context: 0..buffer_2.read(cx).len(), +// primary: None, +// }], +// cx, +// )[0]; +// }); + +// let snapshot = multibuffer.read(cx).snapshot(cx); + +// let expected_range = snapshot +// .anchor_in_excerpt( +// excerpt_1_id, +// buffer_1.read(cx).anchor_before(buffer_len / 2), +// ) +// .unwrap() +// ..snapshot +// .anchor_in_excerpt(excerpt_2_id, buffer_2.read(cx).anchor_after(buffer_len / 2)) +// .unwrap(); + +// let expected_excerpts = vec![ +// make_expected_excerpt_info( +// &snapshot, +// cx, +// excerpt_1_id, +// &buffer_1, +// (buffer_len / 2)..buffer_len, +// ), +// make_expected_excerpt_info(&snapshot, cx, excerpt_2_id, &buffer_2, 0..buffer_len / 2), +// ]; + +// let excerpts = snapshot +// .excerpts_in_ranges(vec![expected_range.clone()].into_iter()) +// .map(|(excerpt_id, buffer, actual_range)| { +// ( +// excerpt_id, +// buffer.remote_id(), +// map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range), +// ) +// }) +// .collect_vec(); + +// validate_excerpts(&excerpts, &expected_excerpts); +// } + +// #[gpui::test] +// fn test_excerpts_in_ranges_range_encloses_excerpt(cx: &mut AppContext) { +// let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); +// let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); +// let buffer_3 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'r'), cx)); +// let buffer_len = buffer_1.read(cx).len(); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// let mut excerpt_1_id = ExcerptId(0); +// let mut excerpt_2_id = ExcerptId(0); +// let mut excerpt_3_id = ExcerptId(0); + +// multibuffer.update(cx, |multibuffer, cx| { +// excerpt_1_id = multibuffer.push_excerpts( +// buffer_1.clone(), +// [ExcerptRange { +// context: 0..buffer_1.read(cx).len(), +// primary: None, +// }], +// cx, +// )[0]; +// excerpt_2_id = multibuffer.push_excerpts( +// buffer_2.clone(), +// [ExcerptRange { +// context: 0..buffer_2.read(cx).len(), +// primary: None, +// }], +// cx, +// )[0]; +// excerpt_3_id = multibuffer.push_excerpts( +// buffer_3.clone(), +// [ExcerptRange { +// context: 0..buffer_3.read(cx).len(), +// primary: None, +// }], +// cx, +// )[0]; +// }); + +// let snapshot = multibuffer.read(cx).snapshot(cx); + +// let expected_range = snapshot +// .anchor_in_excerpt( +// excerpt_1_id, +// buffer_1.read(cx).anchor_before(buffer_len / 2), +// ) +// .unwrap() +// ..snapshot +// .anchor_in_excerpt(excerpt_3_id, buffer_3.read(cx).anchor_after(buffer_len / 2)) +// .unwrap(); + +// let expected_excerpts = vec![ +// make_expected_excerpt_info( +// &snapshot, +// cx, +// excerpt_1_id, +// &buffer_1, +// (buffer_len / 2)..buffer_len, +// ), +// make_expected_excerpt_info(&snapshot, cx, excerpt_2_id, &buffer_2, 0..buffer_len), +// make_expected_excerpt_info(&snapshot, cx, excerpt_3_id, &buffer_3, 0..buffer_len / 2), +// ]; + +// let excerpts = snapshot +// .excerpts_in_ranges(vec![expected_range.clone()].into_iter()) +// .map(|(excerpt_id, buffer, actual_range)| { +// ( +// excerpt_id, +// buffer.remote_id(), +// map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range), +// ) +// }) +// .collect_vec(); + +// validate_excerpts(&excerpts, &expected_excerpts); +// } + +// #[gpui::test] +// fn test_excerpts_in_ranges_multiple_ranges(cx: &mut AppContext) { +// let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); +// let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); +// let buffer_len = buffer_1.read(cx).len(); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// let mut excerpt_1_id = ExcerptId(0); +// let mut excerpt_2_id = ExcerptId(0); + +// multibuffer.update(cx, |multibuffer, cx| { +// excerpt_1_id = multibuffer.push_excerpts( +// buffer_1.clone(), +// [ExcerptRange { +// context: 0..buffer_1.read(cx).len(), +// primary: None, +// }], +// cx, +// )[0]; +// excerpt_2_id = multibuffer.push_excerpts( +// buffer_2.clone(), +// [ExcerptRange { +// context: 0..buffer_2.read(cx).len(), +// primary: None, +// }], +// cx, +// )[0]; +// }); + +// let snapshot = multibuffer.read(cx).snapshot(cx); + +// let ranges = vec![ +// 1..(buffer_len / 4), +// (buffer_len / 3)..(buffer_len / 2), +// (buffer_len / 4 * 3)..(buffer_len), +// ]; + +// let expected_excerpts = ranges +// .iter() +// .map(|range| { +// make_expected_excerpt_info(&snapshot, cx, excerpt_1_id, &buffer_1, range.clone()) +// }) +// .collect_vec(); + +// let ranges = ranges.into_iter().map(|range| { +// map_range_from_excerpt( +// &snapshot, +// excerpt_1_id, +// &buffer_1.read(cx).snapshot(), +// range, +// ) +// }); + +// let excerpts = snapshot +// .excerpts_in_ranges(ranges) +// .map(|(excerpt_id, buffer, actual_range)| { +// ( +// excerpt_id, +// buffer.remote_id(), +// map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range), +// ) +// }) +// .collect_vec(); + +// validate_excerpts(&excerpts, &expected_excerpts); +// } + +// #[gpui::test] +// fn test_excerpts_in_ranges_range_ends_at_excerpt_end(cx: &mut AppContext) { +// let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); +// let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); +// let buffer_len = buffer_1.read(cx).len(); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// let mut excerpt_1_id = ExcerptId(0); +// let mut excerpt_2_id = ExcerptId(0); + +// multibuffer.update(cx, |multibuffer, cx| { +// excerpt_1_id = multibuffer.push_excerpts( +// buffer_1.clone(), +// [ExcerptRange { +// context: 0..buffer_1.read(cx).len(), +// primary: None, +// }], +// cx, +// )[0]; +// excerpt_2_id = multibuffer.push_excerpts( +// buffer_2.clone(), +// [ExcerptRange { +// context: 0..buffer_2.read(cx).len(), +// primary: None, +// }], +// cx, +// )[0]; +// }); + +// let snapshot = multibuffer.read(cx).snapshot(cx); + +// let ranges = [0..buffer_len, (buffer_len / 3)..(buffer_len / 2)]; + +// let expected_excerpts = vec![ +// make_expected_excerpt_info(&snapshot, cx, excerpt_1_id, &buffer_1, ranges[0].clone()), +// make_expected_excerpt_info(&snapshot, cx, excerpt_2_id, &buffer_2, ranges[1].clone()), +// ]; + +// let ranges = [ +// map_range_from_excerpt( +// &snapshot, +// excerpt_1_id, +// &buffer_1.read(cx).snapshot(), +// ranges[0].clone(), +// ), +// map_range_from_excerpt( +// &snapshot, +// excerpt_2_id, +// &buffer_2.read(cx).snapshot(), +// ranges[1].clone(), +// ), +// ]; + +// let excerpts = snapshot +// .excerpts_in_ranges(ranges.into_iter()) +// .map(|(excerpt_id, buffer, actual_range)| { +// ( +// excerpt_id, +// buffer.remote_id(), +// map_range_from_excerpt(&snapshot, excerpt_id, buffer, actual_range), +// ) +// }) +// .collect_vec(); + +// validate_excerpts(&excerpts, &expected_excerpts); +// } + +// #[gpui::test] +// fn test_split_ranges(cx: &mut AppContext) { +// let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); +// let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// multibuffer.update(cx, |multibuffer, cx| { +// multibuffer.push_excerpts( +// buffer_1.clone(), +// [ExcerptRange { +// context: 0..buffer_1.read(cx).len(), +// primary: None, +// }], +// cx, +// ); +// multibuffer.push_excerpts( +// buffer_2.clone(), +// [ExcerptRange { +// context: 0..buffer_2.read(cx).len(), +// primary: None, +// }], +// cx, +// ); +// }); + +// let snapshot = multibuffer.read(cx).snapshot(cx); + +// let buffer_1_len = buffer_1.read(cx).len(); +// let buffer_2_len = buffer_2.read(cx).len(); +// let buffer_1_midpoint = buffer_1_len / 2; +// let buffer_2_start = buffer_1_len + '\n'.len_utf8(); +// let buffer_2_midpoint = buffer_2_start + buffer_2_len / 2; +// let total_len = buffer_2_start + buffer_2_len; + +// let input_ranges = [ +// 0..buffer_1_midpoint, +// buffer_1_midpoint..buffer_2_midpoint, +// buffer_2_midpoint..total_len, +// ] +// .map(|range| snapshot.anchor_before(range.start)..snapshot.anchor_after(range.end)); + +// let actual_ranges = snapshot +// .split_ranges(input_ranges.into_iter()) +// .map(|range| range.to_offset(&snapshot)) +// .collect::>(); + +// let expected_ranges = vec![ +// 0..buffer_1_midpoint, +// buffer_1_midpoint..buffer_1_len, +// buffer_2_start..buffer_2_midpoint, +// buffer_2_midpoint..total_len, +// ]; + +// assert_eq!(actual_ranges, expected_ranges); +// } + +// #[gpui::test] +// fn test_split_ranges_single_range_spanning_three_excerpts(cx: &mut AppContext) { +// let buffer_1 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx)); +// let buffer_2 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'g'), cx)); +// let buffer_3 = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'm'), cx)); +// let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite)); +// multibuffer.update(cx, |multibuffer, cx| { +// multibuffer.push_excerpts( +// buffer_1.clone(), +// [ExcerptRange { +// context: 0..buffer_1.read(cx).len(), +// primary: None, +// }], +// cx, +// ); +// multibuffer.push_excerpts( +// buffer_2.clone(), +// [ExcerptRange { +// context: 0..buffer_2.read(cx).len(), +// primary: None, +// }], +// cx, +// ); +// multibuffer.push_excerpts( +// buffer_3.clone(), +// [ExcerptRange { +// context: 0..buffer_3.read(cx).len(), +// primary: None, +// }], +// cx, +// ); +// }); + +// let snapshot = multibuffer.read(cx).snapshot(cx); + +// let buffer_1_len = buffer_1.read(cx).len(); +// let buffer_2_len = buffer_2.read(cx).len(); +// let buffer_3_len = buffer_3.read(cx).len(); +// let buffer_2_start = buffer_1_len + '\n'.len_utf8(); +// let buffer_3_start = buffer_2_start + buffer_2_len + '\n'.len_utf8(); +// let buffer_1_midpoint = buffer_1_len / 2; +// let buffer_3_midpoint = buffer_3_start + buffer_3_len / 2; + +// let input_range = +// snapshot.anchor_before(buffer_1_midpoint)..snapshot.anchor_after(buffer_3_midpoint); + +// let actual_ranges = snapshot +// .split_ranges(std::iter::once(input_range)) +// .map(|range| range.to_offset(&snapshot)) +// .collect::>(); + +// let expected_ranges = vec![ +// buffer_1_midpoint..buffer_1_len, +// buffer_2_start..buffer_2_start + buffer_2_len, +// buffer_3_start..buffer_3_midpoint, +// ]; + +// assert_eq!(actual_ranges, expected_ranges); +// } +// }