From ccfd4b1887e7dc30e839334d86713b671449c55b Mon Sep 17 00:00:00 2001 From: Thorsten Ball Date: Tue, 17 Sep 2024 19:45:29 +0200 Subject: [PATCH] rust: Test rust-analyzer binary after finding in PATH (#17951) Release Notes: - N/A --------- Co-authored-by: Conrad Irwin --- crates/language/src/language.rs | 1 + crates/languages/src/rust.rs | 23 ++++++++++++++++++++++- crates/project/src/lsp_store.rs | 24 ++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 8cd8c8079d..7901a49d00 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -285,6 +285,7 @@ pub trait LspAdapterDelegate: Send + Sync { async fn which(&self, command: &OsStr) -> Option; async fn shell_env(&self) -> HashMap; async fn read_text_file(&self, path: PathBuf) -> Result; + async fn try_exec(&self, binary: LanguageServerBinary) -> Result<()>; } #[async_trait(?Send)] diff --git a/crates/languages/src/rust.rs b/crates/languages/src/rust.rs index 456ea8e449..5055bb69c1 100644 --- a/crates/languages/src/rust.rs +++ b/crates/languages/src/rust.rs @@ -61,7 +61,28 @@ impl LspAdapter for RustLspAdapter { }) => { let path = delegate.which(Self::SERVER_NAME.as_ref()).await; let env = delegate.shell_env().await; - (path, Some(env), None) + + if let Some(path) = path { + // It is surprisingly common for ~/.cargo/bin/rust-analyzer to be a symlink to + // /usr/bin/rust-analyzer that fails when you run it; so we need to test it. + log::info!("found rust-analyzer in PATH. trying to run `rust-analyzer --help`"); + match delegate + .try_exec(LanguageServerBinary { + path: path.clone(), + arguments: vec!["--help".into()], + env: Some(env.clone()), + }) + .await + { + Ok(()) => (Some(path), Some(env), None), + Err(err) => { + log::error!("failed to run rust-analyzer after detecting it in PATH: binary: {:?}: {:?}", path, err); + (None, None, None) + } + } + } else { + (None, None, None) + } } // Otherwise, we use the configured binary. Some(BinarySettings { diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index e1e6001d24..2c718a42ab 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -7133,6 +7133,30 @@ impl LspAdapterDelegate for ProjectLspAdapterDelegate { which::which(command).ok() } + async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> { + if self.fs.is_none() { + return Ok(()); + } + + let working_dir = self.worktree_root_path(); + let output = smol::process::Command::new(&command.path) + .args(command.arguments) + .envs(command.env.clone().unwrap_or_default()) + .current_dir(working_dir) + .output() + .await?; + + if output.status.success() { + return Ok(()); + } + Err(anyhow!( + "{}, stdout: {:?}, stderr: {:?}", + output.status, + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + )) + } + fn update_status( &self, server_name: LanguageServerName,