-
-
Notifications
You must be signed in to change notification settings - Fork 10
/
carapace.go
133 lines (113 loc) · 3.75 KB
/
carapace.go
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Package carapace is a command argument completion generator for spf13/cobra
package carapace
import (
"os"
"github.com/carapace-sh/carapace/internal/shell"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
// Carapace wraps cobra.Command to define completions.
type Carapace struct {
cmd *cobra.Command
}
// Gen initialized Carapace for given command.
func Gen(cmd *cobra.Command) *Carapace {
addCompletionCommand(cmd)
storage.bridge(cmd)
return &Carapace{
cmd: cmd,
}
}
// PreRun sets a function to be run before completion.
func (c Carapace) PreRun(f func(cmd *cobra.Command, args []string)) {
if entry := storage.get(c.cmd); entry.prerun != nil {
_f := entry.prerun
entry.prerun = func(cmd *cobra.Command, args []string) {
// TODO yuck - probably best to append to a slice in storage
_f(cmd, args)
f(cmd, args)
}
} else {
entry.prerun = f
}
}
// PreInvoke sets a function to alter actions before they are invoked.
func (c Carapace) PreInvoke(f func(cmd *cobra.Command, flag *pflag.Flag, action Action) Action) {
if entry := storage.get(c.cmd); entry.preinvoke != nil {
_f := entry.preinvoke
entry.preinvoke = func(cmd *cobra.Command, flag *pflag.Flag, action Action) Action {
return f(cmd, flag, _f(cmd, flag, action))
}
} else {
entry.preinvoke = f
}
}
// PositionalCompletion defines completion for positional arguments using a list of Actions.
func (c Carapace) PositionalCompletion(action ...Action) {
storage.get(c.cmd).positional = action
}
// PositionalAnyCompletion defines completion for any positional arguments not already defined.
func (c Carapace) PositionalAnyCompletion(action Action) {
storage.get(c.cmd).positionalAny = &action
}
// DashCompletion defines completion for positional arguments after dash (`--`) using a list of Actions.
func (c Carapace) DashCompletion(action ...Action) {
storage.get(c.cmd).dash = action
}
// DashAnyCompletion defines completion for any positional arguments after dash (`--`) not already defined.
func (c Carapace) DashAnyCompletion(action Action) {
storage.get(c.cmd).dashAny = &action
}
// FlagCompletion defines completion for flags using a map consisting of name and Action.
func (c Carapace) FlagCompletion(actions ActionMap) {
e := storage.get(c.cmd)
e.flagMutex.Lock()
defer e.flagMutex.Unlock()
if e.flag == nil {
e.flag = actions
} else {
for name, action := range actions {
e.flag[name] = action
}
}
}
const annotation_standalone = "carapace_standalone"
// Standalone prevents cobra defaults interfering with standalone mode (e.g. implicit help command).
func (c Carapace) Standalone() {
c.cmd.CompletionOptions = cobra.CompletionOptions{
DisableDefaultCmd: true,
}
if c.cmd.Annotations == nil {
c.cmd.Annotations = make(map[string]string)
}
c.cmd.Annotations[annotation_standalone] = "true"
c.PreRun(func(cmd *cobra.Command, args []string) {
if f := cmd.Flag("help"); f == nil {
cmd.Flags().Bool("help", false, "")
cmd.Flag("help").Hidden = true
} else if f.Annotations != nil {
if _, ok := f.Annotations[cobra.FlagSetByCobraAnnotation]; ok {
cmd.Flag("help").Hidden = true
}
}
})
c.cmd.SetHelpCommand(&cobra.Command{Use: "_carapace_help", Hidden: true, Deprecated: "fake help command to prevent default"})
}
// Snippet creates completion script for given shell.
func (c Carapace) Snippet(name string) (string, error) {
return shell.Snippet(c.cmd, name)
}
// IsCallback returns true if current program invocation is a callback.
func IsCallback() bool {
return len(os.Args) > 1 && os.Args[1] == "_carapace"
}
// Test verifies the configuration (e.g. flag name exists)
//
// func TestCarapace(t *testing.T) {
// carapace.Test(t)
// }
func Test(t interface{ Error(args ...interface{}) }) {
for _, e := range storage.check() {
t.Error(e)
}
}