diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 4b4f38c5..e4f51918 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -5,7 +5,7 @@ use nu_protocol::{ Signature, SyntaxShape, }; -use crate::{Alias, Benchmark, BuildString, Def, For, If, Length, Let, LetEnv}; +use crate::{Alias, Benchmark, BuildString, Def, Each, For, If, Length, Let, LetEnv}; pub fn create_default_context() -> Rc> { let engine_state = Rc::new(RefCell::new(EngineState::new())); @@ -31,6 +31,8 @@ pub fn create_default_context() -> Rc> { working_set.add_decl(Box::new(For)); + working_set.add_decl(Box::new(Each)); + working_set.add_decl(Box::new(Benchmark)); working_set.add_decl(Box::new(Length)); diff --git a/crates/nu-command/src/each.rs b/crates/nu-command/src/each.rs new file mode 100644 index 00000000..6a96ec9e --- /dev/null +++ b/crates/nu-command/src/each.rs @@ -0,0 +1,61 @@ +use nu_engine::{eval_block, eval_expression}; +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EvaluationContext}; +use nu_protocol::{IntoValueStream, Signature, Span, SyntaxShape, Value}; + +pub struct Each; + +impl Command for Each { + fn name(&self) -> &str { + "each" + } + + fn usage(&self) -> &str { + "Run a block on each element of input" + } + + fn signature(&self) -> nu_protocol::Signature { + Signature::build("each") + .required( + "var_name", + SyntaxShape::Variable, + "name of the looping variable", + ) + .required("block", SyntaxShape::Block, "the block to run") + } + + fn run( + &self, + context: &EvaluationContext, + call: &Call, + input: Value, + ) -> Result { + let var_id = call.positional[0] + .as_var() + .expect("internal error: missing variable"); + + let block = call.positional[1] + .as_block() + .expect("internal error: expected block"); + let context = context.clone(); + + match input { + Value::List { val, .. } => Ok(Value::List { + val: val + .map(move |x| { + let engine_state = context.engine_state.borrow(); + let block = engine_state.get_block(block); + + let state = context.enter_scope(); + state.add_var(var_id, x.clone()); + + //FIXME: DON'T UNWRAP + eval_block(&state, block, Value::nothing()).unwrap() + }) + .into_value_stream(), + span: call.head, + }), + _ => Ok(Value::nothing()), + } + } +} diff --git a/crates/nu-command/src/for_.rs b/crates/nu-command/src/for_.rs index b240d30c..bdf882ac 100644 --- a/crates/nu-command/src/for_.rs +++ b/crates/nu-command/src/for_.rs @@ -63,7 +63,7 @@ impl Command for For { state.add_var(var_id, x.clone()); //FIXME: DON'T UNWRAP - eval_block(&state, block, input.clone()).unwrap() + eval_block(&state, block, Value::nothing()).unwrap() }) .into_value_stream(), span: call.head, diff --git a/crates/nu-command/src/lib.rs b/crates/nu-command/src/lib.rs index 1d26da00..1df25ef5 100644 --- a/crates/nu-command/src/lib.rs +++ b/crates/nu-command/src/lib.rs @@ -3,6 +3,7 @@ mod benchmark; mod build_string; mod def; mod default_context; +mod each; mod for_; mod if_; mod length; @@ -14,6 +15,7 @@ pub use benchmark::Benchmark; pub use build_string::BuildString; pub use def::Def; pub use default_context::create_default_context; +pub use each::Each; pub use for_::For; pub use if_::If; pub use length::Length;