Repository: casey/just
Pull request #2319 (2024-08-25 11:50:57)

--explain option
Addresses https://github.com/casey/just/issues/1909


Patch:
diff --git a/src/config.rs b/src/config.rs
index 67f24524..356c663f 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -16,6 +16,7 @@ pub(crate) struct Config {
   pub(crate) dotenv_path: Option<PathBuf>,
   pub(crate) dry_run: bool,
   pub(crate) dump_format: DumpFormat,
+  pub(crate) explain: bool,
   pub(crate) highlight: bool,
   pub(crate) invocation_directory: PathBuf,
   pub(crate) list_heading: String,
@@ -88,6 +89,7 @@ mod arg {
   pub(crate) const DOTENV_PATH: &str = "DOTENV-PATH";
   pub(crate) const DRY_RUN: &str = "DRY-RUN";
   pub(crate) const DUMP_FORMAT: &str = "DUMP-FORMAT";
+  pub(crate) const EXPLAIN: &str = "EXPLAIN";
   pub(crate) const GLOBAL_JUSTFILE: &str = "GLOBAL-JUSTFILE";
   pub(crate) const HIGHLIGHT: &str = "HIGHLIGHT";
   pub(crate) const JUSTFILE: &str = "JUSTFILE";
@@ -206,6 +208,13 @@ impl Config {
           .value_name("FORMAT")
           .help("Dump justfile as <FORMAT>"),
       )
+      .arg(
+        Arg::new(arg::EXPLAIN)
+          .action(ArgAction::SetTrue)
+          .long("explain")
+          .env("JUST_EXPLAIN")
+          .help("Print recipe doc comment before running it"),
+      )
       .arg(
         Arg::new(arg::GLOBAL_JUSTFILE)
           .action(ArgAction::SetTrue)
@@ -685,6 +694,7 @@ impl Config {
     };
 
     let unstable = matches.get_flag(arg::UNSTABLE) || subcommand == Subcommand::Summary;
+    let explain = matches.get_flag(arg::EXPLAIN);
 
     Ok(Self {
       check: matches.get_flag(arg::CHECK),
@@ -702,6 +712,7 @@ impl Config {
         .get_one::<DumpFormat>(arg::DUMP_FORMAT)
         .unwrap()
         .clone(),
+      explain,
       highlight: !matches.get_flag(arg::NO_HIGHLIGHT),
       invocation_directory: env::current_dir().context(config_error::CurrentDirContext)?,
       list_heading: matches.get_one::<String>(arg::LIST_HEADING).unwrap().into(),
diff --git a/src/recipe.rs b/src/recipe.rs
index 78b3ef27..3976983a 100644
--- a/src/recipe.rs
+++ b/src/recipe.rs
@@ -153,14 +153,18 @@ impl<'src, D> Recipe<'src, D> {
   ) -> RunResult<'src, ()> {
     let config = &context.config;
 
+    let color = config.color.stderr().banner();
+    let prefix = color.prefix();
+    let suffix = color.suffix();
+
     if config.verbosity.loquacious() {
-      let color = config.color.stderr().banner();
-      eprintln!(
-        "{}===> Running recipe `{}`...{}",
-        color.prefix(),
-        self.name,
-        color.suffix()
-      );
+      eprintln!("{prefix}===> Running recipe `{}`...{suffix}", self.name);
+    }
+
+    if config.explain {
+      if let Some(doc) = self.doc() {
+        eprintln!("{prefix}#### {doc}{suffix}");
+      }
     }
 
     let evaluator = Evaluator::new(context, is_dependency, scope);


Test patch:
diff --git a/tests/explain.rs b/tests/explain.rs
new file mode 100644
index 00000000..541a42fc
--- /dev/null
+++ b/tests/explain.rs
@@ -0,0 +1,22 @@
+use super::*;
+
+#[test]
+fn explain_recipe() {
+  Test::new()
+    .justfile(
+      "
+      # List some fruits
+      fruits:
+        echo 'apple peach dragonfruit'
+    ",
+    )
+    .args(["--explain", "fruits"])
+    .stdout("apple peach dragonfruit\n")
+    .stderr(
+      "
+      #### List some fruits
+      echo 'apple peach dragonfruit'
+    ",
+    )
+    .run();
+}
diff --git a/tests/lib.rs b/tests/lib.rs
index 3f8fd0d0..73f68fb9 100644
--- a/tests/lib.rs
+++ b/tests/lib.rs
@@ -55,6 +55,7 @@ mod equals;
 mod error_messages;
 mod evaluate;
 mod examples;
+mod explain;
 mod export;
 mod fallback;
 mod fmt;