remote: Fix toolchain RPC messages not being handled because of the entity getting dropped (#36665)

Release Notes:

- N/A
This commit is contained in:
Piotr Osiewicz 2025-08-21 11:37:45 +02:00 committed by GitHub
parent 62f2ef86dc
commit 7f1bd2f15e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 49 additions and 39 deletions

View file

@ -34,7 +34,10 @@ enum ToolchainStoreInner {
Entity<LocalToolchainStore>, Entity<LocalToolchainStore>,
#[allow(dead_code)] Subscription, #[allow(dead_code)] Subscription,
), ),
Remote(Entity<RemoteToolchainStore>), Remote(
Entity<RemoteToolchainStore>,
#[allow(dead_code)] Subscription,
),
} }
impl EventEmitter<ToolchainStoreEvent> for ToolchainStore {} impl EventEmitter<ToolchainStoreEvent> for ToolchainStore {}
@ -65,10 +68,12 @@ impl ToolchainStore {
Self(ToolchainStoreInner::Local(entity, subscription)) Self(ToolchainStoreInner::Local(entity, subscription))
} }
pub(super) fn remote(project_id: u64, client: AnyProtoClient, cx: &mut App) -> Self { pub(super) fn remote(project_id: u64, client: AnyProtoClient, cx: &mut Context<Self>) -> Self {
Self(ToolchainStoreInner::Remote( let entity = cx.new(|_| RemoteToolchainStore { client, project_id });
cx.new(|_| RemoteToolchainStore { client, project_id }), let _subscription = cx.subscribe(&entity, |_, _, e: &ToolchainStoreEvent, cx| {
)) cx.emit(e.clone())
});
Self(ToolchainStoreInner::Remote(entity, _subscription))
} }
pub(crate) fn activate_toolchain( pub(crate) fn activate_toolchain(
&self, &self,
@ -80,8 +85,8 @@ impl ToolchainStore {
ToolchainStoreInner::Local(local, _) => { ToolchainStoreInner::Local(local, _) => {
local.update(cx, |this, cx| this.activate_toolchain(path, toolchain, cx)) local.update(cx, |this, cx| this.activate_toolchain(path, toolchain, cx))
} }
ToolchainStoreInner::Remote(remote) => { ToolchainStoreInner::Remote(remote, _) => {
remote.read(cx).activate_toolchain(path, toolchain, cx) remote.update(cx, |this, cx| this.activate_toolchain(path, toolchain, cx))
} }
} }
} }
@ -95,7 +100,7 @@ impl ToolchainStore {
ToolchainStoreInner::Local(local, _) => { ToolchainStoreInner::Local(local, _) => {
local.update(cx, |this, cx| this.list_toolchains(path, language_name, cx)) local.update(cx, |this, cx| this.list_toolchains(path, language_name, cx))
} }
ToolchainStoreInner::Remote(remote) => { ToolchainStoreInner::Remote(remote, _) => {
remote.read(cx).list_toolchains(path, language_name, cx) remote.read(cx).list_toolchains(path, language_name, cx)
} }
} }
@ -112,7 +117,7 @@ impl ToolchainStore {
&path.path, &path.path,
language_name, language_name,
)), )),
ToolchainStoreInner::Remote(remote) => { ToolchainStoreInner::Remote(remote, _) => {
remote.read(cx).active_toolchain(path, language_name, cx) remote.read(cx).active_toolchain(path, language_name, cx)
} }
} }
@ -234,13 +239,13 @@ impl ToolchainStore {
pub fn as_language_toolchain_store(&self) -> Arc<dyn LanguageToolchainStore> { pub fn as_language_toolchain_store(&self) -> Arc<dyn LanguageToolchainStore> {
match &self.0 { match &self.0 {
ToolchainStoreInner::Local(local, _) => Arc::new(LocalStore(local.downgrade())), ToolchainStoreInner::Local(local, _) => Arc::new(LocalStore(local.downgrade())),
ToolchainStoreInner::Remote(remote) => Arc::new(RemoteStore(remote.downgrade())), ToolchainStoreInner::Remote(remote, _) => Arc::new(RemoteStore(remote.downgrade())),
} }
} }
pub fn as_local_store(&self) -> Option<&Entity<LocalToolchainStore>> { pub fn as_local_store(&self) -> Option<&Entity<LocalToolchainStore>> {
match &self.0 { match &self.0 {
ToolchainStoreInner::Local(local, _) => Some(local), ToolchainStoreInner::Local(local, _) => Some(local),
ToolchainStoreInner::Remote(_) => None, ToolchainStoreInner::Remote(_, _) => None,
} }
} }
} }
@ -415,6 +420,8 @@ impl LocalToolchainStore {
.cloned() .cloned()
} }
} }
impl EventEmitter<ToolchainStoreEvent> for RemoteToolchainStore {}
struct RemoteToolchainStore { struct RemoteToolchainStore {
client: AnyProtoClient, client: AnyProtoClient,
project_id: u64, project_id: u64,
@ -425,11 +432,13 @@ impl RemoteToolchainStore {
&self, &self,
project_path: ProjectPath, project_path: ProjectPath,
toolchain: Toolchain, toolchain: Toolchain,
cx: &App, cx: &mut Context<Self>,
) -> Task<Option<()>> { ) -> Task<Option<()>> {
let project_id = self.project_id; let project_id = self.project_id;
let client = self.client.clone(); let client = self.client.clone();
cx.background_spawn(async move { cx.spawn(async move |this, cx| {
let did_activate = cx
.background_spawn(async move {
let path = PathBuf::from(toolchain.path.to_string()); let path = PathBuf::from(toolchain.path.to_string());
let _ = client let _ = client
.request(proto::ActivateToolchain { .request(proto::ActivateToolchain {
@ -447,6 +456,14 @@ impl RemoteToolchainStore {
.log_err()?; .log_err()?;
Some(()) Some(())
}) })
.await;
did_activate.and_then(|_| {
this.update(cx, |_, cx| {
cx.emit(ToolchainStoreEvent::ToolchainActivated);
})
.ok()
})
})
} }
pub(crate) fn list_toolchains( pub(crate) fn list_toolchains(

View file

@ -46,6 +46,9 @@ pub struct HeadlessProject {
pub languages: Arc<LanguageRegistry>, pub languages: Arc<LanguageRegistry>,
pub extensions: Entity<HeadlessExtensionStore>, pub extensions: Entity<HeadlessExtensionStore>,
pub git_store: Entity<GitStore>, pub git_store: Entity<GitStore>,
// Used mostly to keep alive the toolchain store for RPC handlers.
// Local variant is used within LSP store, but that's a separate entity.
pub _toolchain_store: Entity<ToolchainStore>,
} }
pub struct HeadlessAppState { pub struct HeadlessAppState {
@ -269,6 +272,7 @@ impl HeadlessProject {
languages, languages,
extensions, extensions,
git_store, git_store,
_toolchain_store: toolchain_store,
} }
} }

View file

@ -38,7 +38,6 @@ impl ActiveToolchain {
.ok() .ok()
.flatten(); .flatten();
if let Some(editor) = editor { if let Some(editor) = editor {
this.active_toolchain.take();
this.update_lister(editor, window, cx); this.update_lister(editor, window, cx);
} }
}, },
@ -124,16 +123,6 @@ impl ActiveToolchain {
if let Some((_, buffer, _)) = editor.active_excerpt(cx) if let Some((_, buffer, _)) = editor.active_excerpt(cx)
&& let Some(worktree_id) = buffer.read(cx).file().map(|file| file.worktree_id(cx)) && let Some(worktree_id) = buffer.read(cx).file().map(|file| file.worktree_id(cx))
{ {
if self
.active_buffer
.as_ref()
.is_some_and(|(old_worktree_id, old_buffer, _)| {
(old_worktree_id, old_buffer.entity_id()) == (&worktree_id, buffer.entity_id())
})
{
return;
}
let subscription = cx.subscribe_in( let subscription = cx.subscribe_in(
&buffer, &buffer,
window, window,