diff --git a/examples_test.go b/examples_test.go index 727b58359d..1fb578266e 100644 --- a/examples_test.go +++ b/examples_test.go @@ -268,6 +268,57 @@ func ExampleCommand_Run_shellComplete_bash_withShortFlag() { // --help } +func ExampleCommand_Run_shellComplete_bash_withDoubleDashFlag() { + cmd := &cli.Command{ + Name: "greet", + EnableShellCompletion: true, + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "other", + Aliases: []string{"o"}, + }, + &cli.StringFlag{ + Name: "xyz", + Aliases: []string{"x"}, + }, + }, + } + + // Simulate a bash environment and command line arguments + os.Setenv("SHELL", "bash") + os.Args = []string{"greet", "--", "--generate-shell-completion"} + + _ = cmd.Run(context.Background(), os.Args) + // Output: + // --other + // --xyz + // --help +} + +func ExampleCommand_Run_shellComplete_bash_withDoubleDashFlag_Control() { + cmd := &cli.Command{ + Name: "greet", + EnableShellCompletion: true, + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "other", + Aliases: []string{"o"}, + }, + &cli.StringFlag{ + Name: "xyz", + Aliases: []string{"x"}, + }, + }, + } + + // Simulate a bash environment and command line arguments + os.Setenv("SHELL", "bash") + os.Args = []string{"greet", "--", "x", "--generate-shell-completion"} + + _ = cmd.Run(context.Background(), os.Args) + // Output: +} + func ExampleCommand_Run_shellComplete_bash_withLongFlag() { cmd := &cli.Command{ Name: "greet", diff --git a/help.go b/help.go index 028fbb5dbb..c46fce9c92 100644 --- a/help.go +++ b/help.go @@ -251,27 +251,29 @@ func DefaultCompleteWithFlags(ctx context.Context, cmd *Command) { tracef("running default complete with os.Args flags[%v]", args) } argsLen := len(args) - lastArg := "" + var lastButOneArg, lastArg string // parent command will have --generate-shell-completion so we need // to account for that if argsLen > 1 { - lastArg = args[argsLen-2] + lastButOneArg = args[argsLen-2] + lastArg = args[argsLen-1] } else if argsLen > 0 { + lastButOneArg = args[argsLen-1] lastArg = args[argsLen-1] } - if lastArg == "--" { + if lastButOneArg == "--" && lastArg != completionFlag { tracef("No completions due to termination") return } - if lastArg == completionFlag { - lastArg = "" + if lastButOneArg == completionFlag { + lastButOneArg = "" } - if strings.HasPrefix(lastArg, "-") { - tracef("printing flag suggestion for flag[%v] on command %[1]q", lastArg, cmd.Name) - printFlagSuggestions(lastArg, cmd.Flags, cmd.Root().Writer) + if strings.HasPrefix(lastButOneArg, "-") { + tracef("printing flag suggestion for flag[%v] on command %[1]q", lastButOneArg, cmd.Name) + printFlagSuggestions(lastButOneArg, cmd.Flags, cmd.Root().Writer) return } @@ -489,11 +491,11 @@ func checkShellCompleteFlag(c *Command, arguments []string) (bool, []string) { return false, arguments } - for _, arg := range arguments { - // If arguments include "--", shell completion is disabled - // because after "--" only positional arguments are accepted. + for i, arg := range arguments { + // If there is "--" which doesn't go right before + // "--generate-shell-completion", shell completion is disabled. // https://unix.stackexchange.com/a/11382 - if arg == "--" { + if arg == "--" && i != len(arguments)-2 { return false, arguments[:pos] } } diff --git a/help_test.go b/help_test.go index 6944c1b1b1..c5868553a1 100644 --- a/help_test.go +++ b/help_test.go @@ -1270,6 +1270,28 @@ func TestDefaultCompleteWithFlags(t *testing.T) { }, argv: []string{"cmd", "--e", "--", completionFlag}, env: map[string]string{"SHELL": "bash"}, + expected: "--excitement\n--hat-shape\n", + }, + { + name: "double-dash-in-the-middle", + cmd: &Command{ + Flags: []Flag{ + &BoolFlag{Name: "excitement"}, + &StringFlag{Name: "hat-shape"}, + }, + parent: &Command{ + Name: "cmd", + Flags: []Flag{ + &BoolFlag{Name: "happiness"}, + &Int64Flag{Name: "everybody-jump-on"}, + }, + Commands: []*Command{ + {Name: "putz"}, + }, + }, + }, + argv: []string{"cmd", "--", "--e"}, + env: map[string]string{"SHELL": "bash"}, expected: "", }, { @@ -1824,6 +1846,15 @@ func Test_checkShellCompleteFlag(t *testing.T) { wantShellCompletion: false, wantArgs: []string{"--", "foo"}, }, + { + name: "double dash is just before --generate-shell-completion", + arguments: []string{"foo", "--", completionFlag}, + cmd: &Command{ + EnableShellCompletion: true, + }, + wantShellCompletion: true, + wantArgs: []string{"foo", "--"}, + }, { name: "shell completion", arguments: []string{"foo", completionFlag},