Repository navigation
fix: offer ancestors' persistent flags in the fish completion script - #2506
Conversation
…cript ToFishCompletion only offered a command's own flags, so after a subcommand fish never suggested a root flag such as --config, although the subcommand accepts it and its help lists it under GLOBAL OPTIONS. Add the command's visible persistent flags, as the dynamic completion does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d2fe51c to
7b83486
Compare
Juneezee
left a comment
There was a problem hiding this comment.
Thanks! This fixes it: on main, complete -C 'app deploy --' lists --dry-run --help, and with this PR it lists --config --dry-run --help --verbose, the same as the dynamic script.
One case is missing. The dynamic completion leaves out the persistent flags when the command has SkipFlagParsing, because that command takes them as plain arguments:
Lines 320 to 327 in d854bb4
The fish script now offers them there:
Lines 120 to 128 in 7b83486
To reproduce, add this subcommand to the example in the description:
{Name: "exec", SkipFlagParsing: true, Action: func(ctx context.Context, cmd *cli.Command) error {
fmt.Printf("args=%q verbose=%t\n", cmd.Args().Slice(), cmd.Bool("verbose"))
return nil
}},complete -C 'app exec --' lists --config --help --verbose, but app exec --verbose x prints args=["--verbose" "x"] verbose=false. The dynamic script lists only --help.
Could you add the same check, with a test? For example:
// a subcommand also accepts the persistent flags of its ancestors, which
// its help lists as global options, unless it skips flag parsing
if !owner.SkipFlagParsing {
for _, fl := range owner.VisiblePersistentFlags() {
if !hasFlag(flags, fl) {
flags = append(flags, fl)
}
}
}and in TestFishCompletionPersistentFlags, add {Name: "exec", SkipFlagParsing: true} to Commands and:
// nor a root flag after a subcommand that skips flag parsing
assert.NotContains(t, res, "__fish_seen_subcommand_from exec' -f -l verbose")With both on top of current main, the full test suite passes and the new assertion fails without the check. The testdata files don't change.
A command with SkipFlagParsing takes those flags as plain arguments. The dynamic completion already leaves them out, and the generated fish script should too. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@Juneezee Thank you. This is done.
|
What type of PR is this?
What this PR does / why we need it:
In v3 a flag is persistent unless it is
Local, so a subcommand accepts its ancestors' flags, and its help lists them under GLOBAL OPTIONS.ToFishCompletiononly offered each command's own flags, and the root's flags only before any subcommand, so after a subcommand fish never suggested them:In fish 4.9.3 with the generated script,
complete -C 'app deploy --'listed--dry-run --help, whileapp deploy --verbose prodruns andapp deploy prod --helpshows--configand--verboseunder GLOBAL OPTIONS. The dynamic completion (app completion fish) already offers them, sinceDefaultCompleteWithFlagsaddsVisiblePersistentFlags.A command with
SkipFlagParsingis the exception. It takes ancestor flags as plain arguments:complete -C 'app exec --'listed--config --help --verbose, butapp exec --verbose xprintsargs=["--verbose" "x"] verbose=false. The dynamic script lists only--helpthere, because it adds persistent flags only when the command does not skip flag parsing.fish.go:prepareFishFlagsnow adds the command'sVisiblePersistentFlags()that it doesn't define itself, the same wayDefaultCompleteWithFlagsdoes, and only whenSkipFlagParsingis false.VisiblePersistentFlagsalready leaves outLocalflags and flags a subcommand redefines.testdata/expected-fish-full.fishandtestdata/expected-help-output.txt: regenerated. Both only gain lines, the persistent flags under each subcommand, and no existing line changes. TheSkipFlagParsingcase does not change them.With this change,
complete -Cgives the same flags with the static script as with the dynamic one at every subcommand level:app deploy --andapp deploy prod --both list--config --dry-run --help --verbose,--local-onlystays at the root, andapp deploy -ccompletes file names.app exec --lists only--help.Which issue(s) this PR fixes:
None, found while comparing the static and dynamic fish scripts.
Testing
TestFishCompletionPersistentFlags: a root flag is offered after a subcommand and a nested subcommand (fails onmain), while aLocalroot flag and a root flag the subcommand redefines are not. A subcommand withSkipFlagParsingdoes not offer a root flag. That assertion fails without the check.go test ./...passes.The change and the test were written with Claude Code (AI).
Release Notes