Skip to content

Commit 163211e

Browse files
authored
fix: Improve zsh completion script generator (#219)
* `shellCommand` stores output in a local array that is passed to `_describe` to handle spaces and other punctuation in the shell command output * elide the help abstract if it is empty, as it confuses the zsh completion system * set the `_<commandName>_commandname` to `$words[1]`, which is the full name of the command used to invoke the completion. This ensures invocations like `./build/debug/math` ... as passed on to the `_custom_completion` command.
1 parent be80c40 commit 163211e

File tree

3 files changed

+25
-21
lines changed

3 files changed

+25
-21
lines changed

Sources/ArgumentParser/Completions/ZshCompletionsGenerator.swift

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ struct ZshCompletionsGenerator {
1717
return """
1818
#compdef \(type._commandName)
1919
local context state state_descr line
20-
_\(type._commandName)_commandname="\(type._commandName)"
20+
_\(type._commandName)_commandname=$words[1]
2121
typeset -A opt_args
2222
2323
\(generateCompletionFunction([type]))
@@ -118,8 +118,12 @@ extension String {
118118
}
119119

120120
extension ArgumentDefinition {
121-
var zshCompletionAbstract: String? {
122-
help.help?.abstract.zshEscapingSingleQuotes()
121+
var zshCompletionAbstract: String {
122+
guard
123+
let abstract = help.help?.abstract,
124+
!abstract.isEmpty
125+
else { return "" }
126+
return "[\(abstract.zshEscapingSingleQuotes())]"
123127
}
124128

125129
func zshCompletionString(_ commands: [ParsableCommand.Type]) -> String? {
@@ -137,14 +141,14 @@ extension ArgumentDefinition {
137141
line = ""
138142
case 1:
139143
line = """
140-
\(names[0].synopsisString)[\(zshCompletionAbstract ?? "")]
144+
\(names[0].synopsisString)\(zshCompletionAbstract)
141145
"""
142146
default:
143147
let synopses = names.map { $0.synopsisString }
144148
line = """
145149
(\(synopses.joined(separator: " ")))'\
146150
{\(synopses.joined(separator: ","))}\
147-
'[\(zshCompletionAbstract ?? "")]
151+
'\(zshCompletionAbstract)
148152
"""
149153
}
150154

@@ -170,7 +174,7 @@ extension ArgumentDefinition {
170174
return "(" + list.joined(separator: " ") + ")"
171175

172176
case .shellCommand(let command):
173-
return "{_describe '' $(\(command))}"
177+
return "{local -a list; list=(${(f)\"$(\(command))\"}); _describe '''' list}"
174178

175179
case .custom:
176180
// Generate a call back into the command to retrieve a completions list

Tests/ArgumentParserExampleTests/MathExampleTests.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ complete -F _math math
327327
private let zshCompletionScriptText = """
328328
#compdef math
329329
local context state state_descr line
330-
_math_commandname="math"
330+
_math_commandname=$words[1]
331331
typeset -A opt_args
332332
333333
_math() {
@@ -466,14 +466,14 @@ _math_stats_quantiles() {
466466
':one-of-four:(alphabet alligator branch braggart)'
467467
':custom-arg:{_custom_completion $_math_commandname ---completion stats quantiles -- customArg $words}'
468468
':values:'
469-
'--test-success-exit-code[]'
470-
'--test-failure-exit-code[]'
471-
'--test-validation-exit-code[]'
472-
'--test-custom-exit-code[]:test-custom-exit-code:'
473-
'--file[]:file:_files -g '"'"'*.txt *.md'"'"''
474-
'--directory[]:directory:_files -/'
475-
'--shell[]:shell:{_describe '' $(head -100 /usr/share/dict/words | tail -50)}'
476-
'--custom[]:custom:{_custom_completion $_math_commandname ---completion stats quantiles -- --custom $words}'
469+
'--test-success-exit-code'
470+
'--test-failure-exit-code'
471+
'--test-validation-exit-code'
472+
'--test-custom-exit-code:test-custom-exit-code:'
473+
'--file:file:_files -g '"'"'*.txt *.md'"'"''
474+
'--directory:directory:_files -/'
475+
'--shell:shell:{local -a list; list=(${(f)"$(head -100 /usr/share/dict/words | tail -50)"}); _describe '''' list}'
476+
'--custom:custom:{_custom_completion $_math_commandname ---completion stats quantiles -- --custom $words}'
477477
'(-h --help)'{-h,--help}'[Print help information.]'
478478
)
479479
_arguments -w -s -S $args[@] && ret=0

Tests/ArgumentParserUnitTests/CompletionScriptTests.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,19 +112,19 @@ extension CompletionScriptTests {
112112
private let zshBaseCompletions = """
113113
#compdef base
114114
local context state state_descr line
115-
_base_commandname="base"
115+
_base_commandname=$words[1]
116116
typeset -A opt_args
117117
118118
_base() {
119119
integer ret=1
120120
local -a args
121121
args+=(
122122
'--name[The user'"'"'s name.]:name:'
123-
'--kind[]:kind:(one two custom-three)'
124-
'--other-kind[]:other-kind:(1 2 3)'
125-
'--path1[]:path1:_files'
126-
'--path2[]:path2:_files'
127-
'--path3[]:path3:(a b c)'
123+
'--kind:kind:(one two custom-three)'
124+
'--other-kind:other-kind:(1 2 3)'
125+
'--path1:path1:_files'
126+
'--path2:path2:_files'
127+
'--path3:path3:(a b c)'
128128
'(-h --help)'{-h,--help}'[Print help information.]'
129129
)
130130
_arguments -w -s -S $args[@] && ret=0

0 commit comments

Comments
 (0)