mirror of https://github.com/docker/cli.git
vendor: github.com/spf13/cobra v1.1.3
full diff: https://github.com/spf13/cobra/compare/v1.1.1...v1.1.3 Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
d3c36a2a73
commit
25dc8034ff
|
@ -65,7 +65,7 @@ github.com/prometheus/procfs 46159f73e74d1cb8dc223deef9b2
|
|||
github.com/russross/blackfriday/v2 d3b5b032dc8e8927d31a5071b56e14c89f045135 # v2.0.1
|
||||
github.com/shurcooL/sanitized_anchor_name 7bfe4c7ecddb3666a94b053b422cdd8f5aaa3615 # v1.0.0
|
||||
github.com/sirupsen/logrus 6699a89a232f3db797f2e280639854bbc4b89725 # v1.7.0
|
||||
github.com/spf13/cobra 86f8bfd7fef868a174e1b606783bd7f5c82ddf8f # v1.1.1
|
||||
github.com/spf13/cobra 8380ddd3132bdf8fd77731725b550c181dda0aa8 # v1.1.3
|
||||
github.com/spf13/pflag 2e9d26c8c37aae03e3f9d4e90b7116f5accb7cab # v1.0.5
|
||||
github.com/theupdateframework/notary 5f1f4a34f4cfa3066e44f652e895f4b24b96248e
|
||||
github.com/tonistiigi/fsutil 0834f99b7b85462efb69b4f571a4fa3ca7da5ac9
|
||||
|
|
|
@ -6,6 +6,7 @@ Cobra is used in many Go projects such as [Kubernetes](http://kubernetes.io/),
|
|||
[Hugo](https://gohugo.io), and [Github CLI](https://github.com/cli/cli) to
|
||||
name a few. [This list](./projects_using_cobra.md) contains a more extensive list of projects using Cobra.
|
||||
|
||||
[![](https://img.shields.io/github/workflow/status/spf13/cobra/Test?longCache=tru&label=Test&logo=github%20actions&logoColor=fff)](https://github.com/spf13/cobra/actions?query=workflow%3ATest)
|
||||
[![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra)
|
||||
[![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/cobra)](https://goreportcard.com/report/github.com/spf13/cobra)
|
||||
|
@ -62,8 +63,8 @@ Cobra is built on a structure of commands, arguments & flags.
|
|||
|
||||
**Commands** represent actions, **Args** are things and **Flags** are modifiers for those actions.
|
||||
|
||||
The best applications will read like sentences when used. Users will know how
|
||||
to use the application because they will natively understand how to use it.
|
||||
The best applications read like sentences when used, and as a result, users
|
||||
intuitively know how to interact with them.
|
||||
|
||||
The pattern to follow is
|
||||
`APPNAME VERB NOUN --ADJECTIVE.`
|
||||
|
@ -234,11 +235,6 @@ func init() {
|
|||
rootCmd.AddCommand(initCmd)
|
||||
}
|
||||
|
||||
func er(msg interface{}) {
|
||||
fmt.Println("Error:", msg)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func initConfig() {
|
||||
if cfgFile != "" {
|
||||
// Use config file from the flag.
|
||||
|
@ -246,9 +242,7 @@ func initConfig() {
|
|||
} else {
|
||||
// Find home directory.
|
||||
home, err := homedir.Dir()
|
||||
if err != nil {
|
||||
er(err)
|
||||
}
|
||||
cobra.CheckErr(err)
|
||||
|
||||
// Search config in home directory with name ".cobra" (without extension).
|
||||
viper.AddConfigPath(home)
|
||||
|
@ -268,7 +262,7 @@ func initConfig() {
|
|||
With the root command you need to have your main function execute it.
|
||||
Execute should be run on the root for clarity, though it can be called on any command.
|
||||
|
||||
In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra.
|
||||
In a Cobra app, typically the main.go file is very bare. It serves one purpose: to initialize Cobra.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
@ -363,7 +357,7 @@ There are two different approaches to assign a flag.
|
|||
|
||||
### Persistent Flags
|
||||
|
||||
A flag can be 'persistent' meaning that this flag will be available to the
|
||||
A flag can be 'persistent', meaning that this flag will be available to the
|
||||
command it's assigned to as well as every command under that command. For
|
||||
global flags, assign a flag as a persistent flag on the root.
|
||||
|
||||
|
@ -373,7 +367,7 @@ rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose out
|
|||
|
||||
### Local Flags
|
||||
|
||||
A flag can also be assigned locally which will only apply to that specific command.
|
||||
A flag can also be assigned locally, which will only apply to that specific command.
|
||||
|
||||
```go
|
||||
localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
|
||||
|
@ -381,8 +375,8 @@ localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to rea
|
|||
|
||||
### Local Flag on Parent Commands
|
||||
|
||||
By default Cobra only parses local flags on the target command, any local flags on
|
||||
parent commands are ignored. By enabling `Command.TraverseChildren` Cobra will
|
||||
By default, Cobra only parses local flags on the target command, and any local flags on
|
||||
parent commands are ignored. By enabling `Command.TraverseChildren`, Cobra will
|
||||
parse local flags on each command before executing the target command.
|
||||
|
||||
```go
|
||||
|
@ -404,8 +398,8 @@ func init() {
|
|||
}
|
||||
```
|
||||
|
||||
In this example the persistent flag `author` is bound with `viper`.
|
||||
**Note**, that the variable `author` will not be set to the value from config,
|
||||
In this example, the persistent flag `author` is bound with `viper`.
|
||||
**Note**: the variable `author` will not be set to the value from config,
|
||||
when the `--author` flag is not provided by user.
|
||||
|
||||
More in [viper documentation](https://github.com/spf13/viper#working-with-flags).
|
||||
|
@ -465,7 +459,7 @@ var cmd = &cobra.Command{
|
|||
|
||||
In the example below, we have defined three commands. Two are at the top level
|
||||
and one (cmdTimes) is a child of one of the top commands. In this case the root
|
||||
is not executable meaning that a subcommand is required. This is accomplished
|
||||
is not executable, meaning that a subcommand is required. This is accomplished
|
||||
by not providing a 'Run' for the 'rootCmd'.
|
||||
|
||||
We have only defined one flag for a single command.
|
||||
|
@ -759,7 +753,7 @@ Cobra can generate documentation based on subcommands, flags, etc. Read more abo
|
|||
|
||||
## Generating shell completions
|
||||
|
||||
Cobra can generate a shell-completion file for the following shells: Bash, Zsh, Fish, Powershell. If you add more information to your commands, these completions can be amazingly powerful and flexible. Read more about it in [Shell Completions](shell_completions.md).
|
||||
Cobra can generate a shell-completion file for the following shells: bash, zsh, fish, PowerShell. If you add more information to your commands, these completions can be amazingly powerful and flexible. Read more about it in [Shell Completions](shell_completions.md).
|
||||
|
||||
# License
|
||||
|
||||
|
|
|
@ -19,9 +19,9 @@ const (
|
|||
BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir"
|
||||
)
|
||||
|
||||
func writePreamble(buf *bytes.Buffer, name string) {
|
||||
buf.WriteString(fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name))
|
||||
buf.WriteString(fmt.Sprintf(`
|
||||
func writePreamble(buf io.StringWriter, name string) {
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(`
|
||||
__%[1]s_debug()
|
||||
{
|
||||
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
|
||||
|
@ -380,10 +380,10 @@ __%[1]s_handle_word()
|
|||
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
|
||||
}
|
||||
|
||||
func writePostscript(buf *bytes.Buffer, name string) {
|
||||
func writePostscript(buf io.StringWriter, name string) {
|
||||
name = strings.Replace(name, ":", "__", -1)
|
||||
buf.WriteString(fmt.Sprintf("__start_%s()\n", name))
|
||||
buf.WriteString(fmt.Sprintf(`{
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("__start_%s()\n", name))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(`{
|
||||
local cur prev words cword
|
||||
declare -A flaghash 2>/dev/null || :
|
||||
declare -A aliashash 2>/dev/null || :
|
||||
|
@ -410,33 +410,33 @@ func writePostscript(buf *bytes.Buffer, name string) {
|
|||
}
|
||||
|
||||
`, name))
|
||||
buf.WriteString(fmt.Sprintf(`if [[ $(type -t compopt) = "builtin" ]]; then
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(`if [[ $(type -t compopt) = "builtin" ]]; then
|
||||
complete -o default -F __start_%s %s
|
||||
else
|
||||
complete -o default -o nospace -F __start_%s %s
|
||||
fi
|
||||
|
||||
`, name, name, name, name))
|
||||
buf.WriteString("# ex: ts=4 sw=4 et filetype=sh\n")
|
||||
WriteStringAndCheck(buf, "# ex: ts=4 sw=4 et filetype=sh\n")
|
||||
}
|
||||
|
||||
func writeCommands(buf *bytes.Buffer, cmd *Command) {
|
||||
buf.WriteString(" commands=()\n")
|
||||
func writeCommands(buf io.StringWriter, cmd *Command) {
|
||||
WriteStringAndCheck(buf, " commands=()\n")
|
||||
for _, c := range cmd.Commands() {
|
||||
if !c.IsAvailableCommand() && c != cmd.helpCommand {
|
||||
continue
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name()))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" commands+=(%q)\n", c.Name()))
|
||||
writeCmdAliases(buf, c)
|
||||
}
|
||||
buf.WriteString("\n")
|
||||
WriteStringAndCheck(buf, "\n")
|
||||
}
|
||||
|
||||
func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]string, cmd *Command) {
|
||||
func writeFlagHandler(buf io.StringWriter, name string, annotations map[string][]string, cmd *Command) {
|
||||
for key, value := range annotations {
|
||||
switch key {
|
||||
case BashCompFilenameExt:
|
||||
buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
|
||||
|
||||
var ext string
|
||||
if len(value) > 0 {
|
||||
|
@ -444,17 +444,18 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s
|
|||
} else {
|
||||
ext = "_filedir"
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" flags_completion+=(%q)\n", ext))
|
||||
case BashCompCustom:
|
||||
buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
|
||||
|
||||
if len(value) > 0 {
|
||||
handlers := strings.Join(value, "; ")
|
||||
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", handlers))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" flags_completion+=(%q)\n", handlers))
|
||||
} else {
|
||||
buf.WriteString(" flags_completion+=(:)\n")
|
||||
WriteStringAndCheck(buf, " flags_completion+=(:)\n")
|
||||
}
|
||||
case BashCompSubdirsInDir:
|
||||
buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
|
||||
|
||||
var ext string
|
||||
if len(value) == 1 {
|
||||
|
@ -462,46 +463,48 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s
|
|||
} else {
|
||||
ext = "_filedir -d"
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" flags_completion+=(%q)\n", ext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func writeShortFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) {
|
||||
const cbn = "\")\n"
|
||||
|
||||
func writeShortFlag(buf io.StringWriter, flag *pflag.Flag, cmd *Command) {
|
||||
name := flag.Shorthand
|
||||
format := " "
|
||||
if len(flag.NoOptDefVal) == 0 {
|
||||
format += "two_word_"
|
||||
}
|
||||
format += "flags+=(\"-%s\")\n"
|
||||
buf.WriteString(fmt.Sprintf(format, name))
|
||||
format += "flags+=(\"-%s" + cbn
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(format, name))
|
||||
writeFlagHandler(buf, "-"+name, flag.Annotations, cmd)
|
||||
}
|
||||
|
||||
func writeFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) {
|
||||
func writeFlag(buf io.StringWriter, flag *pflag.Flag, cmd *Command) {
|
||||
name := flag.Name
|
||||
format := " flags+=(\"--%s"
|
||||
if len(flag.NoOptDefVal) == 0 {
|
||||
format += "="
|
||||
}
|
||||
format += "\")\n"
|
||||
buf.WriteString(fmt.Sprintf(format, name))
|
||||
format += cbn
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(format, name))
|
||||
if len(flag.NoOptDefVal) == 0 {
|
||||
format = " two_word_flags+=(\"--%s\")\n"
|
||||
buf.WriteString(fmt.Sprintf(format, name))
|
||||
format = " two_word_flags+=(\"--%s" + cbn
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(format, name))
|
||||
}
|
||||
writeFlagHandler(buf, "--"+name, flag.Annotations, cmd)
|
||||
}
|
||||
|
||||
func writeLocalNonPersistentFlag(buf *bytes.Buffer, flag *pflag.Flag) {
|
||||
func writeLocalNonPersistentFlag(buf io.StringWriter, flag *pflag.Flag) {
|
||||
name := flag.Name
|
||||
format := " local_nonpersistent_flags+=(\"--%[1]s\")\n"
|
||||
format := " local_nonpersistent_flags+=(\"--%[1]s" + cbn
|
||||
if len(flag.NoOptDefVal) == 0 {
|
||||
format += " local_nonpersistent_flags+=(\"--%[1]s=\")\n"
|
||||
format += " local_nonpersistent_flags+=(\"--%[1]s=" + cbn
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(format, name))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(format, name))
|
||||
if len(flag.Shorthand) > 0 {
|
||||
buf.WriteString(fmt.Sprintf(" local_nonpersistent_flags+=(\"-%s\")\n", flag.Shorthand))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" local_nonpersistent_flags+=(\"-%s\")\n", flag.Shorthand))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -519,9 +522,9 @@ func prepareCustomAnnotationsForFlags(cmd *Command) {
|
|||
}
|
||||
}
|
||||
|
||||
func writeFlags(buf *bytes.Buffer, cmd *Command) {
|
||||
func writeFlags(buf io.StringWriter, cmd *Command) {
|
||||
prepareCustomAnnotationsForFlags(cmd)
|
||||
buf.WriteString(` flags=()
|
||||
WriteStringAndCheck(buf, ` flags=()
|
||||
two_word_flags=()
|
||||
local_nonpersistent_flags=()
|
||||
flags_with_completion=()
|
||||
|
@ -553,11 +556,11 @@ func writeFlags(buf *bytes.Buffer, cmd *Command) {
|
|||
}
|
||||
})
|
||||
|
||||
buf.WriteString("\n")
|
||||
WriteStringAndCheck(buf, "\n")
|
||||
}
|
||||
|
||||
func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) {
|
||||
buf.WriteString(" must_have_one_flag=()\n")
|
||||
func writeRequiredFlag(buf io.StringWriter, cmd *Command) {
|
||||
WriteStringAndCheck(buf, " must_have_one_flag=()\n")
|
||||
flags := cmd.NonInheritedFlags()
|
||||
flags.VisitAll(func(flag *pflag.Flag) {
|
||||
if nonCompletableFlag(flag) {
|
||||
|
@ -570,55 +573,55 @@ func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) {
|
|||
if flag.Value.Type() != "bool" {
|
||||
format += "="
|
||||
}
|
||||
format += "\")\n"
|
||||
buf.WriteString(fmt.Sprintf(format, flag.Name))
|
||||
format += cbn
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(format, flag.Name))
|
||||
|
||||
if len(flag.Shorthand) > 0 {
|
||||
buf.WriteString(fmt.Sprintf(" must_have_one_flag+=(\"-%s\")\n", flag.Shorthand))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" must_have_one_flag+=(\"-%s"+cbn, flag.Shorthand))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) {
|
||||
buf.WriteString(" must_have_one_noun=()\n")
|
||||
sort.Sort(sort.StringSlice(cmd.ValidArgs))
|
||||
func writeRequiredNouns(buf io.StringWriter, cmd *Command) {
|
||||
WriteStringAndCheck(buf, " must_have_one_noun=()\n")
|
||||
sort.Strings(cmd.ValidArgs)
|
||||
for _, value := range cmd.ValidArgs {
|
||||
// Remove any description that may be included following a tab character.
|
||||
// Descriptions are not supported by bash completion.
|
||||
value = strings.Split(value, "\t")[0]
|
||||
buf.WriteString(fmt.Sprintf(" must_have_one_noun+=(%q)\n", value))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" must_have_one_noun+=(%q)\n", value))
|
||||
}
|
||||
if cmd.ValidArgsFunction != nil {
|
||||
buf.WriteString(" has_completion_function=1\n")
|
||||
WriteStringAndCheck(buf, " has_completion_function=1\n")
|
||||
}
|
||||
}
|
||||
|
||||
func writeCmdAliases(buf *bytes.Buffer, cmd *Command) {
|
||||
func writeCmdAliases(buf io.StringWriter, cmd *Command) {
|
||||
if len(cmd.Aliases) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
sort.Sort(sort.StringSlice(cmd.Aliases))
|
||||
sort.Strings(cmd.Aliases)
|
||||
|
||||
buf.WriteString(fmt.Sprint(` if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then`, "\n"))
|
||||
WriteStringAndCheck(buf, 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()))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" command_aliases+=(%q)\n", value))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name()))
|
||||
}
|
||||
buf.WriteString(` fi`)
|
||||
buf.WriteString("\n")
|
||||
WriteStringAndCheck(buf, ` fi`)
|
||||
WriteStringAndCheck(buf, "\n")
|
||||
}
|
||||
func writeArgAliases(buf *bytes.Buffer, cmd *Command) {
|
||||
buf.WriteString(" noun_aliases=()\n")
|
||||
sort.Sort(sort.StringSlice(cmd.ArgAliases))
|
||||
func writeArgAliases(buf io.StringWriter, cmd *Command) {
|
||||
WriteStringAndCheck(buf, " noun_aliases=()\n")
|
||||
sort.Strings(cmd.ArgAliases)
|
||||
for _, value := range cmd.ArgAliases {
|
||||
buf.WriteString(fmt.Sprintf(" noun_aliases+=(%q)\n", value))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" noun_aliases+=(%q)\n", value))
|
||||
}
|
||||
}
|
||||
|
||||
func gen(buf *bytes.Buffer, cmd *Command) {
|
||||
func gen(buf io.StringWriter, cmd *Command) {
|
||||
for _, c := range cmd.Commands() {
|
||||
if !c.IsAvailableCommand() && c != cmd.helpCommand {
|
||||
continue
|
||||
|
@ -630,22 +633,22 @@ func gen(buf *bytes.Buffer, cmd *Command) {
|
|||
commandName = strings.Replace(commandName, ":", "__", -1)
|
||||
|
||||
if cmd.Root() == cmd {
|
||||
buf.WriteString(fmt.Sprintf("_%s_root_command()\n{\n", commandName))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("_%s_root_command()\n{\n", commandName))
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("_%s()\n{\n", commandName))
|
||||
}
|
||||
|
||||
buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName))
|
||||
buf.WriteString("\n")
|
||||
buf.WriteString(" command_aliases=()\n")
|
||||
buf.WriteString("\n")
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" last_command=%q\n", commandName))
|
||||
WriteStringAndCheck(buf, "\n")
|
||||
WriteStringAndCheck(buf, " command_aliases=()\n")
|
||||
WriteStringAndCheck(buf, "\n")
|
||||
|
||||
writeCommands(buf, cmd)
|
||||
writeFlags(buf, cmd)
|
||||
writeRequiredFlag(buf, cmd)
|
||||
writeRequiredNouns(buf, cmd)
|
||||
writeArgAliases(buf, cmd)
|
||||
buf.WriteString("}\n\n")
|
||||
WriteStringAndCheck(buf, "}\n\n")
|
||||
}
|
||||
|
||||
// GenBashCompletion generates bash completion file and writes to the passed writer.
|
||||
|
|
|
@ -19,6 +19,7 @@ package cobra
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -205,3 +206,17 @@ func stringInSlice(a string, list []string) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// CheckErr prints the msg with the prefix 'Error:' and exits with error code 1. If the msg is nil, it does nothing.
|
||||
func CheckErr(msg interface{}) {
|
||||
if msg != nil {
|
||||
fmt.Fprintln(os.Stderr, "Error:", msg)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// WriteStringAndCheck writes a string into a buffer, and checks if the error is not nil.
|
||||
func WriteStringAndCheck(b io.StringWriter, s string) {
|
||||
_, err := b.WriteString(s)
|
||||
CheckErr(err)
|
||||
}
|
||||
|
|
|
@ -84,9 +84,6 @@ type Command struct {
|
|||
// Deprecated defines, if this command is deprecated and should print this string when used.
|
||||
Deprecated string
|
||||
|
||||
// Hidden defines, if this command is hidden and should NOT show up in the list of available commands.
|
||||
Hidden bool
|
||||
|
||||
// Annotations are key/value pairs that can be used by applications to identify or
|
||||
// group commands.
|
||||
Annotations map[string]string
|
||||
|
@ -126,55 +123,6 @@ type Command struct {
|
|||
// PersistentPostRunE: PersistentPostRun but returns an error.
|
||||
PersistentPostRunE func(cmd *Command, args []string) error
|
||||
|
||||
// SilenceErrors is an option to quiet errors down stream.
|
||||
SilenceErrors bool
|
||||
|
||||
// SilenceUsage is an option to silence usage when an error occurs.
|
||||
SilenceUsage bool
|
||||
|
||||
// DisableFlagParsing disables the flag parsing.
|
||||
// If this is true all flags will be passed to the command as arguments.
|
||||
DisableFlagParsing bool
|
||||
|
||||
// DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...")
|
||||
// will be printed by generating docs for this command.
|
||||
DisableAutoGenTag bool
|
||||
|
||||
// DisableFlagsInUseLine will disable the addition of [flags] to the usage
|
||||
// line of a command when printing help or generating docs
|
||||
DisableFlagsInUseLine bool
|
||||
|
||||
// DisableSuggestions disables the suggestions based on Levenshtein distance
|
||||
// that go along with 'unknown command' messages.
|
||||
DisableSuggestions bool
|
||||
// SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions.
|
||||
// Must be > 0.
|
||||
SuggestionsMinimumDistance int
|
||||
|
||||
// TraverseChildren parses flags on all parents before executing child command.
|
||||
TraverseChildren bool
|
||||
|
||||
// FParseErrWhitelist flag parse errors to be ignored
|
||||
FParseErrWhitelist FParseErrWhitelist
|
||||
|
||||
ctx context.Context
|
||||
|
||||
// commands is the list of commands supported by this program.
|
||||
commands []*Command
|
||||
// parent is a parent command for this command.
|
||||
parent *Command
|
||||
// Max lengths of commands' string lengths for use in padding.
|
||||
commandsMaxUseLen int
|
||||
commandsMaxCommandPathLen int
|
||||
commandsMaxNameLen int
|
||||
// commandsAreSorted defines, if command slice are sorted or not.
|
||||
commandsAreSorted bool
|
||||
// commandCalledAs is the name or alias value used to call this command.
|
||||
commandCalledAs struct {
|
||||
name string
|
||||
called bool
|
||||
}
|
||||
|
||||
// args is actual args parsed from flags.
|
||||
args []string
|
||||
// flagErrorBuf contains all error messages from pflag.
|
||||
|
@ -216,6 +164,60 @@ type Command struct {
|
|||
outWriter io.Writer
|
||||
// errWriter is a writer defined by the user that replaces stderr
|
||||
errWriter io.Writer
|
||||
|
||||
//FParseErrWhitelist flag parse errors to be ignored
|
||||
FParseErrWhitelist FParseErrWhitelist
|
||||
|
||||
// commandsAreSorted defines, if command slice are sorted or not.
|
||||
commandsAreSorted bool
|
||||
// commandCalledAs is the name or alias value used to call this command.
|
||||
commandCalledAs struct {
|
||||
name string
|
||||
called bool
|
||||
}
|
||||
|
||||
ctx context.Context
|
||||
|
||||
// commands is the list of commands supported by this program.
|
||||
commands []*Command
|
||||
// parent is a parent command for this command.
|
||||
parent *Command
|
||||
// Max lengths of commands' string lengths for use in padding.
|
||||
commandsMaxUseLen int
|
||||
commandsMaxCommandPathLen int
|
||||
commandsMaxNameLen int
|
||||
|
||||
// TraverseChildren parses flags on all parents before executing child command.
|
||||
TraverseChildren bool
|
||||
|
||||
// Hidden defines, if this command is hidden and should NOT show up in the list of available commands.
|
||||
Hidden bool
|
||||
|
||||
// SilenceErrors is an option to quiet errors down stream.
|
||||
SilenceErrors bool
|
||||
|
||||
// SilenceUsage is an option to silence usage when an error occurs.
|
||||
SilenceUsage bool
|
||||
|
||||
// DisableFlagParsing disables the flag parsing.
|
||||
// If this is true all flags will be passed to the command as arguments.
|
||||
DisableFlagParsing bool
|
||||
|
||||
// DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...")
|
||||
// will be printed by generating docs for this command.
|
||||
DisableAutoGenTag bool
|
||||
|
||||
// DisableFlagsInUseLine will disable the addition of [flags] to the usage
|
||||
// line of a command when printing help or generating docs
|
||||
DisableFlagsInUseLine bool
|
||||
|
||||
// DisableSuggestions disables the suggestions based on Levenshtein distance
|
||||
// that go along with 'unknown command' messages.
|
||||
DisableSuggestions bool
|
||||
|
||||
// SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions.
|
||||
// Must be > 0.
|
||||
SuggestionsMinimumDistance int
|
||||
}
|
||||
|
||||
// Context returns underlying command context. If command wasn't
|
||||
|
@ -418,7 +420,7 @@ func (c *Command) UsageString() string {
|
|||
c.outWriter = bb
|
||||
c.errWriter = bb
|
||||
|
||||
c.Usage()
|
||||
CheckErr(c.Usage())
|
||||
|
||||
// Setting things back to normal
|
||||
c.outWriter = tmpOutput
|
||||
|
@ -964,13 +966,13 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
|
|||
return cmd, nil
|
||||
}
|
||||
|
||||
// If root command has SilentErrors flagged,
|
||||
// If root command has SilenceErrors flagged,
|
||||
// all subcommands should respect it
|
||||
if !cmd.SilenceErrors && !c.SilenceErrors {
|
||||
c.PrintErrln("Error:", err.Error())
|
||||
}
|
||||
|
||||
// If root command has SilentUsage flagged,
|
||||
// If root command has SilenceUsage flagged,
|
||||
// all subcommands should respect it
|
||||
if !cmd.SilenceUsage && !c.SilenceUsage {
|
||||
c.Println(cmd.UsageString())
|
||||
|
@ -1087,10 +1089,10 @@ Simply type ` + c.Name() + ` help [path to command] for full details.`,
|
|||
cmd, _, e := c.Root().Find(args)
|
||||
if cmd == nil || e != nil {
|
||||
c.Printf("Unknown help topic %#q\n", args)
|
||||
c.Root().Usage()
|
||||
CheckErr(c.Root().Usage())
|
||||
} else {
|
||||
cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown
|
||||
cmd.Help()
|
||||
CheckErr(cmd.Help())
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -527,13 +527,13 @@ func CompDebug(msg string, printToStdErr bool) {
|
|||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err == nil {
|
||||
defer f.Close()
|
||||
f.WriteString(msg)
|
||||
WriteStringAndCheck(f, msg)
|
||||
}
|
||||
}
|
||||
|
||||
if printToStdErr {
|
||||
// Must print to stderr for this not to be read by the completion script.
|
||||
fmt.Fprintf(os.Stderr, msg)
|
||||
fmt.Fprint(os.Stderr, msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -139,23 +139,23 @@ func fillHeader(header *GenManHeader, name string, disableAutoGen bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func manPreamble(buf *bytes.Buffer, header *GenManHeader, cmd *cobra.Command, dashedName string) {
|
||||
func manPreamble(buf io.StringWriter, header *GenManHeader, cmd *cobra.Command, dashedName string) {
|
||||
description := cmd.Long
|
||||
if len(description) == 0 {
|
||||
description = cmd.Short
|
||||
}
|
||||
|
||||
buf.WriteString(fmt.Sprintf(`%% "%s" "%s" "%s" "%s" "%s"
|
||||
cobra.WriteStringAndCheck(buf, fmt.Sprintf(`%% "%s" "%s" "%s" "%s" "%s"
|
||||
# NAME
|
||||
`, header.Title, header.Section, header.date, header.Source, header.Manual))
|
||||
buf.WriteString(fmt.Sprintf("%s \\- %s\n\n", dashedName, cmd.Short))
|
||||
buf.WriteString("# SYNOPSIS\n")
|
||||
buf.WriteString(fmt.Sprintf("**%s**\n\n", cmd.UseLine()))
|
||||
buf.WriteString("# DESCRIPTION\n")
|
||||
buf.WriteString(description + "\n\n")
|
||||
cobra.WriteStringAndCheck(buf, fmt.Sprintf("%s \\- %s\n\n", dashedName, cmd.Short))
|
||||
cobra.WriteStringAndCheck(buf, "# SYNOPSIS\n")
|
||||
cobra.WriteStringAndCheck(buf, fmt.Sprintf("**%s**\n\n", cmd.UseLine()))
|
||||
cobra.WriteStringAndCheck(buf, "# DESCRIPTION\n")
|
||||
cobra.WriteStringAndCheck(buf, description+"\n\n")
|
||||
}
|
||||
|
||||
func manPrintFlags(buf *bytes.Buffer, flags *pflag.FlagSet) {
|
||||
func manPrintFlags(buf io.StringWriter, flags *pflag.FlagSet) {
|
||||
flags.VisitAll(func(flag *pflag.Flag) {
|
||||
if len(flag.Deprecated) > 0 || flag.Hidden {
|
||||
return
|
||||
|
@ -179,22 +179,22 @@ func manPrintFlags(buf *bytes.Buffer, flags *pflag.FlagSet) {
|
|||
format += "]"
|
||||
}
|
||||
format += "\n\t%s\n\n"
|
||||
buf.WriteString(fmt.Sprintf(format, flag.DefValue, flag.Usage))
|
||||
cobra.WriteStringAndCheck(buf, fmt.Sprintf(format, flag.DefValue, flag.Usage))
|
||||
})
|
||||
}
|
||||
|
||||
func manPrintOptions(buf *bytes.Buffer, command *cobra.Command) {
|
||||
func manPrintOptions(buf io.StringWriter, command *cobra.Command) {
|
||||
flags := command.NonInheritedFlags()
|
||||
if flags.HasAvailableFlags() {
|
||||
buf.WriteString("# OPTIONS\n")
|
||||
cobra.WriteStringAndCheck(buf, "# OPTIONS\n")
|
||||
manPrintFlags(buf, flags)
|
||||
buf.WriteString("\n")
|
||||
cobra.WriteStringAndCheck(buf, "\n")
|
||||
}
|
||||
flags = command.InheritedFlags()
|
||||
if flags.HasAvailableFlags() {
|
||||
buf.WriteString("# OPTIONS INHERITED FROM PARENT COMMANDS\n")
|
||||
cobra.WriteStringAndCheck(buf, "# OPTIONS INHERITED FROM PARENT COMMANDS\n")
|
||||
manPrintFlags(buf, flags)
|
||||
buf.WriteString("\n")
|
||||
cobra.WriteStringAndCheck(buf, "\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
func genFishComp(buf *bytes.Buffer, name string, includeDesc bool) {
|
||||
func genFishComp(buf io.StringWriter, name string, includeDesc bool) {
|
||||
// Variables should not contain a '-' or ':' character
|
||||
nameForVar := name
|
||||
nameForVar = strings.Replace(nameForVar, "-", "_", -1)
|
||||
|
@ -18,8 +18,8 @@ func genFishComp(buf *bytes.Buffer, name string, includeDesc bool) {
|
|||
if !includeDesc {
|
||||
compCmd = ShellCompNoDescRequestCmd
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("# fish completion for %-36s -*- shell-script -*-\n", name))
|
||||
buf.WriteString(fmt.Sprintf(`
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("# fish completion for %-36s -*- shell-script -*-\n", name))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(`
|
||||
function __%[1]s_debug
|
||||
set file "$BASH_COMP_DEBUG_FILE"
|
||||
if test -n "$file"
|
||||
|
|
|
@ -8,5 +8,5 @@ require (
|
|||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.7.0
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// PowerShell completions are based on the amazing work from clap:
|
||||
// https://github.com/clap-rs/clap/blob/3294d18efe5f264d12c9035f404c7d189d4824e1/src/completions/powershell.rs
|
||||
//
|
||||
// The generated scripts require PowerShell v5.0+ (which comes Windows 10, but
|
||||
// can be downloaded separately for windows 7 or 8.1).
|
||||
|
||||
|
@ -11,90 +8,278 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var powerShellCompletionTemplate = `using namespace System.Management.Automation
|
||||
using namespace System.Management.Automation.Language
|
||||
Register-ArgumentCompleter -Native -CommandName '%s' -ScriptBlock {
|
||||
param($wordToComplete, $commandAst, $cursorPosition)
|
||||
$commandElements = $commandAst.CommandElements
|
||||
$command = @(
|
||||
'%s'
|
||||
for ($i = 1; $i -lt $commandElements.Count; $i++) {
|
||||
$element = $commandElements[$i]
|
||||
if ($element -isnot [StringConstantExpressionAst] -or
|
||||
$element.StringConstantType -ne [StringConstantType]::BareWord -or
|
||||
$element.Value.StartsWith('-')) {
|
||||
break
|
||||
func genPowerShellComp(buf io.StringWriter, name string, includeDesc bool) {
|
||||
compCmd := ShellCompRequestCmd
|
||||
if !includeDesc {
|
||||
compCmd = ShellCompNoDescRequestCmd
|
||||
}
|
||||
$element.Value
|
||||
}
|
||||
) -join ';'
|
||||
$completions = @(switch ($command) {%s
|
||||
})
|
||||
$completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
|
||||
Sort-Object -Property ListItemText
|
||||
}`
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(`# powershell completion for %-36[1]s -*- shell-script -*-
|
||||
|
||||
func generatePowerShellSubcommandCases(out io.Writer, cmd *Command, previousCommandName string) {
|
||||
var cmdName string
|
||||
if previousCommandName == "" {
|
||||
cmdName = cmd.Name()
|
||||
} else {
|
||||
cmdName = fmt.Sprintf("%s;%s", previousCommandName, cmd.Name())
|
||||
function __%[1]s_debug {
|
||||
if ($env:BASH_COMP_DEBUG_FILE) {
|
||||
"$args" | Out-File -Append -FilePath "$env:BASH_COMP_DEBUG_FILE"
|
||||
}
|
||||
}
|
||||
|
||||
filter __%[1]s_escapeStringWithSpecialChars {
|
||||
`+" $_ -replace '\\s|#|@|\\$|;|,|''|\\{|\\}|\\(|\\)|\"|`|\\||<|>|&','`$&'"+`
|
||||
}
|
||||
|
||||
Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock {
|
||||
param(
|
||||
$WordToComplete,
|
||||
$CommandAst,
|
||||
$CursorPosition
|
||||
)
|
||||
|
||||
# Get the current command line and convert into a string
|
||||
$Command = $CommandAst.CommandElements
|
||||
$Command = "$Command"
|
||||
|
||||
__%[1]s_debug ""
|
||||
__%[1]s_debug "========= starting completion logic =========="
|
||||
__%[1]s_debug "WordToComplete: $WordToComplete Command: $Command CursorPosition: $CursorPosition"
|
||||
|
||||
# The user could have moved the cursor backwards on the command-line.
|
||||
# We need to trigger completion from the $CursorPosition location, so we need
|
||||
# to truncate the command-line ($Command) up to the $CursorPosition location.
|
||||
# Make sure the $Command is longer then the $CursorPosition before we truncate.
|
||||
# This happens because the $Command does not include the last space.
|
||||
if ($Command.Length -gt $CursorPosition) {
|
||||
$Command=$Command.Substring(0,$CursorPosition)
|
||||
}
|
||||
__%[1]s_debug "Truncated command: $Command"
|
||||
|
||||
$ShellCompDirectiveError=%[3]d
|
||||
$ShellCompDirectiveNoSpace=%[4]d
|
||||
$ShellCompDirectiveNoFileComp=%[5]d
|
||||
$ShellCompDirectiveFilterFileExt=%[6]d
|
||||
$ShellCompDirectiveFilterDirs=%[7]d
|
||||
|
||||
# Prepare the command to request completions for the program.
|
||||
# Split the command at the first space to separate the program and arguments.
|
||||
$Program,$Arguments = $Command.Split(" ",2)
|
||||
$RequestComp="$Program %[2]s $Arguments"
|
||||
__%[1]s_debug "RequestComp: $RequestComp"
|
||||
|
||||
# we cannot use $WordToComplete because it
|
||||
# has the wrong values if the cursor was moved
|
||||
# so use the last argument
|
||||
if ($WordToComplete -ne "" ) {
|
||||
$WordToComplete = $Arguments.Split(" ")[-1]
|
||||
}
|
||||
__%[1]s_debug "New WordToComplete: $WordToComplete"
|
||||
|
||||
|
||||
# Check for flag with equal sign
|
||||
$IsEqualFlag = ($WordToComplete -Like "--*=*" )
|
||||
if ( $IsEqualFlag ) {
|
||||
__%[1]s_debug "Completing equal sign flag"
|
||||
# Remove the flag part
|
||||
$Flag,$WordToComplete = $WordToComplete.Split("=",2)
|
||||
}
|
||||
|
||||
fmt.Fprintf(out, "\n '%s' {", cmdName)
|
||||
if ( $WordToComplete -eq "" -And ( -Not $IsEqualFlag )) {
|
||||
# If the last parameter is complete (there is a space following it)
|
||||
# We add an extra empty parameter so we can indicate this to the go method.
|
||||
__%[1]s_debug "Adding extra empty parameter"
|
||||
`+" # We need to use `\"`\" to pass an empty argument a \"\" or '' does not work!!!"+`
|
||||
`+" $RequestComp=\"$RequestComp\" + ' `\"`\"' "+`
|
||||
}
|
||||
|
||||
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
|
||||
if nonCompletableFlag(flag) {
|
||||
__%[1]s_debug "Calling $RequestComp"
|
||||
#call the command store the output in $out and redirect stderr and stdout to null
|
||||
# $Out is an array contains each line per element
|
||||
Invoke-Expression -OutVariable out "$RequestComp" 2>&1 | Out-Null
|
||||
|
||||
|
||||
# get directive from last line
|
||||
[int]$Directive = $Out[-1].TrimStart(':')
|
||||
if ($Directive -eq "") {
|
||||
# There is no directive specified
|
||||
$Directive = 0
|
||||
}
|
||||
__%[1]s_debug "The completion directive is: $Directive"
|
||||
|
||||
# remove directive (last element) from out
|
||||
$Out = $Out | Where-Object { $_ -ne $Out[-1] }
|
||||
__%[1]s_debug "The completions are: $Out"
|
||||
|
||||
if (($Directive -band $ShellCompDirectiveError) -ne 0 ) {
|
||||
# Error code. No completion.
|
||||
__%[1]s_debug "Received error from custom completion go code"
|
||||
return
|
||||
}
|
||||
usage := escapeStringForPowerShell(flag.Usage)
|
||||
if len(flag.Shorthand) > 0 {
|
||||
fmt.Fprintf(out, "\n [CompletionResult]::new('-%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Shorthand, flag.Shorthand, usage)
|
||||
}
|
||||
fmt.Fprintf(out, "\n [CompletionResult]::new('--%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Name, flag.Name, usage)
|
||||
})
|
||||
|
||||
for _, subCmd := range cmd.Commands() {
|
||||
usage := escapeStringForPowerShell(subCmd.Short)
|
||||
fmt.Fprintf(out, "\n [CompletionResult]::new('%s', '%s', [CompletionResultType]::ParameterValue, '%s')", subCmd.Name(), subCmd.Name(), usage)
|
||||
$Longest = 0
|
||||
$Values = $Out | ForEach-Object {
|
||||
#Split the output in name and description
|
||||
`+" $Name, $Description = $_.Split(\"`t\",2)"+`
|
||||
__%[1]s_debug "Name: $Name Description: $Description"
|
||||
|
||||
# Look for the longest completion so that we can format things nicely
|
||||
if ($Longest -lt $Name.Length) {
|
||||
$Longest = $Name.Length
|
||||
}
|
||||
|
||||
fmt.Fprint(out, "\n break\n }")
|
||||
# Set the description to a one space string if there is none set.
|
||||
# This is needed because the CompletionResult does not accept an empty string as argument
|
||||
if (-Not $Description) {
|
||||
$Description = " "
|
||||
}
|
||||
@{Name="$Name";Description="$Description"}
|
||||
}
|
||||
|
||||
|
||||
$Space = " "
|
||||
if (($Directive -band $ShellCompDirectiveNoSpace) -ne 0 ) {
|
||||
# remove the space here
|
||||
__%[1]s_debug "ShellCompDirectiveNoSpace is called"
|
||||
$Space = ""
|
||||
}
|
||||
|
||||
if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) {
|
||||
__%[1]s_debug "ShellCompDirectiveNoFileComp is called"
|
||||
|
||||
if ($Values.Length -eq 0) {
|
||||
# Just print an empty string here so the
|
||||
# shell does not start to complete paths.
|
||||
# We cannot use CompletionResult here because
|
||||
# it does not accept an empty string as argument.
|
||||
""
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if ((($Directive -band $ShellCompDirectiveFilterFileExt) -ne 0 ) -or
|
||||
(($Directive -band $ShellCompDirectiveFilterDirs) -ne 0 )) {
|
||||
__%[1]s_debug "ShellCompDirectiveFilterFileExt ShellCompDirectiveFilterDirs are not supported"
|
||||
|
||||
# return here to prevent the completion of the extensions
|
||||
return
|
||||
}
|
||||
|
||||
$Values = $Values | Where-Object {
|
||||
# filter the result
|
||||
$_.Name -like "$WordToComplete*"
|
||||
|
||||
# Join the flag back if we have a equal sign flag
|
||||
if ( $IsEqualFlag ) {
|
||||
__%[1]s_debug "Join the equal sign flag back to the completion value"
|
||||
$_.Name = $Flag + "=" + $_.Name
|
||||
}
|
||||
}
|
||||
|
||||
# Get the current mode
|
||||
$Mode = (Get-PSReadLineKeyHandler | Where-Object {$_.Key -eq "Tab" }).Function
|
||||
__%[1]s_debug "Mode: $Mode"
|
||||
|
||||
$Values | ForEach-Object {
|
||||
|
||||
# store temporay because switch will overwrite $_
|
||||
$comp = $_
|
||||
|
||||
# PowerShell supports three different completion modes
|
||||
# - TabCompleteNext (default windows style - on each key press the next option is displayed)
|
||||
# - Complete (works like bash)
|
||||
# - MenuComplete (works like zsh)
|
||||
# You set the mode with Set-PSReadLineKeyHandler -Key Tab -Function <mode>
|
||||
|
||||
# CompletionResult Arguments:
|
||||
# 1) CompletionText text to be used as the auto completion result
|
||||
# 2) ListItemText text to be displayed in the suggestion list
|
||||
# 3) ResultType type of completion result
|
||||
# 4) ToolTip text for the tooltip with details about the object
|
||||
|
||||
switch ($Mode) {
|
||||
|
||||
# bash like
|
||||
"Complete" {
|
||||
|
||||
if ($Values.Length -eq 1) {
|
||||
__%[1]s_debug "Only one completion left"
|
||||
|
||||
# insert space after value
|
||||
[System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
|
||||
|
||||
} else {
|
||||
# Add the proper number of spaces to align the descriptions
|
||||
while($comp.Name.Length -lt $Longest) {
|
||||
$comp.Name = $comp.Name + " "
|
||||
}
|
||||
|
||||
# Check for empty description and only add parentheses if needed
|
||||
if ($($comp.Description) -eq " " ) {
|
||||
$Description = ""
|
||||
} else {
|
||||
$Description = " ($($comp.Description))"
|
||||
}
|
||||
|
||||
[System.Management.Automation.CompletionResult]::new("$($comp.Name)$Description", "$($comp.Name)$Description", 'ParameterValue', "$($comp.Description)")
|
||||
}
|
||||
}
|
||||
|
||||
# zsh like
|
||||
"MenuComplete" {
|
||||
# insert space after value
|
||||
# MenuComplete will automatically show the ToolTip of
|
||||
# the highlighted value at the bottom of the suggestions.
|
||||
[System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
|
||||
}
|
||||
|
||||
# TabCompleteNext and in case we get something unknown
|
||||
Default {
|
||||
# Like MenuComplete but we don't want to add a space here because
|
||||
# the user need to press space anyway to get the completion.
|
||||
# Description will not be shown because thats not possible with TabCompleteNext
|
||||
[System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars), "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
|
||||
}
|
||||
}
|
||||
|
||||
for _, subCmd := range cmd.Commands() {
|
||||
generatePowerShellSubcommandCases(out, subCmd, cmdName)
|
||||
}
|
||||
}
|
||||
|
||||
func escapeStringForPowerShell(s string) string {
|
||||
return strings.Replace(s, "'", "''", -1)
|
||||
`, name, compCmd,
|
||||
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
|
||||
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
|
||||
}
|
||||
|
||||
// GenPowerShellCompletion generates PowerShell completion file and writes to the passed writer.
|
||||
func (c *Command) GenPowerShellCompletion(w io.Writer) error {
|
||||
func (c *Command) genPowerShellCompletion(w io.Writer, includeDesc bool) error {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
var subCommandCases bytes.Buffer
|
||||
generatePowerShellSubcommandCases(&subCommandCases, c, "")
|
||||
fmt.Fprintf(buf, powerShellCompletionTemplate, c.Name(), c.Name(), subCommandCases.String())
|
||||
|
||||
genPowerShellComp(buf, c.Name(), includeDesc)
|
||||
_, err := buf.WriteTo(w)
|
||||
return err
|
||||
}
|
||||
|
||||
// GenPowerShellCompletionFile generates PowerShell completion file.
|
||||
func (c *Command) GenPowerShellCompletionFile(filename string) error {
|
||||
func (c *Command) genPowerShellCompletionFile(filename string, includeDesc bool) error {
|
||||
outFile, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
return c.GenPowerShellCompletion(outFile)
|
||||
return c.genPowerShellCompletion(outFile, includeDesc)
|
||||
}
|
||||
|
||||
// GenPowerShellCompletionFile generates powershell completion file without descriptions.
|
||||
func (c *Command) GenPowerShellCompletionFile(filename string) error {
|
||||
return c.genPowerShellCompletionFile(filename, false)
|
||||
}
|
||||
|
||||
// GenPowerShellCompletion generates powershell completion file without descriptions
|
||||
// and writes it to the passed writer.
|
||||
func (c *Command) GenPowerShellCompletion(w io.Writer) error {
|
||||
return c.genPowerShellCompletion(w, false)
|
||||
}
|
||||
|
||||
// GenPowerShellCompletionFileWithDesc generates powershell completion file with descriptions.
|
||||
func (c *Command) GenPowerShellCompletionFileWithDesc(filename string) error {
|
||||
return c.genPowerShellCompletionFile(filename, true)
|
||||
}
|
||||
|
||||
// GenPowerShellCompletionWithDesc generates powershell completion file with descriptions
|
||||
// and writes it to the passed writer.
|
||||
func (c *Command) GenPowerShellCompletionWithDesc(w io.Writer) error {
|
||||
return c.genPowerShellCompletion(w, true)
|
||||
}
|
||||
|
|
|
@ -70,12 +70,12 @@ func (c *Command) genZshCompletion(w io.Writer, includeDesc bool) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func genZshComp(buf *bytes.Buffer, name string, includeDesc bool) {
|
||||
func genZshComp(buf io.StringWriter, name string, includeDesc bool) {
|
||||
compCmd := ShellCompRequestCmd
|
||||
if !includeDesc {
|
||||
compCmd = ShellCompNoDescRequestCmd
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(`#compdef _%[1]s %[1]s
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(`#compdef _%[1]s %[1]s
|
||||
|
||||
# zsh completion for %-36[1]s -*- shell-script -*-
|
||||
|
||||
|
|
Loading…
Reference in New Issue