diff --git a/crates/language_tools/src/lsp_log_view.rs b/crates/language_tools/src/lsp_log_view.rs index 3f99a3e83413691c3893b184406f6e2569062623..c7aa78067294cbb63266e55a0d05d7abbeefddc2 100644 --- a/crates/language_tools/src/lsp_log_view.rs +++ b/crates/language_tools/src/lsp_log_view.rs @@ -7,12 +7,15 @@ use gpui::{ }; use language::{LanguageServerId, language_settings::SoftWrap}; use lsp::{ - LanguageServer, LanguageServerBinary, LanguageServerName, LanguageServerSelector, MessageType, - SetTraceParams, TraceValue, notification::SetTrace, + LanguageServer, LanguageServerName, LanguageServerSelector, MessageType, SetTraceParams, + TraceValue, notification::SetTrace, }; use project::{ - Project, - lsp_store::log_store::{self, Event, LanguageServerKind, LogKind, LogStore, Message}, + LanguageServerStatus, Project, + lsp_store::{ + LanguageServerBinaryInfo, + log_store::{self, Event, LanguageServerKind, LogKind, LogStore, Message}, + }, search::SearchQuery, }; use proto::toggle_lsp_logs::LogType; @@ -337,16 +340,28 @@ impl LspLogView { * Capabilities: {CAPABILITIES} * Configuration: {CONFIGURATION}", - NAME = info.name, + NAME = info.status.name, ID = info.id, - BINARY = info - .binary - .as_ref() - .map_or_else(|| "Unknown".to_string(), |binary| format!("{binary:#?}")), - WORKSPACE_FOLDERS = info.workspace_folders.join(", "), + BINARY = info.status.binary.as_ref().map_or_else( + || "Unknown".to_string(), + |binary| serde_json::to_string_pretty(binary) + .unwrap_or_else(|e| format!("Failed to serialize binary info: {e:#}")) + ), + WORKSPACE_FOLDERS = info + .status + .workspace_folders + .iter() + .filter_map(|uri| { + uri.to_file_path() + .ok() + .map(|path| path.to_string_lossy().into_owned()) + }) + .collect::>() + .join(", "), CAPABILITIES = serde_json::to_string_pretty(&info.capabilities) .unwrap_or_else(|e| format!("Failed to serialize capabilities: {e}")), CONFIGURATION = info + .status .configuration .map(|configuration| serde_json::to_string_pretty(&configuration)) .transpose() @@ -633,17 +648,12 @@ impl LspLogView { .or_else(move || { let capabilities = lsp_store.lsp_server_capabilities.get(&server_id)?.clone(); - let name = lsp_store - .language_server_statuses - .get(&server_id) - .map(|status| status.name.clone())?; + let status = lsp_store.language_server_statuses.get(&server_id)?.clone(); + Some(ServerInfo { id: server_id, capabilities, - binary: None, - name, - workspace_folders: Vec::new(), - configuration: None, + status, }) }) }) @@ -1314,10 +1324,7 @@ impl LspLogToolbarItemView { struct ServerInfo { id: LanguageServerId, capabilities: lsp::ServerCapabilities, - binary: Option, - name: LanguageServerName, - workspace_folders: Vec, - configuration: Option, + status: LanguageServerStatus, } impl ServerInfo { @@ -1325,18 +1332,25 @@ impl ServerInfo { Self { id: server.server_id(), capabilities: server.capabilities(), - binary: Some(server.binary().clone()), - name: server.name(), - workspace_folders: server - .workspace_folders() - .into_iter() - .filter_map(|path| { - path.to_file_path() - .ok() - .map(|path| path.to_string_lossy().into_owned()) - }) - .collect::>(), - configuration: Some(server.configuration().clone()), + status: LanguageServerStatus { + name: server.name(), + pending_work: Default::default(), + has_pending_diagnostic_updates: false, + progress_tokens: Default::default(), + worktree: None, + binary: Some(LanguageServerBinaryInfo { + path: server.binary().path.to_string_lossy().into_owned(), + arguments: server + .binary() + .arguments + .iter() + .map(|arg| arg.to_string_lossy().into_owned()) + .collect(), + env: server.binary().env.clone(), + }), + configuration: Some(server.configuration().clone()), + workspace_folders: server.workspace_folders(), + }, } } } diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index e233ff1c5c121e301a85d829093cbdd37020fe07..d18262215198b8a1d7da38a4a325b6f1dcb82084 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -93,6 +93,7 @@ use rpc::{ proto::{LspRequestId, LspRequestMessage as _}, }; use serde::Serialize; +use serde_json::Value; use settings::{Settings, SettingsLocation, SettingsStore}; use sha2::{Digest, Sha256}; use smol::channel::Sender; @@ -3557,6 +3558,21 @@ fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context< message: proto::update_language_server::Variant::MetadataUpdated( proto::ServerMetadataUpdated { capabilities: Some(capabilities), + binary: Some(proto::LanguageServerBinaryInfo { + path: server.binary().path.to_string_lossy().into_owned(), + arguments: server + .binary() + .arguments + .iter() + .map(|arg| arg.to_string_lossy().into_owned()) + .collect(), + }), + configuration: serde_json::to_string(server.configuration()).ok(), + workspace_folders: server + .workspace_folders() + .iter() + .map(|uri| uri.to_string()) + .collect(), }, ), }); @@ -3713,13 +3729,23 @@ pub enum LspStoreEvent { }, } +#[derive(Clone, Debug, Serialize)] +pub struct LanguageServerBinaryInfo { + pub path: String, + pub arguments: Vec, + pub env: Option>, +} + #[derive(Clone, Debug, Serialize)] pub struct LanguageServerStatus { pub name: LanguageServerName, pub pending_work: BTreeMap, pub has_pending_diagnostic_updates: bool, - progress_tokens: HashSet, + pub progress_tokens: HashSet, pub worktree: Option, + pub binary: Option, + pub configuration: Option, + pub workspace_folders: BTreeSet, } #[derive(Clone, Debug)] @@ -8130,6 +8156,9 @@ impl LspStore { has_pending_diagnostic_updates: false, progress_tokens: Default::default(), worktree, + binary: None, + configuration: None, + workspace_folders: BTreeSet::new(), }, ) }) @@ -9139,6 +9168,9 @@ impl LspStore { has_pending_diagnostic_updates: false, progress_tokens: Default::default(), worktree: server.worktree_id.map(WorktreeId::from_proto), + binary: None, + configuration: None, + workspace_folders: BTreeSet::new(), }, ); cx.emit(LspStoreEvent::LanguageServerAdded( @@ -11155,6 +11187,18 @@ impl LspStore { has_pending_diagnostic_updates: false, progress_tokens: Default::default(), worktree: Some(key.worktree_id), + binary: Some(LanguageServerBinaryInfo { + path: language_server.binary().path.to_string_lossy().into_owned(), + arguments: language_server + .binary() + .arguments + .iter() + .map(|arg| arg.to_string_lossy().into_owned()) + .collect(), + env: language_server.binary().env.clone(), + }), + configuration: Some(language_server.configuration().clone()), + workspace_folders: language_server.workspace_folders(), }, ); diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 3f325aba2b18efb4f36faef4e0a655f716a860bd..63041f8dfff3a432ed8e447ab0fcdb47f519e9e7 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -37,7 +37,7 @@ use dap::inline_value::{InlineValueLocation, VariableLookupKind, VariableScope}; use crate::{ git_store::GitStore, - lsp_store::{SymbolLocation, log_store::LogKind}, + lsp_store::{LanguageServerBinaryInfo, SymbolLocation, log_store::LogKind}, project_search::SearchResultsHandle, }; pub use agent_server_store::{AgentServerStore, AgentServersUpdated, ExternalAgentServerName}; @@ -114,7 +114,7 @@ use std::{ ops::{Not as _, Range}, path::{Path, PathBuf}, pin::pin, - str, + str::{self, FromStr}, sync::Arc, time::Duration, }; @@ -3111,17 +3111,42 @@ impl Project { match message { proto::update_language_server::Variant::MetadataUpdated(update) => { - if let Some(capabilities) = update - .capabilities - .as_ref() - .and_then(|capabilities| serde_json::from_str(capabilities).ok()) - { - self.lsp_store.update(cx, |lsp_store, _| { + self.lsp_store.update(cx, |lsp_store, _| { + if let Some(capabilities) = update + .capabilities + .as_ref() + .and_then(|capabilities| serde_json::from_str(capabilities).ok()) + { lsp_store .lsp_server_capabilities .insert(*language_server_id, capabilities); - }); - } + } + + if let Some(language_server_status) = lsp_store + .language_server_statuses + .get_mut(language_server_id) + { + if let Some(binary) = &update.binary { + language_server_status.binary = + Some(LanguageServerBinaryInfo { + path: binary.path.clone(), + arguments: binary.arguments.clone(), + env: None, + }); + } + + language_server_status.configuration = update + .configuration + .as_ref() + .and_then(|config_str| serde_json::from_str(config_str).ok()); + + language_server_status.workspace_folders = update + .workspace_folders + .iter() + .filter_map(|uri_str| lsp::Uri::from_str(uri_str).ok()) + .collect(); + } + }); } proto::update_language_server::Variant::RegisteredForBuffer(update) => { if let Some(buffer_id) = BufferId::new(update.buffer_id).ok() { diff --git a/crates/proto/proto/lsp.proto b/crates/proto/proto/lsp.proto index 3bdd46c4572acbc570c198288ba5c79b93aa4286..fa44528e2ed6009e6f18b6b5b9702b5228f10f05 100644 --- a/crates/proto/proto/lsp.proto +++ b/crates/proto/proto/lsp.proto @@ -615,8 +615,16 @@ message RegisteredForBuffer { uint64 buffer_id = 2; } +message LanguageServerBinaryInfo { + string path = 1; + repeated string arguments = 2; +} + message ServerMetadataUpdated { optional string capabilities = 1; + optional LanguageServerBinaryInfo binary = 2; + optional string configuration = 3; + repeated string workspace_folders = 4; } message LanguageServerLog {