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