Skip to content

Commit dce16c3

Browse files
committed
- Fix completion escaping
1 parent c669296 commit dce16c3

15 files changed

Lines changed: 184 additions & 90 deletions

lib/completely/pattern.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,16 @@ def compgen
5454
def compgen!
5555
result = []
5656
result << actions.join(' ').to_s if actions.any?
57-
result << %[-W "$(#{function_name} "#{words.join ' '}")"] if words.any?
57+
result << %[-W "$(#{function_name} #{quoted_words.join ' '})"] if words.any?
5858
result.any? ? result.join(' ') : nil
5959
end
60+
61+
def quoted_words
62+
@quoted_words ||= words.map { |word| %("#{escape_for_double_quotes word}") }
63+
end
64+
65+
def escape_for_double_quotes(word)
66+
word.gsub(/["\\]/, '\\\\\&')
67+
end
6068
end
6169
end

lib/completely/templates/template.erb

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# Modifying it manually is not recommended
66

77
<%= function_name %>_filter() {
8-
local words="$1"
8+
local words=("$@")
99
local cur=${COMP_WORDS[COMP_CWORD]}
1010
local result=()
1111

@@ -17,12 +17,12 @@
1717

1818
if [[ "${cur:0:1}" == "-" ]]; then
1919
# Completing an option: offer everything (including options)
20-
echo "$words"
20+
result=("${words[@]}")
2121

2222
else
2323
# Completing a non-option: offer only non-options,
2424
# and don't re-offer ones already used earlier in the line.
25-
for word in $words; do
25+
for word in "${words[@]}"; do
2626
[[ "${word:0:1}" == "-" ]] && continue
2727

2828
local seen=0
@@ -34,9 +34,15 @@
3434
done
3535
((!seen)) && result+=("$word")
3636
done
37-
38-
echo "${result[*]}"
3937
fi
38+
39+
local escaped=()
40+
for word in "${result[@]}"; do
41+
printf -v word '%q' "$word"
42+
escaped+=("$word")
43+
done
44+
45+
echo "${escaped[*]}"
4046
}
4147

4248
<%= function_name %>() {

spec/approvals/cli/generated-script

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# Modifying it manually is not recommended
66

77
_mygit_completions_filter() {
8-
local words="$1"
8+
local words=("$@")
99
local cur=${COMP_WORDS[COMP_CWORD]}
1010
local result=()
1111

@@ -17,12 +17,12 @@ _mygit_completions_filter() {
1717

1818
if [[ "${cur:0:1}" == "-" ]]; then
1919
# Completing an option: offer everything (including options)
20-
echo "$words"
20+
result=("${words[@]}")
2121

2222
else
2323
# Completing a non-option: offer only non-options,
2424
# and don't re-offer ones already used earlier in the line.
25-
for word in $words; do
25+
for word in "${words[@]}"; do
2626
[[ "${word:0:1}" == "-" ]] && continue
2727

2828
local seen=0
@@ -34,9 +34,15 @@ _mygit_completions_filter() {
3434
done
3535
((!seen)) && result+=("$word")
3636
done
37-
38-
echo "${result[*]}"
3937
fi
38+
39+
local escaped=()
40+
for word in "${result[@]}"; do
41+
printf -v word '%q' "$word"
42+
escaped+=("$word")
43+
done
44+
45+
echo "${escaped[*]}"
4046
}
4147

4248
_mygit_completions() {
@@ -59,15 +65,15 @@ _mygit_completions() {
5965
;;
6066

6167
'status'*)
62-
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "--help --verbose --branch -b")" -- "$cur")
68+
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "--help" "--verbose" "--branch" "-b")" -- "$cur")
6369
;;
6470

6571
'init'*)
6672
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -W "$(_mygit_completions_filter "--bare")" -- "$cur")
6773
;;
6874

6975
*)
70-
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "-h -v --help --version init status")" -- "$cur")
76+
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "-h" "-v" "--help" "--version" "init" "status")" -- "$cur")
7177
;;
7278

7379
esac

spec/approvals/cli/generated-script-alt

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# Modifying it manually is not recommended
66

77
_mycomps_filter() {
8-
local words="$1"
8+
local words=("$@")
99
local cur=${COMP_WORDS[COMP_CWORD]}
1010
local result=()
1111

@@ -17,12 +17,12 @@ _mycomps_filter() {
1717

1818
if [[ "${cur:0:1}" == "-" ]]; then
1919
# Completing an option: offer everything (including options)
20-
echo "$words"
20+
result=("${words[@]}")
2121

2222
else
2323
# Completing a non-option: offer only non-options,
2424
# and don't re-offer ones already used earlier in the line.
25-
for word in $words; do
25+
for word in "${words[@]}"; do
2626
[[ "${word:0:1}" == "-" ]] && continue
2727

2828
local seen=0
@@ -34,9 +34,15 @@ _mycomps_filter() {
3434
done
3535
((!seen)) && result+=("$word")
3636
done
37-
38-
echo "${result[*]}"
3937
fi
38+
39+
local escaped=()
40+
for word in "${result[@]}"; do
41+
printf -v word '%q' "$word"
42+
escaped+=("$word")
43+
done
44+
45+
echo "${escaped[*]}"
4046
}
4147

4248
_mycomps() {
@@ -59,15 +65,15 @@ _mycomps() {
5965
;;
6066

6167
'status'*)
62-
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mycomps_filter "--help --verbose --branch -b")" -- "$cur")
68+
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mycomps_filter "--help" "--verbose" "--branch" "-b")" -- "$cur")
6369
;;
6470

6571
'init'*)
6672
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -W "$(_mycomps_filter "--bare")" -- "$cur")
6773
;;
6874

6975
*)
70-
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mycomps_filter "-h -v --help --version init status")" -- "$cur")
76+
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mycomps_filter "-h" "-v" "--help" "--version" "init" "status")" -- "$cur")
7177
;;
7278

7379
esac

spec/approvals/cli/generated-wrapped-script

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ give_comps() {
66
echo $'# Modifying it manually is not recommended'
77
echo $''
88
echo $'_mygit_completions_filter() {'
9-
echo $' local words="$1"'
9+
echo $' local words=("$@")'
1010
echo $' local cur=${COMP_WORDS[COMP_CWORD]}'
1111
echo $' local result=()'
1212
echo $''
@@ -18,12 +18,12 @@ give_comps() {
1818
echo $''
1919
echo $' if [[ "${cur:0:1}" == "-" ]]; then'
2020
echo $' # Completing an option: offer everything (including options)'
21-
echo $' echo "$words"'
21+
echo $' result=("${words[@]}")'
2222
echo $''
2323
echo $' else'
2424
echo $' # Completing a non-option: offer only non-options,'
2525
echo $' # and don\'t re-offer ones already used earlier in the line.'
26-
echo $' for word in $words; do'
26+
echo $' for word in "${words[@]}"; do'
2727
echo $' [[ "${word:0:1}" == "-" ]] && continue'
2828
echo $''
2929
echo $' local seen=0'
@@ -35,9 +35,15 @@ give_comps() {
3535
echo $' done'
3636
echo $' ((!seen)) && result+=("$word")'
3737
echo $' done'
38-
echo $''
39-
echo $' echo "${result[*]}"'
4038
echo $' fi'
39+
echo $''
40+
echo $' local escaped=()'
41+
echo $' for word in "${result[@]}"; do'
42+
echo $' printf -v word \'%q\' "$word"'
43+
echo $' escaped+=("$word")'
44+
echo $' done'
45+
echo $''
46+
echo $' echo "${escaped[*]}"'
4147
echo $'}'
4248
echo $''
4349
echo $'_mygit_completions() {'
@@ -60,15 +66,15 @@ give_comps() {
6066
echo $' ;;'
6167
echo $''
6268
echo $' \'status\'*)'
63-
echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "--help --verbose --branch -b")" -- "$cur")'
69+
echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "--help" "--verbose" "--branch" "-b")" -- "$cur")'
6470
echo $' ;;'
6571
echo $''
6672
echo $' \'init\'*)'
6773
echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -W "$(_mygit_completions_filter "--bare")" -- "$cur")'
6874
echo $' ;;'
6975
echo $''
7076
echo $' *)'
71-
echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "-h -v --help --version init status")" -- "$cur")'
77+
echo $' while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "-h" "-v" "--help" "--version" "init" "status")" -- "$cur")'
7278
echo $' ;;'
7379
echo $''
7480
echo $' esac'

spec/approvals/cli/test/completely-tester-1.sh

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fi
1313
# Modifying it manually is not recommended
1414

1515
_mygit_completions_filter() {
16-
local words="$1"
16+
local words=("$@")
1717
local cur=${COMP_WORDS[COMP_CWORD]}
1818
local result=()
1919

@@ -25,12 +25,12 @@ _mygit_completions_filter() {
2525

2626
if [[ "${cur:0:1}" == "-" ]]; then
2727
# Completing an option: offer everything (including options)
28-
echo "$words"
28+
result=("${words[@]}")
2929

3030
else
3131
# Completing a non-option: offer only non-options,
3232
# and don't re-offer ones already used earlier in the line.
33-
for word in $words; do
33+
for word in "${words[@]}"; do
3434
[[ "${word:0:1}" == "-" ]] && continue
3535

3636
local seen=0
@@ -42,9 +42,15 @@ _mygit_completions_filter() {
4242
done
4343
((!seen)) && result+=("$word")
4444
done
45-
46-
echo "${result[*]}"
4745
fi
46+
47+
local escaped=()
48+
for word in "${result[@]}"; do
49+
printf -v word '%q' "$word"
50+
escaped+=("$word")
51+
done
52+
53+
echo "${escaped[*]}"
4854
}
4955

5056
_mygit_completions() {
@@ -67,15 +73,15 @@ _mygit_completions() {
6773
;;
6874

6975
'status'*)
70-
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "--help --verbose --branch -b")" -- "$cur")
76+
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "--help" "--verbose" "--branch" "-b")" -- "$cur")
7177
;;
7278

7379
'init'*)
7480
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -W "$(_mygit_completions_filter "--bare")" -- "$cur")
7581
;;
7682

7783
*)
78-
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "-h -v --help --version init status")" -- "$cur")
84+
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "-h" "-v" "--help" "--version" "init" "status")" -- "$cur")
7985
;;
8086

8187
esac

spec/approvals/cli/test/completely-tester-2.sh

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fi
1313
# Modifying it manually is not recommended
1414

1515
_mygit_completions_filter() {
16-
local words="$1"
16+
local words=("$@")
1717
local cur=${COMP_WORDS[COMP_CWORD]}
1818
local result=()
1919

@@ -25,12 +25,12 @@ _mygit_completions_filter() {
2525

2626
if [[ "${cur:0:1}" == "-" ]]; then
2727
# Completing an option: offer everything (including options)
28-
echo "$words"
28+
result=("${words[@]}")
2929

3030
else
3131
# Completing a non-option: offer only non-options,
3232
# and don't re-offer ones already used earlier in the line.
33-
for word in $words; do
33+
for word in "${words[@]}"; do
3434
[[ "${word:0:1}" == "-" ]] && continue
3535

3636
local seen=0
@@ -42,9 +42,15 @@ _mygit_completions_filter() {
4242
done
4343
((!seen)) && result+=("$word")
4444
done
45-
46-
echo "${result[*]}"
4745
fi
46+
47+
local escaped=()
48+
for word in "${result[@]}"; do
49+
printf -v word '%q' "$word"
50+
escaped+=("$word")
51+
done
52+
53+
echo "${escaped[*]}"
4854
}
4955

5056
_mygit_completions() {
@@ -67,15 +73,15 @@ _mygit_completions() {
6773
;;
6874

6975
'status'*)
70-
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "--help --verbose --branch -b")" -- "$cur")
76+
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "--help" "--verbose" "--branch" "-b")" -- "$cur")
7177
;;
7278

7379
'init'*)
7480
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -A directory -W "$(_mygit_completions_filter "--bare")" -- "$cur")
7581
;;
7682

7783
*)
78-
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "-h -v --help --version init status")" -- "$cur")
84+
while read -r; do COMPREPLY+=("$REPLY"); done < <(compgen -W "$(_mygit_completions_filter "-h" "-v" "--help" "--version" "init" "status")" -- "$cur")
7985
;;
8086

8187
esac

0 commit comments

Comments
 (0)