diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 8d75488fea..2f4e4d8634 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -57,6 +57,7 @@ pub fn create_default_context(cwd: impl AsRef) -> EngineState { Collect, Columns, Compact, + Default, Drop, DropColumn, DropNth, diff --git a/crates/nu-command/src/filters/default.rs b/crates/nu-command/src/filters/default.rs new file mode 100644 index 0000000000..1db487cd99 --- /dev/null +++ b/crates/nu-command/src/filters/default.rs @@ -0,0 +1,100 @@ +use nu_engine::CallExt; +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::{Category, Example, PipelineData, Signature, Spanned, SyntaxShape, Value}; + +#[derive(Clone)] +pub struct Default; + +impl Command for Default { + fn name(&self) -> &str { + "default" + } + + fn signature(&self) -> Signature { + Signature::build("default") + .required("column name", SyntaxShape::String, "the name of the column") + .required( + "column value", + SyntaxShape::Any, + "the value of the column to default", + ) + .category(Category::Filters) + } + + fn usage(&self) -> &str { + "Sets a default row's column if missing." + } + + fn run( + &self, + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + default(engine_state, stack, call, input) + } + + fn examples(&self) -> Vec { + vec![Example { + description: "Give a default 'target' to all file entries", + example: "ls -la | default target 'nothing'", + result: None, + }] + } +} + +fn default( + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, +) -> Result { + let column: Spanned = call.req(engine_state, stack, 0)?; + let value: Value = call.req(engine_state, stack, 1)?; + + let ctrlc = engine_state.ctrlc.clone(); + + input.map( + move |item| match item { + Value::Record { + mut cols, + mut vals, + span, + } => { + let mut idx = 0; + let mut found = false; + + while idx < cols.len() { + if cols[idx] == column.item && matches!(vals[idx], Value::Nothing { .. }) { + vals[idx] = value.clone(); + found = true; + } + idx += 1; + } + + if !found { + cols.push(column.item.clone()); + vals.push(value.clone()); + } + + Value::Record { cols, vals, span } + } + _ => item, + }, + ctrlc, + ) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_examples() { + use crate::test_examples; + + test_examples(Default {}) + } +} diff --git a/crates/nu-command/src/filters/mod.rs b/crates/nu-command/src/filters/mod.rs index c85c2583a4..3340917e40 100644 --- a/crates/nu-command/src/filters/mod.rs +++ b/crates/nu-command/src/filters/mod.rs @@ -4,6 +4,7 @@ mod append; mod collect; mod columns; mod compact; +mod default; mod drop; mod each; mod empty; @@ -43,6 +44,7 @@ pub use append::Append; pub use collect::Collect; pub use columns::Columns; pub use compact::Compact; +pub use default::Default; pub use drop::*; pub use each::Each; pub use empty::Empty;