Skip to content

Commit

Permalink
Support spaces in bash completion file names (#576)
Browse files Browse the repository at this point in the history
Fixes #379
  • Loading branch information
ajalt authored Feb 9, 2025
1 parent 74ef98e commit 1418237
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
### Fixed
- Fixed `@argfiles` not being expanded when specified after a subcommand ([#570](https://github.com/ajalt/clikt/pull/570))
- Fixed syntax error in generated bash completions when an argument name contained spaces ([#563](https://github.com/ajalt/clikt/pull/563))
- Support bash completions of file parameters when file names contain spaces or special characters ([#379](https://github.com/ajalt/clikt/pull/379))

## 5.0.2
### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal object BashCompletionGenerator {
.flatMap { arg -> (1..arg.nvalues).map { "'${arg.name}'" } }
.joinToString(" ")
val varargName = command._arguments.find { it.nvalues < 0 }?.name.orEmpty()
val paramsWithCandidates =
val paramsWithCandidates: List<Pair<String, CompletionCandidates>> =
(options.map { o -> o.first.maxByOrNull { it.length }!! to o.second } + arguments)

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

append(
"""
|__skip_opt_eq() {
| # this takes advantage of the fact that bash functions can write to local
| # variables in their callers
| (( i = i + 1 ))
| if [[ "${'$'}{COMP_WORDS[${'$'}i]}" == '=' ]]; then
| (( i = i + 1 ))
| fi
|}
|
|__skip_opt_eq() {
| # this takes advantage of the fact that bash functions can write to local
| # variables in their callers
| (( i = i + 1 ))
| if [[ "${'$'}{COMP_WORDS[${'$'}i]}" == '=' ]]; then
| (( i = i + 1 ))
| fi
|}
|
|__complete_files() {
| # Generate filename completions
| local word="${'$'}1"
| local IFS=${'$'}'\n'
|
| # quote each completion to support spaces and special characters
| COMPREPLY=(${'$'}(compgen -o filenames -f -- "${'$'}word" | while read -r line; do
| printf "%q\n" "${'$'}line"
| done))
|}
|
""".trimMargin()
)
}
Expand Down Expand Up @@ -233,7 +244,7 @@ internal object BashCompletionGenerator {
}

CompletionCandidates.Path -> {
append(" COMPREPLY=(\$(compgen -o default -- \"\${word}\"))\n")
append(" __complete_files \"\${word}\"\n")
}

CompletionCandidates.Hostname -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ class BashCompletionTest : CompletionTestBase("bash") {
| fi
|}
|
|__complete_files() {
| # Generate filename completions
| local word="${'$'}1"
| local IFS=${'$'}'\n'
|
| # quote each completion to support spaces and special characters
| COMPREPLY=(${'$'}(compgen -o filenames -f -- "${'$'}word" | while read -r line; do
| printf "%q\n" "${'$'}line"
| done))
|}
|
|__c_complete___o() {
| COMPREPLY=(${'$'}(compgen -W "${'$'}(echo foo bar)" -- "${'$'}{COMP_WORDS[${'$'}COMP_CWORD]}"))
|}
Expand Down Expand Up @@ -100,11 +111,22 @@ class BashCompletionTest : CompletionTestBase("bash") {
| # this takes advantage of the fact that bash functions can write to local
| # variables in their callers
| (( i = i + 1 ))
| if [[ "${"$"}{COMP_WORDS[${"$"}i]}" == '=' ]]; then
| if [[ "${'$'}{COMP_WORDS[${'$'}i]}" == '=' ]]; then
| (( i = i + 1 ))
| fi
|}
|
|__complete_files() {
| # Generate filename completions
| local word="${'$'}1"
| local IFS=${'$'}'\n'
|
| # quote each completion to support spaces and special characters
| COMPREPLY=(${'$'}(compgen -o filenames -f -- "${'$'}word" | while read -r line; do
| printf "%q\n" "${'$'}line"
| done))
|}
|
|_c() {
| local i=1
| local in_param=''
Expand Down Expand Up @@ -381,6 +403,17 @@ class BashCompletionTest : CompletionTestBase("bash") {
| fi
|}
|
|__complete_files() {
| # Generate filename completions
| local word="${'$'}1"
| local IFS=${'$'}'\n'
|
| # quote each completion to support spaces and special characters
| COMPREPLY=(${'$'}(compgen -o filenames -f -- "${'$'}word" | while read -r line; do
| printf "%q\n" "${'$'}line"
| done))
|}
|
|_c() {
| local i=1
| local in_param=''
Expand Down Expand Up @@ -455,6 +488,17 @@ class BashCompletionTest : CompletionTestBase("bash") {
| fi
|}
|
|__complete_files() {
| # Generate filename completions
| local word="${'$'}1"
| local IFS=${'$'}'\n'
|
| # quote each completion to support spaces and special characters
| COMPREPLY=(${'$'}(compgen -o filenames -f -- "${'$'}word" | while read -r line; do
| printf "%q\n" "${'$'}line"
| done))
|}
|
|_c() {
| local i=1
| local in_param=''
Expand Down Expand Up @@ -525,7 +569,7 @@ class BashCompletionTest : CompletionTestBase("bash") {
| "--none")
| ;;
| "--path")
| COMPREPLY=(${'$'}(compgen -o default -- "${'$'}{word}"))
| __complete_files "${'$'}{word}"
| ;;
| "--host")
| COMPREPLY=(${'$'}(compgen -A hostname -- "${'$'}{word}"))
Expand Down Expand Up @@ -564,6 +608,17 @@ class BashCompletionTest : CompletionTestBase("bash") {
| fi
|}
|
|__complete_files() {
| # Generate filename completions
| local word="${'$'}1"
| local IFS=${'$'}'\n'
|
| # quote each completion to support spaces and special characters
| COMPREPLY=(${'$'}(compgen -o filenames -f -- "${'$'}word" | while read -r line; do
| printf "%q\n" "${'$'}line"
| done))
|}
|
|_c() {
| local i=1
| local in_param=''
Expand Down

0 comments on commit 1418237

Please sign in to comment.