Skip to content

Commit

Permalink
Complete hidden commands flags and its subcommands
Browse files Browse the repository at this point in the history
This change enable to have a correct completion on hidden commands flags and
its subcommands if present, when using bash.
If an exact hidden command is typed on the command line and then the
user request completion, instead of printing other available subcommand
at the same level (which is thus incorrect), it will print any of its
subcommand if available.
Flags completion request (starting with -) will also work as expected,
as well as flag completion request on any subcommand (persistent flags
or local).

Merge spf13/cobra#983

Fixes spf13/cobra#981
  • Loading branch information
didrocks authored and hoshsadiq committed Feb 7, 2022
2 parents e04ec72 + ae5480b commit 7949031
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 4 deletions.
14 changes: 11 additions & 3 deletions bash_completions.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ __%[1]s_handle_flag()
# if you set a flag which only applies to this command, don't show subcommands
if __%[1]s_contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then
commands=()
hidden_commands=()
fi
# keep flag value with flagname as flaghash
Expand All @@ -314,6 +315,7 @@ __%[1]s_handle_flag()
# if we are looking for a flags value, don't show commands
if [[ $c -eq $cword ]]; then
commands=()
hidden_commands=()
fi
fi
Expand Down Expand Up @@ -365,6 +367,8 @@ __%[1]s_handle_word()
__%[1]s_handle_flag
elif __%[1]s_contains_word "${words[c]}" "${commands[@]}"; then
__%[1]s_handle_command
elif __%[1]s_contains_word "${words[c]}" "${hidden_commands[@]}"; then
__%[1]s_handle_command
elif [[ $c -eq 0 ]]; then
__%[1]s_handle_command
elif __%[1]s_contains_word "${words[c]}" "${command_aliases[@]}"; then
Expand Down Expand Up @@ -432,10 +436,14 @@ fi
func writeCommands(buf io.StringWriter, cmd *Command) {
WriteStringAndCheck(buf, " commands=()\n")
for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() && c != cmd.helpCommand {
if !c.IsAvailableCommand() && !c.Hidden && c != cmd.helpCommand {
continue
}
WriteStringAndCheck(buf, fmt.Sprintf(" commands+=(%q)\n", c.Name()))
commands := "commands"
if c.Hidden {
commands = "hidden_commands"
}
WriteStringAndCheck(buf, fmt.Sprintf(" %s+=(%q)\n", commands, c.Name()))
writeCmdAliases(buf, c)
}
WriteStringAndCheck(buf, "\n")
Expand Down Expand Up @@ -639,7 +647,7 @@ func writeArgAliases(buf io.StringWriter, cmd *Command) {

func gen(buf io.StringWriter, cmd *Command) {
for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() && c != cmd.helpCommand {
if !c.IsAvailableCommand() && !c.Hidden && c != cmd.helpCommand {
continue
}
gen(buf, c)
Expand Down
26 changes: 25 additions & 1 deletion bash_completions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,22 @@ func TestBashCompletions(t *testing.T) {
Run: emptyRun,
}

hiddenCmd := &Command{
Use: "hidden",
Short: "A command which is hidden",
Long: "an absolutely utterly useless command for testing for testing hiding.",
Hidden: true,
Run: emptyRun,
}

hiddenSubCmd := &Command{
Use: "subcommandForHidden",
Short: "A command which is attached to a hidden one",
Long: "an absolutely utterly useless command for testing for testing subcommand attached to hidden one.",
Hidden: true,
Run: emptyRun,
}

colonCmd := &Command{
Use: "cmd:colon",
Run: emptyRun,
Expand All @@ -147,7 +163,8 @@ func TestBashCompletions(t *testing.T) {
}

echoCmd.AddCommand(timesCmd)
rootCmd.AddCommand(echoCmd, printCmd, deprecatedCmd, colonCmd)
hiddenCmd.AddCommand(hiddenSubCmd)
rootCmd.AddCommand(echoCmd, printCmd, deprecatedCmd, hiddenCmd, colonCmd)

buf := new(bytes.Buffer)
assertNoErr(t, rootCmd.GenBashCompletion(buf))
Expand Down Expand Up @@ -203,6 +220,13 @@ func TestBashCompletions(t *testing.T) {

checkOmit(t, output, deprecatedCmd.Name())

// check that hidden command and its subcommand functions are available
check(t, output, "_root_hidden")
check(t, output, "_root_hidden_subcommandForHidden")
checkOmit(t, output, ` commands+=("hidden")`)
check(t, output, `hidden_commands+=("hidden")`)
check(t, output, `commands+=("subcommandForHidden")`)

// If available, run shellcheck against the script.
if err := exec.Command("which", "shellcheck").Run(); err != nil {
return
Expand Down

0 comments on commit 7949031

Please sign in to comment.