Skip to content

Commit 5dcc605

Browse files
committed
feat: ShellComplete for fish
1 parent fd14621 commit 5dcc605

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

fish.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error {
3434
// Add global flags
3535
completions := prepareFishFlags(cmd.Name, cmd)
3636

37+
if cmd.ShellComplete != nil {
38+
var completion strings.Builder
39+
fmt.Fprintf(&completion,
40+
"complete -c %s -n '%s' -xa '(%s --generate-shell-completion 2>/dev/null)'",
41+
cmd.Name,
42+
fishFlagHelper(cmd.Name, cmd),
43+
cmd.Name,
44+
)
45+
completions = append(completions, completion.String())
46+
}
47+
3748
// Add commands and their flags
3849
completions = append(
3950
completions,
@@ -72,6 +83,25 @@ func prepareFishCommands(binary string, parent *Command) []string {
7283
}
7384
completions = append(completions, completion.String())
7485
}
86+
87+
if command.ShellComplete != nil {
88+
var completion strings.Builder
89+
var path []string
90+
lineage := command.Lineage()
91+
for i := len(lineage) - 2; i >= 0; i-- {
92+
path = append(path, lineage[i].Name)
93+
}
94+
95+
fmt.Fprintf(&completion,
96+
"complete -c %s -n '%s' -xa '(%s %s --generate-shell-completion 2>/dev/null)'",
97+
binary,
98+
fishFlagHelper(binary, command),
99+
binary,
100+
strings.Join(path, " "),
101+
)
102+
completions = append(completions, completion.String())
103+
}
104+
75105
completions = append(
76106
completions,
77107
prepareFishFlags(binary, command)...,

fish_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli
22

33
import (
4+
"context"
45
"testing"
56

67
"github.com/stretchr/testify/assert"
@@ -38,3 +39,23 @@ func TestFishCompletion(t *testing.T) {
3839
require.NoError(t, err)
3940
expectFileContent(t, "testdata/expected-fish-full.fish", res)
4041
}
42+
43+
func TestFishCompletionShellComplete(t *testing.T) {
44+
cmd := buildExtendedTestCommand()
45+
cmd.ShellComplete = func(context.Context, *Command) {}
46+
47+
configCmd := cmd.Command("config")
48+
configCmd.ShellComplete = func(context.Context, *Command) {}
49+
50+
subConfigCmd := configCmd.Command("sub-config")
51+
subConfigCmd.ShellComplete = func(context.Context, *Command) {}
52+
53+
cmd.setupCommandGraph()
54+
55+
res, err := cmd.ToFishCompletion()
56+
require.NoError(t, err)
57+
58+
assert.Contains(t, res, "complete -c greet -n '__fish_greet_no_subcommand' -xa '(greet --generate-shell-completion 2>/dev/null)'")
59+
assert.Contains(t, res, "complete -c greet -n '__fish_seen_subcommand_from config c' -xa '(greet config --generate-shell-completion 2>/dev/null)'")
60+
assert.Contains(t, res, "complete -c greet -n '__fish_seen_subcommand_from config c; and __fish_seen_subcommand_from sub-config s ss' -xa '(greet config sub-config --generate-shell-completion 2>/dev/null)'")
61+
}

0 commit comments

Comments
 (0)