Skip to content

Commit b1cf58d

Browse files
Stratus3DValgard
andauthored
fix: improve zsh completion suggestions (#2022)
Co-authored-by: Valgard Trontheim <[email protected]>
1 parent 807ea38 commit b1cf58d

File tree

1 file changed

+199
-54
lines changed

1 file changed

+199
-54
lines changed

internal/completions/asdf.zsh

Lines changed: 199 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,50 @@
1+
# Define completion for asdf version manager
12
#compdef asdf
23
#description tool to manage versions of multiple runtimes
34

4-
local curcontext="$curcontext" state state_descr line subcmd
5+
# Initialize local variables for ZSH completion context
6+
local state subcmd
7+
8+
# Set asdf directory path, using ASDF_DATA_DIR if set, otherwise default to ~/.asdf
59
local asdf_dir="${ASDF_DATA_DIR:-$HOME/.asdf}"
610

11+
# Define plugin management commands
712
local -a asdf_plugin_commands
813
asdf_plugin_commands=(
914
'add:add plugin from asdf-plugins repo or from git URL'
1015
'list:list installed plugins (--urls with URLs)'
11-
'list all:list all plugins registered in asdf-plugins repo'
12-
'remove:remove named plugin and all versions for it'
16+
'remove:remove named plugin and all packages for it'
1317
'update:update named plugin (or --all)'
1418
)
19+
20+
# Define main asdf commands array with descriptions
1521
local -a asdf_commands
1622
asdf_commands=( # 'asdf help' lists commands with help text
17-
# plugins
23+
# Plugin related commands
1824
'plugin:plugin management sub-commands'
1925

2026
# tools
27+
'help:Output documentation for plugin and tool'
2128
'install:install tool at stated version, or all from .tools-versions'
2229
'uninstall:remove a specific version of a tool'
2330
'current:display current versions for named tool (else all)'
2431
'latest:display latest version available to install for a named tool'
2532
'where:display install path for given tool at optional specified version'
2633
'which:display path to an executable'
27-
'set:set tool version'
34+
'set:Set a tool version in a .tool-version file'
2835
'list:list installed versions of a tool'
29-
'list all:list all available (remote) versions of a tool'
3036

31-
# utils
37+
# Utility commands
3238
'exec:executes the command shim for the current version'
3339
'env:prints or runs an executable under a command environment'
3440
'info:print os, shell and asdf debug information'
3541
'version:print the currently installed version of ASDF'
3642
'reshim:recreate shims for version of a tool'
3743
'shim:shim management sub-commands'
3844
'shimversions:list for given command which plugins and versions provide it'
39-
'update:update ASDF to the latest stable release (unless --head)'
4045
)
4146

47+
# Function to list all available plugins from the repository
4248
_asdf__available_plugins() {
4349
local plugin_dir="${asdf_dir:?}/repository/plugins"
4450
if [[ ! -d "$plugin_dir" ]]; then
@@ -52,6 +58,7 @@ _asdf__available_plugins() {
5258
compadd -a plugins
5359
}
5460

61+
# Function to list currently installed plugins
5562
_asdf__installed_plugins() {
5663
local plugin_dir="${asdf_dir:?}/plugins"
5764
if [[ ! -d "$plugin_dir" ]]; then
@@ -65,6 +72,7 @@ _asdf__installed_plugins() {
6572
compadd -a plugins
6673
}
6774

75+
# Function to list installed versions for a specific plugin
6876
_asdf__installed_versions_of() {
6977
local plugin_dir="${asdf_dir:?}/installs/${1:?need a plugin version}"
7078
if [[ ! -d "$plugin_dir" ]]; then
@@ -78,6 +86,7 @@ _asdf__installed_versions_of() {
7886
compadd -a versions
7987
}
8088

89+
# Similar to _asdf__installed_versions_of but includes 'system' as an option
8190
_asdf__installed_versions_of_plus_system() {
8291
local plugin_dir="${asdf_dir:?}/installs/${1:?need a plugin version}"
8392
if [[ ! -d "$plugin_dir" ]]; then
@@ -92,110 +101,246 @@ _asdf__installed_versions_of_plus_system() {
92101
compadd -a versions
93102
}
94103

104+
# Function to get available git references for a plugin
105+
_asdf__plugin_git_refs() {
106+
local plugin=$1
107+
local data_dir=${ASDF_DATA_DIR:-$HOME/.asdf}
108+
local plugin_path="$data_dir/plugins/$plugin"
95109

110+
if [[ -d "$plugin_path/.git" ]]; then
111+
# Get remote branches and format them
112+
git -C "$plugin_path" branch -r 2> /dev/null | \
113+
sed \
114+
-e 's/^[[:space:]]*[^\/]*\///' \
115+
-e 's/[[:space:]]*->.*$//' \
116+
-e 's/\(.*\)/\1:Remote branch \1/' | \
117+
sort -fd
118+
# Get tags and format them
119+
git -C "$plugin_path" tag 2> /dev/null | \
120+
sed -e 's/\(.*\)/\1:Tag \1/' | \
121+
sort -V
122+
# Get recent commit hashes and messages (last 10 commits)
123+
git -C "$plugin_path" log --pretty=format:'%h:%s' -n 10 2> /dev/null
124+
fi
125+
}
126+
127+
# Handle top-level command completion first
96128
if (( CURRENT == 2 )); then
97129
_arguments -C : '--version[version]' ':command:->command'
98130
fi
99131

132+
# Process command state for top-level commands
100133
case "$state" in
101134
(command)
102135
_describe -t asdf-commands 'ASDF Commands' asdf_commands
103136
return
104137
;;
105138
esac
139+
140+
# Get the subcommand for further processing
106141
subcmd="${words[2]}"
107-
subcmd2="${words[3]}"
108142

143+
# Complex completion logic for each subcommand
144+
# Each case handles specific completion scenarios for the respective command
109145
case "$subcmd" in
110146
(plugin)
111-
case "$subcmd2" in
147+
# Handle plugin subcommand completions with nested subcommands
148+
if (( CURRENT == 3 )); then
149+
_describe -t asdf-plugin-commands 'ASDF Plugin Commands' asdf_plugin_commands
150+
else
151+
local plugin_subcmd="${words[3]}"
152+
case "$plugin_subcmd" in
112153
(add)
154+
# Complete available plugins or URLs for add command
113155
if (( CURRENT == 4 )); then
114156
_asdf__available_plugins
115-
else
116-
if (( CURRENT == 5 )); then
117-
_arguments "*:${words[3]} plugin url:_urls"
118-
fi
157+
elif (( CURRENT == 5 )); then
158+
_arguments "*:${words[4]} plugin url:_urls"
119159
fi
120160
return
121161
;;
122162
(update)
123-
_alternative \
124-
'all:all:(--all)' \
125-
'asdf-available-plugins:Installed ASDF Plugins:_asdf__installed_plugins'
126-
return
127-
;;
163+
# Handle update command with support for --all flag and git refs
164+
if (( CURRENT == 4 )); then
165+
_alternative \
166+
'flags:flags:((--all\:"Update all installed plugins"))' \
167+
'asdf-available-plugins:Installed ASDF Plugins:_asdf__installed_plugins'
168+
elif (( CURRENT == 5 )); then
169+
if [[ ${words[4]} != "--all" ]]; then
170+
local -a refs
171+
while IFS=: read -r value descr; do
172+
refs+=( "${value}:${descr}" )
173+
done < <(_asdf__plugin_git_refs ${words[4]})
174+
_describe -V -t git-refs 'Git References' refs
175+
fi
176+
fi
177+
;;
128178
(remove)
179+
# Complete installed plugin names for remove command
129180
_asdf__installed_plugins
130181
return
131182
;;
132183
(list)
133-
_asdf__installed_plugins
134-
return
184+
# Handle list command options with support for --urls and --refs flags
185+
case $CURRENT in
186+
4)
187+
_alternative \
188+
'flags:flags:((--urls\:"Show repository URLs" --refs\:"Show Git references"))' \
189+
'commands:commands:((all\:"List all available plugins"))'
190+
return
191+
;;
192+
5)
193+
# Handle remaining available flags
194+
if [[ ${words[4]} == --* ]]; then
195+
local used_flags=("${words[@]}")
196+
local -a available_flags
197+
available_flags=()
198+
if [[ ! "${used_flags[@]}" =~ "--urls" ]]; then
199+
available_flags+=("--urls")
200+
fi
201+
if [[ ! "${used_flags[@]}" =~ "--refs" ]]; then
202+
available_flags+=("--refs")
203+
fi
204+
(( ${#available_flags[@]} )) && compadd -- "${available_flags[@]}"
205+
fi
206+
return
207+
;;
208+
esac
135209
;;
136-
(*)
137-
_describe -t asdf-commands 'ASDF Plugin Commands' asdf_plugin_commands
138-
return
139-
;;
140-
esac
210+
esac
211+
fi
141212
;;
142213
(current)
214+
# Complete with installed plugins for current command
143215
_asdf__installed_plugins
144216
;;
217+
(list)
218+
# Handle list command completions with support for 'all' and specific plugins
219+
case $CURRENT in
220+
3)
221+
_alternative \
222+
'commands:commands:((all\:"List all available (remote) versions"))' \
223+
'plugin:plugin:_asdf__installed_plugins'
224+
;;
225+
4)
226+
if [[ ${words[3]} == "all" ]]; then
227+
_asdf__installed_plugins
228+
else
229+
# For normal list: show installed versions with optional filter
230+
_asdf__installed_versions_of ${words[3]}
231+
fi
232+
;;
233+
5)
234+
# When listing all versions of a specific plugin
235+
if [[ ${words[3]} == "all" ]]; then
236+
local versions
237+
if versions=$(asdf list all "${words[4]}" 2>/dev/null); then
238+
_wanted "remote-versions-${words[4]}" \
239+
expl "Available versions of ${words[4]}" \
240+
compadd -- ${(f)versions}
241+
else
242+
_message "Unable to fetch versions for ${words[4]}"
243+
fi
244+
fi
245+
;;
246+
esac
247+
;;
248+
(help)
249+
# Complete installed plugins and their versions for help command
250+
if (( CURRENT == 3 )); then
251+
_asdf__installed_plugins
252+
elif (( CURRENT == 4 )); then
253+
_asdf__installed_versions_of ${words[3]}
254+
fi
255+
;;
145256
(install)
146-
if (( CURRENT == 3)); then
257+
# Handle complex install command completion with latest tag support
258+
if (( CURRENT == 3 )); then
147259
_asdf__installed_plugins
148260
return
149261
elif (( CURRENT == 4 )); then
150262
local tool="${words[3]}"
151263
local ver_prefix="${words[4]}"
152264
if [[ $ver_prefix == latest:* ]]; then
265+
# Handle latest:<version> syntax
153266
_wanted "latest-versions-$tool" \
154267
expl "Latest version" \
155268
compadd -- latest:${^$(asdf list all "$tool")}
156-
else
157-
_wanted "latest-tag-$tool" \
158-
expl "Latest version" \
159-
compadd -- 'latest' 'latest:'
160-
_wanted "remote-versions-$tool" \
161-
expl "Available versions of $tool" \
162-
compadd -- $(asdf list all "$tool")
269+
else
270+
# Offer both latest options and specific versions
271+
_wanted "latest-tag-$tool" \
272+
expl "Latest version" \
273+
compadd -- 'latest' 'latest:'
274+
_wanted "remote-versions-$tool" \
275+
expl "Available versions of $tool" \
276+
compadd -- $(asdf list all "$tool")
163277
fi
164278
return
165279
fi
166280
;;
167281
(latest)
282+
# Complete plugin names or --all flag for latest command
168283
if (( CURRENT == 3 )); then
169284
_alternative \
170-
'all:all:(--all)' \
285+
'flags:flags:((--all\:"Show latest version of all tools"))' \
171286
'asdf-available-plugins:Installed ASDF Plugins:_asdf__installed_plugins'
172-
elif (( CURRENT == 4)); then
173-
local tool="${words[3]}"
174-
local query=${words[4]}
175-
[[ -n $query ]] || query='[0-9]'
176-
_wanted "latest-pattern-$tool" \
177-
expl "Pattern to look for in matching versions of $tool" \
178-
compadd -- $(asdf list all "$tool" "$query")
179287
fi
180288
;;
181-
(uninstall|reshim)
182-
compset -n 2
183-
_arguments '1:plugin-name: _asdf__installed_plugins' '2:tool-version:{_asdf__installed_versions_of ${words[2]}}'
289+
(uninstall|reshim|where)
290+
# Handle complex install command completion with latest tag support
291+
if (( CURRENT == 3 )); then
292+
_asdf__installed_plugins
293+
return
294+
elif (( CURRENT == 4 )); then
295+
# For normal list: show installed versions with optional filter
296+
_asdf__installed_versions_of ${words[3]}
297+
return
298+
fi
184299
;;
185300
(set)
186-
compset -n 2
187-
_arguments '1:plugin-name: _asdf__installed_plugins' '2:tool-version:{_asdf__installed_versions_of_plus_system ${words[2]}}'
188-
;;
189-
(where)
190-
# version is optional
191-
compset -n 2
192-
_arguments '1:plugin-name: _asdf__installed_plugins' '2::tool-version:{_asdf__installed_versions_of ${words[2]}}'
301+
# Handle set command completion
302+
case $CURRENT in
303+
3)
304+
_alternative \
305+
'flags:flags:((-u\:"set version in user home directory" -p\:"set version in closest parent .tool-versions"))' \
306+
'plugin:plugin:_asdf__installed_plugins'
307+
;;
308+
4)
309+
if [[ ${words[3]} == -* ]]; then
310+
# After flag, complete with plugin name
311+
_asdf__installed_plugins
312+
else
313+
# Complete with available versions for the plugin
314+
local versions
315+
if versions=$(asdf list all "${words[3]}" 2>/dev/null); then
316+
_wanted "versions-${words[3]}" \
317+
expl "Available versions of ${words[3]}" \
318+
compadd -- ${(f)versions}
319+
fi
320+
fi
321+
;;
322+
*)
323+
# Support for multiple version specifications
324+
if [[ ${words[3]} == -* ]]; then
325+
local plugin="${words[4]}"
326+
else
327+
local plugin="${words[3]}"
328+
fi
329+
local versions
330+
if versions=$(asdf list all "$plugin" 2>/dev/null); then
331+
_wanted "versions-$plugin" \
332+
expl "Available versions of $plugin" \
333+
compadd -- ${(f)versions}
334+
fi
335+
;;
336+
esac
193337
;;
194338
(which|shimversions)
339+
# Complete with available shims for which and shimversions commands
195340
_wanted asdf-shims expl "ASDF Shims" compadd -- "${asdf_dir:?}/shims"/*(:t)
196341
;;
197342
(exec)
198-
# asdf exec <shim-cmd> [<shim-cmd args ...>]
343+
# Handle exec command completion with shim command and args
199344
if (( CURRENT == 3 )); then
200345
_wanted asdf-shims expl "ASDF Shims" compadd -- "${asdf_dir:?}/shims"/*(:t)
201346
else
@@ -204,7 +349,7 @@ case "$subcmd" in
204349
fi
205350
;;
206351
(env)
207-
# asdf exec <shim-name> <arbitrary-cmd> [<cmd args ...>]
352+
# Handle env command completion with shim name and arbitrary command
208353
if (( CURRENT == 3 )); then
209354
_wanted asdf-shims expl "ASDF Shims" compadd -- "${asdf_dir:?}/shims"/*(:t)
210355
else

0 commit comments

Comments
 (0)