Skip to content

Commit

Permalink
zed: Use CLI env for lang servers, tasks, terminal (#17075)
Browse files Browse the repository at this point in the history
This changes the Zed CLI `zed` to pass along the environment to the Zed
project that it opens (if it opens a new one).

In projects, this CLI environment will now take precedence over any
environment that's acquired by running a login shell in a projects
folder.

The result is that `zed my/folder` now always behaves as if one would
run `zed --foreground` without any previous Zed version running.


Closes #7894
Closes #16293 

Related issues:
- It fixes the issue described in here:
#4977 (comment)


Release Notes:

- Improved the Zed CLI `zed` to pass along the environment as it was on
the CLI to the opened Zed project. That environment is then used when
opening new terminals, spawning tasks, or language servers.
Specifically:
- If Zed was started via `zed my-folder`, a terminal spawned with
`workspace: new terminal` will inherit these environment variables that
existed on the CLI
- Specific language servers that allow looking up the language server
binary in the environments `$PATH` (such as `gopls`, `zls`,
`rust-analyzer` if configured, ...) will look up the language server
binary in the CLI environment too and use that environment when starting
the process.
- Language servers that are _not_ found in the CLI environment (or
configured to not be found in there), will be spawned with the CLI
environment in case that's set. That means users can do something like
`RA_LOG=info zed .` and it will be picked up the rust-analyzer that was
spawned.

Demo/explanation:



https://github.com/user-attachments/assets/455905cc-8b7c-4fc4-b98a-7e027d97cdfa
  • Loading branch information
mrnugget authored Aug 29, 2024
1 parent 4f408ec commit fc4c533
Show file tree
Hide file tree
Showing 19 changed files with 484 additions and 227 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ path = "src/main.rs"
[dependencies]
anyhow.workspace = true
clap.workspace = true
collections.workspace = true
ipc-channel = "0.18"
once_cell.workspace = true
parking_lot.workspace = true
Expand Down
2 changes: 2 additions & 0 deletions crates/cli/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use collections::HashMap;
pub use ipc_channel::ipc;
use serde::{Deserialize, Serialize};

Expand All @@ -15,6 +16,7 @@ pub enum CliRequest {
wait: bool,
open_new_workspace: Option<bool>,
dev_server_token: Option<String>,
env: Option<HashMap<String, String>>,
},
}

Expand Down
4 changes: 4 additions & 0 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use anyhow::{Context, Result};
use clap::Parser;
use cli::{ipc::IpcOneShotServer, CliRequest, CliResponse, IpcHandshake};
use collections::HashMap;
use parking_lot::Mutex;
use std::{
env, fs, io,
Expand Down Expand Up @@ -122,6 +123,7 @@ fn main() -> Result<()> {
None
};

let env = Some(std::env::vars().collect::<HashMap<_, _>>());
let exit_status = Arc::new(Mutex::new(None));
let mut paths = vec![];
let mut urls = vec![];
Expand Down Expand Up @@ -149,12 +151,14 @@ fn main() -> Result<()> {
move || {
let (_, handshake) = server.accept().context("Handshake after Zed spawn")?;
let (tx, rx) = (handshake.requests, handshake.responses);

tx.send(CliRequest::Open {
paths,
urls,
wait: args.wait,
open_new_workspace,
dev_server_token: args.dev_server_token,
env,
})?;

while let Ok(response) = rx.recv() {
Expand Down
1 change: 1 addition & 0 deletions crates/collab/src/tests/test_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,7 @@ impl TestClient {
self.app_state.user_store.clone(),
self.app_state.languages.clone(),
self.app_state.fs.clone(),
None,
cx,
)
})
Expand Down
4 changes: 2 additions & 2 deletions crates/editor/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ pub fn init(cx: &mut AppContext) {
cx.on_action(move |_: &workspace::NewFile, cx| {
let app_state = workspace::AppState::global(cx);
if let Some(app_state) = app_state.upgrade() {
workspace::open_new(app_state, cx, |workspace, cx| {
workspace::open_new(Default::default(), app_state, cx, |workspace, cx| {
Editor::new_file(workspace, &Default::default(), cx)
})
.detach();
Expand All @@ -316,7 +316,7 @@ pub fn init(cx: &mut AppContext) {
cx.on_action(move |_: &workspace::NewWindow, cx| {
let app_state = workspace::AppState::global(cx);
if let Some(app_state) = app_state.upgrade() {
workspace::open_new(app_state, cx, |workspace, cx| {
workspace::open_new(Default::default(), app_state, cx, |workspace, cx| {
Editor::new_file(workspace, &Default::default(), cx)
})
.detach();
Expand Down
1 change: 1 addition & 0 deletions crates/headless/src/headless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ impl DevServer {
this.app_state.user_store.clone(),
this.app_state.languages.clone(),
this.app_state.fs.clone(),
None,
cx,
);

Expand Down
16 changes: 15 additions & 1 deletion crates/language/src/language_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -719,13 +719,15 @@ impl LanguageRegistry {
self.lsp_binary_status_tx.send(server_name, status);
}

#[allow(clippy::too_many_arguments)]
pub fn create_pending_language_server(
self: &Arc<Self>,
stderr_capture: Arc<Mutex<Option<String>>>,
language: Arc<Language>,
adapter: Arc<CachedLspAdapter>,
root_path: Arc<Path>,
delegate: Arc<dyn LspAdapterDelegate>,
cli_environment: Option<HashMap<String, String>>,
cx: &mut AppContext,
) -> Option<PendingLanguageServer> {
let server_id = self.state.write().next_language_server_id();
Expand Down Expand Up @@ -764,7 +766,19 @@ impl LanguageRegistry {

delegate.update_status(adapter.name.clone(), LanguageServerBinaryStatus::None);

let binary = binary_result?;
let mut binary = binary_result?;

// If this Zed project was opened from the CLI and the language server command itself
// doesn't have an environment (which it would have, if it was found in $PATH), then
// we pass along the CLI environment that we inherited.
if binary.env.is_none() && cli_environment.is_some() {
log::info!(
"using CLI environment for language server {:?}, id: {server_id}",
adapter.name.0
);
binary.env = cli_environment.clone();
}

let options = adapter
.adapter
.clone()
Expand Down
Loading

0 comments on commit fc4c533

Please sign in to comment.