From 1de9e1df6348a7b1b2208c659b66758cc61c0b96 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 26 Feb 2022 09:20:42 -0500 Subject: [PATCH 1/3] Make `if` work like a def-env --- crates/nu-command/src/core_commands/if_.rs | 66 +++++++++++++++++----- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/crates/nu-command/src/core_commands/if_.rs b/crates/nu-command/src/core_commands/if_.rs index 5b0fe0b298e2..3d0a6d14f48b 100644 --- a/crates/nu-command/src/core_commands/if_.rs +++ b/crates/nu-command/src/core_commands/if_.rs @@ -37,50 +37,88 @@ impl Command for If { fn run( &self, engine_state: &EngineState, - stack: &mut Stack, + caller_stack: &mut Stack, call: &Call, input: PipelineData, ) -> Result { let cond = &call.positional[0]; - let then_block: CaptureBlock = call.req(engine_state, stack, 1)?; + let then_block: CaptureBlock = call.req(engine_state, caller_stack, 1)?; let else_case = call.positional.get(2); - let result = eval_expression(engine_state, stack, cond)?; + let result = eval_expression(engine_state, caller_stack, cond)?; match &result { Value::Bool { val, .. } => { if *val { let block = engine_state.get_block(then_block.block_id); - let mut stack = stack.captures_to_stack(&then_block.captures); - eval_block( + let mut callee_stack = caller_stack.captures_to_stack(&then_block.captures); + let result = eval_block( engine_state, - &mut stack, + &mut callee_stack, block, input, call.redirect_stdout, call.redirect_stderr, - ) + ); + let caller_env_vars = caller_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) { + caller_stack.remove_env_var(engine_state, var); + } + } + + // add new env vars from callee to caller + for env_vars in callee_stack.env_vars { + for (var, value) in env_vars { + caller_stack.add_env_var(var, value); + } + } + + result } else if let Some(else_case) = else_case { if let Some(else_expr) = else_case.as_keyword() { if let Some(block_id) = else_expr.as_block() { - let result = eval_expression(engine_state, stack, else_expr)?; + let result = eval_expression(engine_state, caller_stack, else_expr)?; let else_block: CaptureBlock = FromValue::from_value(&result)?; - let mut stack = stack.captures_to_stack(&else_block.captures); + let mut callee_stack = + caller_stack.captures_to_stack(&else_block.captures); let block = engine_state.get_block(block_id); - eval_block( + let result = eval_block( engine_state, - &mut stack, + &mut callee_stack, block, input, call.redirect_stdout, call.redirect_stderr, - ) + ); + + let caller_env_vars = caller_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) { + caller_stack.remove_env_var(engine_state, var); + } + } + + // add new env vars from callee to caller + for env_vars in callee_stack.env_vars { + for (var, value) in env_vars { + caller_stack.add_env_var(var, value); + } + } + + result } else { - eval_expression(engine_state, stack, else_expr) + eval_expression(engine_state, caller_stack, else_expr) .map(|x| x.into_pipeline_data()) } } else { - eval_expression(engine_state, stack, else_case) + eval_expression(engine_state, caller_stack, else_case) .map(|x| x.into_pipeline_data()) } } else { From cd0b954a3caf31a760369a345aa00ba23268d065 Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 8 Mar 2022 07:13:45 -0500 Subject: [PATCH 2/3] Add some tests --- src/tests/test_engine.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/tests/test_engine.rs b/src/tests/test_engine.rs index db9ca46bd87a..5ff72ad43c64 100644 --- a/src/tests/test_engine.rs +++ b/src/tests/test_engine.rs @@ -350,3 +350,16 @@ fn default_value11() -> TestResult { fn default_value12() -> TestResult { fail_test(r#"def foo [--x:int = "a"] { $x }"#, "default value not int") } + +#[test] +fn def_env_if() -> TestResult { + run_test(r#"if true { let-env FOO = "QUX" }; $env.FOO"#, "QUX") +} + +#[test] +fn def_env_if2() -> TestResult { + run_test( + r#"if false { let-env FOO = "QUX" } else { let-env FOO = "QUUX" }; $env.FOO"#, + "QUUX", + ) +} From 8348c32ca856dd2c092f5ca5006650eaa66c2ec1 Mon Sep 17 00:00:00 2001 From: JT Date: Tue, 8 Mar 2022 07:16:46 -0500 Subject: [PATCH 3/3] Add an example --- crates/nu-command/src/core_commands/if_.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/nu-command/src/core_commands/if_.rs b/crates/nu-command/src/core_commands/if_.rs index 3d0a6d14f48b..9eda4ba6aee5 100644 --- a/crates/nu-command/src/core_commands/if_.rs +++ b/crates/nu-command/src/core_commands/if_.rs @@ -150,6 +150,11 @@ impl Command for If { example: "if 5 < 3 { 'yes!' } else if 4 < 5 { 'no!' } else { 'okay!' }", result: Some(Value::test_string("no!")), }, + Example { + description: "Update the environment based on a condition", + example: r#"if true { let-env ENV_VAR = "new value" }"#, + result: None, + }, ] } }