1package command
2
3import (
4 "errors"
5 "strconv"
6)
7
8// ErrInvalidArguments reports arguments that do not have the exact command format.
9var ErrInvalidArguments = errors.New("invalid command arguments")
10
11// ParsePositiveUint64 accepts exactly one base-10 positive decimal value.
12// It deliberately rejects signs, whitespace, zero, and non-canonical forms.
13func ParsePositiveUint64(args []string) (uint64, error) {
14 if len(args) != 1 || args[0] == "" || (len(args[0]) > 1 && args[0][0] == '0') {
15 return 0, ErrInvalidArguments
16 }
17 for _, r := range args[0] {
18 if r < '0' || r > '9' {
19 return 0, ErrInvalidArguments
20 }
21 }
22 n, err := strconv.ParseUint(args[0], 10, 64)
23 if err != nil || n < 1 {
24 return 0, ErrInvalidArguments
25 }
26 return n, nil
27}
28
29// ParsePositiveDecimal parses a positive decimal that must fit the platform int.
30func ParsePositiveDecimal(args []string) (int, error) {
31 n, err := ParsePositiveUint64(args)
32 if err != nil || n > uint64(^uint(0)>>1) {
33 return 0, ErrInvalidArguments
34 }
35 return int(n), nil
36}
37
38// Context is the set of application actions available to commands.
39type Context interface {
40 CreateTab() error
41 CreateSession() error
42 CreateSessionNamed(name string) error
43 CreateEphemeralSession() error
44 CloseTab() error
45 SplitRight() error
46 SplitLeft() error
47 SplitUp() error
48 SplitDown() error
49 ConsumeOrExpelPaneLeft() error
50 ConsumeOrExpelPaneRight() error
51 StackPane() error
52 ToggleStack() error
53 ToggleFloatingPane() error
54 ClosePane() error
55 OpenMovePanePicker() error
56 OpenMoveTabPicker() error
57 FocusPaneLeft() error
58 FocusPaneRight() error
59 FocusPaneUp() error
60 FocusPaneDown() error
61 EnterResizeMode() error
62 GrowPaneWidth() error
63 ShrinkPaneWidth() error
64 GrowPaneHeight() error
65 ShrinkPaneHeight() error
66 EqualizePanes() error
67 NextTab() error
68 PrevTab() error
69 BackSession() error
70 Detach() error
71 EnterVisualMode() error
72 RenameSession() error
73 RenameSessionTo(name string) error
74 RenameTab() error
75 RenameTabTo(name string) error
76 OpenSessionPicker() error
77 OpenNotifications() error
78 YankLastNotification() error
79 JumpRecentSession(rank int) error
80}
81
82// Arguments declares whether a command accepts palette arguments.
83type Arguments uint8
84
85const (
86 ArgumentsNone Arguments = iota
87 ArgumentsOptional
88 ArgumentsRequired
89)
90
91// ContextHint describes optional contextual data needed to execute a command.
92type ContextHint uint8
93
94const (
95 ContextHintNone ContextHint = iota
96 ContextHintRecentSessions
97)
98
99// TargetKind declares which resolved target a control command needs.
100type TargetKind uint8
101
102const (
103 TargetNone TargetKind = iota
104 TargetSession
105 TargetTab
106 TargetPane
107)
108
109// CommandScope declares the serialization boundary needed by a command.
110type CommandScope uint8
111
112const (
113 CommandScopeSession CommandScope = iota
114 // CommandScopeCrossSession requires dispatch to defer locking to the
115 // mutation, which resolves and locks both source and destination sessions.
116 CommandScopeCrossSession
117)
118
119// ControlOptions carries per-invocation output preferences.
120type ControlOptions struct {
121 JSON bool
122}
123
124// ControlResult carries a control command's output.
125type ControlResult struct {
126 Output string
127}
128
129// ControlContext exposes prompt-free daemon actions to control commands.
130type ControlContext interface {
131 CreateTab() error
132 CreateSessionNamed(name string) error
133 CloseTab() error
134 ClosePane() error
135 MovePane(destinationSession, destinationTabID string) error
136 MoveTab(destinationSession string) error
137 SplitRight() error
138 SplitLeft() error
139 SplitUp() error
140 SplitDown() error
141 ConsumeOrExpelPaneLeft() error
142 ConsumeOrExpelPaneRight() error
143 StackPane() error
144 ToggleStack() error
145 GrowPaneWidth() error
146 ShrinkPaneWidth() error
147 GrowPaneHeight() error
148 ShrinkPaneHeight() error
149 EqualizePanes() error
150 FocusPaneLeft() error
151 FocusPaneRight() error
152 FocusPaneUp() error
153 FocusPaneDown() error
154 NextTab() error
155 PrevTab() error
156 RenameSessionTo(name string) error
157 RenameTabTo(name string) error
158 Toast(severity, message string) error
159 SessionRecovery(action string) (string, error)
160 ListSessions(json bool) (string, error)
161 ListTabs(json bool) (string, error)
162 ListPanes(json bool) (string, error)
163 SessionEnvironment(json bool) (string, error)
164 RemoteCatalog(json bool) (string, error)
165}
166
167// Command describes an executable command.
168type Command struct {
169 Slug, Code, Name, Desc string
170 Usage string
171 Arguments Arguments
172 // Preview describes the selected palette command while its exact token is
173 // being entered. hasArgument is true after whitespace following the token.
174 Preview func(args []string, hasArgument bool) string
175 ContextHint ContextHint
176 Scriptable bool
177 PaletteVisible bool
178 Target TargetKind
179 Scope CommandScope
180 Run func(Context, []string) error
181 Control func(ControlContext, []string, ControlOptions) (ControlResult, error)
182}