Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show recipes in submodules with --show RECIPE::PATH #2111

Merged
merged 4 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions completions/just.elvish
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ set edit:completion:arg-completer[just] = {|@words|
cand -c 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set'
cand --command 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set'
cand --completions 'Print shell completion script for <SHELL>'
cand -l 'List available recipes and their arguments'
cand --list 'List available recipes and their arguments'
cand -s 'Show information about <RECIPE>'
cand --show 'Show information about <RECIPE>'
cand -l 'List available recipes'
cand --list 'List available recipes'
cand -s 'Show recipe at <PATH>'
cand --show 'Show recipe at <PATH>'
cand --dotenv-filename 'Search for environment file named <DOTENV-FILENAME> instead of `.env`'
cand -E 'Load <DOTENV-PATH> as environment file instead of searching for one'
cand --dotenv-path 'Load <DOTENV-PATH> as environment file instead of searching for one'
Expand Down
4 changes: 2 additions & 2 deletions completions/just.fish
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ complete -c just -l shell-arg -d 'Invoke shell with <SHELL-ARG> as an argument'
complete -c just -s d -l working-directory -d 'Use <WORKING-DIRECTORY> as working directory. --justfile must also be set' -r -F
complete -c just -s c -l command -d 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set' -r
complete -c just -l completions -d 'Print shell completion script for <SHELL>' -r -f -a "{bash '',elvish '',fish '',powershell '',zsh ''}"
complete -c just -s l -l list -d 'List available recipes and their arguments' -r
complete -c just -s s -l show -d 'Show information about <RECIPE>' -r
complete -c just -s l -l list -d 'List available recipes' -r
complete -c just -s s -l show -d 'Show recipe at <PATH>' -r
complete -c just -l dotenv-filename -d 'Search for environment file named <DOTENV-FILENAME> instead of `.env`' -r
complete -c just -s E -l dotenv-path -d 'Load <DOTENV-PATH> as environment file instead of searching for one' -r -F
complete -c just -l timestamp-format -d 'Timestamp format string' -r
Expand Down
8 changes: 4 additions & 4 deletions completions/just.powershell
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock {
[CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set')
[CompletionResult]::new('--command', 'command', [CompletionResultType]::ParameterName, 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set')
[CompletionResult]::new('--completions', 'completions', [CompletionResultType]::ParameterName, 'Print shell completion script for <SHELL>')
[CompletionResult]::new('-l', 'l', [CompletionResultType]::ParameterName, 'List available recipes and their arguments')
[CompletionResult]::new('--list', 'list', [CompletionResultType]::ParameterName, 'List available recipes and their arguments')
[CompletionResult]::new('-s', 's', [CompletionResultType]::ParameterName, 'Show information about <RECIPE>')
[CompletionResult]::new('--show', 'show', [CompletionResultType]::ParameterName, 'Show information about <RECIPE>')
[CompletionResult]::new('-l', 'l', [CompletionResultType]::ParameterName, 'List available recipes')
[CompletionResult]::new('--list', 'list', [CompletionResultType]::ParameterName, 'List available recipes')
[CompletionResult]::new('-s', 's', [CompletionResultType]::ParameterName, 'Show recipe at <PATH>')
[CompletionResult]::new('--show', 'show', [CompletionResultType]::ParameterName, 'Show recipe at <PATH>')
[CompletionResult]::new('--dotenv-filename', 'dotenv-filename', [CompletionResultType]::ParameterName, 'Search for environment file named <DOTENV-FILENAME> instead of `.env`')
[CompletionResult]::new('-E', 'E ', [CompletionResultType]::ParameterName, 'Load <DOTENV-PATH> as environment file instead of searching for one')
[CompletionResult]::new('--dotenv-path', 'dotenv-path', [CompletionResultType]::ParameterName, 'Load <DOTENV-PATH> as environment file instead of searching for one')
Expand Down
8 changes: 4 additions & 4 deletions completions/just.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ _just() {
'*-c+[Run an arbitrary command with the working directory, \`.env\`, overrides, and exports set]: : ' \
'*--command=[Run an arbitrary command with the working directory, \`.env\`, overrides, and exports set]: : ' \
'*--completions=[Print shell completion script for <SHELL>]:SHELL:(bash elvish fish powershell zsh)' \
'-l+[List available recipes and their arguments]' \
'--list=[List available recipes and their arguments]' \
'-s+[Show information about <RECIPE>]: :(_just_commands)' \
'--show=[Show information about <RECIPE>]: :(_just_commands)' \
'()-l+[List available recipes]' \
'()--list=[List available recipes]' \
'-s+[Show recipe at <PATH>]: :(_just_commands)' \
'--show=[Show recipe at <PATH>]: :(_just_commands)' \
'(-E --dotenv-path)--dotenv-filename=[Search for environment file named <DOTENV-FILENAME> instead of \`.env\`]: : ' \
'-E+[Load <DOTENV-PATH> as environment file instead of searching for one]: :_files' \
'--dotenv-path=[Load <DOTENV-PATH> as environment file instead of searching for one]: :_files' \
Expand Down
8 changes: 4 additions & 4 deletions src/completions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ pub(crate) const ZSH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[
r"'*--set=[Override <VARIABLE> with <VALUE>]: :(_just_variables)' \",
),
(
r"'()-s+[Show information about <RECIPE>]:RECIPE: ' \
'()--show=[Show information about <RECIPE>]:RECIPE: ' \",
r"'-s+[Show information about <RECIPE>]: :(_just_commands)' \
'--show=[Show information about <RECIPE>]: :(_just_commands)' \",
r"'()-s+[Show recipe at <PATH>]:PATH: ' \
'()--show=[Show recipe at <PATH>]:PATH: ' \",
r"'-s+[Show recipe at <PATH>]: :(_just_commands)' \
'--show=[Show recipe at <PATH>]: :(_just_commands)' \",
),
(
"'*::ARGUMENTS -- Overrides and recipe(s) to run, defaulting to the first recipe in the \
Expand Down
73 changes: 37 additions & 36 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use {
super::*,
clap::{
builder::{styling::AnsiColor, FalseyValueParser, PossibleValuesParser, Styles},
parser::ValuesRef,
value_parser, Arg, ArgAction, ArgGroup, ArgMatches, Command,
},
};
Expand Down Expand Up @@ -421,7 +422,8 @@ impl Config {
.num_args(0..)
.value_name("PATH")
.action(ArgAction::Set)
.help("List available recipes and their arguments"),
.conflicts_with(arg::ARGUMENTS)
.help("List available recipes"),
)
.arg(
Arg::new(cmd::GROUPS)
Expand All @@ -439,10 +441,11 @@ impl Config {
Arg::new(cmd::SHOW)
.short('s')
.long("show")
.num_args(1..)
.action(ArgAction::Set)
.value_name("RECIPE")
.value_name("PATH")
.conflicts_with(arg::ARGUMENTS)
.help("Show information about <RECIPE>"),
.help("Show recipe at <PATH>"),
)
.arg(
Arg::new(cmd::SUMMARY)
Expand Down Expand Up @@ -557,6 +560,18 @@ impl Config {
}
}

fn parse_module_path(path: ValuesRef<String>) -> ConfigResult<ModulePath> {
path
.clone()
.map(|s| (*s).as_str())
.collect::<Vec<&str>>()
.as_slice()
.try_into()
.map_err(|()| ConfigError::ModulePath {
path: path.cloned().collect(),
})
}

fn search_config(matches: &ArgMatches, positional: &Positional) -> ConfigResult<SearchConfig> {
if matches.get_flag(arg::GLOBAL_JUSTFILE) {
return Ok(SearchConfig::GlobalJustfile);
Expand Down Expand Up @@ -676,22 +691,16 @@ impl Config {
Subcommand::Init
} else if let Some(path) = matches.get_many::<String>(cmd::LIST) {
Subcommand::List {
path: path
.clone()
.map(|s| (*s).as_str())
.collect::<Vec<&str>>()
.as_slice()
.try_into()
.map_err(|()| ConfigError::ListPath {
path: path.cloned().collect(),
})?,
path: Self::parse_module_path(path)?,
}
} else if matches.get_flag(cmd::GROUPS) {
Subcommand::Groups
} else if matches.get_flag(cmd::MAN) {
Subcommand::Man
} else if let Some(name) = matches.get_one::<String>(cmd::SHOW).map(Into::into) {
Subcommand::Show { name }
} else if let Some(path) = matches.get_many::<String>(cmd::SHOW) {
Subcommand::Show {
path: Self::parse_module_path(path)?,
}
} else if matches.get_flag(cmd::EVALUATE) {
if positional.arguments.len() > 1 {
return Err(ConfigError::SubcommandArguments {
Expand Down Expand Up @@ -1298,36 +1307,42 @@ mod tests {
test! {
name: subcommand_list_long,
args: ["--list"],
subcommand: Subcommand::List{ path: ModulePath{ path: Vec::new(), spaced: false } },
subcommand: Subcommand::List{ path: ModulePath { path: Vec::new(), spaced: false } },
}

test! {
name: subcommand_list_short,
args: ["-l"],
subcommand: Subcommand::List{ path: ModulePath{ path: Vec::new(), spaced: false } },
subcommand: Subcommand::List{ path: ModulePath { path: Vec::new(), spaced: false } },
}

test! {
name: subcommand_list_arguments,
args: ["--list", "bar"],
subcommand: Subcommand::List{ path: ModulePath{ path: vec!["bar".into()], spaced: false } },
subcommand: Subcommand::List{ path: ModulePath { path: vec!["bar".into()], spaced: false } },
}

test! {
name: subcommand_show_long,
args: ["--show", "build"],
subcommand: Subcommand::Show { name: String::from("build") },
subcommand: Subcommand::Show { path: ModulePath { path: vec!["build".into()], spaced: false } },
}

test! {
name: subcommand_show_short,
args: ["-s", "build"],
subcommand: Subcommand::Show { name: String::from("build") },
subcommand: Subcommand::Show { path: ModulePath { path: vec!["build".into()], spaced: false } },
}

error! {
name: subcommand_show_no_arg,
args: ["--show"],
test! {
name: subcommand_show_multiple_args,
args: ["--show", "foo", "bar"],
subcommand: Subcommand::Show {
path: ModulePath {
path: vec!["foo".into(), "bar".into()],
spaced: true,
},
},
}

test! {
Expand Down Expand Up @@ -1602,20 +1617,6 @@ mod tests {
},
}

error_matches! {
name: show_arguments,
args: ["--show", "foo", "bar"],
error: error,
check: {
assert_eq!(error.kind(), clap::error::ErrorKind::ArgumentConflict);
assert_eq!(error.context().collect::<Vec<_>>(), vec![
(ContextKind::InvalidArg, &ContextValue::String("--show <RECIPE>".into())),
(ContextKind::PriorArg, &ContextValue::String("[ARGUMENTS]...".into())),
(ContextKind::Usage, &ContextValue::StyledStr("\u{1b}[33mUsage:\u{1b}[0m \u{1b}[32mjust\u{1b}[0m \u{1b}[32m--show\u{1b}[0m\u{1b}[32m \u{1b}[0m\u{1b}[32m<RECIPE>\u{1b}[0m \u{1b}[32m[ARGUMENTS]...\u{1b}[0m".into())),
]);
},
}

error! {
name: summary_arguments,
args: ["--summary", "bar"],
Expand Down
2 changes: 1 addition & 1 deletion src/config_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub(crate) enum ConfigError {
))]
Internal { message: String },
#[snafu(display("Invalid module path `{}`", path.join(" ")))]
ListPath { path: Vec<String> },
ModulePath { path: Vec<String> },
#[snafu(display(
"Path-prefixed recipes may not be used with `--working-directory` or `--justfile`."
))]
Expand Down
27 changes: 20 additions & 7 deletions src/subcommand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub(crate) enum Subcommand {
overrides: BTreeMap<String, String>,
},
Show {
name: String,
path: ModulePath,
},
Summary,
Variables,
Expand Down Expand Up @@ -91,7 +91,7 @@ impl Subcommand {
Format => Self::format(config, &search, src, ast)?,
Groups => Self::groups(config, justfile),
List { path } => Self::list_module(config, justfile, path)?,
Show { ref name } => Self::show(config, name, justfile)?,
Show { path } => Self::show(config, justfile, path)?,
Summary => Self::summary(config, justfile),
Variables => Self::variables(justfile),
Changelog | Completions { .. } | Edit | Init | Man | Run { .. } => unreachable!(),
Expand Down Expand Up @@ -636,19 +636,32 @@ impl Subcommand {
}
}

fn show<'src>(config: &Config, name: &str, justfile: &Justfile<'src>) -> Result<(), Error<'src>> {
if let Some(alias) = justfile.get_alias(name) {
let recipe = justfile.get_recipe(alias.target.name.lexeme()).unwrap();
fn show<'src>(
config: &Config,
mut module: &Justfile<'src>,
path: &ModulePath,
) -> Result<(), Error<'src>> {
for name in &path.path[0..path.path.len() - 1] {
module = module
.modules
.get(name)
.ok_or_else(|| Error::UnknownSubmodule { path: path.clone() })?;
}

let name = path.path.last().unwrap();

if let Some(alias) = module.get_alias(name) {
let recipe = module.get_recipe(alias.target.name.lexeme()).unwrap();
println!("{alias}");
println!("{}", recipe.color_display(config.color.stdout()));
Ok(())
} else if let Some(recipe) = justfile.get_recipe(name) {
} else if let Some(recipe) = module.get_recipe(name) {
println!("{}", recipe.color_display(config.color.stdout()));
Ok(())
} else {
Err(Error::UnknownRecipes {
recipes: vec![name.to_owned()],
suggestion: justfile.suggest_recipe(name),
suggestion: module.suggest_recipe(name),
})
}
}
Expand Down
24 changes: 24 additions & 0 deletions tests/show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,27 @@ a Z="\t z":
stderr: "error: Justfile does not contain recipe `fooooooo`.\n",
status: EXIT_FAILURE,
}

#[test]
fn show_recipe_at_path() {
Test::new()
.write("foo.just", "bar:\n @echo MODULE")
.justfile(
"
mod foo
",
)
.test_round_trip(false)
.args(["--unstable", "--show", "foo::bar"])
.stdout("bar:\n @echo MODULE\n")
.run();
}

#[test]
fn show_invalid_path() {
Test::new()
.args(["--show", "$hello"])
.stderr("error: Invalid module path `$hello`\n")
.status(1)
.run();
}