Visitar URL original
fix: complete subcommands after a flag that needs no value on the root command by vidigoat · Pull Request #2501 · urfave/cli · GitHub
Skip to content

fix: complete subcommands after a flag that needs no value on the root command - #2501

Open
vidigoat wants to merge 1 commit into
urfave:mainfrom
vidigoat:fix/complete-commands-after-finished-flag
Open

vidigoat wants to merge 1 commit into
urfave:mainfrom
vidigoat:fix/complete-commands-after-finished-flag

Conversation

@vidigoat

@vidigoat vidigoat commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

What type of PR is this?

  • bug

What this PR does / why we need it:

The shell scripts send the word under the cursor only when it starts with -, so for app --verbose <TAB> the program gets app --verbose --generate-shell-completion. A subcommand completes its parsed arguments, where --verbose has already been consumed, so app deploy --verbose <TAB> lists deploy's subcommands. The root command completes its raw arguments instead, so its last argument is --verbose, DefaultCompleteWithFlags prints flag suggestions for it, and since printFlagSuggestions skips the flag that was typed in full, it prints nothing. The same thing happens after a value given with =:

app --verbose <TAB>       # nothing (bash falls back to file names, zsh to _files)
app --verbose d<TAB>      # nothing
app --config=x <TAB>      # nothing
app -c x <TAB>            # build deploy help
app deploy --verbose <TAB>  # staging prod help

DefaultCompleteWithFlags now treats the last argument as a complete flag, and lists the subcommands, when it names a flag that takes no value (including a BoolWithInverseFlag's --no- names) or has its value after =, and no longer flag starts with it. So --debug still suggests --debug-level, --format with no value still prints nothing, and partial flags such as --verb work as before. Subcommands do not reach the new branch for a known flag, since their parsed arguments no longer hold it.

This is separate from #2489, which changes where the root command's arguments come from and not how the last one is read. It is rebased on #2489, so the new test passes its arguments to Run instead of setting os.Args.

Which issue(s) this PR fixes:

None, found while testing the generated scripts in bash and fish.

Testing

  • New TestCompletionAfterCompleteRootFlag: a bool flag, an inverse bool flag and --format=json list the subcommands (these three fail on main); --format with no value, --debug next to --debug-level, and a partial --verb keep their current output.
  • Checked in bash 5.3 with bash-completion 2, fish 4.9.3, and the zsh script's function: app --verbose <TAB>, app --verbose d<TAB> and app --config=x <TAB> now complete the subcommands. The other cases are unchanged.
  • make (generate, vet, tests, binary size, gfmrun), make lint and make v3diff pass. go test -race passes, as do the tests with urfave_cli_no_template, urfave_cli_no_docs and urfave_cli_no_suggest.

The change and the test were written with Claude Code (AI).

Release Notes

Shell completion on the root command now lists subcommands after a flag that takes no value or has its value after "=".

🤖 Generated with Claude Code

@vidigoat
vidigoat requested a review from a team as a code owner October 25, 2026 12:10
@vidigoat

Copy link
Copy Markdown
Contributor Author

The ubuntu-24.04 @ Go stable failure is make check-binary-size (the Windows jobs were cancelled after it): the CLI's share of the example binary comes out at 2.3MB against the 2.2MB max.

The change adds about 1.2KB (704 bytes of text and 527 of pclntab, measured with Go 1.27.3 for linux/amd64), but main is already close to the limit: it reports 2.2MB, and the check rounds to one decimal, so anything that crosses the next 4KB page reports 2.3MB. A version without the buffer lands on the same page, so I don't think trimming the code gets it back under.

I can raise desiredMaxBinarySize (and desiredMinBinarySize by the same amount, as the script suggests) in this PR if you think the fix is worth it, or leave the limit to you.

@vidigoat

Copy link
Copy Markdown
Contributor Author

I've added a second commit that raises both limits by 0.1MB, as the check suggests, so CI can go green. The smallest size in CI (macos-15 @ Go oldstable, 1.6MB) stays above the new minimum. #2502 carries the same commit, so they merge in either order. Happy to drop it if you'd rather handle the limit separately.

Comment thread completion_test.go Outdated
Comment on lines +455 to +459
// The root command completes os.Args, which still hold the flags, so a
// flag that needs nothing more must lead to the subcommands rather than
// to an empty list of flag suggestions.
origArgv := os.Args
t.Cleanup(func() { os.Args = origArgv })

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are not required after #2489

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. On current main the root command still reads os.Args, so the test fails without these lines until #2489 lands. I checked the version without them on top of #2489 and it passes, so I'll drop them as soon as #2489 is merged.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropped them now that #2489 is merged: rebased on main, and the test passes its arguments to Run like the other completion tests.

The root command completes the arguments passed to Run, which still hold
its flags, so after a flag that takes no value or has its value after
"=", such as "app --verbose <TAB>", it printed flag suggestions for that
flag and found none. A subcommand completes its parsed arguments and does
not have this problem. Treat such a flag as complete unless it starts a
longer flag name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vidigoat
vidigoat force-pushed the fix/complete-commands-after-finished-flag branch from 2127145 to 245af54 Compare October 29, 2026 10:18

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants