Better fish completion using functions

This commit is contained in:
Evan Fiordeliso 2023-11-13 00:44:09 -05:00
parent 7123217e58
commit 1692790506
2 changed files with 71 additions and 28 deletions

View File

@ -15,59 +15,88 @@ func WriteFishCompletions(out io.Writer, rootCmd *Command) error {
} }
var fishTpl = template.Must(template.New("fish").Funcs(tplFuncs).Parse(` var fishTpl = template.Must(template.New("fish").Funcs(tplFuncs).Parse(`
set -l progName {{ .RootCmd.Name }} {{- $rootCmd := .RootCmd -}}
set -l commands {{- range .RootCmd.Subcommands }} {{ .Name }}{{ end }} {{- $progName := $rootCmd.Name -}}
{{- $varName := under $rootCmd.Name -}}
set -l commands {{- range $rootCmd.Subcommands }} {{ .Name }}{{ end }}
{{- /* Option template */ -}} complete -c {{ $progName }} -f
function __fish_{{ $varName }}_needs_command
set -l cmd (commandline -opc)
if test (count $cmd) -eq 1
return 0
end
return 1
end
function __fish_{{ $varName }}_using_command
set -l cmd (commandline -opc)
echo $cmd
set -l cnt (count $argv)
if test (count $cmd) -gt $cnt
for i in (seq 1 $cnt);
if test $argv[$i] != $cmd[(math $i + 1)]
return 1
end
end
return 0
end
return 1
end
{{/* Option template */ -}}
{{ define "opt" }} {{ define "opt" }}
complete -c $progName {{ $progName := .ProgName -}}
{{- $varName := .VarName -}}
complete -c {{ $progName }}
{{- if ne .Opt.ShortName "" }} -s {{ .Opt.ShortName }} {{ end -}} {{- if ne .Opt.ShortName "" }} -s {{ .Opt.ShortName }} {{ end -}}
{{- if ne .Opt.Name "" }} -l {{ .Opt.Name }} {{ end -}} {{- if ne .Opt.Name "" }} -l {{ .Opt.Name }} {{ end -}}
{{- if .Cond }} -n "{{ .Cond }}" {{ end -}} {{- if .Cmd }} {{- if ne .Cmd.CommandPath "" -}}
-n "__fish_{{ $varName }}_using_command {{.Cmd.CommandPath}}" {{ else -}}
-n "__fish_{{ $varName }}_needs_command" {{ end -}}{{- end -}}
-d '{{ .Opt.Description }}' -d '{{ .Opt.Description }}'
{{- end }} {{- end }}
{{- /* Command template */ -}} {{- /* Command template */ -}}
{{ define "cmd" }} {{ define "cmd" }}
{{ $parentVarPrefix := "" -}} {{ $progName := .ProgName -}}
{{- $varPrefix := join .Cmd.Name "_" -}} {{- $varName := .VarName -}}
{{- if .VarPrefix -}} {{- $cmd := .Cmd -}}
{{- $varPrefix = join .VarPrefix $varPrefix -}} {{- $parentVarPrefix := varPrefix .Cmd.Parent.CommandPath -}}
{{- $parentVarPrefix = .VarPrefix -}} {{- $varPrefix := varPrefix .Cmd.CommandPath -}}
{{- end -}}
{{ $parentCond := "" }} {{- if eq .Cmd.Parent.CommandPath "" -}}
{{- $cond := join "__fish_seen_subcommand_from " .Cmd.Name }} complete -f -c {{ $progName }} -n "__fish_{{ $varName }}_needs_command" -a {{ .Cmd.Name }} -d "{{ .Cmd.ShortDescription }}"
{{- if .Prefix -}} {{- else -}}
{{- $cond = join .Prefix $cond -}} complete -f -c {{ $progName }} -n "__fish_{{ $varName }}_using_command {{.Cmd.Parent.CommandPath}}" -a {{ .Cmd.Name }} -d "{{ .Cmd.ShortDescription }}"
{{- $parentCond = .Prefix -}}
{{- end -}} {{- end -}}
set -l {{ $varPrefix }}commands {{- range .Cmd.Subcommands }} {{ .Name }}{{ end }}
complete -f -c $progName -n "{{ $parentCond }}not __fish_seen_subcommand_from ${{ $parentVarPrefix }}commands" -a {{ .Cmd.Name }} -d "{{ .Cmd.ShortDescription }}"
{{- range .Cmd.Opts }} {{- range .Cmd.Opts }}
{{- template "opt" (map "Opt" . "Cond" $cond) -}} {{- template "opt" (map "Opt" . "ProgName" $progName "VarName" $varName "Cmd" $cmd) -}}
{{ end -}} {{ end -}}
{{ if gt (len .Cmd.Subcommands) 0 }}
set -l {{ $varPrefix }}commands {{- range .Cmd.Subcommands }} {{ .Name }}{{ end -}}
{{ $cmdName := .Cmd.Name }} {{ $cmdName := .Cmd.Name }}
{{- range .Cmd.Subcommands }} {{- range .Cmd.Subcommands }}
{{- template "cmd" (map "Cmd" . "Prefix" (join $cond "; ") "VarPrefix" $varPrefix) -}} {{- template "cmd" (map "Cmd" . "ProgName" $progName "VarName" $varName) -}}
{{ end -}} {{ end -}}
{{- end -}}
{{ end }} {{ end }}
{{- /* Top-level commands */ -}} {{- /* Top-level commands */ -}}
{{ range .RootCmd.Subcommands }} {{ range $rootCmd.Subcommands }}
{{- template "cmd" (map "Cmd" .) -}} {{- template "cmd" (map "Cmd" . "ProgName" $progName "VarName" $varName) -}}
{{ end }} {{ end }}
{{- /* Root command options */ -}} {{- /* Root command options */ -}}
{{ range .RootCmd.Opts }} {{ range $rootCmd.Opts }}
{{- template "opt" (map "Opt" . "Cond" "not __fish_seen_subcommand_from $commands") -}} {{- template "opt" (map "Opt" . "ProgName" $progName "VarName" $varName "Cmd" $rootCmd) -}}
{{ end }} {{ end }}
{{- /* Global options */ -}} {{- /* Global options */ -}}
{{ range .GlobalOpts }} {{ range .GlobalOpts }}
{{- template "opt" (map "Opt" .) -}} {{- template "opt" (map "Opt" . "ProgName" $progName "VarName" $varName) -}}
{{ end }} {{ end }}
`)) `))

View File

@ -7,8 +7,10 @@ import (
) )
var tplFuncs = template.FuncMap{ var tplFuncs = template.FuncMap{
"map": tplMap, "map": tplMap,
"join": tplJoin, "join": tplJoin,
"under": tplUnder,
"varPrefix": tplVarPrefix,
} }
func tplMap(vals ...any) (map[string]any, error) { func tplMap(vals ...any) (map[string]any, error) {
@ -26,3 +28,15 @@ func tplMap(vals ...any) (map[string]any, error) {
func tplJoin(strs ...string) string { func tplJoin(strs ...string) string {
return strings.Join(strs, "") return strings.Join(strs, "")
} }
func tplUnder(s string) string {
return strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(s, " ", "_"), "-", "_"))
}
func tplVarPrefix(s string) string {
if s == "" {
return ""
}
return tplUnder(s) + "_"
}