zsh-completion: added support for subcommand description.

Also make the template more elegant on the way...
This commit is contained in:
Haim Ashkenazi 2018-02-26 22:31:06 +02:00 committed by Steve Francia
parent f0508c8e76
commit 2662787697
2 changed files with 84 additions and 35 deletions

View file

@ -37,43 +37,50 @@ var (
{{/* should accept Command (that contains subcommands) as parameter */}}
{{define "argumentsC" -}}
function {{constructPath .}} {
local line
local -a commands
_arguments -C \
{{range extractFlags . -}}
{{" "}}{{if simpleFlag .}}{{template "simpleFlag" .}}{{else}}{{template "complexFlag" .}}{{end}} \
{{end}} "1: :({{subCmdList .}})" \
_arguments -C \{{- range extractFlags .}}
{{if simpleFlag .}}{{template "simpleFlag" .}}{{else}}{{template "complexFlag" .}}{{end}} \{{- end}}
"1: :->cmnds" \
"*::arg:->args"
case $line[1] in {{- range .Commands}}{{if not .Hidden}}
{{cmdName .}})
{{constructPath .}}
;;
{{end}}{{end}} esac
case $state in
cmnds)
commands=({{range .Commands}}{{if not .Hidden}}
"{{cmdName .}}:{{.Short}}"{{end}}{{end}}
)
_describe "command" commands
;;
esac
case "$words[1]" in {{- range .Commands}}{{if not .Hidden}}
{{cmdName .}})
{{constructPath .}}
;;{{end}}{{end}}
esac
}
{{range .Commands}}
{{range .Commands}}{{if not .Hidden}}
{{template "selectCmdTemplate" .}}
{{- end}}
{{- end}}{{end}}
{{- end}}
{{/* should accept Command without subcommands as parameter */}}
{{define "arguments" -}}
function {{constructPath .}} {
{{with extractFlags . -}}
{{ " _arguments" -}}
{{range .}} \
{{" _arguments"}}{{range extractFlags .}} \
{{if simpleFlag .}}{{template "simpleFlag" .}}{{else}}{{template "complexFlag" .}}{{end -}}
{{end}}
{{end -}}
}
{{- end}}
{{end}}
{{/* dispatcher for commands with or without subcommands */}}
{{define "selectCmdTemplate" -}}
{{if .Hidden}}{{/* ignore hidden*/}}{{else -}}
{{if .Commands}}{{template "argumentsC" .}}{{else}}{{template "arguments" .}}{{end}}
{{- end}}
{{- end}}
{{/* template entry point */}}
{{define "Main" -}}
#compdef _{{cmdName .}} {{cmdName .}}

View file

@ -70,7 +70,7 @@ func TestGenZshCompletion(t *testing.T) {
return r
}(),
expectedExpressions: []string{
`\\\n\s+"1: :\(help subcmd1 subcmd2\)" \\\n`,
`commands=\(\n\s+"help:.*\n\s+"subcmd1:.*\n\s+"subcmd2:.*\n\s+\)`,
`_arguments \\\n.*"--debug\[description]"`,
`_arguments -C \\\n.*"--debug\[description]"`,
`function _rootcmd_subcmd1 {`,
@ -185,24 +185,17 @@ func TestGenZshCompletionHidden(t *testing.T) {
}
}
func BenchmarkConstructPath(b *testing.B) {
c := &Command{
Use: "main",
Long: "main long description which is very long",
Short: "main short description",
}
d := &Command{
Use: "hello",
}
e := &Command{
Use: "world",
}
c.AddCommand(d)
d.AddCommand(e)
func BenchmarkMediumSizeConstruct(b *testing.B) {
root := constructLargeCommandHeirarchy()
// if err := root.GenZshCompletionFile("_mycmd"); err != nil {
// b.Error(err)
// }
for i := 0; i < b.N; i++ {
res := constructPath(e)
if res != "_main_hello_world" {
b.Errorf("expeced path to be '_main_hello_world', got %s", res)
buf := new(bytes.Buffer)
err := root.GenZshCompletion(buf)
if err != nil {
b.Error(err)
}
}
}
@ -232,3 +225,52 @@ func TestExtractFlags(t *testing.T) {
t.Errorf("expected Command D to return 2 flags, got %d", len(resD))
}
}
func constructLargeCommandHeirarchy() *Command {
var config, st1, st2 string
var long, debug bool
var in1, in2 int
r := genTestCommand("mycmd", false)
r.PersistentFlags().StringVarP(&config, "config", "c", config, "config usage")
if err := r.MarkPersistentFlagFilename("config", "*"); err != nil {
panic(err)
}
s1 := genTestCommand("sub1", true)
s1.Flags().BoolVar(&long, "long", long, "long descriptin")
s2 := genTestCommand("sub2", true)
s2.PersistentFlags().BoolVar(&debug, "debug", debug, "debug description")
s3 := genTestCommand("sub3", true)
s3.Hidden = true
s1_1 := genTestCommand("sub1sub1", true)
s1_1.Flags().StringVar(&st1, "st1", st1, "st1 description")
s1_1.Flags().StringVar(&st2, "st2", st2, "st2 description")
s1_2 := genTestCommand("sub1sub2", true)
s1_3 := genTestCommand("sub1sub3", true)
s1_3.Flags().IntVar(&in1, "int1", in1, "int1 descriptionn")
s1_3.Flags().IntVar(&in2, "int2", in2, "int2 descriptionn")
s2_1 := genTestCommand("sub2sub1", true)
s2_2 := genTestCommand("sub2sub2", true)
s2_3 := genTestCommand("sub2sub3", true)
s2_4 := genTestCommand("sub2sub4", true)
s2_5 := genTestCommand("sub2sub5", true)
s1.AddCommand(s1_1, s1_2, s1_3)
s2.AddCommand(s2_1, s2_2, s2_3, s2_4, s2_5)
r.AddCommand(s1, s2, s3)
r.Execute()
return r
}
func genTestCommand(name string, withRun bool) *Command {
r := &Command{
Use: name,
Short: name + " short description",
Long: "Long description for " + name,
}
if withRun {
r.Run = emptyRun
}
return r
}