diff --git a/NOTICE.md b/NOTICE.md index 3150fac81..41d59fe47 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -13,7 +13,7 @@ warrant attribution: - `usage-derive` / `usage-rs` deliberately mirror `clap_derive`'s attribute vocabulary and semantics (`long`, `short`, `env`, `default_value`, `flatten`, `value_enum`, `rename_all`, and friends) so a clap declaration can be ported - field by field. See [docs/rust/clap-compatibility.md](docs/rust/clap-compatibility.md). + field by field. See [docs/rust/migrating-from-clap.md](docs/rust/migrating-from-clap.md). - The rendered help, usage line, and diagnostic conventions follow clap's output shape so migrated CLIs keep their existing user-facing text. - `clap_usage` reads a `clap::Command` through clap's public API to generate a diff --git a/conformance/tests/clap_micro.rs b/conformance/tests/clap_micro.rs index 5c72ee4a5..23c93d5fa 100644 --- a/conformance/tests/clap_micro.rs +++ b/conformance/tests/clap_micro.rs @@ -1,4 +1,4 @@ -//! Minimal paired CLIs that turn the clap compatibility matrix into executable claims. +//! Minimal paired CLIs that turn the clap migration claims into executable checks. use std::ffi::OsStr; diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 3f793a5cc..99b05ce41 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -69,7 +69,6 @@ export default defineConfig({ { text: "Subcommands", link: "/rust/subcommands" }, { text: "Dispatch", link: "/rust/dispatch" }, { text: "Migrating from clap", link: "/rust/migrating-from-clap" }, - { text: "clap Compatibility", link: "/rust/clap-compatibility" }, { text: "Validation", link: "/rust/validation" }, { text: "Configuration", link: "/rust/configuration" }, { text: "Help, Version, and Errors", link: "/rust/help" }, diff --git a/docs/rust/args-and-flags.md b/docs/rust/args-and-flags.md index ee567ecd8..0d2a1fd9d 100644 --- a/docs/rust/args-and-flags.md +++ b/docs/rust/args-and-flags.md @@ -41,6 +41,10 @@ Values are built with `FromStr`, so `PathBuf`, `usize`, `IpAddr`, and your own t The `FromStr` error type must implement `Display` (a compile error names the type otherwise); a conversion failure at runtime becomes `Error::InvalidValue { name, value, reason }`. +On Unix, `PathBuf` and `OsString` keep non-UTF-8 argv bytes unchanged. `String` fields report +invalid UTF-8 rather than replacing it. On Windows, values that cannot be converted safely are +reported instead of using an unchecked reconstruction. + A `Vec` flag is repeatable (`var` in spec terms) automatically. Two related attributes cover the other shapes: @@ -59,8 +63,7 @@ jobs: Option, The tables below cover the attributes most CLIs need. Many clap-compatible spellings (`visible_alias`, `hide_*`, `last`, `trailing_var_arg`, `requires_if`, and others) are also -accepted — see [Migrating from clap](/rust/migrating-from-clap) and the -[compatibility matrix](/rust/clap-compatibility) for the audited surface. +accepted — see [Migrating from clap](/rust/migrating-from-clap). **Naming and shape** — what the field is called and what kind of argument it is: @@ -89,7 +92,7 @@ accepted — see [Migrating from clap](/rust/migrating-from-clap) and the | `delimiter = ','` | Split one word into several values ([Validation](/rust/validation#delimiters)) | | `value_terminator = ";"` | End a variadic field at this token without storing the token | | `bool_value` | Let a boolean long flag accept attached `=true` or `=false` | -| `value_optional` | Mark the value optional in help (help-only; the parser still wants one) | +| `value_optional` | Help/spec only; bind a bare flag with `default_missing` or `Option>` | **Env vars and defaults** — where a value comes from when argv has none: @@ -245,9 +248,8 @@ stdin: bool, Naming a flag or positional that doesn't exist on the command is a **compile error**, not a runtime surprise. Conflicts, requires, and conditional requiredness may name flags or -positionals; `overrides` and some `requires_if` forms stay flag-only. See the -[compatibility matrix](/rust/clap-compatibility#relationships-and-command-routing) for the -audited details. +positionals; `overrides` and some `requires_if` forms stay flag-only. See +[Compatibility gaps](/rust/migrating-from-clap#compatibility-gaps) for the migration details. ## Resolution order diff --git a/docs/rust/clap-compatibility.md b/docs/rust/clap-compatibility.md index a79a7a924..9c2498b91 100644 --- a/docs/rust/clap-compatibility.md +++ b/docs/rust/clap-compatibility.md @@ -1,159 +1,14 @@ -# clap compatibility - -::: warning Draft -This page is a draft and has not yet been human reviewed. Details may change. -::: - -This is the audited compatibility matrix for `clap` 4.6.6 and `clap_derive` 4.6.4, -the versions in this workspace's lockfile. The audit covers clap's public derive -attributes and the corresponding `Command`, `Arg`, `ArgGroup`, and `PossibleValue` -builder settings that affect parsing or generated output. Builder operations for -constructing and mutating a command graph are listed separately as architectural -non-goals. - -Updating either clap package requires updating the versions above and auditing this -matrix in the same pull request. - -Usage mirrors clap's attribute vocabulary and output shape on purpose, so clap's -license is reproduced in the repository's -[NOTICE.md](https://github.com/jdx/usage/blob/main/NOTICE.md) file. - -The columns distinguish every layer a migration crosses: - -- **derive** — `usage-rs` / `usage-derive` can declare it and has typed coverage. -- **argv** — the compiled `usage-argv` parser enforces it. -- **KDL** — the portable spec can represent and round-trip it. -- **lib** — `usage-lib` enforces it when interpreting KDL. -- **output** — help, diagnostics, docs, or completions preserve the relevant behavior. -- **bridge** — `clap_usage` can recover it from a `clap::Command`. - -| Mark | Meaning | -| -------------- | ------------------------------------------------------------------------------------------------------ | -| **yes** | Supported and covered at this layer. | -| **exact** | Supported with clap-matching truth tables (used where a family of forms must match clap exactly). | -| **partial** | Some forms work; the note names what remains unsupported. | -| **usage-only** | Direct usage declarations work, but clap exposes no getter or the bridge cannot preserve the behavior. | -| **lossy** | Some common forms work; the note names what is lost. | -| **different** | Intentionally differs from clap. | -| **no** | Unsupported. | -| **n/a** | The behavior does not belong at this layer. | -| **non-goal** | Deliberately outside the static typed-parser API. | - -The bridge is not a lossless migration verifier. clap exposes some settings only -through setters, so a generated spec cannot report that it lost them. Migrate from -the Rust declaration, not only from generated KDL, wherever the bridge column says -**usage-only** or **lossy**. - -## Types and declarations - -| clap surface | derive | argv | KDL | lib | output | bridge | Notes | -| ------------------------------------------------ | -------- | -------- | --- | --- | ------ | ------ | ----------------------------------------------------------------------------------------------------------- | -| `Parser` / `Command` metadata | yes | yes | yes | yes | yes | yes | `#[derive(usage::Cli)]`; name, bin, about, long about, before/after help, and version are carried. | -| `Args` | yes | yes | yes | yes | yes | yes | Dedicated, unit, reused, nested, and flattened Args types are covered. | -| `Subcommand` | yes | yes | yes | yes | yes | yes | Bare, tuple, inline-struct, nested, boxed, aliases, and hidden aliases are covered. | -| `ValueEnum` / `PossibleValue` | yes | yes | yes | yes | yes | yes | Names, help, hide, visible/hidden aliases, cfg, and case-insensitive matching are preserved. | -| `flatten` | yes | yes | yes | yes | yes | yes | Parsing and flattened `next_help_heading` topology are composed. | -| `skip` | yes | yes | n/a | n/a | n/a | n/a | `#[usage(skip)]` fills the field from `Default` and emits no argument. | -| `from_global` | no | no | no | no | no | no | A global flag is parsed on its declaring root type; copying it into another field is unsupported. | -| arbitrary `Command` / `Arg` builder code | non-goal | non-goal | n/a | yes | yes | lossy | `usage-lib` is the dynamic API; the typed derive does not reproduce clap's builder API. | -| `ArgMatches`, `FromArgMatches`, `CommandFactory` | non-goal | non-goal | n/a | n/a | n/a | n/a | Typed structs and borrowed static metadata replace these APIs. | -| `update_from` / `try_update_from` | yes | yes | n/a | n/a | n/a | n/a | Merges into a value you already have; a standing value satisfies a relationship but cannot be re-validated. | - -## Arguments and values - -| clap surface | derive | argv | KDL | lib | output | bridge | Notes | -| ------------------------------------------------------------ | ---------- | ---- | ----- | --- | ------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `long`, `short`, visible aliases | yes | yes | yes | yes | yes | yes | Multiple forms are accepted and advertised by parsing, help, completion, and generated tables. | -| hidden flag `alias` / `aliases` | yes | yes | yes | yes | yes | yes | Hidden aliases bind and round-trip through KDL and generated Rust/Go tables without appearing in help or completion. | -| explicit `id` | yes | yes | yes | yes | yes | yes | `#[arg(id = "…")]` supplies the stable field identity used by relationships and generated specs. | -| positional arguments | yes | yes | yes | yes | yes | yes | Required, optional, and variadic positionals are supported. | -| `Option`, `Vec`, `Option>`, `Option>` | yes | yes | yes | yes | yes | n/a | Nested `Option` preserves absent, bare, and explicitly valued flags; values use the declared `FromStr` or `ValueEnum` conversion. | -| derived `ValueEnum` | yes | yes | yes | yes | yes | n/a | Canonical values, aliases, case policy, help, and direct enum binding come from one derive; no separate `FromStr` is required. | -| `ArgAction::Set`, `SetTrue`, `SetFalse`, `Append`, `Count` | yes | yes | yes | yes | yes | lossy | Common typed shapes are covered; arbitrary action/type combinations are not. | -| `default_value` | yes | yes | yes | yes | yes | yes | Defaults apply after argv and environment values and clear token-required metadata. | -| `default_missing_value` | yes | yes | yes | yes | yes | usage-only | `#[usage(default_missing = "…")]`; clap has no getter. | -| `default_value_if(s)` | yes | yes | yes | yes | yes | usage-only | Presence and equality predicates are portable; clap has no getter. | -| `env` | yes | yes | yes | yes | yes | lossy | Environment fallback works; the current bridge can lose the binding. | -| ordered/deprecated environment aliases | usage-only | yes | yes | yes | yes | no | `env_fallback(…)` preserves declaration order; `deprecated_env(…)` is consulted last and remains visible in generated output. | -| `value_delimiter` | yes | yes | yes | yes | yes | yes | ASCII delimiters round-trip and are applied before arity checks. | -| `num_args` ranges | yes | yes | yes | yes | yes | lossy | Nested value `var_min` / `var_max` preserve per-occurrence ranges separately from flag occurrence bounds; zero-minimum flag ranges can be bridge-lossy. | -| fixed `num_args` with distinct `value_names` | yes | yes | yes | yes | yes | yes | `#[arg(num_args = 2, value_names = ["START", "END"])]` preserves the exact bound and both placeholders. | -| `allow_hyphen_values` | yes | yes | yes | yes | yes | yes | Supported on value-taking flags; forwarded positionals use `double_dash = "automatic"`. | -| `allow_negative_numbers` | yes | yes | yes | yes | yes | yes | Accepts negative numeric tokens without accepting arbitrary dash-prefixed values. | -| `require_equals` | yes | yes | yes | yes | yes | yes | Detached values are refused. | -| explicit boolean `--flag=false` | usage-only | yes | yes | yes | yes | no | `#[usage(bool_value)]` opts a switch into exact, attached `true`/`false` values; detached words remain positional. | -| `value_terminator` | yes | yes | yes | yes | yes | yes | Ends a variadic value owner without binding the terminator token. | -| `trailing_var_arg` / `last` | yes | yes | yes | yes | yes | lossy | `double_dash` carries automatic/required/optional; clap shadow generation still drops automatic mode. | -| `dont_delimit_trailing_values` | yes | yes | yes | yes | yes | yes | Preserves delimiters after `--` and on automatic trailing positionals while ordinary values still split. | -| possible-values parser | yes | yes | yes | yes | yes | yes | Use `ValueEnum` or `choices`. | -| non-strict suggested values | usage-only | yes | yes | yes | yes | no | `choices_strict = false` keeps choices presentational while accepting other values. | -| arbitrary `value_parser` callbacks | usage-only | yes | lossy | yes | yes | no | `FromStr` handles typed conversion and portable `validate` expressions handle declarative rules; Rust callbacks cannot enter KDL. | -| `ValueHint` completion vocabulary | yes | yes | yes | yes | yes | yes | Every stable clap hint lowers to a portable completion type; open-ended URL/email hints suppress path fallback. | - -## Relationships and command routing - -| clap surface | derive | argv | KDL | lib | output | bridge | Notes | -| ---------------------------------------------------- | --------- | --------- | --------- | --------- | ------- | ---------- | ----------------------------------------------------------------------------------------------------------------------- | -| flag `required`, `conflicts_with`, `overrides_with` | yes | yes | yes | yes | yes | yes | Environment values participate in post-binding checks. | -| `requires` | yes | yes | yes | yes | yes | usage-only | clap exposes setters but no getter. | -| `requires_if(s)` | yes | yes | yes | yes | yes | usage-only | Presence and value-conditional forms are supported. | -| `required_if_eq`, `required_unless_present` families | exact | exact | exact | exact | exact | usage-only | Single, any, and all truth tables work for flags and positionals; clap exposes setters but no getters. | -| `ArgGroup`, required groups, `exclusive` | yes | yes | yes | yes | yes | yes | Bare selectors preserve positional members. A group of switches may also be declared as an enum (see Usage extensions). | -| positional conflicts | yes | yes | yes | yes | yes | yes | Bare selectors name positionals; dashed selectors name flags. | -| other relationships declared on positionals | partial | partial | partial | partial | partial | usage-only | `requires` and conditional requiredness work; binding-time `overrides` and value-source `requires_if` remain flag-only. | -| relationships through `flatten` | lossy | lossy | yes | yes | yes | lossy | A declaring type cannot yet validate a selector supplied by a flattened sibling. | -| global flags | yes | yes | yes | yes | yes | yes | Exact lookup preserves child shadowing. | -| `allow_external_subcommands` | yes | yes | yes | yes | yes | yes | Use an `#[usage(external_subcommand)]` catch-all variant. | -| `multicall` | yes | yes | yes | yes | yes | yes | Process-level entry points route using the executable basename. | -| `no_binary_name` | yes | yes | n/a | yes | n/a | yes | `parse_from` is words-only; full-argv helpers honor the command policy. | -| `infer_subcommands`, `infer_long_args` | no | no | no | no | no | no | Intentional non-goal: usage requires exact flag and subcommand spellings. | -| `arg_required_else_help` | yes | yes | yes | yes | yes | yes | Bare selected commands request short help; defaults and environment values do not count as argv. | -| `args_override_self` | yes | yes | yes | yes | yes | yes | Usage defaults to permissive last-one-wins behavior; set false for strict duplicate checking. | -| `subcommand_negates_reqs` | yes | yes | yes | yes | yes | yes | A selected child suppresses its parent's positive requirements, not conflicts or the child's requirements. | -| `args_conflicts_with_subcommands` | yes | yes | yes | yes | yes | yes | Parent flags or positionals exclude a later child subcommand. | -| `subcommand_precedence_over_arg` | yes | yes | yes | yes | yes | yes | A known child can end a variadic flag or positional value owner. | -| `allow_missing_positional` | yes | yes | yes | yes | yes | yes | Later required positionals can claim the remaining words while earlier optional fields stay empty. | -| unknown flags | different | different | different | different | yes | different | usage is permissive by default; `unknown_flags = "error"` opts into strict parsing. | - -## Help, version, and generated artifacts - -| clap surface | derive | argv | KDL | lib | output | bridge | Notes | -| -------------------------------------------------- | --------- | --------- | --------- | --------- | ------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| short/long help and doc comments | yes | yes | yes | yes | yes | yes | First paragraph is short help; the full block is long help. | -| `help_heading` on flags and arguments | yes | n/a | yes | yes | yes | yes | Flags and arguments are grouped and retain declaration order. | -| `help_heading` on subcommands | yes | yes | yes | yes | yes | n/a | Commands can be grouped into named sections in their parent's help. | -| whole-entry `hide` | yes | yes | yes | yes | yes | yes | Hidden commands, flags, arguments, and values still parse. | -| granular hide settings | yes | yes | yes | yes | yes | yes | Default, environment, possible-value, short-help, and long-help visibility is independent. | -| `subcommand_help_heading`, `subcommand_value_name` | yes | yes | yes | yes | yes | yes | Customize the subcommand section label and the synopsis placeholder. | -| `verbatim_doc_comment` | yes | n/a | yes | yes | yes | n/a | Commands, fields, and variants preserve line breaks and indentation when requested. | -| `rename_all`, `rename_all_env` | yes | n/a | yes | yes | yes | n/a | Full clap casing vocabulary; bare `env` uses the environment casing policy. | -| `next_line_help` | yes | yes | yes | yes | yes | yes | Put command, argument, and flag descriptions below their usage instead of beside it. | -| `flatten_help` | yes | yes | yes | yes | yes | yes | Expand visible subcommands into their parent's usage synopsis and help page. | -| `display_order` | yes | yes | yes | yes | yes | yes | Explicit field and subcommand presentation order is portable; parsing order is unchanged. | -| `help_template` | different | different | different | different | yes | no | Root-level only: nested pages inherit it and cannot declare their own. Closed vocabulary of six pre-rendered sections rather than clap's tags; see [Laying a page out](./help.md#laying-a-page-out). clap keeps `get_help_template` private, so the bridge cannot recover one. | -| `term_width`, `max_term_width` | yes | yes | yes | yes | yes | no | Fixed width overrides a detected-width cap; clap exposes no bridge getters for these settings. | -| help styles and color | n/a | n/a | n/a | yes | lossy | no | Help and diagnostics use automatic ANSI styles; clap's custom style palette is not portable. | -| built-in help/version action and flag control | yes | yes | yes | yes | yes | yes | `Help`, `HelpShort`, `HelpLong`, and `Version` actions can relocate built-ins; usage additionally provides recursive `HelpAll`; each synthetic entry can be disabled. | -| `--version` / `-V`, dynamic and long versions | yes | yes | yes | yes | yes | yes | `long_version` customizes `--version`; `-V` keeps the concise value. | -| `author`, `license`, `repository` | yes | n/a | yes | yes | yes | partial | Package metadata is rendered in Markdown and manpages; clap exposes author but not license. | -| completion generation | yes | yes | yes | yes | lossy | yes | Bash, fish, Nushell, PowerShell, and zsh plus runtime overlays are supported; Elvish is not. | -| KDL, markdown, JSON, and manpages | yes | n/a | yes | yes | yes | yes | Direct derived KDL feeds the existing generators; broader canonicalization remains open. | - -## Usage extensions - -These are not clap compatibility gaps. usage additionally supports `mount`, -`restart_token`, `default_subcommand`, command and flag `effect`, -`source_code_link_template`, Nushell completions, -and a language-neutral conformance corpus. clap cannot express those properties, so -a clap-generated spec cannot carry them without an overlay. - -`#[derive(usage::ArgGroup)]` is one more: a group of valueless flags declared as an -enum of bare variants, held by an `Option` field for an optional group or a bare `T` -field for a required one. This is clap#2621, which clap has not implemented, so there is -nothing for the bridge to recover; it lowers to the same `group` node and the same -`ConflictingFlags` and `MissingGroup` errors a hand-written group produces, so every -other layer sees an ordinary group. - -This matrix is the compatibility baseline, not a promise to reproduce clap's dynamic -builder and `ArgMatches` architecture. Setter-only clap state remains explicitly -**usage-only** until clap exposes a getter or the bridge gains another reliable source. +--- +title: clap compatibility +head: + - - meta + - http-equiv: refresh + content: "0; url=/rust/migrating-from-clap#compatibility-gaps" + - - link + - rel: canonical + href: https://usage.jdx.dev/rust/migrating-from-clap +--- + +# clap compatibility moved + +Compatibility guidance is now part of [Migrating from clap](/rust/migrating-from-clap#compatibility-gaps). diff --git a/docs/rust/index.md b/docs/rust/index.md index 74d3f978e..afe821d3b 100644 --- a/docs/rust/index.md +++ b/docs/rust/index.md @@ -149,31 +149,7 @@ how to opt out of the endpoint. - [Help, version, and errors](/rust/help) — what the parser renders and how to hook it - [Completions](/rust/completions) — static scripts and runtime completion - [Configuration](/rust/configuration) — settings declared in code: `usage::Config` and layered resolution -- [Testing](/rust/testing) — assert parses, help pages, and completions with no process spawned +- [Testing](/rust/testing) — run commands or assert directly on parsing, help, and completions - [Spec output](/rust/spec) — the emitted KDL and usage-cli integration - [Migrating from clap](/rust/migrating-from-clap) — mechanical rewrites and intentional API breaks -- [clap compatibility](/rust/clap-compatibility) — supported behavior, bridge losses, and non-goals - [Performance](/rust/performance) — what a parse costs, measured at mise's scale - -## Current limitations - -The framework intentionally targets standard GNU-style CLIs, and a few clap features have no -equivalent yet: - -- `#[usage(value_optional)]` changes help and spec presentation only. To bind a bare flag, use - `default_missing` or an `Option>` field. -- Literal `value_parser = ["…"]` arrays become portable choices, but typed `value_parser` - callbacks are rejected because they cannot enter the spec. Other values use `FromStr`; - portable validation expressions require the `validation` feature. -- Long flags and subcommands require exact spellings. With `unknown_flags = "error"`, - diagnostics can suggest a close match, but parsing never accepts prefixes whose meaning could - change when another declaration is added. -- Completion scripts cover bash, fish, Nushell, PowerShell, and zsh. Elvish is not supported; a - clap application publishing an Elvish script must keep `clap_complete` for that one artifact. -- `help_template` uses six portable, pre-rendered sections rather than clap's finer-grained - template tags. Existing clap templates must be rewritten, and the clap bridge cannot recover - them because clap does not expose its template. See - [Laying a page out](/rust/help#laying-a-page-out). -- On Unix, `PathBuf` and `OsString` fields accept non-UTF-8 argv without changing a byte. String - fields still report invalid UTF-8 precisely rather than replacing it; on Windows, values that - cannot be converted safely are reported instead of using an unchecked reconstruction. diff --git a/docs/rust/migrating-from-clap.md b/docs/rust/migrating-from-clap.md index 3ebfbadf8..a6bc00f3d 100644 --- a/docs/rust/migrating-from-clap.md +++ b/docs/rust/migrating-from-clap.md @@ -8,9 +8,26 @@ The Rust framework is a typed parser with static metadata, not a compatibility l clap. Most derive-based CLIs migrate mechanically. Builder APIs and `ArgMatches` are intentional API breaks: move their behavior into typed declarations or keep clap at that boundary. -Use the [compatibility matrix](/rust/clap-compatibility) as the audited baseline. It separates -behavior supported by usage itself from metadata that `clap_usage` can recover from an existing -`clap::Command`. +## Compatibility gaps + +Check these before starting a migration: + +| Difference | What to do | +| --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| Runtime `Command` builders, `ArgMatches`, and `CommandFactory` are not part of the typed API. | Move the declaration to derives, keep clap at that boundary, or use `usage-lib` for a CLI that is genuinely dynamic. | +| Unknown flags and repeated scalar flags are permissive by default. | Add `unknown_flags = "error"` and `args_override_self = false` where clap's strict behavior matters. | +| `from_global` is unsupported. | Read the global field from its declaring type and pass it to the command as context. | +| Typed `value_parser` callbacks cannot enter a portable spec. | Use the field type's `FromStr`, a `ValueEnum`, literal choices, or a portable `validate` expression. | +| `#[usage(value_optional)]` changes help and spec presentation only. | Bind a bare flag with `default_missing` or an `Option>` field. | +| Some relationships through `flatten` or on positionals are not available at binding time. | Keep a post-parse check for the cases described under [Subcommands and shared arguments](#subcommands-and-shared-arguments). | +| Prefix inference is intentionally unsupported. | Long flags and subcommands must use a full name or declared alias. | +| clap help templates and style palettes are not portable as-is. | Rewrite templates using usage's six [help sections](/rust/help#laying-a-page-out); usage chooses terminal styles automatically. | +| Completion generation does not target Elvish. | Keep `clap_complete` or another generator for that artifact. | + +If a migration begins from a `clap::Command` rather than the Rust declaration, +`clap_usage::spec_with_report` detects recoverable losses. It cannot report state for which clap +exposes a setter but no getter, including the `requires` family, `default_value_if`, and +`default_missing_value`; audit those declarations directly. ## Dependencies @@ -199,10 +216,8 @@ struct Explicit { Relationships that cross a flattened boundary are **lossy**: common forms work, but a declaring type cannot yet validate a selector supplied by a flattened sibling. Positional relationships are **partial**: conflicts, requires, and conditional requiredness work; binding-time `overrides` -and value-source `requires_if` remain flag-only. Keep a post-parse check only for forms the -[compatibility matrix](/rust/clap-compatibility#relationships-and-command-routing) still marks -lossy or partial; the derive rejects selectors it can prove invalid instead of silently -weakening them. +and value-source `requires_if` remain flag-only. Keep a post-parse check for those cases; the +derive rejects selectors it can prove invalid instead of silently weakening them. ## Parse entry points @@ -299,5 +314,6 @@ spellings may be added when they map to existing behavior. A spelling whose clap be carried losslessly is rejected or documented as partial; it is not silently accepted with weaker semantics. -The compatibility matrix is versioned against the clap releases named at its top. Updating clap -requires re-auditing that matrix; compiling with a new clap is not by itself a parity claim. +The paired conformance tests are audited against the clap versions in the workspace lockfile. +Updating clap requires re-running and reviewing those tests; compiling with a new clap is not by +itself a parity claim. diff --git a/docs/spec/integrations/clap.md b/docs/spec/integrations/clap.md index b94c82814..298754883 100644 --- a/docs/spec/integrations/clap.md +++ b/docs/spec/integrations/clap.md @@ -39,8 +39,7 @@ The report includes the command path, clap argument ID, feature, and source deta for each detectable loss. `is_lossless()` therefore means lossless for behavior visible through clap's public getters, not for every setter clap exposes. Before treating the generated spec as fully compatible, audit the declaration against the -[compatibility matrix](/rust/clap-compatibility), especially its **usage-only** and -**lossy** bridge rows. +[clap migration guide](/rust/migrating-from-clap#compatibility-gaps). ## Integration Pattern @@ -87,6 +86,6 @@ constraint. `Arg::default_value_if` is the same hole: a generated spec never car ## Links -- [clap compatibility matrix](/rust/clap-compatibility) +- [Migrating from clap](/rust/migrating-from-clap) - [crate on crates.io](https://crates.io/crates/clap_usage) - [source code](https://github.com/jdx/usage/tree/main/clap_usage)