mirror of
https://github.com/spf13/cobra
synced 2025-05-06 13:27:26 +00:00
Merge remote-tracking branch 'spf13/master' into zsh-completion
This commit is contained in:
commit
13b42c0440
9 changed files with 155 additions and 8 deletions
|
@ -13,7 +13,7 @@ base: &base
|
||||||
name: "All Commands"
|
name: "All Commands"
|
||||||
command: |
|
command: |
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.3/shellcheck
|
curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.6/shellcheck
|
||||||
chmod +x bin/shellcheck
|
chmod +x bin/shellcheck
|
||||||
go get -t -v ./...
|
go get -t -v ./...
|
||||||
PATH=$PATH:$PWD/bin go test -v ./...
|
PATH=$PATH:$PWD/bin go test -v ./...
|
||||||
|
|
|
@ -251,6 +251,14 @@ __%[1]s_handle_word()
|
||||||
__%[1]s_handle_command
|
__%[1]s_handle_command
|
||||||
elif [[ $c -eq 0 ]]; then
|
elif [[ $c -eq 0 ]]; then
|
||||||
__%[1]s_handle_command
|
__%[1]s_handle_command
|
||||||
|
elif __%[1]s_contains_word "${words[c]}" "${command_aliases[@]}"; then
|
||||||
|
# aliashash variable is an associative array which is only supported in bash > 3.
|
||||||
|
if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
|
||||||
|
words[c]=${aliashash[${words[c]}]}
|
||||||
|
__%[1]s_handle_command
|
||||||
|
else
|
||||||
|
__%[1]s_handle_noun
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
__%[1]s_handle_noun
|
__%[1]s_handle_noun
|
||||||
fi
|
fi
|
||||||
|
@ -266,6 +274,7 @@ func writePostscript(buf *bytes.Buffer, name string) {
|
||||||
buf.WriteString(fmt.Sprintf(`{
|
buf.WriteString(fmt.Sprintf(`{
|
||||||
local cur prev words cword
|
local cur prev words cword
|
||||||
declare -A flaghash 2>/dev/null || :
|
declare -A flaghash 2>/dev/null || :
|
||||||
|
declare -A aliashash 2>/dev/null || :
|
||||||
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
|
||||||
|
@ -305,6 +314,7 @@ func writeCommands(buf *bytes.Buffer, cmd *Command) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name()))
|
buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name()))
|
||||||
|
writeCmdAliases(buf, c)
|
||||||
}
|
}
|
||||||
buf.WriteString("\n")
|
buf.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
@ -443,6 +453,21 @@ func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeCmdAliases(buf *bytes.Buffer, cmd *Command) {
|
||||||
|
if len(cmd.Aliases) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(sort.StringSlice(cmd.Aliases))
|
||||||
|
|
||||||
|
buf.WriteString(fmt.Sprint(` if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then`, "\n"))
|
||||||
|
for _, value := range cmd.Aliases {
|
||||||
|
buf.WriteString(fmt.Sprintf(" command_aliases+=(%q)\n", value))
|
||||||
|
buf.WriteString(fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name()))
|
||||||
|
}
|
||||||
|
buf.WriteString(` fi`)
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
func writeArgAliases(buf *bytes.Buffer, cmd *Command) {
|
func writeArgAliases(buf *bytes.Buffer, cmd *Command) {
|
||||||
buf.WriteString(" noun_aliases=()\n")
|
buf.WriteString(" noun_aliases=()\n")
|
||||||
sort.Sort(sort.StringSlice(cmd.ArgAliases))
|
sort.Sort(sort.StringSlice(cmd.ArgAliases))
|
||||||
|
@ -469,6 +494,10 @@ func gen(buf *bytes.Buffer, cmd *Command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName))
|
buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName))
|
||||||
|
buf.WriteString("\n")
|
||||||
|
buf.WriteString(" command_aliases=()\n")
|
||||||
|
buf.WriteString("\n")
|
||||||
|
|
||||||
writeCommands(buf, cmd)
|
writeCommands(buf, cmd)
|
||||||
writeFlags(buf, cmd)
|
writeFlags(buf, cmd)
|
||||||
writeRequiredFlag(buf, cmd)
|
writeRequiredFlag(buf, cmd)
|
||||||
|
|
|
@ -1,5 +1,40 @@
|
||||||
# Generating Bash Completions For Your Own cobra.Command
|
# Generating Bash Completions For Your Own cobra.Command
|
||||||
|
|
||||||
|
If you are using the generator you can create a completion command by running
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cobra add completion
|
||||||
|
```
|
||||||
|
|
||||||
|
Update the help text show how to install the bash_completion Linux show here [Kubectl docs show mac options](https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion)
|
||||||
|
|
||||||
|
Writing the shell script to stdout allows the most flexible use.
|
||||||
|
|
||||||
|
```go
|
||||||
|
// completionCmd represents the completion command
|
||||||
|
var completionCmd = &cobra.Command{
|
||||||
|
Use: "completion",
|
||||||
|
Short: "Generates bash completion scripts",
|
||||||
|
Long: `To load completion run
|
||||||
|
|
||||||
|
. <(bitbucket completion)
|
||||||
|
|
||||||
|
To configure your bash shell to load completions for each session add to your bashrc
|
||||||
|
|
||||||
|
# ~/.bashrc or ~/.profile
|
||||||
|
. <(bitbucket completion)
|
||||||
|
`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
rootCmd.GenBashCompletion(os.Stdout);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** The cobra generator may include messages printed to stdout for example if the config file is loaded, this will break the auto complete script
|
||||||
|
|
||||||
|
|
||||||
|
## Example from kubectl
|
||||||
|
|
||||||
Generating bash completions from a cobra command is incredibly easy. An actual program which does so for the kubernetes kubectl binary is as follows:
|
Generating bash completions from a cobra command is incredibly easy. An actual program which does so for the kubernetes kubectl binary is as follows:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
@ -181,7 +216,7 @@ a custom flag completion function with cobra.BashCompCustom:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
annotation := make(map[string][]string)
|
annotation := make(map[string][]string)
|
||||||
annotation[cobra.BashCompFilenameExt] = []string{"__kubectl_get_namespaces"}
|
annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"}
|
||||||
|
|
||||||
flag := &pflag.Flag{
|
flag := &pflag.Flag{
|
||||||
Name: "namespace",
|
Name: "namespace",
|
||||||
|
|
|
@ -176,13 +176,13 @@ func manPrintFlags(buf *bytes.Buffer, flags *pflag.FlagSet) {
|
||||||
|
|
||||||
func manPrintOptions(buf *bytes.Buffer, command *cobra.Command) {
|
func manPrintOptions(buf *bytes.Buffer, command *cobra.Command) {
|
||||||
flags := command.NonInheritedFlags()
|
flags := command.NonInheritedFlags()
|
||||||
if flags.HasFlags() {
|
if flags.HasAvailableFlags() {
|
||||||
buf.WriteString("# OPTIONS\n")
|
buf.WriteString("# OPTIONS\n")
|
||||||
manPrintFlags(buf, flags)
|
manPrintFlags(buf, flags)
|
||||||
buf.WriteString("\n")
|
buf.WriteString("\n")
|
||||||
}
|
}
|
||||||
flags = command.InheritedFlags()
|
flags = command.InheritedFlags()
|
||||||
if flags.HasFlags() {
|
if flags.HasAvailableFlags() {
|
||||||
buf.WriteString("# OPTIONS INHERITED FROM PARENT COMMANDS\n")
|
buf.WriteString("# OPTIONS INHERITED FROM PARENT COMMANDS\n")
|
||||||
manPrintFlags(buf, flags)
|
manPrintFlags(buf, flags)
|
||||||
buf.WriteString("\n")
|
buf.WriteString("\n")
|
||||||
|
|
|
@ -47,6 +47,42 @@ func TestGenManDoc(t *testing.T) {
|
||||||
checkStringContains(t, output, translate("Auto generated"))
|
checkStringContains(t, output, translate("Auto generated"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenManNoHiddenParents(t *testing.T) {
|
||||||
|
header := &GenManHeader{
|
||||||
|
Title: "Project",
|
||||||
|
Section: "2",
|
||||||
|
}
|
||||||
|
|
||||||
|
// We generate on a subcommand so we have both subcommands and parents
|
||||||
|
for _, name := range []string{"rootflag", "strtwo"} {
|
||||||
|
f := rootCmd.PersistentFlags().Lookup(name)
|
||||||
|
f.Hidden = true
|
||||||
|
defer func() { f.Hidden = false }()
|
||||||
|
}
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := GenMan(echoCmd, header, buf); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
output := buf.String()
|
||||||
|
|
||||||
|
// Make sure parent has - in CommandPath() in SEE ALSO:
|
||||||
|
parentPath := echoCmd.Parent().CommandPath()
|
||||||
|
dashParentPath := strings.Replace(parentPath, " ", "-", -1)
|
||||||
|
expected := translate(dashParentPath)
|
||||||
|
expected = expected + "(" + header.Section + ")"
|
||||||
|
checkStringContains(t, output, expected)
|
||||||
|
|
||||||
|
checkStringContains(t, output, translate(echoCmd.Name()))
|
||||||
|
checkStringContains(t, output, translate(echoCmd.Name()))
|
||||||
|
checkStringContains(t, output, "boolone")
|
||||||
|
checkStringOmits(t, output, "rootflag")
|
||||||
|
checkStringContains(t, output, translate(rootCmd.Name()))
|
||||||
|
checkStringContains(t, output, translate(echoSubCmd.Name()))
|
||||||
|
checkStringOmits(t, output, translate(deprecatedCmd.Name()))
|
||||||
|
checkStringContains(t, output, translate("Auto generated"))
|
||||||
|
checkStringOmits(t, output, "OPTIONS INHERITED FROM PARENT COMMANDS")
|
||||||
|
}
|
||||||
|
|
||||||
func TestGenManNoGenTag(t *testing.T) {
|
func TestGenManNoGenTag(t *testing.T) {
|
||||||
echoCmd.DisableAutoGenTag = true
|
echoCmd.DisableAutoGenTag = true
|
||||||
defer func() { echoCmd.DisableAutoGenTag = false }()
|
defer func() { echoCmd.DisableAutoGenTag = false }()
|
||||||
|
|
|
@ -29,7 +29,7 @@ import (
|
||||||
func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error {
|
func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error {
|
||||||
flags := cmd.NonInheritedFlags()
|
flags := cmd.NonInheritedFlags()
|
||||||
flags.SetOutput(buf)
|
flags.SetOutput(buf)
|
||||||
if flags.HasFlags() {
|
if flags.HasAvailableFlags() {
|
||||||
buf.WriteString("### Options\n\n```\n")
|
buf.WriteString("### Options\n\n```\n")
|
||||||
flags.PrintDefaults()
|
flags.PrintDefaults()
|
||||||
buf.WriteString("```\n\n")
|
buf.WriteString("```\n\n")
|
||||||
|
@ -37,7 +37,7 @@ func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error {
|
||||||
|
|
||||||
parentFlags := cmd.InheritedFlags()
|
parentFlags := cmd.InheritedFlags()
|
||||||
parentFlags.SetOutput(buf)
|
parentFlags.SetOutput(buf)
|
||||||
if parentFlags.HasFlags() {
|
if parentFlags.HasAvailableFlags() {
|
||||||
buf.WriteString("### Options inherited from parent commands\n\n```\n")
|
buf.WriteString("### Options inherited from parent commands\n\n```\n")
|
||||||
parentFlags.PrintDefaults()
|
parentFlags.PrintDefaults()
|
||||||
buf.WriteString("```\n\n")
|
buf.WriteString("```\n\n")
|
||||||
|
|
|
@ -25,6 +25,30 @@ func TestGenMdDoc(t *testing.T) {
|
||||||
checkStringContains(t, output, rootCmd.Short)
|
checkStringContains(t, output, rootCmd.Short)
|
||||||
checkStringContains(t, output, echoSubCmd.Short)
|
checkStringContains(t, output, echoSubCmd.Short)
|
||||||
checkStringOmits(t, output, deprecatedCmd.Short)
|
checkStringOmits(t, output, deprecatedCmd.Short)
|
||||||
|
checkStringContains(t, output, "Options inherited from parent commands")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenMdNoHiddenParents(t *testing.T) {
|
||||||
|
// We generate on subcommand so we have both subcommands and parents.
|
||||||
|
for _, name := range []string{"rootflag", "strtwo"} {
|
||||||
|
f := rootCmd.PersistentFlags().Lookup(name)
|
||||||
|
f.Hidden = true
|
||||||
|
defer func() { f.Hidden = false }()
|
||||||
|
}
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := GenMarkdown(echoCmd, buf); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
output := buf.String()
|
||||||
|
|
||||||
|
checkStringContains(t, output, echoCmd.Long)
|
||||||
|
checkStringContains(t, output, echoCmd.Example)
|
||||||
|
checkStringContains(t, output, "boolone")
|
||||||
|
checkStringOmits(t, output, "rootflag")
|
||||||
|
checkStringContains(t, output, rootCmd.Short)
|
||||||
|
checkStringContains(t, output, echoSubCmd.Short)
|
||||||
|
checkStringOmits(t, output, deprecatedCmd.Short)
|
||||||
|
checkStringOmits(t, output, "Options inherited from parent commands")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenMdNoTag(t *testing.T) {
|
func TestGenMdNoTag(t *testing.T) {
|
||||||
|
|
|
@ -29,7 +29,7 @@ import (
|
||||||
func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error {
|
func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error {
|
||||||
flags := cmd.NonInheritedFlags()
|
flags := cmd.NonInheritedFlags()
|
||||||
flags.SetOutput(buf)
|
flags.SetOutput(buf)
|
||||||
if flags.HasFlags() {
|
if flags.HasAvailableFlags() {
|
||||||
buf.WriteString("Options\n")
|
buf.WriteString("Options\n")
|
||||||
buf.WriteString("~~~~~~~\n\n::\n\n")
|
buf.WriteString("~~~~~~~\n\n::\n\n")
|
||||||
flags.PrintDefaults()
|
flags.PrintDefaults()
|
||||||
|
@ -38,7 +38,7 @@ func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error
|
||||||
|
|
||||||
parentFlags := cmd.InheritedFlags()
|
parentFlags := cmd.InheritedFlags()
|
||||||
parentFlags.SetOutput(buf)
|
parentFlags.SetOutput(buf)
|
||||||
if parentFlags.HasFlags() {
|
if parentFlags.HasAvailableFlags() {
|
||||||
buf.WriteString("Options inherited from parent commands\n")
|
buf.WriteString("Options inherited from parent commands\n")
|
||||||
buf.WriteString("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n")
|
buf.WriteString("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n")
|
||||||
parentFlags.PrintDefaults()
|
parentFlags.PrintDefaults()
|
||||||
|
|
|
@ -27,6 +27,29 @@ func TestGenRSTDoc(t *testing.T) {
|
||||||
checkStringOmits(t, output, deprecatedCmd.Short)
|
checkStringOmits(t, output, deprecatedCmd.Short)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenRSTNoHiddenParents(t *testing.T) {
|
||||||
|
// We generate on a subcommand so we have both subcommands and parents
|
||||||
|
for _, name := range []string{"rootflag", "strtwo"} {
|
||||||
|
f := rootCmd.PersistentFlags().Lookup(name)
|
||||||
|
f.Hidden = true
|
||||||
|
defer func() { f.Hidden = false }()
|
||||||
|
}
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := GenReST(echoCmd, buf); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
output := buf.String()
|
||||||
|
|
||||||
|
checkStringContains(t, output, echoCmd.Long)
|
||||||
|
checkStringContains(t, output, echoCmd.Example)
|
||||||
|
checkStringContains(t, output, "boolone")
|
||||||
|
checkStringOmits(t, output, "rootflag")
|
||||||
|
checkStringContains(t, output, rootCmd.Short)
|
||||||
|
checkStringContains(t, output, echoSubCmd.Short)
|
||||||
|
checkStringOmits(t, output, deprecatedCmd.Short)
|
||||||
|
checkStringOmits(t, output, "Options inherited from parent commands")
|
||||||
|
}
|
||||||
|
|
||||||
func TestGenRSTNoTag(t *testing.T) {
|
func TestGenRSTNoTag(t *testing.T) {
|
||||||
rootCmd.DisableAutoGenTag = true
|
rootCmd.DisableAutoGenTag = true
|
||||||
defer func() { rootCmd.DisableAutoGenTag = false }()
|
defer func() { rootCmd.DisableAutoGenTag = false }()
|
||||||
|
|
Loading…
Add table
Reference in a new issue