ep: Improve trigger granularity (#58561)
Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Closes #ISSUE Release Notes: - N/A or Added/Fixed/Improved ...
This commit is contained in:
1 parent
252b52e83f
commit
acdef5d09b
15 files changed
+457
-73
No files matched your search
@@ -122,7 +122,13 @@ pub struct PredictEditsBody {
|
||||
pub enum PredictEditsRequestTrigger {
|
||||
Testing,
|
||||
Diagnostics,
|
||||
DiagnosticNavigation,
|
||||
Cli,
|
||||
Explicit,
|
||||
BufferEdit,
|
||||
LSPCompletionAccepted,
|
||||
PredictionAccepted,
|
||||
PredictionPartiallyAccepted,
|
||||
#[default]
|
||||
Other,
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use anyhow::Result;
|
||||
use edit_prediction::cursor_excerpt;
|
||||
use edit_prediction_types::{
|
||||
EditPrediction, EditPredictionDelegate, EditPredictionDiscardReason, EditPredictionIconSet,
|
||||
EditPredictionRequestTrigger,
|
||||
};
|
||||
use futures::AsyncReadExt;
|
||||
use gpui::{App, AppContext as _, Context, Entity, Global, SharedString, Task};
|
||||
@@ -222,6 +223,7 @@ impl EditPredictionDelegate for CodestralEditPredictionDelegate {
|
||||
buffer: Entity<Buffer>,
|
||||
cursor_position: language::Anchor,
|
||||
debounce: bool,
|
||||
_trigger: EditPredictionRequestTrigger,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
log::debug!("Codestral: Refresh called (debounce: {})", debounce);
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::{
|
||||
use anyhow::Result;
|
||||
use edit_prediction_types::{
|
||||
EditPrediction, EditPredictionDelegate, EditPredictionDiscardReason, EditPredictionIconSet,
|
||||
interpolate_edits,
|
||||
EditPredictionRequestTrigger, interpolate_edits,
|
||||
};
|
||||
use gpui::{App, Context, Entity, Task, TaskExt};
|
||||
use icons::IconName;
|
||||
@@ -78,6 +78,7 @@ impl EditPredictionDelegate for CopilotEditPredictionDelegate {
|
||||
buffer: Entity<Buffer>,
|
||||
cursor_position: language::Anchor,
|
||||
debounce: bool,
|
||||
_trigger: EditPredictionRequestTrigger,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let copilot = self.copilot.clone();
|
||||
@@ -1041,7 +1042,13 @@ mod tests {
|
||||
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
|
||||
selections.select_ranges([Point::new(0, 0)..Point::new(0, 0)])
|
||||
});
|
||||
editor.refresh_edit_prediction(true, false, window, cx);
|
||||
editor.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT);
|
||||
@@ -1051,7 +1058,13 @@ mod tests {
|
||||
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
|
||||
s.select_ranges([Point::new(5, 0)..Point::new(5, 0)])
|
||||
});
|
||||
editor.refresh_edit_prediction(true, false, window, cx);
|
||||
editor.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT);
|
||||
|
||||
@@ -22,6 +22,7 @@ use copilot::{Copilot, Reinstall, SignIn, SignOut};
|
||||
use credentials_provider::CredentialsProvider;
|
||||
use db::kvp::{Dismissable, KeyValueStore};
|
||||
use edit_prediction_context::{RelatedExcerptStore, RelatedExcerptStoreEvent, RelatedFile};
|
||||
use edit_prediction_types::EditPredictionRequestTrigger;
|
||||
use feature_flags::{FeatureFlag, FeatureFlagAppExt as _, PresenceFlag, register_feature_flag};
|
||||
use futures::{
|
||||
AsyncReadExt as _, FutureExt as _, StreamExt as _,
|
||||
@@ -842,6 +843,28 @@ pub(crate) fn buffer_path_with_id_fallback(
|
||||
}
|
||||
}
|
||||
|
||||
fn predict_edits_request_trigger_from_editor_trigger(
|
||||
trigger: EditPredictionRequestTrigger,
|
||||
) -> PredictEditsRequestTrigger {
|
||||
match trigger {
|
||||
EditPredictionRequestTrigger::DiagnosticNavigation => {
|
||||
PredictEditsRequestTrigger::DiagnosticNavigation
|
||||
}
|
||||
EditPredictionRequestTrigger::Explicit => PredictEditsRequestTrigger::Explicit,
|
||||
EditPredictionRequestTrigger::BufferEdit => PredictEditsRequestTrigger::BufferEdit,
|
||||
EditPredictionRequestTrigger::LSPCompletionAccepted => {
|
||||
PredictEditsRequestTrigger::LSPCompletionAccepted
|
||||
}
|
||||
EditPredictionRequestTrigger::PredictionAccepted => {
|
||||
PredictEditsRequestTrigger::PredictionAccepted
|
||||
}
|
||||
EditPredictionRequestTrigger::PredictionPartiallyAccepted => {
|
||||
PredictEditsRequestTrigger::PredictionPartiallyAccepted
|
||||
}
|
||||
EditPredictionRequestTrigger::Other => PredictEditsRequestTrigger::Other,
|
||||
}
|
||||
}
|
||||
|
||||
impl EditPredictionStore {
|
||||
pub fn try_global(cx: &App) -> Option<Entity<Self>> {
|
||||
cx.try_global::<EditPredictionStoreGlobal>()
|
||||
@@ -2215,21 +2238,25 @@ impl EditPredictionStore {
|
||||
project: Entity<Project>,
|
||||
buffer: Entity<Buffer>,
|
||||
position: language::Anchor,
|
||||
trigger: EditPredictionRequestTrigger,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let trigger = predict_edits_request_trigger_from_editor_trigger(trigger);
|
||||
|
||||
self.queue_prediction_refresh(
|
||||
project.clone(),
|
||||
PredictEditsRequestTrigger::Other,
|
||||
trigger,
|
||||
buffer.entity_id(),
|
||||
cx,
|
||||
move |this, cx| {
|
||||
let Some(request_task) = this
|
||||
.update(cx, |this, cx| {
|
||||
this.request_prediction(
|
||||
&project,
|
||||
&buffer,
|
||||
this.request_prediction_internal(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
PredictEditsRequestTrigger::Other,
|
||||
trigger,
|
||||
cx.has_flag::<EditPredictionJumpsFeatureFlag>(),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
@@ -2333,11 +2360,12 @@ impl EditPredictionStore {
|
||||
|
||||
let Some(prediction_result) = this
|
||||
.update(cx, |this, cx| {
|
||||
this.request_prediction(
|
||||
&project,
|
||||
&jump_buffer,
|
||||
this.request_prediction_internal(
|
||||
project.clone(),
|
||||
jump_buffer.clone(),
|
||||
jump_position,
|
||||
PredictEditsRequestTrigger::Diagnostics,
|
||||
cx.has_flag::<EditPredictionJumpsFeatureFlag>(),
|
||||
cx,
|
||||
)
|
||||
})?
|
||||
@@ -2454,7 +2482,8 @@ impl EditPredictionStore {
|
||||
request_trigger: PredictEditsRequestTrigger,
|
||||
) -> &mut Option<(EntityId, Instant)> {
|
||||
match request_trigger {
|
||||
PredictEditsRequestTrigger::Diagnostics => {
|
||||
PredictEditsRequestTrigger::Diagnostics
|
||||
| PredictEditsRequestTrigger::DiagnosticNavigation => {
|
||||
&mut project_state.last_jump_prediction_refresh
|
||||
}
|
||||
_ => &mut project_state.last_edit_prediction_refresh,
|
||||
@@ -2769,7 +2798,8 @@ impl EditPredictionStore {
|
||||
inputs.snapshot.clone(),
|
||||
inputs.position,
|
||||
match trigger {
|
||||
PredictEditsRequestTrigger::Diagnostics => {
|
||||
PredictEditsRequestTrigger::Diagnostics
|
||||
| PredictEditsRequestTrigger::DiagnosticNavigation => {
|
||||
JumpExampleTrigger::Diagnostic
|
||||
}
|
||||
_ => JumpExampleTrigger::Prediction,
|
||||
@@ -2802,7 +2832,11 @@ impl EditPredictionStore {
|
||||
if prediction.is_none()
|
||||
&& allow_jump
|
||||
&& has_events
|
||||
&& !matches!(trigger, PredictEditsRequestTrigger::Diagnostics)
|
||||
&& !matches!(
|
||||
trigger,
|
||||
PredictEditsRequestTrigger::Diagnostics
|
||||
| PredictEditsRequestTrigger::DiagnosticNavigation
|
||||
)
|
||||
{
|
||||
this.update(cx, |this, cx| {
|
||||
this.refresh_prediction_from_diagnostics(
|
||||
|
||||
@@ -9,10 +9,12 @@ use cloud_api_types::{
|
||||
SubmitEditPredictionSettledResponse,
|
||||
};
|
||||
use cloud_llm_client::{
|
||||
EditPredictionRejectReason, EditPredictionRejection, RejectEditPredictionsBody,
|
||||
EditPredictionRejectReason, EditPredictionRejection, PredictEditsRequestTrigger,
|
||||
RejectEditPredictionsBody,
|
||||
predict_edits_v3::{PredictEditsV3Request, PredictEditsV3Response},
|
||||
};
|
||||
use db::AppDatabase;
|
||||
use edit_prediction_types::EditPredictionRequestTrigger;
|
||||
use settings::EditPredictionDataCollectionChoice;
|
||||
|
||||
use futures::{
|
||||
@@ -84,7 +86,13 @@ async fn test_current_state(cx: &mut TestAppContext) {
|
||||
// Prediction for current file
|
||||
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer1.clone(), position, cx)
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer1.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
|
||||
@@ -239,7 +247,13 @@ async fn test_diagnostics_refresh_suppressed_while_following(cx: &mut TestAppCon
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.register_project(&project, cx);
|
||||
ep_store.register_buffer(&buffer1, &project, cx);
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer1.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer1.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let (request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
@@ -441,7 +455,13 @@ async fn test_simple_request(cx: &mut TestAppContext) {
|
||||
let position = snapshot.anchor_before(language::Point::new(1, 3));
|
||||
|
||||
let prediction_task = ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.request_prediction(&project, &buffer, position, Default::default(), cx)
|
||||
ep_store.request_prediction(
|
||||
&project,
|
||||
&buffer,
|
||||
position,
|
||||
PredictEditsRequestTrigger::Other,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let (request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
@@ -517,7 +537,13 @@ async fn test_request_events(cx: &mut TestAppContext) {
|
||||
let position = snapshot.anchor_before(language::Point::new(1, 3));
|
||||
|
||||
let prediction_task = ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.request_prediction(&project, &buffer, position, Default::default(), cx)
|
||||
ep_store.request_prediction(
|
||||
&project,
|
||||
&buffer,
|
||||
position,
|
||||
PredictEditsRequestTrigger::Other,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let (request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
@@ -1441,7 +1467,13 @@ async fn test_empty_prediction(cx: &mut TestAppContext) {
|
||||
let position = snapshot.anchor_before(language::Point::new(1, 3));
|
||||
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let (request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
@@ -1499,7 +1531,13 @@ async fn test_interpolated_empty(cx: &mut TestAppContext) {
|
||||
let position = snapshot.anchor_before(language::Point::new(1, 3));
|
||||
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let (request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
@@ -1572,7 +1610,13 @@ async fn test_replace_current(cx: &mut TestAppContext) {
|
||||
let position = snapshot.anchor_before(language::Point::new(1, 3));
|
||||
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let (request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
@@ -1595,7 +1639,13 @@ async fn test_replace_current(cx: &mut TestAppContext) {
|
||||
|
||||
// a second request is triggered
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let (request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
@@ -1656,7 +1706,13 @@ async fn test_current_preferred(cx: &mut TestAppContext) {
|
||||
let position = snapshot.anchor_before(language::Point::new(1, 3));
|
||||
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let (request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
@@ -1679,7 +1735,13 @@ async fn test_current_preferred(cx: &mut TestAppContext) {
|
||||
|
||||
// a second request is triggered
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let (request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
@@ -1754,13 +1816,25 @@ async fn test_cancel_earlier_pending_requests(cx: &mut TestAppContext) {
|
||||
|
||||
// start two refresh tasks
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let (request1, respond_first) = requests.predict.next().await.unwrap();
|
||||
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let (request, respond_second) = requests.predict.next().await.unwrap();
|
||||
@@ -1848,13 +1922,25 @@ async fn test_cancel_second_on_third_request(cx: &mut TestAppContext) {
|
||||
|
||||
// start two refresh tasks
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let (request1, respond_first) = requests.predict.next().await.unwrap();
|
||||
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let (request2, respond_second) = requests.predict.next().await.unwrap();
|
||||
@@ -1864,7 +1950,13 @@ async fn test_cancel_second_on_third_request(cx: &mut TestAppContext) {
|
||||
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
// start a third request
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
|
||||
// 2 are pending, so 2nd is cancelled
|
||||
assert_eq!(
|
||||
@@ -1999,7 +2091,13 @@ async fn test_jump_and_edit_throttles_are_independent(cx: &mut TestAppContext) {
|
||||
|
||||
// First edit request - no prior edit, so not throttled.
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
let (_edit_request, edit_response_tx) = requests.predict.next().await.unwrap();
|
||||
edit_response_tx.send(empty_response()).unwrap();
|
||||
@@ -2037,7 +2135,13 @@ async fn test_jump_and_edit_throttles_are_independent(cx: &mut TestAppContext) {
|
||||
|
||||
// Second edit request - should be throttled by the first edit.
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
assert_no_predict_request_ready(&mut requests.predict);
|
||||
|
||||
@@ -2096,14 +2200,26 @@ async fn test_cloud_timeout_backs_off_zeta_requests(cx: &mut TestAppContext) {
|
||||
});
|
||||
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
let (_request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
respond_tx.send(request_timeout_response()).unwrap();
|
||||
cx.run_until_parked();
|
||||
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
cx.background_executor
|
||||
.advance_clock(EditPredictionStore::THROTTLE_TIMEOUT);
|
||||
@@ -2117,7 +2233,13 @@ async fn test_cloud_timeout_backs_off_zeta_requests(cx: &mut TestAppContext) {
|
||||
cx.run_until_parked();
|
||||
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
let (_request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
respond_tx.send(empty_response()).unwrap();
|
||||
@@ -2152,8 +2274,20 @@ async fn test_same_frame_duplicate_requests_deduplicated(cx: &mut TestAppContext
|
||||
// capture the same `proceed_count_at_enqueue`. Only the first task should
|
||||
// pass the deduplication gate; the second should be skipped.
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
// Let both spawned tasks run to completion (including any throttle waits).
|
||||
@@ -3013,7 +3147,13 @@ async fn test_edit_prediction_no_spurious_trailing_newline(cx: &mut TestAppConte
|
||||
let position = snapshot.anchor_before(language::Point::new(0, 5));
|
||||
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let (request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
@@ -3077,7 +3217,13 @@ async fn test_v3_prediction_strips_cursor_marker_from_edit_text(cx: &mut TestApp
|
||||
let position = snapshot.anchor_before(language::Point::new(0, 5));
|
||||
|
||||
ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.refresh_prediction_from_buffer(project.clone(), buffer.clone(), position, cx);
|
||||
ep_store.refresh_prediction_from_buffer(
|
||||
project.clone(),
|
||||
buffer.clone(),
|
||||
position,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let (request, respond_tx) = requests.predict.next().await.unwrap();
|
||||
@@ -3146,7 +3292,13 @@ async fn run_edit_prediction(
|
||||
});
|
||||
cx.background_executor.run_until_parked();
|
||||
let prediction_task = ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.request_prediction(&project, buffer, cursor, Default::default(), cx)
|
||||
ep_store.request_prediction(
|
||||
&project,
|
||||
buffer,
|
||||
cursor,
|
||||
PredictEditsRequestTrigger::Other,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
prediction_task.await.unwrap().unwrap().prediction.unwrap()
|
||||
}
|
||||
@@ -3326,7 +3478,13 @@ async fn test_unauthenticated_without_custom_url_blocks_prediction_impl(cx: &mut
|
||||
|
||||
let completion_task = ep_store.update(cx, |ep_store, cx| {
|
||||
ep_store.set_edit_prediction_model(EditPredictionModel::Zeta);
|
||||
ep_store.request_prediction(&project, &buffer, cursor, Default::default(), cx)
|
||||
ep_store.request_prediction(
|
||||
&project,
|
||||
&buffer,
|
||||
cursor,
|
||||
PredictEditsRequestTrigger::Other,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
assert!(completion_task.await.unwrap().is_none());
|
||||
|
||||
@@ -4,7 +4,7 @@ use client::{Client, UserStore};
|
||||
use cloud_llm_client::EditPredictionRejectReason;
|
||||
use edit_prediction_types::{
|
||||
DataCollectionState, EditPredictionDelegate, EditPredictionDiscardReason,
|
||||
EditPredictionIconSet, SuggestionDisplayType,
|
||||
EditPredictionIconSet, EditPredictionRequestTrigger, SuggestionDisplayType,
|
||||
};
|
||||
use feature_flags::FeatureFlagAppExt;
|
||||
use fs::Fs;
|
||||
@@ -143,6 +143,7 @@ impl EditPredictionDelegate for ZedEditPredictionDelegate {
|
||||
buffer: Entity<language::Buffer>,
|
||||
cursor_position: language::Anchor,
|
||||
_debounce: bool,
|
||||
trigger: EditPredictionRequestTrigger,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let store = self.store.read(cx);
|
||||
@@ -163,7 +164,13 @@ impl EditPredictionDelegate for ZedEditPredictionDelegate {
|
||||
}
|
||||
|
||||
store.refresh_context(&self.project, &buffer, cursor_position, cx);
|
||||
store.refresh_prediction_from_buffer(self.project.clone(), buffer, cursor_position, cx)
|
||||
store.refresh_prediction_from_buffer(
|
||||
self.project.clone(),
|
||||
buffer,
|
||||
cursor_position,
|
||||
trigger,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,19 @@ pub enum EditPredictionDiscardReason {
|
||||
Rejected,
|
||||
Ignored,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum EditPredictionRequestTrigger {
|
||||
DiagnosticNavigation,
|
||||
Explicit,
|
||||
BufferEdit,
|
||||
LSPCompletionAccepted,
|
||||
PredictionAccepted,
|
||||
PredictionPartiallyAccepted,
|
||||
#[default]
|
||||
Other,
|
||||
}
|
||||
|
||||
use icons::IconName;
|
||||
use language::{Anchor, Buffer, OffsetRangeExt};
|
||||
|
||||
@@ -185,6 +198,7 @@ pub trait EditPredictionDelegate: 'static + Sized {
|
||||
buffer: Entity<Buffer>,
|
||||
cursor_position: language::Anchor,
|
||||
debounce: bool,
|
||||
trigger: EditPredictionRequestTrigger,
|
||||
cx: &mut Context<Self>,
|
||||
);
|
||||
fn accept(&mut self, cx: &mut Context<Self>);
|
||||
@@ -221,6 +235,7 @@ pub trait EditPredictionDelegateHandle {
|
||||
buffer: Entity<Buffer>,
|
||||
cursor_position: language::Anchor,
|
||||
debounce: bool,
|
||||
trigger: EditPredictionRequestTrigger,
|
||||
cx: &mut App,
|
||||
);
|
||||
fn did_show(&self, display_type: SuggestionDisplayType, cx: &mut App);
|
||||
@@ -296,10 +311,11 @@ where
|
||||
buffer: Entity<Buffer>,
|
||||
cursor_position: language::Anchor,
|
||||
debounce: bool,
|
||||
trigger: EditPredictionRequestTrigger,
|
||||
cx: &mut App,
|
||||
) {
|
||||
self.update(cx, |this, cx| {
|
||||
this.refresh(buffer, cursor_position, debounce, cx)
|
||||
this.refresh(buffer, cursor_position, debounce, trigger, cx)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -910,7 +910,13 @@ impl Editor {
|
||||
});
|
||||
}
|
||||
linked_edits.apply(cx);
|
||||
editor.refresh_edit_prediction(true, false, window, cx);
|
||||
editor.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::LSPCompletionAccepted,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
self.invalidate_autoclose_regions(
|
||||
&self.selections.disjoint_anchors_arc(),
|
||||
|
||||
@@ -191,7 +191,13 @@ impl Editor {
|
||||
s.select_ranges(vec![diagnostic.range.start..diagnostic.range.start])
|
||||
});
|
||||
self.activate_diagnostics(buffer_id, diagnostic, window, cx);
|
||||
self.refresh_edit_prediction(false, true, window, cx);
|
||||
self.refresh_edit_prediction(
|
||||
false,
|
||||
true,
|
||||
EditPredictionRequestTrigger::DiagnosticNavigation,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn go_to_diagnostic_in_direction(
|
||||
|
||||
@@ -166,7 +166,13 @@ impl Editor {
|
||||
provider: Arc::new(provider),
|
||||
});
|
||||
self.update_edit_prediction_settings(cx);
|
||||
self.refresh_edit_prediction(false, false, window, cx);
|
||||
self.refresh_edit_prediction(
|
||||
false,
|
||||
false,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn set_edit_predictions_hidden_for_vim_mode(
|
||||
@@ -180,7 +186,13 @@ impl Editor {
|
||||
if hidden {
|
||||
self.update_visible_edit_prediction(window, cx);
|
||||
} else {
|
||||
self.refresh_edit_prediction(true, false, window, cx);
|
||||
self.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,7 +223,13 @@ impl Editor {
|
||||
if let Some(false) = show_edit_predictions {
|
||||
self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
|
||||
} else {
|
||||
self.refresh_edit_prediction(false, true, window, cx);
|
||||
self.refresh_edit_prediction(
|
||||
false,
|
||||
true,
|
||||
EditPredictionRequestTrigger::Explicit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,6 +237,7 @@ impl Editor {
|
||||
&mut self,
|
||||
debounce: bool,
|
||||
user_requested: bool,
|
||||
trigger: EditPredictionRequestTrigger,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<()> {
|
||||
@@ -251,8 +270,13 @@ impl Editor {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.edit_prediction_provider()?
|
||||
.refresh(buffer, cursor_buffer_position, debounce, cx);
|
||||
self.edit_prediction_provider()?.refresh(
|
||||
buffer,
|
||||
cursor_buffer_position,
|
||||
debounce,
|
||||
trigger,
|
||||
cx,
|
||||
);
|
||||
Some(())
|
||||
}
|
||||
|
||||
@@ -311,7 +335,13 @@ impl Editor {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if !self.has_active_edit_prediction() {
|
||||
self.refresh_edit_prediction(false, true, window, cx);
|
||||
self.refresh_edit_prediction(
|
||||
false,
|
||||
true,
|
||||
EditPredictionRequestTrigger::Explicit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -457,7 +487,13 @@ impl Editor {
|
||||
|
||||
self.update_visible_edit_prediction(window, cx);
|
||||
if self.active_edit_prediction.is_none() {
|
||||
self.refresh_edit_prediction(true, true, window, cx);
|
||||
self.refresh_edit_prediction(
|
||||
true,
|
||||
true,
|
||||
EditPredictionRequestTrigger::PredictionAccepted,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
cx.notify();
|
||||
}
|
||||
@@ -510,7 +546,13 @@ impl Editor {
|
||||
});
|
||||
|
||||
self.replace_selections(&text_to_insert, None, window, cx, false);
|
||||
self.refresh_edit_prediction(true, true, window, cx);
|
||||
self.refresh_edit_prediction(
|
||||
true,
|
||||
true,
|
||||
EditPredictionRequestTrigger::PredictionPartiallyAccepted,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
cx.notify();
|
||||
} else {
|
||||
self.accept_partial_edit_prediction(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use edit_prediction_types::{
|
||||
EditPredictionDelegate, EditPredictionIconSet, PredictedCursorPosition,
|
||||
EditPredictionDelegate, EditPredictionIconSet, EditPredictionRequestTrigger,
|
||||
PredictedCursorPosition,
|
||||
};
|
||||
use futures::StreamExt;
|
||||
use gpui::{
|
||||
@@ -532,7 +533,13 @@ async fn test_edit_prediction_refresh_suppressed_while_following(cx: &mut gpui::
|
||||
propose_edits(&provider, vec![(8..8, "42")], &mut cx);
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.refresh_edit_prediction(false, false, window, cx);
|
||||
editor.refresh_edit_prediction(
|
||||
false,
|
||||
false,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
editor.update_visible_edit_prediction(window, cx);
|
||||
});
|
||||
|
||||
@@ -548,7 +555,13 @@ async fn test_edit_prediction_refresh_suppressed_while_following(cx: &mut gpui::
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.leader_id = Some(CollaboratorId::PeerId(PeerId::default()));
|
||||
editor.refresh_edit_prediction(false, false, window, cx);
|
||||
editor.refresh_edit_prediction(
|
||||
false,
|
||||
false,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
@@ -563,7 +576,13 @@ async fn test_edit_prediction_refresh_suppressed_while_following(cx: &mut gpui::
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.leader_id = None;
|
||||
editor.refresh_edit_prediction(false, false, window, cx);
|
||||
editor.refresh_edit_prediction(
|
||||
false,
|
||||
false,
|
||||
EditPredictionRequestTrigger::Other,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
@@ -1763,6 +1782,7 @@ impl EditPredictionDelegate for FakeEditPredictionDelegate {
|
||||
_buffer: gpui::Entity<language::Buffer>,
|
||||
_cursor_position: language::Anchor,
|
||||
_debounce: bool,
|
||||
_trigger: edit_prediction_types::EditPredictionRequestTrigger,
|
||||
_cx: &mut gpui::Context<Self>,
|
||||
) {
|
||||
self.refresh_count.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
@@ -1841,6 +1861,7 @@ impl EditPredictionDelegate for FakeNonZedEditPredictionDelegate {
|
||||
_buffer: gpui::Entity<language::Buffer>,
|
||||
_cursor_position: language::Anchor,
|
||||
_debounce: bool,
|
||||
_trigger: edit_prediction_types::EditPredictionRequestTrigger,
|
||||
_cx: &mut gpui::Context<Self>,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -93,6 +93,7 @@ pub(crate) use edit_prediction::{
|
||||
EditPredictionKeybindAction, EditPredictionKeybindSurface, edit_prediction_edit_text,
|
||||
};
|
||||
pub use edit_prediction_types::Direction;
|
||||
pub use edit_prediction_types::EditPredictionRequestTrigger;
|
||||
pub use editor_settings::{
|
||||
CompletionDetailAlignment, CompletionMenuItemKind, CurrentLineHighlight, DiffViewStyle,
|
||||
DocumentColorsRenderMode, EditorSettings, EditorSettingsScrollbarProxy, ScrollBeyondLastLine,
|
||||
@@ -4807,7 +4808,13 @@ impl Editor {
|
||||
this.change_selections(Default::default(), window, cx, |s| s.select(selections));
|
||||
this.insert("", window, cx);
|
||||
linked_edits.apply_with_left_expansion(cx);
|
||||
this.refresh_edit_prediction(true, false, window, cx);
|
||||
this.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
refresh_linked_ranges(this, window, cx);
|
||||
});
|
||||
}
|
||||
@@ -4830,7 +4837,13 @@ impl Editor {
|
||||
let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
|
||||
this.insert("", window, cx);
|
||||
linked_edits.apply(cx);
|
||||
this.refresh_edit_prediction(true, false, window, cx);
|
||||
this.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
refresh_linked_ranges(this, window, cx);
|
||||
});
|
||||
}
|
||||
@@ -5015,7 +5028,13 @@ impl Editor {
|
||||
self.transact(window, cx, |this, window, cx| {
|
||||
this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
|
||||
this.change_selections(Default::default(), window, cx, |s| s.select(selections));
|
||||
this.refresh_edit_prediction(true, false, window, cx);
|
||||
this.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7326,7 +7345,13 @@ impl Editor {
|
||||
}
|
||||
self.request_autoscroll(Autoscroll::fit(), cx);
|
||||
self.unmark_text(window, cx);
|
||||
self.refresh_edit_prediction(true, false, window, cx);
|
||||
self.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
cx.emit(EditorEvent::Edited { transaction_id });
|
||||
cx.emit(EditorEvent::TransactionUndone { transaction_id });
|
||||
}
|
||||
@@ -7354,7 +7379,13 @@ impl Editor {
|
||||
}
|
||||
self.request_autoscroll(Autoscroll::fit(), cx);
|
||||
self.unmark_text(window, cx);
|
||||
self.refresh_edit_prediction(true, false, window, cx);
|
||||
self.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
cx.emit(EditorEvent::Edited { transaction_id });
|
||||
}
|
||||
}
|
||||
@@ -8472,7 +8503,13 @@ impl Editor {
|
||||
(selection.range(), uuid.to_string())
|
||||
});
|
||||
this.edit(edits, cx);
|
||||
this.refresh_edit_prediction(true, false, window, cx);
|
||||
this.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9491,7 +9528,7 @@ impl Editor {
|
||||
}
|
||||
self.refresh_runnables(None, window, cx);
|
||||
self.update_edit_prediction_settings(cx);
|
||||
self.refresh_edit_prediction(true, false, window, cx);
|
||||
self.refresh_edit_prediction(true, false, EditPredictionRequestTrigger::Other, window, cx);
|
||||
self.refresh_inline_values(cx);
|
||||
|
||||
let old_cursor_shape = self.cursor_shape;
|
||||
|
||||
@@ -523,7 +523,13 @@ impl Editor {
|
||||
}
|
||||
this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
|
||||
refresh_linked_ranges(this, window, cx);
|
||||
this.refresh_edit_prediction(true, false, window, cx);
|
||||
this.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
|
||||
});
|
||||
}
|
||||
@@ -759,7 +765,13 @@ impl Editor {
|
||||
.collect();
|
||||
|
||||
this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
|
||||
this.refresh_edit_prediction(true, false, window, cx);
|
||||
this.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
|
||||
task.detach_and_log_err(cx);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::{
|
||||
state::Mode,
|
||||
};
|
||||
use editor::{
|
||||
Bias, DisplayPoint,
|
||||
Bias, DisplayPoint, EditPredictionRequestTrigger,
|
||||
display_map::{DisplaySnapshot, ToDisplayPoint},
|
||||
movement::TextLayoutDetails,
|
||||
};
|
||||
@@ -90,7 +90,13 @@ impl Vim {
|
||||
if let Some(kind) = motion_kind {
|
||||
vim.copy_selections_content(editor, kind, window, cx);
|
||||
editor.delete_selections_with_linked_edits(window, cx);
|
||||
editor.refresh_edit_prediction(true, false, window, cx);
|
||||
editor.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -127,7 +133,13 @@ impl Vim {
|
||||
};
|
||||
vim.copy_selections_content(editor, kind, window, cx);
|
||||
editor.delete_selections_with_linked_edits(window, cx);
|
||||
editor.refresh_edit_prediction(true, false, window, cx);
|
||||
editor.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::{
|
||||
};
|
||||
use collections::{HashMap, HashSet};
|
||||
use editor::{
|
||||
Bias, DisplayPoint,
|
||||
Bias, DisplayPoint, EditPredictionRequestTrigger,
|
||||
display_map::{DisplaySnapshot, ToDisplayPoint},
|
||||
};
|
||||
use gpui::{Context, Window};
|
||||
@@ -84,7 +84,13 @@ impl Vim {
|
||||
selection.collapse_to(cursor, selection.goal)
|
||||
});
|
||||
});
|
||||
editor.refresh_edit_prediction(true, false, window, cx);
|
||||
editor.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -192,7 +198,13 @@ impl Vim {
|
||||
selection.collapse_to(cursor, selection.goal)
|
||||
});
|
||||
});
|
||||
editor.refresh_edit_prediction(true, false, window, cx);
|
||||
editor.refresh_edit_prediction(
|
||||
true,
|
||||
false,
|
||||
EditPredictionRequestTrigger::BufferEdit,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user