forked from extern/nushell
Allow NU_LIBS_DIR and friends to be const (#8538)
This commit is contained in:
@ -7,13 +7,14 @@ use nu_protocol::{
|
||||
},
|
||||
engine::{StateWorkingSet, DEFAULT_OVERLAY_NAME},
|
||||
span, Alias, BlockId, Exportable, Module, PositionalArg, Span, Spanned, SyntaxShape, Type,
|
||||
VarId,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
static LIB_DIRS_ENV: &str = "NU_LIB_DIRS";
|
||||
pub const LIB_DIRS_VAR: &str = "NU_LIB_DIRS";
|
||||
#[cfg(feature = "plugin")]
|
||||
static PLUGIN_DIRS_ENV: &str = "NU_PLUGIN_DIRS";
|
||||
pub const PLUGIN_DIRS_VAR: &str = "NU_PLUGIN_DIRS";
|
||||
|
||||
use crate::{
|
||||
eval::{eval_constant, value_as_string},
|
||||
@ -916,7 +917,7 @@ pub fn parse_old_alias(
|
||||
decl_id,
|
||||
redirect_stdout: true,
|
||||
redirect_stderr: false,
|
||||
parser_info: vec![],
|
||||
parser_info: HashMap::new(),
|
||||
}));
|
||||
return (
|
||||
Pipeline::from_vec(vec![Expression {
|
||||
@ -1217,7 +1218,7 @@ pub fn parse_export_in_module(
|
||||
arguments: vec![],
|
||||
redirect_stdout: true,
|
||||
redirect_stderr: false,
|
||||
parser_info: vec![],
|
||||
parser_info: HashMap::new(),
|
||||
});
|
||||
|
||||
let exportables = if let Some(kw_span) = spans.get(1) {
|
||||
@ -2041,7 +2042,7 @@ pub fn parse_module(
|
||||
],
|
||||
redirect_stdout: true,
|
||||
redirect_stderr: false,
|
||||
parser_info: vec![],
|
||||
parser_info: HashMap::new(),
|
||||
});
|
||||
|
||||
(
|
||||
@ -2184,7 +2185,7 @@ pub fn parse_use(
|
||||
|
||||
if err.is_none() {
|
||||
if let Some(module_path) =
|
||||
find_in_dirs(&module_filename, working_set, &cwd, LIB_DIRS_ENV)
|
||||
find_in_dirs(&module_filename, working_set, &cwd, LIB_DIRS_VAR)
|
||||
{
|
||||
if let Some(i) = working_set
|
||||
.parsed_module_files
|
||||
@ -2398,7 +2399,7 @@ pub fn parse_use(
|
||||
};
|
||||
|
||||
let mut call = call;
|
||||
call.add_parser_info(import_pattern_expr);
|
||||
call.set_parser_info("import_pattern".to_string(), import_pattern_expr);
|
||||
|
||||
(
|
||||
Pipeline::from_vec(vec![Expression {
|
||||
@ -2619,7 +2620,7 @@ pub fn parse_hide(
|
||||
};
|
||||
|
||||
let mut call = call;
|
||||
call.add_parser_info(import_pattern_expr);
|
||||
call.set_parser_info("import_pattern".to_string(), import_pattern_expr);
|
||||
|
||||
(
|
||||
Pipeline::from_vec(vec![Expression {
|
||||
@ -2844,7 +2845,7 @@ pub fn parse_overlay_use(
|
||||
String::from_utf8(trim_quotes(overlay_name.as_bytes()).to_vec())
|
||||
{
|
||||
if let Some(module_path) =
|
||||
find_in_dirs(&module_filename, working_set, &cwd, LIB_DIRS_ENV)
|
||||
find_in_dirs(&module_filename, working_set, &cwd, LIB_DIRS_VAR)
|
||||
{
|
||||
let overlay_name = if let Some(stem) = module_path.file_stem() {
|
||||
stem.to_string_lossy().to_string()
|
||||
@ -2936,16 +2937,19 @@ pub fn parse_overlay_use(
|
||||
|
||||
// Change the call argument to include the Overlay expression with the module ID
|
||||
let mut call = call;
|
||||
call.add_parser_info(Expression {
|
||||
expr: Expr::Overlay(if is_module_updated {
|
||||
Some(origin_module_id)
|
||||
} else {
|
||||
None
|
||||
}),
|
||||
span: overlay_name_span,
|
||||
ty: Type::Any,
|
||||
custom_completion: None,
|
||||
});
|
||||
call.set_parser_info(
|
||||
"overlay_expr".to_string(),
|
||||
Expression {
|
||||
expr: Expr::Overlay(if is_module_updated {
|
||||
Some(origin_module_id)
|
||||
} else {
|
||||
None
|
||||
}),
|
||||
span: overlay_name_span,
|
||||
ty: Type::Any,
|
||||
custom_completion: None,
|
||||
},
|
||||
);
|
||||
|
||||
let pipeline = Pipeline::from_vec(vec![Expression {
|
||||
expr: Expr::Call(call),
|
||||
@ -3117,7 +3121,7 @@ pub fn parse_let_or_const(
|
||||
],
|
||||
redirect_stdout: true,
|
||||
redirect_stderr: false,
|
||||
parser_info: vec![],
|
||||
parser_info: HashMap::new(),
|
||||
});
|
||||
|
||||
return (
|
||||
@ -3242,7 +3246,7 @@ pub fn parse_mut(
|
||||
],
|
||||
redirect_stdout: true,
|
||||
redirect_stderr: false,
|
||||
parser_info: vec![],
|
||||
parser_info: HashMap::new(),
|
||||
});
|
||||
|
||||
return (
|
||||
@ -3371,7 +3375,7 @@ pub fn parse_source(
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(path) = find_in_dirs(&filename, working_set, &cwd, LIB_DIRS_ENV) {
|
||||
if let Some(path) = find_in_dirs(&filename, working_set, &cwd, LIB_DIRS_VAR) {
|
||||
if let Ok(contents) = std::fs::read(&path) {
|
||||
// Change currently parsed directory
|
||||
let prev_currently_parsed_cwd = if let Some(parent) = path.parent() {
|
||||
@ -3417,12 +3421,15 @@ pub fn parse_source(
|
||||
|
||||
// FIXME: Adding this expression to the positional creates a syntax highlighting error
|
||||
// after writing `source example.nu`
|
||||
call_with_block.add_parser_info(Expression {
|
||||
expr: Expr::Int(block_id as i64),
|
||||
span: spans[1],
|
||||
ty: Type::Any,
|
||||
custom_completion: None,
|
||||
});
|
||||
call_with_block.set_parser_info(
|
||||
"block_id".to_string(),
|
||||
Expression {
|
||||
expr: Expr::Int(block_id as i64),
|
||||
span: spans[1],
|
||||
ty: Type::Any,
|
||||
custom_completion: None,
|
||||
},
|
||||
);
|
||||
|
||||
return (
|
||||
Pipeline::from_vec(vec![Expression {
|
||||
@ -3632,7 +3639,7 @@ pub fn parse_register(
|
||||
if let Some(err) = err {
|
||||
Err(err)
|
||||
} else {
|
||||
let path = if let Some(p) = find_in_dirs(&name, working_set, &cwd, PLUGIN_DIRS_ENV)
|
||||
let path = if let Some(p) = find_in_dirs(&name, working_set, &cwd, PLUGIN_DIRS_VAR)
|
||||
{
|
||||
p
|
||||
} else {
|
||||
@ -3779,14 +3786,22 @@ pub fn parse_register(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn find_dirs_var(working_set: &StateWorkingSet, var_name: &str) -> Option<VarId> {
|
||||
working_set
|
||||
.find_variable(format!("${}", var_name).as_bytes())
|
||||
.filter(|var_id| working_set.find_constant(*var_id).is_some())
|
||||
}
|
||||
|
||||
/// This helper function is used to find files during parsing
|
||||
///
|
||||
/// First, the actual current working directory is selected as
|
||||
/// a) the directory of a file currently being parsed
|
||||
/// b) current working directory (PWD)
|
||||
///
|
||||
/// Then, if the file is not found in the actual cwd, NU_LIB_DIRS is checked.
|
||||
/// If there is a relative path in NU_LIB_DIRS, it is assumed to be relative to the actual cwd
|
||||
/// Then, if the file is not found in the actual cwd, dirs_var is checked.
|
||||
/// For now, we first check for a const with the name of `dirs_var_name`,
|
||||
/// and if that's not found, then we try to look for an environment variable of the same name.
|
||||
/// If there is a relative path in dirs_var, it is assumed to be relative to the actual cwd
|
||||
/// determined in the first step.
|
||||
///
|
||||
/// Always returns an absolute path
|
||||
@ -3794,43 +3809,89 @@ pub fn find_in_dirs(
|
||||
filename: &str,
|
||||
working_set: &StateWorkingSet,
|
||||
cwd: &str,
|
||||
dirs_env: &str,
|
||||
dirs_var_name: &str,
|
||||
) -> Option<PathBuf> {
|
||||
// Choose whether to use file-relative or PWD-relative path
|
||||
let actual_cwd = if let Some(currently_parsed_cwd) = &working_set.currently_parsed_cwd {
|
||||
currently_parsed_cwd.as_path()
|
||||
} else {
|
||||
Path::new(cwd)
|
||||
};
|
||||
pub fn find_in_dirs_with_id(
|
||||
filename: &str,
|
||||
working_set: &StateWorkingSet,
|
||||
cwd: &str,
|
||||
dirs_var_name: &str,
|
||||
) -> Option<PathBuf> {
|
||||
// Choose whether to use file-relative or PWD-relative path
|
||||
let actual_cwd = if let Some(currently_parsed_cwd) = &working_set.currently_parsed_cwd {
|
||||
currently_parsed_cwd.as_path()
|
||||
} else {
|
||||
Path::new(cwd)
|
||||
};
|
||||
if let Ok(p) = canonicalize_with(filename, actual_cwd) {
|
||||
return Some(p);
|
||||
}
|
||||
|
||||
if let Ok(p) = canonicalize_with(filename, actual_cwd) {
|
||||
Some(p)
|
||||
} else {
|
||||
let path = Path::new(filename);
|
||||
if !path.is_relative() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if path.is_relative() {
|
||||
if let Some(lib_dirs) = working_set.get_env_var(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, actual_cwd) {
|
||||
if let Ok(path) = canonicalize_with(filename, dir_abs) {
|
||||
return Some(path);
|
||||
working_set
|
||||
.find_constant(find_dirs_var(working_set, dirs_var_name)?)?
|
||||
.as_list()
|
||||
.ok()?
|
||||
.iter()
|
||||
.map(|lib_dir| -> Option<PathBuf> {
|
||||
let dir = lib_dir.as_path().ok()?;
|
||||
let dir_abs = canonicalize_with(dir, actual_cwd).ok()?;
|
||||
canonicalize_with(filename, dir_abs).ok()
|
||||
})
|
||||
.find(Option::is_some)
|
||||
.flatten()
|
||||
}
|
||||
|
||||
// TODO: remove (see #8310)
|
||||
pub fn find_in_dirs_old(
|
||||
filename: &str,
|
||||
working_set: &StateWorkingSet,
|
||||
cwd: &str,
|
||||
dirs_env: &str,
|
||||
) -> Option<PathBuf> {
|
||||
// Choose whether to use file-relative or PWD-relative path
|
||||
let actual_cwd = if let Some(currently_parsed_cwd) = &working_set.currently_parsed_cwd {
|
||||
currently_parsed_cwd.as_path()
|
||||
} else {
|
||||
Path::new(cwd)
|
||||
};
|
||||
|
||||
if let Ok(p) = canonicalize_with(filename, actual_cwd) {
|
||||
Some(p)
|
||||
} else {
|
||||
let path = Path::new(filename);
|
||||
|
||||
if path.is_relative() {
|
||||
if let Some(lib_dirs) = working_set.get_env_var(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, actual_cwd) {
|
||||
if let Ok(path) = canonicalize_with(filename, dir_abs) {
|
||||
return Some(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
None
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
find_in_dirs_with_id(filename, working_set, cwd, dirs_var_name)
|
||||
.or_else(|| find_in_dirs_old(filename, working_set, cwd, dirs_var_name))
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use crate::{
|
||||
ParseError, Token, TokenContents,
|
||||
};
|
||||
|
||||
use nu_engine::DIR_VAR_PARSER_INFO;
|
||||
use nu_protocol::{
|
||||
ast::{
|
||||
Argument, Assignment, Bits, Block, Boolean, Call, CellPath, Comparison, Expr, Expression,
|
||||
@ -20,10 +21,10 @@ use nu_protocol::{
|
||||
};
|
||||
|
||||
use crate::parse_keywords::{
|
||||
is_unaliasable_parser_keyword, parse_alias, parse_def, parse_def_predecl,
|
||||
find_dirs_var, is_unaliasable_parser_keyword, parse_alias, parse_def, parse_def_predecl,
|
||||
parse_export_in_block, parse_extern, parse_for, parse_hide, parse_keyword, parse_let_or_const,
|
||||
parse_module, parse_old_alias, parse_overlay_hide, parse_overlay_new, parse_overlay_use,
|
||||
parse_source, parse_use, parse_where, parse_where_expr,
|
||||
parse_source, parse_use, parse_where, parse_where_expr, LIB_DIRS_VAR,
|
||||
};
|
||||
|
||||
use itertools::Itertools;
|
||||
@ -809,6 +810,25 @@ pub struct ParsedInternalCall {
|
||||
pub error: Option<ParseError>,
|
||||
}
|
||||
|
||||
fn attach_parser_info_builtin(working_set: &StateWorkingSet, name: &str, call: &mut Call) {
|
||||
match name {
|
||||
"use" | "overlay use" | "source-env" | "nu-check" => {
|
||||
if let Some(var_id) = find_dirs_var(working_set, LIB_DIRS_VAR) {
|
||||
call.set_parser_info(
|
||||
DIR_VAR_PARSER_INFO.to_owned(),
|
||||
Expression {
|
||||
expr: Expr::Var(var_id),
|
||||
span: call.head,
|
||||
ty: Type::Any,
|
||||
custom_completion: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_internal_call(
|
||||
working_set: &mut StateWorkingSet,
|
||||
command_span: Span,
|
||||
@ -828,6 +848,10 @@ pub fn parse_internal_call(
|
||||
let signature = decl.signature();
|
||||
let output = signature.output_type.clone();
|
||||
|
||||
if decl.is_builtin() {
|
||||
attach_parser_info_builtin(working_set, decl.name(), &mut call);
|
||||
}
|
||||
|
||||
// The index into the positional parameter in the definition
|
||||
let mut positional_idx = 0;
|
||||
|
||||
@ -5686,7 +5710,7 @@ pub fn parse_expression(
|
||||
arguments,
|
||||
redirect_stdout: true,
|
||||
redirect_stderr: false,
|
||||
parser_info: vec![],
|
||||
parser_info: HashMap::new(),
|
||||
}));
|
||||
|
||||
(
|
||||
@ -6577,7 +6601,7 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression)
|
||||
decl_id,
|
||||
redirect_stdout: true,
|
||||
redirect_stderr: false,
|
||||
parser_info: vec![],
|
||||
parser_info: HashMap::new(),
|
||||
})),
|
||||
span,
|
||||
ty: Type::String,
|
||||
|
Reference in New Issue
Block a user