From 73d5310c9ca2f0ad310104b87826df6ff19977da Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 29 Apr 2020 19:51:46 +1200 Subject: [PATCH] make it-expansion work through blocks when necessary (#1681) --- crates/nu-cli/src/cli.rs | 2 + crates/nu-protocol/src/hir.rs | 48 +++++++++++++++++++++++ tests/shell/pipeline/commands/internal.rs | 28 ++++++++++++- 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/crates/nu-cli/src/cli.rs b/crates/nu-cli/src/cli.rs index afc1035ea..156000033 100644 --- a/crates/nu-cli/src/cli.rs +++ b/crates/nu-cli/src/cli.rs @@ -848,6 +848,8 @@ async fn process_line( classified_block.block.expand_it_usage(); + trace!("{:#?}", classified_block); + match run_block(&classified_block.block, ctx, input_stream, &Scope::empty()).await { Ok(input) => { // Running a pipeline gives us back a stream that we can then diff --git a/crates/nu-protocol/src/hir.rs b/crates/nu-protocol/src/hir.rs index 712c59faf..1b63c5117 100644 --- a/crates/nu-protocol/src/hir.rs +++ b/crates/nu-protocol/src/hir.rs @@ -105,6 +105,51 @@ impl ClassifiedCommand { _ => false, } } + + pub fn expand_it_usage(&mut self) { + match self { + ClassifiedCommand::Internal(command) => { + if let SpannedExpression { + expr: Expression::Literal(Literal::String(s)), + .. + } = &*command.args.head + { + if s == "run_external" { + // For now, don't it-expand externals + return; + } + } + + if let Some(positionals) = &mut command.args.positional { + for arg in positionals { + if let SpannedExpression { + expr: Expression::Block(block), + .. + } = arg + { + block.expand_it_usage(); + } + } + } + } + ClassifiedCommand::Expr(expr) => { + if let SpannedExpression { + expr: Expression::Block(ref block), + span, + } = **expr + { + let mut block = block.clone(); + block.expand_it_usage(); + *expr = Box::new(SpannedExpression { + expr: Expression::Block(block), + span, + }); + } + } + + _ => {} + } + } } #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] @@ -125,6 +170,9 @@ impl Commands { /// Convert all shallow uses of $it to `each { use of $it }`, converting each to a per-row command pub fn expand_it_usage(&mut self) { for idx in 0..self.list.len() { + self.list[idx].expand_it_usage(); + } + for idx in 1..self.list.len() { if self.list[idx].has_it_iteration() { self.list[idx] = ClassifiedCommand::Internal(InternalCommand { name: "each".to_string(), diff --git a/tests/shell/pipeline/commands/internal.rs b/tests/shell/pipeline/commands/internal.rs index d58c70d39..d08f0fefd 100644 --- a/tests/shell/pipeline/commands/internal.rs +++ b/tests/shell/pipeline/commands/internal.rs @@ -107,7 +107,9 @@ mod parse { } mod tilde_expansion { - use super::nu; + use nu_test_support::fs::Stub::EmptyFile; + use nu_test_support::playground::Playground; + use nu_test_support::{nu, pipeline}; #[test] #[should_panic] @@ -136,4 +138,28 @@ mod tilde_expansion { assert_eq!(actual, "1~1"); } + + #[test] + fn proper_it_expansion() { + Playground::setup("ls_test_1", |dirs, sandbox| { + sandbox.with_files(vec![ + EmptyFile("andres.txt"), + EmptyFile("gedge.txt"), + EmptyFile("jonathan.txt"), + EmptyFile("yehuda.txt"), + ]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + ls | sort-by name | group-by type | each { get File.name | echo $it } | to-json + "# + )); + + assert_eq!( + actual, + r#"["andres.txt","gedge.txt","jonathan.txt","yehuda.txt"]"# + ); + }) + } }