Track cursor offset before bias in Supermaven completion provider (#18858)

Kevin Wang created

Track the cursor offset before biasing in the Supermaven completion
provider to better determine if the text should be suggested. The
underlying issue here is due to the way anchor biasing works, the
completion provider is not able to determine if a given suggestion's
cursor location no longer exists as it is always coalesced to a correct
location (specifically, the end of the line).

This change updates that logic so the offset is stored independently of
the buffer so it can be used to represent a location that may not exist
in the buffer anymore to represent locations that have been deleted.

The net effect is that suggestions can be backspaced much more cleanly
with Supermaven.


![image](https://github.com/user-attachments/assets/ff61aa09-54ea-4cad-b1ca-633a08bcdd96)


![image](https://github.com/user-attachments/assets/b49e2d6b-f1d3-41a1-9b75-c4bc3ac5f85b)

Release Notes:

- Improves https://github.com/zed-industries/zed/issues/17981 to prevent
suggesting completions based on out-of-date cursor locations.

Change summary

crates/supermaven/src/supermaven.rs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

Detailed changes

crates/supermaven/src/supermaven.rs 🔗

@@ -141,6 +141,7 @@ impl Supermaven {
                 SupermavenCompletionState {
                     buffer_id,
                     prefix_anchor: cursor_position,
+                    prefix_offset: offset,
                     text: String::new(),
                     dedent: String::new(),
                     updates_tx,
@@ -216,7 +217,7 @@ fn find_relevant_completion<'a>(
         };
 
         let current_cursor_offset = cursor_position.to_offset(buffer);
-        let original_cursor_offset = state.prefix_anchor.to_offset(buffer);
+        let original_cursor_offset = state.prefix_offset;
         if current_cursor_offset < original_cursor_offset {
             continue;
         }
@@ -419,6 +420,9 @@ pub struct SupermavenCompletionStateId(usize);
 pub struct SupermavenCompletionState {
     buffer_id: EntityId,
     prefix_anchor: Anchor,
+    // prefix_offset is tracked independently because the anchor biases left which
+    // doesn't allow us to determine if the prior text has been deleted.
+    prefix_offset: usize,
     text: String,
     dedent: String,
     updates_tx: watch::Sender<()>,