Skip to content

v6.12.0: Delegated shell completion, command-backed choices, and usage_cmd for scripts

Latest

Choose a tag to compare

@github-actions github-actions released this 28 Sep 18:01
Immutable release. Only release title and notes can be modified.
197b82b

Wrapper CLIs can now pass completion of their trailing words to the wrapped tool's own shell completion. Argument values can come from a command's output with choices run=, and scripts get the chosen subcommand as $usage_cmd. The release also fixes several completion bugs in bash, zsh and fish, and two crashes in #[derive(Cli)] binaries.

Added

  • (complete) complete … delegate="<command>" completes a wrapped command's arguments with that command's own shell completion (#1498, @jdx). With the spec below, wrapper layer1 plan -o<Tab> offers whatever terraform plan -o<Tab> would. delegate can carry fixed arguments (delegate="kubectl --context prod"), and it can't be combined with run or type. It works in fish, bash (requires bash-completion) and zsh. PowerShell and Nushell get no delegated candidates. Typed words are passed to the shell as arguments, not spliced into a script, so they are never run. If the shell can't answer within 3 seconds, completion falls back to files. Fig output leaves delegated args bare.

    arg "<layer>"
    arg "<command>" var=#true
    complete "command" delegate="terraform"
  • (spec) choices run="…" builds an argument's or flag's allowed values from a command that prints one value per line (#1497, @jdx). These values are used to check input (strict and ignore_case still apply), for Tab completion, and in --help handled by the parser, usage bash and usage exec. Any values written on the node are kept alongside them. Static outputs never run the command. render_help, Markdown and man pages describe it as output of `…` , Fig emits a generator, and Go tables and TypeScript/Python SDK types treat the value as an open string. During a parse, the command runs at most once and only when a declared value doesn't match. Parser::with_env values are passed to it. New library API includes SpecChoices::run, resolved_values(env), SpecArgBuilder::choices_run, usage::docs::cli::render_runtime_help and usage::sh::sh_with_env. Fig generator commands, from both choices run= and complete run=, now escape backslashes, backticks and ${.

    arg "<service>" {
      choices run="docker compose config --services"
    }
  • (spec) A complete node can now sit inside the arg it completes, including a flag's arg, or directly inside a flag as shorthand for its value (#1496, @jdx). The inline form takes run, type and descriptions but no name. It takes precedence over a named complete "<name>" for the same arg. The new Spec::completer(cmd, arg) applies this order, and complete-word, Fig, usage-dynamic and the Go generator all follow it.

    flag "--out <path>" {
        complete type="dir"
    }
  • (lib) Scripts run by usage bash, zsh, fish, powershell and exec get the chosen subcommand's canonical name in usage_cmd, with nested names joined by spaces, such as "db migrate" (#1505, @jdx). It is unset at the top level, and a usage_cmd inherited from a parent process is cleared. If the spec declares its own flag or arg named cmd, that one keeps the variable. The value comes from ParseOutput::as_env, so other embedders such as mise tasks get it too.

  • (lib) FlagMeta, CommandMeta and ArgMeta in usage-rs/usage-argv have a const fn getter for every field, including the fields that 6.11.1 moved into extra (#1491, @jdx). For example, flag.env_fallback() works however the struct is laid out. The fields stay public for now, but v7 plans to hide them, so switch to the getters.

  • (lib) Parser::without_running_commands() parses without starting any choices run= command (#1503, @jdx). A value outside the declared choices is accepted unchecked. usage explain now uses this mode, so explaining a command line against an untrusted spec never runs that spec's commands.

  • (cli) Releases now ship a version-matched usage agent skill for writing specs, parsing script arguments, using usage explain, and generating completions and docs (#1509, @jdx). mise users can install it with mise use usage and then mise skills sync --dir .agents/skills.

Fixed

  • (derive) A generated Cli::parse() no longer panics when output goes to a closed pipe, for example with mycli --help | head -1 or a cancelled completion (#1484, @jdx). Before, panic = "abort" builds aborted with SIGABRT. Exit statuses are unchanged.
  • (derive) Async dispatch generated by #[usage(run_async)] and run_async_with now boxes the selected command's future (#1488, @jdx). Before, debug builds reserved stack for every command's future at each dispatch level, which could overflow the stack in large CLIs (for example, STATUS_STACK_OVERFLOW on Windows). This costs one heap allocation per dispatch level. The API is unchanged.
  • (derive) A renamed usage-rs dependency inherited from [workspace.dependencies] now resolves even when an earlier entry uses a multi-line inline table (#1507, @jdx). The derive now reads manifests with a real TOML parser.
  • (complete) Typed completers (#[usage(complete = my_fn)]) now receive the command line when called through a spec's run= (#1487, @jdx). CompletionRequest::parse used to ignore --line=… and now accepts --option=value for every option that takes a value.
  • (complete) A command line that doesn't parse no longer prints an error over the prompt when you press Tab (#1495, @jdx). zsh shows the message below the prompt with _message. bash, fish and Nushell discard it.
  • (bash) Values for --flag=value now complete when the cursor is after the =, in both per-binary scripts and the completion-init handler (#1499, @jdx).
  • (fish) Words you've started quoting or escaping now complete: 'prod<Tab> finds 'prod env' (#1500, @jdx). Text after the cursor is no longer sent. Multi-line help no longer shows up as extra fake candidates in fish, zsh, Nushell or PowerShell.
  • (zsh) With completion-init zsh sourced, file completion for commands that aren't usage scripts works normally again, including in cases like emacs --<Tab> that used to insert a literal * (#1493, @jdx). The fix applies from the next shell start.
  • (cli) usage bash <(…), /dev/stdin and other pipe or FIFO script paths used to run an empty script and exit 0. usage now copies the script to a private temp directory first, for bash, zsh, fish and PowerShell (#1494, @jdx).
  • (lib) The published usage-rs crate's tests now pass on their own, so downstream packagers such as Debian can test the released source (#1510, @jdx).

Changed

  • All crates now use the Rust 2024 edition, and the minimum supported Rust version stays at 1.91 (#1511, @jdx). Public macros accept 2024 expression syntax such as var_min = const { 1 }. Generated shadow crates rename reserved field names such as --gen to gen_.

Upgrading

Regenerate completion scripts made with usage generate completion <shell> <bin> to get the fixes from #1495 (all shells), #1499 (bash) and #1500 (fish). If you use completion-init, just start a new shell.

Full Changelog: v6.11.1...v6.12.0

💚 Sponsor usage

usage is built and maintained by @jdx, an open source developer at entire.io, the title sponsor of his open source work.

If usage powers CLI specs, docs, or completions for a tool you maintain or use, please consider becoming an individual or company sponsor. Your support funds ongoing development and helps keep usage fast, free, and independent.