Ensure Edit Prediction provider is properly assigned on sign-in (#35885)

This PR fixes an issue where Edit Predictions would not be available in
buffers that were opened when the workspace loaded.

The issue was that there was a race condition between fetching/setting
the authenticated user state and when we assigned the Edit Prediction
provider to buffers that were already opened.

We now wait for the event that we emit when we have successfully loaded
the user in order to assign the Edit Prediction provider, as we'll know
the user has been loaded into the `UserStore` by that point.

Closes https://github.com/zed-industries/zed/issues/35883

Release Notes:

- Fixed an issue where Edit Predictions were not working in buffers that
were open when the workspace initially loaded.

Co-authored-by: Richard Feldman <oss@rtfeldman.com>
This commit is contained in:
Marshall Bowers 2025-08-08 14:10:09 -04:00 committed by GitHub
parent f2435f7284
commit 315a92091b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 29 deletions

View file

@ -226,17 +226,35 @@ impl UserStore {
match status { match status {
Status::Authenticated | Status::Connected { .. } => { Status::Authenticated | Status::Connected { .. } => {
if let Some(user_id) = client.user_id() { if let Some(user_id) = client.user_id() {
let response = client.cloud_client().get_authenticated_user().await; let response = client
let mut current_user = None; .cloud_client()
.get_authenticated_user()
.await
.log_err();
let current_user_and_response = if let Some(response) = response {
let user = Arc::new(User {
id: user_id,
github_login: response.user.github_login.clone().into(),
avatar_uri: response.user.avatar_url.clone().into(),
name: response.user.name.clone(),
});
Some((user, response))
} else {
None
};
current_user_tx
.send(
current_user_and_response
.as_ref()
.map(|(user, _)| user.clone()),
)
.await
.ok();
cx.update(|cx| { cx.update(|cx| {
if let Some(response) = response.log_err() { if let Some((user, response)) = current_user_and_response {
let user = Arc::new(User {
id: user_id,
github_login: response.user.github_login.clone().into(),
avatar_uri: response.user.avatar_url.clone().into(),
name: response.user.name.clone(),
});
current_user = Some(user.clone());
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
this.by_github_login this.by_github_login
.insert(user.github_login.clone(), user_id); .insert(user.github_login.clone(), user_id);
@ -247,7 +265,6 @@ impl UserStore {
anyhow::Ok(()) anyhow::Ok(())
} }
})??; })??;
current_user_tx.send(current_user).await.ok();
this.update(cx, |_, cx| cx.notify())?; this.update(cx, |_, cx| cx.notify())?;
} }

View file

@ -5,11 +5,9 @@ use editor::Editor;
use gpui::{AnyWindowHandle, App, AppContext as _, Context, Entity, WeakEntity}; use gpui::{AnyWindowHandle, App, AppContext as _, Context, Entity, WeakEntity};
use language::language_settings::{EditPredictionProvider, all_language_settings}; use language::language_settings::{EditPredictionProvider, all_language_settings};
use settings::SettingsStore; use settings::SettingsStore;
use smol::stream::StreamExt;
use std::{cell::RefCell, rc::Rc, sync::Arc}; use std::{cell::RefCell, rc::Rc, sync::Arc};
use supermaven::{Supermaven, SupermavenCompletionProvider}; use supermaven::{Supermaven, SupermavenCompletionProvider};
use ui::Window; use ui::Window;
use util::ResultExt;
use workspace::Workspace; use workspace::Workspace;
use zeta::{ProviderDataCollection, ZetaEditPredictionProvider}; use zeta::{ProviderDataCollection, ZetaEditPredictionProvider};
@ -59,25 +57,20 @@ pub fn init(client: Arc<Client>, user_store: Entity<UserStore>, cx: &mut App) {
cx.on_action(clear_zeta_edit_history); cx.on_action(clear_zeta_edit_history);
let mut provider = all_language_settings(None, cx).edit_predictions.provider; let mut provider = all_language_settings(None, cx).edit_predictions.provider;
cx.spawn({ cx.subscribe(&user_store, {
let user_store = user_store.clone();
let editors = editors.clone(); let editors = editors.clone();
let client = client.clone(); let client = client.clone();
move |user_store, event, cx| match event {
async move |cx| { client::user::Event::PrivateUserInfoUpdated => {
let mut status = client.status(); assign_edit_prediction_providers(
while let Some(_status) = status.next().await { &editors,
cx.update(|cx| { provider,
assign_edit_prediction_providers( &client,
&editors, user_store.clone(),
provider, cx,
&client, );
user_store.clone(),
cx,
);
})
.log_err();
} }
_ => {}
} }
}) })
.detach(); .detach();