95 lines
2.9 KiB
Go
95 lines
2.9 KiB
Go
package cobra
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
|
|
spfcobra "github.com/spf13/cobra"
|
|
)
|
|
|
|
// CompletionQueryToken is the hidden request understood by generated scripts.
|
|
const CompletionQueryToken = spfcobra.ShellCompRequestCmd
|
|
|
|
// CompletionScript generates a shell script for the installed executable.
|
|
func CompletionScript(w io.Writer, executable, shell string) error {
|
|
root := &spfcobra.Command{Use: executable}
|
|
var generated bytes.Buffer
|
|
var err error
|
|
switch shell {
|
|
case "bash":
|
|
err = root.GenBashCompletionV2(&generated, true)
|
|
case "zsh":
|
|
err = root.GenZshCompletion(&generated)
|
|
case "fish":
|
|
err = root.GenFishCompletion(&generated, true)
|
|
default:
|
|
return fmt.Errorf("unsupported completion shell %q", shell)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
script := generated.String()
|
|
if shell == "zsh" {
|
|
script, err = replaceCompletionText(script, `words=("${=words[1,CURRENT]}")`, `words=("${(@)words[1,CURRENT]}")`)
|
|
if err == nil {
|
|
script, err = replaceCompletionText(script, `=~ '-.*='`, `=~ '-[^=]*='`)
|
|
}
|
|
} else if shell == "fish" {
|
|
script, err = adjustFishCompletion(script, root.Name())
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
n, err := io.WriteString(w, script)
|
|
if err == nil && n != len(script) {
|
|
return io.ErrShortWrite
|
|
}
|
|
return err
|
|
}
|
|
|
|
func replaceCompletionText(script, old, replacement string) (string, error) {
|
|
if strings.Count(script, old) != 1 {
|
|
return "", fmt.Errorf("unsupported generated completion script")
|
|
}
|
|
return strings.Replace(script, old, replacement, 1), nil
|
|
}
|
|
|
|
func adjustFishCompletion(script, name string) (string, error) {
|
|
var err error
|
|
cobraName := strings.NewReplacer("-", "_", ":", "_").Replace(name)
|
|
variableName := strings.ReplaceAll(cobraName, ".", "_")
|
|
if cobraName != variableName {
|
|
script = strings.ReplaceAll(script, "__"+cobraName+"_", "__"+variableName+"_")
|
|
}
|
|
script, err = replaceCompletionText(script,
|
|
`set -l lastArg (string escape -- (commandline -ct))`,
|
|
"set -l lastArg (string unescape -- (commandline -ct))\n set -q lastArg[1]; or set lastArg \"\"")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
script, err = replaceCompletionText(script,
|
|
`set -l results (eval $requestComp 2> /dev/null)`,
|
|
`set -lx COBRA_ACTIVE_HELP 0`+"\n "+`set -l results ($args[1] `+spfcobra.ShellCompRequestCmd+` $args[2..-1] "$lastArg" 2> /dev/null)`)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
script, err = replaceCompletionText(script, `string match -r -- '-.*=' "$lastArg"`, `string match -r -- '-[^=]*=' "$lastArg"`)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
variable := "__" + variableName + "_comp_results"
|
|
directories := fmt.Sprintf(`if test $dirfilter -eq 1
|
|
set -l flagPrefix (string match -r -- '^-[^=]*=' (commandline -ct))
|
|
set --global %[1]s
|
|
for dir in (__fish_complete_directories)
|
|
set -a %[1]s "$flagPrefix$dir"
|
|
end
|
|
return 0
|
|
end
|
|
if test $filefilter -eq 1`, variable)
|
|
return replaceCompletionText(script, `if test $filefilter -eq 1; or test $dirfilter -eq 1`, directories)
|
|
}
|