diff --git a/crates/nu-cli/src/commands/command.rs b/crates/nu-cli/src/commands/command.rs index ebbd1a8c8e..d2b68557fa 100644 --- a/crates/nu-cli/src/commands/command.rs +++ b/crates/nu-cli/src/commands/command.rs @@ -275,6 +275,39 @@ impl WholeStreamCommand for Block { } } } + if let Some(args) = evaluated.args.named { + for named in &block.params.named { + let name = named.0; + if let Some(value) = args.get(name) { + if name.starts_with('$') { + ctx.scope.add_var(name, value.clone()); + } else { + ctx.scope.add_var(format!("${}", name), value.clone()); + } + } else if name.starts_with('$') { + ctx.scope + .add_var(name, UntaggedValue::nothing().into_untagged_value()); + } else { + ctx.scope.add_var( + format!("${}", name), + UntaggedValue::nothing().into_untagged_value(), + ); + } + } + } else { + for named in &block.params.named { + let name = named.0; + if name.starts_with('$') { + ctx.scope + .add_var(name, UntaggedValue::nothing().into_untagged_value()); + } else { + ctx.scope.add_var( + format!("${}", name), + UntaggedValue::nothing().into_untagged_value(), + ); + } + } + } let result = run_block(&block, &ctx, input).await; ctx.scope.exit_scope(); result.map(|x| x.to_output_stream()) diff --git a/crates/nu-parser/src/lex.rs b/crates/nu-parser/src/lex.rs index 42d10d3731..ac32da6ebc 100644 --- a/crates/nu-parser/src/lex.rs +++ b/crates/nu-parser/src/lex.rs @@ -173,6 +173,29 @@ impl LiteBlock { Span::new(start, 0) } } + pub fn head(&self) -> Option> { + if let Some(group) = self.block.get(0) { + if let Some(pipeline) = group.pipelines.get(0) { + if let Some(command) = pipeline.commands.get(0) { + if let Some(head) = command.parts.get(0) { + return Some(head.clone()); + } + } + } + } + None + } + pub fn remove_head(&mut self) { + if let Some(group) = self.block.get_mut(0) { + if let Some(pipeline) = group.pipelines.get_mut(0) { + if let Some(command) = pipeline.commands.get_mut(0) { + if !command.parts.is_empty() { + command.parts.remove(0); + } + } + } + } + } } #[derive(Clone, Copy)] diff --git a/crates/nu-parser/src/parse.rs b/crates/nu-parser/src/parse.rs index c43ae343a9..6bc3ecfe0e 100644 --- a/crates/nu-parser/src/parse.rs +++ b/crates/nu-parser/src/parse.rs @@ -2027,36 +2027,76 @@ fn parse_signature( Expression::Literal(Literal::String(st)) => { let parts: Vec<_> = st.split(':').collect(); if parts.len() == 1 { - signature.positional.push(( - PositionalType::Mandatory(parts[0].to_string(), SyntaxShape::Any), - String::new(), - )); + if parts[0].starts_with("--") { + // Flag + let flagname = parts[0][2..].to_string(); + signature + .named + .insert(flagname, (NamedType::Switch(None), String::new())); + } else { + // Positional + signature.positional.push(( + PositionalType::Mandatory(parts[0].to_string(), SyntaxShape::Any), + String::new(), + )); + } } else if parts.len() == 2 { - let name = parts[0].to_string(); - let shape = match parts[1] { - "int" => SyntaxShape::Int, - "string" => SyntaxShape::String, - "path" => SyntaxShape::Path, - "table" => SyntaxShape::Table, - "unit" => SyntaxShape::Unit, - "number" => SyntaxShape::Number, - "pattern" => SyntaxShape::Pattern, - "range" => SyntaxShape::Range, - "block" => SyntaxShape::Block, - "any" => SyntaxShape::Any, - _ => { - if err.is_none() { - err = Some(ParseError::mismatch( - "params with known types", - s.clone(), - )); + if parts[0].starts_with("--") { + // Flag + let flagname = parts[0][2..].to_string(); + let shape = match parts[1] { + "int" => SyntaxShape::Int, + "string" => SyntaxShape::String, + "path" => SyntaxShape::Path, + "table" => SyntaxShape::Table, + "unit" => SyntaxShape::Unit, + "number" => SyntaxShape::Number, + "pattern" => SyntaxShape::Pattern, + "range" => SyntaxShape::Range, + "block" => SyntaxShape::Block, + "any" => SyntaxShape::Any, + _ => { + if err.is_none() { + err = Some(ParseError::mismatch( + "params with known types", + s.clone(), + )); + } + SyntaxShape::Any } - SyntaxShape::Any - } - }; - signature - .positional - .push((PositionalType::Mandatory(name, shape), String::new())); + }; + signature.named.insert( + flagname, + (NamedType::Optional(None, shape), String::new()), + ); + } else { + // Positional + let name = parts[0].to_string(); + let shape = match parts[1] { + "int" => SyntaxShape::Int, + "string" => SyntaxShape::String, + "path" => SyntaxShape::Path, + "table" => SyntaxShape::Table, + "unit" => SyntaxShape::Unit, + "number" => SyntaxShape::Number, + "pattern" => SyntaxShape::Pattern, + "range" => SyntaxShape::Range, + "block" => SyntaxShape::Block, + "any" => SyntaxShape::Any, + _ => { + if err.is_none() { + err = Some(ParseError::mismatch( + "params with known types", + s.clone(), + )); + } + SyntaxShape::Any + } + }; + signature + .positional + .push((PositionalType::Mandatory(name, shape), String::new())); + } } else if err.is_none() { err = Some(ParseError::mismatch("param with type", s.clone())); } @@ -2246,11 +2286,6 @@ pub fn classify_block( } } - // for def in scope.get_definitions() { - // let name = def.params.name.clone(); - // output.definitions.insert(name, def.clone()); - // } - (output, error) } diff --git a/tests/shell/pipeline/commands/internal.rs b/tests/shell/pipeline/commands/internal.rs index 57e1536fb0..e9a5f31727 100644 --- a/tests/shell/pipeline/commands/internal.rs +++ b/tests/shell/pipeline/commands/internal.rs @@ -344,6 +344,30 @@ fn run_custom_command() { assert_eq!(actual.out, "15"); } +#[test] +fn run_custom_command_with_flag() { + let actual = nu!( + cwd: ".", + r#" + def foo [--bar:number] { if $(echo $bar | empty?) { echo "empty" } { echo $bar } }; foo --bar 10 + "# + ); + + assert_eq!(actual.out, "10"); +} + +#[test] +fn run_custom_command_with_flag_missing() { + let actual = nu!( + cwd: ".", + r#" + def foo [--bar:number] { if $(echo $bar | empty?) { echo "empty" } { echo $bar } }; foo + "# + ); + + assert_eq!(actual.out, "empty"); +} + #[test] fn set_variable() { let actual = nu!(