|
9 | 9 | //
|
10 | 10 | //===----------------------------------------------------------------------===//
|
11 | 11 |
|
| 12 | +#if swift(>=6.0) |
| 13 | +internal import ArgumentParserToolInfo |
| 14 | +#else |
| 15 | +import ArgumentParserToolInfo |
| 16 | +#endif |
| 17 | + |
12 | 18 | /// A shell for which the parser can generate a completion script.
|
13 | 19 | public struct CompletionShell: RawRepresentable, Hashable, CaseIterable {
|
14 | 20 | public var rawValue: String
|
@@ -134,84 +140,81 @@ struct CompletionsGenerator {
|
134 | 140 | CompletionShell._requesting.withLock { $0 = shell }
|
135 | 141 | switch shell {
|
136 | 142 | case .zsh:
|
137 |
| - return [command].zshCompletionScript |
| 143 | + return ToolInfoV0(commandStack: [command]).zshCompletionScript |
138 | 144 | case .bash:
|
139 |
| - return [command].bashCompletionScript |
| 145 | + return ToolInfoV0(commandStack: [command]).bashCompletionScript |
140 | 146 | case .fish:
|
141 |
| - return [command].fishCompletionScript |
| 147 | + return ToolInfoV0(commandStack: [command]).fishCompletionScript |
142 | 148 | default:
|
143 | 149 | fatalError("Invalid CompletionShell: \(shell)")
|
144 | 150 | }
|
145 | 151 | }
|
146 | 152 | }
|
147 | 153 |
|
148 |
| -extension ArgumentDefinition { |
149 |
| - /// Returns a string with the arguments for the callback to generate custom completions for |
150 |
| - /// this argument. |
151 |
| - func customCompletionCall(_ commands: [ParsableCommand.Type]) -> String { |
152 |
| - let subcommandNames = |
153 |
| - commands.dropFirst().map { "\($0._commandName) " }.joined() |
154 |
| - let argumentName = |
155 |
| - names.preferredName?.synopsisString |
156 |
| - ?? self.help.keys.first?.fullPathString |
157 |
| - ?? "---" |
158 |
| - return "---completion \(subcommandNames)-- \(argumentName)" |
| 154 | +extension String { |
| 155 | + func shellEscapeForSingleQuotedString(iterationCount: UInt64 = 1) -> Self { |
| 156 | + iterationCount == 0 |
| 157 | + ? self |
| 158 | + : replacingOccurrences(of: "'", with: "'\\''") |
| 159 | + .shellEscapeForSingleQuotedString(iterationCount: iterationCount - 1) |
159 | 160 | }
|
160 |
| -} |
161 | 161 |
|
162 |
| -extension ParsableCommand { |
163 |
| - fileprivate static var compositeCommandName: [String] { |
164 |
| - if let superCommandName = configuration._superCommandName { |
165 |
| - return [superCommandName] |
166 |
| - + _commandName.split(separator: " ").map(String.init) |
167 |
| - } else { |
168 |
| - return _commandName.split(separator: " ").map(String.init) |
169 |
| - } |
| 162 | + func shellEscapeForVariableName() -> Self { |
| 163 | + replacingOccurrences(of: "-", with: "_") |
170 | 164 | }
|
171 | 165 | }
|
172 | 166 |
|
173 |
| -extension [ParsableCommand.Type] { |
174 |
| - var positionalArguments: [ArgumentDefinition] { |
175 |
| - guard let command = last else { |
176 |
| - return [] |
177 |
| - } |
178 |
| - return ArgumentSet(command, visibility: .default, parent: nil) |
179 |
| - .filter(\.isPositional) |
| 167 | +extension CommandInfoV0 { |
| 168 | + var commandContext: [String] { |
| 169 | + (superCommands ?? []) + [commandName] |
180 | 170 | }
|
181 | 171 |
|
182 |
| - /// Include default 'help' subcommand in nonempty subcommand list if & only if |
183 |
| - /// no help subcommand already exists. |
184 |
| - mutating func addHelpSubcommandIfMissing() { |
185 |
| - if !isEmpty && !contains(where: { $0._commandName == "help" }) { |
186 |
| - append(HelpCommand.self) |
187 |
| - } |
| 172 | + var initialCommand: String { |
| 173 | + superCommands?.first ?? commandName |
188 | 174 | }
|
189 |
| -} |
190 | 175 |
|
191 |
| -extension Sequence where Element == ParsableCommand.Type { |
192 |
| - func completionFunctionName() -> String { |
193 |
| - "_" |
194 |
| - + self.flatMap { $0.compositeCommandName } |
195 |
| - .uniquingAdjacentElements() |
196 |
| - .joined(separator: "_") |
| 176 | + var positionalArguments: [ArgumentInfoV0] { |
| 177 | + (arguments ?? []).filter { $0.kind == .positional } |
197 | 178 | }
|
198 | 179 |
|
199 |
| - var shellVariableNamePrefix: String { |
200 |
| - flatMap { $0.compositeCommandName } |
201 |
| - .joined(separator: "_") |
202 |
| - .shellEscapeForVariableName() |
| 180 | + var completionFunctionName: String { |
| 181 | + "_" + commandContext.joined(separator: "_") |
| 182 | + } |
| 183 | + |
| 184 | + var completionFunctionPrefix: String { |
| 185 | + "__\(initialCommand)" |
203 | 186 | }
|
204 | 187 | }
|
205 | 188 |
|
206 |
| -extension String { |
207 |
| - func shellEscapeForSingleQuotedString(iterationCount: UInt64 = 1) -> Self { |
208 |
| - iterationCount == 0 |
209 |
| - ? self |
210 |
| - : replacingOccurrences(of: "'", with: "'\\''") |
211 |
| - .shellEscapeForSingleQuotedString(iterationCount: iterationCount - 1) |
| 189 | +extension ArgumentInfoV0 { |
| 190 | + /// Returns a string with the arguments for the callback to generate custom |
| 191 | + /// completions for this argument. |
| 192 | + func commonCustomCompletionCall(command: CommandInfoV0) -> String { |
| 193 | + let subcommandNames = |
| 194 | + command.commandContext.dropFirst().map { "\($0) " }.joined() |
| 195 | + |
| 196 | + let argumentName: String |
| 197 | + switch kind { |
| 198 | + case .positional: |
| 199 | + if let index = command.positionalArguments.firstIndex(of: self) { |
| 200 | + argumentName = "positional@\(index)" |
| 201 | + } else { |
| 202 | + argumentName = "---" |
| 203 | + } |
| 204 | + default: |
| 205 | + argumentName = preferredName?.commonCompletionSynopsisString() ?? "---" |
| 206 | + } |
| 207 | + return "---completion \(subcommandNames)-- \(argumentName)" |
212 | 208 | }
|
| 209 | +} |
213 | 210 |
|
214 |
| - func shellEscapeForVariableName() -> Self { |
215 |
| - replacingOccurrences(of: "-", with: "_") |
| 211 | +extension ArgumentInfoV0.NameInfoV0 { |
| 212 | + func commonCompletionSynopsisString() -> String { |
| 213 | + switch kind { |
| 214 | + case .long: |
| 215 | + return "--\(name)" |
| 216 | + case .short, .longWithSingleDash: |
| 217 | + return "-\(name)" |
| 218 | + } |
216 | 219 | }
|
217 | 220 | }
|
0 commit comments