Skip to content

Commit c9faaee

Browse files
akinomyogascop
andcommitted
feat(bash_completion): add a utility _comp_xfunc
Co-authored-by: Ville Skyttä <[email protected]>
1 parent a2db7ad commit c9faaee

File tree

5 files changed

+112
-1
lines changed

5 files changed

+112
-1
lines changed

bash_completion

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2426,6 +2426,22 @@ _completion_loader()
24262426
} &&
24272427
complete -D -F _completion_loader
24282428
2429+
# Function for loading and calling functions from dynamically loaded
2430+
# completion files that may not have been sourced yet.
2431+
# @param $1 completion file to load function from in case it is missing
2432+
# @param $2 the xfunc name. When it does not start with `_',
2433+
# `_comp_xfunc_${1//[^a-zA-Z0-9_]/_}_$2' is used for the actual name of the
2434+
# shell function.
2435+
# @param $3... if any, specifies the arguments that are passed to the xfunc.
2436+
_comp_xfunc()
2437+
{
2438+
local xfunc_name=$2
2439+
[[ $xfunc_name == _* ]] ||
2440+
xfunc_name=_comp_xfunc_${1//[^a-zA-Z0-9_]/_}_$xfunc_name
2441+
declare -F "$xfunc_name" &>/dev/null || __load_completion "$1"
2442+
"$xfunc_name" "${@:3}"
2443+
}
2444+
24292445
# Function for loading and calling functions from dynamically loaded
24302446
# completion files that may not have been sourced yet.
24312447
# @param $1 completion file to load function from in case it is missing
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Dummy completion file for _comp_xfunc tests -*- shell-script -*-
2+
3+
if declare -F _comp_xfunc_xfunc_test1_utility1 &>/dev/null; then
4+
echo "_comp_xfunc_xfunc_test1_utility1 is already defined"
5+
return 1
6+
fi
7+
8+
_comp_xfunc_xfunc_test1_utility1() {
9+
printf 'util1['
10+
printf '<%s>' "$@"
11+
printf ']\n'
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Dummy completion file for _comp_xfunc tests -*- shell-script -*-
2+
3+
if declare -F _comp_xfunc_non_standard_name &>/dev/null; then
4+
echo "_comp_xfunc_non_standard_name is already defined"
5+
return 1
6+
fi
7+
8+
_comp_xfunc_non_standard_name() {
9+
printf 'util2['
10+
printf '<%s>' "$@"
11+
printf ']\n'
12+
}

test/t/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ def bash(request) -> pexpect.spawn:
267267
# FIXME: Tests shouldn't depend on dimensions, but it's difficult to
268268
# expect robustly enough for Bash to wrap lines anywhere (e.g. inside
269269
# MAGIC_MARK). Increase window width to reduce wrapping.
270-
dimensions=(24, 160),
270+
dimensions=(24, 200),
271271
# TODO? codec_errors="replace",
272272
)
273273
bash.expect_exact(PS1)

test/t/unit/test_unit_xfunc.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import pytest
2+
3+
from conftest import assert_bash_exec, bash_env_saved
4+
5+
6+
@pytest.mark.bashcomp(cmd=None)
7+
class TestUnitXfunc:
8+
def test_1(self, bash):
9+
with bash_env_saved(bash) as bash_env:
10+
bash_env.write_variable(
11+
"BASH_COMPLETION_USER_DIR", "$PWD/_comp_xfunc", quote=False
12+
)
13+
14+
# test precondition
15+
assert_bash_exec(
16+
bash,
17+
"! declare -F _comp_xfunc_xfunc_test1_utility1 &>/dev/null",
18+
)
19+
20+
# first invocation (completion/xfunc-test1 is sourced)
21+
output = assert_bash_exec(
22+
bash,
23+
"_comp_xfunc xfunc-test1 utility1 'a b' cde fgh",
24+
want_output=True,
25+
)
26+
assert output.strip() == "util1[<a b><cde><fgh>]"
27+
28+
# test precondition
29+
assert_bash_exec(
30+
bash, "declare -F _comp_xfunc_xfunc_test1_utility1 &>/dev/null"
31+
)
32+
33+
# second invocation (completion/xfunc-test1 is not sourced)
34+
output = assert_bash_exec(
35+
bash,
36+
"_comp_xfunc xfunc-test1 utility1 'a b' cde fgh",
37+
want_output=True,
38+
)
39+
assert output.strip() == "util1[<a b><cde><fgh>]"
40+
41+
def test_2(self, bash):
42+
with bash_env_saved(bash) as bash_env:
43+
bash_env.write_variable(
44+
"BASH_COMPLETION_USER_DIR", "$PWD/_comp_xfunc", quote=False
45+
)
46+
47+
# test precondition
48+
assert_bash_exec(
49+
bash, "! declare -F _comp_xfunc_non_standard_name &>/dev/null"
50+
)
51+
52+
# first invocation (completion/xfunc-test2 is sourced)
53+
output = assert_bash_exec(
54+
bash,
55+
"_comp_xfunc xfunc-test2 _comp_xfunc_non_standard_name 'a b' cde fgh",
56+
want_output=True,
57+
)
58+
assert output.strip() == "util2[<a b><cde><fgh>]"
59+
60+
# test precondition
61+
assert_bash_exec(
62+
bash, "declare -F _comp_xfunc_non_standard_name &>/dev/null"
63+
)
64+
65+
# second invocation (completion/xfunc-test2 is not sourced)
66+
output = assert_bash_exec(
67+
bash,
68+
"_comp_xfunc xfunc-test2 _comp_xfunc_non_standard_name 'a b' cde fgh",
69+
want_output=True,
70+
)
71+
assert output.strip() == "util2[<a b><cde><fgh>]"

0 commit comments

Comments
 (0)