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
parent 75959537ba
commit bb40043362
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(),
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

@ -6,11 +6,9 @@ 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 project::DisableAiSettings; use project::DisableAiSettings;
use settings::{Settings as _, SettingsStore}; use settings::{Settings as _, 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, ZetaInlineCompletionProvider}; use zeta::{ProviderDataCollection, ZetaInlineCompletionProvider};
@ -60,25 +58,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();