diff --git a/crates/nu-command/src/filters/filter.rs b/crates/nu-command/src/filters/filter.rs index 0bb2460048..dce091717a 100644 --- a/crates/nu-command/src/filters/filter.rs +++ b/crates/nu-command/src/filters/filter.rs @@ -1,6 +1,5 @@ -use super::utils::chain_error_with_input; -use nu_engine::{ClosureEval, ClosureEvalOnce, command_prelude::*}; -use nu_protocol::engine::Closure; +use nu_engine::command_prelude::*; +use nu_protocol::{DeprecationEntry, DeprecationType, ReportMode}; #[derive(Clone)] pub struct Filter; @@ -15,8 +14,8 @@ impl Command for Filter { } fn extra_description(&self) -> &str { - r#"This command works similar to 'where' but allows reading the predicate closure from -a variable. On the other hand, the "row condition" syntax is not supported."# + r#"This command works similar to 'where' but can only use a closure as a predicate. +The "row condition" syntax is not supported."# } fn signature(&self) -> nu_protocol::Signature { @@ -47,80 +46,20 @@ a variable. On the other hand, the "row condition" syntax is not supported."# call: &Call, input: PipelineData, ) -> Result { - let head = call.head; - let closure: Closure = call.req(engine_state, stack, 0)?; + use super::where_::Where; + ::run(&Where, engine_state, stack, call, input) + } - let metadata = input.metadata(); - match input { - PipelineData::Empty => Ok(PipelineData::Empty), - PipelineData::Value(Value::Range { .. }, ..) - | PipelineData::Value(Value::List { .. }, ..) - | PipelineData::ListStream(..) => { - let mut closure = ClosureEval::new(engine_state, stack, closure); - Ok(input - .into_iter() - .filter_map(move |value| { - match closure - .run_with_value(value.clone()) - .and_then(|data| data.into_value(head)) - { - Ok(cond) => cond.is_true().then_some(value), - Err(err) => { - let span = value.span(); - let err = chain_error_with_input(err, value.is_error(), span); - Some(Value::error(err, span)) - } - } - }) - .into_pipeline_data(head, engine_state.signals().clone())) + fn deprecation_info(&self) -> Vec { + vec![ + DeprecationEntry { + ty: DeprecationType::Command, + report_mode: ReportMode::FirstUse, + since: Some("0.105.0".into()), + expected_removal: None, + help: Some("`where` command can be used instead, as it can now read the predicate closure from a variable".into()), } - PipelineData::ByteStream(stream, ..) => { - if let Some(chunks) = stream.chunks() { - let mut closure = ClosureEval::new(engine_state, stack, closure); - Ok(chunks - .into_iter() - .filter_map(move |value| { - let value = match value { - Ok(value) => value, - Err(err) => return Some(Value::error(err, head)), - }; - - match closure - .run_with_value(value.clone()) - .and_then(|data| data.into_value(head)) - { - Ok(cond) => cond.is_true().then_some(value), - Err(err) => { - let span = value.span(); - let err = chain_error_with_input(err, value.is_error(), span); - Some(Value::error(err, span)) - } - } - }) - .into_pipeline_data(head, engine_state.signals().clone())) - } else { - Ok(PipelineData::Empty) - } - } - // This match allows non-iterables to be accepted, - // which is currently considered undesirable (Nov 2022). - PipelineData::Value(value, ..) => { - let result = ClosureEvalOnce::new(engine_state, stack, closure) - .run_with_value(value.clone()) - .and_then(|data| data.into_value(head)); - - Ok(match result { - Ok(cond) => cond.is_true().then_some(value), - Err(err) => { - let span = value.span(); - let err = chain_error_with_input(err, value.is_error(), span); - Some(Value::error(err, span)) - } - } - .into_pipeline_data(head, engine_state.signals().clone())) - } - } - .map(|data| data.set_metadata(metadata)) + ] } fn examples(&self) -> Vec { diff --git a/crates/nu-command/src/filters/get.rs b/crates/nu-command/src/filters/get.rs index bece5a9231..2f9a863991 100644 --- a/crates/nu-command/src/filters/get.rs +++ b/crates/nu-command/src/filters/get.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use nu_engine::command_prelude::*; -use nu_protocol::{Signals, ast::PathMember, report_shell_warning}; +use nu_protocol::{DeprecationEntry, DeprecationType, ReportMode, Signals, ast::PathMember}; #[derive(Clone)] pub struct Get; @@ -132,19 +132,7 @@ If multiple cell paths are given, this will produce a list of values."# let cell_path: CellPath = call.req(engine_state, stack, 0)?; let rest: Vec = call.rest(engine_state, stack, 1)?; let ignore_errors = call.has_flag(engine_state, stack, "ignore-errors")?; - let sensitive_span = call.get_flag_span(stack, "sensitive"); let metadata = input.metadata(); - if let Some(span) = sensitive_span { - report_shell_warning( - engine_state, - &ShellError::Deprecated { - deprecated: "sensitive flag", - suggestion: "", - span, - help: Some("cell-paths are case-sensitive by default"), - }, - ); - } action( input, cell_path, @@ -155,6 +143,18 @@ If multiple cell paths are given, this will produce a list of values."# ) .map(|x| x.set_metadata(metadata)) } + + fn deprecation_info(&self) -> Vec { + vec![ + DeprecationEntry { + ty: DeprecationType::Flag("sensitive".into()), + report_mode: ReportMode::FirstUse, + since: Some("0.105.0".into()), + expected_removal: None, + help: Some("Cell-paths are now case-sensitive by default.\nTo access fields case-insensitively, add `!` after the relevant path member.".into()) + } + ] + } } fn action( diff --git a/crates/nu-command/tests/commands/filter.rs b/crates/nu-command/tests/commands/filter.rs index c8f7508502..8f0784bb64 100644 --- a/crates/nu-command/tests/commands/filter.rs +++ b/crates/nu-command/tests/commands/filter.rs @@ -14,5 +14,5 @@ fn filter_with_return_in_closure() { )); assert_eq!(actual.out, "[2, 4, 6, 8, 10]"); - assert!(actual.err.is_empty()); + assert!(actual.err.contains("deprecated")); } diff --git a/crates/nu-std/std/iter/mod.nu b/crates/nu-std/std/iter/mod.nu index 2278c1d8af..d4db0a3a5f 100644 --- a/crates/nu-std/std/iter/mod.nu +++ b/crates/nu-std/std/iter/mod.nu @@ -18,7 +18,7 @@ export def find [ fn: closure # the closure used to perform the search ] { - filter {|e| try {do $fn $e} } | try { first } + where {|e| try {do $fn $e} } | try { first } } # Returns the index of the first element that matches the predicate or -1 if none @@ -87,7 +87,7 @@ export def scan [ # -> list # # This is equivalent to # -# $in | each $fn | filter $fn +# $in | each $fn | where $fn @example "Get the squares of elements that can be squared" { [2 5 "4" 7] | iter filter-map {|e| $e ** 2} } --result [4, 25, 49] @@ -101,7 +101,7 @@ export def filter-map [ null } } - | filter {|e| + | where {|e| $e != null } } diff --git a/crates/nu-std/std/xml/mod.nu b/crates/nu-std/std/xml/mod.nu index 6cf8159afd..949f1e4435 100644 --- a/crates/nu-std/std/xml/mod.nu +++ b/crates/nu-std/std/xml/mod.nu @@ -62,7 +62,7 @@ def xupdate-string-step [ step: string rest: list updater: closure ] { let input = $in # Get a list of elements to be updated and their indices - let to_update = ($input.content | enumerate | filter {|it| + let to_update = ($input.content | enumerate | where {|it| let item = $it.item $step == '*' or $item.tag == $step }) diff --git a/crates/nu-std/testing.nu b/crates/nu-std/testing.nu index 92aa5c1d52..9f9ee75843 100644 --- a/crates/nu-std/testing.nu +++ b/crates/nu-std/testing.nu @@ -333,20 +333,20 @@ export def run-tests [ commands: (get-annotated $row.name) } } - | filter {|x| ($x.commands|length) > 0} + | where {|x| ($x.commands|length) > 0} | upsert commands {|module| $module.commands | create-test-record } | flatten - | filter {|x| ($x.test|length) > 0} - | filter {|x| if ($exclude_module|is-empty) {true} else {$x.name !~ $exclude_module}} - | filter {|x| if ($test|is-empty) {true} else {$x.test|any {|y| $y =~ $test}}} - | filter {|x| if ($module|is-empty) {true} else {$module == $x.name}} + | where {|x| ($x.test|length) > 0} + | where {|x| if ($exclude_module|is-empty) {true} else {$x.name !~ $exclude_module}} + | where {|x| if ($test|is-empty) {true} else {$x.test|any {|y| $y =~ $test}}} + | where {|x| if ($module|is-empty) {true} else {$module == $x.name}} | update test {|x| $x.test - | filter {|y| if ($test|is-empty) {true} else {$y =~ $test}} - | filter {|y| if ($exclude|is-empty) {true} else {$y !~ $exclude}} + | where {|y| if ($test|is-empty) {true} else {$y =~ $test}} + | where {|y| if ($exclude|is-empty) {true} else {$y !~ $exclude}} } ) if $list {