From 403bf1a7343a1fde29ad2bda0bb424ab9bb4035a Mon Sep 17 00:00:00 2001 From: mike <98623181+1Kinoti@users.noreply.github.com> Date: Thu, 23 Mar 2023 22:49:52 +0300 Subject: [PATCH] unify the `run` functions of `all` and `any` (#8578) # Description this pr reduces duplication by making `any` and `all` commands use [one function](https://github.com/nushell/nushell/blob/66ad83c15ce0289a9901b5f618e9ea95ea763974/crates/nu-command/src/filters/any.rs#LL63-L65C28) --- crates/nu-command/src/filters/all.rs | 58 +++------------------ crates/nu-command/src/filters/any.rs | 58 +++------------------ crates/nu-command/src/filters/utils.rs | 70 +++++++++++++++++++++++++- 3 files changed, 81 insertions(+), 105 deletions(-) diff --git a/crates/nu-command/src/filters/all.rs b/crates/nu-command/src/filters/all.rs index 2651ac1b6..990a30f0b 100644 --- a/crates/nu-command/src/filters/all.rs +++ b/crates/nu-command/src/filters/all.rs @@ -1,11 +1,11 @@ -use nu_engine::{eval_block, CallExt}; use nu_protocol::{ ast::Call, - engine::{Closure, Command, EngineState, Stack}, - Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Type, - Value, + engine::{Command, EngineState, Stack}, + Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value, }; +use super::utils; + #[derive(Clone)] pub struct All; @@ -60,9 +60,7 @@ impl Command for All { }, ] } - // This is almost entirely a copy-paste of `any`'s run(), so make sure any changes to this are - // reflected in the other!! (Or, you could figure out a way for both of them to use - // the same function...) + fn run( &self, engine_state: &EngineState, @@ -70,51 +68,7 @@ impl Command for All { call: &Call, input: PipelineData, ) -> Result { - let span = call.head; - - let capture_block: Closure = call.req(engine_state, stack, 0)?; - let block_id = capture_block.block_id; - - let block = engine_state.get_block(block_id); - let var_id = block.signature.get_positional(0).and_then(|arg| arg.var_id); - let mut stack = stack.captures_to_stack(&capture_block.captures); - - let orig_env_vars = stack.env_vars.clone(); - let orig_env_hidden = stack.env_hidden.clone(); - - let ctrlc = engine_state.ctrlc.clone(); - let engine_state = engine_state.clone(); - - for value in input.into_interruptible_iter(ctrlc) { - // with_env() is used here to ensure that each iteration uses - // a different set of environment variables. - // Hence, a 'cd' in the first loop won't affect the next loop. - stack.with_env(&orig_env_vars, &orig_env_hidden); - - if let Some(var_id) = var_id { - stack.add_var(var_id, value.clone()); - } - - let eval = eval_block( - &engine_state, - &mut stack, - block, - value.into_pipeline_data(), - call.redirect_stdout, - call.redirect_stderr, - ); - match eval { - Err(e) => { - return Err(e); - } - Ok(pipeline_data) => { - if !pipeline_data.into_value(span).is_true() { - return Ok(Value::Bool { val: false, span }.into_pipeline_data()); - } - } - } - } - Ok(Value::Bool { val: true, span }.into_pipeline_data()) + utils::boolean_fold(engine_state, stack, call, input, false) } } diff --git a/crates/nu-command/src/filters/any.rs b/crates/nu-command/src/filters/any.rs index 5651a925f..d6fd38244 100644 --- a/crates/nu-command/src/filters/any.rs +++ b/crates/nu-command/src/filters/any.rs @@ -1,11 +1,11 @@ -use nu_engine::{eval_block, CallExt}; use nu_protocol::{ ast::Call, - engine::{Closure, Command, EngineState, Stack}, - Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Type, - Value, + engine::{Command, EngineState, Stack}, + Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value, }; +use super::utils; + #[derive(Clone)] pub struct Any; @@ -60,9 +60,7 @@ impl Command for Any { }, ] } - // This is almost entirely a copy-paste of `all`'s run(), so make sure any changes to this are - // reflected in the other!! Or, you could figure out a way for both of them to use - // the same function... + fn run( &self, engine_state: &EngineState, @@ -70,51 +68,7 @@ impl Command for Any { call: &Call, input: PipelineData, ) -> Result { - let span = call.head; - - let capture_block: Closure = call.req(engine_state, stack, 0)?; - let block_id = capture_block.block_id; - - let block = engine_state.get_block(block_id); - let var_id = block.signature.get_positional(0).and_then(|arg| arg.var_id); - let mut stack = stack.captures_to_stack(&capture_block.captures); - - let orig_env_vars = stack.env_vars.clone(); - let orig_env_hidden = stack.env_hidden.clone(); - - let ctrlc = engine_state.ctrlc.clone(); - let engine_state = engine_state.clone(); - - for value in input.into_interruptible_iter(ctrlc) { - // with_env() is used here to ensure that each iteration uses - // a different set of environment variables. - // Hence, a 'cd' in the first loop won't affect the next loop. - stack.with_env(&orig_env_vars, &orig_env_hidden); - - if let Some(var_id) = var_id { - stack.add_var(var_id, value.clone()); - } - - let eval = eval_block( - &engine_state, - &mut stack, - block, - value.into_pipeline_data(), - call.redirect_stdout, - call.redirect_stderr, - ); - match eval { - Err(e) => { - return Err(e); - } - Ok(pipeline_data) => { - if pipeline_data.into_value(span).is_true() { - return Ok(Value::Bool { val: true, span }.into_pipeline_data()); - } - } - } - } - Ok(Value::Bool { val: false, span }.into_pipeline_data()) + utils::boolean_fold(engine_state, stack, call, input, true) } } diff --git a/crates/nu-command/src/filters/utils.rs b/crates/nu-command/src/filters/utils.rs index 9729b5035..1853f6d0e 100644 --- a/crates/nu-command/src/filters/utils.rs +++ b/crates/nu-command/src/filters/utils.rs @@ -1,4 +1,9 @@ -use nu_protocol::{ShellError, Span}; +use nu_engine::{eval_block, CallExt}; +use nu_protocol::{ + ast::Call, + engine::{Closure, EngineState, Stack}, + IntoPipelineData, PipelineData, ShellError, Span, Value, +}; pub fn chain_error_with_input( error_source: ShellError, @@ -9,3 +14,66 @@ pub fn chain_error_with_input( } error_source } + +pub fn boolean_fold( + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, + accumulator: bool, +) -> Result { + let span = call.head; + + let capture_block: Closure = call.req(engine_state, stack, 0)?; + let block_id = capture_block.block_id; + + let block = engine_state.get_block(block_id); + let var_id = block.signature.get_positional(0).and_then(|arg| arg.var_id); + let mut stack = stack.captures_to_stack(&capture_block.captures); + + let orig_env_vars = stack.env_vars.clone(); + let orig_env_hidden = stack.env_hidden.clone(); + + let ctrlc = engine_state.ctrlc.clone(); + let engine_state = engine_state.clone(); + + for value in input.into_interruptible_iter(ctrlc) { + // with_env() is used here to ensure that each iteration uses + // a different set of environment variables. + // Hence, a 'cd' in the first loop won't affect the next loop. + stack.with_env(&orig_env_vars, &orig_env_hidden); + + if let Some(var_id) = var_id { + stack.add_var(var_id, value.clone()); + } + + let eval = eval_block( + &engine_state, + &mut stack, + block, + value.into_pipeline_data(), + call.redirect_stdout, + call.redirect_stderr, + ); + match eval { + Err(e) => { + return Err(e); + } + Ok(pipeline_data) => { + if pipeline_data.into_value(span).is_true() == accumulator { + return Ok(Value::Bool { + val: accumulator, + span, + } + .into_pipeline_data()); + } + } + } + } + + Ok(Value::Bool { + val: !accumulator, + span, + } + .into_pipeline_data()) +}