diff --git a/bash_completions.go b/bash_completions.go index 6c360c5..1ae1143 100644 --- a/bash_completions.go +++ b/bash_completions.go @@ -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 @@ -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 @@ -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 @@ -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") @@ -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) diff --git a/bash_completions_test.go b/bash_completions_test.go index 21d1fe0..d7f8900 100644 --- a/bash_completions_test.go +++ b/bash_completions_test.go @@ -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, @@ -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)) @@ -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