diff --git a/go/README.md b/go/README.md
index 754eb7cf8..367cc573b 100644
--- a/go/README.md
+++ b/go/README.md
@@ -256,6 +256,8 @@ claim is measured at real scale rather than against a fixture with four flags:
- **A typed front door.** The conversions exist; what is missing is generated
code that calls them, so a CLI author gets a struct rather than events.
-- **Per-shell completion output.** `Walk` and `Candidates` answer _what_ could go
- at the cursor; turning that into the text bash, zsh, fish or PowerShell expect
- is still to do, as is running the `complete` scripts a spec can declare.
+- **The shell scripts themselves.** A CLI can now answer a completion request —
+ `mycli __complete_word__ --shell zsh --line "…"` — in the text each shell reads.
+ What is missing is the handful of lines that register that callback with bash,
+ zsh, fish, nushell and PowerShell, and running the `run=` scripts a spec can
+ declare, which needs a subprocess this package has no business starting.
diff --git a/go/argv/complete.go b/go/argv/complete.go
index e7be2f945..e9ac03f5c 100644
--- a/go/argv/complete.go
+++ b/go/argv/complete.go
@@ -191,10 +191,16 @@ func Candidates(pos Position, partial string, help HelpTable, meta Metadata) []C
commands()
}
- // Flags, only where one could still be typed, and taken from the parser's own
- // scope so that shadowing is respected: a subcommand redeclaring an inherited
- // name offers its own.
- if pos.FlagsPossible {
+ // Flags, only where one could still be typed *and* the user has started typing
+ // one. The reference offers no flags for a bare cursor — `ex ⌶` lists
+ // subcommands, `ex -⌶` lists both forms, `ex --⌶` the longs — and checked
+ // against `usage complete-word` rather than assumed. Offering them anyway made
+ // every position look answered, which is also what decides whether the shell
+ // should fall back to paths.
+ //
+ // The prefix filter below would narrow them to the same set; what this changes
+ // is the empty prefix, where it would not.
+ if pos.FlagsPossible && strings.HasPrefix(partial, "-") {
for _, s := range flagsInScope(pos.Chain) {
if h := help.Lookup(s.flag.Key); h != nil && h.Hide {
continue
diff --git a/go/argv/complete_shell.go b/go/argv/complete_shell.go
index 96fc0cf2e..414136879 100644
--- a/go/argv/complete_shell.go
+++ b/go/argv/complete_shell.go
@@ -21,6 +21,35 @@ const (
PowerShell
)
+// doublesQuotes reports whether a quote inside a quoted string is written by
+// doubling it, which is PowerShell's rule and nobody else's.
+func (s Shell) doublesQuotes() bool { return s == PowerShell }
+
+// backtickEscapes reports whether an escape is written with a backtick rather
+// than a backslash — PowerShell again.
+func (s Shell) backtickEscapes() bool { return s == PowerShell }
+
+// ShellNamed is the shell a `--shell` argument names, and whether it named one.
+//
+// A completion request comes from a script this package wrote, so the name is one
+// of five — but it arrives as text off a command line, and a shell that sends
+// something else should get an answer rather than a crash.
+func ShellNamed(name string) (Shell, bool) {
+ switch name {
+ case "bash":
+ return Bash, true
+ case "zsh":
+ return Zsh, true
+ case "fish":
+ return Fish, true
+ case "nu", "nushell":
+ return Nu, true
+ case "powershell", "pwsh":
+ return PowerShell, true
+ }
+ return Bash, false
+}
+
// Files says whether paths belong at this position as well as the candidates.
type Files uint8
diff --git a/go/argv/complete_test.go b/go/argv/complete_test.go
index 12b9a0c31..0d9accdb5 100644
--- a/go/argv/complete_test.go
+++ b/go/argv/complete_test.go
@@ -61,8 +61,24 @@ func complete(words []string, partial string) []string {
}
func TestCompletionOffersCommandsFlagsAndAliases(t *testing.T) {
+ // A bare cursor is asking which command to run. The reference offers no flags
+ // there — checked against `usage complete-word`, which answers `install` and
+ // `run` for a spec whose root also has `-v --verbose`.
got := complete(nil, "")
- for _, want := range []string{"run", "list", "r", "--verbose", "-v", "--color", "--no-color"} {
+ for _, want := range []string{"run", "list", "r"} {
+ if !offered(got, want) {
+ t.Errorf("want %q offered, got %v", want, got)
+ }
+ }
+ for _, unwanted := range []string{"--verbose", "-v"} {
+ if offered(got, unwanted) {
+ t.Errorf("a bare cursor is not asking for flags: %v", got)
+ }
+ }
+
+ // A dash is: a lone one offers both forms.
+ got = complete(nil, "-")
+ for _, want := range []string{"--verbose", "-v", "--color", "--no-color"} {
if !offered(got, want) {
t.Errorf("want %q offered, got %v", want, got)
}
@@ -87,7 +103,7 @@ func TestCompletionFiltersByThePartialWord(t *testing.T) {
// A global is offered inside a subcommand, because the parser accepts it there.
func TestAGlobalIsOfferedInsideASubcommand(t *testing.T) {
- got := complete([]string{"run"}, "")
+ got := complete([]string{"run"}, "-")
if !offered(got, "--verbose") {
t.Errorf("an inherited global should be offered: %v", got)
}
@@ -213,7 +229,7 @@ func TestOnlyTheClaimedSpellingIsWithdrawn(t *testing.T) {
help := HelpTable{{Key: 1}, {Key: 2}, {Key: 3}, {Key: 4}}
meta := Metadata{{Key: 1}, {Key: 2}, {Key: 3}, {Key: 4}}
- got := values(Candidates(Walk(root, []string{"run"}), "", help, meta))
+ got := values(Candidates(Walk(root, []string{"run"}), "-", help, meta))
// `--jobs` is the subcommand's now, and still offered once.
if n := count(got, "--jobs"); n != 1 {
t.Errorf("--jobs should appear once, got %d: %v", n, got)
@@ -264,7 +280,7 @@ func TestANegationLosesToALongOfTheSameSpelling(t *testing.T) {
if f := binds(t, root, []string{"run", "--no-color"}); f != global {
t.Fatalf("the parser binds --no-color to %v, so the premise is wrong", f)
}
- got := values(Candidates(Walk(root, []string{"run"}), "", help, meta))
+ got := values(Candidates(Walk(root, []string{"run"}), "-", help, meta))
if n := count(got, "--no-color"); n != 1 {
t.Errorf("--no-color should be offered once, by the flag that binds it, got %d: %v",
n, got)
@@ -288,7 +304,7 @@ func TestAnInheritedNegationSurvivesItsFlagsOtherSpellings(t *testing.T) {
if f := binds(t, root, []string{"run", "--no-color"}); f != global {
t.Fatalf("the parser binds --no-color to %v, so the premise is wrong", f)
}
- got := values(Candidates(Walk(root, []string{"run"}), "", help, meta))
+ got := values(Candidates(Walk(root, []string{"run"}), "-", help, meta))
if !offered(got, "--no-color") {
t.Errorf("--no-color still binds, so it should be offered: %v", got)
}
@@ -339,7 +355,7 @@ func TestANegationSpelledLikeItsOwnLongIsOfferedOnce(t *testing.T) {
help := HelpTable{{Key: 1}, {Key: 2}}
meta := Metadata{{Key: 1}, {Key: 2}}
- got := values(Candidates(Walk(root, nil), "", help, meta))
+ got := values(Candidates(Walk(root, nil), "-", help, meta))
if n := count(got, "--no-color"); n != 1 {
t.Errorf("--no-color should be offered once, got %d: %v", n, got)
}
@@ -368,19 +384,24 @@ func TestAVariadicStillCollectingOffersFlagsToo(t *testing.T) {
}
got := values(Candidates(Walk(root, []string{"--tools", "a"}), "", help, meta))
- if !offered(got, "--force") {
- t.Errorf("a flag ends the collection and binds, so it belongs here: %v", got)
- }
if !offered(got, "node") {
t.Errorf("the variadic's own values belong here too: %v", got)
}
+ // And once a dash is typed, the flags that would end the collection — the
+ // same rule as anywhere else, which is the point: this position is not the
+ // exclusive one a flag owed its value is.
+ dashed := values(Candidates(Walk(root, []string{"--tools", "a"}), "-", help, meta))
+ if !offered(dashed, "--force") {
+ t.Errorf("a flag ends the collection and binds, so it belongs here: %v", dashed)
+ }
// A plain word goes to the variadic, so nothing a plain word cannot be.
if offered(got, "run") {
t.Errorf("a subcommand name would be collected as a value, not bound: %v", got)
}
- // And a flag still owed its first value keeps the position to itself.
- owed := values(Candidates(Walk(root, []string{"--tools"}), "", help, meta))
+ // And a flag still owed its first value keeps the position to itself, dash or
+ // no dash: the parser refuses a flag-like token there.
+ owed := values(Candidates(Walk(root, []string{"--tools"}), "-", help, meta))
if offered(owed, "--force") {
t.Errorf("a flag-like token is refused where a value is owed: %v", owed)
}
@@ -403,7 +424,7 @@ func TestANearerFlagTakesTheSpellingFromAnInheritedNegation(t *testing.T) {
if f := binds(t, root, []string{"run", "--x"}); f != local {
t.Fatalf("the parser binds --x to the nearer flag, got %v", f)
}
- got := values(Candidates(Walk(root, []string{"run"}), "", help, meta))
+ got := values(Candidates(Walk(root, []string{"run"}), "-", help, meta))
if n := count(got, "--x"); n != 1 {
t.Errorf("--x should be offered once, by the flag that binds it, got %d: %v", n, got)
}
diff --git a/go/argv/post.go b/go/argv/post.go
index 928ee40ed..6aa5c8492 100644
--- a/go/argv/post.go
+++ b/go/argv/post.go
@@ -39,6 +39,16 @@ type Meta struct {
// between them can name a different flag entirely. Empty for an argument,
// which is typed as its value rather than as a form.
Spelling string
+ // ValueName is what a flag's value is called — the `DIR` of `--into
` —
+ // and empty where the entry is an argument, which is named by its value
+ // already. Read by completion rather than by any rule here: what a value is
+ // called is what says whether a path belongs there.
+ ValueName string
+ // CompleteType is the type a spec's `complete` block names for this entry,
+ // where it names one. Also completion's, and carried for the same reason: an
+ // author who wrote `complete "input" type="file"` said what the position
+ // takes, and the alternative is inferring it from a name they did not choose.
+ CompleteType string
// Flag distinguishes a missing flag from a missing argument, which the
// grammar reports as different classes.
Flag bool
diff --git a/go/argv/request.go b/go/argv/request.go
new file mode 100644
index 000000000..371c0fc84
--- /dev/null
+++ b/go/argv/request.go
@@ -0,0 +1,215 @@
+package argv
+
+import "strings"
+
+// The hidden command a shell calls, and what it answers.
+//
+// A completion is not something the CLI runs. It is recognized before the parse
+// rather than inside it: putting it in the tables would make it a command —
+// visible to the grammar, to the help, to the spec — and every CLI would grow a
+// subcommand nobody typed.
+//
+// The request is usage-argv's, spelled the same way on purpose:
+//
+// mycli __complete_word__ --shell zsh --line "mycli install no"
+//
+// One convention, so a shell script written for either framework says the same
+// thing, and so a spec's `complete "x" run="mycli __complete_word__ …"` means one
+// thing whichever language answers it.
+
+// RequestName is the argument that marks a completion request.
+//
+// Long and ugly on purpose: it is typed by a script, never by a person, and it
+// has to be a word no CLI would want for itself.
+const RequestName = "__complete_word__"
+
+// Request is a completion request as a shell sent it.
+type Request struct {
+ Shell Shell
+ // Line is the command line as typed, and Cursor a byte offset into it.
+ Line string
+ Cursor int
+}
+
+// ParseRequest reads a completion request out of argv, and reports whether this
+// was one at all.
+//
+// `argv` is what the program was given, without its own name — the same slice
+// [New] takes, so a caller asks this first and parses only if the answer is no.
+//
+// The flags are read by hand. There are three, and reading them with the parser
+// would mean putting them in the tables this is deliberately outside of. Anything
+// unrecognized is ignored rather than refused: a completion that errors out is a
+// shell that beeps at every keystroke.
+func ParseRequest(argv []string) (Request, bool) {
+ if len(argv) == 0 || argv[0] != RequestName {
+ return Request{}, false
+ }
+ req := Request{Shell: Bash, Cursor: -1}
+ for i := 1; i < len(argv); i++ {
+ switch argv[i] {
+ case "--shell":
+ if i+1 < len(argv) {
+ i++
+ if shell, ok := ShellNamed(argv[i]); ok {
+ req.Shell = shell
+ }
+ }
+ case "--line":
+ if i+1 < len(argv) {
+ i++
+ req.Line = argv[i]
+ }
+ case "--cursor":
+ if i+1 < len(argv) {
+ i++
+ if n, err := atoi(argv[i]); err == nil {
+ req.Cursor = n
+ }
+ }
+ }
+ }
+ // No cursor means the end of the line, which is where a shell puts it when it
+ // has no way to say — nushell, whose completer only ever sees the words.
+ if req.Cursor < 0 {
+ req.Cursor = len(req.Line)
+ }
+ return req, true
+}
+
+// Answer works out what could be typed at the cursor.
+//
+// The candidates come from the tables, and so does the question of whether paths
+// belong here — a shell can complete those itself, and asking it to is how a CLI
+// says "anything at all goes here" without listing the filesystem.
+func (r Request) Answer(root *Command, help HelpTable, meta Metadata) Answer {
+ split := Split(r.Line, r.Cursor, r.Shell)
+ pos := Walk(root, split.Argv())
+ candidates := Candidates(pos, split.Prefix, help, meta)
+ return Answer{Candidates: candidates, Files: filesAt(pos, split, candidates, meta)}
+}
+
+// Respond is the whole of what a CLI has to do: recognize the request, answer it,
+// and write the text its shell reads.
+//
+// Returns false where argv is an ordinary invocation, which is the caller's cue
+// to parse it as one.
+func Respond(argv []string, root *Command, help HelpTable, meta Metadata) (string, bool) {
+ req, ok := ParseRequest(argv)
+ if !ok {
+ return "", false
+ }
+ return RenderAnswer(req.Answer(root, help, meta), req.Shell), true
+}
+
+// filesAt decides whether the shell should offer paths here as well.
+//
+// Four questions, in the order the reference asks them:
+//
+// - A dash-prefixed word is a flag or nothing. No path starts with one.
+// - An argument that is not readable until after a `--` is not fillable yet, so
+// nothing belongs there — not even a path, which the parser would refuse
+// exactly as it refuses a value.
+// - Did the spec say what this position takes? A `complete` block naming a type
+// answers outright, and so does a name like `` or ``: the reference
+// resolves a completer by name and falls back to reading the name as the type.
+// - Otherwise: is the position *closed*? Something was offered, or the entry
+// declares its own set, in which case an unmatched prefix means "no matches"
+// rather than "ask somebody else". Offering the working directory for a
+// mistyped choice answers the second as though it were the first.
+func filesAt(pos Position, split SplitLine, candidates []Candidate, meta Metadata) Files {
+ if pos.FlagsPossible && strings.HasPrefix(split.Prefix, "-") {
+ return NoFiles
+ }
+ // Only when the cursor is *at* that argument. A flag taking a value is a
+ // different position that happens to have an unfilled positional behind it,
+ // and a rule about the positional has nothing to say about the flag: `ex
+ // --from ⌶` takes a path whatever the argument after it needs. A variadic
+ // still collecting is the same position by a weaker claim, and the reference
+ // folds the two together here.
+ if pos.AwaitingValue == nil && pos.Collecting == nil && pos.NextArg != nil &&
+ pos.NextArg.DoubleDash == DoubleDashRequired && !pos.SeparatorSeen {
+ return NoFiles
+ }
+
+ var m *Meta
+ named := ""
+ switch {
+ case pos.AwaitingValue != nil:
+ m = meta.Lookup(pos.AwaitingValue.Key)
+ named = pos.AwaitingValue.Name
+ case pos.Collecting != nil:
+ m = meta.Lookup(pos.Collecting.Key)
+ named = pos.Collecting.Name
+ case pos.NextArg != nil:
+ m = meta.Lookup(pos.NextArg.Key)
+ named = pos.NextArg.Name
+ }
+ if m != nil {
+ if m.ValueName != "" {
+ named = m.ValueName
+ }
+ if asked := filesFor(m.CompleteType); asked != NoFiles {
+ return asked
+ }
+ }
+ if asked := filesFor(named); asked != NoFiles {
+ return asked
+ }
+
+ declaresChoices := m != nil && len(m.Choices) > 0
+ if len(candidates) > 0 || declaresChoices || pos.HelpTopic {
+ return NoFiles
+ }
+ return AnyFile
+}
+
+// filesFor is the paths a name asks for, by the name itself.
+//
+// The same names the reference reads, compared without case: an argument called
+// `` completes files and `` directories without a spec saying so.
+func filesFor(name string) Files {
+ switch {
+ case name == "":
+ return NoFiles
+ case strings.EqualFold(name, "file"), strings.EqualFold(name, "path"),
+ strings.EqualFold(name, "config_file"):
+ return AnyFile
+ case strings.EqualFold(name, "dir"), strings.EqualFold(name, "directory"):
+ return Dirs
+ }
+ return NoFiles
+}
+
+// atoi is [strconv.Atoi] for a non-negative number, written out because this
+// package takes no imports it can avoid.
+//
+// A number too large to hold is refused rather than wrapped. Wrapping is worse
+// than refusing here: a cursor that came back as a small number would describe a
+// position near the start of the line, and the completion would answer confidently
+// about the wrong word — where a refusal falls back to the end of the line, which
+// is where a shell means when it says nothing.
+func atoi(s string) (int, error) {
+ const maxInt = int(^uint(0) >> 1)
+ if s == "" {
+ return 0, errNotANumber
+ }
+ n := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] < '0' || s[i] > '9' {
+ return 0, errNotANumber
+ }
+ digit := int(s[i] - '0')
+ if n > (maxInt-digit)/10 {
+ return 0, errNotANumber
+ }
+ n = n*10 + digit
+ }
+ return n, nil
+}
+
+type numberError struct{}
+
+func (numberError) Error() string { return "not a number" }
+
+var errNotANumber = numberError{}
diff --git a/go/argv/request_test.go b/go/argv/request_test.go
new file mode 100644
index 000000000..dfd08f9ef
--- /dev/null
+++ b/go/argv/request_test.go
@@ -0,0 +1,223 @@
+package argv
+
+import (
+ "strings"
+ "testing"
+)
+
+// A CLI with the shapes the files rule turns on: a named path, a named
+// directory, a declared set, and an argument that reads only after a separator.
+func requestFixture() (*Command, HelpTable, Metadata) {
+ into := &Flag{Key: 2, Name: "into", Longs: []string{"into"}, TakesValue: true}
+ tool := &Flag{Key: 3, Name: "tool", Longs: []string{"tool"}, TakesValue: true}
+ file := &Arg{Key: 4, Name: "FILE"}
+ edit := &Command{Key: 5, Name: "edit", Flags: []*Flag{into}, Args: []*Arg{file}}
+ use := &Command{Key: 6, Name: "use", Flags: []*Flag{tool},
+ Args: []*Arg{{Key: 7, Name: "TOOL"}}}
+ after := &Command{Key: 8, Name: "run",
+ Args: []*Arg{{Key: 9, Name: "TASK", DoubleDash: DoubleDashRequired}}}
+ root := &Command{Key: 1, Name: "ex", Subcommands: []*Command{edit, use, after}}
+
+ help := HelpTable{{Key: 1}, {Key: 2}, {Key: 3}, {Key: 4}, {Key: 5, Short: "Edit a file"},
+ {Key: 6, Short: "Use a tool"}, {Key: 7}, {Key: 8, Short: "Run a task"}, {Key: 9}}
+ meta := Metadata{
+ {Key: 1},
+ {Key: 2, Name: "into", Flag: true, ValueName: "DIR"},
+ {Key: 3, Name: "tool", Flag: true, ValueName: "TOOL",
+ Choices: []string{"node", "python"}},
+ {Key: 4, Name: "FILE"},
+ {Key: 5}, {Key: 6},
+ {Key: 7, Name: "TOOL", Choices: []string{"node", "python"}},
+ {Key: 8},
+ {Key: 9, Name: "TASK"},
+ }
+ return root, help, meta
+}
+
+func ask(t *testing.T, shell Shell, line string) (Answer, string) {
+ t.Helper()
+ root, help, meta := requestFixture()
+ cursor := strings.Index(line, "⌶")
+ if cursor < 0 {
+ cursor = len(line)
+ }
+ line = strings.Replace(line, "⌶", "", 1)
+
+ argv := []string{RequestName, "--shell", shellName(shell), "--line", line}
+ out, ok := Respond(argv, root, help, meta)
+ if !ok {
+ t.Fatalf("%q should be a completion request", argv)
+ }
+ req, _ := ParseRequest(argv)
+ req.Cursor = cursor
+ return req.Answer(root, help, meta), out
+}
+
+func shellName(s Shell) string {
+ switch s {
+ case Zsh:
+ return "zsh"
+ case Fish:
+ return "fish"
+ case Nu:
+ return "nu"
+ case PowerShell:
+ return "powershell"
+ }
+ return "bash"
+}
+
+// An ordinary invocation is left alone. The request is recognized before the
+// parse, and a CLI that answered completions for `ex --help` would be one nobody
+// could run.
+func TestAnOrdinaryInvocationIsNotARequest(t *testing.T) {
+ root, help, meta := requestFixture()
+ for _, argv := range [][]string{{}, {"edit"}, {"--into", "x"}, {"_complete"}} {
+ if _, ok := Respond(argv, root, help, meta); ok {
+ t.Errorf("%v is a command line, not a completion request", argv)
+ }
+ }
+}
+
+// The three arguments a shell passes, and what a missing one means.
+func TestReadingTheRequest(t *testing.T) {
+ req, ok := ParseRequest([]string{RequestName, "--shell", "zsh",
+ "--line", "ex use no", "--cursor", "6"})
+ if !ok || req.Shell != Zsh || req.Line != "ex use no" || req.Cursor != 6 {
+ t.Fatalf("read back wrong: %+v ok=%v", req, ok)
+ }
+
+ // No cursor is the end of the line, which is where a shell puts it when it has
+ // no way to say — nushell, whose completer only ever sees the words.
+ req, _ = ParseRequest([]string{RequestName, "--line", "ex use"})
+ if req.Cursor != len("ex use") {
+ t.Errorf("want the end of the line, got %d", req.Cursor)
+ }
+
+ // A shell passing something this version does not know about is answered, not
+ // refused: a completion that errors out beeps at every keystroke.
+ req, ok = ParseRequest([]string{RequestName, "--wat", "1", "--shell", "klingon",
+ "--line", "ex ", "--cursor", "nope"})
+ if !ok || req.Shell != Bash || req.Line != "ex " {
+ t.Errorf("unknown arguments should be ignored: %+v", req)
+ }
+}
+
+// What the answer says, end to end, in the shape the shell reads.
+func TestAnsweringARequest(t *testing.T) {
+ _, out := ask(t, Bash, "ex ⌶")
+ for _, want := range []string{"edit", "use", "run"} {
+ if !strings.Contains(out, want+"\n") {
+ t.Errorf("want %q offered:\n%s", want, out)
+ }
+ }
+ // zsh takes three fields, and the description comes from the same table the
+ // page uses.
+ _, out = ask(t, Zsh, "ex ed⌶")
+ if !strings.HasPrefix(out, "edit\tEdit a file\tedit\n") {
+ t.Errorf("want the zsh triple, got %q", out)
+ }
+}
+
+// Whether the shell should offer paths as well — the question a CLI answers by
+// saying nothing about it.
+func TestWhenPathsBelongAtTheCursor(t *testing.T) {
+ for _, c := range []struct {
+ line string
+ want Files
+ why string
+ }{
+ {"ex ⌶", NoFiles, "subcommands were offered, so the position is answered"},
+ {"ex -⌶", NoFiles, "a dash-prefixed word is a flag or nothing"},
+ {"ex edit ⌶", AnyFile, "the argument is called FILE"},
+ {"ex edit --into ⌶", Dirs, "the value is called DIR"},
+ {"ex use ⌶", NoFiles, "the argument declares its own set"},
+ {"ex use --tool ⌶", NoFiles, "so does the value"},
+ {"ex run ⌶", NoFiles, "that argument is not readable until after a --"},
+ {"ex run -- ⌶", AnyFile, "and past the separator it is anything at all"},
+ } {
+ answer, _ := ask(t, Bash, c.line)
+ if answer.Files != c.want {
+ t.Errorf("%q: want %v, got %v — %s", c.line, c.want, answer.Files, c.why)
+ }
+ }
+}
+
+// A command having flags does not close the position.
+//
+// `Candidates` offers flags only for a dash-prefixed word, which is what the
+// reference does — and what keeps the file fallback working, since the fallback
+// asks whether *anything* was offered. Offering every flag at a bare cursor made
+// every position on every command with a flag look answered.
+func TestFlagsDoNotCloseThePositionToPaths(t *testing.T) {
+ root := &Command{Key: 1, Name: "ex",
+ Flags: []*Flag{{Key: 2, Name: "verbose", Longs: []string{"verbose"}}},
+ Args: []*Arg{{Key: 3, Name: "INPUT"}}}
+ help := HelpTable{{Key: 1}, {Key: 2}, {Key: 3}}
+ meta := Metadata{{Key: 1}, {Key: 2, Name: "verbose", Flag: true}, {Key: 3, Name: "INPUT"}}
+
+ answer := Request{Shell: Bash, Line: "ex ", Cursor: 3}.Answer(root, help, meta)
+ if answer.Files != AnyFile {
+ t.Errorf("nothing describes INPUT, so the shell should offer paths: %v", answer.Files)
+ }
+ if len(answer.Candidates) != 0 {
+ t.Errorf("a bare cursor is not asking for flags: %v", values(answer.Candidates))
+ }
+ // And a dash asks for them, which closes the position — no path starts with
+ // one.
+ dashed := Request{Shell: Bash, Line: "ex -", Cursor: 4}.Answer(root, help, meta)
+ if dashed.Files != NoFiles || len(dashed.Candidates) == 0 {
+ t.Errorf("a dash asks for flags and nothing else: %v %v",
+ dashed.Files, values(dashed.Candidates))
+ }
+}
+
+// A variadic still collecting is on the flag's value, not on the argument behind
+// it — so an argument owing a separator has nothing to say about this position.
+func TestASeparatorOwedBehindACollectingFlag(t *testing.T) {
+ tools := &Flag{Key: 2, Name: "tools", Longs: []string{"tools"},
+ TakesValue: true, Variadic: true}
+ root := &Command{Key: 1, Name: "ex", Flags: []*Flag{tools},
+ Args: []*Arg{{Key: 3, Name: "TASK", DoubleDash: DoubleDashRequired}}}
+ help := HelpTable{{Key: 1}, {Key: 2}, {Key: 3}}
+ meta := Metadata{{Key: 1}, {Key: 2, Name: "tools", Flag: true, ValueName: "PATH"},
+ {Key: 3, Name: "TASK"}}
+
+ const line = "ex --tools a "
+ if got := (Request{Shell: Bash, Line: line, Cursor: len(line)}).
+ Answer(root, help, meta).Files; got != AnyFile {
+ t.Errorf("the cursor is on the flag's value, which is called PATH: %v", got)
+ }
+}
+
+// A cursor too large to hold falls back to the end of the line.
+//
+// Wrapping would be worse than refusing: a small number describes a position near
+// the start of the line, and the completion would answer confidently about the
+// wrong word.
+func TestACursorTooLargeToHold(t *testing.T) {
+ for _, huge := range []string{"18446744073709551616", "99999999999999999999"} {
+ req, ok := ParseRequest([]string{RequestName, "--line", "ex use", "--cursor", huge})
+ if !ok || req.Cursor != len("ex use") {
+ t.Errorf("%s should fall back to the end of the line, got %d", huge, req.Cursor)
+ }
+ }
+}
+
+// A completer's declared type outranks the name, because the author wrote it.
+func TestADeclaredCompleterTypeDecidesIt(t *testing.T) {
+ root := &Command{Key: 1, Name: "ex", Args: []*Arg{{Key: 2, Name: "INPUT"}}}
+ help := HelpTable{{Key: 1}, {Key: 2}}
+ meta := Metadata{{Key: 1}, {Key: 2, Name: "INPUT", CompleteType: "dir"}}
+
+ req := Request{Shell: Bash, Line: "ex ", Cursor: 3}
+ if got := req.Answer(root, help, meta).Files; got != Dirs {
+ t.Errorf("`complete type=\"dir\"` says directories, got %v", got)
+ }
+ // And with nothing declared and nothing known, the position is open: a name
+ // nobody described could be anything, so the shell should offer paths.
+ meta[1].CompleteType = ""
+ if got := req.Answer(root, help, meta).Files; got != AnyFile {
+ t.Errorf("an undescribed position takes anything, got %v", got)
+ }
+}
diff --git a/go/argv/split.go b/go/argv/split.go
new file mode 100644
index 000000000..f01aa0aa0
--- /dev/null
+++ b/go/argv/split.go
@@ -0,0 +1,233 @@
+package argv
+
+import "unicode/utf8"
+
+// Turning a command line back into the words a shell would have passed.
+//
+// A completion request arrives as text, not as argv: the shell hands over the
+// line and where the cursor is in it, because the words do not exist yet — the
+// one being typed is half-written and may be inside quotes that are not closed.
+// So the words have to be recovered here, by the same rules the shell would have
+// applied had the line been run.
+//
+// Ported from usage-argv's `split`, which is where the rules were worked out.
+// Both sides answer the same request from the same kind of shell script, so a
+// line that means one thing to a Rust CLI and another to a Go one would be the
+// two frameworks disagreeing about the shell rather than about the spec.
+
+// SplitLine is a command line as the shell would have passed it, plus where the
+// cursor was.
+type SplitLine struct {
+ // Words are the words, unquoted — what argv would hold had the line been run.
+ //
+ // Always at least one: a cursor sitting after a space is completing a word
+ // that does not exist yet, and an empty word is how that is said. Candidates
+ // for "anything at all" and candidates for "something starting with `no`" are
+ // the same question with a different prefix, and a caller should not have to
+ // special-case the empty one.
+ Words []string
+ // Cword is which of Words the cursor is in.
+ Cword int
+ // Prefix is the part of that word before the cursor, unquoted — what a
+ // candidate must start with.
+ Prefix string
+}
+
+// Argv is the words a parser should walk: after the program name, before the
+// cursor's word.
+//
+// Two things dropped for two reasons. The program name, because argv does not
+// contain it and the parse tables describe what comes *after* it. The word being
+// completed, because it is half-typed by definition — feeding it in would ask
+// what can follow a word the user has not finished, when the question is what
+// that word could be.
+func (s SplitLine) Argv() []string {
+ start := min(1, s.Cword)
+ return s.Words[start:s.Cword]
+}
+
+// Split splits a line at a byte cursor, the way `shell` would have split it.
+//
+// `cursor` is a byte offset into `line`; anything past the end is treated as the
+// end, and an offset landing inside a multi-byte character is moved back to that
+// character's start rather than being taken literally — a completion request is
+// not a place to be strict about a shell's arithmetic.
+func Split(line string, cursor int, shell Shell) SplitLine {
+ if cursor > len(line) {
+ cursor = len(line)
+ }
+ if cursor < 0 {
+ cursor = 0
+ }
+ cursor = floorCharBoundary(line, cursor)
+
+ var words []string
+ var word []rune
+ // Whether anything has been written into `word` — including a quote that so
+ // far contains nothing, so that `ex ""` is a word and not a gap between two.
+ started := false
+ cword, prefix, found := 0, "", false
+ // Whether the cursor sat inside a word rather than in the gap before one. A
+ // gap is a word the user is about to type, so one has to be made for them.
+ cursorInWord := false
+
+ // The cursor is reached before the character it sits in front of is read, so
+ // the word in hand is the word being completed and what is in it is the
+ // prefix. Checked at the top of each character and again before an escape
+ // swallows the one after it: only checking the top left a cursor sitting on an
+ // escaped character unnoticed, and the split then described the last word of
+ // the line rather than the one being typed.
+ reached := func(i int) {
+ if i == cursor && !found {
+ cword, prefix, found = len(words), string(word), true
+ cursorInWord = started
+ }
+ }
+
+ var quote rune
+ runes := []rune(line)
+ // Byte offsets alongside, because the cursor is one.
+ offsets := make([]int, len(runes)+1)
+ at := 0
+ for i, r := range runes {
+ offsets[i] = at
+ at += utf8.RuneLen(r)
+ }
+ offsets[len(runes)] = at
+
+ for i := 0; i < len(runes); i++ {
+ c := runes[i]
+ reached(offsets[i])
+
+ peek := func() (rune, bool) {
+ if i+1 < len(runes) {
+ return runes[i+1], true
+ }
+ return 0, false
+ }
+
+ switch {
+ case quote == '\'':
+ if c == '\'' {
+ // PowerShell writes a quote inside a quoted string by doubling it;
+ // the POSIX-shaped shells have no such rule, and there a second
+ // quote always ends the string.
+ if next, ok := peek(); shell.doublesQuotes() && ok && next == '\'' {
+ reached(offsets[i+1])
+ word = append(word, '\'')
+ i++
+ } else {
+ quote = 0
+ }
+ } else {
+ word = append(word, c)
+ }
+
+ case quote != 0:
+ if c == quote {
+ if next, ok := peek(); shell.doublesQuotes() && ok && next == quote {
+ reached(offsets[i+1])
+ word = append(word, quote)
+ i++
+ } else {
+ quote = 0
+ }
+ } else if isEscape(c, shell) {
+ // Inside double quotes an escape is only an escape before a
+ // character it could mean something to; before anything else it is
+ // a literal, which is why a Windows path in double quotes survives.
+ if next, ok := peek(); ok && escapableInQuotes(next, shell) {
+ reached(offsets[i+1])
+ word = append(word, next)
+ i++
+ } else {
+ word = append(word, c)
+ }
+ } else {
+ word = append(word, c)
+ }
+
+ default:
+ switch {
+ case c == '\'' || c == '"':
+ quote = c
+ started = true
+ case isEscape(c, shell):
+ // Before the check, because the escape has already started the
+ // word: a cursor on the escaped character is inside it, not in the
+ // gap before it.
+ started = true
+ if next, ok := peek(); ok {
+ reached(offsets[i+1])
+ word = append(word, next)
+ i++
+ }
+ // A trailing escape is a line the user is still typing, not a
+ // mistake to report: it escapes the character they have not typed.
+ case isSpace(c):
+ if started {
+ words = append(words, string(word))
+ word = word[:0]
+ started = false
+ }
+ default:
+ word = append(word, c)
+ started = true
+ }
+ }
+ }
+
+ // The cursor at the very end of the line: the loop above only sees positions it
+ // reads a character at, and there is no character there.
+ if !found {
+ cword, prefix = len(words), string(word)
+ cursorInWord = started
+ }
+ if started {
+ words = append(words, string(word))
+ }
+
+ // A cursor in a gap is completing a word that is not in the line yet — at the
+ // end of it, or between two that are already there. `ex ⌶use` is asking what
+ // can go *before* `use`, and answering about `use` itself would complete the
+ // wrong word.
+ if !cursorInWord {
+ words = append(words, "")
+ copy(words[cword+1:], words[cword:])
+ words[cword] = ""
+ }
+ return SplitLine{Words: words, Cword: cword, Prefix: prefix}
+}
+
+// isEscape reports whether a character starts an escape in this shell.
+func isEscape(c rune, shell Shell) bool {
+ if shell.backtickEscapes() {
+ return c == '`'
+ }
+ return c == '\\'
+}
+
+// escapableInQuotes reports whether an escape inside double quotes applies to the
+// character after it.
+func escapableInQuotes(c rune, shell Shell) bool {
+ if shell.backtickEscapes() {
+ return c == '"' || c == '`' || c == '$'
+ }
+ return c == '"' || c == '\\' || c == '$' || c == '`'
+}
+
+// isSpace is the whitespace a shell splits words on. Written out rather than
+// taken from `unicode`, which would pull the tables in for a package whose whole
+// claim is that it costs nothing unused.
+func isSpace(c rune) bool {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f'
+}
+
+// floorCharBoundary is the start of the character containing `index`.
+func floorCharBoundary(s string, index int) int {
+ // The end of the string is a boundary and has no byte to look at.
+ for index > 0 && index < len(s) && !utf8.RuneStart(s[index]) {
+ index--
+ }
+ return index
+}
diff --git a/go/argv/split_test.go b/go/argv/split_test.go
new file mode 100644
index 000000000..f95c7c6c6
--- /dev/null
+++ b/go/argv/split_test.go
@@ -0,0 +1,116 @@
+package argv
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+// The cursor is written as `⌶` in these cases, and cut out before the split, so a
+// case reads as the line the user is looking at.
+func at(line string, shell Shell) SplitLine {
+ cursor := strings.Index(line, "⌶")
+ if cursor < 0 {
+ cursor = len(line)
+ }
+ return Split(strings.Replace(line, "⌶", "", 1), cursor, shell)
+}
+
+func TestSplittingALine(t *testing.T) {
+ for _, c := range []struct {
+ line string
+ words []string
+ cword int
+ prefix string
+ }{
+ // The plain cases: a word being typed, and a gap after one.
+ {"ex inst⌶", []string{"ex", "inst"}, 1, "inst"},
+ {"ex ⌶", []string{"ex", ""}, 1, ""},
+ {"ex install ⌶", []string{"ex", "install", ""}, 2, ""},
+ // A cursor inside a word ignores the rest of it: what follows is a tail the
+ // user has not decided on, and it should not narrow what can be typed.
+ {"ex ins⌶tall", []string{"ex", "install"}, 1, "ins"},
+ // A cursor in the gap *before* a word is completing a word that is not
+ // there yet, so one is made for it.
+ {"ex ⌶install", []string{"ex", "", "install"}, 1, ""},
+ // Quotes hold a word together, and an unclosed one is a word being typed.
+ {`ex "two words⌶`, []string{"ex", "two words"}, 1, "two words"},
+ {`ex 'two words' ⌶`, []string{"ex", "two words", ""}, 2, ""},
+ // An empty quoted string is a word, not a gap.
+ {`ex "" ⌶`, []string{"ex", "", ""}, 2, ""},
+ // An escape takes the character after it, and a trailing one is a line
+ // still being typed rather than a mistake.
+ {`ex two\ wo⌶`, []string{"ex", "two wo"}, 1, "two wo"},
+ {`ex two\⌶`, []string{"ex", "two"}, 1, "two"},
+ // Nothing at all is still one word: the cursor is completing it.
+ {"", []string{""}, 0, ""},
+ {"ex⌶", []string{"ex"}, 0, "ex"},
+ } {
+ got := at(c.line, Bash)
+ want := SplitLine{Words: c.words, Cword: c.cword, Prefix: c.prefix}
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("%q:\n got %+v\nwant %+v", c.line, got, want)
+ }
+ }
+}
+
+// Inside double quotes a backslash escapes only what it could mean something to,
+// which is what lets a Windows path survive being quoted.
+func TestAnEscapeInsideQuotes(t *testing.T) {
+ got := at(`ex "C:\Users\me⌶`, Bash)
+ if want := `C:\Users\me`; got.Prefix != want {
+ t.Errorf("want %q, got %q", want, got.Prefix)
+ }
+ got = at(`ex "say \"hi\"⌶`, Bash)
+ if want := `say "hi"`; got.Prefix != want {
+ t.Errorf("want %q, got %q", want, got.Prefix)
+ }
+}
+
+// PowerShell escapes with a backtick and writes a quote by doubling it. Splitting
+// its lines by POSIX rules turned a path into an escape sequence.
+func TestPowerShellQuotesItsOwnWay(t *testing.T) {
+ if got := at("ex C:\\Users\\me⌶", PowerShell); got.Prefix != `C:\Users\me` {
+ t.Errorf("a backslash is not an escape in PowerShell: %q", got.Prefix)
+ }
+ if got := at("ex `\"quoted⌶", PowerShell); got.Prefix != `"quoted` {
+ t.Errorf("a backtick escapes: %q", got.Prefix)
+ }
+ if got := at("ex 'it''s'⌶", PowerShell); got.Prefix != "it's" {
+ t.Errorf("a doubled quote is one quote: %q", got.Prefix)
+ }
+ // And the same doubled quote is two words to bash, which is the point of
+ // asking which shell sent the line.
+ if got := at("ex 'it''s'⌶", Bash); got.Prefix != "its" {
+ t.Errorf("bash has no doubling rule: %q", got.Prefix)
+ }
+}
+
+// A cursor is a byte offset from a shell's arithmetic, and a completion request is
+// not the place to be strict about it.
+func TestACursorOutsideTheLine(t *testing.T) {
+ if got := Split("ex run", 999, Bash); got.Prefix != "run" {
+ t.Errorf("past the end is the end: %+v", got)
+ }
+ if got := Split("ex ünïcode", 5, Bash); got.Prefix != "ü" {
+ // Byte 5 is inside `ï`; the character it belongs to starts at 4, and the
+ // word so far is `ü`. Moved back rather than cutting a rune in half.
+ t.Errorf("a cursor inside a character moves back to its start: %+v", got)
+ }
+}
+
+// The words a parser walks: after the program name, before the word being typed.
+func TestWhatTheParserIsGiven(t *testing.T) {
+ got := at("ex install no⌶", Bash)
+ if want := []string{"install"}; !reflect.DeepEqual(got.Argv(), want) {
+ t.Errorf("want %v, got %v", want, got.Argv())
+ }
+ // Nothing but the program name yet, so nothing to walk.
+ if got := at("ex ⌶", Bash); len(got.Argv()) != 0 {
+ t.Errorf("want nothing, got %v", got.Argv())
+ }
+ // Not even the program name: a line that is only a cursor.
+ if got := at("⌶", Bash); len(got.Argv()) != 0 {
+ t.Errorf("want nothing, got %v", got.Argv())
+ }
+}
diff --git a/go/conformance/complete_test.go b/go/conformance/complete_test.go
new file mode 100644
index 000000000..7c6922dd1
--- /dev/null
+++ b/go/conformance/complete_test.go
@@ -0,0 +1,151 @@
+package conformance
+
+import (
+ "context"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/jdx/usage/go/argv"
+)
+
+// Does the cursor get the same answer here as it does from usage-lib?
+//
+// The same standard the pages are held to, and for the same reason: these rules
+// were reimplemented, and reimplemented rules drift. `usage complete-word` is the
+// reference a shell would have called before any of this existed, so it is the
+// oracle — over mise's real spec, which is the largest one there is.
+//
+// This exists because a divergence got through. `Candidates` offered every flag
+// at a bare cursor; the reference offers none until a `-` is typed, and nothing
+// noticed until a reviewer read the two. A hand-written test asserts what its
+// author believed; this asks.
+
+// completeWord is the reference's answer for a partial word at a command path.
+//
+// Every non-empty line it printed, whatever the line holds. Two of the things it
+// can hold are not this side's to reproduce — a listing of the working directory
+// where nothing else fit, and whatever a spec's `complete` block printed when the
+// reference ran it — so the *positions* asked about are chosen to avoid both,
+// rather than the lines being filtered afterwards. Filtering would quietly hide a
+// real difference behind a rule about what a path looks like.
+//
+// Bounded, because it is another program: a reference that hangs should fail this
+// test rather than the suite.
+func completeWord(t *testing.T, usageBin, kdl string, words []string, cword int) []string {
+ t.Helper()
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+ args := []string{"complete-word", "--shell", "bash", "-f", kdl,
+ "--cword", itoa(cword), "--"}
+ args = append(args, words...)
+ out, err := exec.CommandContext(ctx, usageBin, args...).Output()
+ if err != nil {
+ t.Fatalf("the reference should answer %v: %v", words, err)
+ }
+ var lines []string
+ for _, line := range strings.Split(strings.TrimRight(string(out), "\n"), "\n") {
+ if line != "" {
+ lines = append(lines, line)
+ }
+ }
+ return lines
+}
+
+func TestTheCursorGetsTheReferencesAnswer(t *testing.T) {
+ usageBin := findUsage(t)
+ kdl := filepath.Join("..", "..", "benches", "mise.usage.kdl")
+ lowered := lowerFile(t, usageBin, kdl)
+ root, meta, help := lowered.BuildAll()
+
+ // Lines where the reference answers from the spec alone. Two kinds are left
+ // out on purpose, because they are answers this side does not claim to give:
+ // a position where the reference lists the working directory (compared as a
+ // marker below), and one where it *runs* a spec's `complete` block — `mise ⌶`
+ // and `mise settings ⌶` both do, and shelling out on a Tab is the piece this
+ // package has deliberately not built.
+ //
+ // The root's own cursor is one of those: mise's default subcommand is `run`,
+ // whose `TASK` runs a completer, so even `mise plug⌶` is answered partly by a
+ // subprocess. The lines below sit under a subcommand that has neither.
+ //
+ // What is left covers the branches: subcommands, aliases, a nested command,
+ // both flag forms, a long that narrows, and a word that matches nothing.
+ for _, line := range []string{
+ "mise config ",
+ "mise config l",
+ "mise -",
+ "mise --",
+ "mise --log-",
+ "mise use -",
+ "mise plugins ",
+ "mise plugins in",
+ "mise plugins wat",
+ "mise plugins install -",
+ } {
+ split := argv.Split(line, len(line), argv.Bash)
+ want := completeWord(t, usageBin, kdl, split.Words, split.Cword)
+
+ answer := argv.Request{Shell: argv.Bash, Line: line, Cursor: len(line)}.
+ Answer(root, help, meta)
+ var got []string
+ for _, c := range answer.Candidates {
+ got = append(got, c.Value)
+ }
+
+ if !sameSet(got, want) {
+ t.Errorf("%q:\n ours: %v\n lib: %v", line, got, want)
+ }
+ }
+}
+
+// And where the reference falls back to the filesystem, the Go side says so
+// rather than listing it.
+//
+// The two are the same answer said differently: usage-lib prints the directory
+// because it is answering a shell that has already asked; the tables say "paths
+// belong here" and let the script call the shell's own path completion, which
+// knows about `~`, variables and remote paths.
+func TestAPathFallbackIsAMarkerRatherThanAListing(t *testing.T) {
+ usageBin := findUsage(t)
+ kdl := filepath.Join("..", "..", "benches", "mise.usage.kdl")
+ lowered := lowerFile(t, usageBin, kdl)
+ root, meta, help := lowered.BuildAll()
+
+ // `mise edit` takes a file, and neither side has anything else to offer there.
+ const line = "mise edit "
+ split := argv.Split(line, len(line), argv.Bash)
+ want := completeWord(t, usageBin, kdl, split.Words, split.Cword)
+ if len(want) == 0 {
+ t.Skip("the reference listed nothing here, so there is no fallback to compare")
+ }
+
+ answer := argv.Request{Shell: argv.Bash, Line: line, Cursor: len(line)}.
+ Answer(root, help, meta)
+ if answer.Files != argv.AnyFile {
+ t.Errorf("the reference fell back to paths at %q, and this did not: %v",
+ line, answer.Files)
+ }
+ if len(answer.Candidates) != 0 {
+ t.Errorf("nothing of the spec's own belongs there: %v", answer.Candidates)
+ }
+}
+
+func sameSet(a, b []string) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ seen := map[string]int{}
+ for _, s := range a {
+ seen[s]++
+ }
+ for _, s := range b {
+ seen[s]--
+ if seen[s] < 0 {
+ return false
+ }
+ }
+ return true
+}
diff --git a/go/internal/shadow/mise/tables.go b/go/internal/shadow/mise/tables.go
index 471c6bfb8..fd7698f2f 100644
--- a/go/internal/shadow/mise/tables.go
+++ b/go/internal/shadow/mise/tables.go
@@ -3785,25 +3785,25 @@ var cmdWhich = &argv.Command{
var Meta = argv.Metadata{
{},
{Key: FlagContinueOnError, Name: "continue-on-error", Flag: true, Spelling: "--continue-on-error"},
- {Key: FlagCd, Name: "cd", Flag: true, Spelling: "--cd"},
- {Key: FlagEnv, Name: "env", Flag: true, Spelling: "--env"},
+ {Key: FlagCd, Name: "cd", Flag: true, Spelling: "--cd", ValueName: "DIR"},
+ {Key: FlagEnv, Name: "env", Flag: true, Spelling: "--env", ValueName: "ENV"},
{Key: FlagForce, Name: "force", Flag: true, Spelling: "--force"},
- {Key: FlagJobs, Name: "jobs", Flag: true, Spelling: "--jobs"},
+ {Key: FlagJobs, Name: "jobs", Flag: true, Spelling: "--jobs", ValueName: "JOBS"},
{Key: FlagDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
- {Key: FlagProfile, Name: "profile", Flag: true, Spelling: "--profile"},
+ {Key: FlagProfile, Name: "profile", Flag: true, Spelling: "--profile", ValueName: "PROFILE"},
{Key: FlagQuiet, Name: "quiet", Flag: true, Spelling: "--quiet"},
- {Key: FlagShell, Name: "shell", Flag: true, Spelling: "--shell"},
- {Key: FlagTool, Name: "tool", Flag: true, Spelling: "--tool"},
+ {Key: FlagShell, Name: "shell", Flag: true, Spelling: "--shell", ValueName: "SHELL"},
+ {Key: FlagTool, Name: "tool", Flag: true, Spelling: "--tool", ValueName: "TOOL@VERSION"},
{Key: FlagVerbose, Name: "verbose", Flag: true, Spelling: "--verbose"},
{Key: FlagVersion, Name: "version", Flag: true, Spelling: "--version"},
{Key: FlagYes, Name: "yes", Flag: true, Spelling: "--yes"},
{Key: FlagDebug, Name: "debug", Flag: true, Spelling: "--debug"},
- {Key: FlagLogLevel, Name: "log-level", Flag: true, Spelling: "--log-level", Choices: []string{"trace", "debug", "info", "warning", "error"}},
+ {Key: FlagLogLevel, Name: "log-level", Flag: true, Spelling: "--log-level", ValueName: "LEVEL", Choices: []string{"trace", "debug", "info", "warning", "error"}},
{Key: FlagNoConfig, Name: "no-config", Flag: true, Spelling: "--no-config"},
{Key: FlagNoEnv, Name: "no-env", Flag: true, Spelling: "--no-env"},
{Key: FlagNoHooks, Name: "no-hooks", Flag: true, Spelling: "--no-hooks"},
{Key: FlagNoTimings, Name: "no-timings", Flag: true, Spelling: "--no-timings"},
- {Key: FlagOutput, Name: "output", Flag: true, Spelling: "--output"},
+ {Key: FlagOutput, Name: "output", Flag: true, Spelling: "--output", ValueName: "OUTPUT"},
{Key: FlagRaw, Name: "raw", Flag: true, Spelling: "--raw"},
{Key: FlagLocked, Name: "locked", Flag: true, Spelling: "--locked"},
{Key: FlagSilent, Name: "silent", Flag: true, Spelling: "--silent"},
@@ -3814,13 +3814,13 @@ var Meta = argv.Metadata{
{Key: ArgTaskArgsLast, Name: "TASK_ARGS_LAST"},
{},
{Key: FlagActivateQuiet, Name: "quiet", Flag: true, Spelling: "--quiet"},
- {Key: FlagActivateShell, Name: "shell", Flag: true, Spelling: "--shell", Choices: []string{"bash", "elvish", "fish", "nu", "xonsh", "zsh", "pwsh"}},
+ {Key: FlagActivateShell, Name: "shell", Flag: true, Spelling: "--shell", ValueName: "SHELL", Choices: []string{"bash", "elvish", "fish", "nu", "xonsh", "zsh", "pwsh"}},
{Key: FlagActivateNoHookEnv, Name: "no-hook-env", Flag: true, Spelling: "--no-hook-env"},
{Key: FlagActivateShims, Name: "shims", Flag: true, Spelling: "--shims"},
{Key: FlagActivateStatus, Name: "status", Flag: true, Spelling: "--status"},
{Key: ArgActivateShellType, Name: "SHELL_TYPE", Choices: []string{"bash", "elvish", "fish", "nu", "xonsh", "zsh", "pwsh"}},
{},
- {Key: FlagToolAliasTool, Name: "tool", Flag: true, Spelling: "--tool"},
+ {Key: FlagToolAliasTool, Name: "tool", Flag: true, Spelling: "--tool", ValueName: "TOOL"},
{Key: FlagToolAliasNoHeader, Name: "no-header", Flag: true, Spelling: "--no-header"},
{},
{Key: ArgToolAliasGetTool, Name: "TOOL", Required: true},
@@ -3847,9 +3847,9 @@ var Meta = argv.Metadata{
{Key: FlagBootstrapDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
{Key: FlagBootstrapYes, Name: "yes", Flag: true, Spelling: "--yes"},
{Key: FlagBootstrapForceDotfiles, Name: "force-dotfiles", Flag: true, Spelling: "--force-dotfiles"},
- {Key: FlagBootstrapOnly, Name: "only", Flag: true, Spelling: "--only", Choices: []string{"plugins", "packages", "accounts", "files", "services", "firewall", "compose", "repos", "dotfiles", "mise-shell-activate", "shell", "macos-defaults", "defaults", "macos-launchd-agents", "launchd", "linux-systemd-units", "systemd", "user", "tools", "task", "final-hook"}},
+ {Key: FlagBootstrapOnly, Name: "only", Flag: true, Spelling: "--only", ValueName: "ONLY", Choices: []string{"plugins", "packages", "accounts", "files", "services", "firewall", "compose", "repos", "dotfiles", "mise-shell-activate", "shell", "macos-defaults", "defaults", "macos-launchd-agents", "launchd", "linux-systemd-units", "systemd", "user", "tools", "task", "final-hook"}},
{Key: FlagBootstrapPromptSecrets, Name: "prompt-secrets", Flag: true, Spelling: "--prompt-secrets"},
- {Key: FlagBootstrapSkip, Name: "skip", Flag: true, Spelling: "--skip", Choices: []string{"plugins", "packages", "accounts", "files", "services", "firewall", "compose", "repos", "dotfiles", "mise-shell-activate", "shell", "macos-defaults", "defaults", "macos-launchd-agents", "launchd", "linux-systemd-units", "systemd", "user", "tools", "task", "final-hook"}},
+ {Key: FlagBootstrapSkip, Name: "skip", Flag: true, Spelling: "--skip", ValueName: "SKIP", Choices: []string{"plugins", "packages", "accounts", "files", "services", "firewall", "compose", "repos", "dotfiles", "mise-shell-activate", "shell", "macos-defaults", "defaults", "macos-launchd-agents", "launchd", "linux-systemd-units", "systemd", "user", "tools", "task", "final-hook"}},
{Key: FlagBootstrapUpdate, Name: "update", Flag: true, Spelling: "--update"},
{},
{},
@@ -3876,11 +3876,11 @@ var Meta = argv.Metadata{
{Key: FlagBootstrapDotfilesAddForce, Name: "force", Flag: true, Spelling: "--force"},
{Key: FlagBootstrapDotfilesAddGlobal, Name: "global", Flag: true, Spelling: "--global"},
{Key: FlagBootstrapDotfilesAddLocal, Name: "local", Flag: true, Spelling: "--local"},
- {Key: FlagBootstrapDotfilesAddMode, Name: "mode", Flag: true, Spelling: "--mode"},
+ {Key: FlagBootstrapDotfilesAddMode, Name: "mode", Flag: true, Spelling: "--mode", ValueName: "MODE"},
{Key: FlagBootstrapDotfilesAddDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
{Key: FlagBootstrapDotfilesAddNoApply, Name: "no-apply", Flag: true, Spelling: "--no-apply"},
- {Key: FlagBootstrapDotfilesAddPath, Name: "path", Flag: true, Spelling: "--path"},
- {Key: FlagBootstrapDotfilesAddSource, Name: "source", Flag: true, Spelling: "--source"},
+ {Key: FlagBootstrapDotfilesAddPath, Name: "path", Flag: true, Spelling: "--path", ValueName: "PATH"},
+ {Key: FlagBootstrapDotfilesAddSource, Name: "source", Flag: true, Spelling: "--source", ValueName: "PATH"},
{Key: FlagBootstrapDotfilesAddYes, Name: "yes", Flag: true, Spelling: "--yes"},
{Key: ArgBootstrapDotfilesAddTarget, Name: "TARGET", Required: true},
{},
@@ -3890,8 +3890,8 @@ var Meta = argv.Metadata{
{Key: ArgBootstrapDotfilesApplyTarget, Name: "TARGET"},
{},
{Key: FlagBootstrapDotfilesEditApply, Name: "apply", Flag: true, Spelling: "--apply"},
- {Key: FlagBootstrapDotfilesEditMode, Name: "mode", Flag: true, Spelling: "--mode"},
- {Key: FlagBootstrapDotfilesEditSource, Name: "source", Flag: true, Spelling: "--source"},
+ {Key: FlagBootstrapDotfilesEditMode, Name: "mode", Flag: true, Spelling: "--mode", ValueName: "MODE"},
+ {Key: FlagBootstrapDotfilesEditSource, Name: "source", Flag: true, Spelling: "--source", ValueName: "PATH"},
{Key: FlagBootstrapDotfilesEditYes, Name: "yes", Flag: true, Spelling: "--yes"},
{Key: ArgBootstrapDotfilesEditTarget, Name: "TARGET", Required: true},
{},
@@ -3965,7 +3965,7 @@ var Meta = argv.Metadata{
{Key: FlagBootstrapMiseShellActivateStatusMissing, Name: "missing", Flag: true, Spelling: "--missing"},
{},
{},
- {Key: FlagBootstrapPackagesApplyManager, Name: "manager", Flag: true, Spelling: "--manager"},
+ {Key: FlagBootstrapPackagesApplyManager, Name: "manager", Flag: true, Spelling: "--manager", ValueName: "MANAGER"},
{Key: FlagBootstrapPackagesApplyDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
{Key: FlagBootstrapPackagesApplyYes, Name: "yes", Flag: true, Spelling: "--yes"},
{Key: FlagBootstrapPackagesApplyUpdate, Name: "update", Flag: true, Spelling: "--update"},
@@ -3974,38 +3974,38 @@ var Meta = argv.Metadata{
{},
{Key: FlagBootstrapPackagesBrewTapLocal, Name: "local", Flag: true, Spelling: "--local"},
{Key: FlagBootstrapPackagesBrewTapDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
- {Key: FlagBootstrapPackagesBrewTapPath, Name: "path", Flag: true, Spelling: "--path"},
+ {Key: FlagBootstrapPackagesBrewTapPath, Name: "path", Flag: true, Spelling: "--path", ValueName: "PATH"},
{Key: ArgBootstrapPackagesBrewTapTap, Name: "TAP", Required: true},
{Key: ArgBootstrapPackagesBrewTapUrl, Name: "URL"},
{},
{Key: FlagBootstrapPackagesBrewUntapLocal, Name: "local", Flag: true, Spelling: "--local"},
{Key: FlagBootstrapPackagesBrewUntapDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
- {Key: FlagBootstrapPackagesBrewUntapPath, Name: "path", Flag: true, Spelling: "--path"},
+ {Key: FlagBootstrapPackagesBrewUntapPath, Name: "path", Flag: true, Spelling: "--path", ValueName: "PATH"},
{Key: ArgBootstrapPackagesBrewUntapTaps, Name: "TAPS", Required: true},
{},
- {Key: FlagBootstrapPackagesImportEnv, Name: "env", Flag: true, Spelling: "--env"},
+ {Key: FlagBootstrapPackagesImportEnv, Name: "env", Flag: true, Spelling: "--env", ValueName: "ENV"},
{Key: FlagBootstrapPackagesImportGlobal, Name: "global", Flag: true, Spelling: "--global"},
- {Key: FlagBootstrapPackagesImportManager, Name: "manager", Flag: true, Spelling: "--manager", Choices: []string{"brew"}, Default: []string{"brew"}},
+ {Key: FlagBootstrapPackagesImportManager, Name: "manager", Flag: true, Spelling: "--manager", ValueName: "MANAGER", Choices: []string{"brew"}, Default: []string{"brew"}},
{Key: FlagBootstrapPackagesImportAll, Name: "all", Flag: true, Spelling: "--all"},
{Key: FlagBootstrapPackagesImportDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
- {Key: FlagBootstrapPackagesImportPath, Name: "path", Flag: true, Spelling: "--path"},
+ {Key: FlagBootstrapPackagesImportPath, Name: "path", Flag: true, Spelling: "--path", ValueName: "PATH"},
{},
- {Key: FlagBootstrapPackagesPruneManager, Name: "manager", Flag: true, Spelling: "--manager", Choices: []string{"brew"}, Default: []string{"brew"}},
+ {Key: FlagBootstrapPackagesPruneManager, Name: "manager", Flag: true, Spelling: "--manager", ValueName: "MANAGER", Choices: []string{"brew"}, Default: []string{"brew"}},
{Key: FlagBootstrapPackagesPruneDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
{Key: FlagBootstrapPackagesPruneYes, Name: "yes", Flag: true, Spelling: "--yes"},
{},
{Key: FlagBootstrapPackagesStatusJson, Name: "json", Flag: true, Spelling: "--json"},
{Key: FlagBootstrapPackagesStatusMissing, Name: "missing", Flag: true, Spelling: "--missing"},
{},
- {Key: FlagBootstrapPackagesUpgradeManager, Name: "manager", Flag: true, Spelling: "--manager"},
+ {Key: FlagBootstrapPackagesUpgradeManager, Name: "manager", Flag: true, Spelling: "--manager", ValueName: "MANAGER"},
{Key: FlagBootstrapPackagesUpgradeDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
{Key: FlagBootstrapPackagesUpgradeYes, Name: "yes", Flag: true, Spelling: "--yes"},
{Key: ArgBootstrapPackagesUpgradePackage, Name: "PACKAGE"},
{},
- {Key: FlagBootstrapPackagesUseEnv, Name: "env", Flag: true, Spelling: "--env"},
+ {Key: FlagBootstrapPackagesUseEnv, Name: "env", Flag: true, Spelling: "--env", ValueName: "ENV"},
{Key: FlagBootstrapPackagesUseGlobal, Name: "global", Flag: true, Spelling: "--global"},
{Key: FlagBootstrapPackagesUseDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
- {Key: FlagBootstrapPackagesUsePath, Name: "path", Flag: true, Spelling: "--path"},
+ {Key: FlagBootstrapPackagesUsePath, Name: "path", Flag: true, Spelling: "--path", ValueName: "PATH"},
{Key: FlagBootstrapPackagesUseYes, Name: "yes", Flag: true, Spelling: "--yes"},
{Key: ArgBootstrapPackagesUsePackage, Name: "PACKAGE", Required: true},
{},
@@ -4019,24 +4019,24 @@ var Meta = argv.Metadata{
{Key: FlagBootstrapPluginsStatusMissing, Name: "missing", Flag: true, Spelling: "--missing"},
{},
{Key: FlagBootstrapRemoteAll, Name: "all", Flag: true, Spelling: "--all"},
- {Key: FlagBootstrapRemoteBootstrapCommand, Name: "bootstrap-command", Flag: true, Spelling: "--bootstrap-command"},
- {Key: FlagBootstrapRemoteConnectTimeout, Name: "connect-timeout", Flag: true, Spelling: "--connect-timeout", Default: []string{"10"}},
- {Key: FlagBootstrapRemoteExclude, Name: "exclude", Flag: true, Spelling: "--exclude"},
+ {Key: FlagBootstrapRemoteBootstrapCommand, Name: "bootstrap-command", Flag: true, Spelling: "--bootstrap-command", ValueName: "COMMAND"},
+ {Key: FlagBootstrapRemoteConnectTimeout, Name: "connect-timeout", Flag: true, Spelling: "--connect-timeout", ValueName: "CONNECT_TIMEOUT", Default: []string{"10"}},
+ {Key: FlagBootstrapRemoteExclude, Name: "exclude", Flag: true, Spelling: "--exclude", ValueName: "PATTERN"},
{Key: FlagBootstrapRemoteFailFast, Name: "fail-fast", Flag: true, Spelling: "--fail-fast"},
{Key: FlagBootstrapRemoteForceDotfiles, Name: "force-dotfiles", Flag: true, Spelling: "--force-dotfiles"},
- {Key: FlagBootstrapRemoteHost, Name: "host", Flag: true, Spelling: "--host"},
- {Key: FlagBootstrapRemoteIdentityFile, Name: "identity-file", Flag: true, Spelling: "--identity-file"},
+ {Key: FlagBootstrapRemoteHost, Name: "host", Flag: true, Spelling: "--host", ValueName: "[USER@]HOST"},
+ {Key: FlagBootstrapRemoteIdentityFile, Name: "identity-file", Flag: true, Spelling: "--identity-file", ValueName: "IDENTITY_FILE"},
{Key: FlagBootstrapRemoteDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
{Key: FlagBootstrapRemoteKeepStaging, Name: "keep-staging", Flag: true, Spelling: "--keep-staging"},
- {Key: FlagBootstrapRemoteMiseBin, Name: "mise-bin", Flag: true, Spelling: "--mise-bin"},
- {Key: FlagBootstrapRemoteOnly, Name: "only", Flag: true, Spelling: "--only", Choices: []string{"plugins", "packages", "accounts", "files", "services", "firewall", "compose", "repos", "dotfiles", "mise-shell-activate", "shell", "macos-defaults", "defaults", "macos-launchd-agents", "launchd", "linux-systemd-units", "systemd", "user", "tools", "task", "final-hook"}},
- {Key: FlagBootstrapRemotePort, Name: "port", Flag: true, Spelling: "--port"},
+ {Key: FlagBootstrapRemoteMiseBin, Name: "mise-bin", Flag: true, Spelling: "--mise-bin", ValueName: "MISE_BIN"},
+ {Key: FlagBootstrapRemoteOnly, Name: "only", Flag: true, Spelling: "--only", ValueName: "ONLY", Choices: []string{"plugins", "packages", "accounts", "files", "services", "firewall", "compose", "repos", "dotfiles", "mise-shell-activate", "shell", "macos-defaults", "defaults", "macos-launchd-agents", "launchd", "linux-systemd-units", "systemd", "user", "tools", "task", "final-hook"}},
+ {Key: FlagBootstrapRemotePort, Name: "port", Flag: true, Spelling: "--port", ValueName: "PORT"},
{Key: FlagBootstrapRemotePromptSecrets, Name: "prompt-secrets", Flag: true, Spelling: "--prompt-secrets"},
- {Key: FlagBootstrapRemoteRemoteMise, Name: "remote-mise", Flag: true, Spelling: "--remote-mise"},
- {Key: FlagBootstrapRemoteSkip, Name: "skip", Flag: true, Spelling: "--skip", Choices: []string{"plugins", "packages", "accounts", "files", "services", "firewall", "compose", "repos", "dotfiles", "mise-shell-activate", "shell", "macos-defaults", "defaults", "macos-launchd-agents", "launchd", "linux-systemd-units", "systemd", "user", "tools", "task", "final-hook"}},
- {Key: FlagBootstrapRemoteSource, Name: "source", Flag: true, Spelling: "--source"},
- {Key: FlagBootstrapRemoteSshOption, Name: "ssh-option", Flag: true, Spelling: "--ssh-option"},
- {Key: FlagBootstrapRemoteTag, Name: "tag", Flag: true, Spelling: "--tag"},
+ {Key: FlagBootstrapRemoteRemoteMise, Name: "remote-mise", Flag: true, Spelling: "--remote-mise", ValueName: "COMMAND"},
+ {Key: FlagBootstrapRemoteSkip, Name: "skip", Flag: true, Spelling: "--skip", ValueName: "SKIP", Choices: []string{"plugins", "packages", "accounts", "files", "services", "firewall", "compose", "repos", "dotfiles", "mise-shell-activate", "shell", "macos-defaults", "defaults", "macos-launchd-agents", "launchd", "linux-systemd-units", "systemd", "user", "tools", "task", "final-hook"}},
+ {Key: FlagBootstrapRemoteSource, Name: "source", Flag: true, Spelling: "--source", ValueName: "SOURCE"},
+ {Key: FlagBootstrapRemoteSshOption, Name: "ssh-option", Flag: true, Spelling: "--ssh-option", ValueName: "OPTION"},
+ {Key: FlagBootstrapRemoteTag, Name: "tag", Flag: true, Spelling: "--tag", ValueName: "TAG"},
{Key: FlagBootstrapRemoteUpdate, Name: "update", Flag: true, Spelling: "--update"},
{Key: FlagBootstrapRemoteYes, Name: "yes", Flag: true, Spelling: "--yes"},
{Key: ArgBootstrapRemoteTarget, Name: "TARGET"},
@@ -4088,7 +4088,7 @@ var Meta = argv.Metadata{
{},
{},
{Key: FlagCacheClearOutdate, Name: "outdate", Flag: true, Spelling: "--outdate"},
- {Key: FlagCacheClearTask, Name: "task", Flag: true, Spelling: "--task"},
+ {Key: FlagCacheClearTask, Name: "task", Flag: true, Spelling: "--task", ValueName: "TASK"},
{Key: ArgCacheClearTool, Name: "TOOL"},
{},
{},
@@ -4099,7 +4099,7 @@ var Meta = argv.Metadata{
{Key: FlagCacheTaskJson, Name: "json", Flag: true, Spelling: "--json"},
{Key: ArgCacheTaskTask, Name: "TASK", Required: true},
{},
- {Key: FlagCompletionShell, Name: "shell", Flag: true, Spelling: "--shell", Choices: []string{"bash", "fish", "powershell", "zsh"}},
+ {Key: FlagCompletionShell, Name: "shell", Flag: true, Spelling: "--shell", ValueName: "SHELL_TYPE", Choices: []string{"bash", "fish", "powershell", "zsh"}},
{Key: FlagCompletionIncludeBashCompletionLib, Name: "include-bash-completion-lib", Flag: true, Spelling: "--include-bash-completion-lib"},
{Key: FlagCompletionUsage, Name: "usage", Flag: true, Spelling: "--usage"},
{Key: ArgCompletionShell, Name: "SHELL", Choices: []string{"bash", "fish", "powershell", "zsh"}},
@@ -4108,15 +4108,15 @@ var Meta = argv.Metadata{
{Key: FlagConfigNoHeader, Name: "no-header", Flag: true, Spelling: "--no-header"},
{Key: FlagConfigTrackedConfigs, Name: "tracked-configs", Flag: true, Spelling: "--tracked-configs"},
{},
- {Key: FlagConfigGetFile, Name: "file", Flag: true, Spelling: "--file"},
+ {Key: FlagConfigGetFile, Name: "file", Flag: true, Spelling: "--file", ValueName: "FILE"},
{Key: ArgConfigGetKey, Name: "KEY"},
{},
{Key: FlagConfigLsJson, Name: "json", Flag: true, Spelling: "--json"},
{Key: FlagConfigLsNoHeader, Name: "no-header", Flag: true, Spelling: "--no-header"},
{Key: FlagConfigLsTrackedConfigs, Name: "tracked-configs", Flag: true, Spelling: "--tracked-configs"},
{},
- {Key: FlagConfigSetFile, Name: "file", Flag: true, Spelling: "--file"},
- {Key: FlagConfigSetType, Name: "type", Flag: true, Spelling: "--type", Choices: []string{"infer", "string", "integer", "float", "bool", "list", "set"}, Default: []string{"infer"}},
+ {Key: FlagConfigSetFile, Name: "file", Flag: true, Spelling: "--file", ValueName: "FILE"},
+ {Key: FlagConfigSetType, Name: "type", Flag: true, Spelling: "--type", ValueName: "TYPE", Choices: []string{"infer", "string", "integer", "float", "bool", "list", "set"}, Default: []string{"infer"}},
{Key: ArgConfigSetKey, Name: "KEY", Required: true},
{Key: ArgConfigSetValue, Name: "VALUE"},
{},
@@ -4131,11 +4131,11 @@ var Meta = argv.Metadata{
{Key: FlagDotfilesAddForce, Name: "force", Flag: true, Spelling: "--force"},
{Key: FlagDotfilesAddGlobal, Name: "global", Flag: true, Spelling: "--global"},
{Key: FlagDotfilesAddLocal, Name: "local", Flag: true, Spelling: "--local"},
- {Key: FlagDotfilesAddMode, Name: "mode", Flag: true, Spelling: "--mode"},
+ {Key: FlagDotfilesAddMode, Name: "mode", Flag: true, Spelling: "--mode", ValueName: "MODE"},
{Key: FlagDotfilesAddDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
{Key: FlagDotfilesAddNoApply, Name: "no-apply", Flag: true, Spelling: "--no-apply"},
- {Key: FlagDotfilesAddPath, Name: "path", Flag: true, Spelling: "--path"},
- {Key: FlagDotfilesAddSource, Name: "source", Flag: true, Spelling: "--source"},
+ {Key: FlagDotfilesAddPath, Name: "path", Flag: true, Spelling: "--path", ValueName: "PATH"},
+ {Key: FlagDotfilesAddSource, Name: "source", Flag: true, Spelling: "--source", ValueName: "PATH"},
{Key: FlagDotfilesAddYes, Name: "yes", Flag: true, Spelling: "--yes"},
{Key: ArgDotfilesAddTarget, Name: "TARGET", Required: true},
{},
@@ -4145,8 +4145,8 @@ var Meta = argv.Metadata{
{Key: ArgDotfilesApplyTarget, Name: "TARGET"},
{},
{Key: FlagDotfilesEditApply, Name: "apply", Flag: true, Spelling: "--apply"},
- {Key: FlagDotfilesEditMode, Name: "mode", Flag: true, Spelling: "--mode"},
- {Key: FlagDotfilesEditSource, Name: "source", Flag: true, Spelling: "--source"},
+ {Key: FlagDotfilesEditMode, Name: "mode", Flag: true, Spelling: "--mode", ValueName: "MODE"},
+ {Key: FlagDotfilesEditSource, Name: "source", Flag: true, Spelling: "--source", ValueName: "PATH"},
{Key: FlagDotfilesEditYes, Name: "yes", Flag: true, Spelling: "--yes"},
{Key: ArgDotfilesEditTarget, Name: "TARGET", Required: true},
{},
@@ -4163,23 +4163,23 @@ var Meta = argv.Metadata{
{},
{Key: FlagDoctorPathFull, Name: "full", Flag: true, Spelling: "--full"},
{},
- {Key: FlagEnShell, Name: "shell", Flag: true, Spelling: "--shell"},
+ {Key: FlagEnShell, Name: "shell", Flag: true, Spelling: "--shell", ValueName: "SHELL"},
{Key: ArgEnDir, Name: "DIR", Default: []string{"."}},
{},
{Key: FlagEnvDotenv, Name: "dotenv", Flag: true, Spelling: "--dotenv"},
{Key: FlagEnvJson, Name: "json", Flag: true, Spelling: "--json"},
- {Key: FlagEnvShell, Name: "shell", Flag: true, Spelling: "--shell", Choices: []string{"bash", "elvish", "fish", "nu", "xonsh", "zsh", "pwsh"}},
+ {Key: FlagEnvShell, Name: "shell", Flag: true, Spelling: "--shell", ValueName: "SHELL", Choices: []string{"bash", "elvish", "fish", "nu", "xonsh", "zsh", "pwsh"}},
{Key: FlagEnvJsonExtended, Name: "json-extended", Flag: true, Spelling: "--json-extended"},
{Key: FlagEnvRedacted, Name: "redacted", Flag: true, Spelling: "--redacted"},
{Key: FlagEnvValues, Name: "values", Flag: true, Spelling: "--values"},
{Key: ArgEnvToolVersion, Name: "TOOL@VERSION"},
{},
- {Key: FlagExecCommand, Name: "command", Flag: true, Spelling: "--command"},
- {Key: FlagExecJobs, Name: "jobs", Flag: true, Spelling: "--jobs"},
- {Key: FlagExecAllowEnv, Name: "allow-env", Flag: true, Spelling: "--allow-env"},
- {Key: FlagExecAllowNet, Name: "allow-net", Flag: true, Spelling: "--allow-net"},
- {Key: FlagExecAllowRead, Name: "allow-read", Flag: true, Spelling: "--allow-read"},
- {Key: FlagExecAllowWrite, Name: "allow-write", Flag: true, Spelling: "--allow-write"},
+ {Key: FlagExecCommand, Name: "command", Flag: true, Spelling: "--command", ValueName: "C"},
+ {Key: FlagExecJobs, Name: "jobs", Flag: true, Spelling: "--jobs", ValueName: "JOBS"},
+ {Key: FlagExecAllowEnv, Name: "allow-env", Flag: true, Spelling: "--allow-env", ValueName: "VAR"},
+ {Key: FlagExecAllowNet, Name: "allow-net", Flag: true, Spelling: "--allow-net", ValueName: "HOST"},
+ {Key: FlagExecAllowRead, Name: "allow-read", Flag: true, Spelling: "--allow-read", ValueName: "PATH"},
+ {Key: FlagExecAllowWrite, Name: "allow-write", Flag: true, Spelling: "--allow-write", ValueName: "PATH"},
{Key: FlagExecDenyAll, Name: "deny-all", Flag: true, Spelling: "--deny-all"},
{Key: FlagExecDenyEnv, Name: "deny-env", Flag: true, Spelling: "--deny-env"},
{Key: FlagExecDenyNet, Name: "deny-net", Flag: true, Spelling: "--deny-net"},
@@ -4197,49 +4197,49 @@ var Meta = argv.Metadata{
{},
{},
{Key: FlagGenerateBootstrapLocalize, Name: "localize", Flag: true, Spelling: "--localize"},
- {Key: FlagGenerateBootstrapVersion, Name: "version", Flag: true, Spelling: "--version"},
- {Key: FlagGenerateBootstrapWrite, Name: "write", Flag: true, Spelling: "--write"},
- {Key: FlagGenerateBootstrapLocalizedDir, Name: "localized-dir", Flag: true, Spelling: "--localized-dir", Default: []string{".mise"}},
+ {Key: FlagGenerateBootstrapVersion, Name: "version", Flag: true, Spelling: "--version", ValueName: "VERSION"},
+ {Key: FlagGenerateBootstrapWrite, Name: "write", Flag: true, Spelling: "--write", ValueName: "WRITE"},
+ {Key: FlagGenerateBootstrapLocalizedDir, Name: "localized-dir", Flag: true, Spelling: "--localized-dir", ValueName: "LOCALIZED_DIR", Default: []string{".mise"}},
{},
{Key: FlagGenerateConfigGlobal, Name: "global", Flag: true, Spelling: "--global"},
{Key: FlagGenerateConfigDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
- {Key: FlagGenerateConfigToolVersions, Name: "tool-versions", Flag: true, Spelling: "--tool-versions"},
+ {Key: FlagGenerateConfigToolVersions, Name: "tool-versions", Flag: true, Spelling: "--tool-versions", ValueName: "TOOL_VERSIONS"},
{Key: ArgGenerateConfigPath, Name: "PATH"},
{},
- {Key: FlagGenerateDevcontainerImage, Name: "image", Flag: true, Spelling: "--image"},
+ {Key: FlagGenerateDevcontainerImage, Name: "image", Flag: true, Spelling: "--image", ValueName: "IMAGE"},
{Key: FlagGenerateDevcontainerMountMiseData, Name: "mount-mise-data", Flag: true, Spelling: "--mount-mise-data"},
- {Key: FlagGenerateDevcontainerName, Name: "name", Flag: true, Spelling: "--name"},
+ {Key: FlagGenerateDevcontainerName, Name: "name", Flag: true, Spelling: "--name", ValueName: "NAME"},
{Key: FlagGenerateDevcontainerWrite, Name: "write", Flag: true, Spelling: "--write"},
{},
- {Key: FlagGenerateGitPreCommitTask, Name: "task", Flag: true, Spelling: "--task", Default: []string{"pre-commit"}},
+ {Key: FlagGenerateGitPreCommitTask, Name: "task", Flag: true, Spelling: "--task", ValueName: "TASK", Default: []string{"pre-commit"}},
{Key: FlagGenerateGitPreCommitWrite, Name: "write", Flag: true, Spelling: "--write"},
- {Key: FlagGenerateGitPreCommitHook, Name: "hook", Flag: true, Spelling: "--hook", Default: []string{"pre-commit"}},
+ {Key: FlagGenerateGitPreCommitHook, Name: "hook", Flag: true, Spelling: "--hook", ValueName: "HOOK", Default: []string{"pre-commit"}},
{},
- {Key: FlagGenerateGithubActionTask, Name: "task", Flag: true, Spelling: "--task", Default: []string{"ci"}},
+ {Key: FlagGenerateGithubActionTask, Name: "task", Flag: true, Spelling: "--task", ValueName: "TASK", Default: []string{"ci"}},
{Key: FlagGenerateGithubActionWrite, Name: "write", Flag: true, Spelling: "--write"},
- {Key: FlagGenerateGithubActionName, Name: "name", Flag: true, Spelling: "--name", Default: []string{"ci"}},
+ {Key: FlagGenerateGithubActionName, Name: "name", Flag: true, Spelling: "--name", ValueName: "NAME", Default: []string{"ci"}},
{},
{Key: FlagGenerateTaskDocsInject, Name: "inject", Flag: true, Spelling: "--inject"},
{Key: FlagGenerateTaskDocsIndex, Name: "index", Flag: true, Spelling: "--index"},
{Key: FlagGenerateTaskDocsMulti, Name: "multi", Flag: true, Spelling: "--multi"},
- {Key: FlagGenerateTaskDocsOutput, Name: "output", Flag: true, Spelling: "--output"},
- {Key: FlagGenerateTaskDocsRoot, Name: "root", Flag: true, Spelling: "--root"},
- {Key: FlagGenerateTaskDocsStyle, Name: "style", Flag: true, Spelling: "--style", Choices: []string{"simple", "detailed"}, Default: []string{"simple"}},
+ {Key: FlagGenerateTaskDocsOutput, Name: "output", Flag: true, Spelling: "--output", ValueName: "OUTPUT"},
+ {Key: FlagGenerateTaskDocsRoot, Name: "root", Flag: true, Spelling: "--root", ValueName: "ROOT"},
+ {Key: FlagGenerateTaskDocsStyle, Name: "style", Flag: true, Spelling: "--style", ValueName: "STYLE", Choices: []string{"simple", "detailed"}, Default: []string{"simple"}},
{},
- {Key: FlagGenerateTaskStubsDir, Name: "dir", Flag: true, Spelling: "--dir", Default: []string{"bin"}},
- {Key: FlagGenerateTaskStubsMiseBin, Name: "mise-bin", Flag: true, Spelling: "--mise-bin", Default: []string{"mise"}},
+ {Key: FlagGenerateTaskStubsDir, Name: "dir", Flag: true, Spelling: "--dir", ValueName: "DIR", Default: []string{"bin"}},
+ {Key: FlagGenerateTaskStubsMiseBin, Name: "mise-bin", Flag: true, Spelling: "--mise-bin", ValueName: "MISE_BIN", Default: []string{"mise"}},
{},
- {Key: FlagGenerateToolStubBin, Name: "bin", Flag: true, Spelling: "--bin"},
+ {Key: FlagGenerateToolStubBin, Name: "bin", Flag: true, Spelling: "--bin", ValueName: "BIN"},
{Key: FlagGenerateToolStubBootstrap, Name: "bootstrap", Flag: true, Spelling: "--bootstrap"},
- {Key: FlagGenerateToolStubBootstrapVersion, Name: "bootstrap-version", Flag: true, Spelling: "--bootstrap-version"},
+ {Key: FlagGenerateToolStubBootstrapVersion, Name: "bootstrap-version", Flag: true, Spelling: "--bootstrap-version", ValueName: "BOOTSTRAP_VERSION"},
{Key: FlagGenerateToolStubFetch, Name: "fetch", Flag: true, Spelling: "--fetch"},
- {Key: FlagGenerateToolStubHttp, Name: "http", Flag: true, Spelling: "--http", Default: []string{"http"}},
+ {Key: FlagGenerateToolStubHttp, Name: "http", Flag: true, Spelling: "--http", ValueName: "HTTP", Default: []string{"http"}},
{Key: FlagGenerateToolStubLock, Name: "lock", Flag: true, Spelling: "--lock"},
- {Key: FlagGenerateToolStubPlatformBin, Name: "platform-bin", Flag: true, Spelling: "--platform-bin"},
- {Key: FlagGenerateToolStubPlatformUrl, Name: "platform-url", Flag: true, Spelling: "--platform-url"},
+ {Key: FlagGenerateToolStubPlatformBin, Name: "platform-bin", Flag: true, Spelling: "--platform-bin", ValueName: "PLATFORM_BIN"},
+ {Key: FlagGenerateToolStubPlatformUrl, Name: "platform-url", Flag: true, Spelling: "--platform-url", ValueName: "PLATFORM_URL"},
{Key: FlagGenerateToolStubSkipDownload, Name: "skip-download", Flag: true, Spelling: "--skip-download"},
- {Key: FlagGenerateToolStubUrl, Name: "url", Flag: true, Spelling: "--url"},
- {Key: FlagGenerateToolStubVersion, Name: "version", Flag: true, Spelling: "--version", Default: []string{"latest"}},
+ {Key: FlagGenerateToolStubUrl, Name: "url", Flag: true, Spelling: "--url", ValueName: "URL"},
+ {Key: FlagGenerateToolStubVersion, Name: "version", Flag: true, Spelling: "--version", ValueName: "VERSION", Default: []string{"latest"}},
{Key: ArgGenerateToolStubOutput, Name: "OUTPUT", Required: true},
{},
{},
@@ -4252,16 +4252,16 @@ var Meta = argv.Metadata{
{Key: FlagGlobalFuzzy, Name: "fuzzy", Flag: true, Spelling: "--fuzzy"},
{Key: FlagGlobalPath, Name: "path", Flag: true, Spelling: "--path"},
{Key: FlagGlobalPin, Name: "pin", Flag: true, Spelling: "--pin"},
- {Key: FlagGlobalRemove, Name: "remove", Flag: true, Spelling: "--remove"},
+ {Key: FlagGlobalRemove, Name: "remove", Flag: true, Spelling: "--remove", ValueName: "TOOL"},
{Key: ArgGlobalToolVersion, Name: "TOOL@VERSION"},
{},
{Key: FlagHookEnvForce, Name: "force", Flag: true, Spelling: "--force"},
{Key: FlagHookEnvQuiet, Name: "quiet", Flag: true, Spelling: "--quiet"},
- {Key: FlagHookEnvShell, Name: "shell", Flag: true, Spelling: "--shell", Choices: []string{"bash", "elvish", "fish", "nu", "xonsh", "zsh", "pwsh"}},
- {Key: FlagHookEnvReason, Name: "reason", Flag: true, Spelling: "--reason", Choices: []string{"precmd", "chpwd"}},
+ {Key: FlagHookEnvShell, Name: "shell", Flag: true, Spelling: "--shell", ValueName: "SHELL", Choices: []string{"bash", "elvish", "fish", "nu", "xonsh", "zsh", "pwsh"}},
+ {Key: FlagHookEnvReason, Name: "reason", Flag: true, Spelling: "--reason", ValueName: "REASON", Choices: []string{"precmd", "chpwd"}},
{Key: FlagHookEnvStatus, Name: "status", Flag: true, Spelling: "--status"},
{},
- {Key: FlagHookNotFoundShell, Name: "shell", Flag: true, Spelling: "--shell", Choices: []string{"bash", "elvish", "fish", "nu", "xonsh", "zsh", "pwsh"}},
+ {Key: FlagHookNotFoundShell, Name: "shell", Flag: true, Spelling: "--shell", ValueName: "SHELL", Choices: []string{"bash", "elvish", "fish", "nu", "xonsh", "zsh", "pwsh"}},
{Key: ArgHookNotFoundBin, Name: "BIN", Required: true},
{},
{Key: FlagImplodeDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
@@ -4269,18 +4269,18 @@ var Meta = argv.Metadata{
{},
{Key: FlagEditGlobal, Name: "global", Flag: true, Spelling: "--global"},
{Key: FlagEditDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
- {Key: FlagEditToolVersions, Name: "tool-versions", Flag: true, Spelling: "--tool-versions"},
+ {Key: FlagEditToolVersions, Name: "tool-versions", Flag: true, Spelling: "--tool-versions", ValueName: "TOOL_VERSIONS"},
{Key: ArgEditPath, Name: "PATH"},
{},
{Key: FlagInstallForce, Name: "force", Flag: true, Spelling: "--force"},
- {Key: FlagInstallJobs, Name: "jobs", Flag: true, Spelling: "--jobs"},
+ {Key: FlagInstallJobs, Name: "jobs", Flag: true, Spelling: "--jobs", ValueName: "JOBS"},
{Key: FlagInstallDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
{Key: FlagInstallVerbose, Name: "verbose", Flag: true, Spelling: "--verbose"},
{Key: FlagInstallDryRunCode, Name: "dry-run-code", Flag: true, Spelling: "--dry-run-code"},
- {Key: FlagInstallMinimumReleaseAge, Name: "minimum-release-age", Flag: true, Spelling: "--minimum-release-age"},
+ {Key: FlagInstallMinimumReleaseAge, Name: "minimum-release-age", Flag: true, Spelling: "--minimum-release-age", ValueName: "MINIMUM_RELEASE_AGE"},
{Key: FlagInstallMonorepo, Name: "monorepo", Flag: true, Spelling: "--monorepo"},
{Key: FlagInstallRaw, Name: "raw", Flag: true, Spelling: "--raw"},
- {Key: FlagInstallShared, Name: "shared", Flag: true, Spelling: "--shared"},
+ {Key: FlagInstallShared, Name: "shared", Flag: true, Spelling: "--shared", ValueName: "SHARED"},
{Key: FlagInstallSystem, Name: "system", Flag: true, Spelling: "--system"},
{Key: ArgInstallToolVersion, Name: "TOOL@VERSION"},
{},
@@ -4288,7 +4288,7 @@ var Meta = argv.Metadata{
{Key: ArgInstallIntoPath, Name: "PATH", Required: true},
{},
{Key: FlagLatestInstalled, Name: "installed", Flag: true, Spelling: "--installed"},
- {Key: FlagLatestMinimumReleaseAge, Name: "minimum-release-age", Flag: true, Spelling: "--minimum-release-age"},
+ {Key: FlagLatestMinimumReleaseAge, Name: "minimum-release-age", Flag: true, Spelling: "--minimum-release-age", ValueName: "MINIMUM_RELEASE_AGE"},
{Key: ArgLatestToolVersion, Name: "TOOL@VERSION", Required: true},
{Key: ArgLatestAsdfVersion, Name: "ASDF_VERSION"},
{},
@@ -4300,17 +4300,17 @@ var Meta = argv.Metadata{
{Key: FlagLocalFuzzy, Name: "fuzzy", Flag: true, Spelling: "--fuzzy"},
{Key: FlagLocalPath, Name: "path", Flag: true, Spelling: "--path"},
{Key: FlagLocalPin, Name: "pin", Flag: true, Spelling: "--pin"},
- {Key: FlagLocalRemove, Name: "remove", Flag: true, Spelling: "--remove"},
+ {Key: FlagLocalRemove, Name: "remove", Flag: true, Spelling: "--remove", ValueName: "TOOL"},
{Key: ArgLocalToolVersion, Name: "TOOL@VERSION"},
{},
{Key: FlagLockGlobal, Name: "global", Flag: true, Spelling: "--global"},
- {Key: FlagLockJobs, Name: "jobs", Flag: true, Spelling: "--jobs"},
+ {Key: FlagLockJobs, Name: "jobs", Flag: true, Spelling: "--jobs", ValueName: "JOBS"},
{Key: FlagLockDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
- {Key: FlagLockPlatform, Name: "platform", Flag: true, Spelling: "--platform"},
+ {Key: FlagLockPlatform, Name: "platform", Flag: true, Spelling: "--platform", ValueName: "PLATFORM"},
{Key: FlagLockBump, Name: "bump", Flag: true, Spelling: "--bump"},
{Key: FlagLockJson, Name: "json", Flag: true, Spelling: "--json"},
{Key: FlagLockLocal, Name: "local", Flag: true, Spelling: "--local"},
- {Key: FlagLockMinimumReleaseAge, Name: "minimum-release-age", Flag: true, Spelling: "--minimum-release-age"},
+ {Key: FlagLockMinimumReleaseAge, Name: "minimum-release-age", Flag: true, Spelling: "--minimum-release-age", ValueName: "MINIMUM_RELEASE_AGE"},
{Key: ArgLockTool, Name: "TOOL"},
{},
{Key: FlagLsCurrent, Name: "current", Flag: true, Spelling: "--current"},
@@ -4320,17 +4320,17 @@ var Meta = argv.Metadata{
{Key: FlagLsLocal, Name: "local", Flag: true, Spelling: "--local"},
{Key: FlagLsMissing, Name: "missing", Flag: true, Spelling: "--missing"},
{Key: FlagLsOffline, Name: "offline", Flag: true, Spelling: "--offline"},
- {Key: FlagLsPlugin, Name: "plugin", Flag: true, Spelling: "--plugin"},
+ {Key: FlagLsPlugin, Name: "plugin", Flag: true, Spelling: "--plugin", ValueName: "TOOL_FLAG"},
{Key: FlagLsAllSources, Name: "all-sources", Flag: true, Spelling: "--all-sources"},
{Key: FlagLsMonorepo, Name: "monorepo", Flag: true, Spelling: "--monorepo"},
{Key: FlagLsNoHeader, Name: "no-header", Flag: true, Spelling: "--no-header"},
{Key: FlagLsOutdated, Name: "outdated", Flag: true, Spelling: "--outdated"},
- {Key: FlagLsPrefix, Name: "prefix", Flag: true, Spelling: "--prefix"},
+ {Key: FlagLsPrefix, Name: "prefix", Flag: true, Spelling: "--prefix", ValueName: "PREFIX"},
{Key: FlagLsPrunable, Name: "prunable", Flag: true, Spelling: "--prunable"},
{Key: ArgLsInstalledTool, Name: "INSTALLED_TOOL"},
{},
{Key: FlagLsRemoteAll, Name: "all", Flag: true, Spelling: "--all"},
- {Key: FlagLsRemoteMinimumReleaseAge, Name: "minimum-release-age", Flag: true, Spelling: "--minimum-release-age"},
+ {Key: FlagLsRemoteMinimumReleaseAge, Name: "minimum-release-age", Flag: true, Spelling: "--minimum-release-age", ValueName: "MINIMUM_RELEASE_AGE"},
{Key: FlagLsRemoteJson, Name: "json", Flag: true, Spelling: "--json"},
{Key: FlagLsRemoteNoVersionsHost, Name: "no-versions-host", Flag: true, Spelling: "--no-versions-host"},
{Key: FlagLsRemotePrerelease, Name: "prerelease", Flag: true, Spelling: "--prerelease"},
@@ -4340,39 +4340,39 @@ var Meta = argv.Metadata{
{},
{},
{},
- {Key: FlagOciBuildCopy, Name: "copy", Flag: true, Spelling: "--copy"},
- {Key: FlagOciBuildOutput, Name: "output", Flag: true, Spelling: "--output", Default: []string{"./mise-oci"}},
- {Key: FlagOciBuildFrom, Name: "from", Flag: true, Spelling: "--from"},
+ {Key: FlagOciBuildCopy, Name: "copy", Flag: true, Spelling: "--copy", ValueName: "HOST_PATH:IMAGE_PATH"},
+ {Key: FlagOciBuildOutput, Name: "output", Flag: true, Spelling: "--output", ValueName: "OUTPUT", Default: []string{"./mise-oci"}},
+ {Key: FlagOciBuildFrom, Name: "from", Flag: true, Spelling: "--from", ValueName: "FROM"},
{Key: FlagOciBuildIncludeGlobal, Name: "include-global", Flag: true, Spelling: "--include-global"},
- {Key: FlagOciBuildTag, Name: "tag", Flag: true, Spelling: "--tag"},
- {Key: FlagOciBuildMountPoint, Name: "mount-point", Flag: true, Spelling: "--mount-point"},
+ {Key: FlagOciBuildTag, Name: "tag", Flag: true, Spelling: "--tag", ValueName: "TAG"},
+ {Key: FlagOciBuildMountPoint, Name: "mount-point", Flag: true, Spelling: "--mount-point", ValueName: "MOUNT_POINT"},
{Key: FlagOciBuildNoMise, Name: "no-mise", Flag: true, Spelling: "--no-mise"},
- {Key: FlagOciBuildOwner, Name: "owner", Flag: true, Spelling: "--owner"},
+ {Key: FlagOciBuildOwner, Name: "owner", Flag: true, Spelling: "--owner", ValueName: "UID[:GID]"},
{},
- {Key: FlagOciPushCacheFrom, Name: "cache-from", Flag: true, Spelling: "--cache-from"},
- {Key: FlagOciPushFrom, Name: "from", Flag: true, Spelling: "--from"},
- {Key: FlagOciPushImageDir, Name: "image-dir", Flag: true, Spelling: "--image-dir"},
+ {Key: FlagOciPushCacheFrom, Name: "cache-from", Flag: true, Spelling: "--cache-from", ValueName: "REF"},
+ {Key: FlagOciPushFrom, Name: "from", Flag: true, Spelling: "--from", ValueName: "FROM"},
+ {Key: FlagOciPushImageDir, Name: "image-dir", Flag: true, Spelling: "--image-dir", ValueName: "IMAGE_DIR"},
{Key: FlagOciPushIncludeGlobal, Name: "include-global", Flag: true, Spelling: "--include-global"},
- {Key: FlagOciPushMountPoint, Name: "mount-point", Flag: true, Spelling: "--mount-point"},
+ {Key: FlagOciPushMountPoint, Name: "mount-point", Flag: true, Spelling: "--mount-point", ValueName: "MOUNT_POINT"},
{Key: FlagOciPushNoCache, Name: "no-cache", Flag: true, Spelling: "--no-cache"},
{Key: FlagOciPushNoMise, Name: "no-mise", Flag: true, Spelling: "--no-mise"},
- {Key: FlagOciPushOwner, Name: "owner", Flag: true, Spelling: "--owner"},
+ {Key: FlagOciPushOwner, Name: "owner", Flag: true, Spelling: "--owner", ValueName: "UID[:GID]"},
{Key: FlagOciPushUpdateIndex, Name: "update-index", Flag: true, Spelling: "--update-index"},
{Key: ArgOciPushRef, Name: "REF", Required: true},
{},
- {Key: FlagOciRunEngine, Name: "engine", Flag: true, Spelling: "--engine", Choices: []string{"auto", "podman", "docker"}, Default: []string{"auto"}},
- {Key: FlagOciRunFrom, Name: "from", Flag: true, Spelling: "--from"},
- {Key: FlagOciRunImageDir, Name: "image-dir", Flag: true, Spelling: "--image-dir"},
+ {Key: FlagOciRunEngine, Name: "engine", Flag: true, Spelling: "--engine", ValueName: "ENGINE", Choices: []string{"auto", "podman", "docker"}, Default: []string{"auto"}},
+ {Key: FlagOciRunFrom, Name: "from", Flag: true, Spelling: "--from", ValueName: "FROM"},
+ {Key: FlagOciRunImageDir, Name: "image-dir", Flag: true, Spelling: "--image-dir", ValueName: "IMAGE_DIR"},
{Key: FlagOciRunIncludeGlobal, Name: "include-global", Flag: true, Spelling: "--include-global"},
{Key: FlagOciRunKeep, Name: "keep", Flag: true, Spelling: "--keep"},
- {Key: FlagOciRunMountPoint, Name: "mount-point", Flag: true, Spelling: "--mount-point"},
+ {Key: FlagOciRunMountPoint, Name: "mount-point", Flag: true, Spelling: "--mount-point", ValueName: "MOUNT_POINT"},
{Key: FlagOciRunNoMise, Name: "no-mise", Flag: true, Spelling: "--no-mise"},
- {Key: FlagOciRunOwner, Name: "owner", Flag: true, Spelling: "--owner"},
- {Key: FlagOciRunVolume, Name: "volume", Flag: true, Spelling: "--volume"},
- {Key: FlagOciRunEnv, Name: "env", Flag: true, Spelling: "--env"},
+ {Key: FlagOciRunOwner, Name: "owner", Flag: true, Spelling: "--owner", ValueName: "UID[:GID]"},
+ {Key: FlagOciRunVolume, Name: "volume", Flag: true, Spelling: "--volume", ValueName: "HOST:CONTAINER"},
+ {Key: FlagOciRunEnv, Name: "env", Flag: true, Spelling: "--env", ValueName: "KEY=VAL"},
{Key: FlagOciRunInteractive, Name: "interactive", Flag: true, Spelling: "--interactive"},
{Key: FlagOciRunTty, Name: "tty", Flag: true, Spelling: "--tty"},
- {Key: FlagOciRunWorkdir, Name: "workdir", Flag: true, Spelling: "--workdir"},
+ {Key: FlagOciRunWorkdir, Name: "workdir", Flag: true, Spelling: "--workdir", ValueName: "WORKDIR"},
{Key: ArgOciRunCmd, Name: "CMD"},
{},
{Key: FlagOutdatedJson, Name: "json", Flag: true, Spelling: "--json"},
@@ -4394,7 +4394,7 @@ var Meta = argv.Metadata{
{},
{Key: FlagPluginsInstallAll, Name: "all", Flag: true, Spelling: "--all"},
{Key: FlagPluginsInstallForce, Name: "force", Flag: true, Spelling: "--force"},
- {Key: FlagPluginsInstallJobs, Name: "jobs", Flag: true, Spelling: "--jobs"},
+ {Key: FlagPluginsInstallJobs, Name: "jobs", Flag: true, Spelling: "--jobs", ValueName: "JOBS"},
{Key: FlagPluginsInstallVerbose, Name: "verbose", Flag: true, Spelling: "--verbose"},
{Key: ArgPluginsInstallNewPlugin, Name: "NEW_PLUGIN"},
{Key: ArgPluginsInstallGitUrl, Name: "GIT_URL"},
@@ -4418,7 +4418,7 @@ var Meta = argv.Metadata{
{Key: FlagPluginsUninstallPurge, Name: "purge", Flag: true, Spelling: "--purge"},
{Key: ArgPluginsUninstallPlugin, Name: "PLUGIN"},
{},
- {Key: FlagPluginsUpdateJobs, Name: "jobs", Flag: true, Spelling: "--jobs"},
+ {Key: FlagPluginsUpdateJobs, Name: "jobs", Flag: true, Spelling: "--jobs", ValueName: "JOBS"},
{Key: ArgPluginsUpdatePlugin, Name: "PLUGIN"},
{},
{Key: FlagDepsExplain, Name: "explain", Flag: true, Spelling: "--explain"},
@@ -4426,8 +4426,8 @@ var Meta = argv.Metadata{
{Key: FlagDepsDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
{Key: FlagDepsList, Name: "list", Flag: true, Spelling: "--list"},
{Key: FlagDepsMonorepo, Name: "monorepo", Flag: true, Spelling: "--monorepo"},
- {Key: FlagDepsOnly, Name: "only", Flag: true, Spelling: "--only"},
- {Key: FlagDepsSkip, Name: "skip", Flag: true, Spelling: "--skip"},
+ {Key: FlagDepsOnly, Name: "only", Flag: true, Spelling: "--only", ValueName: "ONLY"},
+ {Key: FlagDepsSkip, Name: "skip", Flag: true, Spelling: "--skip", ValueName: "SKIP"},
{Key: ArgDepsProvider, Name: "PROVIDER"},
{},
{Key: FlagDepsAddDev, Name: "dev", Flag: true, Spelling: "--dev"},
@@ -4438,8 +4438,8 @@ var Meta = argv.Metadata{
{Key: FlagDepsInstallDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
{Key: FlagDepsInstallList, Name: "list", Flag: true, Spelling: "--list"},
{Key: FlagDepsInstallMonorepo, Name: "monorepo", Flag: true, Spelling: "--monorepo"},
- {Key: FlagDepsInstallOnly, Name: "only", Flag: true, Spelling: "--only"},
- {Key: FlagDepsInstallSkip, Name: "skip", Flag: true, Spelling: "--skip"},
+ {Key: FlagDepsInstallOnly, Name: "only", Flag: true, Spelling: "--only", ValueName: "ONLY"},
+ {Key: FlagDepsInstallSkip, Name: "skip", Flag: true, Spelling: "--skip", ValueName: "SKIP"},
{Key: ArgDepsInstallProvider, Name: "PROVIDER"},
{},
{Key: ArgDepsRemovePackages, Name: "PACKAGES", Required: true},
@@ -4451,7 +4451,7 @@ var Meta = argv.Metadata{
{Key: FlagPruneTools, Name: "tools", Flag: true, Spelling: "--tools"},
{Key: ArgPruneInstalledTool, Name: "INSTALLED_TOOL"},
{},
- {Key: FlagRegistryBackend, Name: "backend", Flag: true, Spelling: "--backend"},
+ {Key: FlagRegistryBackend, Name: "backend", Flag: true, Spelling: "--backend", ValueName: "BACKEND"},
{Key: FlagRegistryComplete, Name: "complete", Flag: true, Spelling: "--complete"},
{Key: FlagRegistryHideAliased, Name: "hide-aliased", Flag: true, Spelling: "--hide-aliased"},
{Key: FlagRegistryJson, Name: "json", Flag: true, Spelling: "--json"},
@@ -4464,25 +4464,25 @@ var Meta = argv.Metadata{
{Key: ArgReshimVersion, Name: "VERSION"},
{},
{Key: FlagRunAffected, Name: "affected", Flag: true, Spelling: "--affected"},
- {Key: FlagRunAffectedBase, Name: "affected-base", Flag: true, Spelling: "--affected-base"},
+ {Key: FlagRunAffectedBase, Name: "affected-base", Flag: true, Spelling: "--affected-base", ValueName: "REV"},
{Key: FlagRunAffectedExplain, Name: "affected-explain", Flag: true, Spelling: "--affected-explain"},
- {Key: FlagRunAffectedHead, Name: "affected-head", Flag: true, Spelling: "--affected-head"},
+ {Key: FlagRunAffectedHead, Name: "affected-head", Flag: true, Spelling: "--affected-head", ValueName: "REV"},
{Key: FlagRunAffectedJson, Name: "affected-json", Flag: true, Spelling: "--affected-json"},
{Key: FlagRunContinueOnError, Name: "continue-on-error", Flag: true, Spelling: "--continue-on-error"},
- {Key: FlagRunCd, Name: "cd", Flag: true, Spelling: "--cd"},
+ {Key: FlagRunCd, Name: "cd", Flag: true, Spelling: "--cd", ValueName: "CD"},
{Key: FlagRunForce, Name: "force", Flag: true, Spelling: "--force"},
- {Key: FlagRunJobs, Name: "jobs", Flag: true, Spelling: "--jobs"},
+ {Key: FlagRunJobs, Name: "jobs", Flag: true, Spelling: "--jobs", ValueName: "JOBS"},
{Key: FlagRunDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
- {Key: FlagRunOutput, Name: "output", Flag: true, Spelling: "--output"},
+ {Key: FlagRunOutput, Name: "output", Flag: true, Spelling: "--output", ValueName: "OUTPUT"},
{Key: FlagRunQuiet, Name: "quiet", Flag: true, Spelling: "--quiet"},
{Key: FlagRunRaw, Name: "raw", Flag: true, Spelling: "--raw"},
- {Key: FlagRunShell, Name: "shell", Flag: true, Spelling: "--shell"},
+ {Key: FlagRunShell, Name: "shell", Flag: true, Spelling: "--shell", ValueName: "SHELL"},
{Key: FlagRunSilent, Name: "silent", Flag: true, Spelling: "--silent"},
- {Key: FlagRunTool, Name: "tool", Flag: true, Spelling: "--tool"},
- {Key: FlagRunAllowEnv, Name: "allow-env", Flag: true, Spelling: "--allow-env"},
- {Key: FlagRunAllowNet, Name: "allow-net", Flag: true, Spelling: "--allow-net"},
- {Key: FlagRunAllowRead, Name: "allow-read", Flag: true, Spelling: "--allow-read"},
- {Key: FlagRunAllowWrite, Name: "allow-write", Flag: true, Spelling: "--allow-write"},
+ {Key: FlagRunTool, Name: "tool", Flag: true, Spelling: "--tool", ValueName: "TOOL@VERSION"},
+ {Key: FlagRunAllowEnv, Name: "allow-env", Flag: true, Spelling: "--allow-env", ValueName: "VAR"},
+ {Key: FlagRunAllowNet, Name: "allow-net", Flag: true, Spelling: "--allow-net", ValueName: "HOST"},
+ {Key: FlagRunAllowRead, Name: "allow-read", Flag: true, Spelling: "--allow-read", ValueName: "PATH"},
+ {Key: FlagRunAllowWrite, Name: "allow-write", Flag: true, Spelling: "--allow-write", ValueName: "PATH"},
{Key: FlagRunDenyAll, Name: "deny-all", Flag: true, Spelling: "--deny-all"},
{Key: FlagRunDenyEnv, Name: "deny-env", Flag: true, Spelling: "--deny-env"},
{Key: FlagRunDenyNet, Name: "deny-net", Flag: true, Spelling: "--deny-net"},
@@ -4494,15 +4494,15 @@ var Meta = argv.Metadata{
{Key: FlagRunNoTimings, Name: "no-timings", Flag: true, Spelling: "--no-timings"},
{Key: FlagRunSkipDeps, Name: "skip-deps", Flag: true, Spelling: "--skip-deps"},
{Key: FlagRunSkipTools, Name: "skip-tools", Flag: true, Spelling: "--skip-tools"},
- {Key: FlagRunTaskCache, Name: "task-cache", Flag: true, Spelling: "--task-cache", Choices: []string{"read-write", "read-only", "write-only", "off", "local-only"}, Default: []string{"read-write"}},
+ {Key: FlagRunTaskCache, Name: "task-cache", Flag: true, Spelling: "--task-cache", ValueName: "TASK_CACHE", Choices: []string{"read-write", "read-only", "write-only", "off", "local-only"}, Default: []string{"read-write"}},
{Key: FlagRunTaskCacheExplain, Name: "task-cache-explain", Flag: true, Spelling: "--task-cache-explain"},
{Key: FlagRunTaskCacheExplainJson, Name: "task-cache-explain-json", Flag: true, Spelling: "--task-cache-explain-json"},
{Key: FlagRunTaskCacheStats, Name: "task-cache-stats", Flag: true, Spelling: "--task-cache-stats"},
- {Key: FlagRunTimeout, Name: "timeout", Flag: true, Spelling: "--timeout"},
+ {Key: FlagRunTimeout, Name: "timeout", Flag: true, Spelling: "--timeout", ValueName: "TIMEOUT"},
{Key: FlagRunTimings, Name: "timings", Flag: true, Spelling: "--timings"},
{},
{Key: FlagSearchInteractive, Name: "interactive", Flag: true, Spelling: "--interactive"},
- {Key: FlagSearchMatchType, Name: "match-type", Flag: true, Spelling: "--match-type", Choices: []string{"equal", "contains", "fuzzy"}, Default: []string{"fuzzy"}},
+ {Key: FlagSearchMatchType, Name: "match-type", Flag: true, Spelling: "--match-type", ValueName: "MATCH_TYPE", Choices: []string{"equal", "contains", "fuzzy"}, Default: []string{"fuzzy"}},
{Key: FlagSearchNoHeader, Name: "no-header", Flag: true, Spelling: "--no-header"},
{Key: ArgSearchName, Name: "NAME"},
{},
@@ -4511,17 +4511,17 @@ var Meta = argv.Metadata{
{Key: FlagSelfUpdateNoPlugins, Name: "no-plugins", Flag: true, Spelling: "--no-plugins"},
{Key: ArgSelfUpdateVersion, Name: "VERSION"},
{},
- {Key: FlagSetEnv, Name: "env", Flag: true, Spelling: "--env"},
+ {Key: FlagSetEnv, Name: "env", Flag: true, Spelling: "--env", ValueName: "ENV"},
{Key: FlagSetGlobal, Name: "global", Flag: true, Spelling: "--global"},
{Key: FlagSetAgeEncrypt, Name: "age-encrypt", Flag: true, Spelling: "--age-encrypt"},
- {Key: FlagSetAgeKeyFile, Name: "age-key-file", Flag: true, Spelling: "--age-key-file"},
- {Key: FlagSetAgeRecipient, Name: "age-recipient", Flag: true, Spelling: "--age-recipient"},
- {Key: FlagSetAgeSshRecipient, Name: "age-ssh-recipient", Flag: true, Spelling: "--age-ssh-recipient"},
+ {Key: FlagSetAgeKeyFile, Name: "age-key-file", Flag: true, Spelling: "--age-key-file", ValueName: "PATH"},
+ {Key: FlagSetAgeRecipient, Name: "age-recipient", Flag: true, Spelling: "--age-recipient", ValueName: "RECIPIENT"},
+ {Key: FlagSetAgeSshRecipient, Name: "age-ssh-recipient", Flag: true, Spelling: "--age-ssh-recipient", ValueName: "PATH_OR_PUBKEY"},
{Key: FlagSetComplete, Name: "complete", Flag: true, Spelling: "--complete"},
- {Key: FlagSetFile, Name: "file", Flag: true, Spelling: "--file"},
+ {Key: FlagSetFile, Name: "file", Flag: true, Spelling: "--file", ValueName: "FILE"},
{Key: FlagSetNoRedact, Name: "no-redact", Flag: true, Spelling: "--no-redact"},
{Key: FlagSetPrompt, Name: "prompt", Flag: true, Spelling: "--prompt"},
- {Key: FlagSetRemove, Name: "remove", Flag: true, Spelling: "--remove"},
+ {Key: FlagSetRemove, Name: "remove", Flag: true, Spelling: "--remove", ValueName: "ENV_KEY"},
{Key: FlagSetStdin, Name: "stdin", Flag: true, Spelling: "--stdin"},
{Key: ArgSetEnvVar, Name: "ENV_VAR"},
{},
@@ -4556,7 +4556,7 @@ var Meta = argv.Metadata{
{Key: FlagSettingsUnsetLocal, Name: "local", Flag: true, Spelling: "--local"},
{Key: ArgSettingsUnsetKey, Name: "KEY", Required: true},
{},
- {Key: FlagShellJobs, Name: "jobs", Flag: true, Spelling: "--jobs"},
+ {Key: FlagShellJobs, Name: "jobs", Flag: true, Spelling: "--jobs", ValueName: "JOBS"},
{Key: FlagShellUnset, Name: "unset", Flag: true, Spelling: "--unset"},
{Key: FlagShellRaw, Name: "raw", Flag: true, Spelling: "--raw"},
{Key: ArgShellToolVersion, Name: "TOOL@VERSION", Required: true},
@@ -4592,25 +4592,25 @@ var Meta = argv.Metadata{
{Key: FlagTasksHidden, Name: "hidden", Flag: true, Spelling: "--hidden"},
{Key: FlagTasksNameOnly, Name: "name-only", Flag: true, Spelling: "--name-only"},
{Key: FlagTasksNoHeader, Name: "no-header", Flag: true, Spelling: "--no-header"},
- {Key: FlagTasksSort, Name: "sort", Flag: true, Spelling: "--sort", Choices: []string{"name", "alias", "description", "source"}},
- {Key: FlagTasksSortOrder, Name: "sort-order", Flag: true, Spelling: "--sort-order", Choices: []string{"asc", "desc"}},
+ {Key: FlagTasksSort, Name: "sort", Flag: true, Spelling: "--sort", ValueName: "COLUMN", Choices: []string{"name", "alias", "description", "source"}},
+ {Key: FlagTasksSortOrder, Name: "sort-order", Flag: true, Spelling: "--sort-order", ValueName: "SORT_ORDER", Choices: []string{"asc", "desc"}},
{Key: FlagTasksUsage, Name: "usage", Flag: true, Spelling: "--usage"},
{Key: ArgTasksTask, Name: "TASK"},
{},
- {Key: FlagTasksAddAlias, Name: "alias", Flag: true, Spelling: "--alias"},
- {Key: FlagTasksAddDepends, Name: "depends", Flag: true, Spelling: "--depends"},
- {Key: FlagTasksAddDir, Name: "dir", Flag: true, Spelling: "--dir"},
+ {Key: FlagTasksAddAlias, Name: "alias", Flag: true, Spelling: "--alias", ValueName: "ALIAS"},
+ {Key: FlagTasksAddDepends, Name: "depends", Flag: true, Spelling: "--depends", ValueName: "DEPENDS"},
+ {Key: FlagTasksAddDir, Name: "dir", Flag: true, Spelling: "--dir", ValueName: "DIR"},
{Key: FlagTasksAddFile, Name: "file", Flag: true, Spelling: "--file"},
{Key: FlagTasksAddHide, Name: "hide", Flag: true, Spelling: "--hide"},
{Key: FlagTasksAddQuiet, Name: "quiet", Flag: true, Spelling: "--quiet"},
{Key: FlagTasksAddRaw, Name: "raw", Flag: true, Spelling: "--raw"},
- {Key: FlagTasksAddSources, Name: "sources", Flag: true, Spelling: "--sources"},
- {Key: FlagTasksAddWaitFor, Name: "wait-for", Flag: true, Spelling: "--wait-for"},
- {Key: FlagTasksAddDependsPost, Name: "depends-post", Flag: true, Spelling: "--depends-post"},
- {Key: FlagTasksAddDescription, Name: "description", Flag: true, Spelling: "--description"},
- {Key: FlagTasksAddOutputs, Name: "outputs", Flag: true, Spelling: "--outputs"},
- {Key: FlagTasksAddRunWindows, Name: "run-windows", Flag: true, Spelling: "--run-windows"},
- {Key: FlagTasksAddShell, Name: "shell", Flag: true, Spelling: "--shell"},
+ {Key: FlagTasksAddSources, Name: "sources", Flag: true, Spelling: "--sources", ValueName: "SOURCES"},
+ {Key: FlagTasksAddWaitFor, Name: "wait-for", Flag: true, Spelling: "--wait-for", ValueName: "WAIT_FOR"},
+ {Key: FlagTasksAddDependsPost, Name: "depends-post", Flag: true, Spelling: "--depends-post", ValueName: "DEPENDS_POST"},
+ {Key: FlagTasksAddDescription, Name: "description", Flag: true, Spelling: "--description", ValueName: "DESCRIPTION"},
+ {Key: FlagTasksAddOutputs, Name: "outputs", Flag: true, Spelling: "--outputs", ValueName: "OUTPUTS"},
+ {Key: FlagTasksAddRunWindows, Name: "run-windows", Flag: true, Spelling: "--run-windows", ValueName: "RUN_WINDOWS"},
+ {Key: FlagTasksAddShell, Name: "shell", Flag: true, Spelling: "--shell", ValueName: "SHELL"},
{Key: FlagTasksAddSilent, Name: "silent", Flag: true, Spelling: "--silent"},
{Key: ArgTasksAddTask, Name: "TASK", Required: true},
{Key: ArgTasksAddRun, Name: "RUN"},
@@ -4639,30 +4639,30 @@ var Meta = argv.Metadata{
{Key: FlagTasksLsHidden, Name: "hidden", Flag: true, Spelling: "--hidden"},
{Key: FlagTasksLsNameOnly, Name: "name-only", Flag: true, Spelling: "--name-only"},
{Key: FlagTasksLsNoHeader, Name: "no-header", Flag: true, Spelling: "--no-header"},
- {Key: FlagTasksLsSort, Name: "sort", Flag: true, Spelling: "--sort", Choices: []string{"name", "alias", "description", "source"}},
- {Key: FlagTasksLsSortOrder, Name: "sort-order", Flag: true, Spelling: "--sort-order", Choices: []string{"asc", "desc"}},
+ {Key: FlagTasksLsSort, Name: "sort", Flag: true, Spelling: "--sort", ValueName: "COLUMN", Choices: []string{"name", "alias", "description", "source"}},
+ {Key: FlagTasksLsSortOrder, Name: "sort-order", Flag: true, Spelling: "--sort-order", ValueName: "SORT_ORDER", Choices: []string{"asc", "desc"}},
{Key: FlagTasksLsUsage, Name: "usage", Flag: true, Spelling: "--usage"},
{},
{Key: FlagTasksRunAffected, Name: "affected", Flag: true, Spelling: "--affected"},
- {Key: FlagTasksRunAffectedBase, Name: "affected-base", Flag: true, Spelling: "--affected-base"},
+ {Key: FlagTasksRunAffectedBase, Name: "affected-base", Flag: true, Spelling: "--affected-base", ValueName: "REV"},
{Key: FlagTasksRunAffectedExplain, Name: "affected-explain", Flag: true, Spelling: "--affected-explain"},
- {Key: FlagTasksRunAffectedHead, Name: "affected-head", Flag: true, Spelling: "--affected-head"},
+ {Key: FlagTasksRunAffectedHead, Name: "affected-head", Flag: true, Spelling: "--affected-head", ValueName: "REV"},
{Key: FlagTasksRunAffectedJson, Name: "affected-json", Flag: true, Spelling: "--affected-json"},
{Key: FlagTasksRunContinueOnError, Name: "continue-on-error", Flag: true, Spelling: "--continue-on-error"},
- {Key: FlagTasksRunCd, Name: "cd", Flag: true, Spelling: "--cd"},
+ {Key: FlagTasksRunCd, Name: "cd", Flag: true, Spelling: "--cd", ValueName: "CD"},
{Key: FlagTasksRunForce, Name: "force", Flag: true, Spelling: "--force"},
- {Key: FlagTasksRunJobs, Name: "jobs", Flag: true, Spelling: "--jobs"},
+ {Key: FlagTasksRunJobs, Name: "jobs", Flag: true, Spelling: "--jobs", ValueName: "JOBS"},
{Key: FlagTasksRunDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
- {Key: FlagTasksRunOutput, Name: "output", Flag: true, Spelling: "--output"},
+ {Key: FlagTasksRunOutput, Name: "output", Flag: true, Spelling: "--output", ValueName: "OUTPUT"},
{Key: FlagTasksRunQuiet, Name: "quiet", Flag: true, Spelling: "--quiet"},
{Key: FlagTasksRunRaw, Name: "raw", Flag: true, Spelling: "--raw"},
- {Key: FlagTasksRunShell, Name: "shell", Flag: true, Spelling: "--shell"},
+ {Key: FlagTasksRunShell, Name: "shell", Flag: true, Spelling: "--shell", ValueName: "SHELL"},
{Key: FlagTasksRunSilent, Name: "silent", Flag: true, Spelling: "--silent"},
- {Key: FlagTasksRunTool, Name: "tool", Flag: true, Spelling: "--tool"},
- {Key: FlagTasksRunAllowEnv, Name: "allow-env", Flag: true, Spelling: "--allow-env"},
- {Key: FlagTasksRunAllowNet, Name: "allow-net", Flag: true, Spelling: "--allow-net"},
- {Key: FlagTasksRunAllowRead, Name: "allow-read", Flag: true, Spelling: "--allow-read"},
- {Key: FlagTasksRunAllowWrite, Name: "allow-write", Flag: true, Spelling: "--allow-write"},
+ {Key: FlagTasksRunTool, Name: "tool", Flag: true, Spelling: "--tool", ValueName: "TOOL@VERSION"},
+ {Key: FlagTasksRunAllowEnv, Name: "allow-env", Flag: true, Spelling: "--allow-env", ValueName: "VAR"},
+ {Key: FlagTasksRunAllowNet, Name: "allow-net", Flag: true, Spelling: "--allow-net", ValueName: "HOST"},
+ {Key: FlagTasksRunAllowRead, Name: "allow-read", Flag: true, Spelling: "--allow-read", ValueName: "PATH"},
+ {Key: FlagTasksRunAllowWrite, Name: "allow-write", Flag: true, Spelling: "--allow-write", ValueName: "PATH"},
{Key: FlagTasksRunDenyAll, Name: "deny-all", Flag: true, Spelling: "--deny-all"},
{Key: FlagTasksRunDenyEnv, Name: "deny-env", Flag: true, Spelling: "--deny-env"},
{Key: FlagTasksRunDenyNet, Name: "deny-net", Flag: true, Spelling: "--deny-net"},
@@ -4674,11 +4674,11 @@ var Meta = argv.Metadata{
{Key: FlagTasksRunNoTimings, Name: "no-timings", Flag: true, Spelling: "--no-timings"},
{Key: FlagTasksRunSkipDeps, Name: "skip-deps", Flag: true, Spelling: "--skip-deps"},
{Key: FlagTasksRunSkipTools, Name: "skip-tools", Flag: true, Spelling: "--skip-tools"},
- {Key: FlagTasksRunTaskCache, Name: "task-cache", Flag: true, Spelling: "--task-cache", Choices: []string{"read-write", "read-only", "write-only", "off", "local-only"}, Default: []string{"read-write"}},
+ {Key: FlagTasksRunTaskCache, Name: "task-cache", Flag: true, Spelling: "--task-cache", ValueName: "TASK_CACHE", Choices: []string{"read-write", "read-only", "write-only", "off", "local-only"}, Default: []string{"read-write"}},
{Key: FlagTasksRunTaskCacheExplain, Name: "task-cache-explain", Flag: true, Spelling: "--task-cache-explain"},
{Key: FlagTasksRunTaskCacheExplainJson, Name: "task-cache-explain-json", Flag: true, Spelling: "--task-cache-explain-json"},
{Key: FlagTasksRunTaskCacheStats, Name: "task-cache-stats", Flag: true, Spelling: "--task-cache-stats"},
- {Key: FlagTasksRunTimeout, Name: "timeout", Flag: true, Spelling: "--timeout"},
+ {Key: FlagTasksRunTimeout, Name: "timeout", Flag: true, Spelling: "--timeout", ValueName: "TIMEOUT"},
{Key: FlagTasksRunTimings, Name: "timings", Flag: true, Spelling: "--timings"},
{Key: ArgTasksRunTask, Name: "TASK", Default: []string{"default"}},
{Key: ArgTasksRunArgs, Name: "ARGS"},
@@ -4689,7 +4689,7 @@ var Meta = argv.Metadata{
{Key: ArgTasksValidateTasks, Name: "TASKS"},
{},
{Key: FlagTestToolAll, Name: "all", Flag: true, Spelling: "--all"},
- {Key: FlagTestToolJobs, Name: "jobs", Flag: true, Spelling: "--jobs"},
+ {Key: FlagTestToolJobs, Name: "jobs", Flag: true, Spelling: "--jobs", ValueName: "JOBS"},
{Key: FlagTestToolAllConfig, Name: "all-config", Flag: true, Spelling: "--all-config"},
{Key: FlagTestToolIncludeNonDefined, Name: "include-non-defined", Flag: true, Spelling: "--include-non-defined"},
{Key: FlagTestToolRaw, Name: "raw", Flag: true, Spelling: "--raw"},
@@ -4725,70 +4725,70 @@ var Meta = argv.Metadata{
{Key: FlagTrustIgnore, Name: "ignore", Flag: true, Spelling: "--ignore"},
{Key: FlagTrustShow, Name: "show", Flag: true, Spelling: "--show"},
{Key: FlagTrustUntrust, Name: "untrust", Flag: true, Spelling: "--untrust"},
- {Key: ArgTrustConfigFile, Name: "CONFIG_FILE"},
+ {Key: ArgTrustConfigFile, Name: "CONFIG_FILE", CompleteType: "file"},
{},
{Key: FlagUninstallAll, Name: "all", Flag: true, Spelling: "--all"},
{Key: FlagUninstallDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
{Key: FlagUninstallDryRunCode, Name: "dry-run-code", Flag: true, Spelling: "--dry-run-code"},
{Key: ArgUninstallInstalledToolVersion, Name: "INSTALLED_TOOL@VERSION"},
{},
- {Key: FlagUnsetFile, Name: "file", Flag: true, Spelling: "--file"},
+ {Key: FlagUnsetFile, Name: "file", Flag: true, Spelling: "--file", ValueName: "FILE"},
{Key: FlagUnsetGlobal, Name: "global", Flag: true, Spelling: "--global"},
{Key: ArgUnsetEnvKey, Name: "ENV_KEY"},
{},
- {Key: ArgUntrustConfigFile, Name: "CONFIG_FILE"},
+ {Key: ArgUntrustConfigFile, Name: "CONFIG_FILE", CompleteType: "file"},
{},
- {Key: FlagUnuseEnv, Name: "env", Flag: true, Spelling: "--env"},
+ {Key: FlagUnuseEnv, Name: "env", Flag: true, Spelling: "--env", ValueName: "ENV"},
{Key: FlagUnuseGlobal, Name: "global", Flag: true, Spelling: "--global"},
- {Key: FlagUnusePath, Name: "path", Flag: true, Spelling: "--path"},
+ {Key: FlagUnusePath, Name: "path", Flag: true, Spelling: "--path", ValueName: "PATH"},
{Key: FlagUnuseNoPrune, Name: "no-prune", Flag: true, Spelling: "--no-prune"},
{Key: ArgUnuseInstalledToolVersion, Name: "INSTALLED_TOOL@VERSION", Required: true},
{},
{Key: FlagUpgradeInteractive, Name: "interactive", Flag: true, Spelling: "--interactive"},
- {Key: FlagUpgradeJobs, Name: "jobs", Flag: true, Spelling: "--jobs"},
+ {Key: FlagUpgradeJobs, Name: "jobs", Flag: true, Spelling: "--jobs", ValueName: "JOBS"},
{Key: FlagUpgradeBump, Name: "bump", Flag: true, Spelling: "--bump"},
{Key: FlagUpgradeDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
- {Key: FlagUpgradeExclude, Name: "exclude", Flag: true, Spelling: "--exclude"},
+ {Key: FlagUpgradeExclude, Name: "exclude", Flag: true, Spelling: "--exclude", ValueName: "INSTALLED_TOOL"},
{Key: FlagUpgradeDryRunCode, Name: "dry-run-code", Flag: true, Spelling: "--dry-run-code"},
{Key: FlagUpgradeInactive, Name: "inactive", Flag: true, Spelling: "--inactive"},
{Key: FlagUpgradeLocal, Name: "local", Flag: true, Spelling: "--local"},
- {Key: FlagUpgradeMinimumReleaseAge, Name: "minimum-release-age", Flag: true, Spelling: "--minimum-release-age"},
+ {Key: FlagUpgradeMinimumReleaseAge, Name: "minimum-release-age", Flag: true, Spelling: "--minimum-release-age", ValueName: "MINIMUM_RELEASE_AGE"},
{Key: FlagUpgradeMonorepo, Name: "monorepo", Flag: true, Spelling: "--monorepo"},
{Key: FlagUpgradeNoPrune, Name: "no-prune", Flag: true, Spelling: "--no-prune"},
{Key: FlagUpgradeRaw, Name: "raw", Flag: true, Spelling: "--raw"},
{Key: ArgUpgradeInstalledToolVersion, Name: "INSTALLED_TOOL@VERSION"},
{},
{},
- {Key: FlagUseEnv, Name: "env", Flag: true, Spelling: "--env"},
+ {Key: FlagUseEnv, Name: "env", Flag: true, Spelling: "--env", ValueName: "ENV"},
{Key: FlagUseForce, Name: "force", Flag: true, Spelling: "--force"},
{Key: FlagUseGlobal, Name: "global", Flag: true, Spelling: "--global"},
- {Key: FlagUseJobs, Name: "jobs", Flag: true, Spelling: "--jobs"},
+ {Key: FlagUseJobs, Name: "jobs", Flag: true, Spelling: "--jobs", ValueName: "JOBS"},
{Key: FlagUseDryRun, Name: "dry-run", Flag: true, Spelling: "--dry-run"},
- {Key: FlagUsePath, Name: "path", Flag: true, Spelling: "--path"},
+ {Key: FlagUsePath, Name: "path", Flag: true, Spelling: "--path", ValueName: "PATH"},
{Key: FlagUseDryRunCode, Name: "dry-run-code", Flag: true, Spelling: "--dry-run-code"},
{Key: FlagUseFuzzy, Name: "fuzzy", Flag: true, Spelling: "--fuzzy"},
- {Key: FlagUseMinimumReleaseAge, Name: "minimum-release-age", Flag: true, Spelling: "--minimum-release-age"},
+ {Key: FlagUseMinimumReleaseAge, Name: "minimum-release-age", Flag: true, Spelling: "--minimum-release-age", ValueName: "MINIMUM_RELEASE_AGE"},
{Key: FlagUsePin, Name: "pin", Flag: true, Spelling: "--pin"},
{Key: FlagUseRaw, Name: "raw", Flag: true, Spelling: "--raw"},
- {Key: FlagUseRemove, Name: "remove", Flag: true, Spelling: "--remove"},
+ {Key: FlagUseRemove, Name: "remove", Flag: true, Spelling: "--remove", ValueName: "TOOL"},
{Key: ArgUseToolVersion, Name: "TOOL@VERSION"},
{},
{Key: FlagVersionJson, Name: "json", Flag: true, Spelling: "--json"},
{},
- {Key: FlagWatchTaskFlag, Name: "task-flag", Flag: true, Spelling: "--task-flag"},
- {Key: FlagWatchGlob, Name: "glob", Flag: true, Spelling: "--glob"},
+ {Key: FlagWatchTaskFlag, Name: "task-flag", Flag: true, Spelling: "--task-flag", ValueName: "TASK_FLAG"},
+ {Key: FlagWatchGlob, Name: "glob", Flag: true, Spelling: "--glob", ValueName: "GLOB"},
{Key: FlagWatchSkipDeps, Name: "skip-deps", Flag: true, Spelling: "--skip-deps"},
- {Key: FlagWatchWatch, Name: "watch", Flag: true, Spelling: "--watch"},
- {Key: FlagWatchWatchNonRecursive, Name: "watch-non-recursive", Flag: true, Spelling: "--watch-non-recursive"},
- {Key: FlagWatchWatchFile, Name: "watch-file", Flag: true, Spelling: "--watch-file"},
- {Key: FlagWatchClear, Name: "clear", Flag: true, Spelling: "--clear", Choices: []string{"clear", "reset"}},
- {Key: FlagWatchOnBusyUpdate, Name: "on-busy-update", Flag: true, Spelling: "--on-busy-update", Choices: []string{"queue", "do-nothing", "restart", "signal"}, Default: []string{"do-nothing"}},
+ {Key: FlagWatchWatch, Name: "watch", Flag: true, Spelling: "--watch", ValueName: "PATH"},
+ {Key: FlagWatchWatchNonRecursive, Name: "watch-non-recursive", Flag: true, Spelling: "--watch-non-recursive", ValueName: "PATH"},
+ {Key: FlagWatchWatchFile, Name: "watch-file", Flag: true, Spelling: "--watch-file", ValueName: "PATH"},
+ {Key: FlagWatchClear, Name: "clear", Flag: true, Spelling: "--clear", ValueName: "MODE", Choices: []string{"clear", "reset"}},
+ {Key: FlagWatchOnBusyUpdate, Name: "on-busy-update", Flag: true, Spelling: "--on-busy-update", ValueName: "MODE", Choices: []string{"queue", "do-nothing", "restart", "signal"}, Default: []string{"do-nothing"}},
{Key: FlagWatchRestart, Name: "restart", Flag: true, Spelling: "--restart"},
- {Key: FlagWatchSignal, Name: "signal", Flag: true, Spelling: "--signal"},
- {Key: FlagWatchStopSignal, Name: "stop-signal", Flag: true, Spelling: "--stop-signal"},
- {Key: FlagWatchStopTimeout, Name: "stop-timeout", Flag: true, Spelling: "--stop-timeout", Default: []string{"10s"}},
- {Key: FlagWatchMapSignal, Name: "map-signal", Flag: true, Spelling: "--map-signal"},
- {Key: FlagWatchDebounce, Name: "debounce", Flag: true, Spelling: "--debounce", Default: []string{"50ms"}},
+ {Key: FlagWatchSignal, Name: "signal", Flag: true, Spelling: "--signal", ValueName: "SIGNAL"},
+ {Key: FlagWatchStopSignal, Name: "stop-signal", Flag: true, Spelling: "--stop-signal", ValueName: "SIGNAL"},
+ {Key: FlagWatchStopTimeout, Name: "stop-timeout", Flag: true, Spelling: "--stop-timeout", ValueName: "TIMEOUT", Default: []string{"10s"}},
+ {Key: FlagWatchMapSignal, Name: "map-signal", Flag: true, Spelling: "--map-signal", ValueName: "SIGNAL:SIGNAL"},
+ {Key: FlagWatchDebounce, Name: "debounce", Flag: true, Spelling: "--debounce", ValueName: "TIMEOUT", Default: []string{"50ms"}},
{Key: FlagWatchStdinQuit, Name: "stdin-quit", Flag: true, Spelling: "--stdin-quit"},
{Key: FlagWatchNoVcsIgnore, Name: "no-vcs-ignore", Flag: true, Spelling: "--no-vcs-ignore"},
{Key: FlagWatchNoProjectIgnore, Name: "no-project-ignore", Flag: true, Spelling: "--no-project-ignore"},
@@ -4797,28 +4797,28 @@ var Meta = argv.Metadata{
{Key: FlagWatchNoDiscoverIgnore, Name: "no-discover-ignore", Flag: true, Spelling: "--no-discover-ignore"},
{Key: FlagWatchIgnoreNothing, Name: "ignore-nothing", Flag: true, Spelling: "--ignore-nothing"},
{Key: FlagWatchPostpone, Name: "postpone", Flag: true, Spelling: "--postpone"},
- {Key: FlagWatchDelayRun, Name: "delay-run", Flag: true, Spelling: "--delay-run"},
- {Key: FlagWatchPoll, Name: "poll", Flag: true, Spelling: "--poll"},
- {Key: FlagWatchShell, Name: "shell", Flag: true, Spelling: "--shell"},
+ {Key: FlagWatchDelayRun, Name: "delay-run", Flag: true, Spelling: "--delay-run", ValueName: "DURATION"},
+ {Key: FlagWatchPoll, Name: "poll", Flag: true, Spelling: "--poll", ValueName: "INTERVAL"},
+ {Key: FlagWatchShell, Name: "shell", Flag: true, Spelling: "--shell", ValueName: "SHELL"},
{Key: FlagWatchN, Name: "n", Flag: true, Spelling: "-n"},
- {Key: FlagWatchEmitEventsTo, Name: "emit-events-to", Flag: true, Spelling: "--emit-events-to", Choices: []string{"environment", "stdio", "file", "json-stdio", "json-file", "none"}, Default: []string{"none"}},
+ {Key: FlagWatchEmitEventsTo, Name: "emit-events-to", Flag: true, Spelling: "--emit-events-to", ValueName: "MODE", Choices: []string{"environment", "stdio", "file", "json-stdio", "json-file", "none"}, Default: []string{"none"}},
{Key: FlagWatchOnlyEmitEvents, Name: "only-emit-events", Flag: true, Spelling: "--only-emit-events"},
- {Key: FlagWatchEnv, Name: "env", Flag: true, Spelling: "--env"},
- {Key: FlagWatchWrapProcess, Name: "wrap-process", Flag: true, Spelling: "--wrap-process", Choices: []string{"group", "session", "none"}},
+ {Key: FlagWatchEnv, Name: "env", Flag: true, Spelling: "--env", ValueName: "KEY=VALUE"},
+ {Key: FlagWatchWrapProcess, Name: "wrap-process", Flag: true, Spelling: "--wrap-process", ValueName: "MODE", Choices: []string{"group", "session", "none"}},
{Key: FlagWatchNotify, Name: "notify", Flag: true, Spelling: "--notify"},
- {Key: FlagWatchColor, Name: "color", Flag: true, Spelling: "--color", Choices: []string{"auto", "always", "never"}, Default: []string{"auto"}},
+ {Key: FlagWatchColor, Name: "color", Flag: true, Spelling: "--color", ValueName: "MODE", Choices: []string{"auto", "always", "never"}, Default: []string{"auto"}},
{Key: FlagWatchTimings, Name: "timings", Flag: true, Spelling: "--timings"},
{Key: FlagWatchQuiet, Name: "quiet", Flag: true, Spelling: "--quiet"},
{Key: FlagWatchBell, Name: "bell", Flag: true, Spelling: "--bell"},
- {Key: FlagWatchProjectOrigin, Name: "project-origin", Flag: true, Spelling: "--project-origin"},
- {Key: FlagWatchWorkdir, Name: "workdir", Flag: true, Spelling: "--workdir"},
- {Key: FlagWatchExts, Name: "exts", Flag: true, Spelling: "--exts"},
- {Key: FlagWatchFilter, Name: "filter", Flag: true, Spelling: "--filter"},
- {Key: FlagWatchFilterFile, Name: "filter-file", Flag: true, Spelling: "--filter-file"},
- {Key: FlagWatchFilterProg, Name: "filter-prog", Flag: true, Spelling: "--filter-prog"},
- {Key: FlagWatchIgnore, Name: "ignore", Flag: true, Spelling: "--ignore"},
- {Key: FlagWatchIgnoreFile, Name: "ignore-file", Flag: true, Spelling: "--ignore-file"},
- {Key: FlagWatchFsEvents, Name: "fs-events", Flag: true, Spelling: "--fs-events", Choices: []string{"access", "create", "remove", "rename", "modify", "metadata"}, Default: []string{"create", "remove", "rename", "modify", "metadata"}},
+ {Key: FlagWatchProjectOrigin, Name: "project-origin", Flag: true, Spelling: "--project-origin", ValueName: "DIRECTORY"},
+ {Key: FlagWatchWorkdir, Name: "workdir", Flag: true, Spelling: "--workdir", ValueName: "DIRECTORY"},
+ {Key: FlagWatchExts, Name: "exts", Flag: true, Spelling: "--exts", ValueName: "EXTENSIONS"},
+ {Key: FlagWatchFilter, Name: "filter", Flag: true, Spelling: "--filter", ValueName: "PATTERN"},
+ {Key: FlagWatchFilterFile, Name: "filter-file", Flag: true, Spelling: "--filter-file", ValueName: "PATH"},
+ {Key: FlagWatchFilterProg, Name: "filter-prog", Flag: true, Spelling: "--filter-prog", ValueName: "EXPRESSION"},
+ {Key: FlagWatchIgnore, Name: "ignore", Flag: true, Spelling: "--ignore", ValueName: "PATTERN"},
+ {Key: FlagWatchIgnoreFile, Name: "ignore-file", Flag: true, Spelling: "--ignore-file", ValueName: "PATH"},
+ {Key: FlagWatchFsEvents, Name: "fs-events", Flag: true, Spelling: "--fs-events", ValueName: "EVENTS", Choices: []string{"access", "create", "remove", "rename", "modify", "metadata"}, Default: []string{"create", "remove", "rename", "modify", "metadata"}},
{Key: FlagWatchNoMeta, Name: "no-meta", Flag: true, Spelling: "--no-meta"},
{Key: FlagWatchPrintEvents, Name: "print-events", Flag: true, Spelling: "--print-events"},
{Key: FlagWatchManual, Name: "manual", Flag: true, Spelling: "--manual"},
@@ -4828,7 +4828,7 @@ var Meta = argv.Metadata{
{Key: ArgWhereToolVersion, Name: "TOOL@VERSION", Required: true},
{Key: ArgWhereAsdfVersion, Name: "ASDF_VERSION"},
{},
- {Key: FlagWhichTool, Name: "tool", Flag: true, Spelling: "--tool"},
+ {Key: FlagWhichTool, Name: "tool", Flag: true, Spelling: "--tool", ValueName: "TOOL@VERSION"},
{Key: FlagWhichComplete, Name: "complete", Flag: true, Spelling: "--complete"},
{Key: FlagWhichPlugin, Name: "plugin", Flag: true, Spelling: "--plugin"},
{Key: FlagWhichVersion, Name: "version", Flag: true, Spelling: "--version"},
diff --git a/go/internal/spec/spec.go b/go/internal/spec/spec.go
index c8b3adc9a..3160d508c 100644
--- a/go/internal/spec/spec.go
+++ b/go/internal/spec/spec.go
@@ -41,11 +41,15 @@ type Spec struct {
Version string `json:"version"`
About string `json:"about"`
AboutLong string `json:"about_long"`
- BeforeHelp string `json:"before_help"`
- AfterHelp string `json:"after_help"`
- BeforeHelpLong string `json:"before_help_long"`
- AfterHelpLong string `json:"after_help_long"`
- Usage string `json:"usage"`
+ // Complete is the completers a spec declares, keyed by the lowercased name of
+ // the argument or flag value they belong to — which is how usage-lib keys
+ // them, and how a lookup has to be spelled.
+ Complete map[string]Completer `json:"complete"`
+ BeforeHelp string `json:"before_help"`
+ AfterHelp string `json:"after_help"`
+ BeforeHelpLong string `json:"before_help_long"`
+ AfterHelpLong string `json:"after_help_long"`
+ Usage string `json:"usage"`
}
// HelpSpec is what a page needs from the spec's root rather than from a command.
@@ -63,6 +67,14 @@ func (s *Spec) HelpSpec() argv.HelpSpec {
}
}
+// Completer is one `complete` block. Only the type is read here: running the
+// `run=` script is a completion's job at run time, and needs a subprocess this
+// package has no business starting.
+type Completer struct {
+ Name string `json:"name"`
+ Type string `json:"type_"`
+}
+
// Cmd is one command in the lowered spec.
type Cmd struct {
Name string `json:"name"`
@@ -319,7 +331,7 @@ func (s *Spec) Build() (*argv.Command, argv.Metadata) {
// help one. They share the keys that tie them together, so they are built in one
// pass for the same reason the first two were.
func (s *Spec) BuildAll() (*argv.Command, argv.Metadata, argv.HelpTable) {
- b := &builder{}
+ b := &builder{complete: s.Complete}
root := b.command(&s.Cmd, unknownFlags(s.UnknownFlags, argv.UnknownFlagsValue))
// default_subcommand is a property of the spec rather than of a command, so it
@@ -398,6 +410,8 @@ type builder struct {
// it needs the original. A spec declaring `negate="-no-color"` is not named
// by `--no-color`, and usage-lib does not resolve it either.
negation map[uint64]string
+ // complete is the spec's `complete` blocks, keyed as usage-lib keys them.
+ complete map[string]Completer
}
// record files an entry's cold half at the position its key indexes.
@@ -442,6 +456,26 @@ func visibleAliases(c *Cmd) []string {
return out
}
+// valueOf is what a flag's value is called, or empty where the flag takes none.
+func valueOf(f *Flag) string {
+ if f.Arg == nil {
+ return ""
+ }
+ return f.Arg.Name
+}
+
+// completeType is the type the spec's `complete` block names for an entry.
+//
+// By lowercased name, which is how usage-lib files them: `complete "FILE"` and an
+// argument written `` are the same position as far as the reference is
+// concerned.
+func (b *builder) completeType(name string) string {
+ if b.complete == nil || name == "" {
+ return ""
+ }
+ return b.complete[strings.ToLower(name)].Type
+}
+
func first(values ...string) string {
for _, v := range values {
if v != "" {
@@ -672,14 +706,16 @@ func (b *builder) flag(f *Flag) *argv.Flag {
Default: f.defaults(),
})
b.record(out.Key, argv.Meta{
- Name: f.Name,
- Flag: true,
- Spelling: spelling(f),
- Required: f.Required,
- Choices: f.choices(),
- Default: f.defaults(),
- Env: f.Env,
- VarMin: clampVarMax(f.VarMin),
+ Name: f.Name,
+ Flag: true,
+ Spelling: spelling(f),
+ ValueName: valueOf(f),
+ CompleteType: b.completeType(first(valueOf(f), f.Name)),
+ Required: f.Required,
+ Choices: f.choices(),
+ Default: f.defaults(),
+ Env: f.Env,
+ VarMin: clampVarMax(f.VarMin),
// Occurrences. The per-occurrence value bound is a limit binding applies,
// and is set on the parse table below rather than here.
VarMax: clampVarMax(f.VarMax),
@@ -719,12 +755,13 @@ func (b *builder) arg(a *Arg) *argv.Arg {
Default: a.Default,
})
b.record(out.Key, argv.Meta{
- Name: a.Name,
- Required: a.Required,
- Choices: a.Choices.list(),
- Default: a.Default,
- Env: a.Env,
- VarMin: clampVarMax(a.VarMin),
+ Name: a.Name,
+ Required: a.Required,
+ CompleteType: b.completeType(a.Name),
+ Choices: a.Choices.list(),
+ Default: a.Default,
+ Env: a.Env,
+ VarMin: clampVarMax(a.VarMin),
// No VarMax: for an argument the bound is a limit binding applies, which
// is what makes `[a]… [b]` fillable at all, so judging it again here would
// fail an invocation that never broke it.
diff --git a/lib/src/go/mod.rs b/lib/src/go/mod.rs
index 3d11b3169..35dd785fe 100644
--- a/lib/src/go/mod.rs
+++ b/lib/src/go/mod.rs
@@ -408,7 +408,7 @@ impl Emitter<'_> {
by_key.insert(named.number, self.flag_meta(flag, named, e, commands));
}
for (arg, named) in &e.args {
- by_key.insert(named.number, arg_meta(arg, named));
+ by_key.insert(named.number, arg_meta(self.spec, arg, named));
}
}
@@ -465,6 +465,19 @@ impl Emitter<'_> {
} else if let Some(short) = flag.short.first() {
fields.push(format!("Spelling: {}", go_string(&format!("-{short}"))));
}
+ // What the value is called, which is what says whether a path belongs
+ // there — `--into ` completes directories because of the name.
+ if let Some(value) = flag.arg.as_ref() {
+ fields.push(format!("ValueName: {}", go_string(&value.name)));
+ }
+ let named_value = flag
+ .arg
+ .as_ref()
+ .map(|a| a.name.as_str())
+ .unwrap_or(flag.name.as_str());
+ if let Some(kind) = complete_type(self.spec, named_value) {
+ fields.push(format!("CompleteType: {}", go_string(kind)));
+ }
// Written on the value a flag takes, never on the flag.
if let Some(choices) = flag.arg.as_ref().and_then(|a| a.choices.as_ref()) {
fields.push(format!("Choices: {}", string_slice(&choices.choices)));
@@ -512,7 +525,18 @@ impl Emitter<'_> {
}
/// The cold half of a positional argument.
-fn arg_meta(arg: &SpecArg, named: &Named) -> String {
+/// The type a spec's `complete` block names for an entry, if it names one.
+///
+/// By lowercased name, which is how usage-lib files them: `complete "FILE"` and
+/// an argument written `` are the same position as far as the reference is
+/// concerned.
+fn complete_type<'a>(spec: &'a Spec, name: &str) -> Option<&'a str> {
+ spec.complete
+ .get(&name.to_lowercase())
+ .and_then(|c| c.type_.as_deref())
+}
+
+fn arg_meta(spec: &Spec, arg: &SpecArg, named: &Named) -> String {
let mut fields = vec![
format!("Key: {}", named.key),
format!("Name: {}", go_string(&arg.name)),
@@ -520,6 +544,13 @@ fn arg_meta(arg: &SpecArg, named: &Named) -> String {
if arg.required {
fields.push("Required: true".to_string());
}
+ // What the position takes, where the spec said so. Read by completion rather
+ // than by any post-binding rule: an author who wrote `complete "input"
+ // type="file"` named what belongs there, and the alternative is inferring it
+ // from a name they did not choose.
+ if let Some(kind) = complete_type(spec, &arg.name) {
+ fields.push(format!("CompleteType: {}", go_string(kind)));
+ }
if let Some(choices) = &arg.choices {
fields.push(format!("Choices: {}", string_slice(&choices.choices)));
}
diff --git a/lib/src/go/snapshots/usage__go__tests__a_whole_cli.snap b/lib/src/go/snapshots/usage__go__tests__a_whole_cli.snap
index 7865e9bcc..4e944f28f 100644
--- a/lib/src/go/snapshots/usage__go__tests__a_whole_cli.snap
+++ b/lib/src/go/snapshots/usage__go__tests__a_whole_cli.snap
@@ -95,8 +95,8 @@ var Meta = argv.Metadata{
{},
{Key: FlagVerbose, Name: "verbose", Flag: true, Spelling: "--verbose"},
{Key: FlagColor, Name: "color", Flag: true, Spelling: "--color"},
- {Key: FlagJobs, Name: "jobs", Flag: true, Spelling: "--jobs"},
- {Key: FlagInclude, Name: "include", Flag: true, Spelling: "--include", VarMax: 3},
+ {Key: FlagJobs, Name: "jobs", Flag: true, Spelling: "--jobs", ValueName: "n"},
+ {Key: FlagInclude, Name: "include", Flag: true, Spelling: "--include", ValueName: "pattern", VarMax: 3},
{Key: ArgFile, Name: "file", Required: true},
{Key: ArgRest, Name: "rest"},
{},