Stop extensions' servers and message loops before removing their files (#34208)
Fixes an issue that caused Windows to fail when removing extension's directories, as Zed had never stop any related processes. Now: * Zed shuts down and waits until the end when the language servers are shut down * Adds `impl Drop for WasmExtension` where does `self.tx.close_channel();` to stop a receiver loop that holds the "lock" on the extension's work dir. The extension was dropped, but the channel was not closed for some reason. * Does more unregistration to ensure `Arc<WasmExtension>` with the `tx` does not leak further * Tidies up the related errors which had never reported a problematic path before Release Notes: - N/A --------- Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com> Co-authored-by: Smit <smit@zed.dev>
This commit is contained in:
parent
c549b712fd
commit
c6603e4fba
18 changed files with 273 additions and 84 deletions
|
@ -21,6 +21,7 @@ fs.workspace = true
|
|||
gpui.workspace = true
|
||||
language.workspace = true
|
||||
lsp.workspace = true
|
||||
project.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
util.workspace = true
|
||||
|
|
|
@ -6,21 +6,24 @@ use std::sync::Arc;
|
|||
|
||||
use anyhow::{Context as _, Result};
|
||||
use async_trait::async_trait;
|
||||
use collections::HashMap;
|
||||
use collections::{HashMap, HashSet};
|
||||
use extension::{Extension, ExtensionLanguageServerProxy, WorktreeDelegate};
|
||||
use fs::Fs;
|
||||
use futures::{Future, FutureExt};
|
||||
use gpui::AsyncApp;
|
||||
use futures::{Future, FutureExt, future::join_all};
|
||||
use gpui::{App, AppContext, AsyncApp, Task};
|
||||
use language::{
|
||||
BinaryStatus, CodeLabel, HighlightId, Language, LanguageName, LanguageToolchainStore,
|
||||
LspAdapter, LspAdapterDelegate,
|
||||
};
|
||||
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName};
|
||||
use lsp::{
|
||||
CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName,
|
||||
LanguageServerSelector,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
use util::{ResultExt, fs::make_file_executable, maybe};
|
||||
|
||||
use crate::LanguageServerRegistryProxy;
|
||||
use crate::{LanguageServerRegistryProxy, LspAccess};
|
||||
|
||||
/// An adapter that allows an [`LspAdapterDelegate`] to be used as a [`WorktreeDelegate`].
|
||||
struct WorktreeDelegateAdapter(pub Arc<dyn LspAdapterDelegate>);
|
||||
|
@ -71,10 +74,50 @@ impl ExtensionLanguageServerProxy for LanguageServerRegistryProxy {
|
|||
fn remove_language_server(
|
||||
&self,
|
||||
language: &LanguageName,
|
||||
language_server_id: &LanguageServerName,
|
||||
) {
|
||||
language_server_name: &LanguageServerName,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<()>> {
|
||||
self.language_registry
|
||||
.remove_lsp_adapter(language, language_server_id);
|
||||
.remove_lsp_adapter(language, language_server_name);
|
||||
|
||||
let mut tasks = Vec::new();
|
||||
match &self.lsp_access {
|
||||
LspAccess::ViaLspStore(lsp_store) => lsp_store.update(cx, |lsp_store, cx| {
|
||||
let stop_task = lsp_store.stop_language_servers_for_buffers(
|
||||
Vec::new(),
|
||||
HashSet::from_iter([LanguageServerSelector::Name(
|
||||
language_server_name.clone(),
|
||||
)]),
|
||||
cx,
|
||||
);
|
||||
tasks.push(stop_task);
|
||||
}),
|
||||
LspAccess::ViaWorkspaces(lsp_store_provider) => {
|
||||
if let Ok(lsp_stores) = lsp_store_provider(cx) {
|
||||
for lsp_store in lsp_stores {
|
||||
lsp_store.update(cx, |lsp_store, cx| {
|
||||
let stop_task = lsp_store.stop_language_servers_for_buffers(
|
||||
Vec::new(),
|
||||
HashSet::from_iter([LanguageServerSelector::Name(
|
||||
language_server_name.clone(),
|
||||
)]),
|
||||
cx,
|
||||
);
|
||||
tasks.push(stop_task);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
LspAccess::Noop => {}
|
||||
}
|
||||
|
||||
cx.background_spawn(async move {
|
||||
let results = join_all(tasks).await;
|
||||
for result in results {
|
||||
result?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn update_language_server_status(
|
||||
|
|
|
@ -5,13 +5,26 @@ use std::sync::Arc;
|
|||
|
||||
use anyhow::Result;
|
||||
use extension::{ExtensionGrammarProxy, ExtensionHostProxy, ExtensionLanguageProxy};
|
||||
use gpui::{App, Entity};
|
||||
use language::{LanguageMatcher, LanguageName, LanguageRegistry, LoadedLanguage};
|
||||
use project::LspStore;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum LspAccess {
|
||||
ViaLspStore(Entity<LspStore>),
|
||||
ViaWorkspaces(Arc<dyn Fn(&mut App) -> Result<Vec<Entity<LspStore>>> + Send + Sync + 'static>),
|
||||
Noop,
|
||||
}
|
||||
|
||||
pub fn init(
|
||||
lsp_access: LspAccess,
|
||||
extension_host_proxy: Arc<ExtensionHostProxy>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
) {
|
||||
let language_server_registry_proxy = LanguageServerRegistryProxy { language_registry };
|
||||
let language_server_registry_proxy = LanguageServerRegistryProxy {
|
||||
language_registry,
|
||||
lsp_access,
|
||||
};
|
||||
extension_host_proxy.register_grammar_proxy(language_server_registry_proxy.clone());
|
||||
extension_host_proxy.register_language_proxy(language_server_registry_proxy.clone());
|
||||
extension_host_proxy.register_language_server_proxy(language_server_registry_proxy);
|
||||
|
@ -20,6 +33,7 @@ pub fn init(
|
|||
#[derive(Clone)]
|
||||
struct LanguageServerRegistryProxy {
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
lsp_access: LspAccess,
|
||||
}
|
||||
|
||||
impl ExtensionGrammarProxy for LanguageServerRegistryProxy {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue