mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 18:41:56 +03:00
Fix nushell local env detection by using direnv export (#13902)
I don't intend fully on getting this merged, this is just an experiment on using `direnv` directly without relying on shell-specific behaviours. It works though, so this finally closes #8633 Release Notes: - Fixed nushell not picking up `direnv` environments by directly interfacing with it using `direnv export` --------- Co-authored-by: Thorsten Ball <mrnugget@gmail.com>
This commit is contained in:
parent
9f5309cedd
commit
8abc000553
@ -546,6 +546,14 @@
|
|||||||
// "delay_ms": 600
|
// "delay_ms": 600
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// Configuration for how direnv configuration should be loaded. May take 2 values:
|
||||||
|
// 1. Load direnv configuration through the shell hook, works for POSIX shells and fish.
|
||||||
|
// "direnv": "shell_hook"
|
||||||
|
// 2. Load direnv configuration using `direnv export json` directly.
|
||||||
|
// This can help with some shells that otherwise would not detect
|
||||||
|
// the direnv environment, such as nushell or elvish.
|
||||||
|
// "direnv": "direct"
|
||||||
|
"direnv": "shell_hook",
|
||||||
"inline_completions": {
|
"inline_completions": {
|
||||||
// A list of globs representing files that inline completions should be disabled for.
|
// A list of globs representing files that inline completions should be disabled for.
|
||||||
"disabled_globs": [".env"]
|
"disabled_globs": [".env"]
|
||||||
|
@ -73,7 +73,7 @@ use paths::{
|
|||||||
};
|
};
|
||||||
use postage::watch;
|
use postage::watch;
|
||||||
use prettier_support::{DefaultPrettier, PrettierInstance};
|
use prettier_support::{DefaultPrettier, PrettierInstance};
|
||||||
use project_settings::{LspSettings, ProjectSettings};
|
use project_settings::{DirenvSettings, LspSettings, ProjectSettings};
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use rpc::{ErrorCode, ErrorExt as _};
|
use rpc::{ErrorCode, ErrorExt as _};
|
||||||
use search::SearchQuery;
|
use search::SearchQuery;
|
||||||
@ -11640,6 +11640,7 @@ pub struct ProjectLspAdapterDelegate {
|
|||||||
http_client: Arc<dyn HttpClient>,
|
http_client: Arc<dyn HttpClient>,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
language_registry: Arc<LanguageRegistry>,
|
||||||
shell_env: Mutex<Option<HashMap<String, String>>>,
|
shell_env: Mutex<Option<HashMap<String, String>>>,
|
||||||
|
load_direnv: DirenvSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProjectLspAdapterDelegate {
|
impl ProjectLspAdapterDelegate {
|
||||||
@ -11648,6 +11649,7 @@ impl ProjectLspAdapterDelegate {
|
|||||||
worktree: &Model<Worktree>,
|
worktree: &Model<Worktree>,
|
||||||
cx: &ModelContext<Project>,
|
cx: &ModelContext<Project>,
|
||||||
) -> Arc<Self> {
|
) -> Arc<Self> {
|
||||||
|
let load_direnv = ProjectSettings::get_global(cx).load_direnv.clone();
|
||||||
Arc::new(Self {
|
Arc::new(Self {
|
||||||
project: cx.weak_model(),
|
project: cx.weak_model(),
|
||||||
worktree: worktree.read(cx).snapshot(),
|
worktree: worktree.read(cx).snapshot(),
|
||||||
@ -11655,12 +11657,13 @@ impl ProjectLspAdapterDelegate {
|
|||||||
http_client: project.client.http_client(),
|
http_client: project.client.http_client(),
|
||||||
language_registry: project.languages.clone(),
|
language_registry: project.languages.clone(),
|
||||||
shell_env: Default::default(),
|
shell_env: Default::default(),
|
||||||
|
load_direnv,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_shell_env(&self) {
|
async fn load_shell_env(&self) {
|
||||||
let worktree_abs_path = self.worktree.abs_path();
|
let worktree_abs_path = self.worktree.abs_path();
|
||||||
let shell_env = load_shell_environment(&worktree_abs_path)
|
let shell_env = load_shell_environment(&worktree_abs_path, &self.load_direnv)
|
||||||
.await
|
.await
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
format!("failed to determine load login shell environment in {worktree_abs_path:?}")
|
format!("failed to determine load login shell environment in {worktree_abs_path:?}")
|
||||||
@ -11874,7 +11877,44 @@ fn include_text(server: &lsp::LanguageServer) -> bool {
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_shell_environment(dir: &Path) -> Result<HashMap<String, String>> {
|
async fn load_direnv_environment(dir: &Path) -> Result<Option<HashMap<String, String>>> {
|
||||||
|
let Ok(direnv_path) = which::which("direnv") else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
let direnv_output = smol::process::Command::new(direnv_path)
|
||||||
|
.args(["export", "json"])
|
||||||
|
.current_dir(dir)
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
.context("failed to spawn direnv to get local environment variables")?;
|
||||||
|
|
||||||
|
anyhow::ensure!(
|
||||||
|
direnv_output.status.success(),
|
||||||
|
"direnv exited with error {:?}",
|
||||||
|
direnv_output.status
|
||||||
|
);
|
||||||
|
|
||||||
|
let output = String::from_utf8_lossy(&direnv_output.stdout);
|
||||||
|
if output.is_empty() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some(
|
||||||
|
serde_json::from_str(&output).context("failed to parse direnv output")?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn load_shell_environment(
|
||||||
|
dir: &Path,
|
||||||
|
load_direnv: &DirenvSettings,
|
||||||
|
) -> Result<HashMap<String, String>> {
|
||||||
|
let direnv_environment = match load_direnv {
|
||||||
|
DirenvSettings::ShellHook => None,
|
||||||
|
DirenvSettings::Direct => load_direnv_environment(dir).await?,
|
||||||
|
}
|
||||||
|
.unwrap_or(HashMap::default());
|
||||||
|
|
||||||
let marker = "ZED_SHELL_START";
|
let marker = "ZED_SHELL_START";
|
||||||
let shell = env::var("SHELL").context(
|
let shell = env::var("SHELL").context(
|
||||||
"SHELL environment variable is not assigned so we can't source login environment variables",
|
"SHELL environment variable is not assigned so we can't source login environment variables",
|
||||||
@ -11885,6 +11925,11 @@ async fn load_shell_environment(dir: &Path) -> Result<HashMap<String, String>> {
|
|||||||
// `cd`'d into it. We do that because tools like direnv, asdf, ...
|
// `cd`'d into it. We do that because tools like direnv, asdf, ...
|
||||||
// hook into `cd` and only set up the env after that.
|
// hook into `cd` and only set up the env after that.
|
||||||
//
|
//
|
||||||
|
// If the user selects `Direct` for direnv, it would set an environment
|
||||||
|
// variable that later uses to know that it should not run the hook.
|
||||||
|
// We would include in `.envs` call so it is okay to run the hook
|
||||||
|
// even if direnv direct mode is enabled.
|
||||||
|
//
|
||||||
// In certain shells we need to execute additional_command in order to
|
// In certain shells we need to execute additional_command in order to
|
||||||
// trigger the behavior of direnv, etc.
|
// trigger the behavior of direnv, etc.
|
||||||
//
|
//
|
||||||
@ -11912,6 +11957,7 @@ async fn load_shell_environment(dir: &Path) -> Result<HashMap<String, String>> {
|
|||||||
|
|
||||||
let output = smol::process::Command::new(&shell)
|
let output = smol::process::Command::new(&shell)
|
||||||
.args(["-i", "-c", &command])
|
.args(["-i", "-c", &command])
|
||||||
|
.envs(direnv_environment)
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.context("failed to spawn login shell to source login environment variables")?;
|
.context("failed to spawn login shell to source login environment variables")?;
|
||||||
|
@ -20,6 +20,23 @@ pub struct ProjectSettings {
|
|||||||
/// Configuration for Git-related features
|
/// Configuration for Git-related features
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub git: GitSettings,
|
pub git: GitSettings,
|
||||||
|
|
||||||
|
/// Configuration for how direnv configuration should be loaded
|
||||||
|
#[serde(default)]
|
||||||
|
pub load_direnv: DirenvSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum DirenvSettings {
|
||||||
|
/// Load direnv configuration through a shell hook
|
||||||
|
#[default]
|
||||||
|
ShellHook,
|
||||||
|
/// Load direnv configuration directly using `direnv export json`
|
||||||
|
///
|
||||||
|
/// Warning: This option is experimental and might cause some inconsistent behaviour compared to using the shell hook.
|
||||||
|
/// If it does, please report it to GitHub
|
||||||
|
Direct,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||||
|
@ -190,6 +190,22 @@ You can also set other OpenType features, like setting `cv01` to `7`:
|
|||||||
The `left_padding` and `right_padding` options define the relative width of the
|
The `left_padding` and `right_padding` options define the relative width of the
|
||||||
left and right padding of the central pane from the workspace when the centered layout mode is activated. Valid values range is from `0` to `0.4`.
|
left and right padding of the central pane from the workspace when the centered layout mode is activated. Valid values range is from `0` to `0.4`.
|
||||||
|
|
||||||
|
## Direnv Integration
|
||||||
|
|
||||||
|
- Description: Settings for [direnv](https://direnv.net/) integration. Requires `direnv` to be installed. `direnv` integration currently only means that the environment variables set by a `direnv` configuration can be used to detect some language servers in `$PATH` instead of installing them.
|
||||||
|
- Setting: `direnv`
|
||||||
|
- Default:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"direnv": "shell_hook"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Options**
|
||||||
|
There are two options to choose from:
|
||||||
|
|
||||||
|
1. `shell_hook`: Use the shell hook to load direnv. This relies on direnv to activate upon entering the directory. Supports POSIX shells and fish.
|
||||||
|
2. `direct`: Use `direnv export json` to load direnv. This will load direnv directly without relying on the shell hook and might cause some inconsistencies. This allows direnv to work with any shell.
|
||||||
|
|
||||||
## Inline Completions
|
## Inline Completions
|
||||||
|
|
||||||
- Description: Settings for inline completions.
|
- Description: Settings for inline completions.
|
||||||
|
Loading…
Reference in New Issue
Block a user