Skip to content

Commit 2fa4e6d

Browse files
committed
fix(complete): fix bash dynamic-engine COMP_WORDBREAKS word reassembly
The bash glue script emitted by the dynamic completion engine (CompleteEnv / write_registration in env/shells.rs) passes words[COMP_CWORD]="$2" to the completer. Bash tokenizes COMP_WORDS by splitting on COMP_WORDBREAKS characters (= and : by default), so --option=value arrives as three tokens ("--option", "=", "value") instead of one. This breaks completion for --option=value style arguments. Fix: embed a word reassembly loop (adapted from git-completion and bash-completion's _comp__reassemble_words) that re-merges tokens split on = and : before passing words to the Rust completer. The loop tracks _CLAP_COMPLETE_INDEX in parallel so the completer receives the correct position in the reassembled array. The reassembly is gated on bash >= 4 (same condition as the original block) and only affects = and : characters from COMP_WORDBREAKS, leaving all other tokenization unchanged. Snapshot updated accordingly. Testing: - cargo test -p clap_complete: 9 passed, 0 failed - cargo test -p clap_complete --features clap_complete/unstable-dynamic: 109 passed, 0 failed - Manual interactive test: sourced the generated completion script for the exhaustive example and verified TAB-completion works correctly. Fixes #6363
1 parent d142d8f commit 2fa4e6d

2 files changed

Lines changed: 52 additions & 2 deletions

File tree

  • clap_complete

clap_complete/src/env/shells.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,32 @@ _clap_complete_NAME() {
3939
fi
4040
local words=("${COMP_WORDS[@]}")
4141
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
42-
words[COMP_CWORD]="$2"
42+
# Reassemble words that bash split on COMP_WORDBREAKS characters
43+
# (typically = and :) so that --option=value arrives as one token.
44+
# Based on the approach used by git-completion and bash-completion.
45+
local _i _j=0 _line=$COMP_LINE _ref
46+
local _wb="[${COMP_WORDBREAKS//[^=:]/}]"
47+
words=()
48+
_CLAP_COMPLETE_INDEX=$COMP_CWORD
49+
for (( _i = 0; _i < ${#COMP_WORDS[@]}; _i++, _j++ )); do
50+
while [[ _i -gt 0 && ${COMP_WORDS[_i]} == $_wb ]]; do
51+
[[ $_line != [[:blank:]]* ]] && (( _j >= 2 )) && (( _j-- ))
52+
_ref="words[$_j]"
53+
printf -v "$_ref" %s "${!_ref-}${COMP_WORDS[_i]}"
54+
(( _i == COMP_CWORD )) && _CLAP_COMPLETE_INDEX=$_j
55+
_line=${_line#*"${COMP_WORDS[_i]}"}
56+
if (( _i < ${#COMP_WORDS[@]} - 1 )); then
57+
(( _i++ ))
58+
else
59+
break 2
60+
fi
61+
[[ $_line == [[:blank:]]* ]] && (( _j++ ))
62+
done
63+
_ref="words[$_j]"
64+
printf -v "$_ref" %s "${!_ref-}${COMP_WORDS[_i]}"
65+
_line=${_line#*"${COMP_WORDS[_i]}"}
66+
(( _i == COMP_CWORD )) && _CLAP_COMPLETE_INDEX=$_j
67+
done
4368
fi
4469
COMPREPLY=( $( \
4570
_CLAP_IFS="$IFS" \

clap_complete/tests/snapshots/home/dynamic-env/exhaustive/bash/.bashrc

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,32 @@ _clap_complete_exhaustive() {
1212
fi
1313
local words=("${COMP_WORDS[@]}")
1414
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
15-
words[COMP_CWORD]="$2"
15+
# Reassemble words that bash split on COMP_WORDBREAKS characters
16+
# (typically = and :) so that --option=value arrives as one token.
17+
# Based on the approach used by git-completion and bash-completion.
18+
local _i _j=0 _line=$COMP_LINE _ref
19+
local _wb="[${COMP_WORDBREAKS//[^=:]/}]"
20+
words=()
21+
_CLAP_COMPLETE_INDEX=$COMP_CWORD
22+
for (( _i = 0; _i < ${#COMP_WORDS[@]}; _i++, _j++ )); do
23+
while [[ _i -gt 0 && ${COMP_WORDS[_i]} == $_wb ]]; do
24+
[[ $_line != [[:blank:]]* ]] && (( _j >= 2 )) && (( _j-- ))
25+
_ref="words[$_j]"
26+
printf -v "$_ref" %s "${!_ref-}${COMP_WORDS[_i]}"
27+
(( _i == COMP_CWORD )) && _CLAP_COMPLETE_INDEX=$_j
28+
_line=${_line#*"${COMP_WORDS[_i]}"}
29+
if (( _i < ${#COMP_WORDS[@]} - 1 )); then
30+
(( _i++ ))
31+
else
32+
break 2
33+
fi
34+
[[ $_line == [[:blank:]]* ]] && (( _j++ ))
35+
done
36+
_ref="words[$_j]"
37+
printf -v "$_ref" %s "${!_ref-}${COMP_WORDS[_i]}"
38+
_line=${_line#*"${COMP_WORDS[_i]}"}
39+
(( _i == COMP_CWORD )) && _CLAP_COMPLETE_INDEX=$_j
40+
done
1641
fi
1742
COMPREPLY=( $( \
1843
_CLAP_IFS="$IFS" \

0 commit comments

Comments
 (0)