|
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