unify the run functions of all and any (#8578)

# Description

this pr reduces duplication by making `any` and `all` commands use [one
function](66ad83c15c/crates/nu-command/src/filters/any.rs (LL63-L65C28))
This commit is contained in:
mike 2023-03-23 22:49:52 +03:00 committed by GitHub
parent 05ff7a9925
commit 403bf1a734
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 81 additions and 105 deletions

View File

@ -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<PipelineData, ShellError> {
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)
}
}

View File

@ -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<PipelineData, ShellError> {
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)
}
}

View File

@ -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<PipelineData, ShellError> {
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())
}