Introduce buffer::Content<'a> struct to share logic with buffer::Snapshot

We want to move a bunch of methods on FoldMap to fold_map::Snapshot. This captures a buffer snapshot, and we'll need a bunch of methods that currently are on Buffer to also be implemented on buffer::Snapshot. This Content reference struct will be a good zero-cost place to store that logic.
This commit is contained in:
Nathan Sobo 2021-07-15 09:50:50 -06:00
parent be954872d0
commit 09afba9251
2 changed files with 78 additions and 34 deletions

View file

@ -1215,8 +1215,8 @@ impl Editor {
String::from_iter(clipboard_chars.by_ref().take(clipboard_selection.len));
self.buffer.update(cx, |buffer, cx| {
let selection_start = selection.start.to_point(buffer);
let selection_end = selection.end.to_point(buffer);
let selection_start = selection.start.to_point(&*buffer);
let selection_end = selection.end.to_point(&*buffer);
// If the corresponding selection was empty when this slice of the
// clipboard text was written, then the entire line containing the

View file

@ -601,6 +601,7 @@ impl Buffer {
pub fn snapshot(&self) -> Snapshot {
Snapshot {
text: self.visible_text.clone(),
fragments: self.fragments.clone(),
tree: self.syntax_tree(),
language: self.language.clone(),
query_cursor: QueryCursorHandle::new(),
@ -1005,10 +1006,6 @@ impl Buffer {
self.visible_text.summary()
}
pub fn text_summary_for_range(&self, range: Range<usize>) -> TextSummary {
self.visible_text.cursor(range.start).summary(range.end)
}
pub fn len(&self) -> usize {
self.fragments.extent::<usize>(&None)
}
@ -1149,7 +1146,7 @@ impl Buffer {
// Skip invalid ranges and coalesce contiguous ones.
let mut ranges: Vec<Range<usize>> = Vec::new();
for range in ranges_iter {
let range = range.start.to_offset(self)..range.end.to_offset(self);
let range = range.start.to_offset(&*self)..range.end.to_offset(&*self);
if has_new_text || !range.is_empty() {
if let Some(prev_range) = ranges.last_mut() {
if prev_range.end >= range.start {
@ -1860,6 +1857,14 @@ impl Buffer {
edit
}
fn content<'a>(&'a self) -> Content<'a> {
self.into()
}
pub fn text_summary_for_range(&self, range: Range<usize>) -> TextSummary {
self.content().text_summary_for_range(range)
}
pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
self.anchor_at(position, Bias::Left)
}
@ -1881,18 +1886,6 @@ impl Buffer {
}
}
fn summary_for_anchor(&self, anchor: &Anchor) -> TextSummary {
let cx = Some(anchor.version.clone());
let mut cursor = self.fragments.cursor::<VersionedOffset, usize>();
cursor.seek(&VersionedOffset::Offset(anchor.offset), anchor.bias, &cx);
let overshoot = if cursor.item().map_or(false, |fragment| fragment.visible) {
anchor.offset - cursor.seek_start().offset()
} else {
0
};
self.text_summary_for_range(0..*cursor.sum_start() + overshoot)
}
fn full_offset_for_anchor(&self, anchor: &Anchor) -> usize {
let cx = Some(anchor.version.clone());
let mut cursor = self
@ -1910,7 +1903,7 @@ impl Buffer {
pub fn point_for_offset(&self, offset: usize) -> Result<Point> {
if offset <= self.len() {
Ok(self.text_summary_for_range(0..offset).lines)
Ok(self.content().text_summary_for_range(0..offset).lines)
} else {
Err(anyhow!("offset out of bounds"))
}
@ -1957,6 +1950,7 @@ impl Clone for Buffer {
pub struct Snapshot {
text: Rope,
fragments: SumTree<Fragment>,
tree: Option<Tree>,
language: Option<Arc<Language>>,
query_cursor: QueryCursorHandle,
@ -2020,6 +2014,56 @@ impl Snapshot {
}
}
pub struct Content<'a> {
visible_text: &'a Rope,
fragments: &'a SumTree<Fragment>,
}
impl<'a> From<&'a Snapshot> for Content<'a> {
fn from(snapshot: &'a Snapshot) -> Self {
Self {
visible_text: &snapshot.text,
fragments: &snapshot.fragments,
}
}
}
impl<'a> From<&'a Buffer> for Content<'a> {
fn from(buffer: &'a Buffer) -> Self {
Self {
visible_text: &buffer.visible_text,
fragments: &buffer.fragments,
}
}
}
impl<'a> From<&'a mut Buffer> for Content<'a> {
fn from(buffer: &'a mut Buffer) -> Self {
Self {
visible_text: &buffer.visible_text,
fragments: &buffer.fragments,
}
}
}
impl<'a> Content<'a> {
fn summary_for_anchor(&self, anchor: &Anchor) -> TextSummary {
let cx = Some(anchor.version.clone());
let mut cursor = self.fragments.cursor::<VersionedOffset, usize>();
cursor.seek(&VersionedOffset::Offset(anchor.offset), anchor.bias, &cx);
let overshoot = if cursor.item().map_or(false, |fragment| fragment.visible) {
anchor.offset - cursor.seek_start().offset()
} else {
0
};
self.text_summary_for_range(0..*cursor.sum_start() + overshoot)
}
pub fn text_summary_for_range(&self, range: Range<usize>) -> TextSummary {
self.visible_text.cursor(range.start).summary(range.end)
}
}
struct RopeBuilder<'a> {
old_visible_cursor: rope::Cursor<'a>,
old_deleted_cursor: rope::Cursor<'a>,
@ -2704,46 +2748,46 @@ impl operation_queue::Operation for Operation {
}
pub trait ToOffset {
fn to_offset(&self, buffer: &Buffer) -> usize;
fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> usize;
}
impl ToOffset for Point {
fn to_offset(&self, buffer: &Buffer) -> usize {
buffer.visible_text.to_offset(*self)
fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> usize {
content.into().visible_text.to_offset(*self)
}
}
impl ToOffset for usize {
fn to_offset(&self, _: &Buffer) -> usize {
fn to_offset<'a>(&self, _: impl Into<Content<'a>>) -> usize {
*self
}
}
impl ToOffset for Anchor {
fn to_offset(&self, buffer: &Buffer) -> usize {
buffer.summary_for_anchor(self).bytes
fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> usize {
content.into().summary_for_anchor(self).bytes
}
}
impl<'a> ToOffset for &'a Anchor {
fn to_offset(&self, buffer: &Buffer) -> usize {
buffer.summary_for_anchor(self).bytes
fn to_offset<'b>(&self, content: impl Into<Content<'b>>) -> usize {
content.into().summary_for_anchor(self).bytes
}
}
pub trait ToPoint {
fn to_point(&self, buffer: &Buffer) -> Point;
fn to_point<'a>(&self, content: impl Into<Content<'a>>) -> Point;
}
impl ToPoint for Anchor {
fn to_point(&self, buffer: &Buffer) -> Point {
buffer.summary_for_anchor(self).lines
fn to_point<'a>(&self, content: impl Into<Content<'a>>) -> Point {
content.into().summary_for_anchor(self).lines
}
}
impl ToPoint for usize {
fn to_point(&self, buffer: &Buffer) -> Point {
buffer.visible_text.to_point(*self)
fn to_point<'a>(&self, content: impl Into<Content<'a>>) -> Point {
content.into().visible_text.to_point(*self)
}
}
@ -3411,7 +3455,7 @@ mod tests {
.iter()
.map(|selection| {
assert_eq!(selection.start, selection.end);
selection.start.to_point(&buffer)
selection.start.to_point(&*buffer)
})
.collect::<Vec<_>>();
assert_eq!(