mirror of
https://github.com/spf13/cobra
synced 2024-12-28 23:37:09 +00:00
'Completions for nushell'
This commit is contained in:
parent
02326d52c0
commit
a1431b2c57
4 changed files with 282 additions and 1 deletions
124
nushell_completions.go
Normal file
124
nushell_completions.go
Normal file
|
@ -0,0 +1,124 @@
|
|||
// 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"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var carrageReturnRE = regexp.MustCompile(`\r?\n`)
|
||||
|
||||
func descriptionString(desc string) string {
|
||||
// Remove any carriage returns, this will break the extern
|
||||
desc = carrageReturnRE.ReplaceAllString(desc, " ")
|
||||
|
||||
// Lets keep the descriptions short-ish
|
||||
if len(desc) > 100 {
|
||||
desc = desc[0:97] + "..."
|
||||
}
|
||||
return desc
|
||||
}
|
||||
|
||||
func GenNushellComp(c *Command, buf io.StringWriter, nameBuilder *strings.Builder, isRoot bool, includeDesc bool) {
|
||||
processFlags := func(flags *pflag.FlagSet) {
|
||||
flags.VisitAll(func(f *pflag.Flag) {
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("\t--%[1]s", f.Name))
|
||||
|
||||
if f.Shorthand != "" {
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("(-%[1]s)", f.Shorthand))
|
||||
}
|
||||
|
||||
if includeDesc && f.Usage != "" {
|
||||
desc := descriptionString(f.Usage)
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("\t# %[1]s", desc))
|
||||
}
|
||||
|
||||
WriteStringAndCheck(buf, "\n")
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
cmdName := c.Name()
|
||||
// commands after root name will be like "git pull"
|
||||
if !isRoot {
|
||||
nameBuilder.WriteString(" ")
|
||||
}
|
||||
nameBuilder.WriteString(cmdName)
|
||||
|
||||
// only create an extern block if there is something to put in it
|
||||
if len(c.ValidArgs) > 0 || c.HasAvailableFlags() {
|
||||
builderString := nameBuilder.String()
|
||||
|
||||
// ensure there is a space before any previous content
|
||||
// otherwise it will break descriptions
|
||||
WriteStringAndCheck(buf, "\n")
|
||||
|
||||
funcName := builderString
|
||||
if !isRoot {
|
||||
funcName = fmt.Sprintf("\"%[1]s\"", builderString)
|
||||
}
|
||||
|
||||
if includeDesc && c.Short != "" {
|
||||
desc := descriptionString(c.Short)
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("# %[1]s\n", desc))
|
||||
}
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("export extern %[1]s [\n", funcName))
|
||||
|
||||
// valid args
|
||||
for _, arg := range c.ValidArgs {
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("\t%[1]s?\n", arg))
|
||||
}
|
||||
|
||||
processFlags(c.InheritedFlags())
|
||||
processFlags(c.LocalFlags())
|
||||
|
||||
// End extern statement
|
||||
WriteStringAndCheck(buf, "]\n")
|
||||
}
|
||||
|
||||
// process sub commands
|
||||
for _, child := range c.Commands() {
|
||||
childBuilder := strings.Builder{}
|
||||
childBuilder.WriteString(nameBuilder.String())
|
||||
GenNushellComp(child, buf, &childBuilder, false, includeDesc)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (c *Command) GenNushellCompletion(w io.Writer, includeDesc bool) error {
|
||||
var nameBuilder strings.Builder
|
||||
buf := new(bytes.Buffer)
|
||||
GenNushellComp(c, buf, &nameBuilder, true, includeDesc)
|
||||
|
||||
_, 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)
|
||||
}
|
4
nushell_completions.md
Normal file
4
nushell_completions.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
## Generating Nushell Completions For Your cobra.Command
|
||||
|
||||
Please refer to [Shell Completions](shell_completions.md) for details.
|
||||
|
141
nushell_completions_test.go
Normal file
141
nushell_completions_test.go
Normal file
|
@ -0,0 +1,141 @@
|
|||
// 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"
|
||||
"log"
|
||||
"os"
|
||||
"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))
|
||||
output := buf.String()
|
||||
|
||||
// root command has no local options, it should not be displayed
|
||||
checkOmit(t, output, "export extern kubectl")
|
||||
|
||||
check(t, output, "export extern \"kubectl get\"")
|
||||
check(t, output, "--server")
|
||||
check(t, output, "--skip-headers")
|
||||
check(t, output, "pod?")
|
||||
check(t, output, "node?")
|
||||
check(t, output, "service?")
|
||||
check(t, output, "replicationcontroller?")
|
||||
|
||||
check(t, output, "The address and port of the Kubernetes API serverIf true, avoid header prefixes in the log messages")
|
||||
check(t, output, "The address and port of the Kubernetes API server")
|
||||
check(t, output, "Display one or many resources")
|
||||
}
|
||||
|
||||
func TestGenNushellCompletionWithoutDesc(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, false))
|
||||
output := buf.String()
|
||||
|
||||
checkOmit(t, output, "The address and port of the Kubernetes API server")
|
||||
checkOmit(t, output, "The address and port of the Kubernetes API serverIf true, avoid header prefixes in the log messages")
|
||||
checkOmit(t, output, "Display one or many resources")
|
||||
}
|
||||
|
||||
func TestGenNushellCompletionFile(t *testing.T) {
|
||||
err := os.Mkdir("./tmp", 0755)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
defer os.RemoveAll("./tmp")
|
||||
|
||||
rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
|
||||
child := &Command{
|
||||
Use: "child",
|
||||
ValidArgsFunction: validArgsFunc,
|
||||
Run: emptyRun,
|
||||
}
|
||||
rootCmd.AddCommand(child)
|
||||
|
||||
assertNoErr(t, rootCmd.GenNushellCompletionFile("./tmp/test", false))
|
||||
}
|
||||
|
||||
func TestFailGenNushellCompletionFile(t *testing.T) {
|
||||
err := os.Mkdir("./tmp", 0755)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
defer os.RemoveAll("./tmp")
|
||||
|
||||
f, _ := os.OpenFile("./tmp/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("./tmp/test", false)
|
||||
if got == nil {
|
||||
t.Error("should raise permission denied error")
|
||||
}
|
||||
|
||||
if os.Getenv("MSYSTEM") == "MINGW64" {
|
||||
if got.Error() != "open ./tmp/test: Access is denied." {
|
||||
t.Errorf("got: %s, want: %s", got.Error(), "open ./tmp/test: Access is denied.")
|
||||
}
|
||||
} else {
|
||||
if got.Error() != "open ./tmp/test: permission denied" {
|
||||
t.Errorf("got: %s, want: %s", got.Error(), "open ./tmp/test: permission denied")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
@ -68,9 +69,18 @@ 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 generate completions (replace YOUR_COMPLETION_DIR with actual path to save)
|
||||
> %[1]s completion nushell | save /YOUR_COMPLETION_DIR/%[1]s-completions.nu
|
||||
|
||||
# To load completions for each session, execute once (replace YOUR_COMPLETION_DIR with actual path):
|
||||
> echo "use /YOUR_COMPLETION_DIR/%[1]s-completions.nu *" | save --append $nu.config-path
|
||||
|
||||
`,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 +92,8 @@ PowerShell:
|
|||
cmd.Root().GenFishCompletion(os.Stdout, true)
|
||||
case "powershell":
|
||||
cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
|
||||
case "nushell":
|
||||
cmd.Root().GenNushellCompletion(os.Stdout, true)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue