diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 6f3d2f63db..1bfe1b8ca9 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -51,6 +51,7 @@ pub fn create_default_context() -> EngineState { Append, Collect, Columns, + Compact, Drop, DropColumn, DropNth, diff --git a/crates/nu-command/src/filters/compact.rs b/crates/nu-command/src/filters/compact.rs new file mode 100644 index 0000000000..184f90976c --- /dev/null +++ b/crates/nu-command/src/filters/compact.rs @@ -0,0 +1,116 @@ +use nu_engine::CallExt; +use nu_protocol::{ + ast::Call, engine::Command, engine::EngineState, engine::Stack, Category, Example, + PipelineData, ShellError, Signature, Span, SyntaxShape, Value, +}; + +#[derive(Clone)] +pub struct Compact; + +impl Command for Compact { + fn name(&self) -> &str { + "compact" + } + + fn signature(&self) -> Signature { + Signature::build("compact") + .rest( + "columns", + SyntaxShape::Any, + "the columns to compact from the table", + ) + .category(Category::Filters) + } + + fn usage(&self) -> &str { + "Creates a table with non-empty rows." + } + + fn run( + &self, + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + compact(engine_state, stack, call, input) + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Filter out all records where 'Hello' is null (returns nothing)", + example: r#"echo [["Hello" "World"]; [$nothing 3]]| compact Hello"#, + result: Some(Value::List { + vals: vec![], + span: Span::test_data(), + }), + }, + Example { + description: "Filter out all records where 'World' is null (Returns the table)", + example: r#"echo [["Hello" "World"]; [$nothing 3]]| compact World"#, + result: Some(Value::List { + vals: vec![Value::Record { + cols: vec!["Hello".into(), "World".into()], + vals: vec![Value::nothing(Span::test_data()), Value::test_int(3)], + span: Span::test_data(), + }], + span: Span::test_data(), + }), + }, + Example { + description: "Filter out all instances of nothing from a list (Returns [1,2]", + example: r#"echo [1, $nothing, 2] | compact"#, + result: Some(Value::List { + vals: vec![Value::test_int(1), Value::test_int(2)], + span: Span::test_data(), + }), + }, + ] + } +} + +pub fn compact( + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, +) -> Result { + let columns: Vec = call.rest(engine_state, stack, 0)?; + input.filter( + move |item| { + match item { + // Nothing is filtered out + Value::Nothing { .. } => false, + Value::Record { .. } => { + for column in columns.iter() { + match item.get_data_by_key(column) { + None => return false, + Some(x) => { + if let Value::Nothing { .. } = x { + return false; + } + } + } + } + // No defined columns contained Nothing + true + } + // Any non-Nothing, non-record should be kept + _ => true, + } + }, + engine_state.ctrlc.clone(), + ) +} + +#[cfg(test)] +mod tests { + use super::Compact; + + #[test] + fn examples_work_as_expected() { + use crate::test_examples; + test_examples(Compact {}) + } +} diff --git a/crates/nu-command/src/filters/mod.rs b/crates/nu-command/src/filters/mod.rs index a4a42649a4..bb70b47cd2 100644 --- a/crates/nu-command/src/filters/mod.rs +++ b/crates/nu-command/src/filters/mod.rs @@ -3,6 +3,7 @@ mod any; mod append; mod collect; mod columns; +mod compact; mod drop; mod each; mod empty; @@ -33,6 +34,7 @@ pub use any::Any; pub use append::Append; pub use collect::Collect; pub use columns::Columns; +pub use compact::Compact; pub use drop::*; pub use each::Each; pub use empty::Empty;