mirror of
https://github.com/spf13/cobra.git
synced 2024-12-19 10:05:07 -07:00
Compare commits
35 Commits
c4dadf0e5a
...
ad7634be03
Author | SHA1 | Date | |
---|---|---|---|
|
ad7634be03 | ||
|
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
|
||||
* Grouping help for subcommands
|
||||
* 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
|
||||
* Command aliases so you can change things without breaking them
|
||||
* 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().GenPowerShellCompletionWithDesc(out)
|
||||
|
||||
},
|
||||
}
|
||||
if haveNoDescFlag {
|
||||
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 {
|
||||
@ -876,7 +908,7 @@ func CompDebug(msg string, printToStdErr bool) {
|
||||
// variable BASH_COMP_DEBUG_FILE to the path of some file to be used.
|
||||
if path := os.Getenv("BASH_COMP_DEBUG_FILE"); 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 {
|
||||
defer f.Close()
|
||||
WriteStringAndCheck(f, msg)
|
||||
|
@ -2577,6 +2577,7 @@ func TestCompleteCompletion(t *testing.T) {
|
||||
expected := strings.Join([]string{
|
||||
"bash",
|
||||
"fish",
|
||||
"nushell",
|
||||
"powershell",
|
||||
"zsh",
|
||||
":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
|
||||
- fish
|
||||
- PowerShell
|
||||
- Nushell
|
||||
|
||||
Cobra will automatically provide your program with a fully functional `completion` 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
|
||||
var completionCmd = &cobra.Command{
|
||||
Use: "completion [bash|zsh|fish|powershell]",
|
||||
Use: "completion [bash|zsh|fish|powershell|nushell]",
|
||||
Short: "Generate completion script",
|
||||
Long: fmt.Sprintf(`To load completions:
|
||||
|
||||
@ -68,9 +69,30 @@ PowerShell:
|
||||
# To load completions for every new session, run:
|
||||
PS> %[1]s completion powershell > %[1]s.ps1
|
||||
# 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()),
|
||||
DisableFlagsInUseLine: true,
|
||||
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
|
||||
ValidArgs: []string{"bash", "zsh", "fish", "powershell", "nushell"},
|
||||
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
switch args[0] {
|
||||
@ -82,6 +104,8 @@ PowerShell:
|
||||
cmd.Root().GenFishCompletion(os.Stdout, true)
|
||||
case "powershell":
|
||||
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