Allow task context providers to access project env (#17964)
Closes #13106 Release Notes: - Task context providers now have access to the local shell environment, allowing local rust tool installations to work Before: <img width="1136" alt="Screenshot 2024-09-17 at 22 09 38" src="https://github.com/user-attachments/assets/7d6c5606-4820-4f6f-92d1-c3d314b9ab42"> After: <img width="1136" alt="Screenshot 2024-09-17 at 22 09 58" src="https://github.com/user-attachments/assets/a962e607-15f5-44ce-b53e-a0dbe135f2d8">
This commit is contained in:
parent
d3d3a093b4
commit
8a6c65c63b
6 changed files with 50 additions and 25 deletions
|
@ -25,6 +25,7 @@ pub trait ContextProvider: Send + Sync {
|
||||||
&self,
|
&self,
|
||||||
_variables: &TaskVariables,
|
_variables: &TaskVariables,
|
||||||
_location: &Location,
|
_location: &Location,
|
||||||
|
_project_env: Option<&HashMap<String, String>>,
|
||||||
_cx: &mut AppContext,
|
_cx: &mut AppContext,
|
||||||
) -> Result<TaskVariables> {
|
) -> Result<TaskVariables> {
|
||||||
Ok(TaskVariables::default())
|
Ok(TaskVariables::default())
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use collections::HashMap;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::{AppContext, AsyncAppContext, Task};
|
use gpui::{AppContext, AsyncAppContext, Task};
|
||||||
use http_client::github::latest_github_release;
|
use http_client::github::latest_github_release;
|
||||||
|
@ -454,6 +455,7 @@ impl ContextProvider for GoContextProvider {
|
||||||
&self,
|
&self,
|
||||||
variables: &TaskVariables,
|
variables: &TaskVariables,
|
||||||
location: &Location,
|
location: &Location,
|
||||||
|
_: Option<&HashMap<String, String>>,
|
||||||
cx: &mut gpui::AppContext,
|
cx: &mut gpui::AppContext,
|
||||||
) -> Result<TaskVariables> {
|
) -> Result<TaskVariables> {
|
||||||
let local_abs_path = location
|
let local_abs_path = location
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use collections::HashMap;
|
||||||
use gpui::AppContext;
|
use gpui::AppContext;
|
||||||
use gpui::AsyncAppContext;
|
use gpui::AsyncAppContext;
|
||||||
use language::{ContextProvider, LanguageServerName, LspAdapter, LspAdapterDelegate};
|
use language::{ContextProvider, LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||||
|
@ -215,6 +216,7 @@ impl ContextProvider for PythonContextProvider {
|
||||||
&self,
|
&self,
|
||||||
variables: &task::TaskVariables,
|
variables: &task::TaskVariables,
|
||||||
_location: &project::Location,
|
_location: &project::Location,
|
||||||
|
_: Option<&HashMap<String, String>>,
|
||||||
_cx: &mut gpui::AppContext,
|
_cx: &mut gpui::AppContext,
|
||||||
) -> Result<task::TaskVariables> {
|
) -> Result<task::TaskVariables> {
|
||||||
let python_module_name = python_module_name_from_relative_path(
|
let python_module_name = python_module_name_from_relative_path(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use async_compression::futures::bufread::GzipDecoder;
|
use async_compression::futures::bufread::GzipDecoder;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use collections::HashMap;
|
||||||
use futures::{io::BufReader, StreamExt};
|
use futures::{io::BufReader, StreamExt};
|
||||||
use gpui::{AppContext, AsyncAppContext};
|
use gpui::{AppContext, AsyncAppContext};
|
||||||
use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
|
use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
|
||||||
|
@ -434,6 +435,7 @@ impl ContextProvider for RustContextProvider {
|
||||||
&self,
|
&self,
|
||||||
task_variables: &TaskVariables,
|
task_variables: &TaskVariables,
|
||||||
location: &Location,
|
location: &Location,
|
||||||
|
project_env: Option<&HashMap<String, String>>,
|
||||||
cx: &mut gpui::AppContext,
|
cx: &mut gpui::AppContext,
|
||||||
) -> Result<TaskVariables> {
|
) -> Result<TaskVariables> {
|
||||||
let local_abs_path = location
|
let local_abs_path = location
|
||||||
|
@ -449,8 +451,8 @@ impl ContextProvider for RustContextProvider {
|
||||||
.is_some();
|
.is_some();
|
||||||
|
|
||||||
if is_main_function {
|
if is_main_function {
|
||||||
if let Some((package_name, bin_name)) =
|
if let Some((package_name, bin_name)) = local_abs_path
|
||||||
local_abs_path.and_then(package_name_and_bin_name_from_abs_path)
|
.and_then(|path| package_name_and_bin_name_from_abs_path(path, project_env))
|
||||||
{
|
{
|
||||||
return Ok(TaskVariables::from_iter([
|
return Ok(TaskVariables::from_iter([
|
||||||
(RUST_PACKAGE_TASK_VARIABLE.clone(), package_name),
|
(RUST_PACKAGE_TASK_VARIABLE.clone(), package_name),
|
||||||
|
@ -461,7 +463,7 @@ impl ContextProvider for RustContextProvider {
|
||||||
|
|
||||||
if let Some(package_name) = local_abs_path
|
if let Some(package_name) = local_abs_path
|
||||||
.and_then(|local_abs_path| local_abs_path.parent())
|
.and_then(|local_abs_path| local_abs_path.parent())
|
||||||
.and_then(human_readable_package_name)
|
.and_then(|path| human_readable_package_name(path, project_env))
|
||||||
{
|
{
|
||||||
return Ok(TaskVariables::from_iter([(
|
return Ok(TaskVariables::from_iter([(
|
||||||
RUST_PACKAGE_TASK_VARIABLE.clone(),
|
RUST_PACKAGE_TASK_VARIABLE.clone(),
|
||||||
|
@ -615,8 +617,15 @@ struct CargoTarget {
|
||||||
src_path: String,
|
src_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn package_name_and_bin_name_from_abs_path(abs_path: &Path) -> Option<(String, String)> {
|
fn package_name_and_bin_name_from_abs_path(
|
||||||
let output = std::process::Command::new("cargo")
|
abs_path: &Path,
|
||||||
|
project_env: Option<&HashMap<String, String>>,
|
||||||
|
) -> Option<(String, String)> {
|
||||||
|
let mut command = std::process::Command::new("cargo");
|
||||||
|
if let Some(envs) = project_env {
|
||||||
|
command.envs(envs);
|
||||||
|
}
|
||||||
|
let output = command
|
||||||
.current_dir(abs_path.parent()?)
|
.current_dir(abs_path.parent()?)
|
||||||
.arg("metadata")
|
.arg("metadata")
|
||||||
.arg("--no-deps")
|
.arg("--no-deps")
|
||||||
|
@ -654,9 +663,17 @@ fn retrieve_package_id_and_bin_name_from_metadata(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn human_readable_package_name(package_directory: &Path) -> Option<String> {
|
fn human_readable_package_name(
|
||||||
|
package_directory: &Path,
|
||||||
|
project_env: Option<&HashMap<String, String>>,
|
||||||
|
) -> Option<String> {
|
||||||
|
let mut command = std::process::Command::new("cargo");
|
||||||
|
if let Some(envs) = project_env {
|
||||||
|
command.envs(envs);
|
||||||
|
}
|
||||||
|
|
||||||
let pkgid = String::from_utf8(
|
let pkgid = String::from_utf8(
|
||||||
std::process::Command::new("cargo")
|
command
|
||||||
.current_dir(package_directory)
|
.current_dir(package_directory)
|
||||||
.arg("pkgid")
|
.arg("pkgid")
|
||||||
.output()
|
.output()
|
||||||
|
|
|
@ -4890,21 +4890,6 @@ impl Project {
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.spawn(|project, mut cx| async move {
|
cx.spawn(|project, mut cx| async move {
|
||||||
let mut task_variables = cx
|
|
||||||
.update(|cx| {
|
|
||||||
combine_task_variables(
|
|
||||||
captured_variables,
|
|
||||||
location,
|
|
||||||
BasicContextProvider::new(project.upgrade()?),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
.log_err()
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
.flatten()?;
|
|
||||||
// Remove all custom entries starting with _, as they're not intended for use by the end user.
|
|
||||||
task_variables.sweep();
|
|
||||||
|
|
||||||
let project_env = project
|
let project_env = project
|
||||||
.update(&mut cx, |project, cx| {
|
.update(&mut cx, |project, cx| {
|
||||||
let worktree_abs_path = worktree_abs_path.clone();
|
let worktree_abs_path = worktree_abs_path.clone();
|
||||||
|
@ -4915,6 +4900,22 @@ impl Project {
|
||||||
.ok()?
|
.ok()?
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
let mut task_variables = cx
|
||||||
|
.update(|cx| {
|
||||||
|
combine_task_variables(
|
||||||
|
captured_variables,
|
||||||
|
location,
|
||||||
|
project_env.as_ref(),
|
||||||
|
BasicContextProvider::new(project.upgrade()?),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.log_err()
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
.flatten()?;
|
||||||
|
// Remove all custom entries starting with _, as they're not intended for use by the end user.
|
||||||
|
task_variables.sweep();
|
||||||
|
|
||||||
Some(TaskContext {
|
Some(TaskContext {
|
||||||
project_env: project_env.unwrap_or_default(),
|
project_env: project_env.unwrap_or_default(),
|
||||||
cwd: worktree_abs_path.map(|p| p.to_path_buf()),
|
cwd: worktree_abs_path.map(|p| p.to_path_buf()),
|
||||||
|
@ -5111,6 +5112,7 @@ impl Project {
|
||||||
fn combine_task_variables(
|
fn combine_task_variables(
|
||||||
mut captured_variables: TaskVariables,
|
mut captured_variables: TaskVariables,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
project_env: Option<&HashMap<String, String>>,
|
||||||
baseline: BasicContextProvider,
|
baseline: BasicContextProvider,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> anyhow::Result<TaskVariables> {
|
) -> anyhow::Result<TaskVariables> {
|
||||||
|
@ -5120,13 +5122,13 @@ fn combine_task_variables(
|
||||||
.language()
|
.language()
|
||||||
.and_then(|language| language.context_provider());
|
.and_then(|language| language.context_provider());
|
||||||
let baseline = baseline
|
let baseline = baseline
|
||||||
.build_context(&captured_variables, &location, cx)
|
.build_context(&captured_variables, &location, project_env, cx)
|
||||||
.context("building basic default context")?;
|
.context("building basic default context")?;
|
||||||
captured_variables.extend(baseline);
|
captured_variables.extend(baseline);
|
||||||
if let Some(provider) = language_context_provider {
|
if let Some(provider) = language_context_provider {
|
||||||
captured_variables.extend(
|
captured_variables.extend(
|
||||||
provider
|
provider
|
||||||
.build_context(&captured_variables, &location, cx)
|
.build_context(&captured_variables, &location, project_env, cx)
|
||||||
.context("building provider context")?,
|
.context("building provider context")?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use collections::{btree_map, BTreeMap, VecDeque};
|
use collections::{btree_map, BTreeMap, HashMap, VecDeque};
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::mpsc::{unbounded, UnboundedSender},
|
channel::mpsc::{unbounded, UnboundedSender},
|
||||||
StreamExt,
|
StreamExt,
|
||||||
|
@ -543,6 +543,7 @@ impl ContextProvider for BasicContextProvider {
|
||||||
&self,
|
&self,
|
||||||
_: &TaskVariables,
|
_: &TaskVariables,
|
||||||
location: &Location,
|
location: &Location,
|
||||||
|
_: Option<&HashMap<String, String>>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Result<TaskVariables> {
|
) -> Result<TaskVariables> {
|
||||||
let buffer = location.buffer.read(cx);
|
let buffer = location.buffer.read(cx);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue