Skip to content

Commit 39cc200

Browse files
committed
feat(_comp_compgen): support -i cmd and -x cmd
1 parent d678b9f commit 39cc200

File tree

4 files changed

+82
-5
lines changed

4 files changed

+82
-5
lines changed

bash_completion

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -457,11 +457,14 @@ _comp_compgen__error_fallback()
457457
# @return True (0) if at least one completion is generated, False (1) if no
458458
# completion is generated, or 2 with an incorrect usage.
459459
#
460-
# Usage #2: _comp_compgen [-aR|-v arr|-c cur|-C dir] name args...
460+
# Usage #2: _comp_compgen [-aR|-v arr|-c cur|-C dir|-i cmd|-x cmd] name args...
461461
# Call the generator `_comp_compgen_NAME ARGS...` with the specified options.
462462
# This provides a common interface to call the functions `_comp_compgen_NAME`,
463463
# which produce completion candidates, with custom options [-alR|-v arr|-c
464464
# cur]. The option `-F sep` is not used with this usage.
465+
# OPTIONS
466+
# -x cmd Call exported generator `_comp_xfunc_CMD_compgen_NAME`
467+
# -i cmd Call internal generator `_comp_cmd_CMD__compgen_NAME`
465468
# @param $1... name args Calls the function _comp_compgen_NAME with the
466469
# specified ARGS (if $1 does not start with a hyphen `-`). The options
467470
# [-alR|-v arr|-c cur] are inherited by the child calls of `_comp_compgen`
@@ -516,7 +519,7 @@ _comp_compgen()
516519
shopt -u nocasematch
517520
fi
518521
local OPTIND=1 OPTARG="" OPTERR=0 _opt
519-
while getopts ':av:Rc:C:lF:' _opt "$@"; do
522+
while getopts ':av:Rc:C:lF:i:x:' _opt "$@"; do
520523
case $_opt in
521524
a) _append=set ;;
522525
v)
@@ -537,6 +540,20 @@ _comp_compgen()
537540
;;
538541
l) _has_ifs=set _ifs=$'\n' ;;
539542
F) _has_ifs=set _ifs=$OPTARG ;;
543+
[ix])
544+
if [[ ! $OPTARG ]]; then
545+
printf 'bash_completion: %s: -%s: invalid command name `%s'\''\n' "$FUNCNAME" "$_opt" "$OPTARG" >&2
546+
return 2
547+
elif [[ $_icmd ]]; then
548+
printf 'bash_completion: %s: -%s: `-i %s'\'' is already specified\n' "$FUNCNAME" "$_opt" "$_icmd" >&2
549+
return 2
550+
elif [[ $_xcmd ]]; then
551+
printf 'bash_completion: %s: -%s: `-x %s'\'' is already specified\n' "$FUNCNAME" "$_opt" "$_xcmd" >&2
552+
return 2
553+
fi
554+
;;&
555+
i) _icmd=$OPTARG ;;
556+
x) _xcmd=$OPTARG ;;
540557
*)
541558
printf 'bash_completion: %s: usage error\n' "$FUNCNAME" >&2
542559
return 2
@@ -558,8 +575,16 @@ _comp_compgen()
558575
return 2
559576
fi
560577

561-
if ! declare -F "_comp_compgen_$1" &>/dev/null; then
562-
printf 'bash_completion: %s: unrecognized category `%s'\'' (function _comp_compgen_%s not found)\n' "$FUNCNAME" "$1" "$1" >&2
578+
local -a _generator
579+
if [[ $_icmd ]]; then
580+
_generator=("_comp_cmd_${_icmd//[^a-zA-Z0-9_]/_}__compgen_$1")
581+
elif [[ $_xcmd ]]; then
582+
_generator=(_comp_xfunc "$_xcmd" "compgen_$1")
583+
else
584+
_generator=("_comp_compgen_$1")
585+
fi
586+
if ! declare -F "${_generator[0]}" &>/dev/null; then
587+
printf 'bash_completion: %s: unrecognized generator `%s'\'' (function %s not found)\n' "$FUNCNAME" "$1" "${_generator[0]}" >&2
563588
return 2
564589
fi
565590

@@ -581,7 +606,7 @@ _comp_compgen()
581606
# Note: we use $1 as a part of a function name, and we use $2... as
582607
# arguments to the function if any.
583608
# shellcheck disable=SC2145
584-
_comp_compgen_"$@"
609+
"${_generator[@]}" "${@:2}"
585610
local _status=$?
586611

587612
# Go back to the original directory.
@@ -595,6 +620,10 @@ _comp_compgen()
595620
fi
596621

597622
# usage: _comp_compgen [options] -- [compgen_options]
623+
if [[ $_icmd || $_xcmd ]]; then
624+
printf 'bash_completion: %s: generator name is unspecified for `%s'\''\n' "$FUNCNAME" "${_icmd:+-i $_icmd}${_xcmd:+x $_xcmd}" >&2
625+
return 2
626+
fi
598627

599628
# Note: $* in the below checks would be affected by uncontrolled IFS in
600629
# bash >= 5.0, so we need to set IFS to the normal value. The behavior in
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Dummy completion file for _comp_compgen tests -*- shell-script -*-
2+
3+
_comp_xfunc_compgen_cmd1_compgen_generator1() {
4+
_comp_compgen -- -W '5foo 6bar 7baz'
5+
}
6+
7+
_comp_cmd_compgen_cmd1__compgen_generator2() {
8+
_comp_compgen -- -W '5abc 6def 7ghi'
9+
}
10+
11+
_comp_cmd_compgen_cmd1() {
12+
local cur prev words cword comp_args
13+
_comp_initialize -- "$@" || return
14+
_comp_compgen -- -W '012 123 234'
15+
_comp_compgen -ai compgen-cmd1 generator2
16+
} &&
17+
complete -F _comp_cmd_compgen_cmd1 compgen-cmd1
18+
19+
# ex: filetype=sh
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Dummy completion file for _comp_compgen tests -*- shell-script -*-
2+
3+
_comp_cmd_compgen_cmd2() {
4+
local cur prev words cword comp_args
5+
_comp_initialize -- "$@" || return
6+
_comp_compgen -- -W '012 123 234'
7+
_comp_compgen -ax compgen-cmd1 generator1
8+
} &&
9+
complete -F _comp_cmd_compgen_cmd2 compgen-cmd2
10+
11+
# ex: filetype=sh

test/t/unit/test_unit_compgen.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,21 @@ def test_6_option_C_4(self, functions, completion):
128128
# Note: we are not in the original directory that "b" exists, so Bash
129129
# will not suffix a slash to the directory name.
130130
assert completion == "b"
131+
132+
def test_7_icmd(self, bash, functions):
133+
with bash_env_saved(bash) as bash_env:
134+
bash_env.write_variable(
135+
"BASH_COMPLETION_USER_DIR", "$PWD/_comp_compgen", quote=False
136+
)
137+
138+
completions = assert_complete(bash, "compgen-cmd1 '")
139+
assert completions == ["012", "123", "234", "5abc", "6def", "7ghi"]
140+
141+
def test_7_xcmd(self, bash, functions):
142+
with bash_env_saved(bash) as bash_env:
143+
bash_env.write_variable(
144+
"BASH_COMPLETION_USER_DIR", "$PWD/_comp_compgen", quote=False
145+
)
146+
147+
completions = assert_complete(bash, "compgen-cmd2 '")
148+
assert completions == ["012", "123", "234", "5foo", "6bar", "7baz"]

0 commit comments

Comments
 (0)