mirror of
https://github.com/spf13/cobra.git
synced 2024-12-19 10:05:07 -07:00
Compare commits
36 Commits
ad7634be03
...
c4dadf0e5a
Author | SHA1 | Date | |
---|---|---|---|
|
c4dadf0e5a | ||
|
997ac04e61 | ||
|
da1bab9757 | ||
|
1df1dbd552 | ||
|
52185bed6e | ||
|
d728bbb91e | ||
|
14e642ede9 | ||
|
e0ac28fad8 | ||
|
93a41331ec | ||
|
470ca0a628 | ||
|
ddb39920b4 | ||
|
1886f6baad | ||
|
2f80e0879f | ||
|
18d7a29987 | ||
|
59726e2b0f | ||
|
982ba402cb | ||
|
7006719603 | ||
|
8b4aa590bb | ||
|
7eac0e11ae | ||
|
e7abbf39a3 | ||
|
29af015b57 | ||
|
f963733c4e | ||
|
1a69a83abc | ||
|
8cb9728476 | ||
|
ead0ff3e53 | ||
|
3bfdd6421f | ||
|
4c4bde6586 | ||
|
3b016843b9 | ||
|
247e8e6b55 | ||
|
d86bac4e34 | ||
|
fa746d4d5a | ||
|
37ac7454fb | ||
|
1324e0c316 | ||
|
2f276e3014 | ||
|
594faef23f | ||
|
a1431b2c57 |
@ -25,7 +25,7 @@ Cobra provides:
|
|||||||
* Automatic help generation for commands and flags
|
* Automatic help generation for commands and flags
|
||||||
* Grouping help for subcommands
|
* Grouping help for subcommands
|
||||||
* Automatic help flag recognition of `-h`, `--help`, etc.
|
* Automatic help flag recognition of `-h`, `--help`, etc.
|
||||||
* Automatically generated shell autocomplete for your application (bash, zsh, fish, powershell)
|
* Automatically generated shell autocomplete for your application (bash, zsh, fish, powershell, nushell)
|
||||||
* Automatically generated man pages for your application
|
* Automatically generated man pages for your application
|
||||||
* Command aliases so you can change things without breaking them
|
* Command aliases so you can change things without breaking them
|
||||||
* The flexibility to define your own help, usage, etc.
|
* The flexibility to define your own help, usage, etc.
|
||||||
|
@ -836,14 +836,46 @@ to your powershell profile.
|
|||||||
return cmd.Root().GenPowerShellCompletion(out)
|
return cmd.Root().GenPowerShellCompletion(out)
|
||||||
}
|
}
|
||||||
return cmd.Root().GenPowerShellCompletionWithDesc(out)
|
return cmd.Root().GenPowerShellCompletionWithDesc(out)
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if haveNoDescFlag {
|
if haveNoDescFlag {
|
||||||
powershell.Flags().BoolVar(&noDesc, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc)
|
powershell.Flags().BoolVar(&noDesc, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc)
|
||||||
}
|
}
|
||||||
|
|
||||||
completionCmd.AddCommand(bash, zsh, fish, powershell)
|
nushell := &Command{
|
||||||
|
Use: "nushell",
|
||||||
|
Short: fmt.Sprintf(shortDesc, "nushell"),
|
||||||
|
Long: fmt.Sprintf(`Generate the autocompletion script for nushell.
|
||||||
|
|
||||||
|
To configure the Nushell cobra external completer for the first time:
|
||||||
|
# 1. Edit the nushell config file:
|
||||||
|
> config nu
|
||||||
|
# 2. Copy the output of %[1]s completion nushell to the end of the file.
|
||||||
|
# 3. Add a section like the following below at the end of the file:
|
||||||
|
$env.config.completions.external = {
|
||||||
|
enable: true
|
||||||
|
max_results: 100
|
||||||
|
completer: $cobra_completer
|
||||||
|
}
|
||||||
|
|
||||||
|
This completer will work for all cobra based commands.
|
||||||
|
More information can be found in the External Completions section of the Nushell book:
|
||||||
|
https://www.nushell.sh/book/custom_completions.html#external-completions
|
||||||
|
|
||||||
|
Information on setting up more than one external completer can be found in the Multiple completer section of the Nushell cookbook:
|
||||||
|
https://www.nushell.sh/cookbook/external_completers.html#multiple-completer
|
||||||
|
`, c.Root().Name()),
|
||||||
|
Args: NoArgs,
|
||||||
|
ValidArgsFunction: NoFileCompletions,
|
||||||
|
RunE: func(cmd *Command, args []string) error {
|
||||||
|
return cmd.Root().GenNushellCompletion(out, !noDesc)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if haveNoDescFlag {
|
||||||
|
nushell.Flags().BoolVar(&noDesc, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc)
|
||||||
|
}
|
||||||
|
|
||||||
|
completionCmd.AddCommand(bash, zsh, fish, powershell, nushell)
|
||||||
}
|
}
|
||||||
|
|
||||||
func findFlag(cmd *Command, name string) *pflag.Flag {
|
func findFlag(cmd *Command, name string) *pflag.Flag {
|
||||||
@ -876,7 +908,7 @@ func CompDebug(msg string, printToStdErr bool) {
|
|||||||
// variable BASH_COMP_DEBUG_FILE to the path of some file to be used.
|
// variable BASH_COMP_DEBUG_FILE to the path of some file to be used.
|
||||||
if path := os.Getenv("BASH_COMP_DEBUG_FILE"); path != "" {
|
if path := os.Getenv("BASH_COMP_DEBUG_FILE"); path != "" {
|
||||||
f, err := os.OpenFile(path,
|
f, err := os.OpenFile(path,
|
||||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
WriteStringAndCheck(f, msg)
|
WriteStringAndCheck(f, msg)
|
||||||
|
@ -2577,6 +2577,7 @@ func TestCompleteCompletion(t *testing.T) {
|
|||||||
expected := strings.Join([]string{
|
expected := strings.Join([]string{
|
||||||
"bash",
|
"bash",
|
||||||
"fish",
|
"fish",
|
||||||
|
"nushell",
|
||||||
"powershell",
|
"powershell",
|
||||||
"zsh",
|
"zsh",
|
||||||
":4",
|
":4",
|
||||||
|
131
nushell_completions.go
Normal file
131
nushell_completions.go
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
// Copyright 2013-2022 The Cobra Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package cobra
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Command) GenNushellCompletion(w io.Writer, includeDesc bool) error {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
WriteStringAndCheck(buf, "# nushell completion -*- shell-script -*- \n")
|
||||||
|
WriteStringAndCheck(buf, fmt.Sprintf(`
|
||||||
|
let cobra_completer = {|spans|
|
||||||
|
let ShellCompDirectiveError = %[1]d
|
||||||
|
let ShellCompDirectiveNoSpace = %[2]d
|
||||||
|
let ShellCompDirectiveNoFileComp = %[3]d
|
||||||
|
let ShellCompDirectiveFilterFileExt = %[4]d
|
||||||
|
let ShellCompDirectiveFilterDirs = %[5]d
|
||||||
|
let ShellCompDirectiveKeepOrder = %[6]d
|
||||||
|
|
||||||
|
let cmd = $spans | first
|
||||||
|
let rest = $spans | skip
|
||||||
|
|
||||||
|
def cobra_log [message] {
|
||||||
|
let file = do -i {$env | get NUSHELL_COMP_DEBUG_FILE}
|
||||||
|
if $file != null {
|
||||||
|
echo $"($message)\n" | save $file --append
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cobra_log $"External Completer called for cmd ($cmd)"
|
||||||
|
|
||||||
|
def exec_complete [
|
||||||
|
spans: list<string>
|
||||||
|
] {
|
||||||
|
# This will catch the stderr message related to the directive and any other errors,
|
||||||
|
# such as the command not being a cobra based command
|
||||||
|
let result = do --ignore-errors { COBRA_ACTIVE_HELP=0 run-external $cmd "__complete" ...$spans | complete }
|
||||||
|
|
||||||
|
if $result != null and $result.exit_code == 0 {
|
||||||
|
let completions = $result.stdout | lines
|
||||||
|
|
||||||
|
# the directive is the last line
|
||||||
|
let directive = do -i { $completions | last | str replace ':' '' | into int }
|
||||||
|
|
||||||
|
let completions = $completions | drop | each { |it|
|
||||||
|
# the first word is the command, the rest is the description
|
||||||
|
let words = $it | split row -r '\s{1}'
|
||||||
|
|
||||||
|
# If the last span contains a hypen and equals, attach it to the name
|
||||||
|
let last_span = $spans | last
|
||||||
|
let words = if ($last_span =~ '^-') and ($last_span =~ '=$') {
|
||||||
|
$words | each {|it| $"($last_span)($it)" }
|
||||||
|
} else {
|
||||||
|
$words
|
||||||
|
}
|
||||||
|
|
||||||
|
{value: ($words | first | str trim), description: ($words | skip | str join ' ')}
|
||||||
|
}
|
||||||
|
|
||||||
|
{completions: $completions, directive: $directive}
|
||||||
|
} else {
|
||||||
|
{completions: [], directive: -1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not ($rest | is-empty)) {
|
||||||
|
let result = exec_complete $rest
|
||||||
|
let completions = $result.completions
|
||||||
|
let directive = $result.directive
|
||||||
|
|
||||||
|
# Add space at the end of each completion
|
||||||
|
let completions = if $directive != $ShellCompDirectiveNoSpace {
|
||||||
|
$completions | each {|it| {value: $"($it.value) ", description: $it.description}}
|
||||||
|
} else {
|
||||||
|
$completions
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cobra returns a list of completions that are supported with this directive
|
||||||
|
# There is no way to currently support this in a nushell external completer
|
||||||
|
let completions = if $directive == $ShellCompDirectiveFilterFileExt {
|
||||||
|
[]
|
||||||
|
} else {
|
||||||
|
$completions
|
||||||
|
}
|
||||||
|
|
||||||
|
if $directive == $ShellCompDirectiveNoFileComp {
|
||||||
|
# Allow empty results as this will stop file completion
|
||||||
|
$completions
|
||||||
|
} else if ($completions | is-empty) or $directive == $ShellCompDirectiveError {
|
||||||
|
# Not returning null causes file completions to break
|
||||||
|
# Return null if there are no completions or ShellCompDirectiveError
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
$completions
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
|
||||||
|
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder))
|
||||||
|
|
||||||
|
_, err := buf.WriteTo(w)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) GenNushellCompletionFile(filename string, includeDesc bool) error {
|
||||||
|
outFile, err := os.Create(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer outFile.Close()
|
||||||
|
|
||||||
|
return c.GenNushellCompletion(outFile, includeDesc)
|
||||||
|
}
|
98
nushell_completions_test.go
Normal file
98
nushell_completions_test.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// Copyright 2013-2022 The Cobra Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package cobra
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenNushellCompletion(t *testing.T) {
|
||||||
|
rootCmd := &Command{Use: "kubectl", Run: emptyRun}
|
||||||
|
rootCmd.PersistentFlags().String("server", "s", "The address and port of the Kubernetes API server")
|
||||||
|
rootCmd.PersistentFlags().BoolP("skip-headers", "", false, "The address and port of the Kubernetes API serverIf true, avoid header prefixes in the log messages")
|
||||||
|
getCmd := &Command{
|
||||||
|
Use: "get",
|
||||||
|
Short: "Display one or many resources",
|
||||||
|
ArgAliases: []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"},
|
||||||
|
ValidArgs: []string{"pod", "node", "service", "replicationcontroller"},
|
||||||
|
Run: emptyRun,
|
||||||
|
}
|
||||||
|
rootCmd.AddCommand(getCmd)
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
assertNoErr(t, rootCmd.GenNushellCompletion(buf, true))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenNushellCompletionFile(t *testing.T) {
|
||||||
|
tmpFile, err := os.CreateTemp("", "cobra-test")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
defer os.RemoveAll(tmpFile.Name())
|
||||||
|
|
||||||
|
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
|
||||||
|
child := &Command{
|
||||||
|
Use: "child",
|
||||||
|
ValidArgsFunction: validArgsFunc,
|
||||||
|
Run: emptyRun,
|
||||||
|
}
|
||||||
|
rootCmd.AddCommand(child)
|
||||||
|
|
||||||
|
assertNoErr(t, rootCmd.GenNushellCompletionFile(tmpFile.Name(), true))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFailGenNushellCompletionFile(t *testing.T) {
|
||||||
|
tmpDir, err := os.MkdirTemp("", "cobra-test")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
f, _ := os.OpenFile(filepath.Join(tmpDir, "test"), os.O_CREATE, 0400)
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
|
||||||
|
child := &Command{
|
||||||
|
Use: "child",
|
||||||
|
ValidArgsFunction: validArgsFunc,
|
||||||
|
Run: emptyRun,
|
||||||
|
}
|
||||||
|
rootCmd.AddCommand(child)
|
||||||
|
|
||||||
|
got := rootCmd.GenNushellCompletionFile(f.Name(), false)
|
||||||
|
if !errors.Is(got, os.ErrPermission) {
|
||||||
|
t.Errorf("got: %s, want: %s", got.Error(), os.ErrPermission.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNushellCompletionNoActiveHelp(t *testing.T) {
|
||||||
|
c := &Command{Use: "c", Run: emptyRun}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
assertNoErr(t, c.GenNushellCompletion(buf, true))
|
||||||
|
output := buf.String()
|
||||||
|
|
||||||
|
// check that active help is being disabled
|
||||||
|
activeHelpVar := activeHelpGlobalEnvVar
|
||||||
|
check(t, output, fmt.Sprintf("%s=0", activeHelpVar))
|
||||||
|
}
|
@ -6,6 +6,7 @@ The currently supported shells are:
|
|||||||
- Zsh
|
- Zsh
|
||||||
- fish
|
- fish
|
||||||
- PowerShell
|
- PowerShell
|
||||||
|
- Nushell
|
||||||
|
|
||||||
Cobra will automatically provide your program with a fully functional `completion` command,
|
Cobra will automatically provide your program with a fully functional `completion` command,
|
||||||
similarly to how it provides the `help` command.
|
similarly to how it provides the `help` command.
|
||||||
@ -28,7 +29,7 @@ and then modifying the generated `cmd/completion.go` file to look something like
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
var completionCmd = &cobra.Command{
|
var completionCmd = &cobra.Command{
|
||||||
Use: "completion [bash|zsh|fish|powershell]",
|
Use: "completion [bash|zsh|fish|powershell|nushell]",
|
||||||
Short: "Generate completion script",
|
Short: "Generate completion script",
|
||||||
Long: fmt.Sprintf(`To load completions:
|
Long: fmt.Sprintf(`To load completions:
|
||||||
|
|
||||||
@ -68,9 +69,30 @@ PowerShell:
|
|||||||
# To load completions for every new session, run:
|
# To load completions for every new session, run:
|
||||||
PS> %[1]s completion powershell > %[1]s.ps1
|
PS> %[1]s completion powershell > %[1]s.ps1
|
||||||
# and source this file from your PowerShell profile.
|
# and source this file from your PowerShell profile.
|
||||||
|
|
||||||
|
Nushell:
|
||||||
|
|
||||||
|
# To configure the Nushell cobra external completer for the first time:
|
||||||
|
# 1. Edit the nushell config file:
|
||||||
|
> config nu
|
||||||
|
# 2. Copy the output of %[1]s completion nushell to the end of the file.
|
||||||
|
# 3. Add a section like the following below at the end of the file:
|
||||||
|
$env.config.completions.external = {
|
||||||
|
enable: true
|
||||||
|
max_results: 100
|
||||||
|
completer: $cobra_completer
|
||||||
|
}
|
||||||
|
|
||||||
|
This completer will work for all cobra based commands.
|
||||||
|
More information can be found in the External Completions section of the Nushell book:
|
||||||
|
https://www.nushell.sh/book/custom_completions.html#external-completions
|
||||||
|
|
||||||
|
Information on setting up more than one external completer can be found in the Multiple completer section of the Nushell cookbook:
|
||||||
|
https://www.nushell.sh/cookbook/external_completers.html#multiple-completer
|
||||||
|
|
||||||
`,cmd.Root().Name()),
|
`,cmd.Root().Name()),
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
|
ValidArgs: []string{"bash", "zsh", "fish", "powershell", "nushell"},
|
||||||
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
|
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
@ -82,6 +104,8 @@ PowerShell:
|
|||||||
cmd.Root().GenFishCompletion(os.Stdout, true)
|
cmd.Root().GenFishCompletion(os.Stdout, true)
|
||||||
case "powershell":
|
case "powershell":
|
||||||
cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
|
cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
|
||||||
|
case "nushell":
|
||||||
|
cmd.Root().GenNushellCompletion(os.Stdout, true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
3
site/content/completions/nushell_completions.md
Normal file
3
site/content/completions/nushell_completions.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
## Generating Nushell Completions For Your cobra.Command
|
||||||
|
|
||||||
|
Please refer to [Shell Completions](_index.md#nushell-completions) for details.
|
Loading…
Reference in New Issue
Block a user