mirror of https://github.com/spf13/cobra.git
'Completions for nushell'
This commit is contained in:
parent
02326d52c0
commit
a1431b2c57
|
@ -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)
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
## Generating Nushell Completions For Your cobra.Command
|
||||||
|
|
||||||
|
Please refer to [Shell Completions](shell_completions.md) for details.
|
||||||
|
|
|
@ -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
|
- 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.
|
||||||
|
@ -68,9 +69,18 @@ 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 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()),
|
`,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 +92,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)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue