Skip to content

Commit

Permalink
Quote argument names in bash completion
Browse files Browse the repository at this point in the history
  • Loading branch information
ajalt committed Feb 9, 2025
1 parent 38c6e81 commit 74ef98e
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Unreleased
### 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))

## 5.0.2
### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ internal object BashCompletionGenerator {
for ((name, completion) in paramsWithCandidates) {
append(
"""
| $name)
| "$name")
|
""".trimMargin()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ class BashCompletionTest : CompletionTestBase("bash") {
| [[ -z "${'$'}{in_param}" ]] && in_param=${'$'}{vararg_name}
|
| case "${'$'}{in_param}" in
| --o)
| "--o")
| COMPREPLY=(${'$'}(compgen -F __c_complete___o 2>/dev/null))
| ;;
| --help)
| "--help")
| ;;
| A)
| "A")
| COMPREPLY=(${'$'}(compgen -F __c_complete_A 2>/dev/null))
| ;;
| esac
Expand Down Expand Up @@ -155,7 +155,7 @@ class BashCompletionTest : CompletionTestBase("bash") {
| [[ -z "${"$"}{in_param}" ]] && in_param=${"$"}{vararg_name}
|
| case "${"$"}{in_param}" in
| --help)
| "--help")
| ;;
| *)
| COMPREPLY=(${"$"}(compgen -W 'sub sub-command' -- "${"$"}{word}"))
Expand Down Expand Up @@ -205,7 +205,7 @@ class BashCompletionTest : CompletionTestBase("bash") {
| [[ -z "${"$"}{in_param}" ]] && in_param=${"$"}{vararg_name}
|
| case "${"$"}{in_param}" in
| --help)
| "--help")
| ;;
| esac
|}
Expand Down Expand Up @@ -260,7 +260,7 @@ class BashCompletionTest : CompletionTestBase("bash") {
| [[ -z "${"$"}{in_param}" ]] && in_param=${"$"}{vararg_name}
|
| case "${"$"}{in_param}" in
| --help)
| "--help")
| ;;
| *)
| COMPREPLY=(${"$"}(compgen -W 'sub-sub long-sub-command' -- "${"$"}{word}"))
Expand Down Expand Up @@ -310,7 +310,7 @@ class BashCompletionTest : CompletionTestBase("bash") {
| [[ -z "${"$"}{in_param}" ]] && in_param=${"$"}{vararg_name}
|
| case "${"$"}{in_param}" in
| --help)
| "--help")
| ;;
| esac
|}
Expand Down Expand Up @@ -357,7 +357,7 @@ class BashCompletionTest : CompletionTestBase("bash") {
| [[ -z "${"$"}{in_param}" ]] && in_param=${"$"}{vararg_name}
|
| case "${"$"}{in_param}" in
| --help)
| "--help")
| ;;
| esac
|}
Expand Down Expand Up @@ -428,9 +428,9 @@ class BashCompletionTest : CompletionTestBase("bash") {
| [[ -z "${'$'}{in_param}" ]] && in_param=${'$'}{vararg_name}
|
| case "${'$'}{in_param}" in
| --no-flag)
| "--no-flag")
| ;;
| --help)
| "--help")
| ;;
| esac
|}
Expand Down Expand Up @@ -522,24 +522,24 @@ class BashCompletionTest : CompletionTestBase("bash") {
| [[ -z "${'$'}{in_param}" ]] && in_param=${'$'}{vararg_name}
|
| case "${'$'}{in_param}" in
| --none)
| "--none")
| ;;
| --path)
| "--path")
| COMPREPLY=(${'$'}(compgen -o default -- "${'$'}{word}"))
| ;;
| --host)
| "--host")
| COMPREPLY=(${'$'}(compgen -A hostname -- "${'$'}{word}"))
| ;;
| --user)
| "--user")
| COMPREPLY=(${'$'}(compgen -A user -- "${'$'}{word}"))
| ;;
| --fixed)
| "--fixed")
| COMPREPLY=(${'$'}(compgen -W 'foo bar' -- "${'$'}{word}"))
| ;;
| ARGUSER)
| "ARGUSER")
| COMPREPLY=(${'$'}(compgen -A user -- "${'$'}{word}"))
| ;;
| ARGFIXED)
| "ARGFIXED")
| COMPREPLY=(${'$'}(compgen -W 'baz qux' -- "${'$'}{word}"))
| ;;
| esac
Expand All @@ -548,4 +548,72 @@ class BashCompletionTest : CompletionTestBase("bash") {
|complete -F _c c
"""
}

override fun `arg names with spaces expected`(): String {
return """
|#!/usr/bin/env bash
|# Command completion for c
|# Generated by Clikt
|
|__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
|}
|
|_c() {
| local i=1
| local in_param=''
| local fixed_arg_names=('foo bar')
| local vararg_name=''
| local can_parse_options=1
|
| while [[ ${'$'}{i} -lt ${'$'}COMP_CWORD ]]; do
| if [[ ${'$'}{can_parse_options} -eq 1 ]]; then
| case "${'$'}{COMP_WORDS[${'$'}i]}" in
| --)
| can_parse_options=0
| (( i = i + 1 ));
| continue
| ;;
| -h|--help)
| __skip_opt_eq
| in_param=''
| continue
| ;;
| esac
| fi
| case "${'$'}{COMP_WORDS[${'$'}i]}" in
| *)
| (( i = i + 1 ))
| # drop the head of the array
| fixed_arg_names=("${'$'}{fixed_arg_names[@]:1}")
| ;;
| esac
| done
| local word="${'$'}{COMP_WORDS[${'$'}COMP_CWORD]}"
| if [[ "${'$'}{word}" =~ ^[-] ]]; then
| COMPREPLY=(${'$'}(compgen -W '-h --help' -- "${'$'}{word}"))
| return
| fi
|
| # We're either at an option's value, or the first remaining fixed size
| # arg, or the vararg if there are no fixed args left
| [[ -z "${'$'}{in_param}" ]] && in_param=${'$'}{fixed_arg_names[0]}
| [[ -z "${'$'}{in_param}" ]] && in_param=${'$'}{vararg_name}
|
| case "${'$'}{in_param}" in
| "--help")
| ;;
| "foo bar")
| ;;
| esac
|}
|
|complete -F _c c
"""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,23 @@ abstract class CompletionTestBase(private val shell: String) {
)
}

@JsName("arg_names_with_spaces_expected")
abstract fun `arg names with spaces expected`(): String

@[Test JsName("arg_names_with_spaces")]
fun `arg names with spaces`() {
class C : TestCommand(autoCompleteEnvvar = "TEST_COMPLETE") {
val a by argument(help = "help", name = "foo bar")
}

doTest(
`arg names with spaces expected`(),
C().completionOption(hidden = true)
)

}


@[Test JsName("completion_command")]
fun `completion command`() {
val message = shouldThrow<PrintCompletionMessage> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,18 @@ class FishCompletionTest : CompletionTestBase("fish") {
|
"""
}

override fun `arg names with spaces expected`(): String {
return """
|# Command completion for c
|# Generated by Clikt
|
|## Options for c
|complete -c c -s h -l help -d 'Show this message and exit'
|
|## Arguments for c
|complete -c c -d 'help'
|
"""
}
}

0 comments on commit 74ef98e

Please sign in to comment.