Clamp for all UTF-16 to offset conversions which used to use `ToOffset`

Julia created

Change summary

crates/language/src/diagnostic_set.rs |  4 +-
crates/project/src/lsp_command.rs     | 36 ++++++++++++++++------------
crates/project/src/project.rs         | 17 +++++++------
crates/text/src/text.rs               | 25 +++++++++----------
4 files changed, 43 insertions(+), 39 deletions(-)

Detailed changes

crates/language/src/diagnostic_set.rs 🔗

@@ -70,8 +70,8 @@ impl DiagnosticSet {
         Self {
             diagnostics: SumTree::from_iter(
                 entries.into_iter().map(|entry| DiagnosticEntry {
-                    range: buffer.anchor_before(entry.range.start)
-                        ..buffer.anchor_after(entry.range.end),
+                    range: buffer.clamped_anchor_before(entry.range.start)
+                        ..buffer.clamped_anchor_after(entry.range.end),
                     diagnostic: entry.diagnostic,
                 }),
                 buffer,

crates/project/src/lsp_command.rs 🔗

@@ -131,7 +131,9 @@ impl LspCommand for PrepareRename {
                 if buffer.clip_point_utf16(start, Bias::Left) == start
                     && buffer.clip_point_utf16(end, Bias::Left) == end
                 {
-                    return Ok(Some(buffer.anchor_after(start)..buffer.anchor_before(end)));
+                    return Ok(Some(
+                        buffer.clamped_anchor_after(start)..buffer.clamped_anchor_before(end),
+                    ));
                 }
             }
             Ok(None)
@@ -143,7 +145,7 @@ impl LspCommand for PrepareRename {
             project_id,
             buffer_id: buffer.remote_id(),
             position: Some(language::proto::serialize_anchor(
-                &buffer.anchor_before(self.position),
+                &buffer.clamped_anchor_before(self.position),
             )),
             version: serialize_version(&buffer.version()),
         }
@@ -262,7 +264,7 @@ impl LspCommand for PerformRename {
             project_id,
             buffer_id: buffer.remote_id(),
             position: Some(language::proto::serialize_anchor(
-                &buffer.anchor_before(self.position),
+                &buffer.clamped_anchor_before(self.position),
             )),
             new_name: self.new_name.clone(),
             version: serialize_version(&buffer.version()),
@@ -360,7 +362,7 @@ impl LspCommand for GetDefinition {
             project_id,
             buffer_id: buffer.remote_id(),
             position: Some(language::proto::serialize_anchor(
-                &buffer.anchor_before(self.position),
+                &buffer.clamped_anchor_before(self.position),
             )),
             version: serialize_version(&buffer.version()),
         }
@@ -446,7 +448,7 @@ impl LspCommand for GetTypeDefinition {
             project_id,
             buffer_id: buffer.remote_id(),
             position: Some(language::proto::serialize_anchor(
-                &buffer.anchor_before(self.position),
+                &buffer.clamped_anchor_before(self.position),
             )),
             version: serialize_version(&buffer.version()),
         }
@@ -629,8 +631,8 @@ async fn location_links_from_lsp(
                     origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
                 Location {
                     buffer: buffer.clone(),
-                    range: origin_buffer.anchor_after(origin_start)
-                        ..origin_buffer.anchor_before(origin_end),
+                    range: origin_buffer.clamped_anchor_after(origin_start)
+                        ..origin_buffer.clamped_anchor_before(origin_end),
                 }
             });
 
@@ -641,8 +643,8 @@ async fn location_links_from_lsp(
                 target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
             let target_location = Location {
                 buffer: target_buffer_handle,
-                range: target_buffer.anchor_after(target_start)
-                    ..target_buffer.anchor_before(target_end),
+                range: target_buffer.clamped_anchor_after(target_start)
+                    ..target_buffer.clamped_anchor_before(target_end),
             };
 
             definitions.push(LocationLink {
@@ -741,8 +743,8 @@ impl LspCommand for GetReferences {
                         .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
                     references.push(Location {
                         buffer: target_buffer_handle,
-                        range: target_buffer.anchor_after(target_start)
-                            ..target_buffer.anchor_before(target_end),
+                        range: target_buffer.clamped_anchor_after(target_start)
+                            ..target_buffer.clamped_anchor_before(target_end),
                     });
                 });
             }
@@ -756,7 +758,7 @@ impl LspCommand for GetReferences {
             project_id,
             buffer_id: buffer.remote_id(),
             position: Some(language::proto::serialize_anchor(
-                &buffer.anchor_before(self.position),
+                &buffer.clamped_anchor_before(self.position),
             )),
             version: serialize_version(&buffer.version()),
         }
@@ -882,7 +884,8 @@ impl LspCommand for GetDocumentHighlights {
                     let end = buffer
                         .clip_point_utf16(point_from_lsp(lsp_highlight.range.end), Bias::Left);
                     DocumentHighlight {
-                        range: buffer.anchor_after(start)..buffer.anchor_before(end),
+                        range: buffer.clamped_anchor_after(start)
+                            ..buffer.clamped_anchor_before(end),
                         kind: lsp_highlight
                             .kind
                             .unwrap_or(lsp::DocumentHighlightKind::READ),
@@ -897,7 +900,7 @@ impl LspCommand for GetDocumentHighlights {
             project_id,
             buffer_id: buffer.remote_id(),
             position: Some(language::proto::serialize_anchor(
-                &buffer.anchor_before(self.position),
+                &buffer.clamped_anchor_before(self.position),
             )),
             version: serialize_version(&buffer.version()),
         }
@@ -1017,7 +1020,8 @@ impl LspCommand for GetHover {
                     let token_start =
                         buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
                     let token_end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
-                    buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
+                    buffer.clamped_anchor_after(token_start)
+                        ..buffer.clamped_anchor_before(token_end)
                 })
             });
 
@@ -1099,7 +1103,7 @@ impl LspCommand for GetHover {
             project_id,
             buffer_id: buffer.remote_id(),
             position: Some(language::proto::serialize_anchor(
-                &buffer.anchor_before(self.position),
+                &buffer.clamped_anchor_before(self.position),
             )),
             version: serialize_version(&buffer.version),
         }

crates/project/src/project.rs 🔗

@@ -25,7 +25,8 @@ use language::{
     range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CachedLspAdapter, CharKind, CodeAction,
     CodeLabel, Completion, Diagnostic, DiagnosticEntry, DiagnosticSet, Event as BufferEvent,
     File as _, Language, LanguageRegistry, LanguageServerName, LocalFile, OffsetRangeExt,
-    Operation, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction,
+    Operation, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToOffsetClamped, ToPointUtf16,
+    Transaction,
 };
 use lsp::{
     DiagnosticSeverity, DiagnosticTag, DocumentHighlightKind, LanguageServer, LanguageString,
@@ -3289,7 +3290,7 @@ impl Project {
         };
 
         let position = position.to_point_utf16(source_buffer);
-        let anchor = source_buffer.anchor_after(position);
+        let anchor = source_buffer.clamped_anchor_after(position);
 
         if worktree.read(cx).as_local().is_some() {
             let buffer_abs_path = buffer_abs_path.unwrap();
@@ -3355,7 +3356,7 @@ impl Project {
                                         return None;
                                     }
                                     (
-                                        snapshot.anchor_before(start)..snapshot.anchor_after(end),
+                                        snapshot.clamped_anchor_before(start)..snapshot.clamped_anchor_after(end),
                                         edit.new_text.clone(),
                                     )
                                 }
@@ -3368,7 +3369,7 @@ impl Project {
                                     }
                                     let Range { start, end } = range_for_token
                                         .get_or_insert_with(|| {
-                                            let offset = position.to_offset(&snapshot);
+                                            let offset = position.to_offset_clamped(&snapshot);
                                             let (range, kind) = snapshot.surrounding_word(offset);
                                             if kind == Some(CharKind::Word) {
                                                 range
@@ -5742,7 +5743,7 @@ impl Project {
                 // we can identify the changes more precisely, preserving the locations
                 // of any anchors positioned in the unchanged regions.
                 if range.end.row > range.start.row {
-                    let mut offset = range.start.to_offset(&snapshot);
+                    let mut offset = range.start.to_offset_clamped(&snapshot);
                     let old_text = snapshot.text_for_clamped_range(range).collect::<String>();
 
                     let diff = TextDiff::from_lines(old_text.as_str(), &new_text);
@@ -5778,11 +5779,11 @@ impl Project {
                         }
                     }
                 } else if range.end == range.start {
-                    let anchor = snapshot.anchor_after(range.start);
+                    let anchor = snapshot.clamped_anchor_after(range.start);
                     edits.push((anchor..anchor, new_text));
                 } else {
-                    let edit_start = snapshot.anchor_after(range.start);
-                    let edit_end = snapshot.anchor_before(range.end);
+                    let edit_start = snapshot.clamped_anchor_after(range.start);
+                    let edit_end = snapshot.clamped_anchor_before(range.end);
                     edits.push((edit_start..edit_end, new_text));
                 }
             }

crates/text/src/text.rs 🔗

@@ -1808,12 +1808,23 @@ impl BufferSnapshot {
         self.anchor_at(position, Bias::Left)
     }
 
+    pub fn clamped_anchor_before<T: ToOffsetClamped>(&self, position: T) -> Anchor {
+        self.anchor_at_offset(position.to_offset_clamped(self), Bias::Left)
+    }
+
     pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
         self.anchor_at(position, Bias::Right)
     }
 
+    pub fn clamped_anchor_after<T: ToOffsetClamped>(&self, position: T) -> Anchor {
+        self.anchor_at_offset(position.to_offset_clamped(self), Bias::Right)
+    }
+
     pub fn anchor_at<T: ToOffset>(&self, position: T, bias: Bias) -> Anchor {
-        let offset = position.to_offset(self);
+        self.anchor_at_offset(position.to_offset(self), bias)
+    }
+
+    fn anchor_at_offset(&self, offset: usize, bias: Bias) -> Anchor {
         if bias == Bias::Left && offset == 0 {
             Anchor::MIN
         } else if bias == Bias::Right && offset == self.len() {
@@ -2369,12 +2380,6 @@ impl ToOffset for Point {
     }
 }
 
-impl ToOffset for PointUtf16 {
-    fn to_offset<'a>(&self, snapshot: &BufferSnapshot) -> usize {
-        snapshot.point_utf16_to_offset(*self)
-    }
-}
-
 impl ToOffset for usize {
     fn to_offset<'a>(&self, snapshot: &BufferSnapshot) -> usize {
         assert!(*self <= snapshot.len(), "offset {self} is out of range");
@@ -2382,12 +2387,6 @@ impl ToOffset for usize {
     }
 }
 
-impl ToOffset for OffsetUtf16 {
-    fn to_offset<'a>(&self, snapshot: &BufferSnapshot) -> usize {
-        snapshot.offset_utf16_to_offset(*self)
-    }
-}
-
 impl ToOffset for Anchor {
     fn to_offset<'a>(&self, snapshot: &BufferSnapshot) -> usize {
         snapshot.summary_for_anchor(self)