Skip to content

Commit 1418237

Browse files
authored
Support spaces in bash completion file names (#576)
Fixes #379
1 parent 74ef98e commit 1418237

File tree

3 files changed

+80
-13
lines changed

3 files changed

+80
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
### Fixed
55
- Fixed `@argfiles` not being expanded when specified after a subcommand ([#570](https://github.com/ajalt/clikt/pull/570))
66
- Fixed syntax error in generated bash completions when an argument name contained spaces ([#563](https://github.com/ajalt/clikt/pull/563))
7+
- Support bash completions of file parameters when file names contain spaces or special characters ([#379](https://github.com/ajalt/clikt/pull/379))
78

89
## 5.0.2
910
### Changed

clikt/src/commonMain/kotlin/com/github/ajalt/clikt/completion/BashCompletionGenerator.kt

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ internal object BashCompletionGenerator {
1818
.flatMap { arg -> (1..arg.nvalues).map { "'${arg.name}'" } }
1919
.joinToString(" ")
2020
val varargName = command._arguments.find { it.nvalues < 0 }?.name.orEmpty()
21-
val paramsWithCandidates =
21+
val paramsWithCandidates: List<Pair<String, CompletionCandidates>> =
2222
(options.map { o -> o.first.maxByOrNull { it.length }!! to o.second } + arguments)
2323

2424
if (options.isEmpty() && subcommands.isEmpty() && arguments.isEmpty()) return ""
@@ -50,15 +50,26 @@ internal object BashCompletionGenerator {
5050

5151
append(
5252
"""
53-
|__skip_opt_eq() {
54-
| # this takes advantage of the fact that bash functions can write to local
55-
| # variables in their callers
56-
| (( i = i + 1 ))
57-
| if [[ "${'$'}{COMP_WORDS[${'$'}i]}" == '=' ]]; then
58-
| (( i = i + 1 ))
59-
| fi
60-
|}
61-
|
53+
|__skip_opt_eq() {
54+
| # this takes advantage of the fact that bash functions can write to local
55+
| # variables in their callers
56+
| (( i = i + 1 ))
57+
| if [[ "${'$'}{COMP_WORDS[${'$'}i]}" == '=' ]]; then
58+
| (( i = i + 1 ))
59+
| fi
60+
|}
61+
|
62+
|__complete_files() {
63+
| # Generate filename completions
64+
| local word="${'$'}1"
65+
| local IFS=${'$'}'\n'
66+
|
67+
| # quote each completion to support spaces and special characters
68+
| COMPREPLY=(${'$'}(compgen -o filenames -f -- "${'$'}word" | while read -r line; do
69+
| printf "%q\n" "${'$'}line"
70+
| done))
71+
|}
72+
|
6273
""".trimMargin()
6374
)
6475
}
@@ -233,7 +244,7 @@ internal object BashCompletionGenerator {
233244
}
234245

235246
CompletionCandidates.Path -> {
236-
append(" COMPREPLY=(\$(compgen -o default -- \"\${word}\"))\n")
247+
append(" __complete_files \"\${word}\"\n")
237248
}
238249

239250
CompletionCandidates.Hostname -> {

test/src/commonTest/kotlin/com/github/ajalt/clikt/completion/BashCompletionTest.kt

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ class BashCompletionTest : CompletionTestBase("bash") {
1717
| fi
1818
|}
1919
|
20+
|__complete_files() {
21+
| # Generate filename completions
22+
| local word="${'$'}1"
23+
| local IFS=${'$'}'\n'
24+
|
25+
| # quote each completion to support spaces and special characters
26+
| COMPREPLY=(${'$'}(compgen -o filenames -f -- "${'$'}word" | while read -r line; do
27+
| printf "%q\n" "${'$'}line"
28+
| done))
29+
|}
30+
|
2031
|__c_complete___o() {
2132
| COMPREPLY=(${'$'}(compgen -W "${'$'}(echo foo bar)" -- "${'$'}{COMP_WORDS[${'$'}COMP_CWORD]}"))
2233
|}
@@ -100,11 +111,22 @@ class BashCompletionTest : CompletionTestBase("bash") {
100111
| # this takes advantage of the fact that bash functions can write to local
101112
| # variables in their callers
102113
| (( i = i + 1 ))
103-
| if [[ "${"$"}{COMP_WORDS[${"$"}i]}" == '=' ]]; then
114+
| if [[ "${'$'}{COMP_WORDS[${'$'}i]}" == '=' ]]; then
104115
| (( i = i + 1 ))
105116
| fi
106117
|}
107118
|
119+
|__complete_files() {
120+
| # Generate filename completions
121+
| local word="${'$'}1"
122+
| local IFS=${'$'}'\n'
123+
|
124+
| # quote each completion to support spaces and special characters
125+
| COMPREPLY=(${'$'}(compgen -o filenames -f -- "${'$'}word" | while read -r line; do
126+
| printf "%q\n" "${'$'}line"
127+
| done))
128+
|}
129+
|
108130
|_c() {
109131
| local i=1
110132
| local in_param=''
@@ -381,6 +403,17 @@ class BashCompletionTest : CompletionTestBase("bash") {
381403
| fi
382404
|}
383405
|
406+
|__complete_files() {
407+
| # Generate filename completions
408+
| local word="${'$'}1"
409+
| local IFS=${'$'}'\n'
410+
|
411+
| # quote each completion to support spaces and special characters
412+
| COMPREPLY=(${'$'}(compgen -o filenames -f -- "${'$'}word" | while read -r line; do
413+
| printf "%q\n" "${'$'}line"
414+
| done))
415+
|}
416+
|
384417
|_c() {
385418
| local i=1
386419
| local in_param=''
@@ -455,6 +488,17 @@ class BashCompletionTest : CompletionTestBase("bash") {
455488
| fi
456489
|}
457490
|
491+
|__complete_files() {
492+
| # Generate filename completions
493+
| local word="${'$'}1"
494+
| local IFS=${'$'}'\n'
495+
|
496+
| # quote each completion to support spaces and special characters
497+
| COMPREPLY=(${'$'}(compgen -o filenames -f -- "${'$'}word" | while read -r line; do
498+
| printf "%q\n" "${'$'}line"
499+
| done))
500+
|}
501+
|
458502
|_c() {
459503
| local i=1
460504
| local in_param=''
@@ -525,7 +569,7 @@ class BashCompletionTest : CompletionTestBase("bash") {
525569
| "--none")
526570
| ;;
527571
| "--path")
528-
| COMPREPLY=(${'$'}(compgen -o default -- "${'$'}{word}"))
572+
| __complete_files "${'$'}{word}"
529573
| ;;
530574
| "--host")
531575
| COMPREPLY=(${'$'}(compgen -A hostname -- "${'$'}{word}"))
@@ -564,6 +608,17 @@ class BashCompletionTest : CompletionTestBase("bash") {
564608
| fi
565609
|}
566610
|
611+
|__complete_files() {
612+
| # Generate filename completions
613+
| local word="${'$'}1"
614+
| local IFS=${'$'}'\n'
615+
|
616+
| # quote each completion to support spaces and special characters
617+
| COMPREPLY=(${'$'}(compgen -o filenames -f -- "${'$'}word" | while read -r line; do
618+
| printf "%q\n" "${'$'}line"
619+
| done))
620+
|}
621+
|
567622
|_c() {
568623
| local i=1
569624
| local in_param=''

0 commit comments

Comments
 (0)