Start work on interpreting 'label/insertText' completions

Max Brunsfeld and Keith Simmons created

These completions don't supply a range that should be overwritten, so
the client needs to infer it via substring matching.

Co-authored-by: Keith Simmons <keith@zed.dev>

Change summary

crates/project/src/project.rs | 5 ++++-
crates/text/src/tests.rs      | 9 +++++++++
crates/text/src/text.rs       | 7 +++++++
3 files changed, 20 insertions(+), 1 deletion(-)

Detailed changes

crates/project/src/project.rs 🔗

@@ -2363,7 +2363,10 @@ impl Project {
                                 Some(lsp::CompletionTextEdit::Edit(edit)) => {
                                     (range_from_lsp(edit.range), edit.new_text.clone())
                                 }
-                                None => (position..position, lsp_completion.label.clone()),
+                                None => (
+                                    this.common_prefix_at_position(position, &lsp_completion.label),
+                                    lsp_completion.label.clone(),
+                                ),
                                 Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
                                     log::info!("unsupported insert/replace completion");
                                     return None;

crates/text/src/tests.rs 🔗

@@ -164,6 +164,15 @@ fn test_line_len() {
     assert_eq!(buffer.line_len(5), 0);
 }
 
+#[test]
+fn test_common_prefix_at_positionn() {
+    let buffer = Buffer::new(0, 0, History::new("a = (bcd)".into()));
+    assert_eq!(
+        buffer.common_prefix_at_position(Point::new(0, 8), "bcdef"),
+        Point::new(0, 5)..Point::new(0, 8)
+    )
+}
+
 #[test]
 fn test_text_summary_for_range() {
     let buffer = Buffer::new(0, 0, History::new("ab\nefg\nhklm\nnopqrs\ntuvwxyz".into()));

crates/text/src/text.rs 🔗

@@ -1508,6 +1508,13 @@ impl BufferSnapshot {
                 .eq(needle.bytes())
     }
 
+    pub fn common_prefix_at_position<T>(&self, position: T, needle: &str) -> Range<T>
+    where
+        T: TextDimension + ToOffset,
+    {
+        todo!()
+    }
+
     pub fn text(&self) -> String {
         self.visible_text.to_string()
     }