mirror of
https://github.com/ipfs/kubo.git
synced 2025-07-04 05:16:23 +08:00
feat: add zsh completions (#10040)
Co-authored-by: Henrique Dias <hacdias@gmail.com>
This commit is contained in:

committed by
GitHub

parent
cc79eeb91c
commit
ced348366c
2
.github/workflows/gotest.yml
vendored
2
.github/workflows/gotest.yml
vendored
@ -35,6 +35,8 @@ jobs:
|
|||||||
go-version: 1.19.x
|
go-version: 1.19.x
|
||||||
- name: Check out Kubo
|
- name: Check out Kubo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
- name: Install missing tools
|
||||||
|
run: sudo apt update && sudo apt install -y zsh
|
||||||
- name: Restore Go cache
|
- name: Restore Go cache
|
||||||
uses: protocol/cache-go-action@v1
|
uses: protocol/cache-go-action@v1
|
||||||
with:
|
with:
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ipfs/go-ipfs-cmds"
|
cmds "github.com/ipfs/go-ipfs-cmds"
|
||||||
)
|
)
|
||||||
|
|
||||||
type commandEncoder struct {
|
type commandEncoder struct {
|
||||||
@ -169,6 +169,33 @@ To install the completions permanently, they can be moved to
|
|||||||
return res.Emit(&buf)
|
return res.Emit(&buf)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"zsh": {
|
||||||
|
Helptext: cmds.HelpText{
|
||||||
|
Tagline: "Generate zsh shell completions.",
|
||||||
|
ShortDescription: "Generates command completions for the zsh shell.",
|
||||||
|
LongDescription: `
|
||||||
|
Generates command completions for the zsh shell.
|
||||||
|
|
||||||
|
The simplest way to see it working is write the completions
|
||||||
|
to a file and then source it:
|
||||||
|
|
||||||
|
> ipfs commands completion zsh > ipfs-completion.zsh
|
||||||
|
> source ./ipfs-completion.zsh
|
||||||
|
|
||||||
|
To install the completions permanently, they can be moved to
|
||||||
|
/etc/zsh/completions or sourced from your ~/.zshrc file.
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
NoRemote: true,
|
||||||
|
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := writeZshCompletions(root, &buf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res.SetLength(uint64(buf.Len()))
|
||||||
|
return res.Emit(&buf)
|
||||||
|
},
|
||||||
|
},
|
||||||
"fish": {
|
"fish": {
|
||||||
Helptext: cmds.HelpText{
|
Helptext: cmds.HelpText{
|
||||||
Tagline: "Generate fish shell completions.",
|
Tagline: "Generate fish shell completions.",
|
||||||
|
@ -25,6 +25,7 @@ func TestROCommands(t *testing.T) {
|
|||||||
"/commands/completion",
|
"/commands/completion",
|
||||||
"/commands/completion/bash",
|
"/commands/completion/bash",
|
||||||
"/commands/completion/fish",
|
"/commands/completion/fish",
|
||||||
|
"/commands/completion/zsh",
|
||||||
"/dag",
|
"/dag",
|
||||||
"/dag/get",
|
"/dag/get",
|
||||||
"/dag/resolve",
|
"/dag/resolve",
|
||||||
@ -102,6 +103,7 @@ func TestCommands(t *testing.T) {
|
|||||||
"/commands/completion",
|
"/commands/completion",
|
||||||
"/commands/completion/bash",
|
"/commands/completion/bash",
|
||||||
"/commands/completion/fish",
|
"/commands/completion/fish",
|
||||||
|
"/commands/completion/zsh",
|
||||||
"/config",
|
"/config",
|
||||||
"/config/edit",
|
"/config/edit",
|
||||||
"/config/profile",
|
"/config/profile",
|
||||||
|
@ -83,7 +83,7 @@ func commandToCompletions(name string, fullName string, cmd *cmds.Command) *comp
|
|||||||
return parsed
|
return parsed
|
||||||
}
|
}
|
||||||
|
|
||||||
var bashCompletionTemplate, fishCompletionTemplate *template.Template
|
var bashCompletionTemplate, fishCompletionTemplate, zshCompletionTemplate *template.Template
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
commandTemplate := template.Must(template.New("command").Parse(`
|
commandTemplate := template.Must(template.New("command").Parse(`
|
||||||
@ -153,6 +153,28 @@ _ipfs() {
|
|||||||
{{ template "command" . }}
|
{{ template "command" . }}
|
||||||
}
|
}
|
||||||
complete -o nosort -o nospace -o default -F _ipfs ipfs
|
complete -o nosort -o nospace -o default -F _ipfs ipfs
|
||||||
|
`))
|
||||||
|
|
||||||
|
zshCompletionTemplate = template.Must(commandTemplate.New("root").Parse(`#!bin/zsh
|
||||||
|
autoload bashcompinit
|
||||||
|
bashcompinit
|
||||||
|
_ipfs_compgen() {
|
||||||
|
local oldifs="$IFS"
|
||||||
|
IFS=$'\n'
|
||||||
|
while read -r line; do
|
||||||
|
COMPREPLY+=("$line")
|
||||||
|
done < <(compgen "$@")
|
||||||
|
IFS="$oldifs"
|
||||||
|
}
|
||||||
|
|
||||||
|
_ipfs() {
|
||||||
|
COMPREPLY=()
|
||||||
|
local index=1
|
||||||
|
local argidx=0
|
||||||
|
local word="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
{{ template "command" . }}
|
||||||
|
}
|
||||||
|
complete -o nosort -o nospace -o default -F _ipfs ipfs
|
||||||
`))
|
`))
|
||||||
|
|
||||||
fishCommandTemplate := template.Must(template.New("command").Parse(`
|
fishCommandTemplate := template.Must(template.New("command").Parse(`
|
||||||
@ -221,3 +243,8 @@ func writeFishCompletions(cmd *cmds.Command, out io.Writer) error {
|
|||||||
cmds := commandToCompletions("ipfs", "", cmd)
|
cmds := commandToCompletions("ipfs", "", cmd)
|
||||||
return fishCompletionTemplate.Execute(out, cmds)
|
return fishCompletionTemplate.Execute(out, cmds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeZshCompletions(cmd *cmds.Command, out io.Writer) error {
|
||||||
|
cmds := commandToCompletions("ipfs", "", cmd)
|
||||||
|
return zshCompletionTemplate.Execute(out, cmds)
|
||||||
|
}
|
||||||
|
@ -24,3 +24,16 @@ The simplest way to use the completions logic:
|
|||||||
|
|
||||||
To install the completions permanently, they can be moved to
|
To install the completions permanently, they can be moved to
|
||||||
`/etc/fish/completions` or `~/.config/fish/completions` or sourced from your `~/.config/fish/config.fish` file.
|
`/etc/fish/completions` or `~/.config/fish/completions` or sourced from your `~/.config/fish/config.fish` file.
|
||||||
|
|
||||||
|
## ZSH
|
||||||
|
|
||||||
|
The zsh shell is also supported:
|
||||||
|
|
||||||
|
The simplest way to "eval" the completions logic:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
> eval "$(ipfs commands completion zsh)"
|
||||||
|
```
|
||||||
|
|
||||||
|
To install the completions permanently, they can be moved to
|
||||||
|
`/etc/bash_completion.d` or sourced from your `~/.zshrc` file.
|
||||||
|
@ -29,3 +29,29 @@ func TestBashCompletion(t *testing.T) {
|
|||||||
assert.NoError(t, res.Err)
|
assert.NoError(t, res.Err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestZshCompletion(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
h := harness.NewT(t)
|
||||||
|
node := h.NewNode()
|
||||||
|
|
||||||
|
res := node.IPFS("commands", "completion", "zsh")
|
||||||
|
|
||||||
|
length := len(res.Stdout.String())
|
||||||
|
if length < 100 {
|
||||||
|
t.Fatalf("expected a long Bash completion file, but got one of length %d", length)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("completion file can be loaded in bash", func(t *testing.T) {
|
||||||
|
RequiresLinux(t)
|
||||||
|
|
||||||
|
completionFile := h.WriteToTemp(res.Stdout.String())
|
||||||
|
res = h.Runner.Run(harness.RunRequest{
|
||||||
|
Path: "zsh",
|
||||||
|
Args: []string{"-c", fmt.Sprintf("autoload -Uz compinit && compinit && source %s && echo -E $_comps[ipfs]", completionFile)},
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.NoError(t, res.Err)
|
||||||
|
assert.NotEmpty(t, res.Stdout.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user