File: completion.go

package info (click to toggle)
golang-github-urfave-cli-v3 3.3.8-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 12,676 kB
  • sloc: sh: 26; makefile: 16
file content (100 lines) | stat: -rw-r--r-- 2,624 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package cli

import (
	"context"
	"embed"
	"fmt"
	"sort"
	"strings"
)

const (
	completionCommandName = "completion"

	// This flag is supposed to only be used by the completion script itself to generate completions on the fly.
	completionFlag = "--generate-shell-completion"
)

type renderCompletion func(cmd *Command, appName string) (string, error)

var (
	//go:embed autocomplete
	autoCompleteFS embed.FS

	shellCompletions = map[string]renderCompletion{
		"bash": func(c *Command, appName string) (string, error) {
			b, err := autoCompleteFS.ReadFile("autocomplete/bash_autocomplete")
			return fmt.Sprintf(string(b), appName), err
		},
		"zsh": func(c *Command, appName string) (string, error) {
			b, err := autoCompleteFS.ReadFile("autocomplete/zsh_autocomplete")
			return fmt.Sprintf(string(b), appName), err
		},
		"fish": func(c *Command, appName string) (string, error) {
			return c.Root().ToFishCompletion()
		},
		"pwsh": func(c *Command, appName string) (string, error) {
			b, err := autoCompleteFS.ReadFile("autocomplete/powershell_autocomplete.ps1")
			return string(b), err
		},
	}
)

const completionDescription = `Output shell completion script for bash, zsh, fish, or Powershell.
Source the output to enable completion.

# .bashrc
source <($COMMAND completion bash)

# .zshrc
source <($COMMAND completion zsh)

# fish
$COMMAND completion fish > ~/.config/fish/completions/$COMMAND.fish

# Powershell
Output the script to path/to/autocomplete/$COMMAND.ps1 an run it.
`

func buildCompletionCommand(appName string) *Command {
	return &Command{
		Name:        completionCommandName,
		Hidden:      true,
		Usage:       "Output shell completion script for bash, zsh, fish, or Powershell",
		Description: strings.ReplaceAll(completionDescription, "$COMMAND", appName),
		Action: func(ctx context.Context, cmd *Command) error {
			return printShellCompletion(ctx, cmd, appName)
		},
	}
}

func printShellCompletion(_ context.Context, cmd *Command, appName string) error {
	var shells []string
	for k := range shellCompletions {
		shells = append(shells, k)
	}

	sort.Strings(shells)

	if cmd.Args().Len() == 0 {
		return Exit(fmt.Sprintf("no shell provided for completion command. available shells are %+v", shells), 1)
	}
	s := cmd.Args().First()

	renderCompletion, ok := shellCompletions[s]
	if !ok {
		return Exit(fmt.Sprintf("unknown shell %s, available shells are %+v", s, shells), 1)
	}

	completionScript, err := renderCompletion(cmd, appName)
	if err != nil {
		return Exit(err, 1)
	}

	_, err = cmd.Writer.Write([]byte(completionScript))
	if err != nil {
		return Exit(err, 1)
	}

	return nil
}