Repository: casey/just (rust)

Issue:
--choose doesnt recognize modules
```just
#!/usr/bin/env -S just --justfile

mod dev "just/dev.just"

set shell := ["bash", "-uc"]

default:
  @just --choose --justfile {{justfile()}}
```

```shell
just
```

modules in a justfile are not shown by the chooser

Pull request description:
Show submodule recipes in --choose
Fixes #2016.

Patch:
diff --git a/src/namepath.rs b/src/namepath.rs
index 899b32fb..6d4a7985 100644
--- a/src/namepath.rs
+++ b/src/namepath.rs
@@ -9,20 +9,23 @@ impl<'src> Namepath<'src> {
   }
 }
 
-impl<'str> Serialize for Namepath<'str> {
-  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-  where
-    S: Serializer,
-  {
-    let mut path = String::new();
-
+impl<'src> Display for Namepath<'src> {
+  fn fmt(&self, f: &mut Formatter) -> fmt::Result {
     for (i, name) in self.0.iter().enumerate() {
       if i > 0 {
-        path.push_str("::");
+        write!(f, "::")?;
       }
-      path.push_str(name.lexeme());
+      write!(f, "{name}")?;
     }
+    Ok(())
+  }
+}
 
-    serializer.serialize_str(&path)
+impl<'src> Serialize for Namepath<'src> {
+  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+  where
+    S: Serializer,
+  {
+    serializer.serialize_str(&format!("{self}"))
   }
 }
diff --git a/src/subcommand.rs b/src/subcommand.rs
index ce4e756c..5a695bf7 100644
--- a/src/subcommand.rs
+++ b/src/subcommand.rs
@@ -209,12 +209,17 @@ impl Subcommand {
     overrides: &BTreeMap<String, String>,
     chooser: Option<&str>,
   ) -> Result<(), Error<'src>> {
-    let recipes = justfile
-      .public_recipes(config.unsorted)
-      .iter()
-      .filter(|recipe| recipe.min_arguments() == 0)
-      .copied()
-      .collect::<Vec<&Recipe<Dependency>>>();
+    let mut recipes = Vec::<&Recipe<Dependency>>::new();
+    let mut stack = vec![justfile];
+    while let Some(module) = stack.pop() {
+      recipes.extend(
+        module
+          .public_recipes(config.unsorted)
+          .iter()
+          .filter(|recipe| recipe.min_arguments() == 0),
+      );
+      stack.extend(module.modules.values());
+    }
 
     if recipes.is_empty() {
       return Err(Error::NoChoosableRecipes);
@@ -249,7 +254,7 @@ impl Subcommand {
         .stdin
         .as_mut()
         .expect("Child was created with piped stdio")
-        .write_all(format!("{}\n", recipe.name).as_bytes())
+        .write_all(format!("{}\n", recipe.namepath).as_bytes())
       {
         return Err(Error::ChooserWrite { io_error, chooser });
       }


Test patch:
diff --git a/tests/choose.rs b/tests/choose.rs
index 892045cf..0ba1ae39 100644
--- a/tests/choose.rs
+++ b/tests/choose.rs
@@ -80,6 +80,23 @@ fn skip_private_recipes() {
     .run();
 }
 
+#[test]
+fn recipes_in_submodules_can_be_chosen() {
+  Test::new()
+    .args(["--unstable", "--choose"])
+    .env("JUST_CHOOSER", "head -n10")
+    .write("bar.just", "baz:\n echo BAZ")
+    .test_round_trip(false)
+    .justfile(
+      "
+        mod bar
+      ",
+    )
+    .stderr("echo BAZ\n")
+    .stdout("BAZ\n")
+    .run();
+}
+
 #[test]
 fn skip_recipes_that_require_arguments() {
   Test::new()