Use `&Snapshot` directly instead of `impl Into<Content<'a>>`

Max Brunsfeld created

The text::Buffer and its snapshot already used the same representation
for their content, so we can just make Buffer deref to a Snapshot.

Change summary

crates/editor/src/display_map/fold_map.rs |   8 
crates/editor/src/editor.rs               |  12 
crates/editor/src/movement.rs             |   4 
crates/language/src/buffer.rs             |  52 --
crates/language/src/tests.rs              |  13 
crates/project/src/worktree.rs            |   2 
crates/text/src/anchor.rs                 |  62 +--
crates/text/src/selection.rs              |  21 
crates/text/src/tests.rs                  |  12 
crates/text/src/text.rs                   | 447 ++++++------------------
10 files changed, 197 insertions(+), 436 deletions(-)

Detailed changes

crates/editor/src/display_map/fold_map.rs 🔗

@@ -359,7 +359,8 @@ impl FoldMap {
                 }
 
                 if fold.start > sum.input.bytes {
-                    let text_summary = buffer.text_summary_for_range(sum.input.bytes..fold.start);
+                    let text_summary = buffer
+                        .text_summary_for_range::<TextSummary, _>(sum.input.bytes..fold.start);
                     new_transforms.push(
                         Transform {
                             summary: TransformSummary {
@@ -400,7 +401,8 @@ impl FoldMap {
 
             let sum = new_transforms.summary();
             if sum.input.bytes < edit.new.end {
-                let text_summary = buffer.text_summary_for_range(sum.input.bytes..edit.new.end);
+                let text_summary =
+                    buffer.text_summary_for_range::<TextSummary, _>(sum.input.bytes..edit.new.end);
                 new_transforms.push(
                     Transform {
                         summary: TransformSummary {
@@ -539,7 +541,7 @@ impl Snapshot {
                     let buffer_end = cursor.start().1 + end_in_transform;
                     summary += self
                         .buffer_snapshot
-                        .text_summary_for_range(buffer_start..buffer_end);
+                        .text_summary_for_range::<TextSummary, _>(buffer_start..buffer_end);
                 }
             }
         }

crates/editor/src/editor.rs 🔗

@@ -1358,7 +1358,7 @@ impl Editor {
         let buffer = self.buffer.read(cx);
         if old_selections
             .iter()
-            .zip(autoclose_pair_state.ranges.ranges::<usize, _>(buffer))
+            .zip(autoclose_pair_state.ranges.ranges::<usize>(buffer))
             .all(|(selection, autoclose_range)| {
                 let autoclose_range_end = autoclose_range.end.to_offset(buffer);
                 selection.is_empty() && selection.start == autoclose_range_end
@@ -3072,7 +3072,7 @@ impl Editor {
             .read(cx)
             .selection_set(set_id)
             .unwrap()
-            .intersecting_selections::<Point, _, _>(range, buffer);
+            .intersecting_selections::<Point, _>(range, buffer);
 
         selections
             .map(move |s| Selection {
@@ -3090,7 +3090,7 @@ impl Editor {
         D: 'a + TextDimension<'a> + Ord,
     {
         let buffer = self.buffer.read(cx);
-        let mut selections = self.selection_set(cx).selections::<D, _>(buffer).peekable();
+        let mut selections = self.selection_set(cx).selections::<D>(buffer).peekable();
         let mut pending_selection = self.pending_selection(cx);
         iter::from_fn(move || {
             if let Some(pending) = pending_selection.as_mut() {
@@ -3124,8 +3124,8 @@ impl Editor {
         let buffer = self.buffer.read(cx);
         self.pending_selection.as_ref().map(|pending| Selection {
             id: pending.selection.id,
-            start: pending.selection.start.summary::<D, _>(buffer),
-            end: pending.selection.end.summary::<D, _>(buffer),
+            start: pending.selection.start.summary::<D>(buffer),
+            end: pending.selection.end.summary::<D>(buffer),
             reversed: pending.selection.reversed,
             goal: pending.selection.goal,
         })
@@ -3201,7 +3201,7 @@ impl Editor {
                 if selections.len() == autoclose_pair_state.ranges.len() {
                     selections
                         .iter()
-                        .zip(autoclose_pair_state.ranges.ranges::<Point, _>(buffer))
+                        .zip(autoclose_pair_state.ranges.ranges::<Point>(buffer))
                         .all(|(selection, autoclose_range)| {
                             let head = selection.head().to_point(&*buffer);
                             autoclose_range.start <= head && autoclose_range.end >= head

crates/editor/src/movement.rs 🔗

@@ -183,7 +183,7 @@ pub fn next_word_boundary(map: &DisplayMapSnapshot, mut point: DisplayPoint) ->
 
 pub fn is_inside_word(map: &DisplayMapSnapshot, point: DisplayPoint) -> bool {
     let ix = map.clip_point(point, Bias::Left).to_offset(map, Bias::Left);
-    let text = map.buffer_snapshot.text();
+    let text = &map.buffer_snapshot;
     let next_char_kind = text.chars_at(ix).next().map(char_kind);
     let prev_char_kind = text.reversed_chars_at(ix).next().map(char_kind);
     prev_char_kind.zip(next_char_kind) == Some((CharKind::Word, CharKind::Word))
@@ -193,7 +193,7 @@ pub fn surrounding_word(map: &DisplayMapSnapshot, point: DisplayPoint) -> Range<
     let mut start = map.clip_point(point, Bias::Left).to_offset(map, Bias::Left);
     let mut end = start;
 
-    let text = map.buffer_snapshot.text();
+    let text = &map.buffer_snapshot;
     let mut next_chars = text.chars_at(start).peekable();
     let mut prev_chars = text.reversed_chars_at(start).peekable();
     let word_kind = cmp::max(

crates/language/src/buffer.rs 🔗

@@ -692,9 +692,9 @@ impl Buffer {
                 .pending_snapshots
                 .get(&version)
                 .ok_or_else(|| anyhow!("missing snapshot"))?;
-            snapshot.buffer_snapshot.content()
+            &snapshot.buffer_snapshot
         } else {
-            self.content()
+            self.deref()
         };
         let abs_path = self.file.as_ref().and_then(|f| f.abs_path());
 
@@ -816,9 +816,8 @@ impl Buffer {
         T: 'a + ToOffset,
         O: 'a + FromAnchor,
     {
-        let content = self.content();
         self.diagnostics
-            .intersecting_ranges(search_range, content, true)
+            .intersecting_ranges(search_range, self, true)
             .map(move |(_, range, diagnostic)| (range, diagnostic))
     }
 
@@ -829,9 +828,8 @@ impl Buffer {
     where
         O: 'a + FromAnchor,
     {
-        let content = self.content();
         self.diagnostics
-            .filter(content, move |diagnostic| diagnostic.group_id == group_id)
+            .filter(self, move |diagnostic| diagnostic.group_id == group_id)
             .map(move |(_, range, diagnostic)| (range, diagnostic))
     }
 
@@ -875,12 +873,12 @@ impl Buffer {
             for request in autoindent_requests {
                 let old_to_new_rows = request
                     .edited
-                    .iter::<Point, _>(&request.before_edit)
+                    .iter::<Point>(&request.before_edit)
                     .map(|point| point.row)
                     .zip(
                         request
                             .edited
-                            .iter::<Point, _>(&snapshot)
+                            .iter::<Point>(&snapshot)
                             .map(|point| point.row),
                     )
                     .collect::<BTreeMap<u32, u32>>();
@@ -943,7 +941,7 @@ impl Buffer {
                 if let Some(inserted) = request.inserted.as_ref() {
                     let inserted_row_ranges = contiguous_ranges(
                         inserted
-                            .ranges::<Point, _>(&snapshot)
+                            .ranges::<Point>(&snapshot)
                             .flat_map(|range| range.start.row..range.end.row + 1),
                         max_rows_between_yields,
                     );
@@ -991,7 +989,7 @@ impl Buffer {
         for selection_set_id in &selection_set_ids {
             if let Ok(set) = self.selection_set(*selection_set_id) {
                 let new_selections = set
-                    .selections::<Point, _>(&*self)
+                    .selections::<Point>(&*self)
                     .map(|selection| {
                         if selection.start.column == 0 {
                             let delta = Point::new(
@@ -1023,10 +1021,6 @@ impl Buffer {
             .unwrap();
     }
 
-    pub fn indent_column_for_line(&self, row: u32) -> u32 {
-        self.content().indent_column_for_line(row)
-    }
-
     fn set_indent_column_for_line(&mut self, row: u32, column: u32, cx: &mut ModelContext<Self>) {
         let current_column = self.indent_column_for_line(row);
         if column > current_column {
@@ -1239,7 +1233,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 !new_text.is_empty() || !range.is_empty() {
                 if let Some(prev_range) = ranges.last_mut() {
                     if prev_range.end >= range.start {
@@ -1260,10 +1254,10 @@ impl Buffer {
         self.pending_autoindent.take();
         let autoindent_request = if autoindent && self.language.is_some() {
             let before_edit = self.snapshot();
-            let edited = self.content().anchor_set(
+            let edited = self.anchor_set(
                 Bias::Left,
                 ranges.iter().filter_map(|range| {
-                    let start = range.start.to_point(&*self);
+                    let start = range.start.to_point(self);
                     if new_text.starts_with('\n') && start.column == self.line_len(start.row) {
                         None
                     } else {
@@ -1285,7 +1279,7 @@ impl Buffer {
             let mut inserted = None;
             if let Some(first_newline_ix) = first_newline_ix {
                 let mut delta = 0isize;
-                inserted = Some(self.content().anchor_range_set(
+                inserted = Some(self.anchor_range_set(
                     Bias::Left,
                     Bias::Right,
                     ranges.iter().map(|range| {
@@ -1524,24 +1518,6 @@ impl Deref for Buffer {
     }
 }
 
-impl<'a> From<&'a Buffer> for Content<'a> {
-    fn from(buffer: &'a Buffer) -> Self {
-        Self::from(&buffer.text)
-    }
-}
-
-impl<'a> From<&'a mut Buffer> for Content<'a> {
-    fn from(buffer: &'a mut Buffer) -> Self {
-        Self::from(&buffer.text)
-    }
-}
-
-impl<'a> From<&'a Snapshot> for Content<'a> {
-    fn from(snapshot: &'a Snapshot) -> Self {
-        Self::from(&snapshot.text)
-    }
-}
-
 impl Snapshot {
     fn suggest_autoindents<'a>(
         &'a self,
@@ -1657,14 +1633,14 @@ impl Snapshot {
         range: Range<T>,
         theme: Option<&'a SyntaxTheme>,
     ) -> Chunks<'a> {
-        let range = range.start.to_offset(&*self)..range.end.to_offset(&*self);
+        let range = range.start.to_offset(self)..range.end.to_offset(self);
 
         let mut highlights = None;
         let mut diagnostic_endpoints = Vec::<DiagnosticEndpoint>::new();
         if let Some(theme) = theme {
             for (_, range, diagnostic) in
                 self.diagnostics
-                    .intersecting_ranges(range.clone(), self.content(), true)
+                    .intersecting_ranges(range.clone(), self, true)
             {
                 diagnostic_endpoints.push(DiagnosticEndpoint {
                     offset: range.start,

crates/language/src/tests.rs 🔗

@@ -1,6 +1,15 @@
 use super::*;
 use gpui::{ModelHandle, MutableAppContext, Task};
-use std::{any::Any, cell::RefCell, ffi::OsString, iter::FromIterator, ops::Range, path::PathBuf, rc::Rc, time::{Duration, Instant, SystemTime}};
+use std::{
+    any::Any,
+    cell::RefCell,
+    ffi::OsString,
+    iter::FromIterator,
+    ops::Range,
+    path::PathBuf,
+    rc::Rc,
+    time::{Duration, Instant, SystemTime},
+};
 use unindent::Unindent as _;
 
 #[test]
@@ -359,7 +368,7 @@ fn test_autoindent_moves_selections(cx: &mut MutableAppContext) {
         let selection_ranges = buffer
             .selection_set(selection_set_id)
             .unwrap()
-            .selections::<Point, _>(&buffer)
+            .selections::<Point>(&buffer)
             .map(|selection| selection.point_range(&buffer))
             .collect::<Vec<_>>();
 

crates/project/src/worktree.rs 🔗

@@ -3630,7 +3630,7 @@ mod tests {
             let cursor_positions = buffer
                 .selection_set(selection_set_id)
                 .unwrap()
-                .selections::<Point, _>(&*buffer)
+                .selections::<Point>(&*buffer)
                 .map(|selection| {
                     assert_eq!(selection.start, selection.end);
                     selection.start

crates/text/src/anchor.rs 🔗

@@ -1,6 +1,6 @@
-use crate::rope::TextDimension;
+use crate::{rope::TextDimension, Snapshot};
 
-use super::{Buffer, Content, FromAnchor, FullOffset, Point, ToOffset};
+use super::{Buffer, FromAnchor, FullOffset, Point, ToOffset};
 use anyhow::Result;
 use std::{
     cmp::Ordering,
@@ -83,9 +83,7 @@ impl Anchor {
         }
     }
 
-    pub fn cmp<'a>(&self, other: &Anchor, buffer: impl Into<Content<'a>>) -> Result<Ordering> {
-        let buffer = buffer.into();
-
+    pub fn cmp<'a>(&self, other: &Anchor, buffer: &Snapshot) -> Result<Ordering> {
         if self == other {
             return Ok(Ordering::Equal);
         }
@@ -117,12 +115,11 @@ impl Anchor {
         }
     }
 
-    pub fn summary<'a, D, C>(&self, content: C) -> D
+    pub fn summary<'a, D>(&self, content: &'a Snapshot) -> D
     where
         D: TextDimension<'a>,
-        C: Into<Content<'a>>,
     {
-        content.into().summary_for_anchor(self)
+        content.summary_for_anchor(self)
     }
 }
 
@@ -135,13 +132,11 @@ impl<T> AnchorMap<T> {
         self.entries.len()
     }
 
-    pub fn iter<'a, D, C>(&'a self, content: C) -> impl Iterator<Item = (D, &'a T)> + 'a
+    pub fn iter<'a, D>(&'a self, snapshot: &'a Snapshot) -> impl Iterator<Item = (D, &'a T)> + 'a
     where
         D: 'a + TextDimension<'a>,
-        C: 'a + Into<Content<'a>>,
     {
-        let content = content.into();
-        content
+        snapshot
             .summaries_for_anchors(
                 self.version.clone(),
                 self.bias,
@@ -160,10 +155,9 @@ impl AnchorSet {
         self.0.len()
     }
 
-    pub fn iter<'a, D, C>(&'a self, content: C) -> impl Iterator<Item = D> + 'a
+    pub fn iter<'a, D>(&'a self, content: &'a Snapshot) -> impl Iterator<Item = D> + 'a
     where
         D: 'a + TextDimension<'a>,
-        C: 'a + Into<Content<'a>>,
     {
         self.0.iter(content).map(|(position, _)| position)
     }
@@ -194,12 +188,11 @@ impl<T> AnchorRangeMap<T> {
 
     pub fn ranges<'a, D>(
         &'a self,
-        content: impl Into<Content<'a>> + 'a,
+        content: &'a Snapshot,
     ) -> impl Iterator<Item = (Range<D>, &'a T)> + 'a
     where
         D: 'a + TextDimension<'a>,
     {
-        let content = content.into();
         content
             .summaries_for_anchor_ranges(
                 self.version.clone(),
@@ -213,13 +206,12 @@ impl<T> AnchorRangeMap<T> {
     pub fn intersecting_ranges<'a, D, I>(
         &'a self,
         range: Range<(I, Bias)>,
-        content: impl Into<Content<'a>> + 'a,
+        content: &'a Snapshot,
     ) -> impl Iterator<Item = (Range<D>, &'a T)> + 'a
     where
         D: 'a + TextDimension<'a>,
         I: ToOffset,
     {
-        let content = content.into();
         let range = content.anchor_at(range.start.0, range.start.1)
             ..content.anchor_at(range.end.0, range.end.1);
 
@@ -249,43 +241,39 @@ impl<T> AnchorRangeMap<T> {
         self.entries.iter()
     }
 
-    pub fn min_by_key<'a, C, D, F, K>(
+    pub fn min_by_key<'a, D, F, K>(
         &self,
-        content: C,
+        content: &'a Snapshot,
         mut extract_key: F,
     ) -> Option<(Range<D>, &T)>
     where
-        C: Into<Content<'a>>,
         D: 'a + TextDimension<'a>,
         F: FnMut(&T) -> K,
         K: Ord,
     {
-        let content = content.into();
         self.entries
             .iter()
             .min_by_key(|(_, value)| extract_key(value))
             .map(|(range, value)| (self.resolve_range(range, &content), value))
     }
 
-    pub fn max_by_key<'a, C, D, F, K>(
+    pub fn max_by_key<'a, D, F, K>(
         &self,
-        content: C,
+        content: &'a Snapshot,
         mut extract_key: F,
     ) -> Option<(Range<D>, &T)>
     where
-        C: Into<Content<'a>>,
         D: 'a + TextDimension<'a>,
         F: FnMut(&T) -> K,
         K: Ord,
     {
-        let content = content.into();
         self.entries
             .iter()
             .max_by_key(|(_, value)| extract_key(value))
             .map(|(range, value)| (self.resolve_range(range, &content), value))
     }
 
-    fn resolve_range<'a, D>(&self, range: &Range<FullOffset>, content: &Content<'a>) -> Range<D>
+    fn resolve_range<'a, D>(&self, range: &Range<FullOffset>, content: &'a Snapshot) -> Range<D>
     where
         D: 'a + TextDimension<'a>,
     {
@@ -342,10 +330,9 @@ impl AnchorRangeSet {
         self.0.version()
     }
 
-    pub fn ranges<'a, D, C>(&'a self, content: C) -> impl 'a + Iterator<Item = Range<Point>>
+    pub fn ranges<'a, D>(&'a self, content: &'a Snapshot) -> impl 'a + Iterator<Item = Range<Point>>
     where
         D: 'a + TextDimension<'a>,
-        C: 'a + Into<Content<'a>>,
     {
         self.0.ranges(content).map(|(range, _)| range)
     }
@@ -370,7 +357,7 @@ impl<T: Clone> AnchorRangeMultimap<T> {
     pub fn intersecting_ranges<'a, I, O>(
         &'a self,
         range: Range<I>,
-        content: Content<'a>,
+        content: &'a Snapshot,
         inclusive: bool,
     ) -> impl Iterator<Item = (usize, Range<O>, &T)> + 'a
     where
@@ -382,7 +369,6 @@ impl<T: Clone> AnchorRangeMultimap<T> {
             ..range.end.to_full_offset(&content, end_bias);
         let mut cursor = self.entries.filter::<_, usize>(
             {
-                let content = content.clone();
                 let mut endpoint = Anchor {
                     full_offset: FullOffset(0),
                     bias: Bias::Right,
@@ -465,7 +451,7 @@ impl<T: Clone> AnchorRangeMultimap<T> {
 
     pub fn filter<'a, O, F>(
         &'a self,
-        content: Content<'a>,
+        content: &'a Snapshot,
         mut f: F,
     ) -> impl 'a + Iterator<Item = (usize, Range<O>, &T)>
     where
@@ -574,21 +560,19 @@ impl<'a> sum_tree::SeekTarget<'a, AnchorRangeMultimapSummary, FullOffsetRange> f
 }
 
 pub trait AnchorRangeExt {
-    fn cmp<'a>(&self, b: &Range<Anchor>, buffer: impl Into<Content<'a>>) -> Result<Ordering>;
-    fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> Range<usize>;
+    fn cmp(&self, b: &Range<Anchor>, buffer: &Snapshot) -> Result<Ordering>;
+    fn to_offset(&self, content: &Snapshot) -> Range<usize>;
 }
 
 impl AnchorRangeExt for Range<Anchor> {
-    fn cmp<'a>(&self, other: &Range<Anchor>, buffer: impl Into<Content<'a>>) -> Result<Ordering> {
-        let buffer = buffer.into();
-        Ok(match self.start.cmp(&other.start, &buffer)? {
+    fn cmp(&self, other: &Range<Anchor>, buffer: &Snapshot) -> Result<Ordering> {
+        Ok(match self.start.cmp(&other.start, buffer)? {
             Ordering::Equal => other.end.cmp(&self.end, buffer)?,
             ord @ _ => ord,
         })
     }
 
-    fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> Range<usize> {
-        let content = content.into();
+    fn to_offset(&self, content: &Snapshot) -> Range<usize> {
         self.start.to_offset(&content)..self.end.to_offset(&content)
     }
 }

crates/text/src/selection.rs 🔗

@@ -1,8 +1,8 @@
 use sum_tree::Bias;
 
-use crate::rope::TextDimension;
+use crate::{rope::TextDimension, Snapshot};
 
-use super::{AnchorRangeMap, Buffer, Content, Point, ToOffset, ToPoint};
+use super::{AnchorRangeMap, Buffer, Point, ToOffset, ToPoint};
 use std::{cmp::Ordering, ops::Range, sync::Arc};
 
 pub type SelectionSetId = clock::Lamport;
@@ -103,10 +103,12 @@ impl SelectionSet {
         self.selections.len()
     }
 
-    pub fn selections<'a, D, C>(&'a self, content: C) -> impl 'a + Iterator<Item = Selection<D>>
+    pub fn selections<'a, D>(
+        &'a self,
+        content: &'a Snapshot,
+    ) -> impl 'a + Iterator<Item = Selection<D>>
     where
         D: 'a + TextDimension<'a>,
-        C: 'a + Into<Content<'a>>,
     {
         self.selections
             .ranges(content)
@@ -119,15 +121,14 @@ impl SelectionSet {
             })
     }
 
-    pub fn intersecting_selections<'a, D, I, C>(
+    pub fn intersecting_selections<'a, D, I>(
         &'a self,
         range: Range<(I, Bias)>,
-        content: C,
+        content: &'a Snapshot,
     ) -> impl 'a + Iterator<Item = Selection<D>>
     where
         D: 'a + TextDimension<'a>,
         I: 'a + ToOffset,
-        C: 'a + Into<Content<'a>>,
     {
         self.selections
             .intersecting_ranges(range, content)
@@ -140,10 +141,9 @@ impl SelectionSet {
             })
     }
 
-    pub fn oldest_selection<'a, D, C>(&'a self, content: C) -> Option<Selection<D>>
+    pub fn oldest_selection<'a, D>(&'a self, content: &'a Snapshot) -> Option<Selection<D>>
     where
         D: 'a + TextDimension<'a>,
-        C: 'a + Into<Content<'a>>,
     {
         self.selections
             .min_by_key(content, |selection| selection.id)
@@ -156,10 +156,9 @@ impl SelectionSet {
             })
     }
 
-    pub fn newest_selection<'a, D, C>(&'a self, content: C) -> Option<Selection<D>>
+    pub fn newest_selection<'a, D>(&'a self, content: &'a Snapshot) -> Option<Selection<D>>
     where
         D: 'a + TextDimension<'a>,
-        C: 'a + Into<Content<'a>>,
     {
         self.selections
             .max_by_key(content, |selection| selection.id)

crates/text/src/tests.rs 🔗

@@ -67,7 +67,7 @@ fn test_random_edits(mut rng: StdRng) {
 
         let range = buffer.random_byte_range(0, &mut rng);
         assert_eq!(
-            buffer.text_summary_for_range(range.clone()),
+            buffer.text_summary_for_range::<TextSummary, _>(range.clone()),
             TextSummary::from(&reference_string[range])
         );
 
@@ -119,7 +119,7 @@ fn test_line_len() {
 fn test_text_summary_for_range() {
     let buffer = Buffer::new(0, 0, History::new("ab\nefg\nhklm\nnopqrs\ntuvwxyz".into()));
     assert_eq!(
-        buffer.text_summary_for_range(1..3),
+        buffer.text_summary_for_range::<TextSummary, _>(1..3),
         TextSummary {
             bytes: 2,
             lines: Point::new(1, 0),
@@ -131,7 +131,7 @@ fn test_text_summary_for_range() {
         }
     );
     assert_eq!(
-        buffer.text_summary_for_range(1..12),
+        buffer.text_summary_for_range::<TextSummary, _>(1..12),
         TextSummary {
             bytes: 11,
             lines: Point::new(3, 0),
@@ -143,7 +143,7 @@ fn test_text_summary_for_range() {
         }
     );
     assert_eq!(
-        buffer.text_summary_for_range(0..20),
+        buffer.text_summary_for_range::<TextSummary, _>(0..20),
         TextSummary {
             bytes: 20,
             lines: Point::new(4, 1),
@@ -155,7 +155,7 @@ fn test_text_summary_for_range() {
         }
     );
     assert_eq!(
-        buffer.text_summary_for_range(0..22),
+        buffer.text_summary_for_range::<TextSummary, _>(0..22),
         TextSummary {
             bytes: 22,
             lines: Point::new(4, 3),
@@ -167,7 +167,7 @@ fn test_text_summary_for_range() {
         }
     );
     assert_eq!(
-        buffer.text_summary_for_range(7..22),
+        buffer.text_summary_for_range::<TextSummary, _>(7..22),
         TextSummary {
             bytes: 15,
             lines: Point::new(2, 3),

crates/text/src/text.rs 🔗

@@ -24,7 +24,7 @@ pub use selection::*;
 use std::{
     cmp::{self, Reverse},
     iter::Iterator,
-    ops::{self, Range},
+    ops::{self, Deref, Range},
     str,
     sync::Arc,
     time::{Duration, Instant},
@@ -34,12 +34,8 @@ use sum_tree::{FilterCursor, SumTree};
 
 #[derive(Clone)]
 pub struct Buffer {
-    fragments: SumTree<Fragment>,
-    visible_text: Rope,
-    deleted_text: Rope,
-    pub version: clock::Global,
+    snapshot: Snapshot,
     last_edit: clock::Local,
-    undo_map: UndoMap,
     history: History,
     selections: HashMap<SelectionSetId, SelectionSet>,
     deferred_ops: OperationQueue,
@@ -50,6 +46,15 @@ pub struct Buffer {
     lamport_clock: clock::Lamport,
 }
 
+#[derive(Clone)]
+pub struct Snapshot {
+    visible_text: Rope,
+    deleted_text: Rope,
+    undo_map: UndoMap,
+    fragments: SumTree<Fragment>,
+    pub version: clock::Global,
+}
+
 #[derive(Clone, Debug)]
 pub struct Transaction {
     start: clock::Global,
@@ -440,12 +445,14 @@ impl Buffer {
         }
 
         Buffer {
-            visible_text,
-            deleted_text: Rope::new(),
-            fragments,
-            version,
+            snapshot: Snapshot {
+                visible_text,
+                deleted_text: Rope::new(),
+                fragments,
+                version,
+                undo_map: Default::default(),
+            },
             last_edit: clock::Local::default(),
-            undo_map: Default::default(),
             history,
             selections: HashMap::default(),
             deferred_ops: OperationQueue::new(),
@@ -471,55 +478,6 @@ impl Buffer {
         }
     }
 
-    pub fn content<'a>(&'a self) -> Content<'a> {
-        self.into()
-    }
-
-    pub fn as_rope(&self) -> &Rope {
-        &self.visible_text
-    }
-
-    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)
-    }
-
-    pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
-        self.anchor_at(position, Bias::Right)
-    }
-
-    pub fn anchor_at<T: ToOffset>(&self, position: T, bias: Bias) -> Anchor {
-        self.content().anchor_at(position, bias)
-    }
-
-    pub fn anchor_range_set<E>(
-        &self,
-        start_bias: Bias,
-        end_bias: Bias,
-        entries: E,
-    ) -> AnchorRangeSet
-    where
-        E: IntoIterator<Item = Range<usize>>,
-    {
-        self.content()
-            .anchor_range_set(start_bias, end_bias, entries)
-    }
-
-    pub fn point_for_offset(&self, offset: usize) -> Result<Point> {
-        self.content().point_for_offset(offset)
-    }
-
-    pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
-        self.content().clip_point(point, bias)
-    }
-
-    pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
-        self.visible_text.clip_offset(offset, bias)
-    }
-
     pub fn replica_id(&self) -> ReplicaId {
         self.local_clock.replica_id
     }
@@ -528,78 +486,6 @@ impl Buffer {
         self.remote_id
     }
 
-    pub fn text_summary(&self) -> TextSummary {
-        self.visible_text.summary()
-    }
-
-    pub fn len(&self) -> usize {
-        self.content().len()
-    }
-
-    pub fn line_len(&self, row: u32) -> u32 {
-        self.content().line_len(row)
-    }
-
-    pub fn is_line_blank(&self, row: u32) -> bool {
-        self.content().is_line_blank(row)
-    }
-
-    pub fn max_point(&self) -> Point {
-        self.visible_text.max_point()
-    }
-
-    pub fn row_count(&self) -> u32 {
-        self.max_point().row + 1
-    }
-
-    pub fn text(&self) -> String {
-        self.text_for_range(0..self.len()).collect()
-    }
-
-    pub fn text_for_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> Chunks<'a> {
-        self.content().text_for_range(range)
-    }
-
-    pub fn chars(&self) -> impl Iterator<Item = char> + '_ {
-        self.chars_at(0)
-    }
-
-    pub fn chars_at<'a, T: 'a + ToOffset>(
-        &'a self,
-        position: T,
-    ) -> impl Iterator<Item = char> + 'a {
-        self.content().chars_at(position)
-    }
-
-    pub fn reversed_chars_at<'a, T: 'a + ToOffset>(
-        &'a self,
-        position: T,
-    ) -> impl Iterator<Item = char> + 'a {
-        self.content().reversed_chars_at(position)
-    }
-
-    pub fn chars_for_range<T: ToOffset>(&self, range: Range<T>) -> impl Iterator<Item = char> + '_ {
-        self.text_for_range(range).flat_map(str::chars)
-    }
-
-    pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> rope::Bytes {
-        self.content().bytes_in_range(range)
-    }
-
-    pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
-    where
-        T: ToOffset,
-    {
-        let position = position.to_offset(self);
-        position == self.clip_offset(position, Bias::Left)
-            && self
-                .bytes_in_range(position..self.len())
-                .flatten()
-                .copied()
-                .take(needle.len())
-                .eq(needle.bytes())
-    }
-
     pub fn deferred_ops_len(&self) -> usize {
         self.deferred_ops.len()
     }
@@ -630,7 +516,7 @@ impl Buffer {
         self.history.push(edit.clone());
         self.history.push_undo(edit.timestamp.local());
         self.last_edit = edit.timestamp.local();
-        self.version.observe(edit.timestamp.local());
+        self.snapshot.version.observe(edit.timestamp.local());
         self.end_transaction(None);
         edit
     }
@@ -755,9 +641,9 @@ impl Buffer {
         let (visible_text, deleted_text) = new_ropes.finish();
         drop(old_fragments);
 
-        self.fragments = new_fragments;
-        self.visible_text = visible_text;
-        self.deleted_text = deleted_text;
+        self.snapshot.fragments = new_fragments;
+        self.snapshot.visible_text = visible_text;
+        self.snapshot.deleted_text = deleted_text;
         edit.new_text = new_text;
         edit
     }
@@ -787,7 +673,7 @@ impl Buffer {
                         edit.new_text.as_deref(),
                         edit.timestamp,
                     );
-                    self.version.observe(edit.timestamp.local());
+                    self.snapshot.version.observe(edit.timestamp.local());
                     self.history.push(edit);
                 }
             }
@@ -797,7 +683,7 @@ impl Buffer {
             } => {
                 if !self.version.observed(undo.id) {
                     self.apply_undo(&undo)?;
-                    self.version.observe(undo.id);
+                    self.snapshot.version.observe(undo.id);
                     self.lamport_clock.observe(lamport_timestamp);
                 }
             }
@@ -989,15 +875,15 @@ impl Buffer {
         let (visible_text, deleted_text) = new_ropes.finish();
         drop(old_fragments);
 
-        self.fragments = new_fragments;
-        self.visible_text = visible_text;
-        self.deleted_text = deleted_text;
+        self.snapshot.fragments = new_fragments;
+        self.snapshot.visible_text = visible_text;
+        self.snapshot.deleted_text = deleted_text;
         self.local_clock.observe(timestamp.local());
         self.lamport_clock.observe(timestamp.lamport());
     }
 
     fn apply_undo(&mut self, undo: &UndoOperation) -> Result<()> {
-        self.undo_map.insert(undo);
+        self.snapshot.undo_map.insert(undo);
 
         let mut cx = undo.version.clone();
         for edit_id in undo.counts.keys().copied() {
@@ -1065,9 +951,9 @@ impl Buffer {
 
         drop(old_fragments);
         let (visible_text, deleted_text) = new_ropes.finish();
-        self.fragments = new_fragments;
-        self.visible_text = visible_text;
-        self.deleted_text = deleted_text;
+        self.snapshot.fragments = new_fragments;
+        self.snapshot.visible_text = visible_text;
+        self.snapshot.deleted_text = deleted_text;
         Ok(())
     }
 
@@ -1216,7 +1102,7 @@ impl Buffer {
             version: transaction.start.clone(),
         };
         self.apply_undo(&undo)?;
-        self.version.observe(undo.id);
+        self.snapshot.version.observe(undo.id);
 
         Ok(Operation::Undo {
             undo,
@@ -1238,7 +1124,7 @@ impl Buffer {
         &self,
         selections: &[Selection<T>],
     ) -> Arc<AnchorRangeMap<SelectionState>> {
-        Arc::new(self.content().anchor_range_map(
+        Arc::new(self.anchor_range_map(
             Bias::Left,
             Bias::Left,
             selections.iter().map(|selection| {
@@ -1345,16 +1231,6 @@ impl Buffer {
             lamport_timestamp: self.lamport_clock.tick(),
         })
     }
-
-    pub fn edits_since<'a, D>(
-        &'a self,
-        since: &'a clock::Global,
-    ) -> impl 'a + Iterator<Item = Edit<D>>
-    where
-        D: 'a + TextDimension<'a> + Ord,
-    {
-        self.content().edits_since(since)
-    }
 }
 
 #[cfg(any(test, feature = "test-support"))]
@@ -1516,13 +1392,12 @@ impl Buffer {
     }
 }
 
-#[derive(Clone)]
-pub struct Snapshot {
-    visible_text: Rope,
-    deleted_text: Rope,
-    undo_map: UndoMap,
-    fragments: SumTree<Fragment>,
-    version: clock::Global,
+impl Deref for Buffer {
+    type Target = Snapshot;
+
+    fn deref(&self) -> &Self::Target {
+        &self.snapshot
+    }
 }
 
 impl Snapshot {
@@ -1530,24 +1405,38 @@ impl Snapshot {
         &self.visible_text
     }
 
+    pub fn row_count(&self) -> u32 {
+        self.max_point().row + 1
+    }
+
     pub fn len(&self) -> usize {
         self.visible_text.len()
     }
 
-    pub fn line_len(&self, row: u32) -> u32 {
-        self.content().line_len(row)
+    pub fn chars(&self) -> impl Iterator<Item = char> + '_ {
+        self.chars_at(0)
     }
 
-    pub fn is_line_blank(&self, row: u32) -> bool {
-        self.content().is_line_blank(row)
+    pub fn chars_for_range<T: ToOffset>(&self, range: Range<T>) -> impl Iterator<Item = char> + '_ {
+        self.text_for_range(range).flat_map(str::chars)
     }
 
-    pub fn indent_column_for_line(&self, row: u32) -> u32 {
-        self.content().indent_column_for_line(row)
+    pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
+    where
+        T: ToOffset,
+    {
+        let position = position.to_offset(self);
+        position == self.clip_offset(position, Bias::Left)
+            && self
+                .bytes_in_range(position..self.len())
+                .flatten()
+                .copied()
+                .take(needle.len())
+                .eq(needle.bytes())
     }
 
-    pub fn text(&self) -> Rope {
-        self.visible_text.clone()
+    pub fn text(&self) -> String {
+        self.text_for_range(0..self.len()).collect()
     }
 
     pub fn text_summary(&self) -> TextSummary {
@@ -1558,34 +1447,6 @@ impl Snapshot {
         self.visible_text.max_point()
     }
 
-    pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> rope::Bytes {
-        self.content().bytes_in_range(range)
-    }
-
-    pub fn text_for_range<T: ToOffset>(&self, range: Range<T>) -> Chunks {
-        self.content().text_for_range(range)
-    }
-
-    pub fn text_summary_for_range<T>(&self, range: Range<T>) -> TextSummary
-    where
-        T: ToOffset,
-    {
-        let range = range.start.to_offset(self.content())..range.end.to_offset(self.content());
-        self.content().text_summary_for_range(range)
-    }
-
-    pub fn point_for_offset(&self, offset: usize) -> Result<Point> {
-        self.content().point_for_offset(offset)
-    }
-
-    pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
-        self.visible_text.clip_offset(offset, bias)
-    }
-
-    pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
-        self.visible_text.clip_point(point, bias)
-    }
-
     pub fn to_offset(&self, point: Point) -> usize {
         self.visible_text.point_to_offset(point)
     }
@@ -1594,122 +1455,36 @@ impl Snapshot {
         self.visible_text.offset_to_point(offset)
     }
 
-    pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
-        self.content().anchor_at(position, Bias::Left)
-    }
-
-    pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
-        self.content().anchor_at(position, Bias::Right)
-    }
-
-    pub fn edits_since<'a, D>(
-        &'a self,
-        since: &'a clock::Global,
-    ) -> impl 'a + Iterator<Item = Edit<D>>
-    where
-        D: 'a + TextDimension<'a> + Ord,
-    {
-        self.content().edits_since(since)
-    }
-
     pub fn version(&self) -> &clock::Global {
         &self.version
     }
 
-    pub fn content(&self) -> Content {
-        self.into()
-    }
-}
-
-#[derive(Clone)]
-pub struct Content<'a> {
-    visible_text: &'a Rope,
-    deleted_text: &'a Rope,
-    undo_map: &'a UndoMap,
-    fragments: &'a SumTree<Fragment>,
-    version: &'a clock::Global,
-}
-
-impl<'a> From<&'a Snapshot> for Content<'a> {
-    fn from(snapshot: &'a Snapshot) -> Self {
-        Self {
-            visible_text: &snapshot.visible_text,
-            deleted_text: &snapshot.deleted_text,
-            undo_map: &snapshot.undo_map,
-            fragments: &snapshot.fragments,
-            version: &snapshot.version,
-        }
-    }
-}
-
-impl<'a> From<&'a Buffer> for Content<'a> {
-    fn from(buffer: &'a Buffer) -> Self {
-        Self {
-            visible_text: &buffer.visible_text,
-            deleted_text: &buffer.deleted_text,
-            undo_map: &buffer.undo_map,
-            fragments: &buffer.fragments,
-            version: &buffer.version,
-        }
-    }
-}
-
-impl<'a> From<&'a mut Buffer> for Content<'a> {
-    fn from(buffer: &'a mut Buffer) -> Self {
-        Self {
-            visible_text: &buffer.visible_text,
-            deleted_text: &buffer.deleted_text,
-            undo_map: &buffer.undo_map,
-            fragments: &buffer.fragments,
-            version: &buffer.version,
-        }
-    }
-}
-
-impl<'a> From<&'a Content<'a>> for Content<'a> {
-    fn from(content: &'a Content) -> Self {
-        Self {
-            visible_text: &content.visible_text,
-            deleted_text: &content.deleted_text,
-            undo_map: &content.undo_map,
-            fragments: &content.fragments,
-            version: &content.version,
-        }
-    }
-}
-
-impl<'a> Content<'a> {
-    fn max_point(&self) -> Point {
-        self.visible_text.max_point()
-    }
-
-    fn len(&self) -> usize {
-        self.fragments.extent::<usize>(&None)
-    }
-
-    pub fn chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + 'a {
+    pub fn chars_at<'a, T: ToOffset>(&'a self, position: T) -> impl Iterator<Item = char> + 'a {
         let offset = position.to_offset(self);
         self.visible_text.chars_at(offset)
     }
 
-    pub fn reversed_chars_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = char> + 'a {
+    pub fn reversed_chars_at<'a, T: ToOffset>(
+        &'a self,
+        position: T,
+    ) -> impl Iterator<Item = char> + 'a {
         let offset = position.to_offset(self);
         self.visible_text.reversed_chars_at(offset)
     }
 
-    pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> rope::Bytes<'a> {
+    pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> rope::Bytes<'a> {
         let start = range.start.to_offset(self);
         let end = range.end.to_offset(self);
         self.visible_text.bytes_in_range(start..end)
     }
 
-    pub fn text_for_range<T: ToOffset>(&self, range: Range<T>) -> Chunks<'a> {
+    pub fn text_for_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> Chunks<'a> {
         let start = range.start.to_offset(self);
         let end = range.end.to_offset(self);
         self.visible_text.chunks_in_range(start..end)
     }
 
-    fn line_len(&self, row: u32) -> u32 {
+    pub fn line_len(&self, row: u32) -> u32 {
         let row_start_offset = Point::new(row, 0).to_offset(self);
         let row_end_offset = if row >= self.max_point().row {
             self.len()
@@ -1719,7 +1494,7 @@ impl<'a> Content<'a> {
         (row_end_offset - row_start_offset) as u32
     }
 
-    fn is_line_blank(&self, row: u32) -> bool {
+    pub fn is_line_blank(&self, row: u32) -> bool {
         self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row)))
             .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none())
     }
@@ -1736,7 +1511,7 @@ impl<'a> Content<'a> {
         result
     }
 
-    fn summary_for_anchor<D>(&self, anchor: &Anchor) -> D
+    fn summary_for_anchor<'a, D>(&'a self, anchor: &Anchor) -> D
     where
         D: TextDimension<'a>,
     {
@@ -1755,15 +1530,17 @@ impl<'a> Content<'a> {
         self.text_summary_for_range(0..cursor.start().1 + overshoot)
     }
 
-    fn text_summary_for_range<D>(&self, range: Range<usize>) -> D
+    pub fn text_summary_for_range<'a, D, O: ToOffset>(&'a self, range: Range<O>) -> D
     where
         D: TextDimension<'a>,
     {
-        self.visible_text.cursor(range.start).summary(range.end)
+        self.visible_text
+            .cursor(range.start.to_offset(self))
+            .summary(range.end.to_offset(self))
     }
 
-    fn summaries_for_anchors<D, I>(
-        &self,
+    fn summaries_for_anchors<'a, D, I>(
+        &'a self,
         version: clock::Global,
         bias: Bias,
         ranges: I,
@@ -1788,8 +1565,8 @@ impl<'a> Content<'a> {
         })
     }
 
-    fn summaries_for_anchor_ranges<D, I>(
-        &self,
+    fn summaries_for_anchor_ranges<'a, D, I>(
+        &'a self,
         version: clock::Global,
         start_bias: Bias,
         end_bias: Bias,
@@ -1826,7 +1603,15 @@ impl<'a> Content<'a> {
         })
     }
 
-    fn anchor_at<T: ToOffset>(&self, position: T, bias: Bias) -> Anchor {
+    pub fn anchor_before<T: ToOffset>(&self, position: T) -> Anchor {
+        self.anchor_at(position, Bias::Left)
+    }
+
+    pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
+        self.anchor_at(position, Bias::Right)
+    }
+
+    pub fn anchor_at<T: ToOffset>(&self, position: T, bias: Bias) -> Anchor {
         Anchor {
             full_offset: position.to_full_offset(self, bias),
             bias,
@@ -1962,6 +1747,10 @@ impl<'a> Content<'a> {
         FullOffset(summary.visible + summary.deleted + overshoot)
     }
 
+    pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
+        self.visible_text.clip_offset(offset, bias)
+    }
+
     pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
         self.visible_text.clip_point(point, bias)
     }
@@ -1970,7 +1759,7 @@ impl<'a> Content<'a> {
         self.visible_text.clip_point_utf16(point, bias)
     }
 
-    fn point_for_offset(&self, offset: usize) -> Result<Point> {
+    pub fn point_for_offset(&self, offset: usize) -> Result<Point> {
         if offset <= self.len() {
             Ok(self.text_summary_for_range(0..offset))
         } else {
@@ -1978,11 +1767,14 @@ impl<'a> Content<'a> {
         }
     }
 
-    pub fn edits_since<D>(&self, since: &'a clock::Global) -> impl 'a + Iterator<Item = Edit<D>>
+    pub fn edits_since<'a, D>(
+        &'a self,
+        since: &'a clock::Global,
+    ) -> impl 'a + Iterator<Item = Edit<D>>
     where
         D: 'a + TextDimension<'a> + Ord,
     {
-        let fragments_cursor = if since == self.version {
+        let fragments_cursor = if *since == self.version {
             None
         } else {
             Some(
@@ -2324,10 +2116,9 @@ impl Operation {
 }
 
 pub trait ToOffset {
-    fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> usize;
+    fn to_offset<'a>(&self, content: &Snapshot) -> usize;
 
-    fn to_full_offset<'a>(&self, content: impl Into<Content<'a>>, bias: Bias) -> FullOffset {
-        let content = content.into();
+    fn to_full_offset<'a>(&self, content: &Snapshot, bias: Bias) -> FullOffset {
         let offset = self.to_offset(&content);
         let mut cursor = content.fragments.cursor::<FragmentTextSummary>();
         cursor.seek(&offset, bias, &None);
@@ -2336,70 +2127,70 @@ pub trait ToOffset {
 }
 
 impl ToOffset for Point {
-    fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> usize {
-        content.into().visible_text.point_to_offset(*self)
+    fn to_offset<'a>(&self, content: &Snapshot) -> usize {
+        content.visible_text.point_to_offset(*self)
     }
 }
 
 impl ToOffset for PointUtf16 {
-    fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> usize {
-        content.into().visible_text.point_utf16_to_offset(*self)
+    fn to_offset<'a>(&self, content: &Snapshot) -> usize {
+        content.visible_text.point_utf16_to_offset(*self)
     }
 }
 
 impl ToOffset for usize {
-    fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> usize {
-        assert!(*self <= content.into().len(), "offset is out of range");
+    fn to_offset<'a>(&self, content: &Snapshot) -> usize {
+        assert!(*self <= content.len(), "offset is out of range");
         *self
     }
 }
 
 impl ToOffset for Anchor {
-    fn to_offset<'a>(&self, content: impl Into<Content<'a>>) -> usize {
-        content.into().summary_for_anchor(self)
+    fn to_offset<'a>(&self, content: &Snapshot) -> usize {
+        content.summary_for_anchor(self)
     }
 }
 
 impl<'a> ToOffset for &'a Anchor {
-    fn to_offset<'b>(&self, content: impl Into<Content<'b>>) -> usize {
-        content.into().summary_for_anchor(self)
+    fn to_offset(&self, content: &Snapshot) -> usize {
+        content.summary_for_anchor(self)
     }
 }
 
 pub trait ToPoint {
-    fn to_point<'a>(&self, content: impl Into<Content<'a>>) -> Point;
+    fn to_point<'a>(&self, content: &Snapshot) -> Point;
 }
 
 impl ToPoint for Anchor {
-    fn to_point<'a>(&self, content: impl Into<Content<'a>>) -> Point {
-        content.into().summary_for_anchor(self)
+    fn to_point<'a>(&self, content: &Snapshot) -> Point {
+        content.summary_for_anchor(self)
     }
 }
 
 impl ToPoint for usize {
-    fn to_point<'a>(&self, content: impl Into<Content<'a>>) -> Point {
-        content.into().visible_text.offset_to_point(*self)
+    fn to_point<'a>(&self, content: &Snapshot) -> Point {
+        content.visible_text.offset_to_point(*self)
     }
 }
 
 impl ToPoint for Point {
-    fn to_point<'a>(&self, _: impl Into<Content<'a>>) -> Point {
+    fn to_point<'a>(&self, _: &Snapshot) -> Point {
         *self
     }
 }
 
 pub trait FromAnchor {
-    fn from_anchor<'a>(anchor: &Anchor, content: &Content<'a>) -> Self;
+    fn from_anchor(anchor: &Anchor, content: &Snapshot) -> Self;
 }
 
 impl FromAnchor for Point {
-    fn from_anchor<'a>(anchor: &Anchor, content: &Content<'a>) -> Self {
+    fn from_anchor(anchor: &Anchor, content: &Snapshot) -> Self {
         anchor.to_point(content)
     }
 }
 
 impl FromAnchor for usize {
-    fn from_anchor<'a>(anchor: &Anchor, content: &Content<'a>) -> Self {
+    fn from_anchor(anchor: &Anchor, content: &Snapshot) -> Self {
         anchor.to_offset(content)
     }
 }