diff --git a/src/config.rs b/src/config.rs index 67f24524c4..356c663f05 100644 --- a/src/config.rs +++ b/src/config.rs @@ -16,6 +16,7 @@ pub(crate) struct Config { pub(crate) dotenv_path: Option, 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 "), ) + .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::(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::(arg::LIST_HEADING).unwrap().into(), diff --git a/src/recipe.rs b/src/recipe.rs index 78b3ef27fa..3976983aef 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); diff --git a/tests/explain.rs b/tests/explain.rs new file mode 100644 index 0000000000..541a42fc17 --- /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 3f8fd0d074..73f68fb949 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;