mirror of
https://github.com/nushell/nushell.git
synced 2025-08-16 09:08:30 +02:00
Allow NU_LIBS_DIR and friends to be const (#8310)
# Description Allow NU_LIBS_DIR and friends to be const they can be updated within the same parse pass. This will allow us to remove having multiple config files eventually. Small implementation detail: I've changed `call.parser_info` to a hashmap with string keys, so the information can have names rather than indices, and we don't have to worry too much about the order in which we put things into it. Closes https://github.com/nushell/nushell/issues/8422 # User-Facing Changes In a single file, users can now do stuff like ``` const NU_LIBS_DIR = ['/some/path/here'] source script.nu ``` and the source statement will use the value of NU_LIBS_DIR declared the line before. Currently, if there is no `NU_LIBS_DIR` const, then we fallback to using the value of the `NU_LIBS_DIR` env-var, so there are no breaking changes (unless someone named a const NU_LIBS_DIR for some reason).  # Tests + Formatting ~~TODO: write tests~~ Done # After Submitting ~~TODO: update docs~~ Will do when we update default_env.nu/merge default_env.nu into default_config.nu.
This commit is contained in:
@ -39,7 +39,7 @@ pub trait CallExt {
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
pos: usize,
|
||||
name: &str,
|
||||
) -> Result<T, ShellError>;
|
||||
}
|
||||
|
||||
@ -111,9 +111,9 @@ impl CallExt for Call {
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
pos: usize,
|
||||
name: &str,
|
||||
) -> Result<T, ShellError> {
|
||||
if let Some(expr) = self.parser_info_nth(pos) {
|
||||
if let Some(expr) = self.get_parser_info(name) {
|
||||
let result = eval_expression(engine_state, stack, expr)?;
|
||||
FromValue::from_value(&result)
|
||||
} else if self.parser_info.is_empty() {
|
||||
|
@ -1,9 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use nu_protocol::ast::PathMember;
|
||||
use nu_protocol::ast::{Call, Expr, PathMember};
|
||||
use nu_protocol::engine::{EngineState, Stack};
|
||||
use nu_protocol::{PipelineData, ShellError, Span, Value};
|
||||
use nu_protocol::{PipelineData, ShellError, Span, Value, VarId};
|
||||
|
||||
use nu_path::canonicalize_with;
|
||||
|
||||
@ -18,8 +18,6 @@ const ENV_PATH_NAME: &str = "PATH";
|
||||
|
||||
const ENV_CONVERSIONS: &str = "ENV_CONVERSIONS";
|
||||
|
||||
static LIB_DIRS_ENV: &str = "NU_LIB_DIRS";
|
||||
|
||||
enum ConversionResult {
|
||||
Ok(Value),
|
||||
ConversionError(ShellError), // Failure during the conversion itself
|
||||
@ -224,6 +222,17 @@ pub fn path_str(
|
||||
env_to_string(pathname, &pathval, engine_state, stack)
|
||||
}
|
||||
|
||||
pub const DIR_VAR_PARSER_INFO: &str = "dirs_var";
|
||||
pub fn get_dirs_var_from_call(call: &Call) -> Option<VarId> {
|
||||
call.get_parser_info(DIR_VAR_PARSER_INFO).and_then(|x| {
|
||||
if let Expr::Var(id) = x.expr {
|
||||
Some(id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// This helper function is used to find files during eval
|
||||
///
|
||||
/// First, the actual current working directory is selected as
|
||||
@ -239,6 +248,7 @@ pub fn find_in_dirs_env(
|
||||
filename: &str,
|
||||
engine_state: &EngineState,
|
||||
stack: &Stack,
|
||||
dirs_var: Option<VarId>,
|
||||
) -> Result<Option<PathBuf>, ShellError> {
|
||||
// Choose whether to use file-relative or PWD-relative path
|
||||
let cwd = if let Some(pwd) = stack.get_env_var(engine_state, "FILE_PWD") {
|
||||
@ -262,36 +272,32 @@ pub fn find_in_dirs_env(
|
||||
current_dir_str(engine_state, stack)?
|
||||
};
|
||||
|
||||
if let Ok(p) = canonicalize_with(filename, &cwd) {
|
||||
Ok(Some(p))
|
||||
} else {
|
||||
let path = Path::new(filename);
|
||||
|
||||
if path.is_relative() {
|
||||
if let Some(lib_dirs) = stack.get_env_var(engine_state, LIB_DIRS_ENV) {
|
||||
if let Ok(dirs) = lib_dirs.as_list() {
|
||||
for lib_dir in dirs {
|
||||
if let Ok(dir) = lib_dir.as_path() {
|
||||
// make sure the dir is absolute path
|
||||
if let Ok(dir_abs) = canonicalize_with(dir, &cwd) {
|
||||
if let Ok(path) = canonicalize_with(filename, dir_abs) {
|
||||
return Ok(Some(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
Ok((|| -> Option<PathBuf> {
|
||||
if let Ok(p) = canonicalize_with(filename, &cwd) {
|
||||
return Some(p);
|
||||
}
|
||||
}
|
||||
let path = Path::new(filename);
|
||||
if !path.is_relative() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let lib_dirs = dirs_var.and_then(|dirs_var| engine_state.find_constant(dirs_var, &[]));
|
||||
// TODO: remove (see #8310)
|
||||
let lib_dirs_fallback = stack.get_env_var(engine_state, "NU_LIB_DIRS");
|
||||
let lib_dirs = lib_dirs.or(lib_dirs_fallback.as_ref())?;
|
||||
|
||||
lib_dirs
|
||||
.as_list()
|
||||
.ok()?
|
||||
.iter()
|
||||
.map(|lib_dir| -> Option<PathBuf> {
|
||||
let dir = lib_dir.as_path().ok()?;
|
||||
let dir_abs = canonicalize_with(dir, &cwd).ok()?;
|
||||
canonicalize_with(filename, dir_abs).ok()
|
||||
})
|
||||
.find(Option::is_some)
|
||||
.flatten()
|
||||
})())
|
||||
}
|
||||
|
||||
fn get_converted_value(
|
||||
|
@ -828,7 +828,7 @@ pub fn eval_element_with_input(
|
||||
],
|
||||
redirect_stdout: false,
|
||||
redirect_stderr: false,
|
||||
parser_info: vec![],
|
||||
parser_info: HashMap::new(),
|
||||
},
|
||||
input,
|
||||
)
|
||||
@ -899,7 +899,7 @@ pub fn eval_element_with_input(
|
||||
],
|
||||
redirect_stdout: false,
|
||||
redirect_stderr: false,
|
||||
parser_info: vec![],
|
||||
parser_info: HashMap::new(),
|
||||
},
|
||||
input,
|
||||
)
|
||||
|
Reference in New Issue
Block a user