Compare commits

...

36 Commits

Author SHA1 Message Date
Jack Wright
c4dadf0e5a
Merge 997ac04e61 into 9f9056765c 2024-12-18 08:58:31 -08:00
Jack Wright
997ac04e61 Merge branch 'main' into nushell 2024-12-18 08:58:23 -08:00
Jack Wright
da1bab9757 Fixed the ShellCompDirectiveNoFileComp case 2024-12-11 17:22:41 -08:00
Jack Wright
1df1dbd552 cobra logging command 2024-12-08 20:34:38 -08:00
Jack Wright
52185bed6e tweaking extra completion instructions 2024-12-08 19:44:45 -08:00
Jack Wright
d728bbb91e Nushell instructions tweak 2024-12-08 19:40:45 -08:00
Jack Wright
14e642ede9 fixed bad grammar mistake 2024-12-08 19:35:50 -08:00
Jack Wright
e0ac28fad8 fix fish reference 2024-12-08 19:33:48 -08:00
Jack Wright
93a41331ec tmpfile handling changes 2024-12-01 20:05:39 -08:00
Jack Wright
470ca0a628 Added a comment at the beginning to remain consistent with other shells. 2024-12-01 20:05:18 -08:00
Jack Wright
ddb39920b4 More documentation work for nushell 2024-12-01 18:44:56 -08:00
Jack Wright
1886f6baad minor formatting tweak 2024-12-01 18:27:49 -08:00
Jack Wright
2f80e0879f changed from being markdown, as I don't think the docs here are markdown 2024-11-30 15:01:06 -08:00
Jack Wright
18d7a29987 more documentation tweaks 2024-11-30 14:58:44 -08:00
Jack Wright
59726e2b0f fixed a typo 2024-11-30 14:06:56 -08:00
Jack Wright
982ba402cb fix tests 2024-11-30 13:59:41 -08:00
Jack Wright
7006719603 fixing formatting 2024-11-30 13:57:31 -08:00
Jack Wright
8b4aa590bb Added new directive to the list of directives for posterity. 2024-11-30 13:34:39 -08:00
Jack Wright
7eac0e11ae Format with spaces instead of tabs 2024-11-30 13:32:05 -08:00
Jack Wright
e7abbf39a3 rewriting nushell implementation 2024-11-29 12:30:16 -08:00
Jack Wright
29af015b57 "fixed whitespace" 2024-11-29 12:30:16 -08:00
Jack Wright
f963733c4e "Reverted to old version without formatting changes and readded nushell" 2024-11-29 12:30:16 -08:00
Jack Wright
1a69a83abc "Added nushell to list of shell autompletes" 2024-11-29 12:30:16 -08:00
Jack Wright
8cb9728476 Update completions.go
Co-authored-by: Marc Khouzam <marc.khouzam@gmail.com>
2024-11-29 12:30:16 -08:00
Jack Wright
ead0ff3e53 Update completions.go
Co-authored-by: Marc Khouzam <marc.khouzam@gmail.com>
2024-11-29 12:30:16 -08:00
Jack Wright
3bfdd6421f Update completions.go
Co-authored-by: Marc Khouzam <marc.khouzam@gmail.com>
2024-11-29 12:30:16 -08:00
Jack Wright
4c4bde6586 "removing extra lines/whitespace" 2024-11-29 12:30:16 -08:00
Jack Wright
3b016843b9 "fixing completions that contain a /" 2024-11-29 12:30:16 -08:00
Jack Wright
247e8e6b55 "ignoring return value when directive is ShellComp#directiveFilterFileExt" 2024-11-29 12:30:16 -08:00
Jack Wright
d86bac4e34 "fixing oddities with fuzzy searching and bug with active help" 2024-11-29 12:30:16 -08:00
Jack Wright
fa746d4d5a Incorporating pull request feedback
- Fixing completion on full paths
- Fixing completion with equals in flags
- Fixing fuzzy search
- Typos
2024-11-29 12:30:16 -08:00
Jack Wright
37ac7454fb Added a whitelist to add cobra apps to to prevent non-cobra apps from
being excuted
2024-11-29 12:30:16 -08:00
Jack Wright
1324e0c316 Added nushell to the Use: line 2024-11-29 12:30:16 -08:00
Jack Wright
2f276e3014 Incorporating pull request feedback.
- Renamed completer to be cobra_completer to match docs
- Added whitespace after each completion
- Implemented ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp
- Disabled active help as it isn't supported by nushell
- Added nushell to the default completion command
2024-11-29 12:30:16 -08:00
Jack Wright
594faef23f Changed the nushell completion implementation to be a nushell external completer 2024-11-29 12:30:16 -08:00
Jack Wright
a1431b2c57 'Completions for nushell' 2024-11-29 12:30:16 -08:00
7 changed files with 295 additions and 6 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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
View 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)
}

View 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))
}

View File

@ -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)
}
},
}

View File

@ -0,0 +1,3 @@
## Generating Nushell Completions For Your cobra.Command
Please refer to [Shell Completions](_index.md#nushell-completions) for details.