mirror of
https://github.com/spf13/cobra
synced 2024-11-16 18:57:08 +00:00
Merge b1acb500a2
into 5a1acea321
This commit is contained in:
commit
1808686f0f
4 changed files with 82 additions and 13 deletions
15
command.go
15
command.go
|
@ -1068,12 +1068,6 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
|
|||
|
||||
// initialize help at the last point to allow for user overriding
|
||||
c.InitDefaultHelpCmd()
|
||||
// initialize completion at the last point to allow for user overriding
|
||||
c.InitDefaultCompletionCmd()
|
||||
|
||||
// Now that all commands have been created, let's make sure all groups
|
||||
// are properly created also
|
||||
c.checkCommandGroups()
|
||||
|
||||
args := c.args
|
||||
|
||||
|
@ -1082,9 +1076,16 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
|
|||
args = os.Args[1:]
|
||||
}
|
||||
|
||||
// initialize the hidden command to be used for shell completion
|
||||
// initialize the __complete command to be used for shell completion
|
||||
c.initCompleteCmd(args)
|
||||
|
||||
// initialize the default completion command
|
||||
c.InitDefaultCompletionCmd(args)
|
||||
|
||||
// Now that all commands have been created, let's make sure all groups
|
||||
// are properly created also
|
||||
c.checkCommandGroups()
|
||||
|
||||
var flags []string
|
||||
if c.TraverseChildren {
|
||||
cmd, flags, err = c.Traverse(args)
|
||||
|
|
|
@ -687,8 +687,8 @@ func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*p
|
|||
// 1- the feature has been explicitly disabled by the program,
|
||||
// 2- c has no subcommands (to avoid creating one),
|
||||
// 3- c already has a 'completion' command provided by the program.
|
||||
func (c *Command) InitDefaultCompletionCmd() {
|
||||
if c.CompletionOptions.DisableDefaultCmd || !c.HasSubCommands() {
|
||||
func (c *Command) InitDefaultCompletionCmd(args []string) {
|
||||
if c.CompletionOptions.DisableDefaultCmd {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -700,6 +700,10 @@ func (c *Command) InitDefaultCompletionCmd() {
|
|||
}
|
||||
|
||||
haveNoDescFlag := !c.CompletionOptions.DisableNoDescFlag && !c.CompletionOptions.DisableDescriptions
|
||||
// Special case to know if there are sub-commands or not.
|
||||
// If there is exactly 1 sub-command, it must be the __complete command, so we are looking for the case
|
||||
// where there are *more* than one sub-commands: the _complete command *and* a real sub-command.
|
||||
hasSubCommands := len(c.commands) > 1
|
||||
|
||||
completionCmd := &Command{
|
||||
Use: compCmdName,
|
||||
|
@ -714,6 +718,22 @@ See each sub-command's help for details on how to use the generated script.
|
|||
}
|
||||
c.AddCommand(completionCmd)
|
||||
|
||||
if !hasSubCommands {
|
||||
// If the 'completion' command will be the only sub-command (other than '__complete'),
|
||||
// we only create it if it is actually being called.
|
||||
// This avoids breaking programs that would suddenly find themselves with
|
||||
// a subcommand, which would prevent them from accepting arguments.
|
||||
// We also create the 'completion' command if the user is triggering
|
||||
// shell completion for it (prog __complete completion '')
|
||||
subCmd, cmdArgs, err := c.Find(args)
|
||||
if err != nil || subCmd.Name() != compCmdName &&
|
||||
!(subCmd.Name() == ShellCompRequestCmd && len(cmdArgs) > 1 && cmdArgs[0] == compCmdName) {
|
||||
// The completion command is not being called or being completed so we remove it.
|
||||
c.RemoveCommand(completionCmd)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
out := c.OutOrStdout()
|
||||
noDesc := c.CompletionOptions.DisableDescriptions
|
||||
shortDesc := "Generate the autocompletion script for %s"
|
||||
|
|
|
@ -2432,7 +2432,7 @@ func TestDefaultCompletionCmd(t *testing.T) {
|
|||
Run: emptyRun,
|
||||
}
|
||||
|
||||
// Test that no completion command is created if there are not other sub-commands
|
||||
// Test that when there are no sub-commands, the completion command is not created if it is not called directly.
|
||||
assertNoErr(t, rootCmd.Execute())
|
||||
for _, cmd := range rootCmd.commands {
|
||||
if cmd.Name() == compCmdName {
|
||||
|
@ -2441,6 +2441,17 @@ func TestDefaultCompletionCmd(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Test that when there are no sub-commands, the completion command is created when it is called directly.
|
||||
_, err := executeCommand(rootCmd, compCmdName)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
// Reset the arguments
|
||||
rootCmd.args = nil
|
||||
// Remove completion command for the next test
|
||||
removeCompCmd(rootCmd)
|
||||
|
||||
// Add a sub-command
|
||||
subCmd := &Command{
|
||||
Use: "sub",
|
||||
Run: emptyRun,
|
||||
|
@ -2562,6 +2573,42 @@ func TestDefaultCompletionCmd(t *testing.T) {
|
|||
|
||||
func TestCompleteCompletion(t *testing.T) {
|
||||
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
|
||||
|
||||
// Test that when there are no sub-commands, the 'completion' command is not completed
|
||||
// (because it is not created).
|
||||
output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "completion")
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expected := strings.Join([]string{
|
||||
":0",
|
||||
"Completion ended with directive: ShellCompDirectiveDefault", ""}, "\n")
|
||||
|
||||
if output != expected {
|
||||
t.Errorf("expected: %q, got: %q", expected, output)
|
||||
}
|
||||
|
||||
// Test that when there are no sub-commands, completion can be triggered for the default
|
||||
// 'completion' command
|
||||
output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "completion", "")
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expected = strings.Join([]string{
|
||||
"bash",
|
||||
"fish",
|
||||
"powershell",
|
||||
"zsh",
|
||||
":4",
|
||||
"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
|
||||
|
||||
if output != expected {
|
||||
t.Errorf("expected: %q, got: %q", expected, output)
|
||||
}
|
||||
|
||||
// Add a sub-command
|
||||
subCmd := &Command{
|
||||
Use: "sub",
|
||||
Run: emptyRun,
|
||||
|
@ -2569,12 +2616,12 @@ func TestCompleteCompletion(t *testing.T) {
|
|||
rootCmd.AddCommand(subCmd)
|
||||
|
||||
// Test sub-commands of the completion command
|
||||
output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "completion", "")
|
||||
output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "completion", "")
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expected := strings.Join([]string{
|
||||
expected = strings.Join([]string{
|
||||
"bash",
|
||||
"fish",
|
||||
"powershell",
|
||||
|
|
|
@ -8,7 +8,8 @@ The currently supported shells are:
|
|||
- PowerShell
|
||||
|
||||
Cobra will automatically provide your program with a fully functional `completion` command,
|
||||
similarly to how it provides the `help` command.
|
||||
similarly to how it provides the `help` command. If there are no other subcommands, the
|
||||
default `completion` command will be hidden, but still functional.
|
||||
|
||||
## Creating your own completion command
|
||||
|
||||
|
|
Loading…
Reference in a new issue