spf13/cobra

File completion is triggered even when `cobra.ShellCompDirectiveNoFileComp` is used

bartekpacia opened this issue ยท 2 comments

Hi ๐Ÿ‘‹๐Ÿป This is my first issue in this repo. Thanks to everyone who spends their free time maintaining this amazing module. I respect and appreciate it very much.

I think I've found a bug in Cobra's shell completion, which results in Zsh's default "file completion" being always activated when all flags and arguments are used. I created a reproducible example and a video:

Bug video demo
repro.mp4
Reproducer

Build with:

go build -o go-cobra ./main.go

Code:

package main

import (
	"fmt"
	"os"
	"slices"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

func main() {
	err := rootCmd.Execute()
	if err != nil {
		os.Exit(1)
	}
}

var rootCmd = &cobra.Command{
	Use:               "go-cobra",
	Short:             "A brief description of your application",
	ValidArgsFunction: cobra.NoFileCompletions,
}

var runCmd = &cobra.Command{
	Use:   "run",
	Short: "Run app on device",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("run called")
	},
	ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
		completions := []string{"app1", "app2", "app3"}
		for _, arg := range args {
			for i, completion := range completions {
				if arg == completion {
					completions = slices.Delete(completions, i, i+1)
				}
			}
		}

		return completions, cobra.ShellCompDirectiveNoFileComp
	},
}

func init() {
	rootCmd.AddCommand(runCmd)

	runCmd.Flags().AddFlag(&pflag.Flag{
		Name:  "device",
		Usage: "Select device to run on",
	})

	runCmd.RegisterFlagCompletionFunc(
		"device",
		func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
			return []string{"emulator-5554", "Barteks-iPhone"}, cobra.ShellCompDirectiveNoFileComp
		},
	)
}

I set cobra.ShellCompDirectiveNoFileComp everywhere I could, but file completion is triggered at the end anyway.

I'd very much appreciate a fix to this problem, or confirmation if this is a bug.

The definition of the flag seems problematic.
It should be defined like this:

runCmd.Flags().String(
		"device",
		"",
		"Select device to run on",
	)

I was able to figure this out by using the __complete command manually to see what was happening to shell completion:

$ ./go-cobra __complete run --device Barteks-iPhone ''
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x18 pc=0x104609788]

goroutine 1 [running]:
github.com/spf13/pflag.(*FlagSet).Set(0x140000c2100, {0x10464f76f, 0x6}, {0x16b9135ab, 0xe})
	/Users/kmarc/go/pkg/mod/github.com/spf13/pflag@v1.0.5/flag.go:463 +0x78
github.com/spf13/pflag.(*FlagSet).Parse.func1(0x1046c0ee0?, {0x16b9135ab?, 0x16b9135a4?})
	/Users/kmarc/go/pkg/mod/github.com/spf13/pflag@v1.0.5/flag.go:1138 +0x40
[...]

See this doc: https://github.com/spf13/cobra/blob/main/site/content/completions/_index.md#debugging

Thank you very much โ€“ this helped! :-)