Skip to content

Releases: jdx/usage

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.

v7.0.0: Derive macros no longer read Cargo.toml; `usage generate fig` removed

Choose a tag to compare

@github-actions github-actions released this 14 Oct 13:32
Immutable release. Only release title and notes can be modified.
a39e2b3

The derive macros now generate code against usage_rs directly instead of reading your Cargo.toml, usage generate fig has been removed, and the fields on argv metadata types are no longer public API. usage exec now accepts interpreter arguments, and this release also fixes how -- is handled by the shell runners and how multi-line examples are indented in help.

Breaking Changes

All of these come from #1532 (@jdx).

  • The derive macros always generate paths through ::usage_rs. In 6.12, usage-derive parsed your Cargo.toml to work out how usage-rs was imported. That put toml and related crates into every downstream build. The macros no longer read the manifest, so toml is out of the dependency tree. If a derive can't find the facade crate, compilation fails with unresolved import usage_rs. To upgrade:
    • Depend on usage-rs under its own name: usage-rs = { version = "7" }.
    • If you import it under another name, such as usage = { package = "usage-rs", ... }, add #[usage(crate = usage)] to each derive that needs it. The attribute works on Cli, Args, Subcommands, ValueEnum, ArgGroup and Config, and you have to repeat it on every derive.
      #[derive(usage::Cli)]
      #[usage(crate = usage, bin = "ex")]
      struct Ex { /* ... */ }
    • If you depend directly on usage-argv, usage-derive, usage-config or usage-validation, also add usage-rs = { version = "7", default-features = false, features = ["spec"] }. Turn on the config or validation features if you use those crates, since they're now reached through usage_rs::config and usage_rs::validation.
    • schema_from = T now always generates ::schemars. If you renamed the schemars dependency, change it back to its real name.
    • The derives no longer look up workspace-inherited or target-specific dependencies.
  • usage generate fig is removed. Fig shut down in 2024. Use usage generate completion <shell> instead.
  • Fields on FlagMeta, CommandMeta and ArgMeta in usage-argv are now #[doc(hidden)]. Their struct layout is no longer covered by semver. Use the existing accessor methods instead, for example flag.env_fallback() rather than flag.env_fallback.

Added

  • (cli) usage exec takes a quoted interpreter followed by its own arguments, and splits them the way a shell would (#1537, @jdx). Before this, there was no shebang form for interpreters that need flags before the script path, such as Deno's run and its permission flags. Values without whitespace, values that are paths to existing files, and the unquoted form all work as before.
    #!/usr/bin/env -S usage exec "deno run --allow-env=usage_*"
    //USAGE arg "<name>" help="Name to greet"

Fixed

  • (cli) In usage bash, zsh, fish and powershell, words after -- now reach the script as values (#1541, @jdx). Previously, usage bash script.sh positional -- --help printed the script's help with an Error: prefix and exited with status 1. -h and --help still show help when they come before --.
  • (cli) In --help output, every line of a multi-line example is now indented (#1548, @jdx). Before, sample output lines after the first started at column 0.

Full Changelog: v6.12.1...v7.0.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.

v6.12.1: Test suite passes with each optional feature enabled on its own

Choose a tag to compare

@github-actions github-actions released this 06 Oct 10:39
Immutable release. Only release title and notes can be modified.
4de0837

This release doesn't change runtime behavior or public APIs. It matters mainly to downstream packagers who test each optional feature of the crates separately.

Fixed

  • (lib) The test suites now pass when an optional feature is enabled on its own (#1513, @jdx). Four configurations used to fail even though the all-features tests passed: usage-argv with only complete, only diagnostics or only spec, and usage-rs with only test. CI now tests each of these separately. This brings in the two test patches from Debian's packaging (debcargo-conf MR !1447), which packagers can drop starting with this release.

Full Changelog: v6.12.0...v6.12.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.

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

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.

v6.11.1: Smaller usage-argv footprint in derived CLIs, and coloured help stops styling look-alike prose

Choose a tag to compare

@github-actions github-actions released this 23 Sep 15:19
Immutable release. Only release title and notes can be modified.
13c051e

The help, completion, parse-error and metadata code that usage-argv adds to a #[derive(Cli)] binary is substantially smaller, with byte-identical output, and coloured help pages no longer colour author text that happens to look like a heading or a flag row.

Fixed

  • (help) Coloured help colours only the structure the renderer itself writes (#1480, @jdx). Colour used to be applied by matching every finished line against the page's headings, synopsis and row usages, so a line reading Flags: in after_help/before_help/about, or heading prose that began with a flag's spelling such as -f, --force overrides the *lock*, came out styled as a heading or a flag row. Headings, the synopsis, row usages and command names are now coloured as they are written, and the remaining pass over the page applies only Markdown emphasis (**bold**, *italic*, `code`, ~~strike~~), still skipping $ example lines. Plain (non-TTY) output was never affected and is unchanged.

Changed

  • (argv) Less code and static data per derived CLI (#1469, #1471, #1476, #1475, #1477, #1478, @jdx). Help rows for -h and --help go through one renderer, coloured-help structure is collected while the page is written instead of by a second metadata walk, the __complete_word__ handler and the value-binding/error-exit code that the derive used to expand into every CLI now live in the runtime, the parse-error renderer builds messages from data instead of per-error formatting code, and cold-path lists (help rows, completion candidates, "did you mean" suggestions) share one stable sort instead of six monomorphised quicksorts. View-related branches fold away entirely for CLIs that declare no views. Help, error, spec and completion output was compared byte for byte before and after each change and is identical; a completion request now also walks the command line once instead of twice.

  • (argv) Smaller metadata tables (#1470, #1472, #1474, @jdx). Rarely declared flag fields (relations, deprecation, validation, bounds, hidden aliases, spec-only metadata) moved into FlagExtra behind FlagMeta::extra, and rarely declared command fields (deprecation, help prose, examples, headings, outputs, layout settings, clause, exit codes) into CommandExtra behind CommandMeta::extra; every flag or command that declares none of them points at one shared static. Clauses are stored by reference and display_order, variadic bounds and terminal widths are narrowed to u32/u16. A FlagMeta shrinks from 664 to 168 bytes and a CommandMeta from about 600 to 472. Declared values too large for the narrower types now saturate rather than wrap (a display_order above u32::MAX sorts last; term_width = 0 still disables wrapping).

    Measured on oxlint and oxfmt with their release profile (opt-level 3, fat LTO, one codegen unit, linux x86_64), the first two changes alone cut what usage-rs adds over bpaf from about 219 KB to 138 KB for oxlint (from 169 KB to 114 KB for oxfmt), and each of the remaining changes took a further 1 to 14 KB off.

Breaking Changes

Only code that reads or hand-writes usage-argv metadata tables directly is affected; CLIs built with #[derive(Cli)], Args or ArgGroup need no changes.

  • Fields moved off FlagMeta and CommandMeta are reached through extra (#1470, #1472):

    // before
    if let Some(reason) = meta.deprecated { /* … */ }
    // after
    if let Some(reason) = meta.extra.deprecated { /* … */ }
    
    // hand-written table
    static META: CommandMeta = CommandMeta {
        cmd: &CMD,
        about: Some("…"),
        extra: &CommandExtra {
            deprecated: Some("use `new`"),
            ..CommandExtra::EMPTY
        },
        ..CommandMeta::EMPTY
    };

    ..FlagMeta::EMPTY and ..CommandMeta::EMPTY already point at the shared NO_FLAG_EXTRA/NO_COMMAND_EXTRA, so entries with no extras keep working unchanged.

  • Command::clause is now Option<&Clause> and CommandMeta::clause (now under extra) is Option<&ClauseMeta>, so hand-written tables borrow the clause: clause: Some(&TASKS). display_order, var_min/var_max and value_var_min/value_var_max are Option<u32>, and term_width/max_term_width are Option<u16>; integer literals need no change, but code that read them as usize needs a conversion (#1474). Event::ClauseSeparator still carries the Clause by value.

Full Changelog: v6.11.0...v6.11.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.

v6.11.0: Help pages fill the terminal width and can carry a logo; default subcommands on empty invocations

Choose a tag to compare

@github-actions github-actions released this 21 Sep 16:19
Immutable release. Only release title and notes can be modified.
0676af0

Help output now wraps to the real terminal width instead of a fixed 80 columns, a spec can put ASCII art on its root help page, and default_subcommand_on_empty routes a bare invocation to the default subcommand.

Added

  • (parse) default_subcommand_on_empty selects the default subcommand on an empty invocation (#1458, @zeitlinger). Until now default_subcommand only fired on an unmatched word, so ex with no arguments stayed on the root. With this opt-in (Rust: #[usage(default_subcommand = "run", default_subcommand_on_empty)]), a bare ex or one carrying only parent/global flags such as ex --verbose parses as ex run, with child env values and defaults bound afterwards and the child validated exactly as if it had been named. Explicit commands, positional values, a syntactic --, --help, --version, and parse errors keep their normal precedence; root requirements still apply unless subcommand_negates_reqs is set. It requires default_subcommand (usage lint reports invalid-default-subcommand-on-empty otherwise) and is implemented in the Rust library, usage-argv, generated Go parsers, and the Go runtime.

    default_subcommand "run"
    default_subcommand_on_empty #true
    cmd "run" { arg "[path]" }
  • (spec) logo puts art on the root help page (#1455, @jdx). The optional style property takes the same +-combined vocabulary as help_template (for example "cyan+bold") and is validated when the spec is parsed, or at compile time for #[usage(logo = include_str!("logo.txt"), logo_style = "cyan+bold")]. Placement depends on terminal width: beside the page when at least 50 columns remain after the art and a two-column gutter, above it as a banner when they do not, and omitted entirely when the terminal is narrower than the art. The logo appears only on the root's -h/--help, never on subcommand pages or in generated Markdown, man pages, or SDKs, and plain (non-TTY) output strips its escapes. usage --help itself now shows the project's logo. The Rust library, usage-argv, and Go renderers share one placement rule.

    logo #"""
      /\
     /  \
    /____\
    """# style="cyan+bold"

Fixed

  • (help) Help is laid out at the terminal's actual width (#1454, @jdx). Width came only from COLUMNS, which almost no process has set, so nearly every CLI built on usage wrapped at 80 columns regardless of the window. The renderers now probe the terminal (TIOCGWINSZ on unix, the console buffer on Windows) when COLUMNS is unset; output to a pipe or file still uses 80, and a declared term_width/max_term_width still wins. The probe is exposed as usage_argv::tty::columns(). The Go renderer still uses a fixed 80 columns.
  • (help) Cli::render_help now colours its output by the same rule as parse(): ANSI on a terminal, plain elsewhere, NO_COLOR respected (#1454). CLIs that handled usage::Error::Help themselves were getting a monochrome page. Callers that keep the text rather than printing it can use the new Cli::render_help_styled(cmd, long, Style::PLAIN) to guarantee escape-free output; see Breaking Changes.
  • (help) Examples are separated by a blank line on both -h and --help, in all three renderers, instead of running together as a single block (#1454).
  • (cli) The published usage-cli crate now includes src/cli/logo.txt, which the initial 6.11.0 publish was missing and failed on (#1459, @jdx).

Breaking Changes

  • Cli::render_help (the derive-generated method) may now return ANSI escape sequences when stdout is a terminal. Code that writes its result to a file, compares it in a snapshot, or embeds it in a document should switch to Cli::render_help_styled(cmd, long, Style::PLAIN); setting NO_COLOR also forces plain output with no code change. usage_argv::help::render is unchanged and still plain.
  • Help pages rendered to a terminal now wrap at the detected width rather than 80 columns. Redirected output and specs that declare term_width are unaffected.

Full Changelog: v6.10.0...v6.11.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.