Skip to content

Commit ab21374

Browse files
committed
Only complete positionals through the first repeating positional in zsh.
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
1 parent 71d51af commit ab21374

File tree

1 file changed

+46
-41
lines changed

1 file changed

+46
-41
lines changed

Sources/ArgumentParser/Completions/ZshCompletionsGenerator.swift

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,52 @@ extension CommandInfoV0 {
6060
private var completionFunctions: String {
6161
let functionName = completionFunctionName
6262

63-
let argumentSpecsAndSetupScripts = (arguments ?? []).compactMap {
64-
argumentSpecAndSetupScript($0)
63+
var repeatingPositionalIndicator = ""
64+
let argumentSpecsAndSetupScripts = (arguments ?? []).compactMap { arg in
65+
guard arg.shouldDisplay else {
66+
return nil as (argumentSpec: String, setupScript: String?)?
67+
}
68+
69+
let line: String
70+
let names = arg.names ?? []
71+
switch names.count {
72+
case 0:
73+
guard repeatingPositionalIndicator.isEmpty else {
74+
return nil
75+
}
76+
77+
if arg.isRepeating {
78+
repeatingPositionalIndicator = "*"
79+
}
80+
line = repeatingPositionalIndicator
81+
case 1:
82+
// swift-format-ignore: NeverForceUnwrap
83+
// Preconditions: names has exactly one element.
84+
line = """
85+
\(arg.isRepeatingOption ? "*" : "")\(names.first!.commonCompletionSynopsisString().zshEscapeForSingleQuotedOptionSpec())\(arg.completionAbstract)
86+
"""
87+
default:
88+
let synopses = names.map {
89+
$0.commonCompletionSynopsisString()
90+
.zshEscapeForSingleQuotedOptionSpec()
91+
}
92+
line = """
93+
\(arg.isRepeatingOption ? "*" : "(\(synopses.joined(separator: " ")))")'\
94+
{\(synopses.joined(separator: ","))}\
95+
'\(arg.completionAbstract)
96+
"""
97+
}
98+
99+
switch arg.kind {
100+
case .option, .positional:
101+
let (argumentAction, setupScript) = argumentActionAndSetupScript(arg)
102+
return (
103+
"'\(line):\(arg.valueName?.zshEscapeForSingleQuotedOptionSpec() ?? ""):\(argumentAction)'",
104+
setupScript
105+
)
106+
case .flag:
107+
return ("'\(line)'", nil)
108+
}
65109
}
66110
var argumentSpecs = argumentSpecsAndSetupScripts.map(\.argumentSpec)
67111
let setupScripts = argumentSpecsAndSetupScripts.compactMap(\.setupScript)
@@ -139,45 +183,6 @@ extension CommandInfoV0 {
139183
"""
140184
}
141185

142-
private func argumentSpecAndSetupScript(
143-
_ arg: ArgumentInfoV0
144-
) -> (argumentSpec: String, setupScript: String?)? {
145-
guard arg.shouldDisplay else { return nil }
146-
147-
let line: String
148-
let names = arg.names ?? []
149-
switch names.count {
150-
case 0:
151-
line = arg.isRepeating ? "*" : ""
152-
case 1:
153-
// swift-format-ignore: NeverForceUnwrap
154-
// Preconditions: names has exactly one element.
155-
line = """
156-
\(arg.isRepeatingOption ? "*" : "")\(names.first!.commonCompletionSynopsisString().zshEscapeForSingleQuotedOptionSpec())\(arg.completionAbstract)
157-
"""
158-
default:
159-
let synopses = names.map {
160-
$0.commonCompletionSynopsisString().zshEscapeForSingleQuotedOptionSpec()
161-
}
162-
line = """
163-
\(arg.isRepeatingOption ? "*" : "(\(synopses.joined(separator: " ")))")'\
164-
{\(synopses.joined(separator: ","))}\
165-
'\(arg.completionAbstract)
166-
"""
167-
}
168-
169-
switch arg.kind {
170-
case .option, .positional:
171-
let (argumentAction, setupScript) = argumentActionAndSetupScript(arg)
172-
return (
173-
"'\(line):\(arg.valueName?.zshEscapeForSingleQuotedOptionSpec() ?? ""):\(argumentAction)'",
174-
setupScript
175-
)
176-
case .flag:
177-
return ("'\(line)'", nil)
178-
}
179-
}
180-
181186
/// Returns the zsh "action" for an argument completion string.
182187
private func argumentActionAndSetupScript(
183188
_ arg: ArgumentInfoV0

0 commit comments

Comments
 (0)