Merge pull request #255 from sttts/sttts-bash-completion-flag-equal
Advanced custom bash completion of flags
This commit is contained in:
commit
d6b481239e
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extentions"
|
BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extentions"
|
||||||
|
BashCompCustom = "cobra_annotation_bash_completion_custom"
|
||||||
BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag"
|
BashCompOneRequiredFlag = "cobra_annotation_bash_completion_one_required_flag"
|
||||||
BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir"
|
BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir"
|
||||||
)
|
)
|
||||||
@ -34,7 +35,7 @@ __debug()
|
|||||||
__my_init_completion()
|
__my_init_completion()
|
||||||
{
|
{
|
||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
_get_comp_words_by_ref cur prev words cword
|
_get_comp_words_by_ref "$@" cur prev words cword
|
||||||
}
|
}
|
||||||
|
|
||||||
__index_of_word()
|
__index_of_word()
|
||||||
@ -76,6 +77,25 @@ __handle_reply()
|
|||||||
if [[ $(type -t compopt) = "builtin" ]]; then
|
if [[ $(type -t compopt) = "builtin" ]]; then
|
||||||
[[ $COMPREPLY == *= ]] || compopt +o nospace
|
[[ $COMPREPLY == *= ]] || compopt +o nospace
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# complete after --flag=abc
|
||||||
|
if [[ $cur == *=* ]]; then
|
||||||
|
if [[ $(type -t compopt) = "builtin" ]]; then
|
||||||
|
compopt +o nospace
|
||||||
|
fi
|
||||||
|
|
||||||
|
local index flag
|
||||||
|
flag="${cur%%=*}"
|
||||||
|
__index_of_word "${flag}" "${flags_with_completion[@]}"
|
||||||
|
if [[ ${index} -ge 0 ]]; then
|
||||||
|
COMPREPLY=() PREFIX="" cur="${cur#*=}"
|
||||||
|
${flags_completion[${index}]}
|
||||||
|
if [ -n "${ZSH_VERSION}" ]; then
|
||||||
|
# zfs completion needs --flag= prefix
|
||||||
|
eval COMPREPLY=( "\${COMPREPLY[@]/#/${flag}=}" )
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
return 0;
|
return 0;
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@ -169,6 +189,8 @@ __handle_noun()
|
|||||||
|
|
||||||
if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then
|
if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then
|
||||||
must_have_one_noun=()
|
must_have_one_noun=()
|
||||||
|
elif __contains_word "${words[c]%s}" "${must_have_one_noun[@]}"; then
|
||||||
|
must_have_one_noun=()
|
||||||
fi
|
fi
|
||||||
|
|
||||||
nouns+=("${words[c]}")
|
nouns+=("${words[c]}")
|
||||||
@ -229,7 +251,7 @@ func postscript(w io.Writer, name string) error {
|
|||||||
if declare -F _init_completion >/dev/null 2>&1; then
|
if declare -F _init_completion >/dev/null 2>&1; then
|
||||||
_init_completion -s || return
|
_init_completion -s || return
|
||||||
else
|
else
|
||||||
__my_init_completion || return
|
__my_init_completion -n "=" || return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local c=0
|
local c=0
|
||||||
@ -299,6 +321,20 @@ func writeFlagHandler(name string, annotations map[string][]string, w io.Writer)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
case BashCompCustom:
|
||||||
|
_, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(value) > 0 {
|
||||||
|
handlers := strings.Join(value, "; ")
|
||||||
|
_, err = fmt.Fprintf(w, " flags_completion+=(%q)\n", handlers)
|
||||||
|
} else {
|
||||||
|
_, err = fmt.Fprintf(w, " flags_completion+=(:)\n")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
case BashCompSubdirsInDir:
|
case BashCompSubdirsInDir:
|
||||||
_, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name)
|
_, err := fmt.Fprintf(w, " flags_with_completion+=(%q)\n", name)
|
||||||
|
|
||||||
@ -519,6 +555,12 @@ func (cmd *Command) MarkFlagFilename(name string, extensions ...string) error {
|
|||||||
return MarkFlagFilename(cmd.Flags(), name, extensions...)
|
return MarkFlagFilename(cmd.Flags(), name, extensions...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists.
|
||||||
|
// Generated bash autocompletion will call the bash function f for the flag.
|
||||||
|
func (cmd *Command) MarkFlagCustom(name string, f string) error {
|
||||||
|
return MarkFlagCustom(cmd.Flags(), name, f)
|
||||||
|
}
|
||||||
|
|
||||||
// MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists.
|
// MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists.
|
||||||
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
|
// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
|
||||||
func (cmd *Command) MarkPersistentFlagFilename(name string, extensions ...string) error {
|
func (cmd *Command) MarkPersistentFlagFilename(name string, extensions ...string) error {
|
||||||
@ -530,3 +572,9 @@ func (cmd *Command) MarkPersistentFlagFilename(name string, extensions ...string
|
|||||||
func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error {
|
func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error {
|
||||||
return flags.SetAnnotation(name, BashCompFilenameExt, extensions)
|
return flags.SetAnnotation(name, BashCompFilenameExt, extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkFlagCustom adds the BashCompCustom annotation to the named flag in the flag set, if it exists.
|
||||||
|
// Generated bash autocompletion will call the bash function f for the flag.
|
||||||
|
func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error {
|
||||||
|
return flags.SetAnnotation(name, BashCompCustom, []string{f})
|
||||||
|
}
|
||||||
|
@ -147,3 +147,35 @@ hello.yml test.json
|
|||||||
```
|
```
|
||||||
|
|
||||||
So while there are many other files in the CWD it only shows me subdirs and those with valid extensions.
|
So while there are many other files in the CWD it only shows me subdirs and those with valid extensions.
|
||||||
|
|
||||||
|
# Specifiy custom flag completion
|
||||||
|
|
||||||
|
Similar to the filename completion and filtering usingn cobra.BashCompFilenameExt, you can specifiy
|
||||||
|
a custom flag completion function with cobra.BashCompCustom:
|
||||||
|
|
||||||
|
```go
|
||||||
|
annotation := make(map[string][]string)
|
||||||
|
annotation[cobra.BashCompFilenameExt] = []string{"__kubectl_get_namespaces"}
|
||||||
|
|
||||||
|
flag := &pflag.Flag{
|
||||||
|
Name: "namespace",
|
||||||
|
Usage: usage,
|
||||||
|
Annotations: annotation,
|
||||||
|
}
|
||||||
|
cmd.Flags().AddFlag(flag)
|
||||||
|
```
|
||||||
|
|
||||||
|
In addition add the `__handle_namespace_flag` implementation in the `BashCompletionFunction`
|
||||||
|
value, e.g.:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
__kubectl_get_namespaces()
|
||||||
|
{
|
||||||
|
local template
|
||||||
|
template="{{ range .items }}{{ .metadata.name }} {{ end }}"
|
||||||
|
local kubectl_out
|
||||||
|
if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
|
||||||
|
COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) )
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@ -62,6 +62,11 @@ func TestBashCompletions(t *testing.T) {
|
|||||||
c.Flags().StringVar(&flagvalExt, "filename-ext", "", "Enter a filename (extension limited)")
|
c.Flags().StringVar(&flagvalExt, "filename-ext", "", "Enter a filename (extension limited)")
|
||||||
c.MarkFlagFilename("filename-ext")
|
c.MarkFlagFilename("filename-ext")
|
||||||
|
|
||||||
|
// filename extensions
|
||||||
|
var flagvalCustom string
|
||||||
|
c.Flags().StringVar(&flagvalCustom, "custom", "", "Enter a filename (extension limited)")
|
||||||
|
c.MarkFlagCustom("custom", "__complete_custom")
|
||||||
|
|
||||||
// subdirectories in a given directory
|
// subdirectories in a given directory
|
||||||
var flagvalTheme string
|
var flagvalTheme string
|
||||||
c.Flags().StringVar(&flagvalTheme, "theme", "", "theme to use (located in /themes/THEMENAME/)")
|
c.Flags().StringVar(&flagvalTheme, "theme", "", "theme to use (located in /themes/THEMENAME/)")
|
||||||
@ -88,6 +93,8 @@ func TestBashCompletions(t *testing.T) {
|
|||||||
check(t, str, `flags_completion+=("_filedir")`)
|
check(t, str, `flags_completion+=("_filedir")`)
|
||||||
// check for filename extension flags
|
// check for filename extension flags
|
||||||
check(t, str, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`)
|
check(t, str, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`)
|
||||||
|
// check for custom flags
|
||||||
|
check(t, str, `flags_completion+=("__complete_custom")`)
|
||||||
// check for subdirs_in_dir flags
|
// check for subdirs_in_dir flags
|
||||||
check(t, str, `flags_completion+=("__handle_subdirs_in_dir_flag themes")`)
|
check(t, str, `flags_completion+=("__handle_subdirs_in_dir_flag themes")`)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user