completions: Add subtle/eager behavior to Supermaven and Copilot (#35548)
This pull request introduces changes to improve the behavior and consistency of multiple completion providers (`CopilotCompletionProvider`, `SupermavenCompletionProvider`) and their integration with UI elements like menus and inline completion buttons. It now allows to see the prediction with the completion menu open whilst pressing `opt` and also enables the subtle/eager setting that was introduced with zeta. Edit: I managed to get the preview working with correct icons! <img width="909" height="232" alt="image" src="https://github.com/user-attachments/assets/65800e67-4bc4-40f8-be78-806fcfe74ad9" /> <img width="1460" height="318" alt="CleanShot 2025-08-04 at 01 36 31@2x" src="https://github.com/user-attachments/assets/15651405-720f-465f-a13c-c7470817810a" /> Correct icons are also displayed: <img width="244" height="96" alt="image" src="https://github.com/user-attachments/assets/0b8a687f-73e3-452d-aefb-784c52831b73" /> Edit2: I added some comments, would be very happy to receive feedback (still learning rust) Release Notes: - Added Subtle and Eager edit prediction modes to Copilot and Supermaven
This commit is contained in:
parent
dd840e4b27
commit
2234220618
7 changed files with 372 additions and 63 deletions
|
@ -234,16 +234,14 @@ fn find_relevant_completion<'a>(
|
|||
}
|
||||
|
||||
let original_cursor_offset = buffer.clip_offset(state.prefix_offset, text::Bias::Left);
|
||||
let text_inserted_since_completion_request =
|
||||
buffer.text_for_range(original_cursor_offset..current_cursor_offset);
|
||||
let mut trimmed_completion = state_completion;
|
||||
for chunk in text_inserted_since_completion_request {
|
||||
if let Some(suffix) = trimmed_completion.strip_prefix(chunk) {
|
||||
trimmed_completion = suffix;
|
||||
} else {
|
||||
continue 'completions;
|
||||
}
|
||||
}
|
||||
let text_inserted_since_completion_request: String = buffer
|
||||
.text_for_range(original_cursor_offset..current_cursor_offset)
|
||||
.collect();
|
||||
let trimmed_completion =
|
||||
match state_completion.strip_prefix(&text_inserted_since_completion_request) {
|
||||
Some(suffix) => suffix,
|
||||
None => continue 'completions,
|
||||
};
|
||||
|
||||
if best_completion.map_or(false, |best| best.len() > trimmed_completion.len()) {
|
||||
continue;
|
||||
|
@ -439,3 +437,77 @@ pub struct SupermavenCompletion {
|
|||
pub id: SupermavenCompletionStateId,
|
||||
pub updates: watch::Receiver<()>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use collections::BTreeMap;
|
||||
use gpui::TestAppContext;
|
||||
use language::Buffer;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_find_relevant_completion_no_first_letter_skip(cx: &mut TestAppContext) {
|
||||
let buffer = cx.new(|cx| Buffer::local("hello world", cx));
|
||||
let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
|
||||
|
||||
let mut states = BTreeMap::new();
|
||||
let state_id = SupermavenCompletionStateId(1);
|
||||
let (updates_tx, _) = watch::channel();
|
||||
|
||||
states.insert(
|
||||
state_id,
|
||||
SupermavenCompletionState {
|
||||
buffer_id: buffer.entity_id(),
|
||||
prefix_anchor: buffer_snapshot.anchor_before(0), // Start of buffer
|
||||
prefix_offset: 0,
|
||||
text: "hello".to_string(),
|
||||
dedent: String::new(),
|
||||
updates_tx,
|
||||
},
|
||||
);
|
||||
|
||||
let cursor_position = buffer_snapshot.anchor_after(1);
|
||||
|
||||
let result = find_relevant_completion(
|
||||
&states,
|
||||
buffer.entity_id(),
|
||||
&buffer_snapshot,
|
||||
cursor_position,
|
||||
);
|
||||
|
||||
assert_eq!(result, Some("ello"));
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_find_relevant_completion_with_multiple_chars(cx: &mut TestAppContext) {
|
||||
let buffer = cx.new(|cx| Buffer::local("hello world", cx));
|
||||
let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
|
||||
|
||||
let mut states = BTreeMap::new();
|
||||
let state_id = SupermavenCompletionStateId(1);
|
||||
let (updates_tx, _) = watch::channel();
|
||||
|
||||
states.insert(
|
||||
state_id,
|
||||
SupermavenCompletionState {
|
||||
buffer_id: buffer.entity_id(),
|
||||
prefix_anchor: buffer_snapshot.anchor_before(0), // Start of buffer
|
||||
prefix_offset: 0,
|
||||
text: "hello".to_string(),
|
||||
dedent: String::new(),
|
||||
updates_tx,
|
||||
},
|
||||
);
|
||||
|
||||
let cursor_position = buffer_snapshot.anchor_after(3);
|
||||
|
||||
let result = find_relevant_completion(
|
||||
&states,
|
||||
buffer.entity_id(),
|
||||
&buffer_snapshot,
|
||||
cursor_position,
|
||||
);
|
||||
|
||||
assert_eq!(result, Some("lo"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,6 +108,14 @@ impl EditPredictionProvider for SupermavenCompletionProvider {
|
|||
}
|
||||
|
||||
fn show_completions_in_menu() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn show_tab_accept_marker() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn supports_jump_to_edit() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
|
@ -116,7 +124,7 @@ impl EditPredictionProvider for SupermavenCompletionProvider {
|
|||
}
|
||||
|
||||
fn is_refreshing(&self) -> bool {
|
||||
self.pending_refresh.is_some()
|
||||
self.pending_refresh.is_some() && self.completion_id.is_none()
|
||||
}
|
||||
|
||||
fn refresh(
|
||||
|
@ -197,6 +205,7 @@ impl EditPredictionProvider for SupermavenCompletionProvider {
|
|||
let mut point = cursor_position.to_point(&snapshot);
|
||||
point.column = snapshot.line_len(point.row);
|
||||
let range = cursor_position..snapshot.anchor_after(point);
|
||||
|
||||
Some(completion_from_diff(
|
||||
snapshot,
|
||||
completion_text,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue