From 09afba92511eecc59aa2eb6e201fe3d8da047a65 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 15 Jul 2021 09:50:50 -0600 Subject: [PATCH] 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. --- zed/src/editor.rs | 4 +- zed/src/editor/buffer.rs | 108 +++++++++++++++++++++++++++------------ 2 files changed, 78 insertions(+), 34 deletions(-) diff --git a/zed/src/editor.rs b/zed/src/editor.rs index 621358d334..368efad782 100644 --- a/zed/src/editor.rs +++ b/zed/src/editor.rs @@ -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 diff --git a/zed/src/editor/buffer.rs b/zed/src/editor/buffer.rs index f4a79bed98..376db90bc0 100644 --- a/zed/src/editor/buffer.rs +++ b/zed/src/editor/buffer.rs @@ -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) -> TextSummary { - self.visible_text.cursor(range.start).summary(range.end) - } - pub fn len(&self) -> usize { self.fragments.extent::(&None) } @@ -1149,7 +1146,7 @@ impl Buffer { // Skip invalid ranges and coalesce contiguous ones. let mut ranges: Vec> = 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) -> TextSummary { + self.content().text_summary_for_range(range) + } + pub fn anchor_before(&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::(); - 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 { 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, tree: Option, language: Option>, query_cursor: QueryCursorHandle, @@ -2020,6 +2014,56 @@ impl Snapshot { } } +pub struct Content<'a> { + visible_text: &'a Rope, + fragments: &'a SumTree, +} + +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::(); + 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) -> 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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>) -> 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::>(); assert_eq!(