From 6c829cd1becfa6c6b9e03714b9d450337acff227 Mon Sep 17 00:00:00 2001 From: "Alexis (Poliorcetics) Bourget" Date: Tue, 9 Apr 2024 22:33:56 +0200 Subject: [PATCH 1/8] chore(deps): update clap to 3 This is to prepare for clap 4 --- Cargo.lock | 153 ++++++++++++++++++++++++++++--- Cargo.toml | 3 +- src/completions.rs | 26 +++--- src/config.rs | 224 +++++++++++++++++++++++++-------------------- src/lib.rs | 2 +- src/subcommand.rs | 14 ++- src/verbosity.rs | 2 +- tests/command.rs | 13 +-- tests/fmt.rs | 2 +- 9 files changed, 292 insertions(+), 147 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ae444b72d..eeb84f976b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -91,6 +91,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "bitflags" version = "1.3.2" @@ -171,13 +177,46 @@ dependencies = [ "ansi_term", "atty", "bitflags 1.3.2", - "strsim", - "term_size", - "textwrap", + "strsim 0.8.0", + "textwrap 0.11.0", "unicode-width", "vec_map", ] +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags 1.3.2", + "clap_lex", + "indexmap", + "strsim 0.10.0", + "termcolor", + "terminal_size", + "textwrap 0.16.1", +] + +[[package]] +name = "clap_complete" +version = "3.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f7a2e0a962c45ce25afce14220bc24f9dade0a1787f185cecf96bfba7847cd8" +dependencies = [ + "clap 3.2.25", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "colorchoice" version = "1.0.0" @@ -402,6 +441,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "heck" version = "0.3.3" @@ -447,6 +492,27 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "itoa" version = "1.0.10" @@ -461,7 +527,8 @@ dependencies = [ "atty", "blake3", "camino", - "clap", + "clap 3.2.25", + "clap_complete", "cradle", "ctrlc", "derivative", @@ -529,6 +596,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -590,6 +663,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + [[package]] name = "pretty_assertions" version = "1.4.0" @@ -747,6 +826,20 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + [[package]] name = "rustix" version = "0.38.31" @@ -756,7 +849,7 @@ dependencies = [ "bitflags 2.4.2", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.13", "windows-sys 0.52.0", ] @@ -857,13 +950,19 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "structopt" version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" dependencies = [ - "clap", + "clap 2.34.0", "lazy_static", "structopt-derive", ] @@ -939,7 +1038,7 @@ checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "rustix", + "rustix 0.38.31", "windows-sys 0.52.0", ] @@ -953,13 +1052,22 @@ dependencies = [ ] [[package]] -name = "term_size" -version = "0.3.2" +name = "termcolor" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ - "libc", - "winapi", + "winapi-util", +] + +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix 0.37.27", + "windows-sys 0.48.0", ] [[package]] @@ -968,10 +1076,18 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "term_size", "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +dependencies = [ + "terminal_size", +] + [[package]] name = "thiserror" version = "1.0.57" @@ -1080,7 +1196,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix", + "rustix 0.38.31", "windows-sys 0.52.0", ] @@ -1100,6 +1216,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 64a1537773..4983f647e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,8 @@ ansi_term = "0.12.0" atty = "0.2.0" blake3 = { version = "1.5.0", features = ["rayon", "mmap"] } camino = "1.0.4" -clap = { version = "2.33.0", features = ["wrap_help"] } +clap = { version = "3.0.0", features = ["wrap_help"] } +clap_complete = "3.0.0" ctrlc = { version = "3.1.1", features = ["termination"] } derivative = "2.0.0" dirs = "5.0.1" diff --git a/src/completions.rs b/src/completions.rs index 2964d76c07..4a8bf33469 100644 --- a/src/completions.rs +++ b/src/completions.rs @@ -43,21 +43,19 @@ pub(crate) const ZSH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ r" local common=(", ), ( - r"'*--set=[Override with ]' \", - r"'*--set[Override with ]: :_just_variables' \", + r"'--set=[Override with ]:VARIABLE: :VARIABLE: ' \", + r"'--set=[Override with ]: :(_just_variables)' \", ), ( - r"'-s+[Show information about ]' \ -'--show=[Show information about ]' \", - r"'-s+[Show information about ]: :_just_commands' \ -'--show=[Show information about ]: :_just_commands' \", + r"'()-s+[Show information about ]:RECIPE: ' \ +'()--show=[Show information about ]:RECIPE: ' \", + r"'-s+[Show information about ]: :(_just_commands)' \ +'--show=[Show information about ]: :(_just_commands)' \", ), ( - "'::ARGUMENTS -- Overrides and recipe(s) to run, defaulting to the first recipe in the \ - justfile:_files' \\ -&& ret=0 -\x20\x20\x20\x20 -", + "'*::ARGUMENTS -- Overrides and recipe(s) to run, defaulting to the first recipe in the \ + justfile:' \\ +&& ret=0", r#") _arguments "${_arguments_options[@]}" $common \ @@ -105,9 +103,7 @@ pub(crate) const ZSH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ "#, ), ( - " local commands; commands=( -\x20\x20\x20\x20\x20\x20\x20\x20 - )", + " local commands; commands=()", r#" [[ $PREFIX = -* ]] && return 1 integer ret=1 local variables; variables=( @@ -206,7 +202,7 @@ pub(crate) const BASH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ fi fi"#, ), - (r" just)", r#" "$1")"#), + (r" just)", r#" "$1")"#), ( r"local i cur prev opts cmds", r"local i cur prev words cword opts cmds", diff --git a/src/config.rs b/src/config.rs index 21a6cf8021..8af09bd370 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,6 @@ use { super::*, - clap::{App, AppSettings, Arg, ArgGroup, ArgMatches, ArgSettings}, + clap::{App, AppSettings, Arg, ArgAction, ArgGroup, ArgMatches, ArgSettings}, }; pub(crate) const CHOOSER_ENVIRONMENT_KEY: &str = "JUST_CHOOSER"; @@ -76,16 +76,7 @@ mod cmd { ]; pub(crate) const ARGLESS: &[&str] = &[ - CHANGELOG, - COMPLETIONS, - DUMP, - EDIT, - FORMAT, - INIT, - LIST, - SHOW, - SUMMARY, - VARIABLES, + CHANGELOG, DUMP, EDIT, FORMAT, INIT, LIST, SUMMARY, VARIABLES, ]; } @@ -147,8 +138,9 @@ mod arg { } impl Config { - pub(crate) fn app() -> App<'static, 'static> { + pub(crate) fn app() -> App<'static> { let app = App::new(env!("CARGO_PKG_NAME")) + .bin_name(env!("CARGO_PKG_NAME")) .help_message("Print help information") .version_message("Print version information") .setting(AppSettings::ColoredHelp) @@ -156,19 +148,20 @@ impl Config { .arg( Arg::with_name(arg::CHECK) .long("check") + .action(ArgAction::SetTrue) .requires(cmd::FORMAT) .help("Run `--fmt` in 'check' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required."), ) .arg( Arg::with_name(arg::CHOOSER) .long("chooser") - .takes_value(true) + .action(ArgAction::Set) .help("Override binary invoked by `--choose`"), ) .arg( Arg::with_name(arg::COLOR) .long("color") - .takes_value(true) + .action(ArgAction::Set) .possible_values(arg::COLOR_VALUES) .default_value(arg::COLOR_AUTO) .help("Print colorful output"), @@ -176,22 +169,23 @@ impl Config { .arg( Arg::with_name(arg::COMMAND_COLOR) .long("command-color") - .takes_value(true) + .action(ArgAction::Set) .possible_values(arg::COMMAND_COLOR_VALUES) .help("Echo recipe lines in "), ) - .arg(Arg::with_name(arg::YES).long("yes").help("Automatically confirm all recipes.")) + .arg(Arg::with_name(arg::YES).long("yes").action(ArgAction::SetTrue).help("Automatically confirm all recipes.")) .arg( Arg::with_name(arg::DRY_RUN) - .short("n") + .short('n') .long("dry-run") + .action(ArgAction::SetTrue) .help("Print what just would do without doing it") .conflicts_with(arg::QUIET), ) .arg( Arg::with_name(arg::DUMP_FORMAT) .long("dump-format") - .takes_value(true) + .action(ArgAction::Set) .possible_values(arg::DUMP_FORMAT_VALUES) .default_value(arg::DUMP_FORMAT_JUST) .value_name("FORMAT") @@ -200,6 +194,7 @@ impl Config { .arg( Arg::with_name(arg::HIGHLIGHT) .long("highlight") + .action(ArgAction::SetTrue) .help("Highlight echoed recipe lines in bold") .overrides_with(arg::NO_HIGHLIGHT), ) @@ -208,14 +203,14 @@ impl Config { .long("list-heading") .help("Print before list") .value_name("TEXT") - .takes_value(true), + .action(ArgAction::Set), ) .arg( Arg::with_name(arg::LIST_PREFIX) .long("list-prefix") .help("Print before each list item") .value_name("TEXT") - .takes_value(true), + .action(ArgAction::Set), ) .arg( Arg::with_name(arg::NO_ALIASES) @@ -226,54 +221,55 @@ impl Config { Arg::with_name(arg::NO_DEPS) .long("no-deps") .alias("no-dependencies") + .action(ArgAction::SetTrue) .help("Don't run recipe dependencies") ) .arg( Arg::with_name(arg::NO_DOTENV) .long("no-dotenv") + .action(ArgAction::SetTrue) .help("Don't load `.env` file"), ) .arg( Arg::with_name(arg::NO_HIGHLIGHT) .long("no-highlight") + .action(ArgAction::SetTrue) .help("Don't highlight echoed recipe lines in bold") .overrides_with(arg::HIGHLIGHT), ) .arg( Arg::with_name(arg::JUSTFILE) - .short("f") + .short('f') .long("justfile") - .takes_value(true) + .action(ArgAction::Set) .help("Use as justfile"), ) .arg( Arg::with_name(arg::QUIET) - .short("q") + .short('q') .long("quiet") + .action(ArgAction::SetTrue) .help("Suppress all output") .conflicts_with(arg::DRY_RUN), ) .arg( Arg::with_name(arg::SET) .long("set") - .takes_value(true) + .action(ArgAction::Append) .number_of_values(2) .value_names(&["VARIABLE", "VALUE"]) - .multiple(true) .help("Override with "), ) .arg( Arg::with_name(arg::SHELL) .long("shell") - .takes_value(true) + .action(ArgAction::Set) .help("Invoke to run recipes"), ) .arg( Arg::with_name(arg::SHELL_ARG) .long("shell-arg") - .takes_value(true) - .multiple(true) - .number_of_values(1) + .action(ArgAction::Append) .allow_hyphen_values(true) .overrides_with(arg::CLEAR_SHELL_ARGS) .help("Invoke shell with as an argument"), @@ -282,52 +278,59 @@ impl Config { Arg::with_name(arg::SHELL_COMMAND) .long("shell-command") .requires(cmd::COMMAND) + .action(ArgAction::SetTrue) .help("Invoke with the shell used to run recipe lines and backticks"), ) .arg( Arg::with_name(arg::CLEAR_SHELL_ARGS) .long("clear-shell-args") + .action(ArgAction::SetTrue) .overrides_with(arg::SHELL_ARG) .help("Clear shell arguments"), ) .arg( Arg::with_name(arg::UNSORTED) .long("unsorted") - .short("u") + .short('u') + .action(ArgAction::SetTrue) .help("Return list and summary entries in source order"), ) .arg( Arg::with_name(arg::UNSTABLE) .long("unstable") + .action(ArgAction::SetTrue) .help("Enable unstable features"), ) .arg( Arg::with_name(arg::VERBOSE) - .short("v") + .short('v') .long("verbose") - .multiple(true) + .action(ArgAction::Count) .help("Use verbose output"), ) .arg( Arg::with_name(arg::WORKING_DIRECTORY) - .short("d") + .short('d') .long("working-directory") - .takes_value(true) + .action(ArgAction::Set) .help("Use as working directory. --justfile must also be set") .requires(arg::JUSTFILE), ) .arg( Arg::with_name(cmd::CHANGELOG) .long("changelog") + .action(ArgAction::SetTrue) .help("Print changelog"), ) - .arg(Arg::with_name(cmd::CHOOSE).long("choose").help(CHOOSE_HELP)) + .arg(Arg::with_name(cmd::CHOOSE).long("choose").action(ArgAction::SetTrue).help(CHOOSE_HELP)) .arg( Arg::with_name(cmd::COMMAND) .long("command") - .short("c") + .short('c') .min_values(1) .allow_hyphen_values(true) + .action(ArgAction::Append) + .value_parser(clap::value_parser!(std::ffi::OsString)) .help( "Run an arbitrary command with the working directory, `.env`, overrides, and exports \ set", @@ -336,81 +339,96 @@ impl Config { .arg( Arg::with_name(cmd::COMPLETIONS) .long("completions") - .takes_value(true) + .action(ArgAction::Append) + .min_values(1) .value_name("SHELL") - .possible_values(&clap::Shell::variants()) + .possible_values(clap_complete::Shell::possible_values()) .set(ArgSettings::CaseInsensitive) .help("Print shell completion script for "), ) .arg( Arg::with_name(cmd::DUMP) .long("dump") + .action(ArgAction::SetTrue) .help("Print justfile"), ) .arg( Arg::with_name(cmd::EDIT) - .short("e") + .short('e') .long("edit") + .action(ArgAction::SetTrue) .help("Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`"), ) - .arg(Arg::with_name(cmd::EVALUATE).long("evaluate").help( - "Evaluate and print all variables. If a variable name is given as an argument, only print \ - that variable's value.", - )) + .arg( + Arg::with_name(cmd::EVALUATE) + .long("evaluate") + .action(ArgAction::SetTrue) + .help( + "Evaluate and print all variables. If a variable name is given as an argument, only \ + print that variable's value.", + ), + ) .arg( Arg::with_name(cmd::FORMAT) .long("fmt") .alias("format") + .action(ArgAction::SetTrue) .help("Format and overwrite justfile"), ) .arg( Arg::with_name(cmd::INIT) .long("init") .alias("initialize") + .action(ArgAction::SetTrue) .help("Initialize new justfile in project root"), ) .arg( Arg::with_name(cmd::LIST) - .short("l") + .short('l') .long("list") + .action(ArgAction::SetTrue) .help("List available recipes and their arguments"), ) .arg( Arg::with_name(cmd::SHOW) - .short("s") + .short('s') .long("show") - .takes_value(true) + .action(ArgAction::Set) .value_name("RECIPE") + .conflicts_with(arg::ARGUMENTS) .help("Show information about "), ) .arg( Arg::with_name(cmd::SUMMARY) .long("summary") + .action(ArgAction::SetTrue) .help("List names of available recipes"), ) .arg( Arg::with_name(cmd::VARIABLES) .long("variables") + .action(ArgAction::SetTrue) .help("List names of variables"), ) .arg( Arg::with_name(arg::DOTENV_FILENAME) .long("dotenv-filename") - .takes_value(true) + .action(ArgAction::Set) .help("Search for environment file named instead of `.env`") .conflicts_with(arg::DOTENV_PATH), ) .arg( Arg::with_name(arg::DOTENV_PATH) - .short("E") + .short('E') .long("dotenv-path") + .action(ArgAction::Set) .help("Load as environment file instead of searching for one") - .takes_value(true), ) .group(ArgGroup::with_name("SUBCOMMAND").args(cmd::ALL)) .arg( Arg::with_name(arg::ARGUMENTS) - .multiple(true) + .multiple_values(true) + .action(ArgAction::Append) .help("Overrides and recipe(s) to run, defaulting to the first recipe in the justfile"), ); @@ -487,24 +505,19 @@ impl Config { pub(crate) fn from_matches(matches: &ArgMatches) -> ConfigResult { let invocation_directory = env::current_dir().context(config_error::CurrentDirContext)?; - let verbosity = if matches.is_present(arg::QUIET) { + let verbosity = if matches.get_flag(arg::QUIET) { Verbosity::Quiet } else { - Verbosity::from_flag_occurrences(matches.occurrences_of(arg::VERBOSE)) + Verbosity::from_flag_occurrences(matches.get_count(arg::VERBOSE)) }; let color = Self::color_from_matches(matches)?; let command_color = Self::command_color_from_matches(matches)?; - let set_count = matches.occurrences_of(arg::SET); let mut overrides = BTreeMap::new(); - if set_count > 0 { - let mut values = matches.values_of(arg::SET).unwrap(); - for _ in 0..set_count { - overrides.insert( - values.next().unwrap().to_owned(), - values.next().unwrap().to_owned(), - ); + if let Some(mut values) = matches.get_many::(arg::SET) { + while let (Some(k), Some(v)) = (values.next(), values.next()) { + overrides.insert(k.into(), v.into()); } } @@ -543,7 +556,7 @@ impl Config { }; for subcommand in cmd::ARGLESS { - if matches.is_present(subcommand) { + if matches.get_flag(subcommand) { match (!overrides.is_empty(), !positional.arguments.is_empty()) { (false, false) => {} (true, false) => { @@ -569,9 +582,9 @@ impl Config { } } - let subcommand = if matches.is_present(cmd::CHANGELOG) { + let subcommand = if matches.get_flag(cmd::CHANGELOG) { Subcommand::Changelog - } else if matches.is_present(cmd::CHOOSE) { + } else if matches.get_flag(cmd::CHOOSE) { Subcommand::Choose { chooser: matches.value_of(arg::CHOOSER).map(str::to_owned), overrides, @@ -587,23 +600,23 @@ impl Config { Subcommand::Completions { shell: shell.to_owned(), } - } else if matches.is_present(cmd::EDIT) { + } else if matches.get_flag(cmd::EDIT) { Subcommand::Edit - } else if matches.is_present(cmd::SUMMARY) { + } else if matches.get_flag(cmd::SUMMARY) { Subcommand::Summary - } else if matches.is_present(cmd::DUMP) { + } else if matches.get_flag(cmd::DUMP) { Subcommand::Dump - } else if matches.is_present(cmd::FORMAT) { + } else if matches.get_flag(cmd::FORMAT) { Subcommand::Format - } else if matches.is_present(cmd::INIT) { + } else if matches.get_flag(cmd::INIT) { Subcommand::Init - } else if matches.is_present(cmd::LIST) { + } else if matches.get_flag(cmd::LIST) { Subcommand::List } else if let Some(name) = matches.value_of(cmd::SHOW) { Subcommand::Show { name: name.to_owned(), } - } else if matches.is_present(cmd::EVALUATE) { + } else if matches.get_flag(cmd::EVALUATE) { if positional.arguments.len() > 1 { return Err(ConfigError::SubcommandArguments { subcommand: cmd::EVALUATE, @@ -619,7 +632,7 @@ impl Config { variable: positional.arguments.into_iter().next(), overrides, } - } else if matches.is_present(cmd::VARIABLES) { + } else if matches.get_flag(cmd::VARIABLES) { Subcommand::Variables } else { Subcommand::Run { @@ -628,34 +641,28 @@ impl Config { } }; - let shell_args = if matches.occurrences_of(arg::SHELL_ARG) > 0 - || matches.occurrences_of(arg::CLEAR_SHELL_ARGS) > 0 - { - Some( - matches - .values_of(arg::SHELL_ARG) - .map_or(Vec::new(), |shell_args| { - shell_args.map(str::to_owned).collect() - }), - ) + let shell_args = if matches.get_flag(arg::CLEAR_SHELL_ARGS) { + Some(Vec::new()) } else { - None + matches + .get_many::(arg::SHELL_ARG) + .map(|s| s.map(Into::into).collect()) }; - let unstable = matches.is_present(arg::UNSTABLE) + let unstable = matches.get_flag(arg::UNSTABLE) || env::var_os("JUST_UNSTABLE") .map(|val| !(val == "false" || val == "0" || val.is_empty())) .unwrap_or_default(); Ok(Self { - check: matches.is_present(arg::CHECK), + check: matches.get_flag(arg::CHECK), color, command_color, dotenv_filename: matches.value_of(arg::DOTENV_FILENAME).map(str::to_owned), dotenv_path: matches.value_of(arg::DOTENV_PATH).map(PathBuf::from), - dry_run: matches.is_present(arg::DRY_RUN), + dry_run: matches.get_flag(arg::DRY_RUN), dump_format: Self::dump_format_from_matches(matches)?, - highlight: !matches.is_present(arg::NO_HIGHLIGHT), + highlight: !matches.get_flag(arg::NO_HIGHLIGHT), invocation_directory, list_heading: matches .value_of(arg::LIST_HEADING) @@ -671,12 +678,12 @@ impl Config { search_config, shell: matches.value_of(arg::SHELL).map(str::to_owned), shell_args, - shell_command: matches.is_present(arg::SHELL_COMMAND), + shell_command: matches.get_flag(arg::SHELL_COMMAND), subcommand, - unsorted: matches.is_present(arg::UNSORTED), + unsorted: matches.get_flag(arg::UNSORTED), unstable, verbosity, - yes: matches.is_present(arg::YES), + yes: matches.get_flag(arg::YES), }) } @@ -748,6 +755,7 @@ mod tests { } } + #[track_caller] fn test(arguments: &[&str], want: Config) { let app = Config::app(); let matches = app @@ -799,6 +807,30 @@ mod tests { } } + macro_rules! error_matches { + ( + name: $name:ident, + args: [$($arg:expr),*], + error: $error:pat, + $(check: $check:block,)? + ) => { + #[test] + fn $name() { + let arguments = &[ + "just", + $($arg,)* + ]; + + let app = Config::app(); + + match app.get_matches_from_safe(arguments) { + Err($error) => { $($check)? } + other => panic!("Unexpected result from get matches: {other:?}") + } + } + }; + } + macro_rules! map { {} => { BTreeMap::new() @@ -1400,13 +1432,12 @@ mod tests { error: ConfigError::SearchDirConflict, } - error! { + error_matches! { name: completions_arguments, args: ["--completions", "zsh", "foo"], - error: ConfigError::SubcommandArguments { subcommand, arguments }, + error: clap::Error { kind: clap::ErrorKind::InvalidValue, info, .. }, check: { - assert_eq!(subcommand, cmd::COMPLETIONS); - assert_eq!(arguments, &["foo"]); + assert_eq!(info, &["--completions ...", "foo", "bash", "elvish", "fish", "powershell", "zsh"]); }, } @@ -1490,13 +1521,12 @@ mod tests { }, } - error! { + error_matches! { name: show_arguments, args: ["--show", "foo", "bar"], - error: ConfigError::SubcommandArguments { subcommand, arguments }, + error: clap::Error { kind: clap::ErrorKind::ArgumentConflict, info, .. }, check: { - assert_eq!(subcommand, cmd::SHOW); - assert_eq!(arguments, &["bar"]); + assert_eq!(info, &["..."]); }, } diff --git a/src/lib.rs b/src/lib.rs index 445e819019..7f113ca678 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,7 +44,7 @@ pub(crate) use { ffi::{OsStr, OsString}, fmt::{self, Debug, Display, Formatter}, fs, - io::{self, Cursor, Write}, + io::{self, Write}, iter::{self, FromIterator}, mem, ops::Deref, diff --git a/src/subcommand.rs b/src/subcommand.rs index 22102a502f..a680968b6f 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -50,7 +50,7 @@ impl Subcommand { Self::changelog(); return Ok(()); } - Completions { shell } => return Self::completions(shell), + Completions { shell } => return Self::completions(crate::config::Config::app(), shell), Init => return Self::init(config), Run { arguments, @@ -275,8 +275,8 @@ impl Subcommand { justfile.run(config, search, overrides, &recipes) } - fn completions(shell: &str) -> RunResult<'static, ()> { - use clap::Shell; + fn completions(command: clap::Command<'_>, shell: &str) -> RunResult<'static, ()> { + use clap_complete::{Generator, Shell}; fn replace(haystack: &mut String, needle: &str, replacement: &str) -> RunResult<'static, ()> { if let Some(index) = haystack.find(needle) { @@ -293,10 +293,8 @@ impl Subcommand { .parse::() .expect("Invalid value for clap::Shell"); - let buffer = Vec::new(); - let mut cursor = Cursor::new(buffer); - Config::app().gen_completions_to(env!("CARGO_PKG_NAME"), shell, &mut cursor); - let buffer = cursor.into_inner(); + let mut buffer = Vec::new(); + shell.generate(&command, &mut buffer); let mut script = String::from_utf8(buffer).expect("Clap completion not UTF-8"); match shell { @@ -319,7 +317,7 @@ impl Subcommand { replace(&mut script, needle, replacement)?; } } - Shell::Elvish => {} + _ => {} } println!("{}", script.trim()); diff --git a/src/verbosity.rs b/src/verbosity.rs index 0461a50584..4fc8c0df9f 100644 --- a/src/verbosity.rs +++ b/src/verbosity.rs @@ -9,7 +9,7 @@ pub(crate) enum Verbosity { } impl Verbosity { - pub(crate) fn from_flag_occurrences(flag_occurrences: u64) -> Self { + pub(crate) fn from_flag_occurrences(flag_occurrences: u8) -> Self { match flag_occurrences { 0 => Taciturn, 1 => Loquacious, diff --git a/tests/command.rs b/tests/command.rs index c1c9473ef8..4a956945d2 100644 --- a/tests/command.rs +++ b/tests/command.rs @@ -39,17 +39,12 @@ test! { echo XYZ ", args: ("--command"), - stderr: &format!(" - error: The argument '--command ' requires a value but none was supplied - - USAGE: - just{EXE_SUFFIX} --color --dump-format --shell \ - <--changelog|--choose|--command |--completions |--dump|--edit|\ - --evaluate|--fmt|--init|--list|--show |--summary|--variables> + stderr: " + error: The argument '--command ...' requires a value but none was supplied For more information try --help - "), - status: EXIT_FAILURE, + ", + status: 2, } test! { diff --git a/tests/fmt.rs b/tests/fmt.rs index 3ad46f384b..0c5e16ff95 100644 --- a/tests/fmt.rs +++ b/tests/fmt.rs @@ -18,7 +18,7 @@ test! { stderr_regex: "error: The following required arguments were not provided: --fmt (.|\\n)+", - status: EXIT_FAILURE, + status: 2, } test! { From 032b3d4a5f0452e8d9d287917fb378f170ad1da9 Mon Sep 17 00:00:00 2001 From: "Alexis (Poliorcetics) Bourget" Date: Tue, 9 Apr 2024 22:34:16 +0200 Subject: [PATCH 2/8] chore(deps): resolve deprecation warnings for clap 3 --- src/config.rs | 211 +++++++++++++++++++++++++--------------------- src/function.rs | 5 +- src/lib.rs | 2 +- src/subcommand.rs | 39 ++++++--- src/testing.rs | 2 +- tests/test.rs | 1 + 6 files changed, 151 insertions(+), 109 deletions(-) diff --git a/src/config.rs b/src/config.rs index 8af09bd370..b388cd4e5f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,9 @@ use { super::*, - clap::{App, AppSettings, Arg, ArgAction, ArgGroup, ArgMatches, ArgSettings}, + clap::{ + builder::PossibleValuesParser, value_parser, AppSettings, Arg, ArgAction, ArgGroup, ArgMatches, + Command, + }, }; pub(crate) const CHOOSER_ENVIRONMENT_KEY: &str = "JUST_CHOOSER"; @@ -138,44 +141,45 @@ mod arg { } impl Config { - pub(crate) fn app() -> App<'static> { - let app = App::new(env!("CARGO_PKG_NAME")) + pub(crate) fn app() -> Command<'static> { + let app = Command::new(env!("CARGO_PKG_NAME")) .bin_name(env!("CARGO_PKG_NAME")) .help_message("Print help information") .version_message("Print version information") .setting(AppSettings::ColoredHelp) .setting(AppSettings::TrailingVarArg) + .trailing_var_arg(true) .arg( - Arg::with_name(arg::CHECK) + Arg::new(arg::CHECK) .long("check") .action(ArgAction::SetTrue) .requires(cmd::FORMAT) .help("Run `--fmt` in 'check' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required."), ) .arg( - Arg::with_name(arg::CHOOSER) + Arg::new(arg::CHOOSER) .long("chooser") .action(ArgAction::Set) .help("Override binary invoked by `--choose`"), ) .arg( - Arg::with_name(arg::COLOR) + Arg::new(arg::COLOR) .long("color") .action(ArgAction::Set) - .possible_values(arg::COLOR_VALUES) + .value_parser(PossibleValuesParser::new(arg::COLOR_VALUES)) .default_value(arg::COLOR_AUTO) .help("Print colorful output"), ) .arg( - Arg::with_name(arg::COMMAND_COLOR) + Arg::new(arg::COMMAND_COLOR) .long("command-color") .action(ArgAction::Set) - .possible_values(arg::COMMAND_COLOR_VALUES) + .value_parser(PossibleValuesParser::new(arg::COMMAND_COLOR_VALUES)) .help("Echo recipe lines in "), ) - .arg(Arg::with_name(arg::YES).long("yes").action(ArgAction::SetTrue).help("Automatically confirm all recipes.")) + .arg(Arg::new(arg::YES).long("yes").action(ArgAction::SetTrue).help("Automatically confirm all recipes.")) .arg( - Arg::with_name(arg::DRY_RUN) + Arg::new(arg::DRY_RUN) .short('n') .long("dry-run") .action(ArgAction::SetTrue) @@ -183,30 +187,30 @@ impl Config { .conflicts_with(arg::QUIET), ) .arg( - Arg::with_name(arg::DUMP_FORMAT) + Arg::new(arg::DUMP_FORMAT) .long("dump-format") .action(ArgAction::Set) - .possible_values(arg::DUMP_FORMAT_VALUES) + .value_parser(PossibleValuesParser::new(arg::DUMP_FORMAT_VALUES)) .default_value(arg::DUMP_FORMAT_JUST) .value_name("FORMAT") .help("Dump justfile as "), ) .arg( - Arg::with_name(arg::HIGHLIGHT) + Arg::new(arg::HIGHLIGHT) .long("highlight") .action(ArgAction::SetTrue) .help("Highlight echoed recipe lines in bold") .overrides_with(arg::NO_HIGHLIGHT), ) .arg( - Arg::with_name(arg::LIST_HEADING) + Arg::new(arg::LIST_HEADING) .long("list-heading") .help("Print before list") .value_name("TEXT") .action(ArgAction::Set), ) .arg( - Arg::with_name(arg::LIST_PREFIX) + Arg::new(arg::LIST_PREFIX) .long("list-prefix") .help("Print before each list item") .value_name("TEXT") @@ -218,34 +222,35 @@ impl Config { .help("Don't show aliases in list") ) .arg ( - Arg::with_name(arg::NO_DEPS) + Arg::new(arg::NO_DEPS) .long("no-deps") .alias("no-dependencies") .action(ArgAction::SetTrue) .help("Don't run recipe dependencies") ) .arg( - Arg::with_name(arg::NO_DOTENV) + Arg::new(arg::NO_DOTENV) .long("no-dotenv") .action(ArgAction::SetTrue) .help("Don't load `.env` file"), ) .arg( - Arg::with_name(arg::NO_HIGHLIGHT) + Arg::new(arg::NO_HIGHLIGHT) .long("no-highlight") .action(ArgAction::SetTrue) .help("Don't highlight echoed recipe lines in bold") .overrides_with(arg::HIGHLIGHT), ) .arg( - Arg::with_name(arg::JUSTFILE) + Arg::new(arg::JUSTFILE) .short('f') .long("justfile") .action(ArgAction::Set) + .value_parser(value_parser!(PathBuf)) .help("Use as justfile"), ) .arg( - Arg::with_name(arg::QUIET) + Arg::new(arg::QUIET) .short('q') .long("quiet") .action(ArgAction::SetTrue) @@ -253,7 +258,7 @@ impl Config { .conflicts_with(arg::DRY_RUN), ) .arg( - Arg::with_name(arg::SET) + Arg::new(arg::SET) .long("set") .action(ArgAction::Append) .number_of_values(2) @@ -261,13 +266,13 @@ impl Config { .help("Override with "), ) .arg( - Arg::with_name(arg::SHELL) + Arg::new(arg::SHELL) .long("shell") .action(ArgAction::Set) .help("Invoke to run recipes"), ) .arg( - Arg::with_name(arg::SHELL_ARG) + Arg::new(arg::SHELL_ARG) .long("shell-arg") .action(ArgAction::Append) .allow_hyphen_values(true) @@ -275,92 +280,93 @@ impl Config { .help("Invoke shell with as an argument"), ) .arg( - Arg::with_name(arg::SHELL_COMMAND) + Arg::new(arg::SHELL_COMMAND) .long("shell-command") .requires(cmd::COMMAND) .action(ArgAction::SetTrue) .help("Invoke with the shell used to run recipe lines and backticks"), ) .arg( - Arg::with_name(arg::CLEAR_SHELL_ARGS) + Arg::new(arg::CLEAR_SHELL_ARGS) .long("clear-shell-args") .action(ArgAction::SetTrue) .overrides_with(arg::SHELL_ARG) .help("Clear shell arguments"), ) .arg( - Arg::with_name(arg::UNSORTED) + Arg::new(arg::UNSORTED) .long("unsorted") .short('u') .action(ArgAction::SetTrue) .help("Return list and summary entries in source order"), ) .arg( - Arg::with_name(arg::UNSTABLE) + Arg::new(arg::UNSTABLE) .long("unstable") .action(ArgAction::SetTrue) .help("Enable unstable features"), ) .arg( - Arg::with_name(arg::VERBOSE) + Arg::new(arg::VERBOSE) .short('v') .long("verbose") .action(ArgAction::Count) .help("Use verbose output"), ) .arg( - Arg::with_name(arg::WORKING_DIRECTORY) + Arg::new(arg::WORKING_DIRECTORY) .short('d') .long("working-directory") .action(ArgAction::Set) + .value_parser(value_parser!(PathBuf)) .help("Use as working directory. --justfile must also be set") .requires(arg::JUSTFILE), ) .arg( - Arg::with_name(cmd::CHANGELOG) + Arg::new(cmd::CHANGELOG) .long("changelog") .action(ArgAction::SetTrue) .help("Print changelog"), ) - .arg(Arg::with_name(cmd::CHOOSE).long("choose").action(ArgAction::SetTrue).help(CHOOSE_HELP)) + .arg(Arg::new(cmd::CHOOSE).long("choose").action(ArgAction::SetTrue).help(CHOOSE_HELP)) .arg( - Arg::with_name(cmd::COMMAND) + Arg::new(cmd::COMMAND) .long("command") .short('c') .min_values(1) .allow_hyphen_values(true) .action(ArgAction::Append) - .value_parser(clap::value_parser!(std::ffi::OsString)) + .value_parser(value_parser!(std::ffi::OsString)) .help( "Run an arbitrary command with the working directory, `.env`, overrides, and exports \ set", ), ) .arg( - Arg::with_name(cmd::COMPLETIONS) + Arg::new(cmd::COMPLETIONS) .long("completions") .action(ArgAction::Append) .min_values(1) .value_name("SHELL") - .possible_values(clap_complete::Shell::possible_values()) - .set(ArgSettings::CaseInsensitive) + .value_parser(value_parser!(clap_complete::Shell)) + .ignore_case(true) .help("Print shell completion script for "), ) .arg( - Arg::with_name(cmd::DUMP) + Arg::new(cmd::DUMP) .long("dump") .action(ArgAction::SetTrue) .help("Print justfile"), ) .arg( - Arg::with_name(cmd::EDIT) + Arg::new(cmd::EDIT) .short('e') .long("edit") .action(ArgAction::SetTrue) .help("Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`"), ) .arg( - Arg::with_name(cmd::EVALUATE) + Arg::new(cmd::EVALUATE) .long("evaluate") .action(ArgAction::SetTrue) .help( @@ -369,28 +375,28 @@ impl Config { ), ) .arg( - Arg::with_name(cmd::FORMAT) + Arg::new(cmd::FORMAT) .long("fmt") .alias("format") .action(ArgAction::SetTrue) .help("Format and overwrite justfile"), ) .arg( - Arg::with_name(cmd::INIT) + Arg::new(cmd::INIT) .long("init") .alias("initialize") .action(ArgAction::SetTrue) .help("Initialize new justfile in project root"), ) .arg( - Arg::with_name(cmd::LIST) + Arg::new(cmd::LIST) .short('l') .long("list") .action(ArgAction::SetTrue) .help("List available recipes and their arguments"), ) .arg( - Arg::with_name(cmd::SHOW) + Arg::new(cmd::SHOW) .short('s') .long("show") .action(ArgAction::Set) @@ -399,34 +405,35 @@ impl Config { .help("Show information about "), ) .arg( - Arg::with_name(cmd::SUMMARY) + Arg::new(cmd::SUMMARY) .long("summary") .action(ArgAction::SetTrue) .help("List names of available recipes"), ) .arg( - Arg::with_name(cmd::VARIABLES) + Arg::new(cmd::VARIABLES) .long("variables") .action(ArgAction::SetTrue) .help("List names of variables"), ) .arg( - Arg::with_name(arg::DOTENV_FILENAME) + Arg::new(arg::DOTENV_FILENAME) .long("dotenv-filename") .action(ArgAction::Set) .help("Search for environment file named instead of `.env`") .conflicts_with(arg::DOTENV_PATH), ) .arg( - Arg::with_name(arg::DOTENV_PATH) + Arg::new(arg::DOTENV_PATH) .short('E') .long("dotenv-path") .action(ArgAction::Set) + .value_parser(value_parser!(PathBuf)) .help("Load as environment file instead of searching for one") ) - .group(ArgGroup::with_name("SUBCOMMAND").args(cmd::ALL)) + .group(ArgGroup::new("SUBCOMMAND").args(cmd::ALL)) .arg( - Arg::with_name(arg::ARGUMENTS) + Arg::new(arg::ARGUMENTS) .multiple_values(true) .action(ArgAction::Append) .help("Overrides and recipe(s) to run, defaulting to the first recipe in the justfile"), @@ -452,12 +459,12 @@ impl Config { fn color_from_matches(matches: &ArgMatches) -> ConfigResult { let value = matches - .value_of(arg::COLOR) + .get_one::(arg::COLOR) .ok_or_else(|| ConfigError::Internal { message: "`--color` had no value".to_string(), })?; - match value { + match value.as_str() { arg::COLOR_AUTO => Ok(Color::auto()), arg::COLOR_ALWAYS => Ok(Color::always()), arg::COLOR_NEVER => Ok(Color::never()), @@ -468,8 +475,8 @@ impl Config { } fn command_color_from_matches(matches: &ArgMatches) -> ConfigResult> { - if let Some(value) = matches.value_of(arg::COMMAND_COLOR) { - match value { + if let Some(value) = matches.get_one::(arg::COMMAND_COLOR) { + match value.as_str() { arg::COMMAND_COLOR_BLACK => Ok(Some(ansi_term::Color::Black)), arg::COMMAND_COLOR_BLUE => Ok(Some(ansi_term::Color::Blue)), arg::COMMAND_COLOR_CYAN => Ok(Some(ansi_term::Color::Cyan)), @@ -487,13 +494,14 @@ impl Config { } fn dump_format_from_matches(matches: &ArgMatches) -> ConfigResult { - let value = matches - .value_of(arg::DUMP_FORMAT) - .ok_or_else(|| ConfigError::Internal { - message: "`--dump-format` had no value".to_string(), - })?; + let value = + matches + .get_one::(arg::DUMP_FORMAT) + .ok_or_else(|| ConfigError::Internal { + message: "`--dump-format` had no value".to_string(), + })?; - match value { + match value.as_str() { arg::DUMP_FORMAT_JSON => Ok(DumpFormat::Json), arg::DUMP_FORMAT_JUST => Ok(DumpFormat::Just), _ => Err(ConfigError::Internal { @@ -521,15 +529,21 @@ impl Config { } } - let positional = Positional::from_values(matches.values_of(arg::ARGUMENTS)); + let positional = Positional::from_values( + matches + .get_many::(arg::ARGUMENTS) + .map(|s| s.map(String::as_str)), + ); for (name, value) in positional.overrides { overrides.insert(name.clone(), value.clone()); } let search_config = { - let justfile = matches.value_of(arg::JUSTFILE).map(PathBuf::from); - let working_directory = matches.value_of(arg::WORKING_DIRECTORY).map(PathBuf::from); + let justfile = matches.get_one::(arg::JUSTFILE).map(Into::into); + let working_directory = matches + .get_one::(arg::WORKING_DIRECTORY) + .map(Into::into); if let Some(search_directory) = positional.search_directory.map(PathBuf::from) { if justfile.is_some() || working_directory.is_some() { @@ -586,20 +600,18 @@ impl Config { Subcommand::Changelog } else if matches.get_flag(cmd::CHOOSE) { Subcommand::Choose { - chooser: matches.value_of(arg::CHOOSER).map(str::to_owned), + chooser: matches.get_one::(arg::CHOOSER).map(Into::into), overrides, } - } else if let Some(values) = matches.values_of_os(cmd::COMMAND) { - let mut arguments = values.map(OsStr::to_owned).collect::>(); + } else if let Some(values) = matches.get_many::(cmd::COMMAND) { + let mut arguments = values.map(Into::into).collect::>(); Subcommand::Command { binary: arguments.remove(0), arguments, overrides, } - } else if let Some(shell) = matches.value_of(cmd::COMPLETIONS) { - Subcommand::Completions { - shell: shell.to_owned(), - } + } else if let Some(&shell) = matches.get_one::(cmd::COMPLETIONS) { + Subcommand::Completions { shell } } else if matches.get_flag(cmd::EDIT) { Subcommand::Edit } else if matches.get_flag(cmd::SUMMARY) { @@ -612,10 +624,8 @@ impl Config { Subcommand::Init } else if matches.get_flag(cmd::LIST) { Subcommand::List - } else if let Some(name) = matches.value_of(cmd::SHOW) { - Subcommand::Show { - name: name.to_owned(), - } + } else if let Some(name) = matches.get_one::(cmd::SHOW).map(Into::into) { + Subcommand::Show { name } } else if matches.get_flag(cmd::EVALUATE) { if positional.arguments.len() > 1 { return Err(ConfigError::SubcommandArguments { @@ -658,25 +668,25 @@ impl Config { check: matches.get_flag(arg::CHECK), color, command_color, - dotenv_filename: matches.value_of(arg::DOTENV_FILENAME).map(str::to_owned), - dotenv_path: matches.value_of(arg::DOTENV_PATH).map(PathBuf::from), + dotenv_filename: matches + .get_one::(arg::DOTENV_FILENAME) + .map(Into::into), + dotenv_path: matches.get_one::(arg::DOTENV_PATH).map(Into::into), dry_run: matches.get_flag(arg::DRY_RUN), dump_format: Self::dump_format_from_matches(matches)?, highlight: !matches.get_flag(arg::NO_HIGHLIGHT), invocation_directory, list_heading: matches - .value_of(arg::LIST_HEADING) - .unwrap_or("Available recipes:\n") - .to_owned(), + .get_one::(arg::LIST_HEADING) + .map_or_else(|| "Available recipes:\n".into(), Into::into), list_prefix: matches - .value_of(arg::LIST_PREFIX) - .unwrap_or(" ") - .to_owned(), - load_dotenv: !matches.is_present(arg::NO_DOTENV), + .get_one::(arg::LIST_PREFIX) + .map_or_else(|| " ".into(), Into::into), + load_dotenv: !matches.get_flag(arg::NO_DOTENV), no_aliases: matches.is_present(arg::NO_ALIASES), - no_dependencies: matches.is_present(arg::NO_DEPS), + no_dependencies: matches.get_flag(arg::NO_DEPS), search_config, - shell: matches.value_of(arg::SHELL).map(str::to_owned), + shell: matches.get_one::(arg::SHELL).map(Into::into), shell_args, shell_command: matches.get_flag(arg::SHELL_COMMAND), subcommand, @@ -710,6 +720,7 @@ impl Config { mod tests { use super::*; + use clap::error::{ContextKind, ContextValue}; use pretty_assertions::assert_eq; macro_rules! test { @@ -759,7 +770,7 @@ mod tests { fn test(arguments: &[&str], want: Config) { let app = Config::app(); let matches = app - .get_matches_from_safe(arguments) + .try_get_matches_from(arguments) .expect("argument parsing failed"); let have = Config::from_matches(&matches).expect("config parsing failed"); assert_eq!(have, want); @@ -779,7 +790,7 @@ mod tests { let app = Config::app(); - app.get_matches_from_safe(arguments).expect_err("Expected clap error"); + app.try_get_matches_from(arguments).expect_err("Expected clap error"); } }; { @@ -797,7 +808,7 @@ mod tests { let app = Config::app(); - let matches = app.get_matches_from_safe(arguments).expect("Matching fails"); + let matches = app.try_get_matches_from(arguments).expect("Matching fails"); match Config::from_matches(&matches).expect_err("config parsing succeeded") { $error => { $($check)? } @@ -823,7 +834,7 @@ mod tests { let app = Config::app(); - match app.get_matches_from_safe(arguments) { + match app.try_get_matches_from(arguments) { Err($error) => { $($check)? } other => panic!("Unexpected result from get matches: {other:?}") } @@ -1156,13 +1167,13 @@ mod tests { test! { name: subcommand_completions, args: ["--completions", "bash"], - subcommand: Subcommand::Completions{shell: "bash".to_owned()}, + subcommand: Subcommand::Completions{ shell: clap_complete::Shell::Bash }, } test! { name: subcommand_completions_uppercase, args: ["--completions", "BASH"], - subcommand: Subcommand::Completions{shell: "BASH".to_owned()}, + subcommand: Subcommand::Completions{ shell: clap_complete::Shell::Bash }, } error! { @@ -1435,9 +1446,14 @@ mod tests { error_matches! { name: completions_arguments, args: ["--completions", "zsh", "foo"], - error: clap::Error { kind: clap::ErrorKind::InvalidValue, info, .. }, + error: error, check: { - assert_eq!(info, &["--completions ...", "foo", "bash", "elvish", "fish", "powershell", "zsh"]); + assert_eq!(error.kind(), clap::error::ErrorKind::InvalidValue); + assert_eq!(error.context().collect::>(), vec![ + (ContextKind::InvalidArg, &ContextValue::String("--completions ...".into())), + (ContextKind::InvalidValue, &ContextValue::String("foo".into())), + (ContextKind::ValidValue, &ContextValue::Strings(["bash".into(), "elvish".into(), "fish".into(), "powershell".into(), "zsh".into()].into())), + ]); }, } @@ -1524,9 +1540,14 @@ mod tests { error_matches! { name: show_arguments, args: ["--show", "foo", "bar"], - error: clap::Error { kind: clap::ErrorKind::ArgumentConflict, info, .. }, + error: error, check: { - assert_eq!(info, &["..."]); + assert_eq!(error.kind(), clap::error::ErrorKind::ArgumentConflict); + assert_eq!(error.context().collect::>(), vec![ + (ContextKind::InvalidArg, &ContextValue::String("--show ".into())), + (ContextKind::PriorArg, &ContextValue::String("...".into())), + (ContextKind::Usage, &ContextValue::String("USAGE:\n just <--changelog|--choose|--command ...|--completions ...|--dump|--edit|--evaluate|--fmt|--init|--list|--show |--summary|--variables>".into())), + ]); }, } diff --git a/src/function.rs b/src/function.rs index fee4bfc5e9..b7e03e5553 100644 --- a/src/function.rs +++ b/src/function.rs @@ -504,7 +504,10 @@ mod tests { fn dir_not_unicode() { use std::os::unix::ffi::OsStrExt; assert_eq!( - dir("foo", || Some(OsStr::from_bytes(b"\xe0\x80\x80").into())).unwrap_err(), + dir("foo", || Some( + std::ffi::OsStr::from_bytes(b"\xe0\x80\x80").into() + )) + .unwrap_err(), "unable to convert foo directory path to string: ���", ); } diff --git a/src/lib.rs b/src/lib.rs index 7f113ca678..65592f8e54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,7 +41,7 @@ pub(crate) use { cmp, collections::{BTreeMap, BTreeSet, HashMap}, env, - ffi::{OsStr, OsString}, + ffi::OsString, fmt::{self, Debug, Display, Formatter}, fs, io::{self, Write}, diff --git a/src/subcommand.rs b/src/subcommand.rs index a680968b6f..622b834434 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -1,3 +1,7 @@ +use std::io::{Read, Seek}; + +use tempfile::tempfile; + use super::*; const INIT_JUSTFILE: &str = "default:\n echo 'Hello, world!'\n"; @@ -15,7 +19,7 @@ pub(crate) enum Subcommand { overrides: BTreeMap, }, Completions { - shell: String, + shell: clap_complete::Shell, }, Dump, Edit, @@ -50,7 +54,7 @@ impl Subcommand { Self::changelog(); return Ok(()); } - Completions { shell } => return Self::completions(crate::config::Config::app(), shell), + Completions { shell } => return Self::completions(*shell), Init => return Self::init(config), Run { arguments, @@ -275,8 +279,8 @@ impl Subcommand { justfile.run(config, search, overrides, &recipes) } - fn completions(command: clap::Command<'_>, shell: &str) -> RunResult<'static, ()> { - use clap_complete::{Generator, Shell}; + fn completions(shell: clap_complete::Shell) -> RunResult<'static, ()> { + use clap_complete::Shell; fn replace(haystack: &mut String, needle: &str, replacement: &str) -> RunResult<'static, ()> { if let Some(index) = haystack.find(needle) { @@ -289,13 +293,26 @@ impl Subcommand { } } - let shell = shell - .parse::() - .expect("Invalid value for clap::Shell"); - - let mut buffer = Vec::new(); - shell.generate(&command, &mut buffer); - let mut script = String::from_utf8(buffer).expect("Clap completion not UTF-8"); + let mut script = { + let mut tmp = tempfile() + .map_err(|e| Error::internal(format!("Failed to create tempfile for completions: {e}")))?; + clap_complete::generate( + shell, + &mut crate::config::Config::app(), + env!("CARGO_PKG_NAME"), + &mut tmp, + ); + tmp.rewind().map_err(|e| { + Error::internal(format!( + "Failed to rewind tempfile to read completions to update: {e}" + )) + })?; + let mut buffer = String::new(); + tmp + .read_to_string(&mut buffer) + .map_err(|e| Error::internal(format!("Failed to read completions from tempfile: {e}")))?; + buffer + }; match shell { Shell::Bash => { diff --git a/src/testing.rs b/src/testing.rs index 09ddb3e16a..56241dc332 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -10,7 +10,7 @@ pub(crate) fn config(args: &[&str]) -> Config { let app = Config::app(); - let matches = app.get_matches_from_safe(args).unwrap(); + let matches = app.try_get_matches_from(args).unwrap(); Config::from_matches(&matches).unwrap() } diff --git a/tests/test.rs b/tests/test.rs index 2a3a6ac37d..f2a3cea6bf 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -189,6 +189,7 @@ impl Test { } impl Test { + #[track_caller] pub(crate) fn run(self) -> Output { if let Some(justfile) = &self.justfile { let justfile = unindent(justfile); From 657fa58a89d44a64efc461b8e90922712a5dc409 Mon Sep 17 00:00:00 2001 From: "Alexis (Poliorcetics) Bourget" Date: Tue, 9 Apr 2024 22:34:23 +0200 Subject: [PATCH 3/8] chore(deps): move to clap 4 --- Cargo.lock | 141 ++++++++++----------------------------------- Cargo.toml | 4 +- src/completions.rs | 8 +-- src/config.rs | 36 +++++++----- tests/command.rs | 4 +- tests/fmt.rs | 4 +- 6 files changed, 59 insertions(+), 138 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eeb84f976b..1035c41bbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -91,12 +91,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "bitflags" version = "1.3.2" @@ -178,44 +172,47 @@ dependencies = [ "atty", "bitflags 1.3.2", "strsim 0.8.0", - "textwrap 0.11.0", + "textwrap", "unicode-width", "vec_map", ] [[package]] name = "clap" -version = "3.2.25" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ - "atty", - "bitflags 1.3.2", + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", "clap_lex", - "indexmap", - "strsim 0.10.0", - "termcolor", + "strsim 0.11.1", "terminal_size", - "textwrap 0.16.1", ] [[package]] name = "clap_complete" -version = "3.2.5" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f7a2e0a962c45ce25afce14220bc24f9dade0a1787f185cecf96bfba7847cd8" +checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e" dependencies = [ - "clap 3.2.25", + "clap 4.5.4", ] [[package]] name = "clap_lex" -version = "0.2.4" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" @@ -441,12 +438,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "heck" version = "0.3.3" @@ -492,27 +483,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "itoa" version = "1.0.10" @@ -527,7 +497,7 @@ dependencies = [ "atty", "blake3", "camino", - "clap 3.2.25", + "clap 4.5.4", "clap_complete", "cradle", "ctrlc", @@ -596,12 +566,6 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -663,12 +627,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "os_str_bytes" -version = "6.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" - [[package]] name = "pretty_assertions" version = "1.4.0" @@ -826,20 +784,6 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" -[[package]] -name = "rustix" -version = "0.37.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - [[package]] name = "rustix" version = "0.38.31" @@ -849,7 +793,7 @@ dependencies = [ "bitflags 2.4.2", "errno", "libc", - "linux-raw-sys 0.4.13", + "linux-raw-sys", "windows-sys 0.52.0", ] @@ -952,9 +896,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "structopt" @@ -1038,7 +982,7 @@ checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "rustix 0.38.31", + "rustix", "windows-sys 0.52.0", ] @@ -1051,22 +995,13 @@ dependencies = [ "tempfile", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "terminal_size" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.37.27", + "rustix", "windows-sys 0.48.0", ] @@ -1079,15 +1014,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "textwrap" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" -dependencies = [ - "terminal_size", -] - [[package]] name = "thiserror" version = "1.0.57" @@ -1196,7 +1122,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.31", + "rustix", "windows-sys 0.52.0", ] @@ -1216,15 +1142,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 4983f647e1..fea4cd2f29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,8 +22,8 @@ ansi_term = "0.12.0" atty = "0.2.0" blake3 = { version = "1.5.0", features = ["rayon", "mmap"] } camino = "1.0.4" -clap = { version = "3.0.0", features = ["wrap_help"] } -clap_complete = "3.0.0" +clap = { version = "4.0.0", features = ["wrap_help"] } +clap_complete = "4.0.0" ctrlc = { version = "3.1.1", features = ["termination"] } derivative = "2.0.0" dirs = "5.0.1" diff --git a/src/completions.rs b/src/completions.rs index 4a8bf33469..74d0eb5dbe 100644 --- a/src/completions.rs +++ b/src/completions.rs @@ -43,8 +43,8 @@ pub(crate) const ZSH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ r" local common=(", ), ( - r"'--set=[Override with ]:VARIABLE: :VARIABLE: ' \", - r"'--set=[Override with ]: :(_just_variables)' \", + r"'*--set=[Override with ]:VARIABLE: :VARIABLE: ' \", + r"'*--set=[Override with ]: :(_just_variables)' \", ), ( r"'()-s+[Show information about ]:RECIPE: ' \ @@ -204,8 +204,8 @@ pub(crate) const BASH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[ ), (r" just)", r#" "$1")"#), ( - r"local i cur prev opts cmds", - r"local i cur prev words cword opts cmds", + r"local i cur prev opts cmd", + r"local i cur prev words cword opts cmd", ), ( r#" cur="${COMP_WORDS[COMP_CWORD]}" diff --git a/src/config.rs b/src/config.rs index b388cd4e5f..07a1094723 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,8 +1,8 @@ use { super::*, clap::{ - builder::PossibleValuesParser, value_parser, AppSettings, Arg, ArgAction, ArgGroup, ArgMatches, - Command, + builder::{styling::AnsiColor, PossibleValuesParser, Styles}, + value_parser, Arg, ArgAction, ArgGroup, ArgMatches, Command, }, }; @@ -141,14 +141,17 @@ mod arg { } impl Config { - pub(crate) fn app() -> Command<'static> { + pub(crate) fn app() -> Command { let app = Command::new(env!("CARGO_PKG_NAME")) .bin_name(env!("CARGO_PKG_NAME")) - .help_message("Print help information") - .version_message("Print version information") - .setting(AppSettings::ColoredHelp) - .setting(AppSettings::TrailingVarArg) .trailing_var_arg(true) + .styles( + Styles::styled() + .header(AnsiColor::Yellow.on_default()) + .usage(AnsiColor::Yellow.on_default()) + .literal(AnsiColor::Green.on_default()) + .placeholder(AnsiColor::Green.on_default()) + ) .arg( Arg::new(arg::CHECK) .long("check") @@ -217,9 +220,10 @@ impl Config { .action(ArgAction::Set), ) .arg( - Arg::with_name(arg::NO_ALIASES) + Arg::new(arg::NO_ALIASES) .long("no-aliases") - .help("Don't show aliases in list") + .action(ArgAction::SetTrue) + .help("Don't show aliases in list"), ) .arg ( Arg::new(arg::NO_DEPS) @@ -262,7 +266,7 @@ impl Config { .long("set") .action(ArgAction::Append) .number_of_values(2) - .value_names(&["VARIABLE", "VALUE"]) + .value_names(["VARIABLE", "VALUE"]) .help("Override with "), ) .arg( @@ -333,7 +337,7 @@ impl Config { Arg::new(cmd::COMMAND) .long("command") .short('c') - .min_values(1) + .num_args(1..) .allow_hyphen_values(true) .action(ArgAction::Append) .value_parser(value_parser!(std::ffi::OsString)) @@ -346,7 +350,7 @@ impl Config { Arg::new(cmd::COMPLETIONS) .long("completions") .action(ArgAction::Append) - .min_values(1) + .num_args(1..) .value_name("SHELL") .value_parser(value_parser!(clap_complete::Shell)) .ignore_case(true) @@ -434,7 +438,7 @@ impl Config { .group(ArgGroup::new("SUBCOMMAND").args(cmd::ALL)) .arg( Arg::new(arg::ARGUMENTS) - .multiple_values(true) + .num_args(1..) .action(ArgAction::Append) .help("Overrides and recipe(s) to run, defaulting to the first recipe in the justfile"), ); @@ -683,7 +687,7 @@ impl Config { .get_one::(arg::LIST_PREFIX) .map_or_else(|| " ".into(), Into::into), load_dotenv: !matches.get_flag(arg::NO_DOTENV), - no_aliases: matches.is_present(arg::NO_ALIASES), + no_aliases: matches.get_flag(arg::NO_ALIASES), no_dependencies: matches.get_flag(arg::NO_DEPS), search_config, shell: matches.get_one::(arg::SHELL).map(Into::into), @@ -1545,8 +1549,8 @@ mod tests { assert_eq!(error.kind(), clap::error::ErrorKind::ArgumentConflict); assert_eq!(error.context().collect::>(), vec![ (ContextKind::InvalidArg, &ContextValue::String("--show ".into())), - (ContextKind::PriorArg, &ContextValue::String("...".into())), - (ContextKind::Usage, &ContextValue::String("USAGE:\n just <--changelog|--choose|--command ...|--completions ...|--dump|--edit|--evaluate|--fmt|--init|--list|--show |--summary|--variables>".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\u{1b}[0m \u{1b}[32m[ARGUMENTS]...\u{1b}[0m".into())), ]); }, } diff --git a/tests/command.rs b/tests/command.rs index 4a956945d2..44bde24f56 100644 --- a/tests/command.rs +++ b/tests/command.rs @@ -40,9 +40,9 @@ test! { ", args: ("--command"), stderr: " - error: The argument '--command ...' requires a value but none was supplied + error: a value is required for '--command ...' but none was supplied - For more information try --help + For more information, try '--help'. ", status: 2, } diff --git a/tests/fmt.rs b/tests/fmt.rs index 0c5e16ff95..1d70a6f9ab 100644 --- a/tests/fmt.rs +++ b/tests/fmt.rs @@ -15,8 +15,8 @@ test! { name: check_without_fmt, justfile: "", args: ("--check"), - stderr_regex: "error: The following required arguments were not provided: - --fmt + stderr_regex: "error: the following required arguments were not provided: + --fmt (.|\\n)+", status: 2, } From 700e2c7d9ad9903cdcdbd426692c08ce117bde13 Mon Sep 17 00:00:00 2001 From: "Alexis (Poliorcetics) Bourget" Date: Tue, 9 Apr 2024 22:34:29 +0200 Subject: [PATCH 4/8] chore(cli): use clap's facilities for env var instead of rolling our own solution --- Cargo.toml | 2 +- src/config.rs | 18 +++++++++--------- src/subcommand.rs | 5 +---- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fea4cd2f29..2d9c5401b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ ansi_term = "0.12.0" atty = "0.2.0" blake3 = { version = "1.5.0", features = ["rayon", "mmap"] } camino = "1.0.4" -clap = { version = "4.0.0", features = ["wrap_help"] } +clap = { version = "4.0.0", features = ["env", "wrap_help"] } clap_complete = "4.0.0" ctrlc = { version = "3.1.1", features = ["termination"] } derivative = "2.0.0" diff --git a/src/config.rs b/src/config.rs index 07a1094723..edd1f4739a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,16 +1,16 @@ use { super::*, clap::{ - builder::{styling::AnsiColor, PossibleValuesParser, Styles}, + builder::{styling::AnsiColor, FalseyValueParser, PossibleValuesParser, Styles}, value_parser, Arg, ArgAction, ArgGroup, ArgMatches, Command, }, }; -pub(crate) const CHOOSER_ENVIRONMENT_KEY: &str = "JUST_CHOOSER"; +const CHOOSER_ENVIRONMENT_KEY: &str = "JUST_CHOOSER"; -pub(crate) const CHOOSE_HELP: &str = "Select one or more recipes to run using a binary chooser. \ - If `--chooser` is not passed the chooser defaults to the \ - value of $JUST_CHOOSER, falling back to `fzf`"; +const CHOOSE_HELP: &str = "Select one or more recipes to run using a binary chooser. \ + If `--chooser` is not passed the chooser defaults to the \ + value of $JUST_CHOOSER, falling back to `fzf`"; pub(crate) fn chooser_default(justfile: &Path) -> OsString { let mut chooser = OsString::new(); @@ -162,6 +162,7 @@ impl Config { .arg( Arg::new(arg::CHOOSER) .long("chooser") + .env(CHOOSER_ENVIRONMENT_KEY) .action(ArgAction::Set) .help("Override binary invoked by `--choose`"), ) @@ -307,7 +308,9 @@ impl Config { .arg( Arg::new(arg::UNSTABLE) .long("unstable") + .env("JUST_UNSTABLE") .action(ArgAction::SetTrue) + .value_parser(FalseyValueParser::new()) .help("Enable unstable features"), ) .arg( @@ -663,10 +666,7 @@ impl Config { .map(|s| s.map(Into::into).collect()) }; - let unstable = matches.get_flag(arg::UNSTABLE) - || env::var_os("JUST_UNSTABLE") - .map(|val| !(val == "false" || val == "0" || val.is_empty())) - .unwrap_or_default(); + let unstable = matches.get_flag(arg::UNSTABLE); Ok(Self { check: matches.get_flag(arg::CHECK), diff --git a/src/subcommand.rs b/src/subcommand.rs index 622b834434..36a5860485 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -217,10 +217,7 @@ impl Subcommand { return Err(Error::NoChoosableRecipes); } - let chooser = chooser - .map(OsString::from) - .or_else(|| env::var_os(config::CHOOSER_ENVIRONMENT_KEY)) - .unwrap_or_else(|| config::chooser_default(&search.justfile)); + let chooser = chooser.map_or_else(|| config::chooser_default(&search.justfile), From::from); let result = justfile .settings From 7d522fa4d9cfb72fdc3026225ac7e62b74d837a5 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 14 May 2024 20:12:01 -0700 Subject: [PATCH 5/8] Inline CHOOSER_ENVIRONMENT_KEY --- Cargo.toml | 2 +- src/config.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c7314b1609..cbbb1e1ed2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ atty = "0.2.0" blake3 = { version = "1.5.0", features = ["rayon", "mmap"] } camino = "1.0.4" clap = { version = "4.0.0", features = ["env", "wrap_help"] } -clap_complete = "4.0.0" +clap_complete = "4.0.0" ctrlc = { version = "3.1.1", features = ["termination"] } derivative = "2.0.0" dirs = "5.0.1" diff --git a/src/config.rs b/src/config.rs index 1852dfdd66..0b2976a072 100644 --- a/src/config.rs +++ b/src/config.rs @@ -6,8 +6,6 @@ use { }, }; -const CHOOSER_ENVIRONMENT_KEY: &str = "JUST_CHOOSER"; - const CHOOSE_HELP: &str = "Select one or more recipes to run using a binary chooser. \ If `--chooser` is not passed the chooser defaults to the \ value of $JUST_CHOOSER, falling back to `fzf`"; @@ -162,7 +160,7 @@ impl Config { .arg( Arg::new(arg::CHOOSER) .long("chooser") - .env(CHOOSER_ENVIRONMENT_KEY) + .env("JUST_CHOOSER") .action(ArgAction::Set) .help("Override binary invoked by `--choose`"), ) From 22c05c7f0cb6a583c2d2bf271cd43dcb4f0813d1 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 14 May 2024 20:13:16 -0700 Subject: [PATCH 6/8] Combine imports --- src/subcommand.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/subcommand.rs b/src/subcommand.rs index bbf9e45c55..69442f5cb7 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -1,8 +1,8 @@ -use std::io::{Read, Seek}; - -use tempfile::tempfile; - -use super::*; +use { + super::*, + std::io::{Read, Seek}, + tempfile::tempfile, +}; const INIT_JUSTFILE: &str = "default:\n echo 'Hello, world!'\n"; From da9f1cc6f048e0736d2ddc9878fd15842b322d92 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 14 May 2024 20:19:51 -0700 Subject: [PATCH 7/8] Update error --- completions/just.bash | 31 +++++++------- completions/just.elvish | 31 +++++++------- completions/just.fish | 84 ++++++++++++++++++------------------- completions/just.powershell | 13 +++--- completions/just.zsh | 63 +++++++++++++++------------- src/error.rs | 10 ++++- src/recipe.rs | 8 ++-- src/subcommand.rs | 22 +++++----- 8 files changed, 140 insertions(+), 122 deletions(-) diff --git a/completions/just.bash b/completions/just.bash index 57f0041958..0cd0880c61 100644 --- a/completions/just.bash +++ b/completions/just.bash @@ -1,5 +1,5 @@ _just() { - local i cur prev words cword opts cmds + local i cur prev words cword opts cmd COMPREPLY=() # Modules use "::" as the separator, which is considered a wordbreak character in bash. @@ -19,19 +19,18 @@ _just() { for i in ${words[@]} do - case "${i}" in - "$1") + case "${cmd},${i}" in + ",$1") cmd="just" ;; - *) ;; esac done case "${cmd}" in - just) - opts=" -n -q -u -v -e -l -h -V -f -d -c -s -E --check --yes --dry-run --highlight --no-aliases --no-deps --no-dotenv --no-highlight --quiet --shell-command --clear-shell-args --unsorted --unstable --verbose --changelog --choose --dump --edit --evaluate --fmt --init --list --summary --variables --help --version --chooser --color --command-color --dump-format --list-heading --list-prefix --justfile --set --shell --shell-arg --working-directory --command --completions --show --dotenv-filename --dotenv-path ... " + "$1") + opts="-n -f -q -u -v -d -c -e -l -s -E -h -V --check --chooser --color --command-color --yes --dry-run --dump-format --highlight --list-heading --list-prefix --no-aliases --no-deps --no-dotenv --no-highlight --justfile --quiet --set --shell --shell-arg --shell-command --clear-shell-args --unsorted --unstable --verbose --working-directory --changelog --choose --command --completions --dump --edit --evaluate --fmt --init --list --show --summary --variables --dotenv-filename --dotenv-path --help --version [ARGUMENTS]..." if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -53,7 +52,6 @@ _just() { fi fi case "${prev}" in - --chooser) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -82,7 +80,7 @@ _just() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -f) + -f) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -102,7 +100,7 @@ _just() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -d) + -d) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -110,19 +108,19 @@ _just() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -c) + -c) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; --completions) - COMPREPLY=($(compgen -W "zsh bash fish powershell elvish" -- "${cur}")) + COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) return 0 ;; --show) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -s) + -s) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -134,7 +132,7 @@ _just() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; - -E) + -E) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; @@ -145,8 +143,11 @@ _just() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - esac } -complete -F _just -o bashdefault -o default just +if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then + complete -F _just -o nosort -o bashdefault -o default just +else + complete -F _just -o bashdefault -o default just +fi diff --git a/completions/just.elvish b/completions/just.elvish index 6ec3874ed6..86882d50ec 100644 --- a/completions/just.elvish +++ b/completions/just.elvish @@ -1,18 +1,21 @@ -edit:completion:arg-completer[just] = [@words]{ - fn spaces [n]{ - repeat $n ' ' | joins '' +use builtin; +use str; + +set edit:completion:arg-completer[just] = {|@words| + fn spaces {|n| + builtin:repeat $n ' ' | str:join '' } - fn cand [text desc]{ - edit:complex-candidate $text &display-suffix=' '(spaces (- 14 (wcswidth $text)))$desc + fn cand {|text desc| + edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc } - command = 'just' - for word $words[1:-1] { - if (has-prefix $word '-') { + var command = 'just' + for word $words[1..-1] { + if (str:has-prefix $word '-') { break } - command = $command';'$word + set command = $command';'$word } - completions = [ + var completions = [ &'just'= { cand --chooser 'Override binary invoked by `--choose`' cand --color 'Print colorful output' @@ -65,10 +68,10 @@ edit:completion:arg-completer[just] = [@words]{ cand --list 'List available recipes and their arguments' cand --summary 'List names of available recipes' cand --variables 'List names of variables' - cand -h 'Print help information' - cand --help 'Print help information' - cand -V 'Print version information' - cand --version 'Print version information' + cand -h 'Print help' + cand --help 'Print help' + cand -V 'Print version' + cand --version 'Print version' } ] $completions[$command] diff --git a/completions/just.fish b/completions/just.fish index 6664bd65b5..23da10459b 100644 --- a/completions/just.fish +++ b/completions/just.fish @@ -35,45 +35,45 @@ complete -c just -n "__fish_is_first_arg" --no-files complete -c just -a '(__fish_just_complete_recipes)' # autogenerated completions -complete -c just -n "__fish_use_subcommand" -l chooser -d 'Override binary invoked by `--choose`' -complete -c just -n "__fish_use_subcommand" -l color -d 'Print colorful output' -r -f -a "auto always never" -complete -c just -n "__fish_use_subcommand" -l command-color -d 'Echo recipe lines in ' -r -f -a "black blue cyan green purple red yellow" -complete -c just -n "__fish_use_subcommand" -l dump-format -d 'Dump justfile as ' -r -f -a "just json" -complete -c just -n "__fish_use_subcommand" -l list-heading -d 'Print before list' -complete -c just -n "__fish_use_subcommand" -l list-prefix -d 'Print before each list item' -complete -c just -n "__fish_use_subcommand" -s f -l justfile -d 'Use as justfile' -complete -c just -n "__fish_use_subcommand" -l set -d 'Override with ' -complete -c just -n "__fish_use_subcommand" -l shell -d 'Invoke to run recipes' -complete -c just -n "__fish_use_subcommand" -l shell-arg -d 'Invoke shell with as an argument' -complete -c just -n "__fish_use_subcommand" -s d -l working-directory -d 'Use as working directory. --justfile must also be set' -complete -c just -n "__fish_use_subcommand" -s c -l command -d 'Run an arbitrary command with the working directory, `.env`, overrides, and exports set' -complete -c just -n "__fish_use_subcommand" -l completions -d 'Print shell completion script for ' -r -f -a "zsh bash fish powershell elvish" -complete -c just -n "__fish_use_subcommand" -s s -l show -d 'Show information about ' -complete -c just -n "__fish_use_subcommand" -l dotenv-filename -d 'Search for environment file named instead of `.env`' -complete -c just -n "__fish_use_subcommand" -s E -l dotenv-path -d 'Load as environment file instead of searching for one' -complete -c just -n "__fish_use_subcommand" -l check -d 'Run `--fmt` in \'check\' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.' -complete -c just -n "__fish_use_subcommand" -l yes -d 'Automatically confirm all recipes.' -complete -c just -n "__fish_use_subcommand" -s n -l dry-run -d 'Print what just would do without doing it' -complete -c just -n "__fish_use_subcommand" -l highlight -d 'Highlight echoed recipe lines in bold' -complete -c just -n "__fish_use_subcommand" -l no-aliases -d 'Don\'t show aliases in list' -complete -c just -n "__fish_use_subcommand" -l no-deps -d 'Don\'t run recipe dependencies' -complete -c just -n "__fish_use_subcommand" -l no-dotenv -d 'Don\'t load `.env` file' -complete -c just -n "__fish_use_subcommand" -l no-highlight -d 'Don\'t highlight echoed recipe lines in bold' -complete -c just -n "__fish_use_subcommand" -s q -l quiet -d 'Suppress all output' -complete -c just -n "__fish_use_subcommand" -l shell-command -d 'Invoke with the shell used to run recipe lines and backticks' -complete -c just -n "__fish_use_subcommand" -l clear-shell-args -d 'Clear shell arguments' -complete -c just -n "__fish_use_subcommand" -s u -l unsorted -d 'Return list and summary entries in source order' -complete -c just -n "__fish_use_subcommand" -l unstable -d 'Enable unstable features' -complete -c just -n "__fish_use_subcommand" -s v -l verbose -d 'Use verbose output' -complete -c just -n "__fish_use_subcommand" -l changelog -d 'Print changelog' -complete -c just -n "__fish_use_subcommand" -l choose -d 'Select one or more recipes to run using a binary chooser. If `--chooser` is not passed the chooser defaults to the value of $JUST_CHOOSER, falling back to `fzf`' -complete -c just -n "__fish_use_subcommand" -l dump -d 'Print justfile' -complete -c just -n "__fish_use_subcommand" -s e -l edit -d 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`' -complete -c just -n "__fish_use_subcommand" -l evaluate -d 'Evaluate and print all variables. If a variable name is given as an argument, only print that variable\'s value.' -complete -c just -n "__fish_use_subcommand" -l fmt -d 'Format and overwrite justfile' -complete -c just -n "__fish_use_subcommand" -l init -d 'Initialize new justfile in project root' -complete -c just -n "__fish_use_subcommand" -s l -l list -d 'List available recipes and their arguments' -complete -c just -n "__fish_use_subcommand" -l summary -d 'List names of available recipes' -complete -c just -n "__fish_use_subcommand" -l variables -d 'List names of variables' -complete -c just -n "__fish_use_subcommand" -s h -l help -d 'Print help information' -complete -c just -n "__fish_use_subcommand" -s V -l version -d 'Print version information' +complete -c just -l chooser -d 'Override binary invoked by `--choose`' -r +complete -c just -l color -d 'Print colorful output' -r -f -a "{auto '',always '',never ''}" +complete -c just -l command-color -d 'Echo recipe lines in ' -r -f -a "{black '',blue '',cyan '',green '',purple '',red '',yellow ''}" +complete -c just -l dump-format -d 'Dump justfile as ' -r -f -a "{just '',json ''}" +complete -c just -l list-heading -d 'Print before list' -r +complete -c just -l list-prefix -d 'Print before each list item' -r +complete -c just -s f -l justfile -d 'Use as justfile' -r -F +complete -c just -l set -d 'Override with ' -r +complete -c just -l shell -d 'Invoke to run recipes' -r +complete -c just -l shell-arg -d 'Invoke shell with as an argument' -r +complete -c just -s d -l working-directory -d 'Use 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 ' -r -f -a "{bash '',elvish '',fish '',powershell '',zsh ''}" +complete -c just -s s -l show -d 'Show information about ' -r +complete -c just -l dotenv-filename -d 'Search for environment file named instead of `.env`' -r +complete -c just -s E -l dotenv-path -d 'Load as environment file instead of searching for one' -r -F +complete -c just -l check -d 'Run `--fmt` in \'check\' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.' +complete -c just -l yes -d 'Automatically confirm all recipes.' +complete -c just -s n -l dry-run -d 'Print what just would do without doing it' +complete -c just -l highlight -d 'Highlight echoed recipe lines in bold' +complete -c just -l no-aliases -d 'Don\'t show aliases in list' +complete -c just -l no-deps -d 'Don\'t run recipe dependencies' +complete -c just -l no-dotenv -d 'Don\'t load `.env` file' +complete -c just -l no-highlight -d 'Don\'t highlight echoed recipe lines in bold' +complete -c just -s q -l quiet -d 'Suppress all output' +complete -c just -l shell-command -d 'Invoke with the shell used to run recipe lines and backticks' +complete -c just -l clear-shell-args -d 'Clear shell arguments' +complete -c just -s u -l unsorted -d 'Return list and summary entries in source order' +complete -c just -l unstable -d 'Enable unstable features' +complete -c just -s v -l verbose -d 'Use verbose output' +complete -c just -l changelog -d 'Print changelog' +complete -c just -l choose -d 'Select one or more recipes to run using a binary chooser. If `--chooser` is not passed the chooser defaults to the value of $JUST_CHOOSER, falling back to `fzf`' +complete -c just -l dump -d 'Print justfile' +complete -c just -s e -l edit -d 'Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`' +complete -c just -l evaluate -d 'Evaluate and print all variables. If a variable name is given as an argument, only print that variable\'s value.' +complete -c just -l fmt -d 'Format and overwrite justfile' +complete -c just -l init -d 'Initialize new justfile in project root' +complete -c just -s l -l list -d 'List available recipes and their arguments' +complete -c just -l summary -d 'List names of available recipes' +complete -c just -l variables -d 'List names of variables' +complete -c just -s h -l help -d 'Print help' +complete -c just -s V -l version -d 'Print version' diff --git a/completions/just.powershell b/completions/just.powershell index fbdc529ba8..f46cea1a2e 100644 --- a/completions/just.powershell +++ b/completions/just.powershell @@ -11,7 +11,8 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock { $element = $commandElements[$i] if ($element -isnot [StringConstantExpressionAst] -or $element.StringConstantType -ne [StringConstantType]::BareWord -or - $element.Value.StartsWith('-')) { + $element.Value.StartsWith('-') -or + $element.Value -eq $wordToComplete) { break } $element.Value @@ -38,7 +39,7 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock { [CompletionResult]::new('-s', 's', [CompletionResultType]::ParameterName, 'Show information about ') [CompletionResult]::new('--show', 'show', [CompletionResultType]::ParameterName, 'Show information about ') [CompletionResult]::new('--dotenv-filename', 'dotenv-filename', [CompletionResultType]::ParameterName, 'Search for environment file named instead of `.env`') - [CompletionResult]::new('-E', 'E', [CompletionResultType]::ParameterName, 'Load as environment file instead of searching for one') + [CompletionResult]::new('-E', 'E ', [CompletionResultType]::ParameterName, 'Load as environment file instead of searching for one') [CompletionResult]::new('--dotenv-path', 'dotenv-path', [CompletionResultType]::ParameterName, 'Load as environment file instead of searching for one') [CompletionResult]::new('--check', 'check', [CompletionResultType]::ParameterName, 'Run `--fmt` in ''check'' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.') [CompletionResult]::new('--yes', 'yes', [CompletionResultType]::ParameterName, 'Automatically confirm all recipes.') @@ -70,10 +71,10 @@ Register-ArgumentCompleter -Native -CommandName 'just' -ScriptBlock { [CompletionResult]::new('--list', 'list', [CompletionResultType]::ParameterName, 'List available recipes and their arguments') [CompletionResult]::new('--summary', 'summary', [CompletionResultType]::ParameterName, 'List names of available recipes') [CompletionResult]::new('--variables', 'variables', [CompletionResultType]::ParameterName, 'List names of variables') - [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information') - [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help information') - [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version information') - [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version information') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('-V', 'V ', [CompletionResultType]::ParameterName, 'Print version') + [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version') break } }) diff --git a/completions/just.zsh b/completions/just.zsh index 45f06a781a..4550daa7e9 100644 --- a/completions/just.zsh +++ b/completions/just.zsh @@ -15,35 +15,35 @@ _just() { local context curcontext="$curcontext" state line local common=( -'--chooser=[Override binary invoked by `--choose`]' \ +'--chooser=[Override binary invoked by \`--choose\`]: : ' \ '--color=[Print colorful output]: :(auto always never)' \ '--command-color=[Echo recipe lines in ]: :(black blue cyan green purple red yellow)' \ -'--dump-format=[Dump justfile as ]: :(just json)' \ -'--list-heading=[Print before list]' \ -'--list-prefix=[Print before each list item]' \ -'-f+[Use as justfile]' \ -'--justfile=[Use as justfile]' \ -'*--set[Override with ]: :_just_variables' \ -'--shell=[Invoke to run recipes]' \ -'*--shell-arg=[Invoke shell with as an argument]' \ -'-d+[Use as working directory. --justfile must also be set]' \ -'--working-directory=[Use as working directory. --justfile must also be set]' \ -'-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 ]: :(zsh bash fish powershell elvish)' \ -'-s+[Show information about ]: :_just_commands' \ -'--show=[Show information about ]: :_just_commands' \ -'(-E --dotenv-path)--dotenv-filename=[Search for environment file named instead of `.env`]' \ -'-E+[Load as environment file instead of searching for one]' \ -'--dotenv-path=[Load as environment file instead of searching for one]' \ -'--check[Run `--fmt` in '\''check'\'' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.]' \ +'--dump-format=[Dump justfile as ]:FORMAT:(just json)' \ +'--list-heading=[Print before list]:TEXT: ' \ +'--list-prefix=[Print before each list item]:TEXT: ' \ +'-f+[Use as justfile]: :_files' \ +'--justfile=[Use as justfile]: :_files' \ +'*--set=[Override with ]: :(_just_variables)' \ +'--shell=[Invoke to run recipes]: : ' \ +'*--shell-arg=[Invoke shell with as an argument]: : ' \ +'-d+[Use as working directory. --justfile must also be set]: :_files' \ +'--working-directory=[Use as working directory. --justfile must also be set]: :_files' \ +'*-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:(bash elvish fish powershell zsh)' \ +'-s+[Show information about ]: :(_just_commands)' \ +'--show=[Show information about ]: :(_just_commands)' \ +'(-E --dotenv-path)--dotenv-filename=[Search for environment file named instead of \`.env\`]: : ' \ +'-E+[Load as environment file instead of searching for one]: :_files' \ +'--dotenv-path=[Load as environment file instead of searching for one]: :_files' \ +'--check[Run \`--fmt\` in '\''check'\'' mode. Exits with 0 if justfile is formatted correctly. Exits with 1 and prints a diff if formatting is required.]' \ '--yes[Automatically confirm all recipes.]' \ '(-q --quiet)-n[Print what just would do without doing it]' \ '(-q --quiet)--dry-run[Print what just would do without doing it]' \ '--highlight[Highlight echoed recipe lines in bold]' \ '--no-aliases[Don'\''t show aliases in list]' \ '--no-deps[Don'\''t run recipe dependencies]' \ -'--no-dotenv[Don'\''t load `.env` file]' \ +'--no-dotenv[Don'\''t load \`.env\` file]' \ '--no-highlight[Don'\''t highlight echoed recipe lines in bold]' \ '(-n --dry-run)-q[Suppress all output]' \ '(-n --dry-run)--quiet[Suppress all output]' \ @@ -55,10 +55,10 @@ _just() { '*-v[Use verbose output]' \ '*--verbose[Use verbose output]' \ '--changelog[Print changelog]' \ -'--choose[Select one or more recipes to run using a binary chooser. If `--chooser` is not passed the chooser defaults to the value of $JUST_CHOOSER, falling back to `fzf`]' \ +'--choose[Select one or more recipes to run using a binary chooser. If \`--chooser\` is not passed the chooser defaults to the value of \$JUST_CHOOSER, falling back to \`fzf\`]' \ '--dump[Print justfile]' \ -'-e[Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`]' \ -'--edit[Edit justfile with editor given by $VISUAL or $EDITOR, falling back to `vim`]' \ +'-e[Edit justfile with editor given by \$VISUAL or \$EDITOR, falling back to \`vim\`]' \ +'--edit[Edit justfile with editor given by \$VISUAL or \$EDITOR, falling back to \`vim\`]' \ '--evaluate[Evaluate and print all variables. If a variable name is given as an argument, only print that variable'\''s value.]' \ '--fmt[Format and overwrite justfile]' \ '--init[Initialize new justfile in project root]' \ @@ -66,10 +66,10 @@ _just() { '--list[List available recipes and their arguments]' \ '--summary[List names of available recipes]' \ '--variables[List names of variables]' \ -'-h[Print help information]' \ -'--help[Print help information]' \ -'-V[Print version information]' \ -'--version[Print version information]' \ +'-h[Print help]' \ +'--help[Print help]' \ +'-V[Print version]' \ +'--version[Print version]' \ ) _arguments "${_arguments_options[@]}" $common \ @@ -114,6 +114,7 @@ _just() { esac return ret + } (( $+functions[_just_commands] )) || @@ -138,7 +139,8 @@ _just_commands() { } -(( $+functions[_just_variables] )) || +if [ "$funcstack[1]" = "_just" ]; then + (( $+functions[_just_variables] )) || _just_variables() { [[ $PREFIX = -* ]] && return 1 integer ret=1 @@ -158,3 +160,6 @@ _just_variables() { } _just "$@" +else + compdef _just just +fi diff --git a/src/error.rs b/src/error.rs index 0a59ca7df4..9bcf2719df 100644 --- a/src/error.rs +++ b/src/error.rs @@ -142,10 +142,13 @@ pub(crate) enum Error<'src> { line_number: Option, signal: i32, }, - TmpdirIo { + TempdirIo { recipe: &'src str, io_error: io::Error, }, + TempfileIo { + io_error: io::Error, + }, Unknown { recipe: &'src str, line_number: Option, @@ -403,10 +406,13 @@ impl<'src> ColorDisplay for Error<'src> { write!(f, "Recipe `{recipe}` was terminated by signal {signal}")?; } } - TmpdirIo { recipe, io_error } => { + TempdirIo { recipe, io_error } => { write!(f, "Recipe `{recipe}` could not be run because of an IO error while trying to create a temporary \ directory or write a file to that directory: {io_error}")?; } + TempfileIo { io_error } => { + write!(f, "Tempfile I/O error: {io_error}")?; + } Unknown { recipe, line_number} => { if let Some(n) = line_number { write!(f, "Recipe `{recipe}` failed on line {n} for an unknown reason")?; diff --git a/src/recipe.rs b/src/recipe.rs index f5850a5066..5834d5b3bb 100644 --- a/src/recipe.rs +++ b/src/recipe.rs @@ -336,7 +336,7 @@ impl<'src, D> Recipe<'src, D> { Some(tempdir) => tempdir_builder.tempdir_in(context.search.working_directory.join(tempdir)), None => tempdir_builder.tempdir(), } - .map_err(|error| Error::TmpdirIo { + .map_err(|error| Error::TempdirIo { recipe: self.name(), io_error: error, })?; @@ -344,7 +344,7 @@ impl<'src, D> Recipe<'src, D> { path.push(shebang.script_filename(self.name())); { - let mut f = fs::File::create(&path).map_err(|error| Error::TmpdirIo { + let mut f = fs::File::create(&path).map_err(|error| Error::TempdirIo { recipe: self.name(), io_error: error, })?; @@ -372,14 +372,14 @@ impl<'src, D> Recipe<'src, D> { } f.write_all(text.as_bytes()) - .map_err(|error| Error::TmpdirIo { + .map_err(|error| Error::TempdirIo { recipe: self.name(), io_error: error, })?; } // make script executable - Platform::set_execute_permission(&path).map_err(|error| Error::TmpdirIo { + Platform::set_execute_permission(&path).map_err(|error| Error::TempdirIo { recipe: self.name(), io_error: error, })?; diff --git a/src/subcommand.rs b/src/subcommand.rs index 69442f5cb7..30417e0229 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -291,23 +291,25 @@ impl Subcommand { } let mut script = { - let mut tmp = tempfile() - .map_err(|e| Error::internal(format!("Failed to create tempfile for completions: {e}")))?; + let mut tempfile = tempfile().map_err(|io_error| Error::TempfileIo { io_error })?; + clap_complete::generate( shell, &mut crate::config::Config::app(), env!("CARGO_PKG_NAME"), - &mut tmp, + &mut tempfile, ); - tmp.rewind().map_err(|e| { - Error::internal(format!( - "Failed to rewind tempfile to read completions to update: {e}" - )) - })?; + + tempfile + .rewind() + .map_err(|io_error| Error::TempfileIo { io_error })?; + let mut buffer = String::new(); - tmp + + tempfile .read_to_string(&mut buffer) - .map_err(|e| Error::internal(format!("Failed to read completions from tempfile: {e}")))?; + .map_err(|io_error| Error::TempfileIo { io_error })?; + buffer }; From dee0c14601e4570e8c37045f270b41e64eb7fc79 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 14 May 2024 20:27:43 -0700 Subject: [PATCH 8/8] Adjust --- src/config.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/config.rs b/src/config.rs index 0b2976a072..10a15caa8e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -720,10 +720,11 @@ impl Config { #[cfg(test)] mod tests { - use super::*; - - use clap::error::{ContextKind, ContextValue}; - use pretty_assertions::assert_eq; + use { + super::*, + clap::error::{ContextKind, ContextValue}, + pretty_assertions::assert_eq, + }; macro_rules! test { {