From bb6bf03607ab15bb86f95e05a69bd84d2cf24175 Mon Sep 17 00:00:00 2001 From: WindSoilder Date: Wed, 17 Jul 2024 07:38:46 +0800 Subject: [PATCH] swap parameter order in generate, so the closure can run with no initial value --- crates/nu-command/src/generators/generate.rs | 41 +++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/crates/nu-command/src/generators/generate.rs b/crates/nu-command/src/generators/generate.rs index 8d4f48d3fb..210b21bc1e 100644 --- a/crates/nu-command/src/generators/generate.rs +++ b/crates/nu-command/src/generators/generate.rs @@ -12,12 +12,12 @@ impl Command for Generate { fn signature(&self) -> Signature { Signature::build("generate") .input_output_types(vec![(Type::Nothing, Type::List(Box::new(Type::Any)))]) - .required("initial", SyntaxShape::Any, "Initial value.") .required( "closure", SyntaxShape::Closure(Some(vec![SyntaxShape::Any])), "Generator function.", ) + .optional("initial", SyntaxShape::Any, "Initial value.") .allow_variants_without_examples(true) .category(Category::Generators) } @@ -72,15 +72,16 @@ used as the next argument to the closure, otherwise generation stops. _input: PipelineData, ) -> Result { let head = call.head; - let initial: Value = call.req(engine_state, stack, 0)?; - let closure: Closure = call.req(engine_state, stack, 1)?; - + let initial: Option = call.opt(engine_state, stack, 1)?; + let closure: Closure = call.req(engine_state, stack, 0)?; + let block = engine_state.get_block(closure.block_id); let mut closure = ClosureEval::new(engine_state, stack, closure); // A type of Option is used to represent state. Invocation // will stop on None. Using Option allows functions to output // one final value before stopping. - let mut state = Some(initial); + let mut state = Some(get_initial_state(initial, &block.signature)?); + // let mut state = Some(initial); let iter = std::iter::from_fn(move || { let arg = state.take()?; @@ -181,3 +182,33 @@ mod test { test_examples(Generate {}) } } + +fn get_initial_state(initial: Option, signature: &Signature) -> Result { + match initial { + Some(v) => Ok(v), + None => { + // the initial state shold be referred from signature + if signature.optional_positional.len() > 0 { + if let Some(v) = &signature.optional_positional[0].default_value { + Ok(v.clone()) + } else { + Err(ShellError::GenericError { + error: "".to_string(), + msg: "bb".to_string(), + help: None, + span: None, + inner: vec![], + }) + } + } else { + Err(ShellError::GenericError { + error: "aa".to_string(), + msg: "bb".to_string(), + help: None, + span: None, + inner: vec![], + }) + } + } + } +}