diff --git a/Cargo.lock b/Cargo.lock index c73d0d0df..f98bda270 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "addr2line" version = "0.17.0" @@ -680,6 +690,7 @@ dependencies = [ name = "nu-command" version = "0.1.0" dependencies = [ + "Inflector", "bytesize", "chrono", "chrono-humanize", diff --git a/crates/nu-command/src/filters/where_.rs b/crates/nu-command/src/filters/where_.rs index 593b23ff1..66f6b6fe8 100644 --- a/crates/nu-command/src/filters/where_.rs +++ b/crates/nu-command/src/filters/where_.rs @@ -1,10 +1,7 @@ use nu_engine::eval_expression; use nu_protocol::ast::{Call, Expr, Expression}; use nu_protocol::engine::{Command, EngineState, Stack}; -use nu_protocol::{ - IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError, Signature, - SyntaxShape, Value, -}; +use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape}; #[derive(Clone)] pub struct Where; @@ -29,13 +26,12 @@ impl Command for Where { call: &Call, input: PipelineData, ) -> Result { - let head = call.head; let cond = call.positional[0].clone(); let ctrlc = engine_state.ctrlc.clone(); let engine_state = engine_state.clone(); - // FIXME: very expensive + // FIXME: expensive let mut stack = stack.clone(); let (var_id, cond) = match cond { @@ -46,43 +42,18 @@ impl Command for Where { _ => return Err(ShellError::InternalError("Expected row condition".into())), }; - match input { - PipelineData::Stream(stream) => Ok(stream - .filter(move |value| { - stack.add_var(var_id, value.clone()); + input.filter( + move |value| { + stack.add_var(var_id, value.clone()); - let result = eval_expression(&engine_state, &mut stack, &cond); + let result = eval_expression(&engine_state, &mut stack, &cond); - match result { - Ok(result) => result.is_true(), - _ => false, - } - }) - .into_pipeline_data(ctrlc)), - PipelineData::Value(Value::List { vals, .. }) => Ok(vals - .into_iter() - .filter(move |value| { - stack.add_var(var_id, value.clone()); - - let result = eval_expression(&engine_state, &mut stack, &cond); - - match result { - Ok(result) => result.is_true(), - _ => false, - } - }) - .into_pipeline_data(ctrlc)), - PipelineData::Value(x) => { - stack.add_var(var_id, x.clone()); - - let result = eval_expression(&engine_state, &mut stack, &cond)?; - - if result.is_true() { - Ok(x.into_pipeline_data()) - } else { - Ok(PipelineData::new(head)) + match result { + Ok(result) => result.is_true(), + _ => false, } - } - } + }, + ctrlc, + ) } } diff --git a/crates/nu-protocol/src/pipeline_data.rs b/crates/nu-protocol/src/pipeline_data.rs index ac5694346..16dd9bb9f 100644 --- a/crates/nu-protocol/src/pipeline_data.rs +++ b/crates/nu-protocol/src/pipeline_data.rs @@ -138,6 +138,34 @@ impl PipelineData { PipelineData::Value(v) => Ok(f(v).into_iter().into_pipeline_data(ctrlc)), } } + + pub fn filter( + self, + mut f: F, + ctrlc: Option>, + ) -> Result + where + Self: Sized, + F: FnMut(&Value) -> bool + 'static + Send, + { + match self { + PipelineData::Value(Value::List { vals, .. }) => { + Ok(vals.into_iter().filter(f).into_pipeline_data(ctrlc)) + } + PipelineData::Stream(stream) => Ok(stream.filter(f).into_pipeline_data(ctrlc)), + PipelineData::Value(Value::Range { val, .. }) => match val.into_range_iter() { + Ok(iter) => Ok(iter.filter(f).into_pipeline_data(ctrlc)), + Err(error) => Err(error), + }, + PipelineData::Value(v) => { + if f(&v) { + Ok(v.into_pipeline_data()) + } else { + Ok(Value::Nothing { span: v.span()? }.into_pipeline_data()) + } + } + } + } } // impl Default for PipelineData { diff --git a/src/tests.rs b/src/tests.rs index 45e7a15ac..36b7b36d5 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -849,3 +849,8 @@ fn range_and_reduction() -> TestResult { fn precedence_of_or_groups() -> TestResult { run_test(r#"4 mod 3 == 0 || 5 mod 5 == 0"#, "true") } + +#[test] +fn where_on_ranges() -> TestResult { + run_test(r#"1..10 | where $it > 8 | math sum"#, "19") +}