-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathargsparse-completion.sh
253 lines (248 loc) · 7.11 KB
/
argsparse-completion.sh
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#!/usr/bin/env bash
# -*- tab-width: 4; encoding: utf-8; -*-
#
#########
# License:
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# Version 2, December 2004
#
# Copyright (C) 2004 Sam Hocevar <[email protected]>
#
# Everyone is permitted to copy and distribute verbatim or modified
# copies of this license document, and changing it is allowed as long
# as the name is changed.
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
# 0. You just DO WHAT THE FUCK YOU WANT TO.
#
#########
#
## @file
## @author Damien Nadé <[email protected]>
## @brief Bash completion for scripts using argsparse library.
## @copyright WTFPLv2
## @version 1.8
## @details
## @par URL
## https://github.com/Anvil/bash-argsparse @n
##
## @par Purpose
##
## To automatically enable, for bash-completion users, completion for
## scripts that use the argsparse library.
##
## @par Usage
##
## In your ~/.bashrc, add the following lines to enable completion for
## all your argsparse-written scripts:
##
## @code
## . argsparse-completion.sh
## complete -F _argsparse_complete [ your scripts names ... ]
## @endcode
##
## @par Required configuration
##
## argsparse-completion relies on a few shell settings:
##
## @li "sourcepath" shell option must be enabled. This should be
## enabled by default, but you can enforce it by running:
##
## @code
## shopt -s sourcepath
## @endcode
##
## If correctly enabled, the following command below should return
## this output.
##
## @code
## $ shopt sourcepath
## sourcepath on
## @endcode
##
## @par Limitations
##
## @li Every time the completion is invoked, the completed script will
## be sourced, up to either the argsparse_parse_options() function
## call or any the first return top-level statement. This means that
## up to this point the script should not have any side effect (like
## file system alteration, network connections, ...), and should
## avoid time-consuming tasks up to this point.
##
## @li Only a limited set of option types completion are currently
## implemented.
##
##
##
## @defgroup ArgsparseCompletion Bash Completion-related functions.
## @fn __argsparse_compgen()
## @private
## @brief A compgen wrapper.
## @details This function will just call compgen with given argument,
## safely adding $cur in the command line. Also if compgen_prefix is
## set, a -P option will be provided to compgen.
## @note __argsparse_compgen() makes use of the bash-completion
## standard variables.
## @param param... any set of compgen options
## @return compgen output and return code.
## @ingroup ArgsparseCompletion
__argsparse_compgen() {
if [[ -v compgen_prefix ]]
then
set -- "$@" -P "$compgen_prefix"
fi
compgen "$@" -- "$cur"
}
## @fn __argsparse_complete_value()
## @brief Complete the value an option.
## @details Run compgen with values matching given option. If an array
## "option_<optionname>_values" exists, complete with its values. Else
## if option has a type, complete values according to type when
## possible. Else do nothing.
## @note __argsparse_complete_value() makes use of the bash-completion
## standard variables.
## @param option a long option name.
## @ingroup ArgsparseCompletion
__argsparse_complete_value() {
[[ $# -eq 1 ]] || return 1
local option=$1
local array option_type
local -a values
if array=$(__argsparse_values_array_identifier "$option")
then
# Option accepts an enumeration of values.
values=( "${!array}" )
__argsparse_compgen -W "${values[*]}"
elif option_type=$(argsparse_has_option_property "$option" type)
then
case "$option_type" in
file|pipe|socket|link)
__argsparse_compgen -A file
;;
directory|group)
__argsparse_compgen -A "$option_type"
;;
username)
__argsparse_compgen -A user
;;
host|hostname)
__argsparse_compgen -A hostname
;;
hexa)
values=( "$cur"{a..f} )
;;&
int|hexa)
values+=( "$cur"{0..9} )
__argsparse_compgen -W "${values[*]}"
;;
esac
fi
}
## @fn __argsparse_complete_get_long()
## @brief Find the option we want to complete.
## @details If given word parameter is a recognized option, print the
## matching long option name. Also if "$cur" should be this option
## value, then return 0.
## @param word any word.
## @param long... a list of long options.
## @return the long option matching given parameter.
## @retval 0 if given word matches an option and if that option
## accepts a value.
## @private
## @ingroup ArgsparseCompletion
__argsparse_complete_get_long() {
[[ $# -ge 1 ]] || return 1
local word=$1
shift
local -a longs=( "$@" )
local long
if [[ $word = -[!-] ]]
then
long=$(argsparse_short_to_long "${word#-}") || return
elif __argsparse_index_of "$word" "${longs[@]}" >/dev/null
then
long=${word#--}
else
# Unknown option
return 1
fi
printf %s "$long"
argsparse_has_option_property "$long" value
}
## @fn __argsparse_complete()
## @brief Completion for the command stored in ${words[0]}.
## @details Will load the script to complete, and invoke compgen
## according to context.
## @retval non-zero if completed command cannot be sourced.
## @ingroup ArgsparseCompletion
__argsparse_complete() {
local script=${words[0]}
(
set +o posix
ARGSPARSE_COMPLETION_MODE=1
shopt -s expand_aliases
unalias -a
. "$script" 2>/dev/null || return
longs=( "${!__argsparse_options_descriptions[@]}" )
longs=( "${longs[@]/#/--}" )
option=${prev#--}
if __argsparse_index_of -- "${words[@]:0:${#words[@]}-1}" >/dev/null
then
# We're after the -- parameter, complete positionnal arguments
__argsparse_compgen -A file
elif long=$(__argsparse_complete_get_long "$prev" "${longs[@]}")
then
# We're right after an option that accepts a value, so
# complete a value.
__argsparse_complete_value "$long"
else
# Complete current token
case "$cur" in
--?*=*|-[!-]?*)
# Complete the --foo=something pattern as if
# prev=--foo and cur=something
# Complete -fsomething as if prev=-f and cur=something
if [[ "$cur" =~ ^((--[^=]+)=)(.*)$ ||
"$cur" =~ ^((-[^-]))(.*)$ ]]
then
compgen_prefix=${BASH_REMATCH[1]}
option=${BASH_REMATCH[2]}
cur=${BASH_REMATCH[3]}
long=$(__argsparse_complete_get_long \
"$option" "${longs[@]}") && \
__argsparse_complete_value "$long"
fi
;;
""|-)
shorts=( "${!__argsparse_short_options[@]}" )
shorts=( "${shorts[@]/#/-}" )
;;&
""|-*)
__argsparse_compgen -W "${shorts[*]} ${longs[*]}"
;;
*)
# Default non-option completion.
__argsparse_compgen -A file
;;
esac
fi
)
}
## @fn _argsparse_complete()
## @brief The argsparse completion function.
## @details To enable completion on a script that uses the argsparse
## library, call the "complete" built-in as following: @n
## @code
## complete -F _argsparse_complete <your script>
## @endcode
## @note Technically, this function gets a parameter (the name of the
## command to complete), but it is ignored.
## @ingroup ArgsparseCompletion
_argsparse_complete() {
local cur prev words cword split
_init_completion -s || return
COMPREPLY=( $(__argsparse_complete) )
}