2022-07-20 19:39:22 +02:00
|
|
|
package completion
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2022-07-25 20:11:54 +02:00
|
|
|
"strings"
|
2022-07-20 19:39:22 +02:00
|
|
|
|
|
|
|
"github.com/alecthomas/kong"
|
|
|
|
)
|
|
|
|
|
2022-07-25 22:21:44 +02:00
|
|
|
// Zsh is zsh completion generator.
|
2022-07-20 19:39:22 +02:00
|
|
|
type Zsh struct{}
|
|
|
|
|
2022-07-25 22:21:44 +02:00
|
|
|
// Run generates zsh completion script.
|
|
|
|
func (z Zsh) Run(ctx *kong.Context) error {
|
|
|
|
var out strings.Builder
|
|
|
|
format := `#compdef %[1]s
|
|
|
|
# zsh completion for %[1]s
|
|
|
|
# generated by gum completion
|
|
|
|
|
|
|
|
`
|
|
|
|
fmt.Fprintf(&out, format, ctx.Model.Name)
|
|
|
|
z.gen(&out, ctx.Model.Node)
|
|
|
|
_, err := fmt.Fprint(ctx.Stdout, out.String())
|
2022-08-05 00:45:19 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to generate zsh completion: %w", err)
|
|
|
|
}
|
|
|
|
return nil
|
2022-07-25 22:21:44 +02:00
|
|
|
}
|
|
|
|
|
2022-07-25 20:11:54 +02:00
|
|
|
func (z Zsh) writeFlag(buf io.StringWriter, f *kong.Flag) {
|
|
|
|
var str strings.Builder
|
|
|
|
str.WriteString(" ")
|
|
|
|
if f.Short != 0 {
|
|
|
|
str.WriteString("'(")
|
|
|
|
str.WriteString(fmt.Sprintf("-%c --%s", f.Short, f.Name))
|
|
|
|
if !f.IsBool() {
|
|
|
|
str.WriteString("=")
|
|
|
|
}
|
|
|
|
str.WriteString(")'")
|
|
|
|
str.WriteString("{")
|
|
|
|
str.WriteString(fmt.Sprintf("-%c,--%s", f.Short, f.Name))
|
|
|
|
if !f.IsBool() {
|
|
|
|
str.WriteString("=")
|
|
|
|
}
|
|
|
|
str.WriteString("}")
|
|
|
|
str.WriteString("\"")
|
|
|
|
} else {
|
|
|
|
str.WriteString("\"")
|
|
|
|
str.WriteString(fmt.Sprintf("--%s", f.Name))
|
|
|
|
if !f.IsBool() {
|
|
|
|
str.WriteString("=")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
str.WriteString(fmt.Sprintf("[%s]", f.Help))
|
|
|
|
if !f.IsBool() {
|
|
|
|
str.WriteString(":")
|
|
|
|
str.WriteString(strings.ToLower(f.Help))
|
|
|
|
str.WriteString(":")
|
|
|
|
}
|
2022-07-25 22:21:44 +02:00
|
|
|
values := flagPossibleValues(f)
|
|
|
|
if len(values) > 0 {
|
2022-07-25 20:11:54 +02:00
|
|
|
str.WriteString("(")
|
|
|
|
for i, v := range f.EnumSlice() {
|
|
|
|
str.WriteString(v)
|
2022-07-25 22:21:44 +02:00
|
|
|
if i < len(values)-1 {
|
2022-07-25 20:11:54 +02:00
|
|
|
str.WriteString(" ")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
str.WriteString(")")
|
|
|
|
}
|
|
|
|
str.WriteString("\"")
|
|
|
|
writeString(buf, str.String())
|
2022-07-20 19:39:22 +02:00
|
|
|
}
|
|
|
|
|
2022-07-25 20:11:54 +02:00
|
|
|
func (z Zsh) writeFlags(buf io.StringWriter, cmd *kong.Node) {
|
|
|
|
for i, f := range cmd.Flags {
|
|
|
|
if f.Hidden {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
z.writeFlag(buf, f)
|
|
|
|
if i < len(cmd.Flags)-1 {
|
|
|
|
writeString(buf, " \\\n")
|
|
|
|
}
|
|
|
|
}
|
2022-07-20 19:39:22 +02:00
|
|
|
}
|
|
|
|
|
2022-07-25 20:11:54 +02:00
|
|
|
func (z Zsh) writeCommand(buf io.StringWriter, c *kong.Node) {
|
|
|
|
writeString(buf, fmt.Sprintf(" \"%s[%s]\"", c.Name, c.Help))
|
2022-07-20 19:39:22 +02:00
|
|
|
}
|
|
|
|
|
2022-07-25 20:11:54 +02:00
|
|
|
func (z Zsh) writeCommands(buf io.StringWriter, cmd *kong.Node) {
|
|
|
|
for i, c := range cmd.Children {
|
|
|
|
if c == nil || c.Hidden {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
z.writeCommand(buf, c)
|
|
|
|
if i < len(cmd.Children)-1 {
|
2022-07-30 18:32:59 +02:00
|
|
|
_, _ = buf.WriteString(" \\")
|
2022-07-25 20:11:54 +02:00
|
|
|
}
|
|
|
|
writeString(buf, "\n")
|
2022-07-20 19:39:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-25 20:11:54 +02:00
|
|
|
func (z Zsh) gen(buf io.StringWriter, cmd *kong.Node) {
|
|
|
|
for _, c := range cmd.Children {
|
|
|
|
if c == nil || c.Hidden {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
z.gen(buf, c)
|
|
|
|
}
|
|
|
|
cmdName := commandName(cmd)
|
2022-07-20 19:39:22 +02:00
|
|
|
|
2022-07-25 20:11:54 +02:00
|
|
|
writeString(buf, fmt.Sprintf("_%s() {\n", cmdName))
|
|
|
|
if hasCommands(cmd) {
|
|
|
|
writeString(buf, " local line state\n")
|
|
|
|
}
|
|
|
|
writeString(buf, " _arguments -C \\\n")
|
|
|
|
z.writeFlags(buf, cmd)
|
|
|
|
if hasCommands(cmd) {
|
|
|
|
writeString(buf, " \\\n")
|
|
|
|
writeString(buf, " \"1: :->cmds\" \\\n")
|
|
|
|
writeString(buf, " \"*::arg:->args\"\n")
|
|
|
|
writeString(buf, " case \"$state\" in\n")
|
|
|
|
writeString(buf, " cmds)\n")
|
|
|
|
writeString(buf, fmt.Sprintf(" _values \"%s command\" \\\n", cmdName))
|
|
|
|
z.writeCommands(buf, cmd)
|
|
|
|
writeString(buf, " ;;\n")
|
|
|
|
writeString(buf, " args)\n")
|
|
|
|
writeString(buf, " case \"$line[1]\" in\n")
|
|
|
|
for _, c := range cmd.Children {
|
|
|
|
if c == nil || c.Hidden {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
writeString(buf, fmt.Sprintf(" %s)\n", c.Name))
|
|
|
|
writeString(buf, fmt.Sprintf(" _%s\n", commandName(c)))
|
|
|
|
writeString(buf, " ;;\n")
|
|
|
|
}
|
|
|
|
writeString(buf, " esac\n")
|
|
|
|
writeString(buf, " ;;\n")
|
|
|
|
writeString(buf, " esac\n")
|
|
|
|
}
|
|
|
|
// writeArgAliases(buf, cmd)
|
|
|
|
writeString(buf, "\n")
|
|
|
|
writeString(buf, "}\n\n")
|
2022-07-20 19:39:22 +02:00
|
|
|
}
|