@@ -1190,10 +1190,52 @@ _comp_initialize()
1190
1190
return 0
1191
1191
}
1192
1192
1193
- # Helper function for _parse_help and _parse_usage.
1193
+ # Helper function for _comp_compgen_help and _comp_compgen_usage.
1194
+ # Obtain the help output based on the arguments.
1195
+ # @param $@ args Arguments specified to the caller.
1196
+ # @var[out] _lines
1197
+ # @return 2 if the usage is wrong, 1 if no output is obtained, or otherwise 0.
1198
+ _comp_compgen_help__get_help_lines ()
1199
+ {
1200
+ local -a help_cmd
1201
+ case ${1-} in
1202
+ -)
1203
+ if (( $# > 1 )) ; then
1204
+ printf ' bash_completion: %s -: extra arguments for -\n' " ${FUNCNAME[1]} " >&2
1205
+ printf ' usage: %s -\n' " ${FUNCNAME[1]} " >&2
1206
+ printf ' usage: %s -c cmd args...\n' " ${FUNCNAME[1]} " >&2
1207
+ printf ' usage: %s [-- args...]\n' " ${FUNCNAME[1]} " >&2
1208
+ return 2
1209
+ fi
1210
+ help_cmd=(exec cat)
1211
+ ;;
1212
+ -c)
1213
+ if (( $# < 2 )) ; then
1214
+ printf ' bash_completion: %s -c: no command is specified\n' " ${FUNCNAME[1]} " >&2
1215
+ printf ' usage: %s -\n' " ${FUNCNAME[1]} " >&2
1216
+ printf ' usage: %s -c cmd args...\n' " ${FUNCNAME[1]} " >&2
1217
+ printf ' usage: %s [-- args...]\n' " ${FUNCNAME[1]} " >&2
1218
+ return 2
1219
+ fi
1220
+ help_cmd=(" ${@: 2} " )
1221
+ ;;
1222
+ --) shift 1 ;&
1223
+ * )
1224
+ local ret
1225
+ _comp_dequote " ${comp_args[0]-} " || ret=${comp_args[0]-}
1226
+ help_cmd=(" ${ret:- false} " " $@ " )
1227
+ ;;
1228
+ esac
1229
+
1230
+ local ret
1231
+ _comp_split -l ret " $( LC_ALL=C " ${help_cmd[@]} " 2>&1 ) " &&
1232
+ _lines=(" ${ret[@]} " )
1233
+ }
1234
+
1235
+ # Helper function for _comp_compgen_help and _comp_compgen_usage.
1236
+ # @var[in,out] _options Add options
1194
1237
# @return True (0) if an option was found, False (> 0) otherwise
1195
- # TODO: rename per API conventions, rework to use vars rather than outputting
1196
- __parse_options ()
1238
+ _comp_compgen_help__parse ()
1197
1239
{
1198
1240
local option option2 i
1199
1241
@@ -1219,108 +1261,89 @@ __parse_options()
1219
1261
if [[ $option =~ (\[ (( no| dont)-? )\]). ]]; then
1220
1262
option2 =${option/ " ${BASH_REMATCH[1]} " / }
1221
1263
option2 =${option2%% [<{().[]* }
1222
- printf '%s\n' "${option2/ =*/ =} "
1264
+ _options+=( "${option2/ =*/ =} ")
1223
1265
option=${option/ " ${BASH_REMATCH[1]} " / " ${BASH_REMATCH[2]} " }
1224
1266
fi
1225
1267
1226
1268
option=${option%% [<{().[]* }
1227
1269
option=${option/ =*/ =}
1228
1270
[[ $option ]] || return 1
1229
1271
1230
- printf '%s\n' "$option "
1272
+ _options+=( "$option ")
1231
1273
}
1232
1274
1233
- # Parse GNU style help output of the given command.
1234
- # @param $1 command; if "-", read from stdin and ignore rest of args
1235
- # @param $2 command options (default: --help)
1275
+ # Parse GNU style help output of the given command and generate and store
1276
+ # completions in an array. The help output is produced in the way depending on
1277
+ # the usage:
1278
+ # usage: _comp_compgen_help - # read from stdin
1279
+ # usage: _comp_compgen_help -c cmd args... # run "cmd args..."
1280
+ # usage: _comp_compgen_help [[--] args...] # run "${comp_args[0]} args..."
1281
+ # When no arguments are specified, `--help` is assumed.
1236
1282
#
1237
- # TODO: rename per API conventions, rework to use vars rather than outputting
1238
- _parse_help ()
1283
+ # @var[in] comp_args[ 0 ]
1284
+ _comp_compgen_help ()
1239
1285
{
1240
- local IFS=$' \t\n'
1241
- local reset_monitor=$(shopt -po monitor) reset_lastpipe=$(shopt -p lastpipe) reset_noglob=$(shopt -po noglob)
1242
- set +o monitor
1243
- shopt -s lastpipe
1244
- set -o noglob
1286
+ (($# )) || set -- -- --help
1245
1287
1246
- local cmd=$1
1247
- local line rc=1
1248
- (
1249
- case $cmd in
1250
- -) exec cat ;;
1251
- *)
1252
- # shellcheck disable=SC2086
1253
- _comp_dequote "$cmd " && LC_ALL=C "$ret " ${2:- --help} 2 >& 1
1254
- ;;
1255
- esac
1256
- ) |
1257
- while read -r line; do
1258
-
1259
- [[ $line == *([[:blank:]])-* ]] || continue
1260
- # transform "-f FOO, --foo=FOO" to "-f , --foo=FOO" etc
1261
- while [[ $line =~ ((^|[^-])-[A-Za-z0 -9 ?][[:space:]]+)\[?[A-Z0 -9 ]+([,_-]+[A-Z0 -9 ]+)?(\.\.+)?\]? ]]; do
1262
- line=${line/ " ${BASH_REMATCH[0]} " / " ${BASH_REMATCH[1]} " }
1263
- done
1264
- __parse_options "${line// or / , } " && rc= 0
1288
+ local -a _lines
1289
+ _comp_compgen_help__get_help_lines " $@ " || return " $? "
1265
1290
1291
+ local -a _options=()
1292
+ local _line
1293
+ for _line in " ${_lines[@]} " ; do
1294
+ [[ $_line == * ([[:blank:]])-* ]] || continue
1295
+ # transform "-f FOO, --foo=FOO" to "-f , --foo=FOO" etc
1296
+ while [[ $_line =~ (( ^| [^- ])- [A- Za- z0 - 9 ? ][[: space: ]]+ )\[? [A- Z0 - 9 ]+ ([, _- ]+ [A- Z0 - 9 ]+ )? (\.\.+ )? \]? ]]; do
1297
+ _line=${_line/ " ${BASH_REMATCH[0]} " / " ${BASH_REMATCH[1]} " }
1266
1298
done
1299
+ _comp_compgen_help__parse "${_line// or / , } "
1300
+ done
1301
+ ((${# _options[@]} )) || return 1
1267
1302
1268
- $reset_monitor
1269
- $reset_lastpipe
1270
- $reset_noglob
1271
- return $rc
1303
+ _comp_compgen -- -W ' "${_options[@]}"'
1304
+ return 0
1272
1305
}
1273
1306
1274
- # Parse BSD style usage output (options in brackets) of the given command.
1275
- # @param $1 command; if "-", read from stdin and ignore rest of args
1276
- # @param $2 command options (default: --usage)
1277
- #
1278
- # TODO: rename per API conventions, rework to use vars rather than outputting
1279
- _parse_usage()
1280
- {
1281
- local IFS=$' \t\n'
1282
- local reset_monitor=$(shopt -po monitor) reset_lastpipe=$(shopt -p lastpipe) reset_noglob=$(shopt -po noglob)
1283
- set +o monitor
1284
- shopt -s lastpipe
1285
- set -o noglob
1286
-
1287
- local cmd=$1
1288
- local line match option i char rc=1
1289
- (
1290
- case $cmd in
1291
- -) exec cat ;;
1292
- *)
1293
- # shellcheck disable=SC2086
1294
- _comp_dequote "$cmd " && LC_ALL=C "$ret " ${2:- --usage} 2 >& 1
1295
- ;;
1296
- esac
1297
- ) |
1298
- while read -r line; do
1299
-
1300
- while [[ $line =~ \[[[:space:]]*(-[^]]+)[[:space:]]*\] ]]; do
1301
- match=${BASH_REMATCH[0]}
1302
- option=${BASH_REMATCH[1]}
1303
- case $option in
1304
- -?(\[)+([a-zA-Z0 -9 ?]))
1305
- # Treat as bundled short options
1306
- for (( i = 1 ; i < ${# option} ; i++ )) ; do
1307
- char=${option: i: 1}
1308
- [[ $char != ' [' ]] && printf ' %s\n' -" $char " && rc=0
1309
- done
1310
- ;;
1311
- * )
1312
- __parse_options " $option " && rc= 0
1313
- ;;
1314
- esac
1315
- line= ${line#* " $match " }
1316
- done
1317
-
1307
+ # Parse BSD style usage output (options in brackets) of the given command. The
1308
+ # help output is produced in the way depending on the usage:
1309
+ # usage: _comp_compgen_usage - # read from stdin
1310
+ # usage: _comp_compgen_usage -c cmd args... # run "cmd args..."
1311
+ # usage: _comp_compgen_usage [[--] args...] # run "${comp_args[0]} args..."
1312
+ # When no arguments are specified, `--usage` is assumed.
1313
+ #
1314
+ # @var[in] comp_args[0]
1315
+ _comp_compgen_usage ()
1316
+ {
1317
+ (( $# )) || set -- -- --usage
1318
+
1319
+ local -a _lines
1320
+ _comp_compgen_help__get_help_lines " $@ " || return " $? "
1321
+
1322
+ local -a _options=()
1323
+ local _line _match _option _i _char
1324
+ for _line in " ${_lines[@]} " ; do
1325
+ while [[ $_line =~ \[ [[:space:]]* (-[^]]+)[[:space:]]* \] ]]; do
1326
+ _match=${BASH_REMATCH[0]}
1327
+ _option=${BASH_REMATCH[1]}
1328
+ case $_option in
1329
+ -? (\[ )+ ([a-zA-Z0-9? ]))
1330
+ # Treat as bundled short options
1331
+ for (( _i = 1 ; _i < ${# _option} ; _i++ )) ; do
1332
+ _char=${_option: _i: 1}
1333
+ [[ $_char != ' [' ]] && _options+=(" -$_char " )
1334
+ done
1335
+ ;;
1336
+ * )
1337
+ _comp_compgen_help__parse " $_option "
1338
+ ;;
1339
+ esac
1340
+ _line=${_line#* " $_match " }
1318
1341
done
1342
+ done
1343
+ (( ${# _options[@]} )) || return 1
1319
1344
1320
- $reset_monitor
1321
- $reset_lastpipe
1322
- $reset_noglob
1323
- return $rc
1345
+ _comp_compgen -- -W ' "${_options[@]}"'
1346
+ return 0
1324
1347
}
1325
1348
1326
1349
# This function completes on signal names (minus the SIG prefix)
0 commit comments