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
This commit is contained in:
@@ -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<Result<Entity<Terminal>>> {
|
||||
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(),
|
||||
};
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -60,8 +60,10 @@ async fn lsp_task_context(
|
||||
buffer: &Entity<Buffer>,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Option<TaskContext> {
|
||||
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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<Path> = 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,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -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<Path>), Shared<Task<Option<HashMap<String, String>>>>>,
|
||||
environment_error_messages: VecDeque<String>,
|
||||
environment_error_messages_tx: mpsc::UnboundedSender<String>,
|
||||
worktree_store: WeakEntity<WorktreeStore>,
|
||||
remote_client: Option<WeakEntity<RemoteClient>>,
|
||||
_tasks: Vec<Task<()>>,
|
||||
}
|
||||
|
||||
@@ -33,7 +36,12 @@ pub enum ProjectEnvironmentEvent {
|
||||
impl EventEmitter<ProjectEnvironmentEvent> for ProjectEnvironment {}
|
||||
|
||||
impl ProjectEnvironment {
|
||||
pub fn new(cli_environment: Option<HashMap<String, String>>, cx: &mut Context<Self>) -> Self {
|
||||
pub fn new(
|
||||
cli_environment: Option<HashMap<String, String>>,
|
||||
worktree_store: WeakEntity<WorktreeStore>,
|
||||
remote_client: Option<WeakEntity<RemoteClient>>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> 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<HashMap<String, String>> {
|
||||
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<Buffer>,
|
||||
worktree_store: &Entity<WorktreeStore>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Shared<Task<Option<HashMap<String, String>>>> {
|
||||
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<Worktree>,
|
||||
cx: &mut Context<Self>,
|
||||
cx: &mut App,
|
||||
) -> Shared<Task<Option<HashMap<String, String>>>> {
|
||||
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<Path>,
|
||||
cx: &mut App,
|
||||
) -> Shared<Task<Option<HashMap<String, String>>>> {
|
||||
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<Path>,
|
||||
cx: &mut Context<Self>,
|
||||
cx: &mut App,
|
||||
) -> Shared<Task<Option<HashMap<String, String>>>> {
|
||||
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<Path>,
|
||||
remote_client: Entity<RemoteClient>,
|
||||
cx: &mut Context<Self>,
|
||||
cx: &mut App,
|
||||
) -> Shared<Task<Option<HashMap<String, String>>>> {
|
||||
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())
|
||||
})
|
||||
|
||||
@@ -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(|| {
|
||||
|
||||
@@ -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<Task<Option<HashMap<String, String>>>> {
|
||||
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<LspStore>,
|
||||
) -> 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<dyn Fs>,
|
||||
cx: &mut App,
|
||||
) -> Arc<Self> {
|
||||
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,
|
||||
|
||||
@@ -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<Buffer>,
|
||||
worktree_store: &Entity<WorktreeStore>,
|
||||
cx: &'a mut App,
|
||||
) -> Shared<Task<Option<HashMap<String, String>>>> {
|
||||
self.environment.update(cx, |environment, cx| {
|
||||
environment.get_buffer_environment(buffer, worktree_store, cx)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn directory_environment(
|
||||
&self,
|
||||
shell: &Shell,
|
||||
abs_path: Arc<Path>,
|
||||
cx: &mut App,
|
||||
) -> Shared<Task<Option<HashMap<String, String>>>> {
|
||||
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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user