| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789 |
- //===----------------------------------------------------------------------===//
- //
- // This source file is part of the Swift Argument Parser open source project
- //
- // Copyright (c) 2020 Apple Inc. and the Swift project authors
- // Licensed under Apache License v2.0 with Runtime Library Exception
- //
- // See https://swift.org/LICENSE.txt for license information
- //
- //===----------------------------------------------------------------------===//
- /// A property wrapper that represents a positional command-line argument.
- ///
- /// Use the `@Argument` wrapper to define a property of your custom command as
- /// a positional argument. A *positional argument* for a command-line tool is
- /// specified without a label and must appear in declaration order. `@Argument`
- /// properties with `Optional` type or a default value are optional for the user
- /// of your command-line tool.
- ///
- /// For example, the following program has two positional arguments. The `name`
- /// argument is required, while `greeting` is optional because it has a default
- /// value.
- ///
- /// ```swift
- /// @main
- /// struct Greet: ParsableCommand {
- /// @Argument var name: String
- /// @Argument var greeting: String = "Hello"
- ///
- /// mutating func run() {
- /// print("\(greeting) \(name)!")
- /// }
- /// }
- /// ```
- ///
- /// You can call this program with just a name or with a name and a
- /// greeting. When you supply both arguments, the first argument is always
- /// treated as the name, due to the order of the property declarations.
- ///
- /// $ greet Nadia
- /// Hello Nadia!
- /// $ greet Tamara Hi
- /// Hi Tamara!
- @propertyWrapper
- public struct Argument<Value>:
- Decodable, ParsedWrapper
- {
- internal var _parsedValue: Parsed<Value>
- internal init(_parsedValue: Parsed<Value>) {
- self._parsedValue = _parsedValue
- }
- public init(from _decoder: Decoder) throws {
- try self.init(_decoder: _decoder)
- }
- /// This initializer works around a quirk of property wrappers, where the
- /// compiler will not see no-argument initializers in extensions.
- ///
- /// Explicitly marking this initializer unavailable means that when `Value`
- /// conforms to `ExpressibleByArgument`, that overload will be selected
- /// instead.
- ///
- /// ```swift
- /// @Argument() var foo: String // Syntax without this initializer
- /// @Argument var foo: String // Syntax with this initializer
- /// ```
- @available(
- *, unavailable,
- message:
- "A default value must be provided unless the value type conforms to ExpressibleByArgument."
- )
- public init() {
- fatalError("unavailable")
- }
- /// The value presented by this property wrapper.
- public var wrappedValue: Value {
- get {
- switch _parsedValue {
- case .value(let v):
- return v
- case .definition:
- configurationFailure(directlyInitializedError)
- }
- }
- set {
- _parsedValue = .value(newValue)
- }
- }
- }
- extension Argument: CustomStringConvertible {
- public var description: String {
- switch _parsedValue {
- case .value(let v):
- return String(describing: v)
- case .definition:
- return "Argument(*definition*)"
- }
- }
- }
- extension Argument: Sendable where Value: Sendable {}
- extension Argument: DecodableParsedWrapper where Value: Decodable {}
- /// The strategy to use when parsing multiple values from positional arguments
- /// into an array.
- public struct ArgumentArrayParsingStrategy: Hashable {
- internal var base: ArgumentDefinition.ParsingStrategy
- /// Parse only unprefixed values from the command-line input, ignoring
- /// any inputs that have a dash prefix; this is the default strategy.
- ///
- /// `remaining` is the default parsing strategy for argument arrays.
- ///
- /// For example, the `Example` command defined below has a `words` array that
- /// uses the `remaining` parsing strategy:
- ///
- /// @main
- /// struct Example: ParsableCommand {
- /// @Flag var verbose = false
- ///
- /// @Argument(parsing: .remaining)
- /// var words: [String]
- ///
- /// func run() {
- /// print(words.joined(separator: "\n"))
- /// }
- /// }
- ///
- /// Any non-dash-prefixed inputs will be captured in the `words` array.
- ///
- /// ```
- /// $ example --verbose one two
- /// one
- /// two
- /// $ example one two --verbose
- /// one
- /// two
- /// $ example one two --other
- /// Error: Unknown option '--other'
- /// ```
- ///
- /// If a user uses the `--` terminator in their input, all following inputs
- /// will be captured in `words`.
- ///
- /// ```
- /// $ example one two -- --verbose --other
- /// one
- /// two
- /// --verbose
- /// --other
- /// ```
- public static var remaining: ArgumentArrayParsingStrategy {
- self.init(base: .default)
- }
- /// After parsing, capture all unrecognized inputs in this argument array.
- ///
- /// You can use the `allUnrecognized` parsing strategy to suppress
- /// "unexpected argument" errors or to capture unrecognized inputs for further
- /// processing.
- ///
- /// For example, the `Example` command defined below has an `other` array that
- /// uses the `allUnrecognized` parsing strategy:
- ///
- /// @main
- /// struct Example: ParsableCommand {
- /// @Flag var verbose = false
- /// @Argument var name: String
- ///
- /// @Argument(parsing: .allUnrecognized)
- /// var other: [String]
- ///
- /// func run() {
- /// print(other.joined(separator: "\n"))
- /// }
- /// }
- ///
- /// After parsing the `--verbose` flag and `<name>` argument, any remaining
- /// input is captured in the `other` array.
- ///
- /// ```
- /// $ example --verbose Negin one two
- /// one
- /// two
- /// $ example Asa --verbose --other -zzz
- /// --other
- /// -zzz
- /// ```
- public static var allUnrecognized: ArgumentArrayParsingStrategy {
- self.init(base: .allUnrecognized)
- }
- // swift-format-ignore: BeginDocumentationCommentWithOneLineSummary
- // https://github.com/swiftlang/swift-format/issues/924
- /// Before parsing arguments, capture all inputs that follow the `--`
- /// terminator in this argument array.
- ///
- /// For example, the `Example` command defined below has a `words` array that
- /// uses the `postTerminator` parsing strategy:
- ///
- /// @main
- /// struct Example: ParsableCommand {
- /// @Flag var verbose = false
- /// @Argument var name = ""
- ///
- /// @Argument(parsing: .postTerminator)
- /// var words: [String]
- ///
- /// func run() {
- /// print(words.joined(separator: "\n"))
- /// }
- /// }
- ///
- /// Before looking for the `--verbose` flag and `<name>` argument, any inputs
- /// after the `--` terminator are captured into the `words` array.
- ///
- /// ```
- /// $ example --verbose Asa -- one two --other
- /// one
- /// two
- /// --other
- /// $ example Asa Extra -- one two --other
- /// Error: Unexpected argument 'Extra'
- /// ```
- ///
- /// Because options are parsed before arguments, an option that consumes or
- /// suppresses the `--` terminator can prevent a `postTerminator` argument
- /// array from capturing any input. In particular, the
- /// ``SingleValueParsingStrategy/unconditional``,
- /// ``ArrayParsingStrategy/unconditionalSingleValue``, and
- /// ``ArrayParsingStrategy/remaining`` parsing strategies can all consume
- /// the terminator as part of their values.
- ///
- /// - Note: This parsing strategy can be surprising for users, since it
- /// changes the behavior of the `--` terminator. Prefer ``remaining``
- /// whenever possible.
- public static var postTerminator: ArgumentArrayParsingStrategy {
- self.init(base: .postTerminator)
- }
- // swift-format-ignore: BeginDocumentationCommentWithOneLineSummary
- // https://github.com/swiftlang/swift-format/issues/924
- /// Parse all remaining inputs after parsing any known options or flags,
- /// including dash-prefixed inputs and the `--` terminator.
- ///
- /// You can use the `captureForPassthrough` parsing strategy if you need to
- /// capture a user's input to manually pass it unchanged to another command.
- ///
- /// When you use this parsing strategy, the parser stops parsing flags and
- /// options as soon as it encounters a positional argument or an unrecognized
- /// flag, and captures all remaining inputs in the array argument.
- ///
- /// For example, the `Example` command defined below has an `words` array that
- /// uses the `captureForPassthrough` parsing strategy:
- ///
- /// @main
- /// struct Example: ParsableCommand {
- /// @Flag var verbose = false
- ///
- /// @Argument(parsing: .captureForPassthrough)
- /// var words: [String] = []
- ///
- /// func run() {
- /// print(words.joined(separator: "\n"))
- /// }
- /// }
- ///
- /// Any values after the first unrecognized input are captured in the `words`
- /// array.
- ///
- /// ```
- /// $ example --verbose one two --other
- /// one
- /// two
- /// --other
- /// $ example one two --verbose
- /// one
- /// two
- /// --verbose
- /// ```
- ///
- /// With the `captureForPassthrough` parsing strategy, the `--` terminator
- /// is included in the captured values.
- ///
- /// ```
- /// $ example --verbose one two -- --other
- /// one
- /// two
- /// --
- /// --other
- /// ```
- ///
- /// - Note: This parsing strategy can be surprising for users, particularly
- /// when combined with options and flags. Prefer ``remaining`` or
- /// ``allUnrecognized`` whenever possible, since users can always terminate
- /// options and flags with the `--` terminator. With the `remaining`
- /// parsing strategy, the input `--verbose -- one two --other` would have
- /// the same result as the first example above.
- public static var captureForPassthrough: ArgumentArrayParsingStrategy {
- self.init(base: .allRemainingInput)
- }
- @available(*, deprecated, renamed: "captureForPassthrough")
- public static var unconditionalRemaining: ArgumentArrayParsingStrategy {
- .captureForPassthrough
- }
- }
- extension ArgumentArrayParsingStrategy: Sendable {}
- // MARK: - @Argument T: ExpressibleByArgument Initializers
- extension Argument where Value: ExpressibleByArgument {
- /// Creates a property with a default value provided by standard Swift default
- /// value syntax.
- ///
- /// This method is called to initialize an `Argument` with a default value
- /// such as:
- /// ```swift
- /// @Argument var foo: String = "bar"
- /// ```
- ///
- /// - Parameters:
- /// - wrappedValue: A default value to use for this property, provided
- /// implicitly by the compiler during property wrapper initialization.
- /// - help: Information about how to use this argument.
- /// - completion: Kind of completion provided to the user for this option.
- public init(
- wrappedValue: Value,
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil
- ) {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Bare<Value>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: .default,
- initial: wrappedValue,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- /// Creates a property with no default value.
- ///
- /// This method is called to initialize an `Argument` without a default value
- /// such as:
- /// ```swift
- /// @Argument var foo: String
- /// ```
- ///
- /// - Parameters:
- /// - help: Information about how to use this argument.
- /// - completion: Kind of completion provided to the user for this option.
- public init(
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil
- ) {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Bare<Value>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: .default,
- initial: nil,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- }
- // MARK: - @Argument T Initializers
- extension Argument {
- /// Creates a property with a default value provided by standard Swift default
- /// value syntax, parsing with the given closure.
- ///
- /// This method is called to initialize an `Argument` with a default value
- /// such as:
- /// ```swift
- /// @Argument(transform: baz)
- /// var foo: String = "bar"
- /// ```
- ///
- /// - Parameters:
- /// - wrappedValue: A default value to use for this property, provided
- /// implicitly by the compiler during property wrapper initialization.
- /// - help: Information about how to use this argument.
- /// - completion: Kind of completion provided to the user for this option.
- /// - transform: A closure that converts a string into this property's type
- /// or throws an error.
- @preconcurrency
- public init(
- wrappedValue: Value,
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil,
- transform: @Sendable @escaping (String) throws -> Value
- ) {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Bare<Value>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: .default,
- transform: transform,
- initial: wrappedValue,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- /// Creates a property with no default value, parsing with the given closure.
- ///
- /// This method is called to initialize an `Argument` with no default value such as:
- /// ```swift
- /// @Argument(transform: baz)
- /// var foo: String
- /// ```
- ///
- /// - Parameters:
- /// - help: Information about how to use this argument.
- /// - completion: Kind of completion provided to the user for this option.
- /// - transform: A closure that converts a string into this property's
- /// element type or throws an error.
- @preconcurrency
- @_disfavoredOverload
- public init(
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil,
- transform: @Sendable @escaping (String) throws -> Value
- ) {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Bare<Value>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: .default,
- transform: transform,
- initial: nil,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- }
- // MARK: - @Argument Optional<T: ExpressibleByArgument> Initializers
- extension Argument {
- /// This initializer allows a user to provide a `nil` default value for an
- /// optional `@Argument`-marked property without allowing a non-`nil` default
- /// value.
- ///
- /// - Parameters:
- /// - wrappedValue: A default value to use for this property, provided
- /// implicitly by the compiler during property wrapper initialization.
- /// - help: Information about how to use this argument.
- /// - completion: Kind of completion provided to the user for this option.
- public init<T>(
- wrappedValue: _OptionalNilComparisonType,
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil
- ) where T: ExpressibleByArgument, Value == T? {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Optional<T>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: .default,
- initial: nil,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- @available(
- *, deprecated,
- message: """
- Optional @Arguments with default values should be declared as non-Optional.
- """
- )
- @_disfavoredOverload
- public init<T>(
- wrappedValue _wrappedValue: T?,
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil
- ) where T: ExpressibleByArgument, Value == T? {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Optional<T>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: .default,
- initial: _wrappedValue,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- /// Creates an optional property that reads its value from an argument.
- ///
- /// The argument is optional for the caller of the command and defaults to
- /// `nil`.
- ///
- /// - Parameters:
- /// - help: Information about how to use this argument.
- /// - completion: Kind of completion provided to the user for this option.
- public init<T>(
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil
- ) where T: ExpressibleByArgument, Value == T? {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Optional<T>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: .default,
- initial: nil,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- }
- // MARK: - @Argument Optional<T> Initializers
- extension Argument {
- /// This initializer allows a user to provide a `nil` default value for an
- /// optional `@Argument`-marked property without allowing a non-`nil` default
- /// value.
- ///
- /// - Parameters:
- /// - wrappedValue: A default value to use for this property, provided
- /// implicitly by the compiler during property wrapper initialization.
- /// - help: Information about how to use this argument.
- /// - completion: Kind of completion provided to the user for this option.
- /// - transform: A closure that converts a string into this property's
- /// element type or throws an error.
- @preconcurrency
- public init<T>(
- wrappedValue: _OptionalNilComparisonType,
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil,
- transform: @Sendable @escaping (String) throws -> T
- ) where Value == T? {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Optional<T>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: .default,
- transform: transform,
- initial: nil,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- @available(
- *, deprecated,
- message: """
- Optional @Arguments with default values should be declared as non-Optional.
- """
- )
- @_disfavoredOverload
- @preconcurrency
- public init<T>(
- wrappedValue _wrappedValue: T?,
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil,
- transform: @Sendable @escaping (String) throws -> T
- ) where Value == T? {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Optional<T>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: .default,
- transform: transform,
- initial: _wrappedValue,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- /// Creates an optional property that reads its value from an argument.
- ///
- /// The argument is optional for the caller of the command and defaults to
- /// `nil`.
- ///
- /// - Parameters:
- /// - help: Information about how to use this argument.
- /// - completion: Kind of completion provided to the user for this option.
- /// - transform: A closure that converts a string into this property's
- /// element type or throws an error.
- @preconcurrency
- public init<T>(
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil,
- transform: @Sendable @escaping (String) throws -> T
- ) where Value == T? {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Optional<T>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: .default,
- transform: transform,
- initial: nil,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- }
- // MARK: - @Argument Array<T: ExpressibleByArgument> Initializers
- extension Argument {
- /// Creates a property that reads an array from zero or more arguments.
- ///
- /// - Parameters:
- /// - wrappedValue: A default value to use for this property.
- /// - parsingStrategy: The behavior to use when parsing multiple values from
- /// the command-line arguments.
- /// - help: Information about how to use this argument.
- /// - completion: Kind of completion provided to the user for this option.
- public init<T>(
- wrappedValue: [T],
- parsing parsingStrategy: ArgumentArrayParsingStrategy = .remaining,
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil
- ) where T: ExpressibleByArgument, Value == [T] {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Array<T>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: parsingStrategy.base,
- initial: wrappedValue,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- /// Creates a property with no default value that reads an array from zero or
- /// more arguments.
- ///
- /// This method is called to initialize an array `Argument` with no default
- /// value such as:
- /// ```swift
- /// @Argument()
- /// var foo: [String]
- /// ```
- ///
- /// - Parameters:
- /// - parsingStrategy: The behavior to use when parsing multiple values from
- /// the command-line arguments.
- /// - help: Information about how to use this argument.
- /// - completion: Kind of completion provided to the user for this option.
- public init<T>(
- parsing parsingStrategy: ArgumentArrayParsingStrategy = .remaining,
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil
- ) where T: ExpressibleByArgument, Value == [T] {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Array<T>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: parsingStrategy.base,
- initial: nil,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- }
- // MARK: - @Argument Array<T> Initializers
- extension Argument {
- /// Creates a property that reads an array from zero or more arguments,
- /// parsing each element with the given closure.
- ///
- /// - Parameters:
- /// - wrappedValue: A default value to use for this property.
- /// - parsingStrategy: The behavior to use when parsing multiple values from
- /// the command-line arguments.
- /// - help: Information about how to use this argument.
- /// - completion: Kind of completion provided to the user for this option.
- /// - transform: A closure that converts a string into this property's
- /// element type or throws an error.
- @preconcurrency
- public init<T>(
- wrappedValue: [T],
- parsing parsingStrategy: ArgumentArrayParsingStrategy = .remaining,
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil,
- transform: @Sendable @escaping (String) throws -> T
- ) where Value == [T] {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Array<T>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: parsingStrategy.base,
- transform: transform,
- initial: wrappedValue,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- /// Creates a property with no default value that reads an array from zero or
- /// more arguments, parsing each element with the given closure.
- ///
- /// This method is called to initialize an array `Argument` with no default
- /// value such as:
- /// ```swift
- /// @Argument(transform: baz)
- /// var foo: [String]
- /// ```
- ///
- /// - Parameters:
- /// - parsingStrategy: The behavior to use when parsing multiple values from
- /// the command-line arguments.
- /// - help: Information about how to use this argument.
- /// - completion: Kind of completion provided to the user for this option.
- /// - transform: A closure that converts a string into this property's
- /// element type or throws an error.
- @preconcurrency
- public init<T>(
- parsing parsingStrategy: ArgumentArrayParsingStrategy = .remaining,
- help: ArgumentHelp? = nil,
- completion: CompletionKind? = nil,
- transform: @Sendable @escaping (String) throws -> T
- ) where Value == [T] {
- self.init(
- _parsedValue: .init { key in
- let arg = ArgumentDefinition(
- container: Array<T>.self,
- key: key,
- kind: .positional,
- help: help,
- parsingStrategy: parsingStrategy.base,
- transform: transform,
- initial: nil,
- completion: completion)
- return ArgumentSet(arg)
- })
- }
- }
|