Add blocks as env hooks; Preserve hook environment

This commit is contained in:
Jakub Žádník
2022-07-07 23:39:14 +03:00
parent 79baa4d484
commit 2309601dd4
4 changed files with 49 additions and 9 deletions

View File

@ -21,7 +21,7 @@ pub use menus::{DescriptionMenu, NuHelpCompleter};
pub use nu_highlight::NuHighlight;
pub use print::Print;
pub use prompt::NushellPrompt;
pub use repl::eval_env_change_hooks;
pub use repl::eval_env_change_hook;
pub use repl::evaluate_repl;
pub use syntax_highlight::NuHighlighter;
pub use util::{eval_source, gather_parent_env_vars, get_init_cwd, report_error};

View File

@ -26,7 +26,7 @@ const PRE_EXECUTE_MARKER: &str = "\x1b]133;C\x1b\\";
const CMD_FINISHED_MARKER: &str = "\x1b]133;D\x1b\\";
const RESET_APPLICATION_MODE: &str = "\x1b[?1l";
pub fn eval_env_change_hooks(
pub fn eval_env_change_hook(
env_change_hook: Option<Value>,
engine_state: &mut EngineState,
stack: &mut Stack,
@ -301,7 +301,7 @@ pub fn evaluate_repl(
// Next, check all the environment variables they ask for
// fire the "env_change" hook
if let Err(error) =
eval_env_change_hooks(config.hooks.env_change_str.clone(), engine_state, stack)
eval_env_change_hook(config.hooks.env_change_str.clone(), engine_state, stack)
{
report_error_new(&engine_state, &error)
}
@ -615,8 +615,16 @@ pub fn eval_hook(
let block = engine_state.get_block(block_id);
let input = PipelineData::new(*span);
let mut stack = stack.captures_to_stack(&HashMap::new());
match eval_block(engine_state, &mut stack, block, input, false, false) {
let mut callee_stack = stack.gather_captures(&block.captures);
match eval_block(
engine_state,
&mut callee_stack,
block,
input,
false,
false,
) {
Ok(pipeline_data) => {
match pipeline_data.into_value(*span) {
Value::Bool { val, span } => val,
@ -701,7 +709,7 @@ pub fn eval_hook(
val: block_id,
captures,
span,
} => {}
} => run_hook_block(&engine_state, stack, block_id, arguments, span)?,
other => {
return Err(ShellError::UnsupportedConfigValue(
"block or string".to_string(),
@ -796,6 +804,7 @@ pub fn run_hook_block(
span: Span,
) -> Result<(), ShellError> {
let block = engine_state.get_block(block_id);
let input = PipelineData::new(span);
let mut callee_stack = stack.gather_captures(&block.captures);
@ -811,7 +820,24 @@ pub fn run_hook_block(
match eval_block(engine_state, &mut callee_stack, block, input, false, false) {
Ok(pipeline_data) => match pipeline_data.into_value(span) {
Value::Error { error } => Err(error),
_ => Ok(()),
_ => {
// If all went fine, preserve the environment of the called block
let caller_env_vars = stack.get_env_var_names(engine_state);
// remove env vars that are present in the caller but not in the callee
// (the callee hid them)
for var in caller_env_vars.iter() {
if !callee_stack.has_env_var(engine_state, var) {
stack.remove_env_var(engine_state, var);
}
}
// add new env vars from callee to caller
for (var, value) in callee_stack.get_stack_env_vars() {
stack.add_env_var(var, value);
}
Ok(())
}
},
Err(err) => Err(err),
}

View File

@ -71,3 +71,17 @@ fn env_change_define_alias() {
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}
#[test]
fn env_change_block_preserve_env_var() {
let inp = &[
&hook_env_with_code(r#"{ let-env SPAM = "spam" }"#),
"let-env FOO = 1",
"$env.SPAM",
];
let actual_repl = nu_repl("tests/hooks", inp);
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "spam");
}

View File

@ -1,4 +1,4 @@
use nu_cli::eval_env_change_hooks;
use nu_cli::eval_env_change_hook;
use nu_command::create_default_context;
use nu_engine::eval_block;
use nu_parser::parse;
@ -46,7 +46,7 @@ pub fn nu_repl(cwd: &str, source_lines: &[&str]) -> Outcome {
// Check for env change hook
let config = engine_state.get_config();
if let Err(error) = eval_env_change_hooks(
if let Err(error) = eval_env_change_hook(
config.hooks.env_change_str.clone(),
&mut engine_state,
&mut stack,