zsh-completion: added support for filename globbing.

This commit is contained in:
Haim Ashkenazi 2018-03-02 08:42:52 +02:00 committed by Steve Francia
parent bda855a1a0
commit 50f385938e
3 changed files with 21 additions and 17 deletions

View File

@ -137,7 +137,7 @@ func genFlagEntryForSingleOptionFlag(f *pflag.Flag) string {
} }
extras = genZshFlagEntryExtras(f) extras = genZshFlagEntryExtras(f)
return fmt.Sprintf(`"%s%s[%s]%s"`, multiMark, option, f.Usage, extras) return fmt.Sprintf(`'%s%s[%s]%s'`, multiMark, option, f.Usage, extras)
} }
func genFlagEntryForMultiOptionFlag(f *pflag.Flag) string { func genFlagEntryForMultiOptionFlag(f *pflag.Flag) string {
@ -148,19 +148,22 @@ func genFlagEntryForMultiOptionFlag(f *pflag.Flag) string {
curlyMultiMark = "\\*" curlyMultiMark = "\\*"
} }
options = fmt.Sprintf(`"(%s-%s %s--%s)"{%s-%s,%s--%s}`, options = fmt.Sprintf(`'(%s-%s %s--%s)'{%s-%s,%s--%s}`,
parenMultiMark, f.Shorthand, parenMultiMark, f.Name, curlyMultiMark, f.Shorthand, curlyMultiMark, f.Name) parenMultiMark, f.Shorthand, parenMultiMark, f.Name, curlyMultiMark, f.Shorthand, curlyMultiMark, f.Name)
extras = genZshFlagEntryExtras(f) extras = genZshFlagEntryExtras(f)
return fmt.Sprintf(`%s"[%s]%s"`, options, f.Usage, extras) return fmt.Sprintf(`%s'[%s]%s'`, options, f.Usage, extras)
} }
func genZshFlagEntryExtras(f *pflag.Flag) string { func genZshFlagEntryExtras(f *pflag.Flag) string {
var extras string var extras string
_, pathSpecified := f.Annotations[BashCompFilenameExt] globs, pathSpecified := f.Annotations[BashCompFilenameExt]
if pathSpecified { if pathSpecified {
extras = ":filename:_files" extras = ":filename:_files"
for _, g := range globs {
extras = extras + fmt.Sprintf(` -g "%s"`, g)
}
} else if f.NoOptDefVal == "" { } else if f.NoOptDefVal == "" {
extras = ":" // allow option variable without assisting extras = ":" // allow option variable without assisting
} }

View File

@ -9,8 +9,7 @@ The generated completion script should be put somewhere in your `$fpath` named
* Completion for all non-hidden subcommands using their `.Short` description. * Completion for all non-hidden subcommands using their `.Short` description.
* Completion for all non-hidden flags using the following rules: * Completion for all non-hidden flags using the following rules:
* Filename completion works by marking the flag with `cmd.MarkFlagFilename...` * Filename completion works by marking the flag with `cmd.MarkFlagFilename...`
family of commands. However, it will ignore specific extensions requested by family of commands.
this command (see about what's not supported yet below).
* The requirement for argument to the flag is decided by the `.NoOptDefVal` * The requirement for argument to the flag is decided by the `.NoOptDefVal`
flag value - if it's empty then completion will expect an argument. flag value - if it's empty then completion will expect an argument.
* Flags of one of the various `*Arrary` and `*Slice` types supports multiple * Flags of one of the various `*Arrary` and `*Slice` types supports multiple
@ -19,7 +18,6 @@ The generated completion script should be put somewhere in your `$fpath` named
### What's not yet Supported ### What's not yet Supported
* Positional argument completion are not supported yet. * Positional argument completion are not supported yet.
* Filename completion ignores extension specification.
* Custom completion scripts are not supported yet (We should probably create zsh * Custom completion scripts are not supported yet (We should probably create zsh
specific one, doesn't make sense to re-use the bash one as the functions will specific one, doesn't make sense to re-use the bash one as the functions will
be different). be different).

View File

@ -29,7 +29,7 @@ func TestGenZshCompletion(t *testing.T) {
return r return r
}(), }(),
expectedExpressions: []string{ expectedExpressions: []string{
`(?s)function _mycommand {\s+_arguments \\\s+"--debug\[description\]".*--help.*}`, `(?s)function _mycommand {\s+_arguments \\\s+'--debug\[description\]'.*--help.*}`,
"#compdef _mycommand mycommand", "#compdef _mycommand mycommand",
}, },
}, },
@ -45,7 +45,7 @@ func TestGenZshCompletion(t *testing.T) {
return r return r
}(), }(),
expectedExpressions: []string{ expectedExpressions: []string{
`"\(-d --debug\)"{-d,--debug}"\[debug description\]"`, `'\(-d --debug\)'{-d,--debug}'\[debug description\]'`,
}, },
}, },
{ {
@ -72,15 +72,15 @@ func TestGenZshCompletion(t *testing.T) {
}(), }(),
expectedExpressions: []string{ expectedExpressions: []string{
`commands=\(\n\s+"help:.*\n\s+"subcmd1:.*\n\s+"subcmd2:.*\n\s+\)`, `commands=\(\n\s+"help:.*\n\s+"subcmd1:.*\n\s+"subcmd2:.*\n\s+\)`,
`_arguments \\\n.*"--debug\[description]"`, `_arguments \\\n.*'--debug\[description]'`,
`_arguments -C \\\n.*"--debug\[description]"`, `_arguments -C \\\n.*'--debug\[description]'`,
`function _rootcmd_subcmd1 {`, `function _rootcmd_subcmd1 {`,
`function _rootcmd_subcmd1 {`, `function _rootcmd_subcmd1 {`,
`_arguments \\\n.*"\(-o --option\)"{-o,--option}"\[option description]:" \\\n`, `_arguments \\\n.*'\(-o --option\)'{-o,--option}'\[option description]:' \\\n`,
}, },
}, },
{ {
name: "filename completion", name: "filename completion with and without globs",
root: func() *Command { root: func() *Command {
var file string var file string
r := &Command{ r := &Command{
@ -90,10 +90,13 @@ func TestGenZshCompletion(t *testing.T) {
} }
r.Flags().StringVarP(&file, "config", "c", file, "config file") r.Flags().StringVarP(&file, "config", "c", file, "config file")
r.MarkFlagFilename("config") r.MarkFlagFilename("config")
r.Flags().String("output", "", "output file")
r.MarkFlagFilename("output", "*.log", "*.txt")
return r return r
}(), }(),
expectedExpressions: []string{ expectedExpressions: []string{
`\n +"\(-c --config\)"{-c,--config}"\[config file]:filename:_files"`, `\n +'\(-c --config\)'{-c,--config}'\[config file]:filename:_files'`,
`:_files -g "\*.log" -g "\*.txt"`,
}, },
}, },
{ {
@ -105,8 +108,8 @@ func TestGenZshCompletion(t *testing.T) {
return r return r
}(), }(),
expectedExpressions: []string{ expectedExpressions: []string{
`"\*--option\[options]`, `'\*--option\[options]`,
`"\(\*-d \*--debug\)"{\\\*-d,\\\*--debug}`, `'\(\*-d \*--debug\)'{\\\*-d,\\\*--debug}`,
}, },
}, },
{ {
@ -117,7 +120,7 @@ func TestGenZshCompletion(t *testing.T) {
return r return r
}(), }(),
expectedExpressions: []string{ expectedExpressions: []string{
`"\*--verbose\[verbosity level]"`, `'\*--verbose\[verbosity level]'`,
}, },
skip: "BoolSlice behaves strangely both with NoOptDefVal and type (identifies as bool)", skip: "BoolSlice behaves strangely both with NoOptDefVal and type (identifies as bool)",
}, },