Add completion for help command (#1136)
* Don't exclude 'help' from bash completions Fixes #1000. * Provide completion for the help command 1- Show 'help' as a possible completion 2- Provide completions for the help command itself Signed-off-by: Marc Khouzam <marc.khouzam@montreal.ca> Co-authored-by: Zaven Muradyan <voithos@google.com>
This commit is contained in:
parent
ed7b60e298
commit
04318720db
@ -389,7 +389,7 @@ fi
|
|||||||
func writeCommands(buf *bytes.Buffer, cmd *Command) {
|
func writeCommands(buf *bytes.Buffer, cmd *Command) {
|
||||||
buf.WriteString(" commands=()\n")
|
buf.WriteString(" commands=()\n")
|
||||||
for _, c := range cmd.Commands() {
|
for _, c := range cmd.Commands() {
|
||||||
if !c.IsAvailableCommand() || c == cmd.helpCommand {
|
if !c.IsAvailableCommand() && c != cmd.helpCommand {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name()))
|
buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name()))
|
||||||
@ -582,7 +582,7 @@ func writeArgAliases(buf *bytes.Buffer, cmd *Command) {
|
|||||||
|
|
||||||
func gen(buf *bytes.Buffer, cmd *Command) {
|
func gen(buf *bytes.Buffer, cmd *Command) {
|
||||||
for _, c := range cmd.Commands() {
|
for _, c := range cmd.Commands() {
|
||||||
if !c.IsAvailableCommand() || c == cmd.helpCommand {
|
if !c.IsAvailableCommand() && c != cmd.helpCommand {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
gen(buf, c)
|
gen(buf, c)
|
||||||
|
20
command.go
20
command.go
@ -1056,7 +1056,25 @@ func (c *Command) InitDefaultHelpCmd() {
|
|||||||
Short: "Help about any command",
|
Short: "Help about any command",
|
||||||
Long: `Help provides help for any command in the application.
|
Long: `Help provides help for any command in the application.
|
||||||
Simply type ` + c.Name() + ` help [path to command] for full details.`,
|
Simply type ` + c.Name() + ` help [path to command] for full details.`,
|
||||||
|
ValidArgsFunction: func(c *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
|
||||||
|
var completions []string
|
||||||
|
cmd, _, e := c.Root().Find(args)
|
||||||
|
if e != nil {
|
||||||
|
return nil, ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
if cmd == nil {
|
||||||
|
// Root help command.
|
||||||
|
cmd = c.Root()
|
||||||
|
}
|
||||||
|
for _, subCmd := range cmd.Commands() {
|
||||||
|
if subCmd.IsAvailableCommand() || subCmd == cmd.helpCommand {
|
||||||
|
if strings.HasPrefix(subCmd.Name(), toComplete) {
|
||||||
|
completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return completions, ShellCompDirectiveNoFileComp
|
||||||
|
},
|
||||||
Run: func(c *Command, args []string) {
|
Run: func(c *Command, args []string) {
|
||||||
cmd, _, e := c.Root().Find(args)
|
cmd, _, e := c.Root().Find(args)
|
||||||
if cmd == nil || e != nil {
|
if cmd == nil || e != nil {
|
||||||
|
@ -183,12 +183,14 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
|
|||||||
}
|
}
|
||||||
|
|
||||||
if flag == nil {
|
if flag == nil {
|
||||||
// Complete subcommand names
|
// Complete subcommand names, including the help command
|
||||||
for _, subCmd := range finalCmd.Commands() {
|
for _, subCmd := range finalCmd.Commands() {
|
||||||
if subCmd.IsAvailableCommand() && strings.HasPrefix(subCmd.Name(), toComplete) {
|
if subCmd.IsAvailableCommand() || subCmd == finalCmd.helpCommand {
|
||||||
|
if strings.HasPrefix(subCmd.Name(), toComplete) {
|
||||||
completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
|
completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(finalCmd.ValidArgs) > 0 {
|
if len(finalCmd.ValidArgs) > 0 {
|
||||||
// Always complete ValidArgs, even if we are completing a subcommand name.
|
// Always complete ValidArgs, even if we are completing a subcommand name.
|
||||||
|
@ -629,3 +629,71 @@ func TestFlagCompletionInGoWithDesc(t *testing.T) {
|
|||||||
t.Errorf("expected: %q, got: %q", expected, output)
|
t.Errorf("expected: %q, got: %q", expected, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCompleteHelp(t *testing.T) {
|
||||||
|
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
|
||||||
|
child1Cmd := &Command{
|
||||||
|
Use: "child1",
|
||||||
|
Run: emptyRun,
|
||||||
|
}
|
||||||
|
child2Cmd := &Command{
|
||||||
|
Use: "child2",
|
||||||
|
Run: emptyRun,
|
||||||
|
}
|
||||||
|
rootCmd.AddCommand(child1Cmd, child2Cmd)
|
||||||
|
|
||||||
|
child3Cmd := &Command{
|
||||||
|
Use: "child3",
|
||||||
|
Run: emptyRun,
|
||||||
|
}
|
||||||
|
child1Cmd.AddCommand(child3Cmd)
|
||||||
|
|
||||||
|
// Test that completion includes the help command
|
||||||
|
output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := strings.Join([]string{
|
||||||
|
"child1",
|
||||||
|
"child2",
|
||||||
|
"help",
|
||||||
|
":0",
|
||||||
|
"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
|
||||||
|
|
||||||
|
if output != expected {
|
||||||
|
t.Errorf("expected: %q, got: %q", expected, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test sub-commands are completed on first level of help command
|
||||||
|
output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "help", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = strings.Join([]string{
|
||||||
|
"child1",
|
||||||
|
"child2",
|
||||||
|
"help", // "<program> help help" is a valid command, so should be completed
|
||||||
|
":4",
|
||||||
|
"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
|
||||||
|
|
||||||
|
if output != expected {
|
||||||
|
t.Errorf("expected: %q, got: %q", expected, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test sub-commands are completed on first level of help command
|
||||||
|
output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "help", "child1", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = strings.Join([]string{
|
||||||
|
"child3",
|
||||||
|
":4",
|
||||||
|
"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
|
||||||
|
|
||||||
|
if output != expected {
|
||||||
|
t.Errorf("expected: %q, got: %q", expected, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user