From 7ade7d8e45620669c6e5d313aeeeb902933e7025 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Fri, 21 Mar 2025 00:15:41 -0700 Subject: [PATCH] lsp-config: Allow setting a server's environment variables (#27213) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://github.com/zed-industries/zed/issues/14334, allowing users to set environment variables for a language server binary like: ```json "lsp": { "rust-analyzer": { "binary": { "path": "/Users/dbarsky/.cargo/bin/rust-analyzer", "env": { "RA_PROFILE": "*>100" } }, } } ``` The newly introduced environment variables are merged with the shell environment. Perhaps more controversially, I've _also_ removed the trimming/`stderr:`-prefixing of language server logs. This because rust-analyzer has some nice, tree-shaped profiling built-in, and it prevents us from printing profiles like this:
Screenshot 2025-03-20 at 12 09 14 PM
Release Notes: - Added the ability to set a language server's environment variables. - Removed the `stderr`-prefix of a language server's stderr logs. --- .../src/wasm_host/wit/since_v0_3_0.rs | 2 +- crates/language_tools/src/lsp_log.rs | 1 - crates/project/src/lsp_store.rs | 19 ++++++++++++++----- crates/project/src/project_settings.rs | 2 ++ 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_3_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_3_0.rs index b5dfb55fd4..362a3555b1 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_3_0.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_3_0.rs @@ -651,7 +651,7 @@ impl ExtensionImports for WasmState { binary: settings.binary.map(|binary| settings::CommandSettings { path: binary.path, arguments: binary.arguments, - env: None, + env: binary.env, }), settings: settings.settings, initialization_options: settings.initialization_options, diff --git a/crates/language_tools/src/lsp_log.rs b/crates/language_tools/src/lsp_log.rs index b956b7439d..09b77b47ce 100644 --- a/crates/language_tools/src/lsp_log.rs +++ b/crates/language_tools/src/lsp_log.rs @@ -540,7 +540,6 @@ impl LogStore { IoKind::StdOut => true, IoKind::StdIn => false, IoKind::StdErr => { - let message = format!("stderr: {}", message.trim()); self.add_language_server_log(language_server_id, MessageType::LOG, &message, cx); return Some(()); } diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index 3f13413c03..61870b464b 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -382,10 +382,14 @@ impl LocalLspStore { if settings.as_ref().is_some_and(|b| b.path.is_some()) { let settings = settings.unwrap(); + return cx.spawn(async move |_| { + let mut env = delegate.shell_env().await; + env.extend(settings.env.unwrap_or_default()); + Ok(LanguageServerBinary { path: PathBuf::from(&settings.path.unwrap()), - env: Some(delegate.shell_env().await), + env: Some(env), arguments: settings .arguments .unwrap_or_default() @@ -412,12 +416,17 @@ impl LocalLspStore { delegate.update_status(adapter.name.clone(), BinaryStatus::None); let mut binary = binary_result?; - if let Some(arguments) = settings.and_then(|b| b.arguments) { - binary.arguments = arguments.into_iter().map(Into::into).collect(); + let mut shell_env = delegate.shell_env().await; + + if let Some(settings) = settings { + if let Some(arguments) = settings.arguments { + binary.arguments = arguments.into_iter().map(Into::into).collect(); + } + if let Some(env) = settings.env { + shell_env.extend(env); + } } - let mut shell_env = delegate.shell_env().await; - shell_env.extend(binary.env.unwrap_or_default()); binary.env = Some(shell_env); Ok(binary) }) diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index 250144d8ab..579786b4f6 100644 --- a/crates/project/src/project_settings.rs +++ b/crates/project/src/project_settings.rs @@ -273,6 +273,8 @@ const fn true_value() -> bool { pub struct BinarySettings { pub path: Option, pub arguments: Option>, + // this can't be an FxHashMap because the extension APIs require the default SipHash + pub env: Option>, pub ignore_system_version: Option, }