Use language server ids for lsp tool
This commit is contained in:
parent
70575d1115
commit
4292d883b0
9 changed files with 186 additions and 138 deletions
|
@ -56,6 +56,7 @@ pub struct ActivityIndicator {
|
|||
#[derive(Debug)]
|
||||
struct ServerStatus {
|
||||
name: LanguageServerName,
|
||||
id: LanguageServerId,
|
||||
status: LanguageServerStatusUpdate,
|
||||
}
|
||||
|
||||
|
@ -86,11 +87,12 @@ impl ActivityIndicator {
|
|||
let this = cx.new(|cx| {
|
||||
let mut status_events = languages.language_server_binary_statuses();
|
||||
cx.spawn(async move |this, cx| {
|
||||
while let Some((name, binary_status)) = status_events.next().await {
|
||||
while let Some((id, name, binary_status)) = status_events.next().await {
|
||||
this.update(cx, |this: &mut ActivityIndicator, cx| {
|
||||
this.statuses.retain(|s| s.name != name);
|
||||
this.statuses.retain(|s| s.id != id);
|
||||
this.statuses.push(ServerStatus {
|
||||
name,
|
||||
id,
|
||||
status: LanguageServerStatusUpdate::Binary(binary_status),
|
||||
});
|
||||
cx.notify();
|
||||
|
@ -117,7 +119,13 @@ impl ActivityIndicator {
|
|||
cx.subscribe(
|
||||
&project.read(cx).lsp_store(),
|
||||
|activity_indicator, _, event, cx| {
|
||||
if let LspStoreEvent::LanguageServerUpdate { name, message, .. } = event {
|
||||
if let LspStoreEvent::LanguageServerUpdate {
|
||||
language_server_id,
|
||||
name,
|
||||
message,
|
||||
..
|
||||
} = event
|
||||
{
|
||||
if let proto::update_language_server::Variant::StatusUpdate(status_update) =
|
||||
message
|
||||
{
|
||||
|
@ -180,9 +188,11 @@ impl ActivityIndicator {
|
|||
};
|
||||
|
||||
activity_indicator.statuses.retain(|s| s.name != name);
|
||||
activity_indicator
|
||||
.statuses
|
||||
.push(ServerStatus { name, status });
|
||||
activity_indicator.statuses.push(ServerStatus {
|
||||
name,
|
||||
id: *language_server_id,
|
||||
status,
|
||||
});
|
||||
}
|
||||
cx.notify()
|
||||
}
|
||||
|
|
|
@ -1361,11 +1361,12 @@ impl ExtensionStore {
|
|||
for (manifest, wasm_extension) in &wasm_extensions {
|
||||
let extension = Arc::new(wasm_extension.clone());
|
||||
|
||||
for (language_server_id, language_server_config) in &manifest.language_servers {
|
||||
for (language_server_name, language_server_config) in &manifest.language_servers
|
||||
{
|
||||
for language in language_server_config.languages() {
|
||||
this.proxy.register_language_server(
|
||||
extension.clone(),
|
||||
language_server_id.clone(),
|
||||
language_server_name.clone(),
|
||||
language.clone(),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use gpui::{AppContext as _, SemanticVersion, TestAppContext};
|
|||
use http_client::{FakeHttpClient, Response};
|
||||
use language::{BinaryStatus, LanguageMatcher, LanguageName, LanguageRegistry};
|
||||
use language_extension::LspAccess;
|
||||
use lsp::LanguageServerName;
|
||||
use lsp::{LanguageServerId, LanguageServerName};
|
||||
use node_runtime::NodeRuntime;
|
||||
use parking_lot::Mutex;
|
||||
use project::{DEFAULT_COMPLETION_CONTEXT, Project};
|
||||
|
@ -737,18 +737,25 @@ async fn test_extension_store_with_test_extension(cx: &mut TestAppContext) {
|
|||
],
|
||||
[
|
||||
(
|
||||
LanguageServerId(0),
|
||||
LanguageServerName::new_static("gleam"),
|
||||
BinaryStatus::Starting
|
||||
),
|
||||
(
|
||||
LanguageServerId(0),
|
||||
LanguageServerName::new_static("gleam"),
|
||||
BinaryStatus::CheckingForUpdate
|
||||
),
|
||||
(
|
||||
LanguageServerId(0),
|
||||
LanguageServerName::new_static("gleam"),
|
||||
BinaryStatus::Downloading
|
||||
),
|
||||
(LanguageServerName::new_static("gleam"), BinaryStatus::None)
|
||||
(
|
||||
LanguageServerId(0),
|
||||
LanguageServerName::new_static("gleam"),
|
||||
BinaryStatus::None
|
||||
)
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -177,21 +177,21 @@ impl HeadlessExtensionStore {
|
|||
let wasm_extension: Arc<dyn Extension> =
|
||||
Arc::new(WasmExtension::load(&extension_dir, &manifest, wasm_host.clone(), cx).await?);
|
||||
|
||||
for (language_server_id, language_server_config) in &manifest.language_servers {
|
||||
for (language_server_name, language_server_config) in &manifest.language_servers {
|
||||
for language in language_server_config.languages() {
|
||||
this.update(cx, |this, _cx| {
|
||||
this.loaded_language_servers
|
||||
.entry(manifest.id.clone())
|
||||
.or_default()
|
||||
.push((language_server_id.clone(), language.clone()));
|
||||
.push((language_server_name.clone(), language.clone()));
|
||||
this.proxy.register_language_server(
|
||||
wasm_extension.clone(),
|
||||
language_server_id.clone(),
|
||||
language_server_name.clone(),
|
||||
language.clone(),
|
||||
);
|
||||
})?;
|
||||
}
|
||||
log::info!("Loaded language server: {}", language_server_id);
|
||||
log::info!("Loaded language server: {}", language_server_name);
|
||||
}
|
||||
|
||||
for (debug_adapter, meta) in &manifest.debug_adapters {
|
||||
|
|
|
@ -214,12 +214,20 @@ impl CachedLspAdapter {
|
|||
delegate: Arc<dyn LspAdapterDelegate>,
|
||||
toolchains: Option<Toolchain>,
|
||||
binary_options: LanguageServerBinaryOptions,
|
||||
server_id: LanguageServerId,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<LanguageServerBinary> {
|
||||
let cached_binary = self.cached_binary.lock().await;
|
||||
self.adapter
|
||||
.clone()
|
||||
.get_language_server_command(delegate, toolchains, binary_options, cached_binary, cx)
|
||||
.get_language_server_command(
|
||||
delegate,
|
||||
toolchains,
|
||||
binary_options,
|
||||
cached_binary,
|
||||
server_id,
|
||||
cx,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
|
@ -291,7 +299,12 @@ pub trait LspAdapterDelegate: Send + Sync {
|
|||
fn http_client(&self) -> Arc<dyn HttpClient>;
|
||||
fn worktree_id(&self) -> WorktreeId;
|
||||
fn worktree_root_path(&self) -> &Path;
|
||||
fn update_status(&self, language: LanguageServerName, status: BinaryStatus);
|
||||
fn update_status(
|
||||
&self,
|
||||
language: LanguageServerId,
|
||||
server_name: LanguageServerName,
|
||||
status: BinaryStatus,
|
||||
);
|
||||
fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>>;
|
||||
async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>>;
|
||||
|
||||
|
@ -315,6 +328,7 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||
toolchains: Option<Toolchain>,
|
||||
binary_options: LanguageServerBinaryOptions,
|
||||
mut cached_binary: futures::lock::MutexGuard<'a, Option<LanguageServerBinary>>,
|
||||
server_id: LanguageServerId,
|
||||
cx: &'a mut AsyncApp,
|
||||
) -> Pin<Box<dyn 'a + Future<Output = Result<LanguageServerBinary>>>> {
|
||||
async move {
|
||||
|
@ -330,27 +344,41 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||
// because we don't want to download and overwrite our global one
|
||||
// for each worktree we might have open.
|
||||
if binary_options.allow_path_lookup
|
||||
&& let Some(binary) = self.check_if_user_installed(delegate.as_ref(), toolchains, cx).await {
|
||||
log::debug!(
|
||||
"found user-installed language server for {}. path: {:?}, arguments: {:?}",
|
||||
self.name().0,
|
||||
binary.path,
|
||||
binary.arguments
|
||||
);
|
||||
return Ok(binary);
|
||||
}
|
||||
&& let Some(binary) = self
|
||||
.check_if_user_installed(delegate.as_ref(), toolchains, cx)
|
||||
.await
|
||||
{
|
||||
log::debug!(
|
||||
"found user-installed language server for {}. path: {:?}, arguments: {:?}",
|
||||
self.name().0,
|
||||
binary.path,
|
||||
binary.arguments
|
||||
);
|
||||
return Ok(binary);
|
||||
}
|
||||
|
||||
anyhow::ensure!(binary_options.allow_binary_download, "downloading language servers disabled");
|
||||
anyhow::ensure!(
|
||||
binary_options.allow_binary_download,
|
||||
"downloading language servers disabled"
|
||||
);
|
||||
|
||||
if let Some(cached_binary) = cached_binary.as_ref() {
|
||||
return Ok(cached_binary.clone());
|
||||
}
|
||||
|
||||
let Some(container_dir) = delegate.language_server_download_dir(&self.name()).await else {
|
||||
let Some(container_dir) = delegate.language_server_download_dir(&self.name()).await
|
||||
else {
|
||||
anyhow::bail!("no language server download dir defined")
|
||||
};
|
||||
|
||||
let mut binary = try_fetch_server_binary(self.as_ref(), &delegate, container_dir.to_path_buf(), cx).await;
|
||||
let mut binary = try_fetch_server_binary(
|
||||
self.as_ref(),
|
||||
&delegate,
|
||||
container_dir.to_path_buf(),
|
||||
server_id,
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
if let Err(error) = binary.as_ref() {
|
||||
if let Some(prev_downloaded_binary) = self
|
||||
|
@ -358,7 +386,8 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||
.await
|
||||
{
|
||||
log::info!(
|
||||
"failed to fetch newest version of language server {:?}. error: {:?}, falling back to using {:?}",
|
||||
"failed to fetch newest version of language server {:?}. \
|
||||
error: {:?}, falling back to using {:?}",
|
||||
self.name(),
|
||||
error,
|
||||
prev_downloaded_binary.path
|
||||
|
@ -366,6 +395,7 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||
binary = Ok(prev_downloaded_binary);
|
||||
} else {
|
||||
delegate.update_status(
|
||||
server_id,
|
||||
self.name(),
|
||||
BinaryStatus::Failed {
|
||||
error: format!("{error:?}"),
|
||||
|
@ -594,6 +624,7 @@ async fn try_fetch_server_binary<L: LspAdapter + 'static + Send + Sync + ?Sized>
|
|||
adapter: &L,
|
||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||
container_dir: PathBuf,
|
||||
server_id: LanguageServerId,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<LanguageServerBinary> {
|
||||
if let Some(task) = adapter.will_fetch_server(delegate, cx) {
|
||||
|
@ -602,7 +633,7 @@ async fn try_fetch_server_binary<L: LspAdapter + 'static + Send + Sync + ?Sized>
|
|||
|
||||
let name = adapter.name();
|
||||
log::debug!("fetching latest version of language server {:?}", name.0);
|
||||
delegate.update_status(name.clone(), BinaryStatus::CheckingForUpdate);
|
||||
delegate.update_status(server_id, adapter.name(), BinaryStatus::CheckingForUpdate);
|
||||
|
||||
let latest_version = adapter
|
||||
.fetch_latest_server_version(delegate.as_ref())
|
||||
|
@ -613,16 +644,16 @@ async fn try_fetch_server_binary<L: LspAdapter + 'static + Send + Sync + ?Sized>
|
|||
.await
|
||||
{
|
||||
log::debug!("language server {:?} is already installed", name.0);
|
||||
delegate.update_status(name.clone(), BinaryStatus::None);
|
||||
delegate.update_status(server_id, adapter.name(), BinaryStatus::None);
|
||||
Ok(binary)
|
||||
} else {
|
||||
log::info!("downloading language server {:?}", name.0);
|
||||
delegate.update_status(adapter.name(), BinaryStatus::Downloading);
|
||||
delegate.update_status(server_id, adapter.name(), BinaryStatus::Downloading);
|
||||
let binary = adapter
|
||||
.fetch_server_binary(latest_version, container_dir, delegate.as_ref())
|
||||
.await;
|
||||
|
||||
delegate.update_status(name.clone(), BinaryStatus::None);
|
||||
delegate.update_status(server_id, adapter.name(), BinaryStatus::None);
|
||||
binary
|
||||
}
|
||||
}
|
||||
|
@ -2197,6 +2228,7 @@ impl LspAdapter for FakeLspAdapter {
|
|||
_: Option<Toolchain>,
|
||||
_: LanguageServerBinaryOptions,
|
||||
_: futures::lock::MutexGuard<'a, Option<LanguageServerBinary>>,
|
||||
_: LanguageServerId,
|
||||
_: &'a mut AsyncApp,
|
||||
) -> Pin<Box<dyn 'a + Future<Output = Result<LanguageServerBinary>>>> {
|
||||
async move { Ok(self.language_server_binary.clone()) }.boxed_local()
|
||||
|
|
|
@ -252,7 +252,9 @@ pub struct LanguageQueries {
|
|||
|
||||
#[derive(Clone, Default)]
|
||||
struct ServerStatusSender {
|
||||
txs: Arc<Mutex<Vec<mpsc::UnboundedSender<(LanguageServerName, BinaryStatus)>>>>,
|
||||
txs: Arc<
|
||||
Mutex<Vec<mpsc::UnboundedSender<(LanguageServerId, LanguageServerName, BinaryStatus)>>>,
|
||||
>,
|
||||
}
|
||||
|
||||
pub struct LoadedLanguage {
|
||||
|
@ -1077,8 +1079,13 @@ impl LanguageRegistry {
|
|||
self.state.read().all_lsp_adapters.get(name).cloned()
|
||||
}
|
||||
|
||||
pub fn update_lsp_binary_status(&self, server_name: LanguageServerName, status: BinaryStatus) {
|
||||
self.lsp_binary_status_tx.send(server_name, status);
|
||||
pub fn update_lsp_binary_status(
|
||||
&self,
|
||||
server_id: LanguageServerId,
|
||||
name: LanguageServerName,
|
||||
status: BinaryStatus,
|
||||
) {
|
||||
self.lsp_binary_status_tx.send(server_id, name, status);
|
||||
}
|
||||
|
||||
pub fn next_language_server_id(&self) -> LanguageServerId {
|
||||
|
@ -1133,7 +1140,7 @@ impl LanguageRegistry {
|
|||
|
||||
pub fn language_server_binary_statuses(
|
||||
&self,
|
||||
) -> mpsc::UnboundedReceiver<(LanguageServerName, BinaryStatus)> {
|
||||
) -> mpsc::UnboundedReceiver<(LanguageServerId, LanguageServerName, BinaryStatus)> {
|
||||
self.lsp_binary_status_tx.subscribe()
|
||||
}
|
||||
|
||||
|
@ -1247,14 +1254,19 @@ impl LanguageRegistryState {
|
|||
}
|
||||
|
||||
impl ServerStatusSender {
|
||||
fn subscribe(&self) -> mpsc::UnboundedReceiver<(LanguageServerName, BinaryStatus)> {
|
||||
fn subscribe(
|
||||
&self,
|
||||
) -> mpsc::UnboundedReceiver<(LanguageServerId, LanguageServerName, BinaryStatus)> {
|
||||
let (tx, rx) = mpsc::unbounded();
|
||||
self.txs.lock().push(tx);
|
||||
rx
|
||||
}
|
||||
|
||||
fn send(&self, name: LanguageServerName, status: BinaryStatus) {
|
||||
fn send(&self, id: LanguageServerId, name: LanguageServerName, status: BinaryStatus) {
|
||||
let mut txs = self.txs.lock();
|
||||
txs.retain(|tx| tx.unbounded_send((name.clone(), status.clone())).is_ok());
|
||||
txs.retain(|tx| {
|
||||
tx.unbounded_send((id, name.clone(), status.clone()))
|
||||
.is_ok()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@ use language::{
|
|||
Toolchain,
|
||||
};
|
||||
use lsp::{
|
||||
CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName,
|
||||
LanguageServerSelector,
|
||||
CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
|
||||
LanguageServerName, LanguageServerSelector,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
|
@ -58,14 +58,14 @@ impl ExtensionLanguageServerProxy for LanguageServerRegistryProxy {
|
|||
fn register_language_server(
|
||||
&self,
|
||||
extension: Arc<dyn Extension>,
|
||||
language_server_id: LanguageServerName,
|
||||
language_server_name: LanguageServerName,
|
||||
language: LanguageName,
|
||||
) {
|
||||
self.language_registry.register_lsp_adapter(
|
||||
language.clone(),
|
||||
Arc::new(ExtensionLspAdapter::new(
|
||||
extension,
|
||||
language_server_id,
|
||||
language_server_name,
|
||||
language,
|
||||
)),
|
||||
);
|
||||
|
@ -122,29 +122,29 @@ impl ExtensionLanguageServerProxy for LanguageServerRegistryProxy {
|
|||
|
||||
fn update_language_server_status(
|
||||
&self,
|
||||
language_server_id: LanguageServerName,
|
||||
language_server_name: LanguageServerName,
|
||||
status: BinaryStatus,
|
||||
) {
|
||||
self.language_registry
|
||||
.update_lsp_binary_status(language_server_id, status);
|
||||
// self.language_registry
|
||||
// .update_lsp_binary_status(language_server_name, status);
|
||||
}
|
||||
}
|
||||
|
||||
struct ExtensionLspAdapter {
|
||||
extension: Arc<dyn Extension>,
|
||||
language_server_id: LanguageServerName,
|
||||
language_server_name: LanguageServerName,
|
||||
language_name: LanguageName,
|
||||
}
|
||||
|
||||
impl ExtensionLspAdapter {
|
||||
fn new(
|
||||
extension: Arc<dyn Extension>,
|
||||
language_server_id: LanguageServerName,
|
||||
language_server_name: LanguageServerName,
|
||||
language_name: LanguageName,
|
||||
) -> Self {
|
||||
Self {
|
||||
extension,
|
||||
language_server_id,
|
||||
language_server_name,
|
||||
language_name,
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ impl ExtensionLspAdapter {
|
|||
#[async_trait(?Send)]
|
||||
impl LspAdapter for ExtensionLspAdapter {
|
||||
fn name(&self) -> LanguageServerName {
|
||||
self.language_server_id.clone()
|
||||
self.language_server_name.clone()
|
||||
}
|
||||
|
||||
fn get_language_server_command<'a>(
|
||||
|
@ -162,6 +162,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
|||
_: Option<Toolchain>,
|
||||
_: LanguageServerBinaryOptions,
|
||||
_: futures::lock::MutexGuard<'a, Option<LanguageServerBinary>>,
|
||||
_: LanguageServerId,
|
||||
_: &'a mut AsyncApp,
|
||||
) -> Pin<Box<dyn 'a + Future<Output = Result<LanguageServerBinary>>>> {
|
||||
async move {
|
||||
|
@ -169,7 +170,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
|||
let command = self
|
||||
.extension
|
||||
.language_server_command(
|
||||
self.language_server_id.clone(),
|
||||
self.language_server_name.clone(),
|
||||
self.language_name.clone(),
|
||||
delegate,
|
||||
)
|
||||
|
@ -230,7 +231,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
|||
.extension
|
||||
.manifest()
|
||||
.language_servers
|
||||
.get(&self.language_server_id)
|
||||
.get(&self.language_server_name)
|
||||
.and_then(|server| server.code_action_kinds.clone());
|
||||
|
||||
code_action_kinds.or(Some(vec![
|
||||
|
@ -256,7 +257,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
|||
self.extension
|
||||
.manifest()
|
||||
.language_servers
|
||||
.get(&self.language_server_id)
|
||||
.get(&self.language_server_name)
|
||||
.map(|server| server.language_ids.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
@ -270,7 +271,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
|||
let json_options = self
|
||||
.extension
|
||||
.language_server_initialization_options(
|
||||
self.language_server_id.clone(),
|
||||
self.language_server_name.clone(),
|
||||
self.language_name.clone(),
|
||||
delegate,
|
||||
)
|
||||
|
@ -294,7 +295,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
|||
let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
|
||||
let json_options: Option<String> = self
|
||||
.extension
|
||||
.language_server_workspace_configuration(self.language_server_id.clone(), delegate)
|
||||
.language_server_workspace_configuration(self.language_server_name.clone(), delegate)
|
||||
.await?;
|
||||
Ok(if let Some(json_options) = json_options {
|
||||
serde_json::from_str(&json_options).with_context(|| {
|
||||
|
@ -315,7 +316,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
|||
let json_options: Option<String> = self
|
||||
.extension
|
||||
.language_server_additional_initialization_options(
|
||||
self.language_server_id.clone(),
|
||||
self.language_server_name.clone(),
|
||||
target_language_server_id.clone(),
|
||||
delegate,
|
||||
)
|
||||
|
@ -343,7 +344,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
|||
let json_options: Option<String> = self
|
||||
.extension
|
||||
.language_server_additional_workspace_configuration(
|
||||
self.language_server_id.clone(),
|
||||
self.language_server_name.clone(),
|
||||
target_language_server_id.clone(),
|
||||
delegate,
|
||||
)
|
||||
|
@ -370,7 +371,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
|||
|
||||
let labels = self
|
||||
.extension
|
||||
.labels_for_completions(self.language_server_id.clone(), completions)
|
||||
.labels_for_completions(self.language_server_name.clone(), completions)
|
||||
.await?;
|
||||
|
||||
Ok(labels_from_extension(labels, language))
|
||||
|
@ -392,7 +393,7 @@ impl LspAdapter for ExtensionLspAdapter {
|
|||
|
||||
let labels = self
|
||||
.extension
|
||||
.labels_for_symbols(self.language_server_id.clone(), symbols)
|
||||
.labels_for_symbols(self.language_server_name.clone(), symbols)
|
||||
.await?;
|
||||
|
||||
Ok(labels_from_extension(labels, language))
|
||||
|
|
|
@ -65,7 +65,7 @@ impl std::fmt::Debug for ActiveEditor {
|
|||
#[derive(Debug, Default, Clone)]
|
||||
struct LanguageServers {
|
||||
health_statuses: HashMap<LanguageServerId, LanguageServerHealthStatus>,
|
||||
binary_statuses: HashMap<LanguageServerName, LanguageServerBinaryStatus>,
|
||||
binary_statuses: HashMap<LanguageServerId, LanguageServerBinaryStatus>,
|
||||
servers_per_buffer_abs_path: HashMap<PathBuf, ServersForPath>,
|
||||
}
|
||||
|
||||
|
@ -85,6 +85,7 @@ struct LanguageServerHealthStatus {
|
|||
struct LanguageServerBinaryStatus {
|
||||
status: BinaryStatus,
|
||||
message: Option<SharedString>,
|
||||
name: LanguageServerName,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -370,17 +371,19 @@ impl LanguageServers {
|
|||
binary_status: BinaryStatus,
|
||||
message: Option<&str>,
|
||||
name: LanguageServerName,
|
||||
id: LanguageServerId,
|
||||
) {
|
||||
let binary_status_message = message.map(SharedString::new);
|
||||
if matches!(
|
||||
binary_status,
|
||||
BinaryStatus::Stopped | BinaryStatus::Failed { .. }
|
||||
) {
|
||||
self.health_statuses.retain(|_, server| server.name != name);
|
||||
self.health_statuses.remove(&id);
|
||||
}
|
||||
self.binary_statuses.insert(
|
||||
name,
|
||||
id,
|
||||
LanguageServerBinaryStatus {
|
||||
name,
|
||||
status: binary_status,
|
||||
message: binary_status_message,
|
||||
},
|
||||
|
@ -583,18 +586,16 @@ impl LspTool {
|
|||
proto::ServerBinaryStatus::Starting => BinaryStatus::Starting,
|
||||
proto::ServerBinaryStatus::Stopping => BinaryStatus::Stopping,
|
||||
proto::ServerBinaryStatus::Stopped => BinaryStatus::Stopped,
|
||||
proto::ServerBinaryStatus::Failed => {
|
||||
let Some(error) = status_update.message.clone() else {
|
||||
return;
|
||||
};
|
||||
BinaryStatus::Failed { error }
|
||||
}
|
||||
proto::ServerBinaryStatus::Failed => BinaryStatus::Failed {
|
||||
error: status_update.message.clone().unwrap_or_default(),
|
||||
},
|
||||
};
|
||||
self.server_state.update(cx, |state, _| {
|
||||
state.language_servers.update_binary_status(
|
||||
binary_status,
|
||||
status_update.message.as_deref(),
|
||||
name.clone(),
|
||||
*language_server_id,
|
||||
);
|
||||
});
|
||||
updated = true;
|
||||
|
@ -684,27 +685,16 @@ impl LspTool {
|
|||
})
|
||||
})
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
let mut server_ids_to_worktrees =
|
||||
HashMap::<LanguageServerId, Entity<Worktree>>::default();
|
||||
let mut server_names_to_worktrees = HashMap::<
|
||||
LanguageServerName,
|
||||
HashSet<(Entity<Worktree>, LanguageServerId)>,
|
||||
>::default();
|
||||
for servers_for_path in state.language_servers.servers_per_buffer_abs_path.values() {
|
||||
if let Some(worktree) = servers_for_path
|
||||
.worktree
|
||||
.as_ref()
|
||||
.and_then(|worktree| worktree.upgrade())
|
||||
{
|
||||
for (server_id, server_name) in &servers_for_path.servers {
|
||||
for (server_id, _) in &servers_for_path.servers {
|
||||
server_ids_to_worktrees.insert(*server_id, worktree.clone());
|
||||
if let Some(server_name) = server_name {
|
||||
server_names_to_worktrees
|
||||
.entry(server_name.clone())
|
||||
.or_default()
|
||||
.insert((worktree.clone(), *server_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -714,19 +704,12 @@ impl LspTool {
|
|||
let mut servers_with_health_checks = HashSet::default();
|
||||
|
||||
for (server_id, health) in &state.language_servers.health_statuses {
|
||||
let worktree = server_ids_to_worktrees.get(server_id).or_else(|| {
|
||||
let worktrees = server_names_to_worktrees.get(&health.name)?;
|
||||
worktrees
|
||||
.iter()
|
||||
.find(|(worktree, _)| active_worktrees.contains(worktree))
|
||||
.or_else(|| worktrees.iter().next())
|
||||
.map(|(worktree, _)| worktree)
|
||||
});
|
||||
servers_with_health_checks.insert(&health.name);
|
||||
let worktree = server_ids_to_worktrees.get(server_id);
|
||||
servers_with_health_checks.insert(*server_id);
|
||||
let worktree_name =
|
||||
worktree.map(|worktree| SharedString::new(worktree.read(cx).root_name()));
|
||||
|
||||
let binary_status = state.language_servers.binary_statuses.get(&health.name);
|
||||
let binary_status = state.language_servers.binary_statuses.get(server_id);
|
||||
let server_data = ServerData::WithHealthCheck {
|
||||
server_id: *server_id,
|
||||
health,
|
||||
|
@ -743,11 +726,11 @@ impl LspTool {
|
|||
|
||||
let mut can_stop_all = !state.language_servers.health_statuses.is_empty();
|
||||
let mut can_restart_all = state.language_servers.health_statuses.is_empty();
|
||||
for (server_name, binary_status) in state
|
||||
for (server_id, binary_status) in state
|
||||
.language_servers
|
||||
.binary_statuses
|
||||
.iter()
|
||||
.filter(|(name, _)| !servers_with_health_checks.contains(name))
|
||||
.filter(|&(id, _)| !servers_with_health_checks.contains(id))
|
||||
{
|
||||
match binary_status.status {
|
||||
BinaryStatus::None => {
|
||||
|
@ -774,40 +757,25 @@ impl LspTool {
|
|||
BinaryStatus::Failed { .. } => {}
|
||||
}
|
||||
|
||||
match server_names_to_worktrees.get(server_name) {
|
||||
Some(worktrees_for_name) => {
|
||||
match worktrees_for_name
|
||||
.iter()
|
||||
.find(|(worktree, _)| active_worktrees.contains(worktree))
|
||||
.or_else(|| worktrees_for_name.iter().next())
|
||||
{
|
||||
Some((worktree, server_id)) => {
|
||||
let worktree_name =
|
||||
SharedString::new(worktree.read(cx).root_name());
|
||||
servers_per_worktree
|
||||
.entry(worktree_name.clone())
|
||||
.or_default()
|
||||
.push(ServerData::WithBinaryStatus {
|
||||
server_name,
|
||||
binary_status,
|
||||
server_id: Some(*server_id),
|
||||
});
|
||||
}
|
||||
None => servers_without_worktree.push(ServerData::WithBinaryStatus {
|
||||
let server_name = &binary_status.name;
|
||||
match server_ids_to_worktrees.get(server_id) {
|
||||
Some(worktree) if active_worktrees.contains(worktree) => {
|
||||
let worktree_name = SharedString::new(worktree.read(cx).root_name());
|
||||
servers_per_worktree.entry(worktree_name).or_default().push(
|
||||
ServerData::WithBinaryStatus {
|
||||
server_name,
|
||||
binary_status,
|
||||
server_id: None,
|
||||
}),
|
||||
}
|
||||
server_id: Some(*server_id),
|
||||
},
|
||||
);
|
||||
}
|
||||
None => servers_without_worktree.push(ServerData::WithBinaryStatus {
|
||||
_ => servers_without_worktree.push(ServerData::WithBinaryStatus {
|
||||
server_name,
|
||||
binary_status,
|
||||
server_id: None,
|
||||
server_id: Some(*server_id),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_lsp_items =
|
||||
Vec::with_capacity(servers_per_worktree.len() + servers_without_worktree.len() + 2);
|
||||
for (worktree_name, worktree_servers) in servers_per_worktree {
|
||||
|
|
|
@ -308,6 +308,7 @@ impl LocalLspStore {
|
|||
toolchain.clone(),
|
||||
delegate.clone(),
|
||||
true,
|
||||
server_id,
|
||||
cx,
|
||||
);
|
||||
let pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>> = Default::default();
|
||||
|
@ -351,11 +352,11 @@ impl LocalLspStore {
|
|||
}
|
||||
});
|
||||
|
||||
let server_name = adapter.name.clone();
|
||||
let startup = {
|
||||
let server_name = adapter.name.0.clone();
|
||||
let server_name = server_name.clone();
|
||||
let delegate = delegate as Arc<dyn LspAdapterDelegate>;
|
||||
let key = key.clone();
|
||||
let adapter = adapter.clone();
|
||||
let lsp_store = self.weak.clone();
|
||||
let pending_workspace_folders = pending_workspace_folders.clone();
|
||||
let fs = self.fs.clone();
|
||||
|
@ -460,8 +461,10 @@ impl LocalLspStore {
|
|||
|
||||
Err(err) => {
|
||||
let log = stderr_capture.lock().take().unwrap_or_default();
|
||||
log::error!("Failed to start language server {server_name:?}: {err:?}");
|
||||
delegate.update_status(
|
||||
adapter.name(),
|
||||
server_id,
|
||||
server_name,
|
||||
BinaryStatus::Failed {
|
||||
error: if log.is_empty() {
|
||||
format!("{err:#}")
|
||||
|
@ -470,7 +473,6 @@ impl LocalLspStore {
|
|||
},
|
||||
},
|
||||
);
|
||||
log::error!("Failed to start language server {server_name:?}: {err:?}");
|
||||
if !log.is_empty() {
|
||||
log::error!("server stderr: {log}");
|
||||
}
|
||||
|
@ -485,7 +487,7 @@ impl LocalLspStore {
|
|||
};
|
||||
|
||||
self.languages
|
||||
.update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
|
||||
.update_lsp_binary_status(server_id, server_name, BinaryStatus::Starting);
|
||||
|
||||
self.language_servers.insert(server_id, state);
|
||||
self.language_server_ids
|
||||
|
@ -504,6 +506,7 @@ impl LocalLspStore {
|
|||
toolchain: Option<Toolchain>,
|
||||
delegate: Arc<dyn LspAdapterDelegate>,
|
||||
allow_binary_download: bool,
|
||||
server_id: LanguageServerId,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<LanguageServerBinary>> {
|
||||
if let Some(settings) = settings.binary.as_ref()
|
||||
|
@ -539,10 +542,16 @@ impl LocalLspStore {
|
|||
cx.spawn(async move |cx| {
|
||||
let binary_result = adapter
|
||||
.clone()
|
||||
.get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
|
||||
.get_language_server_command(
|
||||
delegate.clone(),
|
||||
toolchain,
|
||||
lsp_binary_options,
|
||||
server_id,
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
delegate.update_status(adapter.name.clone(), BinaryStatus::None);
|
||||
delegate.update_status(server_id, adapter.name(), BinaryStatus::None);
|
||||
|
||||
let mut binary = binary_result?;
|
||||
let mut shell_env = delegate.shell_env().await;
|
||||
|
@ -10409,17 +10418,22 @@ impl LspStore {
|
|||
|
||||
if let Some(name) = name {
|
||||
log::info!("stopping language server {name}");
|
||||
self.languages
|
||||
.update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
|
||||
self.languages.update_lsp_binary_status(
|
||||
server_id,
|
||||
name.clone(),
|
||||
BinaryStatus::Stopping,
|
||||
);
|
||||
cx.notify();
|
||||
|
||||
return cx.spawn(async move |lsp_store, cx| {
|
||||
Self::shutdown_language_server(server_state, name.clone(), cx).await;
|
||||
lsp_store
|
||||
.update(cx, |lsp_store, cx| {
|
||||
lsp_store
|
||||
.languages
|
||||
.update_lsp_binary_status(name, BinaryStatus::Stopped);
|
||||
lsp_store.languages.update_lsp_binary_status(
|
||||
server_id,
|
||||
name.clone(),
|
||||
BinaryStatus::Stopped,
|
||||
);
|
||||
cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
|
||||
cx.notify();
|
||||
})
|
||||
|
@ -10882,7 +10896,7 @@ impl LspStore {
|
|||
);
|
||||
local
|
||||
.languages
|
||||
.update_lsp_binary_status(adapter.name(), BinaryStatus::None);
|
||||
.update_lsp_binary_status(server_id, adapter.name(), BinaryStatus::None);
|
||||
if let Some(file_ops_caps) = language_server
|
||||
.capabilities()
|
||||
.workspace
|
||||
|
@ -12197,7 +12211,7 @@ fn subscribe_to_binary_statuses(
|
|||
) -> Task<()> {
|
||||
let mut server_statuses = languages.language_server_binary_statuses();
|
||||
cx.spawn(async move |lsp_store, cx| {
|
||||
while let Some((server_name, binary_status)) = server_statuses.next().await {
|
||||
while let Some((server_id, server_name, binary_status)) = server_statuses.next().await {
|
||||
if lsp_store
|
||||
.update(cx, |_, cx| {
|
||||
let mut message = None;
|
||||
|
@ -12216,9 +12230,7 @@ fn subscribe_to_binary_statuses(
|
|||
}
|
||||
};
|
||||
cx.emit(LspStoreEvent::LanguageServerUpdate {
|
||||
// Binary updates are about the binary that might not have any language server id at that point.
|
||||
// Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
|
||||
language_server_id: LanguageServerId(0),
|
||||
language_server_id: server_id,
|
||||
name: Some(server_name),
|
||||
message: proto::update_language_server::Variant::StatusUpdate(
|
||||
proto::StatusUpdate {
|
||||
|
@ -13154,9 +13166,14 @@ impl LspAdapterDelegate for LocalLspAdapterDelegate {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
|
||||
fn update_status(
|
||||
&self,
|
||||
server_id: LanguageServerId,
|
||||
server_name: LanguageServerName,
|
||||
status: language::BinaryStatus,
|
||||
) {
|
||||
self.language_registry
|
||||
.update_lsp_binary_status(server_name, status);
|
||||
.update_lsp_binary_status(server_id, server_name, status);
|
||||
}
|
||||
|
||||
fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue