Remove unneccessary snapshot storing in the buffer chunks (#44972)

Kirill Bulatov and Lukas Wirth created

Release Notes:

- N/A

Co-authored-by: Lukas Wirth <me@lukaswirth.dev>

Change summary

crates/language/src/buffer.rs                    |  6 -
crates/language/src/buffer/row_chunk.rs          | 62 ++++++++---------
crates/project/src/lsp_store.rs                  | 21 ++++-
crates/project/src/lsp_store/inlay_hint_cache.rs | 11 --
4 files changed, 50 insertions(+), 50 deletions(-)

Detailed changes

crates/language/src/buffer.rs 🔗

@@ -4317,14 +4317,12 @@ impl BufferSnapshot {
         for chunk in self
             .tree_sitter_data
             .chunks
-            .applicable_chunks(&[self.anchor_before(range.start)..self.anchor_after(range.end)])
+            .applicable_chunks(&[range.to_point(self)])
         {
             if known_chunks.is_some_and(|chunks| chunks.contains(&chunk.row_range())) {
                 continue;
             }
-            let Some(chunk_range) = self.tree_sitter_data.chunks.chunk_range(chunk) else {
-                continue;
-            };
+            let chunk_range = chunk.anchor_range();
             let chunk_range = chunk_range.to_offset(&self);
 
             if let Some(cached_brackets) =

crates/language/src/buffer/row_chunk.rs 🔗

@@ -3,7 +3,6 @@
 
 use std::{ops::Range, sync::Arc};
 
-use clock::Global;
 use text::{Anchor, OffsetRangeExt as _, Point};
 use util::RangeExt;
 
@@ -19,14 +18,13 @@ use crate::BufferRow;
 /// <https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#inlayHintParams>
 #[derive(Clone)]
 pub struct RowChunks {
-    snapshot: text::BufferSnapshot,
     chunks: Arc<[RowChunk]>,
+    version: clock::Global,
 }
 
 impl std::fmt::Debug for RowChunks {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         f.debug_struct("RowChunks")
-            .field("version", self.snapshot.version())
             .field("chunks", &self.chunks)
             .finish()
     }
@@ -38,34 +36,45 @@ impl RowChunks {
         let last_row = buffer_point_range.end.row;
         let chunks = (buffer_point_range.start.row..=last_row)
             .step_by(max_rows_per_chunk as usize)
+            .collect::<Vec<_>>();
+        let last_chunk_id = chunks.len() - 1;
+        let chunks = chunks
+            .into_iter()
             .enumerate()
-            .map(|(id, chunk_start)| RowChunk {
-                id,
-                start: chunk_start,
-                end_exclusive: (chunk_start + max_rows_per_chunk).min(last_row),
+            .map(|(id, chunk_start)| {
+                let start = Point::new(chunk_start, 0);
+                let end_exclusive = (chunk_start + max_rows_per_chunk).min(last_row);
+                let end = if id == last_chunk_id {
+                    Point::new(end_exclusive, snapshot.line_len(end_exclusive))
+                } else {
+                    Point::new(end_exclusive, 0)
+                };
+                RowChunk {
+                    id,
+                    start: chunk_start,
+                    end_exclusive,
+                    start_anchor: snapshot.anchor_before(start),
+                    end_anchor: snapshot.anchor_after(end),
+                }
             })
             .collect::<Vec<_>>();
         Self {
-            snapshot,
             chunks: Arc::from(chunks),
+            version: snapshot.version().clone(),
         }
     }
 
-    pub fn version(&self) -> &Global {
-        self.snapshot.version()
+    pub fn version(&self) -> &clock::Global {
+        &self.version
     }
 
     pub fn len(&self) -> usize {
         self.chunks.len()
     }
 
-    pub fn applicable_chunks(
-        &self,
-        ranges: &[Range<text::Anchor>],
-    ) -> impl Iterator<Item = RowChunk> {
+    pub fn applicable_chunks(&self, ranges: &[Range<Point>]) -> impl Iterator<Item = RowChunk> {
         let row_ranges = ranges
             .iter()
-            .map(|range| range.to_point(&self.snapshot))
             // Be lenient and yield multiple chunks if they "touch" the exclusive part of the range.
             // This will result in LSP hints [re-]queried for more ranges, but also more hints already visible when scrolling around.
             .map(|point_range| point_range.start.row..point_range.end.row + 1)
@@ -81,23 +90,6 @@ impl RowChunks {
             .copied()
     }
 
-    pub fn chunk_range(&self, chunk: RowChunk) -> Option<Range<Anchor>> {
-        if !self.chunks.contains(&chunk) {
-            return None;
-        }
-
-        let start = Point::new(chunk.start, 0);
-        let end = if self.chunks.last() == Some(&chunk) {
-            Point::new(
-                chunk.end_exclusive,
-                self.snapshot.line_len(chunk.end_exclusive),
-            )
-        } else {
-            Point::new(chunk.end_exclusive, 0)
-        };
-        Some(self.snapshot.anchor_before(start)..self.snapshot.anchor_after(end))
-    }
-
     pub fn previous_chunk(&self, chunk: RowChunk) -> Option<RowChunk> {
         if chunk.id == 0 {
             None
@@ -112,10 +104,16 @@ pub struct RowChunk {
     pub id: usize,
     pub start: BufferRow,
     pub end_exclusive: BufferRow,
+    pub start_anchor: Anchor,
+    pub end_anchor: Anchor,
 }
 
 impl RowChunk {
     pub fn row_range(&self) -> Range<BufferRow> {
         self.start..self.end_exclusive
     }
+
+    pub fn anchor_range(&self) -> Range<Anchor> {
+        self.start_anchor..self.end_anchor
+    }
 }

crates/project/src/lsp_store.rs 🔗

@@ -6849,9 +6849,15 @@ impl LspStore {
         ranges: &[Range<text::Anchor>],
         cx: &mut Context<Self>,
     ) -> Vec<Range<BufferRow>> {
+        let buffer_snapshot = buffer.read(cx).snapshot();
+        let ranges = ranges
+            .iter()
+            .map(|range| range.to_point(&buffer_snapshot))
+            .collect::<Vec<_>>();
+
         self.latest_lsp_data(buffer, cx)
             .inlay_hints
-            .applicable_chunks(ranges)
+            .applicable_chunks(ranges.as_slice())
             .map(|chunk| chunk.row_range())
             .collect()
     }
@@ -6898,6 +6904,12 @@ impl LspStore {
             .map(|(_, known_chunks)| known_chunks)
             .unwrap_or_default();
 
+        let buffer_snapshot = buffer.read(cx).snapshot();
+        let ranges = ranges
+            .iter()
+            .map(|range| range.to_point(&buffer_snapshot))
+            .collect::<Vec<_>>();
+
         let mut hint_fetch_tasks = Vec::new();
         let mut cached_inlay_hints = None;
         let mut ranges_to_query = None;
@@ -6922,9 +6934,7 @@ impl LspStore {
                     .cloned(),
             ) {
                 (None, None) => {
-                    let Some(chunk_range) = existing_inlay_hints.chunk_range(row_chunk) else {
-                        continue;
-                    };
+                    let chunk_range = row_chunk.anchor_range();
                     ranges_to_query
                         .get_or_insert_with(Vec::new)
                         .push((row_chunk, chunk_range));
@@ -12726,10 +12736,11 @@ impl LspStore {
             .update(cx, |buffer, _| buffer.wait_for_version(version))?
             .await?;
         lsp_store.update(cx, |lsp_store, cx| {
+            let buffer_snapshot = buffer.read(cx).snapshot();
             let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
             let chunks_queried_for = lsp_data
                 .inlay_hints
-                .applicable_chunks(&[range])
+                .applicable_chunks(&[range.to_point(&buffer_snapshot)])
                 .collect::<Vec<_>>();
             match chunks_queried_for.as_slice() {
                 &[chunk] => {

crates/project/src/lsp_store/inlay_hint_cache.rs 🔗

@@ -8,7 +8,7 @@ use language::{
     row_chunk::{RowChunk, RowChunks},
 };
 use lsp::LanguageServerId;
-use text::Anchor;
+use text::Point;
 
 use crate::{InlayHint, InlayId};
 
@@ -90,10 +90,7 @@ impl BufferInlayHints {
         }
     }
 
-    pub fn applicable_chunks(
-        &self,
-        ranges: &[Range<text::Anchor>],
-    ) -> impl Iterator<Item = RowChunk> {
+    pub fn applicable_chunks(&self, ranges: &[Range<Point>]) -> impl Iterator<Item = RowChunk> {
         self.chunks.applicable_chunks(ranges)
     }
 
@@ -226,8 +223,4 @@ impl BufferInlayHints {
             }
         }
     }
-
-    pub fn chunk_range(&self, chunk: RowChunk) -> Option<Range<Anchor>> {
-        self.chunks.chunk_range(chunk)
-    }
 }