diff --git a/Examples/math/Math.swift b/Examples/math/Math.swift index b4160dda..eec24fee 100644 --- a/Examples/math/Math.swift +++ b/Examples/math/Math.swift @@ -259,7 +259,7 @@ extension Math.Statistics { } } -func customCompletion(_ s: [String], _: Int, _: Int) -> [String] { +func customCompletion(_ s: [String], _: Int, _: String) -> [String] { (s.last ?? "").starts(with: "a") ? ["aardvark", "aaaaalbert"] : ["hello", "helicopter", "heliotrope"] diff --git a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift index 2d229ba2..e6ca3803 100644 --- a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift +++ b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift @@ -40,7 +40,7 @@ public struct CompletionKind { case file(extensions: [String]) case directory case shellCommand(String) - case custom(@Sendable ([String], Int, Int) -> [String]) + case custom(@Sendable ([String], Int, String) -> [String]) case customDeprecated(@Sendable ([String]) -> [String]) } @@ -126,11 +126,11 @@ public struct CompletionKind { /// passed to Swift as `"abc\\""def"` (i.e. the Swift String's contents would /// include all 4 of the double quotes and the 2 consecutive backslashes). /// - /// The first of the two `Int` arguments is the 0-based index of the word - /// for which completions are being requested within the given `[String]`. + /// The second argument (an `Int`) is the 0-based index of the word for which + /// completions are being requested within the given `[String]`. /// - /// The second of the two `Int` arguments is the 0-based index of the shell - /// cursor within the word for which completions are being requested. + /// The third argument (a `String`) is the prefix of the word for which + /// completions are being requested that precedes the cursor. /// /// ### bash /// @@ -171,21 +171,21 @@ public struct CompletionKind { /// character, not as after the backslash. @preconcurrency public static func custom( - _ completion: @Sendable @escaping ([String], Int, Int) -> [String] + _ completion: @Sendable @escaping ([String], Int, String) -> [String] ) -> CompletionKind { CompletionKind(kind: .custom(completion)) } /// Deprecated; only kept for backwards compatibility. /// - /// The same as `custom(@Sendable @escaping ([String], Int, Int) -> [String])`, - /// except that index arguments are not supplied. + /// The same as `custom(@Sendable @escaping ([String], Int, String) -> [String])`, + /// except that the last two closure arguments are not supplied. @preconcurrency @available( *, deprecated, message: - "Provide a three-parameter closure instead. See custom(@Sendable @escaping ([String], Int, Int) -> [String])." + "Provide a three-parameter closure instead. See custom(@Sendable @escaping ([String], Int, String) -> [String])." ) public static func custom( _ completion: @Sendable @escaping ([String]) -> [String] diff --git a/Sources/ArgumentParser/Parsing/CommandParser.swift b/Sources/ArgumentParser/Parsing/CommandParser.swift index 5c24586a..f45939c6 100644 --- a/Sources/ArgumentParser/Parsing/CommandParser.swift +++ b/Sources/ArgumentParser/Parsing/CommandParser.swift @@ -456,16 +456,27 @@ extension CommandParser { } guard - let s = args.popFirst(), - let cursorIndexWithinCompletingArgument = Int(s) + let arg = args.popFirst(), + let cursorIndexWithinCompletingArgument = Int(arg) else { throw ParserError.invalidState } + let completingPrefix: String + if let completingArgument = args.last { + completingPrefix = String( + completingArgument.prefix(cursorIndexWithinCompletingArgument) + ) + } else if cursorIndexWithinCompletingArgument == 0 { + completingPrefix = "" + } else { + throw ParserError.invalidState + } + completions = complete( Array(args), completingArgumentIndex, - cursorIndexWithinCompletingArgument + completingPrefix ) case .customDeprecated(let complete): completions = complete(args) diff --git a/Sources/ArgumentParserToolInfo/ToolInfo.swift b/Sources/ArgumentParserToolInfo/ToolInfo.swift index df35f15f..808106a8 100644 --- a/Sources/ArgumentParserToolInfo/ToolInfo.swift +++ b/Sources/ArgumentParserToolInfo/ToolInfo.swift @@ -149,9 +149,9 @@ public struct ArgumentInfoV0: Codable, Hashable { case directory /// Call the given shell command to generate completions. case shellCommand(command: String) - /// Generate completions using the given closure including index arguments. + /// Generate completions using the given three-parameter closure. case custom - /// Generate completions using the given closure without index arguments. + /// Generate completions using the given one-parameter closure. @available(*, deprecated, message: "Use custom instead.") case customDeprecated }