-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add shell completion to flag groups #1659
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -172,3 +172,52 @@ func sortedKeys(m map[string]map[string]bool) []string { | |
sort.Strings(keys) | ||
return keys | ||
} | ||
|
||
// enforceFlagGroupsForCompletion will do the following: | ||
// - when a flag in a group is present, other flags in the group will be marked required | ||
// - when a flag in a mutually exclusive group is present, other flags in the group will be marked as hidden | ||
// This allows the standard completion logic to behave appropriately for flag groups | ||
func (c *Command) enforceFlagGroupsForCompletion() { | ||
if c.DisableFlagParsing { | ||
return | ||
} | ||
|
||
flags := c.Flags() | ||
groupStatus := map[string]map[string]bool{} | ||
mutuallyExclusiveGroupStatus := map[string]map[string]bool{} | ||
c.Flags().VisitAll(func(pflag *flag.Flag) { | ||
processFlagForGroupAnnotation(flags, pflag, requiredAsGroup, groupStatus) | ||
processFlagForGroupAnnotation(flags, pflag, mutuallyExclusive, mutuallyExclusiveGroupStatus) | ||
}) | ||
|
||
// If a flag that is part of a group is present, we make all the other flags | ||
// of that group required so that the shell completion suggests them automatically | ||
for flagList, flagnameAndStatus := range groupStatus { | ||
for _, isSet := range flagnameAndStatus { | ||
if isSet { | ||
// One of the flags of the group is set, mark the other ones as required | ||
for _, fName := range strings.Split(flagList, " ") { | ||
_ = c.MarkFlagRequired(fName) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same issue regarding persistent/local flags mixed; may end up with an error here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, even if there is an error, we can just ignore it since all it will mean is that the non-existent flag couldn't be marked as required. |
||
} | ||
} | ||
} | ||
} | ||
|
||
// If a flag that is mutually exclusive to others is present, we hide the other | ||
// flags of that group so the shell completion does not suggest them | ||
for flagList, flagnameAndStatus := range mutuallyExclusiveGroupStatus { | ||
for flagName, isSet := range flagnameAndStatus { | ||
if isSet { | ||
// One of the flags of the mutually exclusive group is set, mark the other ones as hidden | ||
// Don't mark the flag that is already set as hidden because it may be an | ||
// array or slice flag and therefore must continue being suggested | ||
for _, fName := range strings.Split(flagList, " ") { | ||
if fName != flagName { | ||
flag := c.Flags().Lookup(fName) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you'll need to check for nil here due to the same problem you raised on my PR: the case with mixed persistent/local flags and then the command being invoked not having them all. At definition time we know they'll all exist or panic, but at invocation time we could end up with that case where they were defined properly but not all of them exist on the invoked command. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I'm safe in this case because thanks to your new |
||
flag.Hidden = true | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably include a test case for the persistent/local mixing and ensure it behaves on both the parent and subcommand.
On the parent (which is missing the subcommands local flags) the flag groups shouldn't apply at all.
On the subcommand things should behave as normal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do