Repository: casey/just
Pull request #369 (2018-10-28 23:29:12)

Print recipe signature if missing arguments
references issue #341 

Wasn't sure what format would be the best, but I took a stab at it and and printed out a simple usage doc on top of the error that was already there. Let me know what more I can do to help/make the code cleaner! I'm still fairly new to rust, so if this seems like a naÏve approach, please forgive me :laughing:   



casey: Thank you for the PR! I think this a stray commit. You might want to create a separate branch for the pull request, so that pushes to master don't land on the PR after you've opened it.
ladysamantha: > Thank you for the PR! I think this has a stray 2nd commit. You might want to create a separate branch for the pull request, so that pushes to master don't land on the PR after you've opened it.

D'oh! That actually makes sense, I'm just so used to not using branches at work (company policy...) so I forget sometimes to use them lol

Did you want the usage printed on all of the conditions in `ArugmentCountMismatch`?

Patch:
diff --git a/src/justfile.rs b/src/justfile.rs
index bcb37c0a..cbedf023 100644
--- a/src/justfile.rs
+++ b/src/justfile.rs
@@ -99,6 +99,7 @@ impl<'a> Justfile<'a> where {
           if !argument_range.range_contains(argument_count) {
             return Err(RuntimeError::ArgumentCountMismatch {
               recipe: recipe.name,
+              parameters: recipe.parameters.iter().collect(),
               found: tail.len(),
               min: recipe.min_arguments(),
               max: recipe.max_arguments(),
@@ -307,11 +308,17 @@ a return code:
     {
       ArgumentCountMismatch {
         recipe,
+        parameters,
         found,
         min,
         max,
       } => {
+        let param_names = parameters
+          .iter()
+          .map(|p| p.name)
+          .collect::<Vec<&str>>();
         assert_eq!(recipe, "a");
+        assert_eq!(param_names, ["b", "c", "d"]);
         assert_eq!(found, 2);
         assert_eq!(min, 3);
         assert_eq!(max, 3);
@@ -328,11 +335,17 @@ a return code:
     {
       ArgumentCountMismatch {
         recipe,
+        parameters,
         found,
         min,
         max,
       } => {
+        let param_names = parameters
+          .iter()
+          .map(|p| p.name)
+          .collect::<Vec<&str>>();
         assert_eq!(recipe, "a");
+        assert_eq!(param_names, ["b", "c", "d"]);
         assert_eq!(found, 2);
         assert_eq!(min, 3);
         assert_eq!(max, usize::MAX - 1);
@@ -349,11 +362,17 @@ a return code:
     {
       ArgumentCountMismatch {
         recipe,
+        parameters,
         found,
         min,
         max,
       } => {
+        let param_names = parameters
+          .iter()
+          .map(|p| p.name)
+          .collect::<Vec<&str>>();
         assert_eq!(recipe, "a");
+        assert_eq!(param_names, ["b", "c", "d"]);
         assert_eq!(found, 0);
         assert_eq!(min, 3);
         assert_eq!(max, 3);
@@ -370,11 +389,17 @@ a return code:
     {
       ArgumentCountMismatch {
         recipe,
+        parameters,
         found,
         min,
         max,
       } => {
+        let param_names = parameters
+          .iter()
+          .map(|p| p.name)
+          .collect::<Vec<&str>>();
         assert_eq!(recipe, "a");
+        assert_eq!(param_names, ["b", "c", "d"]);
         assert_eq!(found, 1);
         assert_eq!(min, 2);
         assert_eq!(max, 3);
@@ -391,11 +416,17 @@ a return code:
     {
       ArgumentCountMismatch {
         recipe,
+        parameters,
         found,
         min,
         max,
       } => {
+        let param_names = parameters
+          .iter()
+          .map(|p| p.name)
+          .collect::<Vec<&str>>();
         assert_eq!(recipe, "a");
+        assert_eq!(param_names, ["b", "c", "d"]);
         assert_eq!(found, 0);
         assert_eq!(min, 1);
         assert_eq!(max, 3);
diff --git a/src/runtime_error.rs b/src/runtime_error.rs
index 3b2513ab..277f4e48 100644
--- a/src/runtime_error.rs
+++ b/src/runtime_error.rs
@@ -23,7 +23,7 @@ fn write_token_error_context(f: &mut fmt::Formatter, token: &Token) -> Result<()
 
 #[derive(Debug)]
 pub enum RuntimeError<'a> {
-  ArgumentCountMismatch{recipe: &'a str, found: usize, min: usize, max: usize},
+  ArgumentCountMismatch{recipe: &'a str, parameters: Vec<&'a Parameter<'a>>, found: usize, min: usize, max: usize},
   Backtick{token: Token<'a>, output_error: OutputError},
   Code{recipe: &'a str, line_number: Option<usize>, code: i32},
   Cygpath{recipe: &'a str, output_error: OutputError},
@@ -71,7 +71,7 @@ impl<'a> Display for RuntimeError<'a> {
                   maybe_s(overrides.len()),
                   And(&overrides.iter().map(Tick).collect::<Vec<_>>()))?;
       },
-      ArgumentCountMismatch{recipe, found, min, max} => {
+      ArgumentCountMismatch{recipe, ref parameters, found, min, max} => {
         if min == max {
           let expected = min;
           write!(f, "Recipe `{}` got {} argument{} but {}takes {}",
@@ -84,6 +84,14 @@ impl<'a> Display for RuntimeError<'a> {
           write!(f, "Recipe `{}` got {} argument{} but takes at most {}",
                     recipe, found, maybe_s(found), max)?;
         }
+        write!(f, "\nusage:\n    just {}", recipe)?;
+        for param in parameters {
+          if color.stderr().active() {
+            write!(f, " {:#}", param)?;
+          } else {
+            write!(f, " {}", param)?;
+          }
+        }
       },
       Code{recipe, line_number, code} => {
         if let Some(n) = line_number {


Test patch:
diff --git a/tests/integration.rs b/tests/integration.rs
index 62412fb1..a8d85b35 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -779,7 +779,7 @@ foo A B:
     ",
   args:     ("foo", "ONE"),
   stdout:   "",
-  stderr:   "error: Recipe `foo` got 1 argument but takes 2\n",
+  stderr:   "error: Recipe `foo` got 1 argument but takes 2\nusage:\n    just foo A B\n",
   status:   EXIT_FAILURE,
 }
 
@@ -803,7 +803,7 @@ foo A B C='C':
     ",
   args:     ("foo", "bar"),
   stdout:   "",
-  stderr:   "error: Recipe `foo` got 1 argument but takes at least 2\n",
+  stderr:   "error: Recipe `foo` got 1 argument but takes at least 2\nusage:\n    just foo A B C='C'\n",
   status:   EXIT_FAILURE,
 }
 
@@ -1670,7 +1670,7 @@ a x y +z:
 ",
   args:     ("a", "0", "1"),
   stdout:   "",
-  stderr:   "error: Recipe `a` got 2 arguments but takes at least 3\n",
+  stderr:   "error: Recipe `a` got 2 arguments but takes at least 3\nusage:\n    just a x y +z\n",
   status:   EXIT_FAILURE,
 }