Detailed changes
@@ -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>> {