From 38e1e3f4988bf23070982bfffbdb7c78e1be9547 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 3 Nov 2025 17:29:07 +0100 Subject: [PATCH] project: Use user configured shells for project env fetching (#41288) Closes https://github.com/zed-industries/zed/issues/40464 Release Notes: - Fix shell environment sourcing not respecting users remote shells --- crates/acp_thread/src/acp_thread.rs | 17 +-- crates/acp_thread/src/terminal.rs | 16 +-- crates/editor/src/lsp_ext.rs | 12 +- crates/project/src/agent_server_store.rs | 16 ++- crates/project/src/debugger/dap_store.rs | 16 +-- crates/project/src/environment.rs | 128 ++++++++++++++----- crates/project/src/git_store.rs | 2 +- crates/project/src/lsp_store.rs | 63 +++++---- crates/project/src/project.rs | 49 +++---- crates/project/src/task_store.rs | 2 +- crates/project/src/toolchain_store.rs | 4 +- crates/remote_server/src/headless_project.rs | 5 +- 12 files changed, 177 insertions(+), 153 deletions(-) diff --git a/crates/acp_thread/src/acp_thread.rs b/crates/acp_thread/src/acp_thread.rs index 5ecf2be445ecf8afc6a93e2961302758ea0037ae..37622d004a2e9cd27a3686263ffd1aa98979104f 100644 --- a/crates/acp_thread/src/acp_thread.rs +++ b/crates/acp_thread/src/acp_thread.rs @@ -3,7 +3,6 @@ mod diff; mod mention; mod terminal; -use ::terminal::terminal_settings::TerminalSettings; use agent_settings::AgentSettings; use collections::HashSet; pub use connection::*; @@ -12,7 +11,7 @@ use language::language_settings::FormatOnSave; pub use mention::*; use project::lsp_store::{FormatTrigger, LspFormatTarget}; use serde::{Deserialize, Serialize}; -use settings::{Settings as _, SettingsLocation}; +use settings::Settings as _; use task::{Shell, ShellBuilder}; pub use terminal::*; @@ -2141,17 +2140,9 @@ impl AcpThread { ) -> Task>> { let env = match &cwd { Some(dir) => self.project.update(cx, |project, cx| { - let worktree = project.find_worktree(dir.as_path(), cx); - let shell = TerminalSettings::get( - worktree.as_ref().map(|(worktree, path)| SettingsLocation { - worktree_id: worktree.read(cx).id(), - path: &path, - }), - cx, - ) - .shell - .clone(); - project.directory_environment(&shell, dir.as_path().into(), cx) + project.environment().update(cx, |env, cx| { + env.directory_environment(dir.as_path().into(), cx) + }) }), None => Task::ready(None).shared(), }; diff --git a/crates/acp_thread/src/terminal.rs b/crates/acp_thread/src/terminal.rs index 9ca6d4021b316231930ab7803957dab3a0139f1e..8b08868616e19b0d1855558a057af8eebc314e4a 100644 --- a/crates/acp_thread/src/terminal.rs +++ b/crates/acp_thread/src/terminal.rs @@ -5,10 +5,8 @@ use gpui::{App, AppContext, AsyncApp, Context, Entity, Task}; use language::LanguageRegistry; use markdown::Markdown; use project::Project; -use settings::{Settings as _, SettingsLocation}; use std::{path::PathBuf, process::ExitStatus, sync::Arc, time::Instant}; use task::Shell; -use terminal::terminal_settings::TerminalSettings; use util::get_default_system_shell_preferring_bash; pub struct Terminal { @@ -187,17 +185,9 @@ pub async fn create_terminal_entity( let mut env = if let Some(dir) = &cwd { project .update(cx, |project, cx| { - let worktree = project.find_worktree(dir.as_path(), cx); - let shell = TerminalSettings::get( - worktree.as_ref().map(|(worktree, path)| SettingsLocation { - worktree_id: worktree.read(cx).id(), - path: &path, - }), - cx, - ) - .shell - .clone(); - project.directory_environment(&shell, dir.clone().into(), cx) + project.environment().update(cx, |env, cx| { + env.directory_environment(dir.clone().into(), cx) + }) })? .await .unwrap_or_default() diff --git a/crates/editor/src/lsp_ext.rs b/crates/editor/src/lsp_ext.rs index 0c4760f5684acf450b793a1deac54be983dcafd0..36353e8d42527cd59043ab3cf2b6105c534412d9 100644 --- a/crates/editor/src/lsp_ext.rs +++ b/crates/editor/src/lsp_ext.rs @@ -60,8 +60,10 @@ async fn lsp_task_context( buffer: &Entity, cx: &mut AsyncApp, ) -> Option { - let worktree_store = project - .read_with(cx, |project, _| project.worktree_store()) + let (worktree_store, environment) = project + .read_with(cx, |project, _| { + (project.worktree_store(), project.environment().clone()) + }) .ok()?; let worktree_abs_path = cx @@ -74,9 +76,9 @@ async fn lsp_task_context( }) .ok()?; - let project_env = project - .update(cx, |project, cx| { - project.buffer_environment(buffer, &worktree_store, cx) + let project_env = environment + .update(cx, |environment, cx| { + environment.buffer_environment(buffer, &worktree_store, cx) }) .ok()? .await; diff --git a/crates/project/src/agent_server_store.rs b/crates/project/src/agent_server_store.rs index a6efa1ef75786d3f0dc77ed2e57ec0edec42fc8c..ec1c5c1d60fcfac2b6356076176784b33a8d9fde 100644 --- a/crates/project/src/agent_server_store.rs +++ b/crates/project/src/agent_server_store.rs @@ -1037,7 +1037,7 @@ impl ExternalAgentServer for LocalGemini { cx.spawn(async move |cx| { let mut env = project_environment .update(cx, |project_environment, cx| { - project_environment.get_local_directory_environment( + project_environment.local_directory_environment( &Shell::System, root_dir.clone(), cx, @@ -1133,7 +1133,7 @@ impl ExternalAgentServer for LocalClaudeCode { cx.spawn(async move |cx| { let mut env = project_environment .update(cx, |project_environment, cx| { - project_environment.get_local_directory_environment( + project_environment.local_directory_environment( &Shell::System, root_dir.clone(), cx, @@ -1227,7 +1227,7 @@ impl ExternalAgentServer for LocalCodex { cx.spawn(async move |cx| { let mut env = project_environment .update(cx, |project_environment, cx| { - project_environment.get_local_directory_environment( + project_environment.local_directory_environment( &Shell::System, root_dir.clone(), cx, @@ -1402,7 +1402,7 @@ impl ExternalAgentServer for LocalExtensionArchiveAgent { // Get project environment let mut env = project_environment .update(cx, |project_environment, cx| { - project_environment.get_local_directory_environment( + project_environment.local_directory_environment( &Shell::System, root_dir.clone(), cx, @@ -1585,7 +1585,7 @@ impl ExternalAgentServer for LocalCustomAgent { cx.spawn(async move |cx| { let mut env = project_environment .update(cx, |project_environment, cx| { - project_environment.get_local_directory_environment( + project_environment.local_directory_environment( &Shell::System, root_dir.clone(), cx, @@ -1702,6 +1702,8 @@ impl settings::Settings for AllAgentServersSettings { #[cfg(test)] mod extension_agent_tests { + use crate::worktree_store::WorktreeStore; + use super::*; use gpui::TestAppContext; use std::sync::Arc; @@ -1826,7 +1828,9 @@ mod extension_agent_tests { async fn archive_agent_uses_extension_and_agent_id_for_cache_key(cx: &mut TestAppContext) { let fs = fs::FakeFs::new(cx.background_executor.clone()); let http_client = http_client::FakeHttpClient::with_404_response(); - let project_environment = cx.new(|cx| crate::ProjectEnvironment::new(None, cx)); + let worktree_store = cx.new(|_| WorktreeStore::local(false, fs.clone())); + let project_environment = + cx.new(|cx| crate::ProjectEnvironment::new(None, worktree_store.downgrade(), None, cx)); let agent = LocalExtensionArchiveAgent { fs, diff --git a/crates/project/src/debugger/dap_store.rs b/crates/project/src/debugger/dap_store.rs index 7d80c563e9678ec097dab030bdca047a967e2cf0..0b733aac29843090361cd5868799f6cb1db630f6 100644 --- a/crates/project/src/debugger/dap_store.rs +++ b/crates/project/src/debugger/dap_store.rs @@ -49,7 +49,7 @@ use std::{ path::{Path, PathBuf}, sync::{Arc, Once}, }; -use task::{DebugScenario, Shell, SpawnInTerminal, TaskContext, TaskTemplate}; +use task::{DebugScenario, SpawnInTerminal, TaskContext, TaskTemplate}; use util::{ResultExt as _, rel_path::RelPath}; use worktree::Worktree; @@ -267,8 +267,8 @@ impl DapStore { let user_env = dap_settings.map(|s| s.env.clone()); let delegate = self.delegate(worktree, console, cx); - let cwd: Arc = worktree.read(cx).abs_path().as_ref().into(); + let worktree = worktree.clone(); cx.spawn(async move |this, cx| { let mut binary = adapter .get_binary( @@ -287,11 +287,7 @@ impl DapStore { .unwrap() .environment .update(cx, |environment, cx| { - environment.get_local_directory_environment( - &Shell::System, - cwd, - cx, - ) + environment.worktree_environment(worktree, cx) }) })? .await; @@ -607,9 +603,9 @@ impl DapStore { local_store.node_runtime.clone(), local_store.http_client.clone(), local_store.toolchain_store.clone(), - local_store.environment.update(cx, |env, cx| { - env.get_worktree_environment(worktree.clone(), cx) - }), + local_store + .environment + .update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx)), local_store.is_headless, )) } diff --git a/crates/project/src/environment.rs b/crates/project/src/environment.rs index 0f713b7deb3aca07ea7f867fc768ab2af9716c15..cc14611edbcec922c439cb06c63566036dc64cc6 100644 --- a/crates/project/src/environment.rs +++ b/crates/project/src/environment.rs @@ -5,11 +5,12 @@ use remote::RemoteClient; use rpc::proto::{self, REMOTE_SERVER_PROJECT_ID}; use std::{collections::VecDeque, path::Path, sync::Arc}; use task::{Shell, shell_to_proto}; -use util::ResultExt; +use terminal::terminal_settings::TerminalSettings; +use util::{ResultExt, rel_path::RelPath}; use worktree::Worktree; use collections::HashMap; -use gpui::{AppContext as _, Context, Entity, EventEmitter, Task}; +use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Task, WeakEntity}; use settings::Settings as _; use crate::{ @@ -23,6 +24,8 @@ pub struct ProjectEnvironment { remote_environments: HashMap<(Shell, Arc), Shared>>>>, environment_error_messages: VecDeque, environment_error_messages_tx: mpsc::UnboundedSender, + worktree_store: WeakEntity, + remote_client: Option>, _tasks: Vec>, } @@ -33,7 +36,12 @@ pub enum ProjectEnvironmentEvent { impl EventEmitter for ProjectEnvironment {} impl ProjectEnvironment { - pub fn new(cli_environment: Option>, cx: &mut Context) -> Self { + pub fn new( + cli_environment: Option>, + worktree_store: WeakEntity, + remote_client: Option>, + cx: &mut Context, + ) -> Self { let (tx, mut rx) = mpsc::unbounded(); let task = cx.spawn(async move |this, cx| { while let Some(message) = rx.next().await { @@ -50,12 +58,17 @@ impl ProjectEnvironment { remote_environments: Default::default(), environment_error_messages: Default::default(), environment_error_messages_tx: tx, + worktree_store, + remote_client, _tasks: vec![task], } } /// Returns the inherited CLI environment, if this project was opened from the Zed CLI. pub(crate) fn get_cli_environment(&self) -> Option> { + if cfg!(any(test, feature = "test-support")) { + return Some(HashMap::default()); + } if let Some(mut env) = self.cli_environment.clone() { set_origin_marker(&mut env, EnvironmentOrigin::Cli); Some(env) @@ -64,16 +77,12 @@ impl ProjectEnvironment { } } - pub(crate) fn get_buffer_environment( + pub fn buffer_environment( &mut self, buffer: &Entity, worktree_store: &Entity, cx: &mut Context, ) -> Shared>>> { - if cfg!(any(test, feature = "test-support")) { - return Task::ready(Some(HashMap::default())).shared(); - } - if let Some(cli_environment) = self.get_cli_environment() { log::debug!("using project environment variables from CLI"); return Task::ready(Some(cli_environment)).shared(); @@ -87,54 +96,105 @@ impl ProjectEnvironment { else { return Task::ready(None).shared(); }; - - self.get_worktree_environment(worktree, cx) + self.worktree_environment(worktree, cx) } - pub fn get_worktree_environment( + pub fn worktree_environment( &mut self, worktree: Entity, - cx: &mut Context, + cx: &mut App, ) -> Shared>>> { - if cfg!(any(test, feature = "test-support")) { - return Task::ready(Some(HashMap::default())).shared(); - } - if let Some(cli_environment) = self.get_cli_environment() { log::debug!("using project environment variables from CLI"); return Task::ready(Some(cli_environment)).shared(); } - let mut abs_path = worktree.read(cx).abs_path(); - if !worktree.read(cx).is_local() { - log::error!( - "attempted to get project environment for a non-local worktree at {abs_path:?}" - ); - return Task::ready(None).shared(); - } else if worktree.read(cx).is_single_file() { + let worktree = worktree.read(cx); + let mut abs_path = worktree.abs_path(); + if worktree.is_single_file() { let Some(parent) = abs_path.parent() else { return Task::ready(None).shared(); }; abs_path = parent.into(); } - self.get_local_directory_environment(&Shell::System, abs_path, cx) + let remote_client = self.remote_client.as_ref().and_then(|it| it.upgrade()); + match remote_client { + Some(remote_client) => remote_client.clone().read(cx).shell().map(|shell| { + self.remote_directory_environment( + &Shell::Program(shell), + abs_path, + remote_client, + cx, + ) + }), + None => Some({ + let shell = TerminalSettings::get( + Some(settings::SettingsLocation { + worktree_id: worktree.id(), + path: RelPath::empty(), + }), + cx, + ) + .shell + .clone(); + + self.local_directory_environment(&shell, abs_path, cx) + }), + } + .unwrap_or_else(|| Task::ready(None).shared()) + } + + pub fn directory_environment( + &mut self, + abs_path: Arc, + cx: &mut App, + ) -> Shared>>> { + let remote_client = self.remote_client.as_ref().and_then(|it| it.upgrade()); + match remote_client { + Some(remote_client) => remote_client.clone().read(cx).shell().map(|shell| { + self.remote_directory_environment( + &Shell::Program(shell), + abs_path, + remote_client, + cx, + ) + }), + None => self + .worktree_store + .read_with(cx, |worktree_store, cx| { + worktree_store.find_worktree(&abs_path, cx) + }) + .ok() + .map(|worktree| { + let shell = terminal::terminal_settings::TerminalSettings::get( + worktree + .as_ref() + .map(|(worktree, path)| settings::SettingsLocation { + worktree_id: worktree.read(cx).id(), + path: &path, + }), + cx, + ) + .shell + .clone(); + + self.local_directory_environment(&shell, abs_path, cx) + }), + } + .unwrap_or_else(|| Task::ready(None).shared()) } /// Returns the project environment, if possible. /// If the project was opened from the CLI, then the inherited CLI environment is returned. /// If it wasn't opened from the CLI, and an absolute path is given, then a shell is spawned in /// that directory, to get environment variables as if the user has `cd`'d there. - pub fn get_local_directory_environment( + pub fn local_directory_environment( &mut self, shell: &Shell, abs_path: Arc, - cx: &mut Context, + cx: &mut App, ) -> Shared>>> { - if cfg!(any(test, feature = "test-support")) { - return Task::ready(Some(HashMap::default())).shared(); - } - if let Some(cli_environment) = self.get_cli_environment() { log::debug!("using project environment variables from CLI"); return Task::ready(Some(cli_environment)).shared(); @@ -146,7 +206,7 @@ impl ProjectEnvironment { let load_direnv = ProjectSettings::get_global(cx).load_direnv.clone(); let shell = shell.clone(); let tx = self.environment_error_messages_tx.clone(); - cx.spawn(async move |_, cx| { + cx.spawn(async move |cx| { let mut shell_env = cx .background_spawn(load_directory_shell_environment( shell, @@ -178,12 +238,12 @@ impl ProjectEnvironment { .clone() } - pub fn get_remote_directory_environment( + pub fn remote_directory_environment( &mut self, shell: &Shell, abs_path: Arc, remote_client: Entity, - cx: &mut Context, + cx: &mut App, ) -> Shared>>> { if cfg!(any(test, feature = "test-support")) { return Task::ready(Some(HashMap::default())).shared(); @@ -201,7 +261,7 @@ impl ProjectEnvironment { shell: Some(shell_to_proto(shell.clone())), directory: abs_path.to_string_lossy().to_string(), }); - cx.spawn(async move |_, _| { + cx.background_spawn(async move { let environment = response.await.log_err()?; Some(environment.environment.into_iter().collect()) }) diff --git a/crates/project/src/git_store.rs b/crates/project/src/git_store.rs index e29710682b45125ff06a0cc8390e768a11289c6d..2ada4a94eff69e73cd4e9d5fc360443d583ced91 100644 --- a/crates/project/src/git_store.rs +++ b/crates/project/src/git_store.rs @@ -4804,7 +4804,7 @@ impl Repository { .upgrade() .context("missing project environment")? .update(cx, |project_environment, cx| { - project_environment.get_local_directory_environment(&Shell::System, work_directory_abs_path.clone(), cx) + project_environment.local_directory_environment(&Shell::System, work_directory_abs_path.clone(), cx) })? .await .unwrap_or_else(|| { diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index 2be2d20253bb4257fe00dbf4c3ce4f309d40e1e8..5ed0d39de47a56e4aec5e0e215f220854b11c32e 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -5341,8 +5341,8 @@ impl LspStore { request.to_proto(project_id, buffer.read(cx)), ); let buffer = buffer.clone(); - cx.spawn(async move |weak_project, cx| { - let Some(project) = weak_project.upgrade() else { + cx.spawn(async move |weak_lsp_store, cx| { + let Some(lsp_store) = weak_lsp_store.upgrade() else { return Ok(None); }; let Some(responses) = request_task.await? else { @@ -5351,7 +5351,7 @@ impl LspStore { let actions = join_all(responses.payload.into_iter().map(|response| { GetDefinitions { position }.response_from_proto( response.response, - project.clone(), + lsp_store.clone(), buffer.clone(), cx.clone(), ) @@ -5407,8 +5407,8 @@ impl LspStore { request.to_proto(project_id, buffer.read(cx)), ); let buffer = buffer.clone(); - cx.spawn(async move |weak_project, cx| { - let Some(project) = weak_project.upgrade() else { + cx.spawn(async move |weak_lsp_store, cx| { + let Some(lsp_store) = weak_lsp_store.upgrade() else { return Ok(None); }; let Some(responses) = request_task.await? else { @@ -5417,7 +5417,7 @@ impl LspStore { let actions = join_all(responses.payload.into_iter().map(|response| { GetDeclarations { position }.response_from_proto( response.response, - project.clone(), + lsp_store.clone(), buffer.clone(), cx.clone(), ) @@ -5473,8 +5473,8 @@ impl LspStore { request.to_proto(project_id, buffer.read(cx)), ); let buffer = buffer.clone(); - cx.spawn(async move |weak_project, cx| { - let Some(project) = weak_project.upgrade() else { + cx.spawn(async move |weak_lsp_store, cx| { + let Some(lsp_store) = weak_lsp_store.upgrade() else { return Ok(None); }; let Some(responses) = request_task.await? else { @@ -5483,7 +5483,7 @@ impl LspStore { let actions = join_all(responses.payload.into_iter().map(|response| { GetTypeDefinitions { position }.response_from_proto( response.response, - project.clone(), + lsp_store.clone(), buffer.clone(), cx.clone(), ) @@ -5539,8 +5539,8 @@ impl LspStore { request.to_proto(project_id, buffer.read(cx)), ); let buffer = buffer.clone(); - cx.spawn(async move |weak_project, cx| { - let Some(project) = weak_project.upgrade() else { + cx.spawn(async move |weak_lsp_store, cx| { + let Some(lsp_store) = weak_lsp_store.upgrade() else { return Ok(None); }; let Some(responses) = request_task.await? else { @@ -5549,7 +5549,7 @@ impl LspStore { let actions = join_all(responses.payload.into_iter().map(|response| { GetImplementations { position }.response_from_proto( response.response, - project.clone(), + lsp_store.clone(), buffer.clone(), cx.clone(), ) @@ -5606,8 +5606,8 @@ impl LspStore { request.to_proto(project_id, buffer.read(cx)), ); let buffer = buffer.clone(); - cx.spawn(async move |weak_project, cx| { - let Some(project) = weak_project.upgrade() else { + cx.spawn(async move |weak_lsp_store, cx| { + let Some(lsp_store) = weak_lsp_store.upgrade() else { return Ok(None); }; let Some(responses) = request_task.await? else { @@ -5617,7 +5617,7 @@ impl LspStore { let locations = join_all(responses.payload.into_iter().map(|lsp_response| { GetReferences { position }.response_from_proto( lsp_response.response, - project.clone(), + lsp_store.clone(), buffer.clone(), cx.clone(), ) @@ -5674,8 +5674,8 @@ impl LspStore { request.to_proto(project_id, buffer.read(cx)), ); let buffer = buffer.clone(); - cx.spawn(async move |weak_project, cx| { - let Some(project) = weak_project.upgrade() else { + cx.spawn(async move |weak_lsp_store, cx| { + let Some(lsp_store) = weak_lsp_store.upgrade() else { return Ok(None); }; let Some(responses) = request_task.await? else { @@ -5688,7 +5688,7 @@ impl LspStore { } .response_from_proto( response.response, - project.clone(), + lsp_store.clone(), buffer.clone(), cx.clone(), ) @@ -7187,7 +7187,7 @@ impl LspStore { ); let buffer = buffer.clone(); cx.spawn(async move |lsp_store, cx| { - let Some(project) = lsp_store.upgrade() else { + let Some(lsp_store) = lsp_store.upgrade() else { return Ok(None); }; let colors = join_all( @@ -7201,7 +7201,7 @@ impl LspStore { .map(|color_response| { let response = request.response_from_proto( color_response.response, - project.clone(), + lsp_store.clone(), buffer.clone(), cx.clone(), ); @@ -7265,8 +7265,8 @@ impl LspStore { request.to_proto(upstream_project_id, buffer.read(cx)), ); let buffer = buffer.clone(); - cx.spawn(async move |weak_project, cx| { - let project = weak_project.upgrade()?; + cx.spawn(async move |weak_lsp_store, cx| { + let lsp_store = weak_lsp_store.upgrade()?; let signatures = join_all( request_task .await @@ -7278,7 +7278,7 @@ impl LspStore { .map(|response| { let response = GetSignatureHelp { position }.response_from_proto( response.response, - project.clone(), + lsp_store.clone(), buffer.clone(), cx.clone(), ); @@ -7329,8 +7329,8 @@ impl LspStore { request.to_proto(upstream_project_id, buffer.read(cx)), ); let buffer = buffer.clone(); - cx.spawn(async move |weak_project, cx| { - let project = weak_project.upgrade()?; + cx.spawn(async move |weak_lsp_store, cx| { + let lsp_store = weak_lsp_store.upgrade()?; let hovers = join_all( request_task .await @@ -7342,7 +7342,7 @@ impl LspStore { .map(|response| { let response = GetHover { position }.response_from_proto( response.response, - project.clone(), + lsp_store.clone(), buffer.clone(), cx.clone(), ); @@ -10164,7 +10164,7 @@ impl LspStore { ) -> Shared>>> { if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) { environment.update(cx, |env, cx| { - env.get_buffer_environment(buffer, &self.worktree_store, cx) + env.buffer_environment(buffer, &self.worktree_store, cx) }) } else { Task::ready(None).shared() @@ -12949,7 +12949,7 @@ impl LanguageServerWatchedPathsBuilder { language_server_id: LanguageServerId, cx: &mut Context, ) -> LanguageServerWatchedPaths { - let project = cx.weak_entity(); + let lsp_store = cx.weak_entity(); const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100); let abs_paths = self @@ -12960,7 +12960,7 @@ impl LanguageServerWatchedPathsBuilder { let abs_path = abs_path.clone(); let fs = fs.clone(); - let lsp_store = project.clone(); + let lsp_store = lsp_store.clone(); async move |_, cx| { maybe!(async move { let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await; @@ -13428,9 +13428,8 @@ impl LocalLspAdapterDelegate { fs: Arc, cx: &mut App, ) -> Arc { - let load_shell_env_task = environment.update(cx, |env, cx| { - env.get_worktree_environment(worktree.clone(), cx) - }); + let load_shell_env_task = + environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx)); Arc::new(Self { lsp_store, diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index e75a1bd395e9558c707ea5e27ab18d38c6b603be..cf124217b833158bd632512c62a3dd530cd3b599 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -33,7 +33,6 @@ pub mod search_history; mod yarn; use dap::inline_value::{InlineValueLocation, VariableLookupKind, VariableScope}; -use task::Shell; use crate::{ agent_server_store::AllAgentServersSettings, @@ -68,7 +67,7 @@ use futures::future::join_all; use futures::{ StreamExt, channel::mpsc::{self, UnboundedReceiver}, - future::{Shared, try_join_all}, + future::try_join_all, }; pub use image_store::{ImageItem, ImageStore}; use image_store::{ImageItemEvent, ImageStoreEvent}; @@ -1073,9 +1072,10 @@ impl Project { let weak_self = cx.weak_entity(); let context_server_store = - cx.new(|cx| ContextServerStore::new(worktree_store.clone(), weak_self, cx)); + cx.new(|cx| ContextServerStore::new(worktree_store.clone(), weak_self.clone(), cx)); - let environment = cx.new(|cx| ProjectEnvironment::new(env, cx)); + let environment = + cx.new(|cx| ProjectEnvironment::new(env, worktree_store.downgrade(), None, cx)); let manifest_tree = ManifestTree::new(worktree_store.clone(), cx); let toolchain_store = cx.new(|cx| { ToolchainStore::local( @@ -1264,7 +1264,7 @@ impl Project { let weak_self = cx.weak_entity(); let context_server_store = - cx.new(|cx| ContextServerStore::new(worktree_store.clone(), weak_self, cx)); + cx.new(|cx| ContextServerStore::new(worktree_store.clone(), weak_self.clone(), cx)); let buffer_store = cx.new(|cx| { BufferStore::remote( @@ -1310,7 +1310,14 @@ impl Project { cx.subscribe(&settings_observer, Self::on_settings_observer_event) .detach(); - let environment = cx.new(|cx| ProjectEnvironment::new(None, cx)); + let environment = cx.new(|cx| { + ProjectEnvironment::new( + None, + worktree_store.downgrade(), + Some(remote.downgrade()), + cx, + ) + }); let lsp_store = cx.new(|cx| { LspStore::new_remote( @@ -1523,8 +1530,8 @@ impl Project { ImageStore::remote(worktree_store.clone(), client.clone().into(), remote_id, cx) })?; - let environment = cx.new(|cx| ProjectEnvironment::new(None, cx))?; - + let environment = + cx.new(|cx| ProjectEnvironment::new(None, worktree_store.downgrade(), None, cx))?; let breakpoint_store = cx.new(|_| BreakpointStore::remote(remote_id, client.clone().into()))?; let dap_store = cx.new(|cx| { @@ -1928,32 +1935,6 @@ impl Project { self.environment.read(cx).get_cli_environment() } - pub fn buffer_environment<'a>( - &'a self, - buffer: &Entity, - worktree_store: &Entity, - cx: &'a mut App, - ) -> Shared>>> { - self.environment.update(cx, |environment, cx| { - environment.get_buffer_environment(buffer, worktree_store, cx) - }) - } - - pub fn directory_environment( - &self, - shell: &Shell, - abs_path: Arc, - cx: &mut App, - ) -> Shared>>> { - self.environment.update(cx, |environment, cx| { - if let Some(remote_client) = self.remote_client.clone() { - environment.get_remote_directory_environment(shell, abs_path, remote_client, cx) - } else { - environment.get_local_directory_environment(shell, abs_path, cx) - } - }) - } - #[inline] pub fn peek_environment_error<'a>(&'a self, cx: &'a App) -> Option<&'a String> { self.environment.read(cx).peek_environment_error() diff --git a/crates/project/src/task_store.rs b/crates/project/src/task_store.rs index 0de5e239798c6a95078d79c2a25775c914a13611..462b164e83b6d7dd91c11edc8482290079019bf3 100644 --- a/crates/project/src/task_store.rs +++ b/crates/project/src/task_store.rs @@ -317,7 +317,7 @@ fn local_task_context_for_location( cx.spawn(async move |cx| { let project_env = environment .update(cx, |environment, cx| { - environment.get_buffer_environment(&location.buffer, &worktree_store, cx) + environment.buffer_environment(&location.buffer, &worktree_store, cx) }) .ok()? .await; diff --git a/crates/project/src/toolchain_store.rs b/crates/project/src/toolchain_store.rs index d1c4fc629698bb70d156786837bc2540533d4867..21b74bd784d1d9af12fe43e3fe82051afc103b0d 100644 --- a/crates/project/src/toolchain_store.rs +++ b/crates/project/src/toolchain_store.rs @@ -527,7 +527,7 @@ impl LocalToolchainStore { let project_env = environment .update(cx, |environment, cx| { - environment.get_local_directory_environment( + environment.local_directory_environment( &Shell::System, abs_path.as_path().into(), cx, @@ -590,7 +590,7 @@ impl LocalToolchainStore { let project_env = environment .update(cx, |environment, cx| { - environment.get_local_directory_environment( + environment.local_directory_environment( &Shell::System, path.as_path().into(), cx, diff --git a/crates/remote_server/src/headless_project.rs b/crates/remote_server/src/headless_project.rs index 5d50853601b3949835a350559d48ef755419c93d..57d77f3696283d2e8074713ecd69916eaff07cac 100644 --- a/crates/remote_server/src/headless_project.rs +++ b/crates/remote_server/src/headless_project.rs @@ -94,7 +94,8 @@ impl HeadlessProject { store }); - let environment = cx.new(|cx| ProjectEnvironment::new(None, cx)); + let environment = + cx.new(|cx| ProjectEnvironment::new(None, worktree_store.downgrade(), None, cx)); let manifest_tree = ManifestTree::new(worktree_store.clone(), cx); let toolchain_store = cx.new(|cx| { ToolchainStore::local( @@ -786,7 +787,7 @@ impl HeadlessProject { let environment = this .update(&mut cx, |this, cx| { this.environment.update(cx, |environment, cx| { - environment.get_local_directory_environment(&shell, directory.into(), cx) + environment.local_directory_environment(&shell, directory.into(), cx) }) })? .await