mirror of
https://github.com/spf13/cobra
synced 2024-09-28 19:06:26 +00:00
Compare commits
2 commits
1808686f0f
...
83e08a7a16
Author | SHA1 | Date | |
---|---|---|---|
83e08a7a16 | |||
b1acb500a2 |
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
|
// initialize help at the last point to allow for user overriding
|
||||||
c.InitDefaultHelpCmd()
|
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
|
args := c.args
|
||||||
|
|
||||||
|
@ -1082,9 +1076,16 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
|
||||||
args = os.Args[1:]
|
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)
|
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
|
var flags []string
|
||||||
if c.TraverseChildren {
|
if c.TraverseChildren {
|
||||||
cmd, flags, err = c.Traverse(args)
|
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,
|
// 1- the feature has been explicitly disabled by the program,
|
||||||
// 2- c has no subcommands (to avoid creating one),
|
// 2- c has no subcommands (to avoid creating one),
|
||||||
// 3- c already has a 'completion' command provided by the program.
|
// 3- c already has a 'completion' command provided by the program.
|
||||||
func (c *Command) InitDefaultCompletionCmd() {
|
func (c *Command) InitDefaultCompletionCmd(args []string) {
|
||||||
if c.CompletionOptions.DisableDefaultCmd || !c.HasSubCommands() {
|
if c.CompletionOptions.DisableDefaultCmd {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -700,6 +700,10 @@ func (c *Command) InitDefaultCompletionCmd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
haveNoDescFlag := !c.CompletionOptions.DisableNoDescFlag && !c.CompletionOptions.DisableDescriptions
|
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{
|
completionCmd := &Command{
|
||||||
Use: compCmdName,
|
Use: compCmdName,
|
||||||
|
@ -714,6 +718,22 @@ See each sub-command's help for details on how to use the generated script.
|
||||||
}
|
}
|
||||||
c.AddCommand(completionCmd)
|
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()
|
out := c.OutOrStdout()
|
||||||
noDesc := c.CompletionOptions.DisableDescriptions
|
noDesc := c.CompletionOptions.DisableDescriptions
|
||||||
shortDesc := "Generate the autocompletion script for %s"
|
shortDesc := "Generate the autocompletion script for %s"
|
||||||
|
|
|
@ -2432,7 +2432,7 @@ func TestDefaultCompletionCmd(t *testing.T) {
|
||||||
Run: emptyRun,
|
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())
|
assertNoErr(t, rootCmd.Execute())
|
||||||
for _, cmd := range rootCmd.commands {
|
for _, cmd := range rootCmd.commands {
|
||||||
if cmd.Name() == compCmdName {
|
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{
|
subCmd := &Command{
|
||||||
Use: "sub",
|
Use: "sub",
|
||||||
Run: emptyRun,
|
Run: emptyRun,
|
||||||
|
@ -2562,6 +2573,42 @@ func TestDefaultCompletionCmd(t *testing.T) {
|
||||||
|
|
||||||
func TestCompleteCompletion(t *testing.T) {
|
func TestCompleteCompletion(t *testing.T) {
|
||||||
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
|
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{
|
subCmd := &Command{
|
||||||
Use: "sub",
|
Use: "sub",
|
||||||
Run: emptyRun,
|
Run: emptyRun,
|
||||||
|
@ -2569,12 +2616,12 @@ func TestCompleteCompletion(t *testing.T) {
|
||||||
rootCmd.AddCommand(subCmd)
|
rootCmd.AddCommand(subCmd)
|
||||||
|
|
||||||
// Test sub-commands of the completion command
|
// Test sub-commands of the completion command
|
||||||
output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "completion", "")
|
output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "completion", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := strings.Join([]string{
|
expected = strings.Join([]string{
|
||||||
"bash",
|
"bash",
|
||||||
"fish",
|
"fish",
|
||||||
"powershell",
|
"powershell",
|
||||||
|
|
|
@ -8,7 +8,8 @@ The currently supported shells are:
|
||||||
- PowerShell
|
- PowerShell
|
||||||
|
|
||||||
Cobra will automatically provide your program with a fully functional `completion` command,
|
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
|
## Creating your own completion command
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue