diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 453486eb2..9992f8421 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -59,6 +59,7 @@ pub fn create_default_context() -> EngineState { DropNth, Each, Empty, + Every, First, Flatten, Get, diff --git a/crates/nu-command/src/filters/every.rs b/crates/nu-command/src/filters/every.rs new file mode 100644 index 000000000..59e15bee2 --- /dev/null +++ b/crates/nu-command/src/filters/every.rs @@ -0,0 +1,96 @@ +use nu_engine::CallExt; + +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::{ + Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span, + SyntaxShape, Value, +}; + +#[derive(Clone)] +pub struct Every; + +impl Command for Every { + fn name(&self) -> &str { + "every" + } + + fn signature(&self) -> Signature { + Signature::build("every") + .required( + "stride", + SyntaxShape::Int, + "how many rows to skip between (and including) each row returned", + ) + .switch( + "skip", + "skip the rows that would be returned, instead of selecting them", + Some('s'), + ) + .category(Category::Filters) + } + + fn usage(&self) -> &str { + "Show (or skip) every n-th row, starting from the first one." + } + + fn examples(&self) -> Vec { + vec![ + Example { + example: "[1 2 3 4 5] | every 2", + description: "Get every second row", + result: Some(Value::List { + vals: vec![Value::test_int(1), Value::test_int(3), Value::test_int(5)], + span: Span::test_data(), + }), + }, + Example { + example: "[1 2 3 4 5] | every 2 --skip", + description: "Skip every second row", + result: Some(Value::List { + vals: vec![Value::test_int(2), Value::test_int(4)], + span: Span::test_data(), + }), + }, + ] + } + + fn run( + &self, + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + let stride = match call.req::(engine_state, stack, 0)? { + 0 => 1, + stride => stride, + }; + + let skip = call.has_flag("skip"); + + Ok(input + .into_iter() + .enumerate() + .filter_map(move |(i, value)| { + if (i % stride != 0) == skip { + Some(value) + } else { + None + } + }) + .into_pipeline_data(engine_state.ctrlc.clone())) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_examples() { + use crate::test_examples; + + test_examples(Every {}) + } +} diff --git a/crates/nu-command/src/filters/mod.rs b/crates/nu-command/src/filters/mod.rs index bb70b47cd..487ed01ec 100644 --- a/crates/nu-command/src/filters/mod.rs +++ b/crates/nu-command/src/filters/mod.rs @@ -7,6 +7,7 @@ mod compact; mod drop; mod each; mod empty; +mod every; mod first; mod flatten; mod get; @@ -38,6 +39,7 @@ pub use compact::Compact; pub use drop::*; pub use each::Each; pub use empty::Empty; +pub use every::Every; pub use first::First; pub use flatten::Flatten; pub use get::Get;