diff --git a/autocomplete/fish_autocomplete b/autocomplete/fish_autocomplete new file mode 100644 index 0000000000..7aa7d0a8ba --- /dev/null +++ b/autocomplete/fish_autocomplete @@ -0,0 +1,35 @@ +# This is a shell completion script auto-generated by https://github.com/urfave/cli for fish. + +function __%[1]_perform_completion + # Extract all args except the last one + set -l args (commandline -opc) + # Extract the last arg (partial input) + set -l lastArg (commandline -ct) + + set -l results ($args[1] $args[2..-1] $lastArg --generate-shell-completion 2> /dev/null) + + # Remove trailing empty lines + for line in $results[-1..1] + if test (string trim -- $line) = "" + set results $results[1..-2] + else + break + end + end + + for line in $results + if not string match -q -- "%[1]*" $line + set -l parts (string split -m 1 ":" -- "$line") + if test (count $parts) -eq 2 + printf "%s\t%s\n" "$parts[1]" "$parts[2]" + else + printf "%s\n" "$line" + end + end + end +end + +# Clear existing completions for %[1] +complete -c %[1] -e +# Register completion function +complete -c %[1] -f -a '(__%[1]_perform_completion)' \ No newline at end of file diff --git a/completion.go b/completion.go index 609b204375..de11edb406 100644 --- a/completion.go +++ b/completion.go @@ -31,7 +31,8 @@ var ( return fmt.Sprintf(string(b), appName), err }, "fish": func(c *Command, appName string) (string, error) { - return c.Root().ToFishCompletion() + b, err := autoCompleteFS.ReadFile("autocomplete/fish_autocomplete") + return fmt.Sprintf(string(b), appName), err }, "pwsh": func(c *Command, appName string) (string, error) { b, err := autoCompleteFS.ReadFile("autocomplete/powershell_autocomplete.ps1") diff --git a/examples_test.go b/examples_test.go index 727b58359d..afda009ceb 100644 --- a/examples_test.go +++ b/examples_test.go @@ -409,6 +409,43 @@ func ExampleCommand_Run_shellComplete_zsh() { // help:Shows a list of commands or help for one command } +func ExampleCommand_Run_shellComplete_fish() { + cmd := &cli.Command{ + Name: "greet", + EnableShellCompletion: true, + Commands: []*cli.Command{ + { + Name: "describeit", + Aliases: []string{"d"}, + Usage: "use it to see a description", + Description: "This is how we describe describeit the function", + Action: func(context.Context, *cli.Command) error { + fmt.Printf("i like to describe things") + return nil + }, + }, { + Name: "next", + Usage: "next example", + Description: "more stuff to see when generating bash completion", + Action: func(context.Context, *cli.Command) error { + fmt.Printf("the next example") + return nil + }, + }, + }, + } + + // Simulate a fish environment and command line arguments + os.Args = []string{"greet", "--generate-shell-completion"} + os.Setenv("SHELL", "/usr/bin/fish") + + _ = cmd.Run(context.Background(), os.Args) + // Output: + // describeit:use it to see a description + // next:next example + // help:Shows a list of commands or help for one command +} + func ExampleCommand_Run_sliceValues() { cmd := &cli.Command{ Name: "multi_values", diff --git a/help.go b/help.go index 37b1091126..af1947d2e0 100644 --- a/help.go +++ b/help.go @@ -184,11 +184,12 @@ func DefaultRootCommandComplete(ctx context.Context, cmd *Command) { var DefaultAppComplete = DefaultRootCommandComplete func printCommandSuggestions(commands []*Command, writer io.Writer) { + shell := os.Getenv("SHELL") for _, command := range commands { if command.Hidden { continue } - if strings.HasSuffix(os.Getenv("SHELL"), "zsh") && len(command.Usage) > 0 { + if (strings.HasSuffix(shell, "zsh") || strings.HasSuffix(shell, "fish")) && len(command.Usage) > 0 { _, _ = fmt.Fprintf(writer, "%s:%s\n", command.Name, command.Usage) } else { _, _ = fmt.Fprintf(writer, "%s\n", command.Name) @@ -240,7 +241,8 @@ func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) { // match if last argument matches this flag and it is not repeated if strings.HasPrefix(name, cur) && cur != name /* && !cliArgContains(name, os.Args)*/ { flagCompletion := fmt.Sprintf("%s%s", strings.Repeat("-", count), name) - if usage != "" && strings.HasSuffix(os.Getenv("SHELL"), "zsh") { + shell := os.Getenv("SHELL") + if usage != "" && (strings.HasSuffix(shell, "zsh") || strings.HasSuffix(shell, "fish")) { flagCompletion = fmt.Sprintf("%s:%s", flagCompletion, usage) } fmt.Fprintln(writer, flagCompletion)