Skip to content

Commit 2dec3ce

Browse files
committed
fix(_comp_count_args): check optarg correctly
When the current implementation checks an option argument, it tests whether the previous word matches $2 (i.e., a pattern of options taking an option argument). This implementation has multiple issues: * When the options taking an option argument does not start with `-`, the option is counted as an independent argument. For example, `ssh` completion passes `@(-c|[-+]o)` as $2, but `+o` is counted as an argument with the current implementation. * An option argument that looks like an option taking an option argument can prevent the next word counted as an argument. For example, when `cmd -o -o arg` is processed with $2 being `-o`, the second `-o` should be treated as an option argument and `arg` should be counted as an argument. However, with the current implementation, `arg` is not counted because the previous word `-o` matches the pattern. * When `cmd -o -- -x` is processed with $2 being `-o`, `--` should be treated as an option argument so should lose its special meaning, and `-x` is still treated as an option. However, with the current implementation, `--` does not lose its special meaning, so `-x` is unexpectedly treated as an argument. * Also, with the current implementation, when $2 is not specified, an argument after an empty is not counted as an argument because $2 matches an empty word, (though Readline usually do not store an empty word in COMP_WORDS). This patch fixes those issues by changing how options taking an option argument are processed.
1 parent 4099c8a commit 2dec3ce

File tree

2 files changed

+22
-2
lines changed

2 files changed

+22
-2
lines changed

bash_completion

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,8 +2192,9 @@ _comp_count_args()
21922192
ret=1
21932193
for ((i = 1; i < cword; i++)); do
21942194
# shellcheck disable=SC2053
2195-
if [[ (${words[i]} != -?* || ${3-} && ${words[i]} == ${3-}) &&
2196-
${words[i - 1]} != ${2-} ]]; then
2195+
if [[ ${2-} && ${words[i]} == ${2-} ]]; then
2196+
((i++))
2197+
elif [[ ${words[i]} != -?* || ${3-} && ${words[i]} == ${3-} ]]; then
21972198
((ret++))
21982199
elif [[ ${words[i]} == -- ]]; then
21992200
((ret += cword - i - 1))

test/t/unit/test_unit_count_args.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,22 @@ def test_12_exclude_optarg_3(self, bash):
111111
bash, "(a -o -x -y c)", 4, "a -o -x -y c", 11, arg='"" "-o" "-x"'
112112
)
113113
assert output == "1"
114+
115+
def test_13_no_optarg_chain_1(self, bash):
116+
"""an option argument should not take another option argument"""
117+
output = self._test(
118+
bash, "(a -o -o -o -o c)", 5, "a -o -o -o -o c", 14, arg='"" "-o"'
119+
)
120+
assert output == "1"
121+
122+
def test_13_no_optarg_chain_2(self, bash):
123+
"""an option argument should not take another option argument"""
124+
output = self._test(
125+
bash,
126+
"(a -o -o b -o -o c)",
127+
6,
128+
"a -o -o b -o -o c",
129+
16,
130+
arg='"" "-o"',
131+
)
132+
assert output == "1"

0 commit comments

Comments
 (0)