diff --git a/bash_completions.go b/bash_completions.go index 03ddda27..3df19a4a 100644 --- a/bash_completions.go +++ b/bash_completions.go @@ -190,6 +190,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 @@ -211,6 +212,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 @@ -262,6 +264,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 @@ -323,10 +327,14 @@ fi func writeCommands(buf *bytes.Buffer, cmd *Command) { buf.WriteString(" commands=()\n") for _, c := range cmd.Commands() { - if !c.IsAvailableCommand() || c == cmd.helpCommand { + if (!c.IsAvailableCommand() && !c.Hidden) || c == cmd.helpCommand { continue } - buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name())) + commands := "commands" + if c.Hidden { + commands = "hidden_commands" + } + buf.WriteString(fmt.Sprintf(" %s+=(%q)\n", commands, c.Name())) writeCmdAliases(buf, c) } buf.WriteString("\n") @@ -495,7 +503,7 @@ func writeArgAliases(buf *bytes.Buffer, cmd *Command) { func gen(buf *bytes.Buffer, 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) diff --git a/bash_completions_test.go b/bash_completions_test.go index eefa3de0..586461cb 100644 --- a/bash_completions_test.go +++ b/bash_completions_test.go @@ -130,6 +130,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, @@ -146,7 +162,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) rootCmd.GenBashCompletion(buf) @@ -195,6 +212,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