Skip to content

Commit 2962ba2

Browse files
committed
Addressing PR comments
1 parent 711deae commit 2962ba2

5 files changed

Lines changed: 146 additions & 144 deletions

File tree

Sources/ArgumentParser/Documentation.docc/Articles/DeclaringArguments.md

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -333,32 +333,26 @@ The `defaultAsFlag` parameter allows you to create options that can work both as
333333

334334
```swift
335335
struct Example: ParsableCommand {
336-
@Option(defaultAsFlag: "default", help: "Set output format.")
337-
var format: String?
338-
339-
@Option(defaultAsFlag: 8080, help: "Server port.")
340-
var port: Int?
336+
@Option(defaultAsFlag: "json", help: "Set the export format.")
337+
var export: String?
341338

342339
func run() {
343-
print("Format: \(format ?? "none")")
344-
print("Port: \(port ?? 3000)")
340+
print("Export: \(format ?? "<don't export>")")
345341
}
346342
}
347343
```
348344

349345
**Command-line behavior:**
350346
```
351-
% example # format = nil, port = nil
352-
% example --format # format = "default", port = nil
353-
% example --format json # format = "json", port = nil
354-
% example --port # format = nil, port = 8080
355-
% example --port 9000 # format = nil, port = 9000
347+
% example # export = nil
348+
% example --export # export = "json"
349+
% example --format yaml # format = "yaml"
356350
```
357351

358352
The `defaultAsFlag` parameter creates a hybrid that supports both patterns:
359-
- **Flag behavior**: `--format` (sets format to "default")
360-
- **Option behavior**: `--format json` (sets format to "json")
361-
- **No usage**: format remains `nil`
353+
- **Flag behavior**: `--export` (sets format to "json")
354+
- **Option behavior**: `--export yaml` (sets format to "yaml")
355+
- **No usage**: `export` remains `nil`
362356

363357
#### Type requirements
364358

@@ -405,7 +399,7 @@ The parser determines whether a value follows the option:
405399
2. **No value available**: Use the `defaultAsFlag` value
406400
3. **Explicit value provided**: Parse and use that value
407401

408-
This works with all parsing strategies (`.next`, `.scanningForValue`, `.unconditional`), though `.unconditional` defeats the purpose by always requiring a value.
402+
This works with parsing strategies `.next` and `.scanningForValue`. The `.unconditional` parsing strategy defeats the purpose by always requiring a value.
409403

410404
For complete examples and API reference, see the [`default-as-flag`](https://github.com/apple/swift-argument-parser/tree/main/Examples/default-as-flag) example.
411405

Sources/ArgumentParser/Parsable Properties/Option.swift

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,46 @@ public struct SingleValueParsingStrategy: Hashable {
161161
}
162162
}
163163

164+
/// The strategy to use when parsing a single value from `@Option` arguments with `defaultAsFlag`.
165+
///
166+
/// This is a subset of `SingleValueParsingStrategy` that excludes strategies incompatible
167+
/// with default-as-flag behavior.
168+
public struct DefaultAsFlagParsingStrategy: Hashable {
169+
internal var base: ArgumentDefinition.ParsingStrategy
170+
171+
/// Parse the input after the option and expect it to be a value.
172+
///
173+
/// For inputs such as `--foo foo`, this would parse `foo` as the
174+
/// value. However, the input `--foo --bar foo bar` would
175+
/// result in an error. Even though two values are provided, they don't
176+
/// succeed each option. Parsing would result in an error such as the following:
177+
///
178+
/// Error: Missing value for '--foo <foo>'
179+
/// Usage: command [--foo <foo>]
180+
///
181+
/// When used with `defaultAsFlag`, if no value is found, the default flag value is used.
182+
public static var next: DefaultAsFlagParsingStrategy {
183+
self.init(base: .default)
184+
}
185+
186+
/// Parse the next input, as long as that input can't be interpreted as
187+
/// an option or flag.
188+
///
189+
/// - Note: This will skip other options and _read ahead_ in the input
190+
/// to find the next available value. This may be *unexpected* for users.
191+
/// Use with caution.
192+
///
193+
/// For example, if `--foo` takes a value, then the input `--foo --bar bar`
194+
/// would be parsed such that the value `bar` is used for `--foo`.
195+
///
196+
/// This is the **default behavior** for `defaultAsFlag` options.
197+
public static var scanningForValue: DefaultAsFlagParsingStrategy {
198+
self.init(base: .scanningForValue)
199+
}
200+
}
201+
164202
extension SingleValueParsingStrategy: Sendable {}
203+
extension DefaultAsFlagParsingStrategy: Sendable {}
165204

166205
/// The strategy to use when parsing multiple values from `@Option` arguments into an
167206
/// array.
@@ -504,7 +543,7 @@ extension Option {
504543
}
505544

506545
/// Creates an optional property that reads its value from a labeled option,
507-
/// with a default value when the flag is provided without an argument.
546+
/// with a default value when the flag is provided without a value.
508547
///
509548
/// This initializer allows providing a `defaultAsFlag` value that is used
510549
/// when the flag is present but no value follows it:
@@ -518,15 +557,15 @@ extension Option {
518557
/// - wrappedValue: A default value to use for this property, provided
519558
/// implicitly by the compiler during property wrapper initialization.
520559
/// - name: A specification for what names are allowed for this option.
521-
/// - defaultAsFlag: The value to use when the flag is provided without an argument.
560+
/// - defaultAsFlag: The value to use when the flag is provided without a value.
522561
/// - parsingStrategy: The behavior to use when looking for this option's value.
523562
/// - help: Information about how to use this option.
524563
/// - completion: The type of command-line completion provided for this option.
525564
public init<T>(
526565
wrappedValue: _OptionalNilComparisonType,
527566
name: NameSpecification = .long,
528567
defaultAsFlag: T,
529-
parsing parsingStrategy: SingleValueParsingStrategy = .scanningForValue,
568+
parsing parsingStrategy: DefaultAsFlagParsingStrategy = .scanningForValue,
530569
help: ArgumentHelp? = nil,
531570
completion: CompletionKind? = nil
532571
) where T: ExpressibleByArgument, Value == T? {
@@ -646,7 +685,7 @@ extension Option {
646685
}
647686

648687
/// Creates an optional property that reads its value from a labeled option,
649-
/// with a default value when the flag is provided without an argument.
688+
/// with a default value when the flag is provided without a value.
650689
///
651690
/// This initializer allows providing a `defaultAsFlag` value that is used
652691
/// when the flag is present but no value follows it:
@@ -658,14 +697,14 @@ extension Option {
658697
///
659698
/// - Parameters:
660699
/// - name: A specification for what names are allowed for this option.
661-
/// - defaultAsFlag: The value to use when the flag is provided without an argument.
700+
/// - defaultAsFlag: The value to use when the flag is provided without a value.
662701
/// - parsingStrategy: The behavior to use when looking for this option's value.
663702
/// - help: Information about how to use this option.
664703
/// - completion: The type of command-line completion provided for this option.
665704
public init<T>(
666705
name: NameSpecification = .long,
667706
defaultAsFlag: T,
668-
parsing parsingStrategy: SingleValueParsingStrategy = .scanningForValue,
707+
parsing parsingStrategy: DefaultAsFlagParsingStrategy = .scanningForValue,
669708
help: ArgumentHelp? = nil,
670709
completion: CompletionKind? = nil
671710
) where T: ExpressibleByArgument, Value == T? {
@@ -759,7 +798,7 @@ extension Option {
759798

760799
/// Creates an optional property that reads its value from a labeled option,
761800
/// parsing with the given closure, with a default value when the flag is
762-
/// provided without an argument.
801+
/// provided without a value.
763802
///
764803
/// This initializer allows providing a `defaultAsFlag` value that is used
765804
/// when the flag is present but no value follows it:
@@ -773,7 +812,7 @@ extension Option {
773812
/// - wrappedValue: A default value to use for this property, provided
774813
/// implicitly by the compiler during property wrapper initialization.
775814
/// - name: A specification for what names are allowed for this option.
776-
/// - defaultAsFlag: The value to use when the flag is provided without an argument.
815+
/// - defaultAsFlag: The value to use when the flag is provided without a value.
777816
/// - parsingStrategy: The behavior to use when looking for this option's value.
778817
/// - help: Information about how to use this option.
779818
/// - completion: The type of command-line completion provided for this option.
@@ -784,7 +823,7 @@ extension Option {
784823
wrappedValue: _OptionalNilComparisonType,
785824
name: NameSpecification = .long,
786825
defaultAsFlag: T,
787-
parsing parsingStrategy: SingleValueParsingStrategy = .scanningForValue,
826+
parsing parsingStrategy: DefaultAsFlagParsingStrategy = .scanningForValue,
788827
help: ArgumentHelp? = nil,
789828
completion: CompletionKind? = nil,
790829
transform: @Sendable @escaping (String) throws -> T
@@ -907,7 +946,7 @@ extension Option {
907946

908947
/// Creates an optional property that reads its value from a labeled option,
909948
/// parsing with the given closure, with a default value when the flag is
910-
/// provided without an argument.
949+
/// provided without a value.
911950
///
912951
/// This initializer allows providing a `defaultAsFlag` value that is used
913952
/// when the flag is present but no value follows it:
@@ -919,7 +958,7 @@ extension Option {
919958
///
920959
/// - Parameters:
921960
/// - name: A specification for what names are allowed for this option.
922-
/// - defaultAsFlag: The value to use when the flag is provided without an argument.
961+
/// - defaultAsFlag: The value to use when the flag is provided without a value.
923962
/// - parsingStrategy: The behavior to use when looking for this option's value.
924963
/// - help: Information about how to use this option.
925964
/// - completion: The type of command-line completion provided for this option.
@@ -929,7 +968,7 @@ extension Option {
929968
public init<T>(
930969
name: NameSpecification = .long,
931970
defaultAsFlag: T,
932-
parsing parsingStrategy: SingleValueParsingStrategy = .scanningForValue,
971+
parsing parsingStrategy: DefaultAsFlagParsingStrategy = .scanningForValue,
933972
help: ArgumentHelp? = nil,
934973
completion: CompletionKind? = nil,
935974
transform: @Sendable @escaping (String) throws -> T

0 commit comments

Comments
 (0)