Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions cli/usage.usage.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ cmd "complete-word" help="Generate shell completion candidates for a partial com
flag "--cword" help="Current word index" {
arg "<CWORD>"
}
flag "--shell" required=#true default="bash" {
flag "--shell" default="bash" {
arg "<SHELL>" {
choices "bash" "fish" "nu" "powershell" "zsh"
}
Expand Down Expand Up @@ -70,7 +70,7 @@ cmd "generate" help="Generate completions, documentation, and other artifacts fr
flag "--include-bash-completion-lib" help="Include https://github.com/scop/bash-completion" {
long_help "Include https://github.com/scop/bash-completion\n\nThis is required for usage completions to work in bash, but the user may already provide it"
}
flag "--usage-bin" help="Override the bin used for calling back to usage-cli" required=#true env="JDX_USAGE_BIN" default="usage" {
flag "--usage-bin" help="Override the bin used for calling back to usage-cli" env="JDX_USAGE_BIN" default="usage" {
long_help "Override the bin used for calling back to usage-cli\n\nYou may need to set this if you have a different bin named \"usage\""
arg "<USAGE_BIN>"
}
Expand All @@ -88,7 +88,7 @@ cmd "generate" help="Generate completions, documentation, and other artifacts fr
alias "init" hide=#true
alias "completions-init" hide=#true
long_help "Generate a shell init script that auto-completes any usage shebang script on $PATH\n\nSource the output once from your shell rc (e.g. ~/.bashrc) to enable\ntab-completion for any executable whose first line is a `usage` shebang —\nno per-script `usage g completion` step required."
flag "--usage-bin" help="Override the bin used for calling back to usage-cli" required=#true env="JDX_USAGE_BIN" default="usage" {
flag "--usage-bin" help="Override the bin used for calling back to usage-cli" env="JDX_USAGE_BIN" default="usage" {
long_help "Override the bin used for calling back to usage-cli\n\nYou may need to set this if you have a different bin named \"usage\""
arg "<USAGE_BIN>"
}
Expand Down Expand Up @@ -158,7 +158,7 @@ cmd "generate" help="Generate completions, documentation, and other artifacts fr
flag "-o --out-file" help="Output file path, or \"-\" for stdout (default)" effect="write" {
arg "<OUT_FILE>"
}
flag "-s --section" help="Manual section number (default: 1)" required=#true default="1" {
flag "-s --section" help="Manual section number (default: 1)" default="1" {
long_help "Manual section number (default: 1)\n\nCommon sections:\n- 1: User commands\n- 5: File formats\n- 7: Miscellaneous\n- 8: System administration commands"
arg "<SECTION>"
}
Expand Down Expand Up @@ -205,7 +205,7 @@ cmd "generate" help="Generate completions, documentation, and other artifacts fr
}
}
cmd "lint" help="Lint a usage spec file for common issues" effect="read" {
flag "-f --format" help="Output format" required=#true default="text" {
flag "-f --format" help="Output format" default="text" {
arg "<FORMAT>" {
choices "text" "json"
}
Expand Down
12 changes: 11 additions & 1 deletion conformance/tests/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,17 @@ fn a_defaulted_argument_reads_as_optional_in_both_renderers() {
// `required=#false default=…`, so there is nothing to normalize. A *derived* one is
// required by its type and defaulted by its attribute, which is exactly the shape that
// diverges.
let spec: LibSpec = Defaulted::to_kdl().parse().expect("valid spec");
let kdl = Defaulted::to_kdl();
let derived = Defaulted::spec();
assert!(!derived.root.args[0].required, "{kdl}");
assert!(!derived.root.flags[0].required, "{kdl}");
assert!(kdl.contains(r#"arg "[DIR]""#), "{kdl}");
assert!(
!kdl.contains(r#"flag "--out <out>" required=#true"#),
"{kdl}"
);

let spec: LibSpec = kdl.parse().expect("valid spec");
let theirs = format!("ex {}", spec.cmd.usage()).trim().to_string();
let ours = usage_argv::help::usage_line(&["ex"], Defaulted::spec().root);
assert_eq!(ours, theirs, "the two renderers disagree");
Expand Down
6 changes: 4 additions & 2 deletions derive/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,8 @@ fn flag_meta(i: usize, field: &Field, owner: &syn::Ident) -> TokenStream {
// describe a different CLI from the one that runs.
// A collecting field's type cannot say whether one value is needed, so `required` may
// declare it. Every other shape gets its answer from the type.
let required = field.shape == Shape::Required || field.required_collection;
let required =
(field.shape == Shape::Required || field.required_collection) && field.default.is_empty();
// Declared, not inferred: `Option<String>` already says the *flag* is optional and says
// nothing about whether its value is.
let value_optional = field.value_optional;
Expand Down Expand Up @@ -1168,7 +1169,8 @@ fn arg_meta(i: usize, field: &Field, owner: &syn::Ident) -> TokenStream {
// `String` must be filled; `Option` and `Vec` need not be.
// A collecting field's type cannot say whether one value is needed, so `required` may
// declare it. Every other shape gets its answer from the type.
let required = field.shape == Shape::Required || field.required_collection;
let required =
(field.shape == Shape::Required || field.required_collection) && field.default.is_empty();
let (choices, accepted_choices, choice_aliases, ignore_case) = choices_tokens(field);
let validate = option_str(field.validate.as_deref());
let validate_error = option_str(field.validate_error.as_deref());
Expand Down
Loading