+2
-2
PROJECT.md
+2
-2
PROJECT.md
···
122
122
123
123
#### Create a tap repo
124
124
125
-
Make a repo: `github.com/stormlightlabs/homebrew-tools`.
125
+
Make a repo: `github.com/stormlightlabs/homebrew-tap`.
126
126
127
127
#### Formula template (`storm.rb`)
128
128
···
153
153
154
154
```yaml
155
155
brews:
156
-
- tap: stormlightlabs/homebrew-tools
156
+
- tap: stormlightlabs/homebrew-tap
157
157
name: storm
158
158
folder: Formula
159
159
commit_author:
+11
-2
README.md
+11
-2
README.md
···
11
11
12
12
## Install
13
13
14
+
### Homebrew (macOS / Linux)
15
+
16
+
```sh
17
+
brew install stormlightlabs/tap/storm
18
+
```
19
+
20
+
The goreleaser workflow keeps the [`stormlightlabs/homebrew-tap`](https://github.com/stormlightlabs/homebrew-tap)
21
+
formula up to date.
22
+
23
+
### Go toolchain
24
+
14
25
```sh
15
26
go install github.com/stormlightlabs/git-storm/cmd/storm@latest
16
27
```
17
-
18
-
(Need Homebrew? Use the `storm.rb` formula template in this repo to build a tap.)
19
28
20
29
## Quick Start
21
30
+426
completions/storm.bash
+426
completions/storm.bash
···
1
+
# bash completion V2 for storm -*- shell-script -*-
2
+
3
+
__storm_debug()
4
+
{
5
+
if [[ -n ${BASH_COMP_DEBUG_FILE-} ]]; then
6
+
echo "$*" >> "${BASH_COMP_DEBUG_FILE}"
7
+
fi
8
+
}
9
+
10
+
# Macs have bash3 for which the bash-completion package doesn't include
11
+
# _init_completion. This is a minimal version of that function.
12
+
__storm_init_completion()
13
+
{
14
+
COMPREPLY=()
15
+
_get_comp_words_by_ref "$@" cur prev words cword
16
+
}
17
+
18
+
# This function calls the storm program to obtain the completion
19
+
# results and the directive. It fills the 'out' and 'directive' vars.
20
+
__storm_get_completion_results() {
21
+
local requestComp lastParam lastChar args
22
+
23
+
# Prepare the command to request completions for the program.
24
+
# Calling ${words[0]} instead of directly storm allows handling aliases
25
+
args=("${words[@]:1}")
26
+
requestComp="${words[0]} __complete ${args[*]}"
27
+
28
+
lastParam=${words[$((${#words[@]}-1))]}
29
+
lastChar=${lastParam:$((${#lastParam}-1)):1}
30
+
__storm_debug "lastParam ${lastParam}, lastChar ${lastChar}"
31
+
32
+
if [[ -z ${cur} && ${lastChar} != = ]]; then
33
+
# If the last parameter is complete (there is a space following it)
34
+
# We add an extra empty parameter so we can indicate this to the go method.
35
+
__storm_debug "Adding extra empty parameter"
36
+
requestComp="${requestComp} ''"
37
+
fi
38
+
39
+
# When completing a flag with an = (e.g., storm -n=<TAB>)
40
+
# bash focuses on the part after the =, so we need to remove
41
+
# the flag part from $cur
42
+
if [[ ${cur} == -*=* ]]; then
43
+
cur="${cur#*=}"
44
+
fi
45
+
46
+
__storm_debug "Calling ${requestComp}"
47
+
# Use eval to handle any environment variables and such
48
+
out=$(eval "${requestComp}" 2>/dev/null)
49
+
50
+
# Extract the directive integer at the very end of the output following a colon (:)
51
+
directive=${out##*:}
52
+
# Remove the directive
53
+
out=${out%:*}
54
+
if [[ ${directive} == "${out}" ]]; then
55
+
# There is not directive specified
56
+
directive=0
57
+
fi
58
+
__storm_debug "The completion directive is: ${directive}"
59
+
__storm_debug "The completions are: ${out}"
60
+
}
61
+
62
+
__storm_process_completion_results() {
63
+
local shellCompDirectiveError=1
64
+
local shellCompDirectiveNoSpace=2
65
+
local shellCompDirectiveNoFileComp=4
66
+
local shellCompDirectiveFilterFileExt=8
67
+
local shellCompDirectiveFilterDirs=16
68
+
local shellCompDirectiveKeepOrder=32
69
+
70
+
if (((directive & shellCompDirectiveError) != 0)); then
71
+
# Error code. No completion.
72
+
__storm_debug "Received error from custom completion go code"
73
+
return
74
+
else
75
+
if (((directive & shellCompDirectiveNoSpace) != 0)); then
76
+
if [[ $(type -t compopt) == builtin ]]; then
77
+
__storm_debug "Activating no space"
78
+
compopt -o nospace
79
+
else
80
+
__storm_debug "No space directive not supported in this version of bash"
81
+
fi
82
+
fi
83
+
if (((directive & shellCompDirectiveKeepOrder) != 0)); then
84
+
if [[ $(type -t compopt) == builtin ]]; then
85
+
# no sort isn't supported for bash less than < 4.4
86
+
if [[ ${BASH_VERSINFO[0]} -lt 4 || ( ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -lt 4 ) ]]; then
87
+
__storm_debug "No sort directive not supported in this version of bash"
88
+
else
89
+
__storm_debug "Activating keep order"
90
+
compopt -o nosort
91
+
fi
92
+
else
93
+
__storm_debug "No sort directive not supported in this version of bash"
94
+
fi
95
+
fi
96
+
if (((directive & shellCompDirectiveNoFileComp) != 0)); then
97
+
if [[ $(type -t compopt) == builtin ]]; then
98
+
__storm_debug "Activating no file completion"
99
+
compopt +o default
100
+
else
101
+
__storm_debug "No file completion directive not supported in this version of bash"
102
+
fi
103
+
fi
104
+
fi
105
+
106
+
# Separate activeHelp from normal completions
107
+
local completions=()
108
+
local activeHelp=()
109
+
__storm_extract_activeHelp
110
+
111
+
if (((directive & shellCompDirectiveFilterFileExt) != 0)); then
112
+
# File extension filtering
113
+
local fullFilter="" filter filteringCmd
114
+
115
+
# Do not use quotes around the $completions variable or else newline
116
+
# characters will be kept.
117
+
for filter in ${completions[*]}; do
118
+
fullFilter+="$filter|"
119
+
done
120
+
121
+
filteringCmd="_filedir $fullFilter"
122
+
__storm_debug "File filtering command: $filteringCmd"
123
+
$filteringCmd
124
+
elif (((directive & shellCompDirectiveFilterDirs) != 0)); then
125
+
# File completion for directories only
126
+
127
+
local subdir
128
+
subdir=${completions[0]}
129
+
if [[ -n $subdir ]]; then
130
+
__storm_debug "Listing directories in $subdir"
131
+
pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return
132
+
else
133
+
__storm_debug "Listing directories in ."
134
+
_filedir -d
135
+
fi
136
+
else
137
+
__storm_handle_completion_types
138
+
fi
139
+
140
+
__storm_handle_special_char "$cur" :
141
+
__storm_handle_special_char "$cur" =
142
+
143
+
# Print the activeHelp statements before we finish
144
+
__storm_handle_activeHelp
145
+
}
146
+
147
+
__storm_handle_activeHelp() {
148
+
# Print the activeHelp statements
149
+
if ((${#activeHelp[*]} != 0)); then
150
+
if [ -z $COMP_TYPE ]; then
151
+
# Bash v3 does not set the COMP_TYPE variable.
152
+
printf "\n";
153
+
printf "%s\n" "${activeHelp[@]}"
154
+
printf "\n"
155
+
__storm_reprint_commandLine
156
+
return
157
+
fi
158
+
159
+
# Only print ActiveHelp on the second TAB press
160
+
if [ $COMP_TYPE -eq 63 ]; then
161
+
printf "\n"
162
+
printf "%s\n" "${activeHelp[@]}"
163
+
164
+
if ((${#COMPREPLY[*]} == 0)); then
165
+
# When there are no completion choices from the program, file completion
166
+
# may kick in if the program has not disabled it; in such a case, we want
167
+
# to know if any files will match what the user typed, so that we know if
168
+
# there will be completions presented, so that we know how to handle ActiveHelp.
169
+
# To find out, we actually trigger the file completion ourselves;
170
+
# the call to _filedir will fill COMPREPLY if files match.
171
+
if (((directive & shellCompDirectiveNoFileComp) == 0)); then
172
+
__storm_debug "Listing files"
173
+
_filedir
174
+
fi
175
+
fi
176
+
177
+
if ((${#COMPREPLY[*]} != 0)); then
178
+
# If there are completion choices to be shown, print a delimiter.
179
+
# Re-printing the command-line will automatically be done
180
+
# by the shell when it prints the completion choices.
181
+
printf -- "--"
182
+
else
183
+
# When there are no completion choices at all, we need
184
+
# to re-print the command-line since the shell will
185
+
# not be doing it itself.
186
+
__storm_reprint_commandLine
187
+
fi
188
+
elif [ $COMP_TYPE -eq 37 ] || [ $COMP_TYPE -eq 42 ]; then
189
+
# For completion type: menu-complete/menu-complete-backward and insert-completions
190
+
# the completions are immediately inserted into the command-line, so we first
191
+
# print the activeHelp message and reprint the command-line since the shell won't.
192
+
printf "\n"
193
+
printf "%s\n" "${activeHelp[@]}"
194
+
195
+
__storm_reprint_commandLine
196
+
fi
197
+
fi
198
+
}
199
+
200
+
__storm_reprint_commandLine() {
201
+
# The prompt format is only available from bash 4.4.
202
+
# We test if it is available before using it.
203
+
if (x=${PS1@P}) 2> /dev/null; then
204
+
printf "%s" "${PS1@P}${COMP_LINE[@]}"
205
+
else
206
+
# Can't print the prompt. Just print the
207
+
# text the user had typed, it is workable enough.
208
+
printf "%s" "${COMP_LINE[@]}"
209
+
fi
210
+
}
211
+
212
+
# Separate activeHelp lines from real completions.
213
+
# Fills the $activeHelp and $completions arrays.
214
+
__storm_extract_activeHelp() {
215
+
local activeHelpMarker="_activeHelp_ "
216
+
local endIndex=${#activeHelpMarker}
217
+
218
+
while IFS='' read -r comp; do
219
+
[[ -z $comp ]] && continue
220
+
221
+
if [[ ${comp:0:endIndex} == $activeHelpMarker ]]; then
222
+
comp=${comp:endIndex}
223
+
__storm_debug "ActiveHelp found: $comp"
224
+
if [[ -n $comp ]]; then
225
+
activeHelp+=("$comp")
226
+
fi
227
+
else
228
+
# Not an activeHelp line but a normal completion
229
+
completions+=("$comp")
230
+
fi
231
+
done <<<"${out}"
232
+
}
233
+
234
+
__storm_handle_completion_types() {
235
+
__storm_debug "__storm_handle_completion_types: COMP_TYPE is $COMP_TYPE"
236
+
237
+
case $COMP_TYPE in
238
+
37|42)
239
+
# Type: menu-complete/menu-complete-backward and insert-completions
240
+
# If the user requested inserting one completion at a time, or all
241
+
# completions at once on the command-line we must remove the descriptions.
242
+
# https://github.com/spf13/cobra/issues/1508
243
+
244
+
# If there are no completions, we don't need to do anything
245
+
(( ${#completions[@]} == 0 )) && return 0
246
+
247
+
local tab=$'\t'
248
+
249
+
# Strip any description and escape the completion to handled special characters
250
+
IFS=$'\n' read -ra completions -d '' < <(printf "%q\n" "${completions[@]%%$tab*}")
251
+
252
+
# Only consider the completions that match
253
+
IFS=$'\n' read -ra COMPREPLY -d '' < <(IFS=$'\n'; compgen -W "${completions[*]}" -- "${cur}")
254
+
255
+
# compgen looses the escaping so we need to escape all completions again since they will
256
+
# all be inserted on the command-line.
257
+
IFS=$'\n' read -ra COMPREPLY -d '' < <(printf "%q\n" "${COMPREPLY[@]}")
258
+
;;
259
+
260
+
*)
261
+
# Type: complete (normal completion)
262
+
__storm_handle_standard_completion_case
263
+
;;
264
+
esac
265
+
}
266
+
267
+
__storm_handle_standard_completion_case() {
268
+
local tab=$'\t'
269
+
270
+
# If there are no completions, we don't need to do anything
271
+
(( ${#completions[@]} == 0 )) && return 0
272
+
273
+
# Short circuit to optimize if we don't have descriptions
274
+
if [[ "${completions[*]}" != *$tab* ]]; then
275
+
# First, escape the completions to handle special characters
276
+
IFS=$'\n' read -ra completions -d '' < <(printf "%q\n" "${completions[@]}")
277
+
# Only consider the completions that match what the user typed
278
+
IFS=$'\n' read -ra COMPREPLY -d '' < <(IFS=$'\n'; compgen -W "${completions[*]}" -- "${cur}")
279
+
280
+
# compgen looses the escaping so, if there is only a single completion, we need to
281
+
# escape it again because it will be inserted on the command-line. If there are multiple
282
+
# completions, we don't want to escape them because they will be printed in a list
283
+
# and we don't want to show escape characters in that list.
284
+
if (( ${#COMPREPLY[@]} == 1 )); then
285
+
COMPREPLY[0]=$(printf "%q" "${COMPREPLY[0]}")
286
+
fi
287
+
return 0
288
+
fi
289
+
290
+
local longest=0
291
+
local compline
292
+
# Look for the longest completion so that we can format things nicely
293
+
while IFS='' read -r compline; do
294
+
[[ -z $compline ]] && continue
295
+
296
+
# Before checking if the completion matches what the user typed,
297
+
# we need to strip any description and escape the completion to handle special
298
+
# characters because those escape characters are part of what the user typed.
299
+
# Don't call "printf" in a sub-shell because it will be much slower
300
+
# since we are in a loop.
301
+
printf -v comp "%q" "${compline%%$tab*}" &>/dev/null || comp=$(printf "%q" "${compline%%$tab*}")
302
+
303
+
# Only consider the completions that match
304
+
[[ $comp == "$cur"* ]] || continue
305
+
306
+
# The completions matches. Add it to the list of full completions including
307
+
# its description. We don't escape the completion because it may get printed
308
+
# in a list if there are more than one and we don't want show escape characters
309
+
# in that list.
310
+
COMPREPLY+=("$compline")
311
+
312
+
# Strip any description before checking the length, and again, don't escape
313
+
# the completion because this length is only used when printing the completions
314
+
# in a list and we don't want show escape characters in that list.
315
+
comp=${compline%%$tab*}
316
+
if ((${#comp}>longest)); then
317
+
longest=${#comp}
318
+
fi
319
+
done < <(printf "%s\n" "${completions[@]}")
320
+
321
+
# If there is a single completion left, remove the description text and escape any special characters
322
+
if ((${#COMPREPLY[*]} == 1)); then
323
+
__storm_debug "COMPREPLY[0]: ${COMPREPLY[0]}"
324
+
COMPREPLY[0]=$(printf "%q" "${COMPREPLY[0]%%$tab*}")
325
+
__storm_debug "Removed description from single completion, which is now: ${COMPREPLY[0]}"
326
+
else
327
+
# Format the descriptions
328
+
__storm_format_comp_descriptions $longest
329
+
fi
330
+
}
331
+
332
+
__storm_handle_special_char()
333
+
{
334
+
local comp="$1"
335
+
local char=$2
336
+
if [[ "$comp" == *${char}* && "$COMP_WORDBREAKS" == *${char}* ]]; then
337
+
local word=${comp%"${comp##*${char}}"}
338
+
local idx=${#COMPREPLY[*]}
339
+
while ((--idx >= 0)); do
340
+
COMPREPLY[idx]=${COMPREPLY[idx]#"$word"}
341
+
done
342
+
fi
343
+
}
344
+
345
+
__storm_format_comp_descriptions()
346
+
{
347
+
local tab=$'\t'
348
+
local comp desc maxdesclength
349
+
local longest=$1
350
+
351
+
local i ci
352
+
for ci in ${!COMPREPLY[*]}; do
353
+
comp=${COMPREPLY[ci]}
354
+
# Properly format the description string which follows a tab character if there is one
355
+
if [[ "$comp" == *$tab* ]]; then
356
+
__storm_debug "Original comp: $comp"
357
+
desc=${comp#*$tab}
358
+
comp=${comp%%$tab*}
359
+
360
+
# $COLUMNS stores the current shell width.
361
+
# Remove an extra 4 because we add 2 spaces and 2 parentheses.
362
+
maxdesclength=$(( COLUMNS - longest - 4 ))
363
+
364
+
# Make sure we can fit a description of at least 8 characters
365
+
# if we are to align the descriptions.
366
+
if ((maxdesclength > 8)); then
367
+
# Add the proper number of spaces to align the descriptions
368
+
for ((i = ${#comp} ; i < longest ; i++)); do
369
+
comp+=" "
370
+
done
371
+
else
372
+
# Don't pad the descriptions so we can fit more text after the completion
373
+
maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
374
+
fi
375
+
376
+
# If there is enough space for any description text,
377
+
# truncate the descriptions that are too long for the shell width
378
+
if ((maxdesclength > 0)); then
379
+
if ((${#desc} > maxdesclength)); then
380
+
desc=${desc:0:$(( maxdesclength - 1 ))}
381
+
desc+="…"
382
+
fi
383
+
comp+=" ($desc)"
384
+
fi
385
+
COMPREPLY[ci]=$comp
386
+
__storm_debug "Final comp: $comp"
387
+
fi
388
+
done
389
+
}
390
+
391
+
__start_storm()
392
+
{
393
+
local cur prev words cword split
394
+
395
+
COMPREPLY=()
396
+
397
+
# Call _init_completion from the bash-completion package
398
+
# to prepare the arguments properly
399
+
if declare -F _init_completion >/dev/null 2>&1; then
400
+
_init_completion -n =: || return
401
+
else
402
+
__storm_init_completion -n =: || return
403
+
fi
404
+
405
+
__storm_debug
406
+
__storm_debug "========= starting completion logic =========="
407
+
__storm_debug "cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}, cword is $cword"
408
+
409
+
# The user could have moved the cursor backwards on the command-line.
410
+
# We need to trigger completion from the $cword location, so we need
411
+
# to truncate the command-line ($words) up to the $cword location.
412
+
words=("${words[@]:0:$cword+1}")
413
+
__storm_debug "Truncated words[*]: ${words[*]},"
414
+
415
+
local out directive
416
+
__storm_get_completion_results
417
+
__storm_process_completion_results
418
+
}
419
+
420
+
if [[ $(type -t compopt) = "builtin" ]]; then
421
+
complete -o default -F __start_storm storm
422
+
else
423
+
complete -o default -o nospace -F __start_storm storm
424
+
fi
425
+
426
+
# ex: ts=4 sw=4 et filetype=sh
+235
completions/storm.fish
+235
completions/storm.fish
···
1
+
# fish completion for storm -*- shell-script -*-
2
+
3
+
function __storm_debug
4
+
set -l file "$BASH_COMP_DEBUG_FILE"
5
+
if test -n "$file"
6
+
echo "$argv" >> $file
7
+
end
8
+
end
9
+
10
+
function __storm_perform_completion
11
+
__storm_debug "Starting __storm_perform_completion"
12
+
13
+
# Extract all args except the last one
14
+
set -l args (commandline -opc)
15
+
# Extract the last arg and escape it in case it is a space
16
+
set -l lastArg (string escape -- (commandline -ct))
17
+
18
+
__storm_debug "args: $args"
19
+
__storm_debug "last arg: $lastArg"
20
+
21
+
# Disable ActiveHelp which is not supported for fish shell
22
+
set -l requestComp "STORM_ACTIVE_HELP=0 $args[1] __complete $args[2..-1] $lastArg"
23
+
24
+
__storm_debug "Calling $requestComp"
25
+
set -l results (eval $requestComp 2> /dev/null)
26
+
27
+
# Some programs may output extra empty lines after the directive.
28
+
# Let's ignore them or else it will break completion.
29
+
# Ref: https://github.com/spf13/cobra/issues/1279
30
+
for line in $results[-1..1]
31
+
if test (string trim -- $line) = ""
32
+
# Found an empty line, remove it
33
+
set results $results[1..-2]
34
+
else
35
+
# Found non-empty line, we have our proper output
36
+
break
37
+
end
38
+
end
39
+
40
+
set -l comps $results[1..-2]
41
+
set -l directiveLine $results[-1]
42
+
43
+
# For Fish, when completing a flag with an = (e.g., <program> -n=<TAB>)
44
+
# completions must be prefixed with the flag
45
+
set -l flagPrefix (string match -r -- '-.*=' "$lastArg")
46
+
47
+
__storm_debug "Comps: $comps"
48
+
__storm_debug "DirectiveLine: $directiveLine"
49
+
__storm_debug "flagPrefix: $flagPrefix"
50
+
51
+
for comp in $comps
52
+
printf "%s%s\n" "$flagPrefix" "$comp"
53
+
end
54
+
55
+
printf "%s\n" "$directiveLine"
56
+
end
57
+
58
+
# this function limits calls to __storm_perform_completion, by caching the result behind $__storm_perform_completion_once_result
59
+
function __storm_perform_completion_once
60
+
__storm_debug "Starting __storm_perform_completion_once"
61
+
62
+
if test -n "$__storm_perform_completion_once_result"
63
+
__storm_debug "Seems like a valid result already exists, skipping __storm_perform_completion"
64
+
return 0
65
+
end
66
+
67
+
set --global __storm_perform_completion_once_result (__storm_perform_completion)
68
+
if test -z "$__storm_perform_completion_once_result"
69
+
__storm_debug "No completions, probably due to a failure"
70
+
return 1
71
+
end
72
+
73
+
__storm_debug "Performed completions and set __storm_perform_completion_once_result"
74
+
return 0
75
+
end
76
+
77
+
# this function is used to clear the $__storm_perform_completion_once_result variable after completions are run
78
+
function __storm_clear_perform_completion_once_result
79
+
__storm_debug ""
80
+
__storm_debug "========= clearing previously set __storm_perform_completion_once_result variable =========="
81
+
set --erase __storm_perform_completion_once_result
82
+
__storm_debug "Successfully erased the variable __storm_perform_completion_once_result"
83
+
end
84
+
85
+
function __storm_requires_order_preservation
86
+
__storm_debug ""
87
+
__storm_debug "========= checking if order preservation is required =========="
88
+
89
+
__storm_perform_completion_once
90
+
if test -z "$__storm_perform_completion_once_result"
91
+
__storm_debug "Error determining if order preservation is required"
92
+
return 1
93
+
end
94
+
95
+
set -l directive (string sub --start 2 $__storm_perform_completion_once_result[-1])
96
+
__storm_debug "Directive is: $directive"
97
+
98
+
set -l shellCompDirectiveKeepOrder 32
99
+
set -l keeporder (math (math --scale 0 $directive / $shellCompDirectiveKeepOrder) % 2)
100
+
__storm_debug "Keeporder is: $keeporder"
101
+
102
+
if test $keeporder -ne 0
103
+
__storm_debug "This does require order preservation"
104
+
return 0
105
+
end
106
+
107
+
__storm_debug "This doesn't require order preservation"
108
+
return 1
109
+
end
110
+
111
+
112
+
# This function does two things:
113
+
# - Obtain the completions and store them in the global __storm_comp_results
114
+
# - Return false if file completion should be performed
115
+
function __storm_prepare_completions
116
+
__storm_debug ""
117
+
__storm_debug "========= starting completion logic =========="
118
+
119
+
# Start fresh
120
+
set --erase __storm_comp_results
121
+
122
+
__storm_perform_completion_once
123
+
__storm_debug "Completion results: $__storm_perform_completion_once_result"
124
+
125
+
if test -z "$__storm_perform_completion_once_result"
126
+
__storm_debug "No completion, probably due to a failure"
127
+
# Might as well do file completion, in case it helps
128
+
return 1
129
+
end
130
+
131
+
set -l directive (string sub --start 2 $__storm_perform_completion_once_result[-1])
132
+
set --global __storm_comp_results $__storm_perform_completion_once_result[1..-2]
133
+
134
+
__storm_debug "Completions are: $__storm_comp_results"
135
+
__storm_debug "Directive is: $directive"
136
+
137
+
set -l shellCompDirectiveError 1
138
+
set -l shellCompDirectiveNoSpace 2
139
+
set -l shellCompDirectiveNoFileComp 4
140
+
set -l shellCompDirectiveFilterFileExt 8
141
+
set -l shellCompDirectiveFilterDirs 16
142
+
143
+
if test -z "$directive"
144
+
set directive 0
145
+
end
146
+
147
+
set -l compErr (math (math --scale 0 $directive / $shellCompDirectiveError) % 2)
148
+
if test $compErr -eq 1
149
+
__storm_debug "Received error directive: aborting."
150
+
# Might as well do file completion, in case it helps
151
+
return 1
152
+
end
153
+
154
+
set -l filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) % 2)
155
+
set -l dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) % 2)
156
+
if test $filefilter -eq 1; or test $dirfilter -eq 1
157
+
__storm_debug "File extension filtering or directory filtering not supported"
158
+
# Do full file completion instead
159
+
return 1
160
+
end
161
+
162
+
set -l nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) % 2)
163
+
set -l nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) % 2)
164
+
165
+
__storm_debug "nospace: $nospace, nofiles: $nofiles"
166
+
167
+
# If we want to prevent a space, or if file completion is NOT disabled,
168
+
# we need to count the number of valid completions.
169
+
# To do so, we will filter on prefix as the completions we have received
170
+
# may not already be filtered so as to allow fish to match on different
171
+
# criteria than the prefix.
172
+
if test $nospace -ne 0; or test $nofiles -eq 0
173
+
set -l prefix (commandline -t | string escape --style=regex)
174
+
__storm_debug "prefix: $prefix"
175
+
176
+
set -l completions (string match -r -- "^$prefix.*" $__storm_comp_results)
177
+
set --global __storm_comp_results $completions
178
+
__storm_debug "Filtered completions are: $__storm_comp_results"
179
+
180
+
# Important not to quote the variable for count to work
181
+
set -l numComps (count $__storm_comp_results)
182
+
__storm_debug "numComps: $numComps"
183
+
184
+
if test $numComps -eq 1; and test $nospace -ne 0
185
+
# We must first split on \t to get rid of the descriptions to be
186
+
# able to check what the actual completion will be.
187
+
# We don't need descriptions anyway since there is only a single
188
+
# real completion which the shell will expand immediately.
189
+
set -l split (string split --max 1 \t $__storm_comp_results[1])
190
+
191
+
# Fish won't add a space if the completion ends with any
192
+
# of the following characters: @=/:.,
193
+
set -l lastChar (string sub -s -1 -- $split)
194
+
if not string match -r -q "[@=/:.,]" -- "$lastChar"
195
+
# In other cases, to support the "nospace" directive we trick the shell
196
+
# by outputting an extra, longer completion.
197
+
__storm_debug "Adding second completion to perform nospace directive"
198
+
set --global __storm_comp_results $split[1] $split[1].
199
+
__storm_debug "Completions are now: $__storm_comp_results"
200
+
end
201
+
end
202
+
203
+
if test $numComps -eq 0; and test $nofiles -eq 0
204
+
# To be consistent with bash and zsh, we only trigger file
205
+
# completion when there are no other completions
206
+
__storm_debug "Requesting file completion"
207
+
return 1
208
+
end
209
+
end
210
+
211
+
return 0
212
+
end
213
+
214
+
# Since Fish completions are only loaded once the user triggers them, we trigger them ourselves
215
+
# so we can properly delete any completions provided by another script.
216
+
# Only do this if the program can be found, or else fish may print some errors; besides,
217
+
# the existing completions will only be loaded if the program can be found.
218
+
if type -q "storm"
219
+
# The space after the program name is essential to trigger completion for the program
220
+
# and not completion of the program name itself.
221
+
# Also, we use '> /dev/null 2>&1' since '&>' is not supported in older versions of fish.
222
+
complete --do-complete "storm " > /dev/null 2>&1
223
+
end
224
+
225
+
# Remove any pre-existing completions for the program since we will be handling all of them.
226
+
complete -c storm -e
227
+
228
+
# this will get called after the two calls below and clear the $__storm_perform_completion_once_result global
229
+
complete -c storm -n '__storm_clear_perform_completion_once_result'
230
+
# The call to __storm_prepare_completions will setup __storm_comp_results
231
+
# which provides the program's completion choices.
232
+
# If this doesn't require order preservation, we don't use the -k flag
233
+
complete -c storm -n 'not __storm_requires_order_preservation && __storm_prepare_completions' -f -a '$__storm_comp_results'
234
+
# otherwise we use the -k flag
235
+
complete -k -c storm -n '__storm_requires_order_preservation && __storm_prepare_completions' -f -a '$__storm_comp_results'
+212
completions/storm.zsh
+212
completions/storm.zsh
···
1
+
#compdef storm
2
+
compdef _storm storm
3
+
4
+
# zsh completion for storm -*- shell-script -*-
5
+
6
+
__storm_debug()
7
+
{
8
+
local file="$BASH_COMP_DEBUG_FILE"
9
+
if [[ -n ${file} ]]; then
10
+
echo "$*" >> "${file}"
11
+
fi
12
+
}
13
+
14
+
_storm()
15
+
{
16
+
local shellCompDirectiveError=1
17
+
local shellCompDirectiveNoSpace=2
18
+
local shellCompDirectiveNoFileComp=4
19
+
local shellCompDirectiveFilterFileExt=8
20
+
local shellCompDirectiveFilterDirs=16
21
+
local shellCompDirectiveKeepOrder=32
22
+
23
+
local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace keepOrder
24
+
local -a completions
25
+
26
+
__storm_debug "\n========= starting completion logic =========="
27
+
__storm_debug "CURRENT: ${CURRENT}, words[*]: ${words[*]}"
28
+
29
+
# The user could have moved the cursor backwards on the command-line.
30
+
# We need to trigger completion from the $CURRENT location, so we need
31
+
# to truncate the command-line ($words) up to the $CURRENT location.
32
+
# (We cannot use $CURSOR as its value does not work when a command is an alias.)
33
+
words=("${=words[1,CURRENT]}")
34
+
__storm_debug "Truncated words[*]: ${words[*]},"
35
+
36
+
lastParam=${words[-1]}
37
+
lastChar=${lastParam[-1]}
38
+
__storm_debug "lastParam: ${lastParam}, lastChar: ${lastChar}"
39
+
40
+
# For zsh, when completing a flag with an = (e.g., storm -n=<TAB>)
41
+
# completions must be prefixed with the flag
42
+
setopt local_options BASH_REMATCH
43
+
if [[ "${lastParam}" =~ '-.*=' ]]; then
44
+
# We are dealing with a flag with an =
45
+
flagPrefix="-P ${BASH_REMATCH}"
46
+
fi
47
+
48
+
# Prepare the command to obtain completions
49
+
requestComp="${words[1]} __complete ${words[2,-1]}"
50
+
if [ "${lastChar}" = "" ]; then
51
+
# If the last parameter is complete (there is a space following it)
52
+
# We add an extra empty parameter so we can indicate this to the go completion code.
53
+
__storm_debug "Adding extra empty parameter"
54
+
requestComp="${requestComp} \"\""
55
+
fi
56
+
57
+
__storm_debug "About to call: eval ${requestComp}"
58
+
59
+
# Use eval to handle any environment variables and such
60
+
out=$(eval ${requestComp} 2>/dev/null)
61
+
__storm_debug "completion output: ${out}"
62
+
63
+
# Extract the directive integer following a : from the last line
64
+
local lastLine
65
+
while IFS='\n' read -r line; do
66
+
lastLine=${line}
67
+
done < <(printf "%s\n" "${out[@]}")
68
+
__storm_debug "last line: ${lastLine}"
69
+
70
+
if [ "${lastLine[1]}" = : ]; then
71
+
directive=${lastLine[2,-1]}
72
+
# Remove the directive including the : and the newline
73
+
local suffix
74
+
(( suffix=${#lastLine}+2))
75
+
out=${out[1,-$suffix]}
76
+
else
77
+
# There is no directive specified. Leave $out as is.
78
+
__storm_debug "No directive found. Setting do default"
79
+
directive=0
80
+
fi
81
+
82
+
__storm_debug "directive: ${directive}"
83
+
__storm_debug "completions: ${out}"
84
+
__storm_debug "flagPrefix: ${flagPrefix}"
85
+
86
+
if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then
87
+
__storm_debug "Completion received error. Ignoring completions."
88
+
return
89
+
fi
90
+
91
+
local activeHelpMarker="_activeHelp_ "
92
+
local endIndex=${#activeHelpMarker}
93
+
local startIndex=$((${#activeHelpMarker}+1))
94
+
local hasActiveHelp=0
95
+
while IFS='\n' read -r comp; do
96
+
# Check if this is an activeHelp statement (i.e., prefixed with $activeHelpMarker)
97
+
if [ "${comp[1,$endIndex]}" = "$activeHelpMarker" ];then
98
+
__storm_debug "ActiveHelp found: $comp"
99
+
comp="${comp[$startIndex,-1]}"
100
+
if [ -n "$comp" ]; then
101
+
compadd -x "${comp}"
102
+
__storm_debug "ActiveHelp will need delimiter"
103
+
hasActiveHelp=1
104
+
fi
105
+
106
+
continue
107
+
fi
108
+
109
+
if [ -n "$comp" ]; then
110
+
# If requested, completions are returned with a description.
111
+
# The description is preceded by a TAB character.
112
+
# For zsh's _describe, we need to use a : instead of a TAB.
113
+
# We first need to escape any : as part of the completion itself.
114
+
comp=${comp//:/\\:}
115
+
116
+
local tab="$(printf '\t')"
117
+
comp=${comp//$tab/:}
118
+
119
+
__storm_debug "Adding completion: ${comp}"
120
+
completions+=${comp}
121
+
lastComp=$comp
122
+
fi
123
+
done < <(printf "%s\n" "${out[@]}")
124
+
125
+
# Add a delimiter after the activeHelp statements, but only if:
126
+
# - there are completions following the activeHelp statements, or
127
+
# - file completion will be performed (so there will be choices after the activeHelp)
128
+
if [ $hasActiveHelp -eq 1 ]; then
129
+
if [ ${#completions} -ne 0 ] || [ $((directive & shellCompDirectiveNoFileComp)) -eq 0 ]; then
130
+
__storm_debug "Adding activeHelp delimiter"
131
+
compadd -x "--"
132
+
hasActiveHelp=0
133
+
fi
134
+
fi
135
+
136
+
if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then
137
+
__storm_debug "Activating nospace."
138
+
noSpace="-S ''"
139
+
fi
140
+
141
+
if [ $((directive & shellCompDirectiveKeepOrder)) -ne 0 ]; then
142
+
__storm_debug "Activating keep order."
143
+
keepOrder="-V"
144
+
fi
145
+
146
+
if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then
147
+
# File extension filtering
148
+
local filteringCmd
149
+
filteringCmd='_files'
150
+
for filter in ${completions[@]}; do
151
+
if [ ${filter[1]} != '*' ]; then
152
+
# zsh requires a glob pattern to do file filtering
153
+
filter="\*.$filter"
154
+
fi
155
+
filteringCmd+=" -g $filter"
156
+
done
157
+
filteringCmd+=" ${flagPrefix}"
158
+
159
+
__storm_debug "File filtering command: $filteringCmd"
160
+
_arguments '*:filename:'"$filteringCmd"
161
+
elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then
162
+
# File completion for directories only
163
+
local subdir
164
+
subdir="${completions[1]}"
165
+
if [ -n "$subdir" ]; then
166
+
__storm_debug "Listing directories in $subdir"
167
+
pushd "${subdir}" >/dev/null 2>&1
168
+
else
169
+
__storm_debug "Listing directories in ."
170
+
fi
171
+
172
+
local result
173
+
_arguments '*:dirname:_files -/'" ${flagPrefix}"
174
+
result=$?
175
+
if [ -n "$subdir" ]; then
176
+
popd >/dev/null 2>&1
177
+
fi
178
+
return $result
179
+
else
180
+
__storm_debug "Calling _describe"
181
+
if eval _describe $keepOrder "completions" completions $flagPrefix $noSpace; then
182
+
__storm_debug "_describe found some completions"
183
+
184
+
# Return the success of having called _describe
185
+
return 0
186
+
else
187
+
__storm_debug "_describe did not find completions."
188
+
__storm_debug "Checking if we should do file completion."
189
+
if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then
190
+
__storm_debug "deactivating file completion"
191
+
192
+
# We must return an error code here to let zsh know that there were no
193
+
# completions found by _describe; this is what will trigger other
194
+
# matching algorithms to attempt to find completions.
195
+
# For example zsh can match letters in the middle of words.
196
+
return 1
197
+
else
198
+
# Perform file completion
199
+
__storm_debug "Activating file completion"
200
+
201
+
# We must return the result of this command, so it must be the
202
+
# last command, or else we must store its result to return it.
203
+
_arguments '*:filename:_files'" ${flagPrefix}"
204
+
fi
205
+
fi
206
+
fi
207
+
}
208
+
209
+
# don't run the completion function when being source-ed or eval-ed
210
+
if [ "$funcstack[1]" = "_storm" ]; then
211
+
_storm
212
+
fi
+224
manpages/storm.1
+224
manpages/storm.1
···
1
+
.TH STORM 1 "2025-11-09" "storm" "A Git-aware changelog manager for Go projects"
2
+
.SH NAME
3
+
storm - A Git-aware changelog manager for Go projects
4
+
.SH SYNOPSIS
5
+
\fBstorm\fP [\fIoptions\&.\&.\&.\fP] [\fIargument\&.\&.\&.\fP]
6
+
.SH DESCRIPTION
7
+
storm is a modern changelog generator inspired by Towncrier\&.
8
+
.PP
9
+
It manages \&.changes/ entries, generates Keep a Changelog sections,
10
+
.PP
11
+
and can review commits interactively through a TUI\&.
12
+
.SH OPTIONS
13
+
.TP
14
+
\fB--o --output\fP
15
+
Output changelog file path
16
+
.TP
17
+
\fB--repo\fP
18
+
Path to the Git repository
19
+
.SH COMMANDS
20
+
.TP
21
+
\fBbump\fP
22
+
.RS 4
23
+
Calculate the next semantic version and optionally update toolchain manifests
24
+
.RE
25
+
.TP
26
+
\fBOPTIONS\fP
27
+
.RS 4
28
+
\fB--bump\fP
29
+
Which semver component to bump (major, minor, or patch)
30
+
.TP
31
+
\fB--toolchain\fP
32
+
Toolchain manifests to update (paths, types, or 'interactive')
33
+
.RE
34
+
.TP
35
+
\fBcheck\fP [from] [to]
36
+
.RS 4
37
+
Validate changelog entries exist for all commits
38
+
.RE
39
+
.TP
40
+
\fBOPTIONS\fP
41
+
.RS 4
42
+
\fB--since\fP
43
+
Check changes since the given tag
44
+
.RE
45
+
.TP
46
+
\fBcompletion\fP
47
+
.RS 4
48
+
Generate the autocompletion script for the specified shell
49
+
.RE
50
+
.TP
51
+
\fBCOMMANDS\fP
52
+
.RS 4
53
+
\fBbash\fP
54
+
.RS 4
55
+
Generate the autocompletion script for bash
56
+
.RE
57
+
.TP
58
+
\fBOPTIONS\fP
59
+
.RS 4
60
+
\fB--no-descriptions\fP
61
+
disable completion descriptions
62
+
.RE
63
+
.TP
64
+
\fBfish\fP
65
+
.RS 4
66
+
Generate the autocompletion script for fish
67
+
.RE
68
+
.TP
69
+
\fBOPTIONS\fP
70
+
.RS 4
71
+
\fB--no-descriptions\fP
72
+
disable completion descriptions
73
+
.RE
74
+
.TP
75
+
\fBpowershell\fP
76
+
.RS 4
77
+
Generate the autocompletion script for powershell
78
+
.RE
79
+
.TP
80
+
\fBOPTIONS\fP
81
+
.RS 4
82
+
\fB--no-descriptions\fP
83
+
disable completion descriptions
84
+
.RE
85
+
.TP
86
+
\fBzsh\fP
87
+
.RS 4
88
+
Generate the autocompletion script for zsh
89
+
.RE
90
+
.TP
91
+
\fBOPTIONS\fP
92
+
.RS 4
93
+
\fB--no-descriptions\fP
94
+
disable completion descriptions
95
+
.RE
96
+
.RE
97
+
.TP
98
+
\fBdiff\fP <from>\&.\&.<to> | diff <from> <to>
99
+
.RS 4
100
+
Show a line-based diff between two commits or tags
101
+
.RE
102
+
.TP
103
+
\fBOPTIONS\fP
104
+
.RS 4
105
+
\fB--e --expanded\fP
106
+
Show all unchanged lines (disable compression)
107
+
.TP
108
+
\fB--f --file\fP
109
+
Specific file to diff (optional, shows all files if omitted)
110
+
.TP
111
+
\fB--v --view\fP
112
+
Diff rendering: split or unified
113
+
.RE
114
+
.TP
115
+
\fBgenerate\fP [from] [to]
116
+
.RS 4
117
+
Generate changelog entries from Git commits
118
+
.RE
119
+
.TP
120
+
\fBOPTIONS\fP
121
+
.RS 4
122
+
\fB--i --interactive\fP
123
+
Review changes interactively in a TUI
124
+
.TP
125
+
\fB--since\fP
126
+
Generate changes since the given tag
127
+
.RE
128
+
.TP
129
+
\fBhelp\fP [command]
130
+
.RS 4
131
+
Help about any command
132
+
.RE
133
+
.TP
134
+
\fBrelease\fP
135
+
.RS 4
136
+
Promote unreleased changes into a new changelog version
137
+
.RE
138
+
.TP
139
+
\fBOPTIONS\fP
140
+
.RS 4
141
+
\fB--bump\fP
142
+
Automatically bump the previous version (major, minor, or patch)
143
+
.TP
144
+
\fB--clear-changes\fP
145
+
Delete \&.changes/*\&.md files after successful release
146
+
.TP
147
+
\fB--date\fP
148
+
Release date in YYYY-MM-DD format (default: today)
149
+
.TP
150
+
\fB--dry-run\fP
151
+
Preview changes without writing files
152
+
.TP
153
+
\fB--tag\fP
154
+
Create an annotated Git tag with release notes
155
+
.TP
156
+
\fB--toolchain\fP
157
+
Toolchain manifests to update (paths, types, or 'interactive')
158
+
.TP
159
+
\fB--version\fP
160
+
Semantic version for the new release (e\&.g\&., 1\&.3\&.0)
161
+
.RE
162
+
.TP
163
+
\fBunreleased\fP
164
+
.RS 4
165
+
Manage unreleased changes (\&.changes directory)
166
+
.RE
167
+
.TP
168
+
\fBCOMMANDS\fP
169
+
.RS 4
170
+
\fBadd\fP
171
+
.RS 4
172
+
Add a new unreleased change entry
173
+
.RE
174
+
.TP
175
+
\fBOPTIONS\fP
176
+
.RS 4
177
+
\fB--scope\fP
178
+
Optional scope or subsystem name
179
+
.TP
180
+
\fB--summary\fP
181
+
Short summary of the change
182
+
.TP
183
+
\fB--type\fP
184
+
Type of change (added, changed, fixed, removed, security)
185
+
.RE
186
+
.TP
187
+
\fBlist\fP
188
+
.RS 4
189
+
List all unreleased changes
190
+
.RE
191
+
.TP
192
+
\fBOPTIONS\fP
193
+
.RS 4
194
+
\fB--json\fP
195
+
Output results as JSON
196
+
.RE
197
+
.TP
198
+
\fBpartial\fP <commit-ref>
199
+
.RS 4
200
+
Create entry linked to a specific commit
201
+
.RE
202
+
.TP
203
+
\fBOPTIONS\fP
204
+
.RS 4
205
+
\fB--scope\fP
206
+
Optional scope or subsystem name
207
+
.TP
208
+
\fB--summary\fP
209
+
Override summary (auto-detected from commit)
210
+
.TP
211
+
\fB--type\fP
212
+
Override change type (auto-detected from commit)
213
+
.RE
214
+
.TP
215
+
\fBreview\fP
216
+
.RS 4
217
+
Review unreleased changes interactively
218
+
.RE
219
+
.RE
220
+
.TP
221
+
\fBversion\fP
222
+
.RS 4
223
+
Print the current storm version
224
+
.RE