Repository: casey/just
Pull request #810 (2021-05-02 10:23:29)

Pass evaluated arguments as positional arguments


Patch:
diff --git a/src/evaluator.rs b/src/evaluator.rs
index 99a8b3c4..f259caba 100644
--- a/src/evaluator.rs
+++ b/src/evaluator.rs
@@ -194,7 +194,7 @@ impl<'src, 'run> Evaluator<'src, 'run> {
     scope: &'run Scope<'src, 'run>,
     settings: &'run Settings,
     search: &'run Search,
-  ) -> RunResult<'src, Scope<'src, 'run>> {
+  ) -> RunResult<'src, (Scope<'src, 'run>, Vec<String>)> {
     let mut evaluator = Evaluator {
       assignments: None,
       scope: scope.child(),
@@ -206,11 +206,15 @@ impl<'src, 'run> Evaluator<'src, 'run> {
 
     let mut scope = scope.child();
 
+    let mut positional = Vec::new();
+
     let mut rest = arguments;
     for parameter in parameters {
       let value = if rest.is_empty() {
         if let Some(ref default) = parameter.default {
-          evaluator.evaluate_expression(default)?
+          let value = evaluator.evaluate_expression(default)?;
+          positional.push(value.clone());
+          value
         } else if parameter.kind == ParameterKind::Star {
           String::new()
         } else {
@@ -219,18 +223,22 @@ impl<'src, 'run> Evaluator<'src, 'run> {
           });
         }
       } else if parameter.kind.is_variadic() {
+        for value in rest {
+          positional.push((*value).to_owned());
+        }
         let value = rest.to_vec().join(" ");
         rest = &[];
         value
       } else {
         let value = rest[0].to_owned();
+        positional.push(value.clone());
         rest = &rest[1..];
         value
       };
       scope.bind(parameter.export, parameter.name, value);
     }
 
-    Ok(scope)
+    Ok((scope, positional))
   }
 
   pub(crate) fn recipe_evaluator(
diff --git a/src/justfile.rs b/src/justfile.rs
index 849b63f4..8d1ac4aa 100644
--- a/src/justfile.rs
+++ b/src/justfile.rs
@@ -253,7 +253,7 @@ impl<'src> Justfile<'src> {
     search: &'run Search,
     ran: &mut BTreeSet<Vec<String>>,
   ) -> RunResult<'src, ()> {
-    let outer = Evaluator::evaluate_parameters(
+    let (outer, positional) = Evaluator::evaluate_parameters(
       context.config,
       dotenv,
       &recipe.parameters,
@@ -285,7 +285,7 @@ impl<'src> Justfile<'src> {
       }
     }
 
-    recipe.run(context, dotenv, scope.child(), search, arguments)?;
+    recipe.run(context, dotenv, scope.child(), search, &positional)?;
 
     let mut invocation = vec![recipe.name().to_owned()];
     for argument in arguments.iter().cloned() {
diff --git a/src/recipe.rs b/src/recipe.rs
index f1fc40eb..f7ae982b 100644
--- a/src/recipe.rs
+++ b/src/recipe.rs
@@ -74,7 +74,7 @@ impl<'src, D> Recipe<'src, D> {
     dotenv: &BTreeMap<String, String>,
     scope: Scope<'src, 'run>,
     search: &'run Search,
-    arguments: &[&'run str],
+    positional: &[String],
   ) -> RunResult<'src, ()> {
     let config = &context.config;
 
@@ -178,7 +178,7 @@ impl<'src, D> Recipe<'src, D> {
       })?;
 
       if context.settings.positional_arguments {
-        command.args(arguments);
+        command.args(positional);
       }
 
       command.export(context.settings, dotenv, &scope);
@@ -267,7 +267,7 @@ impl<'src, D> Recipe<'src, D> {
 
         if context.settings.positional_arguments {
           cmd.arg(self.name.lexeme());
-          cmd.args(arguments);
+          cmd.args(positional);
         }
 
         if config.verbosity.quiet() {


Test patch:
diff --git a/tests/positional_arguments.rs b/tests/positional_arguments.rs
index 2d242980..f412f0c3 100644
--- a/tests/positional_arguments.rs
+++ b/tests/positional_arguments.rs
@@ -64,3 +64,43 @@ test! {
   args:   ("foo", "a", "b", "c"),
   stdout: "a\na b c\n",
 }
+
+test! {
+  name: default_arguments,
+  justfile: r#"
+    set positional-arguments
+
+    foo bar='baz':
+      echo $1
+  "#,
+  args:   (),
+  stdout: "baz\n",
+  stderr: "echo $1\n",
+}
+
+test! {
+  name: empty_variadic_is_undefined,
+  justfile: r#"
+    set positional-arguments
+
+    foo *bar:
+      if [ -n "${1+1}" ]; then echo defined; else echo undefined; fi
+  "#,
+  args:   (),
+  stdout: "undefined\n",
+  stderr: "if [ -n \"${1+1}\" ]; then echo defined; else echo undefined; fi\n",
+}
+
+test! {
+  name: variadic_arguments_are_separate,
+  justfile: r#"
+    set positional-arguments
+
+    foo *bar:
+      echo $1
+      echo $2
+  "#,
+  args:   ("foo", "a", "b"),
+  stdout: "a\nb\n",
+  stderr: "echo $1\necho $2\n",
+}