Visitar URL original
Releases · jdx/usage · GitHub
Skip to content

Releases

v7.3.0: Shared `completion` subcommand for usage-rs CLIs

Choose a tag to compare

@github-actions github-actions released this 06 Nov 03:13
Immutable release. Only release title and notes can be modified.
facfe1a

usage-rs now ships a ready-made completion subcommand. Every CLI built on it can mount the command, so they all print and install shell completions the same way.

Added

  • (lib) New usage_rs::completion::Completion subcommand, available with the completions feature (#1624, @jdx). Until now each tool wrote its own completion command: some had --install, while others printed a script for the user to redirect by hand. You can now mount the shared command instead:

    use usage_rs::completion::Completion;
    
    #[derive(Subcommands)]
    enum Commands {
        /// Generate shell completions
        Completion(Completion),
    }
    
    // in the run function:
    completion.run("ex", &mut std::io::stdout())?;

    Any tool that mounts it gets these commands:

    ex completion fish                     # print the script, e.g. `ex completion fish | source`
    ex completion fish --install           # write it where fish looks for it
    ex completion fish --install --force   # also replace a file usage did not generate
    
    • Shells: bash, elvish, fish, nu/nushell, powershell/pwsh and zsh are accepted. Any other shell name fails to parse.
    • Flags: --force requires --install.
    • Scripts: The scripts are the short callback scripts. They contain no spec and don't need the usage binary. On every Tab they ask the installed tool for candidates, so they stay correct when the tool is upgraded.
    • Installing: --install never edits a startup file. If a shell needs a line added once, the command prints that line after the install path.
    • Errors: Completion::run returns Error::Install or Error::Output. A closed pipe (for example ex completion zsh | head) is not treated as an error.
    • Testing: Completion::run_in takes an explicit Env, so tests can install without touching the real home directory.

    The Rust completions guide (docs/rust/completions.md) now uses Completion in place of the hand-written example.

Full Changelog: v7.2.0...v7.3.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.

v7.2.0: Refuse unknown environment variables under an application prefix

Choose a tag to compare

@github-actions github-actions released this 03 Nov 18:13
Immutable release. Only release title and notes can be modified.
aee991b

A CLI can now claim an environment variable prefix. Any variable under that prefix that the spec doesn't declare then makes the parse fail, which catches typos and stale names in deployment config. This release also lets derive flags declare their own settings, makes flags inside clauses set their settings, and adds --help/--version to tab completion.

Added

  • (spec) New opt-in unknown_env node (#1609, @jdx). When it's set, a parse fails if the environment holds any variable under the prefix that nothing in the spec reads, and the error lists every such variable at once. Without the node, nothing changes.

    unknown_env prefix="MOQ_" {
      allow "MOQ_VAAPI_DEVICE" "MOQ_V4L2_ENCODER"
    }
    flag "--port <port>" env="MOQ_PORT"
    cmd "serve" {
      flag "--tls-cert <path>" env="MOQ_TLS_CERT" deprecated_env="MOQ_CERT"
    }

    Rust derive CLIs declare it on the root struct: #[usage(bin = "moq", unknown_env(prefix = "MOQ_", allow("MOQ_VAAPI_DEVICE")))]. With MOQ_PROT and MOQ_TSL set, a derived CLI exits 2:

    error: unknown environment variables under 'MOQ_':
      MOQ_PROT
      MOQ_TSL
    

    A variable counts as known if anything in the command tree declares it, not only the command that ran. That covers env, env_fallback and deprecated_env on any flag or argument, including those in subcommands, flattened groups and clauses. It also covers variables read by config properties and names in allow. Other details:

    • The prefix only limits which variables are checked. It is never used to build a variable name, so this is not clap's env_prefix.
    • Deprecated names still produce a deprecation warning rather than an error.
    • --help and --version are answered before the check runs.
    • On Windows, names are compared case-insensitively.

    In usage-lib, Parser checks the map passed to Parser::with_env if there is one, and the process environment otherwise. It reports a UsageErr::UnknownEnv.

  • (go) Parsers from usage generate go now enforce unknown_env too (#1612, @jdx). Before this, generated Go ignored the node. The check runs before required flags and arguments are checked, and it reports offenders in sorted order:

    error: unknown environment variables under `MOQ_`: `MOQ_PROT`, `MOQ_TSL`
    

    The Go generator can't see what variables a mounted command declares, so usage generate go fails on a spec that has both unknown_env and a mount. go/argv adds UnknownEnv, RefuseUnknownEnv, EnvNames and the error code CodeUnknownEnv.

  • (derive) A field with setting = "key" now declares that setting on its own, so you no longer need a matching #[derive(Config)] field (#1610, @jdx). The registry entry takes its type from the field's type and its environment names from env/env_fallback/deprecated_env. List splitting comes from delimiter (, or :), help comes from the doc comment, and the flags are every flag bound to the key. The root Cli now exposes SETTINGS_PROPS and SETTINGS_REGISTRY, and its spec gets a config block even when there is no config = Type.

    #[derive(usage_rs::Args)]
    struct ListenTls {
        /// Load the given certificate from disk.
        #[usage(long = "listen-tls-cert", env = "EX_LISTEN_TLS_CERT", delimiter = ',',
                setting = "listen.tls.cert")]
        cert: Vec<std::path::PathBuf>,
    }

    If several subcommands bind the same key, they must agree on field type, environment names and delimiter. Otherwise it's a compile error. Existing CLIs don't need to change, because a key declared on the config struct takes precedence over the flag. Settings that need a default, merge, scope or choices still have to be Config fields. Settings declared only by a flag are always optional and have no default.

Fixed

  • (complete) Tab completion now offers -h/--help, and -V/--version where the parser accepts them (#1605, @jdx). Before this fix, CLIs compiled from the derive and usage itself never offered these flags. This applies to both the derive and usage complete-word. A spelling that a declared flag already uses (hidden flags included) is not offered twice, and disable_help_flag/disable_version_flag are respected. Also, merging a mounted spec no longer clears disable_help_flag, disable_help_subcommand or disable_version_flag on the host command. For example, mise run no longer gets --help back from the mounted root.
  • (derive) A flag with setting = "key" inside a #[usage(clause)] element now sets its setting, the same way a flag in a flattened group does (#1611, @jdx). When several clause items give the same setting, list settings collect every entry in order and other settings keep the last value. A root whose only bound flags are in clauses can now use #[usage(settings)]. Before this fix, that failed to compile.

Full Changelog: v7.1.5...v7.2.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.

v7.1.5: Reject relationship properties that name several targets

Choose a tag to compare

@github-actions github-actions released this 01 Nov 10:10
Immutable release. Only release title and notes can be modified.
b15054a

Specs that list several flags in one relationship property, or repeat the property, now fail to load with an error. Before this release, usage accepted them but enforced nothing.

Fixed

  • (spec) A relationship property such as conflicts="--b --c" is now rejected when the spec loads (#1599, @jdx). Previously, --b --c was read as one selector that matched no flag, so --a --b and --a --c both parsed without error. Repeating the property (conflicts="--b" conflicts="--c") also loaded, but only the last value was kept. Both forms now produce an error:

    conflicts takes one flag or argument per property, but "--b --c" has several; write them as a child node instead: conflicts "--a" "--b"
    conflicts is given more than once; the second would replace the first, so write several as a child node instead: conflicts "--a" "--b"
    

    This check applies to conflicts, overrides, requires, required_if, required_unless and required_unless_all on flags, and to the same properties except overrides on positional args. A value is refused only if it has more than one word and at least one starts with a dash. Values like conflicts="input file" still refer to a positional named [input file].

    Upgrading: These specs were never enforcing their relationships, so they now need to be rewritten in the child-node form. That form already worked and has not changed:

    flag "--a" {
      conflicts "--b" "--c"
    }

    The flag reference (docs/spec/reference/flag.md) now covers the child-node form and these load-time errors.

Full Changelog: v7.1.4...v7.1.5

💚 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.

v7.1.4: Mounted scripts tolerate rejected env values; Cobra exporter quotes boolean and numeric defaults

Choose a tag to compare

@github-actions github-actions released this 30 Oct 10:10
Immutable release. Only release title and notes can be modified.
84b039a

A mount run= that reads another usage script's spec no longer fails when an environment variable holds a value that script rejects, and the Cobra exporter now writes specs that usage lint accepts.

Fixed

  • (lib) A mount run= that gets its spec from another usage-shebang script now works even when the environment holds a value that one of that script's env-bound flags rejects (#1591, @jdx). For example, if the child declares flag "--mode <m>" env="X_MODE" { choices "a" "b" }, then X_MODE=zzz ./parent sub used to fail with Invalid choice for option mode: zzz (exit 181), and completion failed the same way. When usage runs the script itself and the parse fails, it now drops the env values the spec rejects and keeps the valid ones. If the parse still fails, the original error is reported. Running the script directly still reports invalid env values, and a bad value typed on the command line is still an error.

    When a mount does fail, the error now names the command being resolved:

    could not read the commands mounted under `sub`: exited with code 1
    sh -c ./child2
    

    This message comes from usage-lib, so CLIs built on it show the same wording. Script exit codes have not changed, and they are now documented in docs/cli/scripts.md: the script's own code when it runs, 1 when the command line doesn't satisfy the spec, and 181 when usage can't read or run something the spec depends on, such as an invalid spec or a failing mount.

  • (cli) The Cobra integration now quotes flag defaults that KDL would otherwise read as non-strings (#1595, @jdx). Before this fix, a Bool flag defaulting to true or an Int flag defaulting to -1 produced default=true or default=-1, and usage lint rejected the spec. Defaults such as true, false, null, inf, -inf, nan, signed numbers (-1, +1, -0.5) and values containing [ or ] are now written as quoted strings. Plain values such as json are still written without quotes.

Full Changelog: v7.1.3...v7.1.4

💚 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.

v7.1.3: Order subcommand help sections by display_order

Choose a tag to compare

@github-actions github-actions released this 26 Oct 10:16
Immutable release. Only release title and notes can be modified.
f357a6c

display_order on a subcommand now sets where its whole help section appears, not just its position within the section. Before this, the ungrouped Commands: section, which holds the built-in help, always came first.

Fixed

  • (cli) CLIs that group subcommands with help_heading can now put the default Commands: section after their named sections (#1583, @jdx). Each section is placed according to the lowest display_order among its commands. A command without a display_order counts as 999, so the built-in help never moves its section forward. Sections with the same value keep their current order. usage-argv runtime help and the usage-lib reference renderer both follow this rule.

    enum Cmds {
        #[usage(display_order = 99)]
        Completion(NoArgs),
        #[usage(help_heading = "Source", display_order = 1)]
        Fmt(NoArgs),
        #[usage(help_heading = "Dependencies", display_order = 2)]
        Fetch(NoArgs),
    }

    Help used to list Commands: (completion, help), then Source:, then Dependencies:. It now lists Source:, Dependencies:, then Commands:.

    If none of your commands set display_order, help looks the same as before. If you set display_order on grouped commands but not on ungrouped ones, the ungrouped section now appears last.

Full Changelog: v7.1.2...v7.1.3

💚 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.

v7.1.2: Completion scripts treat candidates as plain text; mounted commands stop inheriting top-level completers

Choose a tag to compare

@github-actions github-actions released this 24 Oct 10:12
Immutable release. Only release title and notes can be modified.
ad1549d

Generated bash, zsh and fish completion scripts no longer expand completion candidates or file extensions as shell code. Mounted commands also stop picking up the mounting spec's top-level completers. The first fix matters for tools like mise, where candidates can come from project files. Regenerate any completion files you've installed to get the script fixes.

Fixed

  • (complete) Completion candidates and extension filters are now handled as plain text in every shell (#1581, @jdx):
    • bash: usage generate completion bash used to pass candidates through compgen -W, which expands them as shell input. A run= completer that printed $(touch pwned) ran that command when you pressed Tab, and a * candidate turned into the files in the current directory. The completion-init handler had the same globbing problem. Both now read one candidate per line without expanding it, so a candidate that contains a space stays one entry instead of splitting in two.
    • zsh: extension names were inserted directly into the _files -g pattern, and zsh runs glob qualifiers as code. The pattern is now built only from plain extension names (letters, digits, _ . + -). If no usable names are left, completion falls back to unfiltered _files. This also fixes a single extension, which produced *.(toml) and matched nothing. It now produces *.toml.
    • fish: extensions are matched as a literal suffix, so a * or ? in an extension no longer matches extra files.

Changed

  • (complete) A command brought in by mount now uses only the completers it declares itself, in its own complete nodes or inside its arg nodes (#1581, @jdx). Before, a mounted argument that shared a name with a top-level completer (for example <tool>) used the mounting spec's completer, even when the mounted command declared its own. If you type one of the mounting CLI's flags inside a mounted command, its value still completes the same way it does outside the mount. Specs without mounts are unaffected. If a mounted command relied on a top-level completer, declare it in the spec that the mount emits instead, for example with complete "tool" run="..." inside the cmd.

Full Changelog: v7.1.1...v7.1.2

💚 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.

v7.1.1: Fix nushell 0.116 deprecation warning in generated completions

Choose a tag to compare

@github-actions github-actions released this 22 Oct 10:11
Immutable release. Only release title and notes can be modified.
c565982

Nushell completion scripts generated by usage-argv and the Go runtime no longer print a deprecation warning on nushell 0.116.

Fixed

  • (complete) Nushell 0.116 deprecated external completers that take a positional spans argument, so the generated script printed a nu::shell::deprecated warning every time it completed (#1570, @jdx). The completer now uses the {|place|} signature. On 0.116 it reads the tokens from $place.command, and on older nushell releases, which pass the token list directly, it uses that list. If you already had an external completer installed, it still gets called, and it receives the input in the format it expects: the token list for completers written with spans, the original input for everything else. If you saved the script to a file, regenerate it to pick up the fix.

Full Changelog: v7.1.0...v7.1.1

💚 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.

v7.1.0: Effect v4 CLI exporter and bash completion escaping

Choose a tag to compare

@github-actions github-actions released this 19 Oct 10:13
Immutable release. Only release title and notes can be modified.
40a8527

This release adds usage-spec-effect, a new npm package that turns Effect v4 effect/cli command trees into usage specs. It also fixes bash completions from usage-argv, which could pass the command a different value than the one offered when a candidate contained quotes, spaces or other shell syntax.

Added

  • (spec) usage-spec-effect exports a usage spec from an Effect v4 effect/cli command tree (#1564, @jdx). Effect still parses and runs the CLI, and the spec drives shell completions, markdown docs and man pages. It requires effect 4.x.

    npm install usage-spec-effect
    import { generate } from "usage-spec-effect";
    
    if (process.argv.includes("--usage-spec")) {
      process.stdout.write(generate(app, { version: "1.0.0" }));
      process.exit(0);
    }
    mycli --usage-spec | usage generate completion bash mycli --file -

    The exporter handles nested subcommands, aliases, unlisted commands, examples, shared flags (exported as global), flag aliases, boolean and valued flags, choices, defaults, and optional and variadic args. Some constructs can only be exported approximately: orElse alternatives, file, redacted and key-value types (exported as strings), non-primitive defaults, and flags with an optional value. generateWithReport returns these in an unsupported list so they aren't dropped without notice. Effect's public Command type doesn't expose flags or arguments, so the exporter reads the command's runtime config. If a future Effect release changes that shape, generate throws an error that names the command. See the Effect integration guide.

Fixed

  • (bash) usage-argv and usage-dynamic now escape bash completion candidates so the command gets the value that was offered (#1566, @jdx). Before this fix, Readline put candidates on the line unescaped, so a candidate like tasks."hello.sh" reached the command as tasks.hello.sh, and it's here left an unclosed quote on the line. Candidates are now backslash-escaped. When a quote is already open in the word (', " or $'), each candidate is escaped for that quote style instead. Path completions still use Readline's own filename quoting, and zsh and fish were already correct. Hosts handling __complete_word__ should call render_request(&answer, &request) instead of render(&answer, shell) so the open-quote state is used. App::completion_request in usage-dynamic already does this. The script-based bash completions behind usage complete-word are unchanged, since compgen -W can't carry spaces or quotes in candidates.

Full Changelog: v7.0.2...v7.1.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.

v7.0.2: Completion honors .usage.kdl sidecars and shows help for short flags

Choose a tag to compare

@github-actions github-actions released this 17 Oct 10:12
Immutable release. Only release title and notes can be modified.
872ac77

Two completion fixes: completing a script now uses the same .<script>.usage.kdl sidecar spec that usage exec runs with, and short flags show their help text in completion menus.

Fixed

  • (complete) usage complete-word -f <script> now reads a .<script>.usage.kdl file next to the script before falling back to its USAGE comments, the same lookup usage exec already did (#1558, @jdx). Before this, a script with a sidecar completed against the comment spec, or against nothing at all. The bash, zsh and fish scripts from usage generate completion-init call complete-word, so they get the fix without being regenerated. Other usage generate subcommands that take -f <script>, such as completion and markdown, now prefer the sidecar too. When the sidecar doesn't set name or bin, the script's basename is used. Inline specs and stdin input work as before.
  • (complete) Short flags now show their help text in completion menus, as long flags already did (#1561, @Ehsan-hash). For flag "-v --verbose" help="Verbose output", completing -v used to show no description and now shows Verbose output. If a root command and a subcommand both define the same short flag, the menu shows the help for the flag that actually applies. Bash completions still list flag names only, with no descriptions.

New Contributors

Full Changelog: v7.0.1...v7.0.2

💚 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.

v7.0.1: Smaller usage-argv help, completion and error rendering code

Choose a tag to compare

@github-actions github-actions released this 14 Oct 20:08
Immutable release. Only release title and notes can be modified.
84dc627

This release reduces how much code usage-argv adds to CLIs that embed it. Help, -h, version, completion and parse-error output stay byte-for-byte the same, and startup and parse speed are unchanged.

Changed

  • (lib) Help, completion and error rendering in usage-argv produce less machine code (#1551, #1553, #1554, @jdx). String appends, text wrapping, slicing, searching, completion splitting and error suggestions now go through shared helpers instead of being expanded at every call site. In stripped release builds of oxlint and oxfmt, the three PRs together removed about 85 KB from each binary. That covers most of the size those CLIs gained when they moved from bpaf to usage-rs.

Fixed

  • (complete) Split::walked and Split::argv no longer panic when cword is out of range. They now return the whole word list and an empty slice (#1554, @jdx).

Full Changelog: v7.0.0...v7.0.1

💚 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.