11 // GenZshCompletionFile generates zsh completion file.
12 func (c *Command) GenZshCompletionFile(filename string) error {
13 outFile, err := os.Create(filename)
19 return c.GenZshCompletion(outFile)
22 // GenZshCompletion generates a zsh completion file and writes to the passed writer.
23 func (c *Command) GenZshCompletion(w io.Writer) error {
24 buf := new(bytes.Buffer)
27 maxDepth := maxDepth(c)
28 writeLevelMapping(buf, maxDepth)
29 writeLevelCases(buf, maxDepth, c)
31 _, err := buf.WriteTo(w)
35 func writeHeader(w io.Writer, cmd *Command) {
36 fmt.Fprintf(w, "#compdef %s\n\n", cmd.Name())
39 func maxDepth(c *Command) int {
40 if len(c.Commands()) == 0 {
44 for _, s := range c.Commands() {
45 subDepth := maxDepth(s)
46 if subDepth > maxDepthSub {
47 maxDepthSub = subDepth
50 return 1 + maxDepthSub
53 func writeLevelMapping(w io.Writer, numLevels int) {
54 fmt.Fprintln(w, `_arguments \`)
55 for i := 1; i <= numLevels; i++ {
56 fmt.Fprintf(w, ` '%d: :->level%d' \`, i, i)
59 fmt.Fprintf(w, ` '%d: :%s'`, numLevels+1, "_files")
63 func writeLevelCases(w io.Writer, maxDepth int, root *Command) {
64 fmt.Fprintln(w, "case $state in")
65 defer fmt.Fprintln(w, "esac")
67 for i := 1; i <= maxDepth; i++ {
68 fmt.Fprintf(w, " level%d)\n", i)
69 writeLevel(w, root, i)
70 fmt.Fprintln(w, " ;;")
72 fmt.Fprintln(w, " *)")
73 fmt.Fprintln(w, " _arguments '*: :_files'")
74 fmt.Fprintln(w, " ;;")
77 func writeLevel(w io.Writer, root *Command, i int) {
78 fmt.Fprintf(w, " case $words[%d] in\n", i)
79 defer fmt.Fprintln(w, " esac")
81 commands := filterByLevel(root, i)
82 byParent := groupByParent(commands)
84 for p, c := range byParent {
86 fmt.Fprintf(w, " %s)\n", p)
87 fmt.Fprintf(w, " _arguments '%d: :(%s)'\n", i, strings.Join(names, " "))
88 fmt.Fprintln(w, " ;;")
90 fmt.Fprintln(w, " *)")
91 fmt.Fprintln(w, " _arguments '*: :_files'")
92 fmt.Fprintln(w, " ;;")
96 func filterByLevel(c *Command, l int) []*Command {
97 cs := make([]*Command, 0)
102 for _, s := range c.Commands() {
103 cs = append(cs, filterByLevel(s, l-1)...)
108 func groupByParent(commands []*Command) map[string][]*Command {
109 m := make(map[string][]*Command)
110 for _, c := range commands {
115 m[parent.Name()] = append(m[parent.Name()], c)
120 func names(commands []*Command) []string {
121 ns := make([]string, len(commands))
122 for i, c := range commands {