Skip to content

Commit

Permalink
start
Browse files Browse the repository at this point in the history
Signed-off-by: Marc Khouzam <marc.khouzam@gmail.com>
  • Loading branch information
marckhouzam committed Feb 7, 2025
1 parent 7580c22 commit b33f75c
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 6 deletions.
2 changes: 1 addition & 1 deletion command.go
Original file line number Diff line number Diff line change
Expand Up @@ -1112,7 +1112,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
c.initCompleteCmd(args)

// initialize the default completion command
c.InitDefaultCompletionCmd(args)
c.InitDefaultCompletionCmd(args...)

// Now that all commands have been created, let's make sure all groups
// are properly created also
Expand Down
16 changes: 11 additions & 5 deletions completions.go
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ 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(args []string) {
func (c *Command) InitDefaultCompletionCmd(args ...string) {
if c.CompletionOptions.DisableDefaultCmd {
return
}
Expand All @@ -724,10 +724,16 @@ func (c *Command) InitDefaultCompletionCmd(args []string) {
}

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
hasSubCommands := false
for _, cmd := range c.commands {
if cmd.Name() != ShellCompRequestCmd && cmd.Name() != helpCommandName {
// We found a real sub-command (not 'help' or '__complete')
hasSubCommands = true
break
}
}

completionCmd := &Command{
Use: compCmdName,
Expand All @@ -743,7 +749,7 @@ 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'),
// If the 'completion' command will be the only sub-command,
// 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.
Expand Down
91 changes: 91 additions & 0 deletions completions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3789,3 +3789,94 @@ func TestDisableDescriptions(t *testing.T) {
})
}
}

// A test to make sure the InitDefaultCompletionCmd function works as expected
// in case a project calls it directly.
func TestInitDefaultCompletionCmd(t *testing.T) {

testCases := []struct {
desc string
hasChildCmd bool
args []string
expectCompCmd bool
}{
{
desc: "no child command and not calling the completion command",
hasChildCmd: false,
args: []string{"somearg"},
expectCompCmd: false,
},
{
desc: "no child command but calling the completion command",
hasChildCmd: false,
args: []string{"completion"},
expectCompCmd: true,
},
{
desc: "no child command but calling __complete on the root command",
hasChildCmd: false,
args: []string{"__complete", ""},
expectCompCmd: false,
},
{
desc: "no child command but calling __complete on the completion command",
hasChildCmd: false,
args: []string{"__complete", "completion", ""},
expectCompCmd: true,
},
{
desc: "with child command",
hasChildCmd: true,
args: []string{"child"},
expectCompCmd: true,
},
{
desc: "no child command not passing args",
hasChildCmd: false,
args: nil,
expectCompCmd: false,
},
{
desc: "with child command not passing args",
hasChildCmd: true,
args: nil,
expectCompCmd: true,
},
}

for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
childCmd := &Command{Use: "child", Run: emptyRun}

expectedNumSubCommands := 0
if tc.hasChildCmd {
rootCmd.AddCommand(childCmd)
expectedNumSubCommands++
}

if tc.expectCompCmd {
expectedNumSubCommands++
}

if len(tc.args) > 0 && tc.args[0] == "__complete" {
expectedNumSubCommands++
}

// Setup the __complete command to mimic real world scenarios
rootCmd.initCompleteCmd(tc.args)

// Call the InitDefaultCompletionCmd function directly
if tc.args == nil {
rootCmd.InitDefaultCompletionCmd()
} else {
rootCmd.InitDefaultCompletionCmd(tc.args...)
}

// Check if the completion command was added
if len(rootCmd.Commands()) != expectedNumSubCommands {
t.Errorf("Expected %d subcommands, got %d", expectedNumSubCommands, len(rootCmd.Commands()))
}
})
}
}

0 comments on commit b33f75c

Please sign in to comment.