From 2eeefd47ef23f8b56494d211c43525bd5cccc2df Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 10 Jun 2021 13:11:22 -0500 Subject: [PATCH 01/18] DocC experimentation --- {Documentation => Docs}/01 Getting Started.md | 0 .../02 Arguments, Options, and Flags.md | 0 .../03 Commands and Subcommands.md | 0 .../04 Customizing Help.md | 0 .../05 Validation and Errors.md | 0 .../06 Manual Parsing and Testing.md | 0 .../07 Completion Scripts.md | 0 .../Documentation.docc/ArgumentParser.md | 50 +++ .../Documentation.docc/GettingStarted.md | 288 ++++++++++++++++++ .../Resources/Tutorial Code/code.txt | 288 ++++++++++++++++++ .../Resources/Tutorial Images/Image.png | Bin 0 -> 97845 bytes .../Tutorials/ArgumentParser.tutorial | 15 + .../Tutorials/Get Started.tutorial | 27 ++ 13 files changed, 668 insertions(+) rename {Documentation => Docs}/01 Getting Started.md (100%) rename {Documentation => Docs}/02 Arguments, Options, and Flags.md (100%) rename {Documentation => Docs}/03 Commands and Subcommands.md (100%) rename {Documentation => Docs}/04 Customizing Help.md (100%) rename {Documentation => Docs}/05 Validation and Errors.md (100%) rename {Documentation => Docs}/06 Manual Parsing and Testing.md (100%) rename {Documentation => Docs}/07 Completion Scripts.md (100%) create mode 100644 Sources/ArgumentParser/Documentation.docc/ArgumentParser.md create mode 100644 Sources/ArgumentParser/Documentation.docc/GettingStarted.md create mode 100644 Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Code/code.txt create mode 100644 Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Images/Image.png create mode 100644 Sources/ArgumentParser/Documentation.docc/Tutorials/ArgumentParser.tutorial create mode 100644 Sources/ArgumentParser/Documentation.docc/Tutorials/Get Started.tutorial diff --git a/Documentation/01 Getting Started.md b/Docs/01 Getting Started.md similarity index 100% rename from Documentation/01 Getting Started.md rename to Docs/01 Getting Started.md diff --git a/Documentation/02 Arguments, Options, and Flags.md b/Docs/02 Arguments, Options, and Flags.md similarity index 100% rename from Documentation/02 Arguments, Options, and Flags.md rename to Docs/02 Arguments, Options, and Flags.md diff --git a/Documentation/03 Commands and Subcommands.md b/Docs/03 Commands and Subcommands.md similarity index 100% rename from Documentation/03 Commands and Subcommands.md rename to Docs/03 Commands and Subcommands.md diff --git a/Documentation/04 Customizing Help.md b/Docs/04 Customizing Help.md similarity index 100% rename from Documentation/04 Customizing Help.md rename to Docs/04 Customizing Help.md diff --git a/Documentation/05 Validation and Errors.md b/Docs/05 Validation and Errors.md similarity index 100% rename from Documentation/05 Validation and Errors.md rename to Docs/05 Validation and Errors.md diff --git a/Documentation/06 Manual Parsing and Testing.md b/Docs/06 Manual Parsing and Testing.md similarity index 100% rename from Documentation/06 Manual Parsing and Testing.md rename to Docs/06 Manual Parsing and Testing.md diff --git a/Documentation/07 Completion Scripts.md b/Docs/07 Completion Scripts.md similarity index 100% rename from Documentation/07 Completion Scripts.md rename to Docs/07 Completion Scripts.md diff --git a/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md b/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md new file mode 100644 index 000000000..813aba292 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md @@ -0,0 +1,50 @@ +# ``ArgumentParser`` + +Summary.. + +## Overview + +Text... + +## Topics + +### Guides + +- +- + +### Parsable Properties + +- ``Argument`` +- ``Option`` +- ``Flag`` + +### Parsable Types + +- ``ParsableCommand`` +- ``ParsableArguments`` +- ``OptionGroup`` +- ``EnumerableFlag`` + +### Customization + +- ``ArgumentHelp`` +- ``NameSpecification`` +- ``CommandConfiguration`` +- ``FlagInversion`` +- ``FlagExclusivity`` +- ``SingleValueParsingStrategy`` +- ``ArrayParsingStrategy`` +- ``ArgumentArrayParsingStrategy`` +- ``CompletionKind`` +- ``CompletionShell`` + +### Validation and Errors + +- ``ValidationError`` +- ``CleanExit`` +- ``ExitCode`` + +### Expressible Types + +- ``ExpressibleByArgument`` diff --git a/Sources/ArgumentParser/Documentation.docc/GettingStarted.md b/Sources/ArgumentParser/Documentation.docc/GettingStarted.md new file mode 100644 index 000000000..175f62c82 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/GettingStarted.md @@ -0,0 +1,288 @@ +# Getting Started with ArgumentParser + +Learn to set up and customize a simple command-line tool. + +## Overview + +This guide walks through building an example command. You'll learn about the different tools that `ArgumentParser` provides for defining a command's options, customizing the interface, and providing help text for your user. + +## Adding `ArgumentParser` as a Dependency + +Let's write a tool called `count` that reads an input file, counts the words, and writes the result to an output file. + +First, we need to add `swift-argument-parser` as a dependency to our package, +and then include `"ArgumentParser"` as a dependency for our executable target. +Our "Package.swift" file ends up looking like this: + +```swift +// swift-tools-version:5.2 +import PackageDescription + +let package = Package( + name: "random", + dependencies: [ + .package(url: "https://github.com/apple/swift-argument-parser.git", from: "0.4.0"), + ], + targets: [ + .target( + name: "count", + dependencies: [.product(name: "ArgumentParser", package: "swift-argument-parser")]), + ] +) +``` + +> **Note:** To read more about creating and configuring packages using Swift Package Manager, see [Using the Package Manager](https://swift.org/getting-started/#using-the-package-manager). + +## Building Our First Command + +Once we've built the `count` tool, we'll be able to run it like this: + +``` +% count readme.md readme.counts +Counting words in 'readme.md' and writing the result into 'readme.counts'. +``` + +We'll define the initial version of the command as a type that conforms to the `ParsableCommand` protocol: + +```swift +import ArgumentParser + +struct Count: ParsableCommand { + @Argument var inputFile: String + @Argument var outputFile: String + + mutating func run() throws { + print(""" + Counting words in '\(inputFile)' \ + and writing the result into '\(outputFile)'. + """) + + // Read 'inputFile', count the words, and save to 'outputFile'. + } +} + +Count.main() +``` + +In the code above, the `inputFile` and `outputFile` properties use the `@Argument` property wrapper. `ArgumentParser` uses this wrapper to denote a positional command-line input — because `inputFile` is specified first in the `Count` type, it's the first value read from the command line, and `outputFile` is read second. + +We've implemented the command's logic in its `run()` method. Here, we're printing out a message confirming the names of the files the user gave. (You can find a full implementation of the completed command at the end of this guide.) + +Finally, you tell the parser to execute the `Count` command by calling its static `main()` method. This method parses the command-line arguments, verifies that they match up with what we've defined in `Count`, and either calls the `run()` method or exits with a helpful message. + + +## Working with Named Options + +Our `count` tool may have a usability problem — it's not immediately clear whether a user should provide the input file first, or the output file. Instead of using positional arguments for our two inputs, let's specify that they should be labeled options: + +``` +% count --input-file readme.md --output-file readme.counts +Counting words in 'readme.md' and writing the result into 'readme.counts'. +``` + +We do this by using the `@Option` property wrapper instead of `@Argument`: + +```swift +struct Count: ParsableCommand { + @Option var inputFile: String + @Option var outputFile: String + + mutating func run() throws { + print(""" + Counting words in '\(inputFile)' \ + and writing the result into '\(outputFile)'. + """) + + // Read 'inputFile', count the words, and save to 'outputFile'. + } +} +``` + +The `@Option` property wrapper denotes a command-line input that looks like `--name `, deriving its name from the name of your property. + +This interface has a trade-off for the users of our `count` tool: With `@Argument`, users don't need to type as much, but they have to remember whether to provide the input file or the output file first. Using `@Option` makes the user type a little more, but the distinction between values is explicit. Options are order-independent, as well, so the user can name the input and output files in either order: + +``` +% count --output-file readme.counts --input-file readme.md +Counting words in 'readme.md' and writing the result into 'readme.counts'. +``` + +## Adding a Flag + +Next, we want to add a `--verbose` flag to our tool, and only print the message if the user specifies that option: + +``` +% count --input-file readme.md --output-file readme.counts +(no output) +% count --verbose --input-file readme.md --output-file readme.counts +Counting words in 'readme.md' and writing the result into 'readme.counts'. +``` + +Let's change our `Count` type to look like this: + +```swift +struct Count: ParsableCommand { + @Option var inputFile: String + @Option var outputFile: String + @Flag var verbose = false + + mutating func run() throws { + if verbose { + print(""" + Counting words in '\(inputFile)' \ + and writing the result into '\(outputFile)'. + """) + } + + // Read 'inputFile', count the words, and save to 'outputFile'. + } +} +``` + +The `@Flag` property wrapper denotes a command-line input that looks like `--name`, deriving its name from the name of your property. Flags are most frequently used for Boolean values, like the `verbose` property here. + + +## Using Custom Names + +We can customize the names of our options and add an alternative to the `verbose` flag so that users can specify `-v` instead of `--verbose`. The new interface will look like this: + +``` +% count -v -i readme.md -o readme.counts +Counting words in 'readme.md' and writing the result into 'readme.counts'. +% count --input readme.md --output readme.counts -v +Counting words in 'readme.md' and writing the result into 'readme.counts'. +% count -o readme.counts -i readme.md --verbose +Counting words in 'readme.md' and writing the result into 'readme.counts'. +``` + +Customize the input names by passing `name` parameters to the `@Option` and `@Flag` initializers: + +```swift +struct Count: ParsableCommand { + @Option(name: [.short, .customLong("input")]) + var inputFile: String + + @Option(name: [.short, .customLong("output")]) + var outputFile: String + + @Flag(name: .shortAndLong) + var verbose = false + + mutating func run() throws { ... } +} +``` + +The default name specification is `.long`, which uses a property's name with a two-dash prefix. `.short` uses only the first letter of a property's name with a single-dash prefix, and allows combining groups of short options. You can specify custom short and long names with the `.customShort(_:)` and `.customLong(_:)` methods, respectively, or use the combined `.shortAndLong` property to specify the common case of both the short and long derived names. + +## Providing Help + +`ArgumentParser` automatically generates help for any command when a user provides the `-h` or `--help` flags: + +``` +% count --help +USAGE: count --input --output [--verbose] + +OPTIONS: + -i, --input + -o, --output + -v, --verbose + -h, --help Show help information. +``` + +This is a great start — you can see that all the custom names are visible, and the help shows that values are expected for the `--input` and `--output` options. However, our custom options and flag don't have any descriptive text. Let's add that now by passing string literals as the `help` parameter: + +```swift +struct Count: ParsableCommand { + @Option(name: [.short, .customLong("input")], help: "A file to read.") + var inputFile: String + + @Option(name: [.short, .customLong("output")], help: "A file to save word counts to.") + var outputFile: String + + @Flag(name: .shortAndLong, help: "Print status updates while counting.") + var verbose = false + + mutating func run() throws { ... } +} +``` + +The help screen now includes descriptions for each parameter: + +``` +% count -h +USAGE: count --input --output [--verbose] + +OPTIONS: + -i, --input A file to read. + -o, --output A file to save word counts to. + -v, --verbose Print status updates while counting. + -h, --help Show help information. + +``` + +## The Complete Utility + +As promised, here's the complete `count` command, for your experimentation: + +```swift +import ArgumentParser +import Foundation + +struct Count: ParsableCommand { + static let configuration = CommandConfiguration(abstract: "Word counter.") + + @Option(name: [.short, .customLong("input")], help: "A file to read.") + var inputFile: String + + @Option(name: [.short, .customLong("output")], help: "A file to save word counts to.") + var outputFile: String + + @Flag(name: .shortAndLong, help: "Print status updates while counting.") + var verbose = false + + mutating func run() throws { + if verbose { + print(""" + Counting words in '\(inputFile)' \ + and writing the result into '\(outputFile)'. + """) + } + + guard let input = try? String(contentsOfFile: inputFile) else { + throw RuntimeError("Couldn't read from '\(inputFile)'!") + } + + let words = input.components(separatedBy: .whitespacesAndNewlines) + .map { word in + word.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) + .lowercased() + } + .compactMap { word in word.isEmpty ? nil : word } + + let counts = Dictionary(grouping: words, by: { $0 }) + .mapValues { $0.count } + .sorted(by: { $0.value > $1.value }) + + if verbose { + print("Found \(counts.count) words.") + } + + let output = counts.map { word, count in "\(word): \(count)" } + .joined(separator: "\n") + + guard let _ = try? output.write(toFile: outputFile, atomically: true, encoding: .utf8) else { + throw RuntimeError("Couldn't write to '\(outputFile)'!") + } + } +} + +struct RuntimeError: Error, CustomStringConvertible { + var description: String + + init(_ description: String) { + self.description = description + } +} + +Count.main() +``` diff --git a/Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Code/code.txt b/Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Code/code.txt new file mode 100644 index 000000000..175f62c82 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Code/code.txt @@ -0,0 +1,288 @@ +# Getting Started with ArgumentParser + +Learn to set up and customize a simple command-line tool. + +## Overview + +This guide walks through building an example command. You'll learn about the different tools that `ArgumentParser` provides for defining a command's options, customizing the interface, and providing help text for your user. + +## Adding `ArgumentParser` as a Dependency + +Let's write a tool called `count` that reads an input file, counts the words, and writes the result to an output file. + +First, we need to add `swift-argument-parser` as a dependency to our package, +and then include `"ArgumentParser"` as a dependency for our executable target. +Our "Package.swift" file ends up looking like this: + +```swift +// swift-tools-version:5.2 +import PackageDescription + +let package = Package( + name: "random", + dependencies: [ + .package(url: "https://github.com/apple/swift-argument-parser.git", from: "0.4.0"), + ], + targets: [ + .target( + name: "count", + dependencies: [.product(name: "ArgumentParser", package: "swift-argument-parser")]), + ] +) +``` + +> **Note:** To read more about creating and configuring packages using Swift Package Manager, see [Using the Package Manager](https://swift.org/getting-started/#using-the-package-manager). + +## Building Our First Command + +Once we've built the `count` tool, we'll be able to run it like this: + +``` +% count readme.md readme.counts +Counting words in 'readme.md' and writing the result into 'readme.counts'. +``` + +We'll define the initial version of the command as a type that conforms to the `ParsableCommand` protocol: + +```swift +import ArgumentParser + +struct Count: ParsableCommand { + @Argument var inputFile: String + @Argument var outputFile: String + + mutating func run() throws { + print(""" + Counting words in '\(inputFile)' \ + and writing the result into '\(outputFile)'. + """) + + // Read 'inputFile', count the words, and save to 'outputFile'. + } +} + +Count.main() +``` + +In the code above, the `inputFile` and `outputFile` properties use the `@Argument` property wrapper. `ArgumentParser` uses this wrapper to denote a positional command-line input — because `inputFile` is specified first in the `Count` type, it's the first value read from the command line, and `outputFile` is read second. + +We've implemented the command's logic in its `run()` method. Here, we're printing out a message confirming the names of the files the user gave. (You can find a full implementation of the completed command at the end of this guide.) + +Finally, you tell the parser to execute the `Count` command by calling its static `main()` method. This method parses the command-line arguments, verifies that they match up with what we've defined in `Count`, and either calls the `run()` method or exits with a helpful message. + + +## Working with Named Options + +Our `count` tool may have a usability problem — it's not immediately clear whether a user should provide the input file first, or the output file. Instead of using positional arguments for our two inputs, let's specify that they should be labeled options: + +``` +% count --input-file readme.md --output-file readme.counts +Counting words in 'readme.md' and writing the result into 'readme.counts'. +``` + +We do this by using the `@Option` property wrapper instead of `@Argument`: + +```swift +struct Count: ParsableCommand { + @Option var inputFile: String + @Option var outputFile: String + + mutating func run() throws { + print(""" + Counting words in '\(inputFile)' \ + and writing the result into '\(outputFile)'. + """) + + // Read 'inputFile', count the words, and save to 'outputFile'. + } +} +``` + +The `@Option` property wrapper denotes a command-line input that looks like `--name `, deriving its name from the name of your property. + +This interface has a trade-off for the users of our `count` tool: With `@Argument`, users don't need to type as much, but they have to remember whether to provide the input file or the output file first. Using `@Option` makes the user type a little more, but the distinction between values is explicit. Options are order-independent, as well, so the user can name the input and output files in either order: + +``` +% count --output-file readme.counts --input-file readme.md +Counting words in 'readme.md' and writing the result into 'readme.counts'. +``` + +## Adding a Flag + +Next, we want to add a `--verbose` flag to our tool, and only print the message if the user specifies that option: + +``` +% count --input-file readme.md --output-file readme.counts +(no output) +% count --verbose --input-file readme.md --output-file readme.counts +Counting words in 'readme.md' and writing the result into 'readme.counts'. +``` + +Let's change our `Count` type to look like this: + +```swift +struct Count: ParsableCommand { + @Option var inputFile: String + @Option var outputFile: String + @Flag var verbose = false + + mutating func run() throws { + if verbose { + print(""" + Counting words in '\(inputFile)' \ + and writing the result into '\(outputFile)'. + """) + } + + // Read 'inputFile', count the words, and save to 'outputFile'. + } +} +``` + +The `@Flag` property wrapper denotes a command-line input that looks like `--name`, deriving its name from the name of your property. Flags are most frequently used for Boolean values, like the `verbose` property here. + + +## Using Custom Names + +We can customize the names of our options and add an alternative to the `verbose` flag so that users can specify `-v` instead of `--verbose`. The new interface will look like this: + +``` +% count -v -i readme.md -o readme.counts +Counting words in 'readme.md' and writing the result into 'readme.counts'. +% count --input readme.md --output readme.counts -v +Counting words in 'readme.md' and writing the result into 'readme.counts'. +% count -o readme.counts -i readme.md --verbose +Counting words in 'readme.md' and writing the result into 'readme.counts'. +``` + +Customize the input names by passing `name` parameters to the `@Option` and `@Flag` initializers: + +```swift +struct Count: ParsableCommand { + @Option(name: [.short, .customLong("input")]) + var inputFile: String + + @Option(name: [.short, .customLong("output")]) + var outputFile: String + + @Flag(name: .shortAndLong) + var verbose = false + + mutating func run() throws { ... } +} +``` + +The default name specification is `.long`, which uses a property's name with a two-dash prefix. `.short` uses only the first letter of a property's name with a single-dash prefix, and allows combining groups of short options. You can specify custom short and long names with the `.customShort(_:)` and `.customLong(_:)` methods, respectively, or use the combined `.shortAndLong` property to specify the common case of both the short and long derived names. + +## Providing Help + +`ArgumentParser` automatically generates help for any command when a user provides the `-h` or `--help` flags: + +``` +% count --help +USAGE: count --input --output [--verbose] + +OPTIONS: + -i, --input + -o, --output + -v, --verbose + -h, --help Show help information. +``` + +This is a great start — you can see that all the custom names are visible, and the help shows that values are expected for the `--input` and `--output` options. However, our custom options and flag don't have any descriptive text. Let's add that now by passing string literals as the `help` parameter: + +```swift +struct Count: ParsableCommand { + @Option(name: [.short, .customLong("input")], help: "A file to read.") + var inputFile: String + + @Option(name: [.short, .customLong("output")], help: "A file to save word counts to.") + var outputFile: String + + @Flag(name: .shortAndLong, help: "Print status updates while counting.") + var verbose = false + + mutating func run() throws { ... } +} +``` + +The help screen now includes descriptions for each parameter: + +``` +% count -h +USAGE: count --input --output [--verbose] + +OPTIONS: + -i, --input A file to read. + -o, --output A file to save word counts to. + -v, --verbose Print status updates while counting. + -h, --help Show help information. + +``` + +## The Complete Utility + +As promised, here's the complete `count` command, for your experimentation: + +```swift +import ArgumentParser +import Foundation + +struct Count: ParsableCommand { + static let configuration = CommandConfiguration(abstract: "Word counter.") + + @Option(name: [.short, .customLong("input")], help: "A file to read.") + var inputFile: String + + @Option(name: [.short, .customLong("output")], help: "A file to save word counts to.") + var outputFile: String + + @Flag(name: .shortAndLong, help: "Print status updates while counting.") + var verbose = false + + mutating func run() throws { + if verbose { + print(""" + Counting words in '\(inputFile)' \ + and writing the result into '\(outputFile)'. + """) + } + + guard let input = try? String(contentsOfFile: inputFile) else { + throw RuntimeError("Couldn't read from '\(inputFile)'!") + } + + let words = input.components(separatedBy: .whitespacesAndNewlines) + .map { word in + word.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) + .lowercased() + } + .compactMap { word in word.isEmpty ? nil : word } + + let counts = Dictionary(grouping: words, by: { $0 }) + .mapValues { $0.count } + .sorted(by: { $0.value > $1.value }) + + if verbose { + print("Found \(counts.count) words.") + } + + let output = counts.map { word, count in "\(word): \(count)" } + .joined(separator: "\n") + + guard let _ = try? output.write(toFile: outputFile, atomically: true, encoding: .utf8) else { + throw RuntimeError("Couldn't write to '\(outputFile)'!") + } + } +} + +struct RuntimeError: Error, CustomStringConvertible { + var description: String + + init(_ description: String) { + self.description = description + } +} + +Count.main() +``` diff --git a/Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Images/Image.png b/Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Images/Image.png new file mode 100644 index 0000000000000000000000000000000000000000..0aee5dc76f6fcb4a7c1a2402dce7a5fc38b6d4cd GIT binary patch literal 97845 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%0Dx+@wY+Dih#)d*G)J#aJgWI1NL;`tGSZ0Q| zY{M#f?*PQ_T#&F?LSX09|Z%R%EmrFHJ*39;;@V)^i-hAP~lHvKpD^o*k7<&Ux$x}4Pr$; zb1!}Pv9*cblqoMOU){q?*fKEw5DFm3GbD@H&q9`Ri5$$;g@E-T>wO{{8}T+`mu|( z#(suTO247r?)smZ19tAtHmt}0%+z}oKK;QCXT;LH3sjd$Ujj-H^IP4MEJH6*fk4-s z;^XB**G*sRx|L!Xt9^mMMsF#^Xb$ug%_twiC%0Ak1ufsfLS_&A$L03>GdBGLhUVNY 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 SK;O3c+`eIQJ^z~hv;PMW+DW7U literal 0 HcmV?d00001 diff --git a/Sources/ArgumentParser/Documentation.docc/Tutorials/ArgumentParser.tutorial b/Sources/ArgumentParser/Documentation.docc/Tutorials/ArgumentParser.tutorial new file mode 100644 index 000000000..d5c08bc53 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/Tutorials/ArgumentParser.tutorial @@ -0,0 +1,15 @@ +@Tutorials(name: "ArgumentParser") { + @Intro(title: "Get Started with ArgumentParser") { + Do a thing with a CLI tool. + + @Image(source: Image, alt: "<#accessible description#>") + } + + @Chapter(name: "ArgumentParser Essentials") { + Create your thingy + + @Image(source: Image, alt: "<#accessible description#>") + + @TutorialReference(tutorial: "doc:Get-Started") + } +} diff --git a/Sources/ArgumentParser/Documentation.docc/Tutorials/Get Started.tutorial b/Sources/ArgumentParser/Documentation.docc/Tutorials/Get Started.tutorial new file mode 100644 index 000000000..bfa2aeae5 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/Tutorials/Get Started.tutorial @@ -0,0 +1,27 @@ +@Tutorial(time: 20) { + @Intro(title: "A Command Line App with ArgumentParser") { + This tutorial guides you through building a custom command-line tool using ArgumentParser. + + @Image(source: Image, alt: "<#accessible description#>") + } + + @Section(title: "Create a new project and add ArgumentParser") { + @ContentAndMedia(layout: horizontal) { + <#text#> + + @Image(source: Image, alt: "<#accessible description#>") + } + + @Steps { + @Step { + <#text#> + @Image(source: Image, alt: "<#accessible description#>") + } + + @Step { + <#text#> + @Code(name: "Some Code.txt", file: code.txt) + } + } + } +} From 7e6e86926a40f58b1b00067dbe34da103ff7fa1d Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 10 Jun 2021 14:52:50 -0500 Subject: [PATCH 02/18] More curation / move article content into DocC articles --- Docs/07 Completion Scripts.md | 56 ------ .../Documentation.docc/ArgumentParser.md | 44 +++-- .../CommandsAndSubcommands.md | 178 ++++++++++++++++++ .../CustomizingCompletions.md | 62 ++++++ .../InstallingCompletionScripts.md | 59 ++++++ 5 files changed, 323 insertions(+), 76 deletions(-) create mode 100644 Sources/ArgumentParser/Documentation.docc/CommandsAndSubcommands.md create mode 100644 Sources/ArgumentParser/Documentation.docc/CustomizingCompletions.md create mode 100644 Sources/ArgumentParser/Documentation.docc/InstallingCompletionScripts.md diff --git a/Docs/07 Completion Scripts.md b/Docs/07 Completion Scripts.md index 4cf0a411f..f3ddc1cac 100644 --- a/Docs/07 Completion Scripts.md +++ b/Docs/07 Completion Scripts.md @@ -60,59 +60,3 @@ Copy the completion script to any path listed in the environment variable `$fish ## Customizing Completions -`ArgumentParser` provides default completions for any types that it can. For example, an `@Option` property that is a `CaseIterable` type will automatically have the correct values as completion suggestions. - -When declaring an option or argument, you can customize the completions that are offered by specifying a `CompletionKind`. With this completion kind you can specify that the value should be a file, a directory, or one of a list of strings: - -```swift -struct Example: ParsableCommand { - @Option(help: "The file to read from.", completion: .file()) - var input: String - - @Option(help: "The output directory.", completion: .directory) - var outputDir: String - - @Option(help: "The preferred file format.", completion: .list(["markdown", "rst"])) - var format: String - - enum CompressionType: String, CaseIterable, ExpressibleByArgument { - case zip, gzip - } - - @Option(help: "The compression type to use.") - var compression: CompressionType -} -``` - -The generated completion script will suggest only file names for the `--input` option, only directory names for `--output-dir`, and only the strings `markdown` and `rst` for `--format`. The `--compression` option uses the default completions for a `CaseIterable` type, so the completion script will suggest `zip` and `gzip`. - -You can define the default completion kind for custom `ExpressibleByArgument` types by implementing `static var defaultCompletionKind: CompletionKind`. For example, any arguments or options with this `File` type will automatically use files for completions: - -```swift -struct File: Hashable, ExpressibleByArgument { - var path: String - - init?(argument: String) { - self.path = argument - } - - static var defaultCompletionKind: CompletionKind { - .file() - } -} -``` - -For even more control over the suggested completions, you can specify a function that will be called during completion by using the `.custom` completion kind. - -```swift -func listExecutables(_ arguments: [String]) -> [String] { - // Generate the list of executables in the current directory -} - -struct SwiftRun { - @Option(help: "The target to execute.", completion: .custom(listExecutables)) - var target: String? -} -``` - -In this example, when a user requests completions for the `--target` option, the completion script runs the `SwiftRun` command-line tool with a special syntax, calling the `listExecutables` function with an array of the arguments given so far. diff --git a/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md b/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md index 813aba292..f043ff8cf 100644 --- a/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md +++ b/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md @@ -8,43 +8,47 @@ Text... ## Topics -### Guides +### Getting Started - - -### Parsable Properties +### Commands and Subcommands + +- +- ``ParsableCommand`` +- ``CommandConfiguration`` + +### Arguments, Options, and Flags + +Declare properties of commands using the `@Argument`, `@Option`, and `@Flag` +property wrappers. - ``Argument`` - ``Option`` - ``Flag`` - -### Parsable Types - -- ``ParsableCommand`` -- ``ParsableArguments`` - ``OptionGroup`` -- ``EnumerableFlag`` +- ``ParsableArguments`` -### Customization +### Property Customization - ``ArgumentHelp`` - ``NameSpecification`` -- ``CommandConfiguration`` -- ``FlagInversion`` -- ``FlagExclusivity`` -- ``SingleValueParsingStrategy`` -- ``ArrayParsingStrategy`` -- ``ArgumentArrayParsingStrategy`` -- ``CompletionKind`` -- ``CompletionShell`` -### Validation and Errors +### Custom Types + +- ``ExpressibleByArgument`` +- ``EnumerableFlag`` + +### Errors and Validation - ``ValidationError`` - ``CleanExit`` - ``ExitCode`` -### Expressible Types +### Shell Completion Scripts -- ``ExpressibleByArgument`` +- +- +- ``CompletionKind`` +- ``CompletionShell`` diff --git a/Sources/ArgumentParser/Documentation.docc/CommandsAndSubcommands.md b/Sources/ArgumentParser/Documentation.docc/CommandsAndSubcommands.md new file mode 100644 index 000000000..1825af795 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/CommandsAndSubcommands.md @@ -0,0 +1,178 @@ +# Defining Commands and Subcommands + +When command-line programs grow larger, it can be useful to divide them into a group of smaller programs, providing an interface through subcommands. Utilities such as `git` and the Swift package manager are able to provide varied interfaces for each of their sub-functions by implementing subcommands such as `git branch` or `swift package init`. + +Generally, these subcommands each have their own configuration options, as well as options that are shared across several or all aspects of the larger program. + +You can build a program with commands and subcommands by defining multiple command types and specifying each command's subcommands in its configuration. For example, here's the interface of a `math` utility that performs operations on a series of values given on the command line. + +``` +% math add 10 15 7 +32 +% math multiply 10 15 7 +1050 +% math stats average 3 4 13 15 15 +10.0 +% math stats average --kind median 3 4 13 15 15 +13.0 +% math stats +OVERVIEW: Calculate descriptive statistics. + +USAGE: math stats + +OPTIONS: + -h, --help Show help information. + +SUBCOMMANDS: + average Print the average of the values. + stdev Print the standard deviation of the values. + quantiles Print the quantiles of the values (TBD). + + See 'math help stats ' for detailed help. +``` + +Start by defining the root `Math` command. You can provide a static `configuration` property for a command that specifies its subcommands and a default subcommand, if any. + +```swift +struct Math: ParsableCommand { + static var configuration = CommandConfiguration( + abstract: "A utility for performing maths.", + subcommands: [Add.self, Multiply.self, Statistics.self], + defaultSubcommand: Add.self) +} +``` + +`Math` lists its three subcommands by their types; we'll see the definitions of `Add`, `Multiply`, and `Statistics` below. `Add` is also given as a default subcommand — this means that it is selected if a user leaves out a subcommand name: + +``` +% math 10 15 7 +32 +``` + +Next, define a `ParsableArguments` type with properties that will be shared across multiple subcommands. Types that conform to `ParsableArguments` can be parsed from command-line arguments, but don't provide any execution through a `run()` method. + +In this case, the `Options` type accepts a `--hexadecimal-output` flag and expects a list of integers. + +```swift +struct Options: ParsableArguments { + @Flag(name: [.long, .customShort("x")], help: "Use hexadecimal notation for the result.") + var hexadecimalOutput = false + + @Argument(help: "A group of integers to operate on.") + var values: [Int] +} +``` + +It's time to define our first two subcommands: `Add` and `Multiply`. Both of these subcommands include the arguments defined in the `Options` type by denoting that property with the `@OptionGroup` property wrapper. `@OptionGroup` doesn't define any new arguments for a command; instead, it splats in the arguments defined by another `ParsableArguments` type. + +```swift +extension Math { + struct Add: ParsableCommand { + static var configuration + = CommandConfiguration(abstract: "Print the sum of the values.") + + @OptionGroup var options: Math.Options + + mutating func run() { + let result = options.values.reduce(0, +) + print(format(result: result, usingHex: options.hexadecimalOutput)) + } + } + + struct Multiply: ParsableCommand { + static var configuration + = CommandConfiguration(abstract: "Print the product of the values.") + + @OptionGroup var options: Math.Options + + mutating func run() { + let result = options.values.reduce(1, *) + print(format(result: result, usingHex: options.hexadecimalOutput)) + } + } +} +``` + +Next, we'll define `Statistics`, the third subcommand of `Math`. The `Statistics` command specifies a custom command name (`stats`) in its configuration, overriding the default derived from the type name (`statistics`). It also declares two additional subcommands, meaning that it acts as a forked branch in the command tree, and not a leaf. + +```swift +extension Math { + struct Statistics: ParsableCommand { + static var configuration = CommandConfiguration( + commandName: "stats", + abstract: "Calculate descriptive statistics.", + subcommands: [Average.self, StandardDeviation.self]) + } +} +``` + +Let's finish our subcommands with the `Average` and `StandardDeviation` types. Each of them has slightly different arguments, so they don't use the `Options` type defined above. Each subcommand is ultimately independent and can specify a combination of shared and unique arguments. + +```swift +extension Math.Statistics { + struct Average: ParsableCommand { + static var configuration = CommandConfiguration( + abstract: "Print the average of the values.") + + enum Kind: String, ExpressibleByArgument { + case mean, median, mode + } + + @Option(help: "The kind of average to provide.") + var kind: Kind = .mean + + @Argument(help: "A group of floating-point values to operate on.") + var values: [Double] = [] + + func calculateMean() -> Double { ... } + func calculateMedian() -> Double { ... } + func calculateMode() -> [Double] { ... } + + mutating func run() { + switch kind { + case .mean: + print(calculateMean()) + case .median: + print(calculateMedian()) + case .mode: + let result = calculateMode() + .map(String.init(describing:)) + .joined(separator: " ") + print(result) + } + } + } + + struct StandardDeviation: ParsableCommand { + static var configuration = CommandConfiguration( + commandName: "stdev", + abstract: "Print the standard deviation of the values.") + + @Argument(help: "A group of floating-point values to operate on.") + var values: [Double] = [] + + mutating func run() { + if values.isEmpty { + print(0.0) + } else { + let sum = values.reduce(0, +) + let mean = sum / Double(values.count) + let squaredErrors = values + .map { $0 - mean } + .map { $0 * $0 } + let variance = squaredErrors.reduce(0, +) + let result = variance.squareRoot() + print(result) + } + } + } +} +``` + +Last but not least, we kick off parsing and execution with a call to the static `main` method on the type at the root of our command tree. The call to main parses the command-line arguments, determines whether a subcommand was selected, and then instantiates and calls the `run()` method on that particular subcommand. + +```swift +Math.main() +``` + +That's it for this doubly-nested `math` command! This example is also provided as a part of the `swift-argument-parser` repository, so you can see it all together and experiment with it [here](https://github.com/apple/swift-argument-parser/blob/main/Examples/math/main.swift). diff --git a/Sources/ArgumentParser/Documentation.docc/CustomizingCompletions.md b/Sources/ArgumentParser/Documentation.docc/CustomizingCompletions.md new file mode 100644 index 000000000..3ce754477 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/CustomizingCompletions.md @@ -0,0 +1,62 @@ +# Customizing Completions + +Summary + +## Overview + +`ArgumentParser` provides default completions for any types that it can. For example, an `@Option` property that is a `CaseIterable` type will automatically have the correct values as completion suggestions. + +When declaring an option or argument, you can customize the completions that are offered by specifying a `CompletionKind`. With this completion kind you can specify that the value should be a file, a directory, or one of a list of strings: + +```swift +struct Example: ParsableCommand { + @Option(help: "The file to read from.", completion: .file()) + var input: String + + @Option(help: "The output directory.", completion: .directory) + var outputDir: String + + @Option(help: "The preferred file format.", completion: .list(["markdown", "rst"])) + var format: String + + enum CompressionType: String, CaseIterable, ExpressibleByArgument { + case zip, gzip + } + + @Option(help: "The compression type to use.") + var compression: CompressionType +} +``` + +The generated completion script will suggest only file names for the `--input` option, only directory names for `--output-dir`, and only the strings `markdown` and `rst` for `--format`. The `--compression` option uses the default completions for a `CaseIterable` type, so the completion script will suggest `zip` and `gzip`. + +You can define the default completion kind for custom `ExpressibleByArgument` types by implementing `static var defaultCompletionKind: CompletionKind`. For example, any arguments or options with this `File` type will automatically use files for completions: + +```swift +struct File: Hashable, ExpressibleByArgument { + var path: String + + init?(argument: String) { + self.path = argument + } + + static var defaultCompletionKind: CompletionKind { + .file() + } +} +``` + +For even more control over the suggested completions, you can specify a function that will be called during completion by using the `.custom` completion kind. + +```swift +func listExecutables(_ arguments: [String]) -> [String] { + // Generate the list of executables in the current directory +} + +struct SwiftRun { + @Option(help: "The target to execute.", completion: .custom(listExecutables)) + var target: String? +} +``` + +In this example, when a user requests completions for the `--target` option, the completion script runs the `SwiftRun` command-line tool with a special syntax, calling the `listExecutables` function with an array of the arguments given so far. diff --git a/Sources/ArgumentParser/Documentation.docc/InstallingCompletionScripts.md b/Sources/ArgumentParser/Documentation.docc/InstallingCompletionScripts.md new file mode 100644 index 000000000..6599e51fc --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/InstallingCompletionScripts.md @@ -0,0 +1,59 @@ +# Generating and Installing Completion Scripts + +Summary + +## Overview + +Command-line tools that you build with `ArgumentParser` include a built-in option for generating completion scripts, with support for Bash, Z shell, and Fish. To generate completions, run your command with the `--generate-completion-script` flag to generate completions for the autodetected shell, or with a value to generate completions for a specific shell. + +``` +$ example --generate-completion-script bash +#compdef example +local context state state_descr line +_example_commandname="example" +typeset -A opt_args + +_example() { + integer ret=1 + local -a args + ... +} + +_example +``` + +The correct method of installing a completion script depends on your shell and your configuration. + +### Installing Zsh Completions + +If you have [`oh-my-zsh`](https://ohmyz.sh) installed, you already have a directory of automatically loading completion scripts — `.oh-my-zsh/completions`. Copy your new completion script to that directory. + +``` +$ example --generate-completion-script zsh > ~/.oh-my-zsh/completions/_example +``` + +> Your completion script must have the following filename format: `_example`. + +Without `oh-my-zsh`, you'll need to add a path for completion scripts to your function path, and turn on completion script autoloading. First, add these lines to `~/.zshrc`: + +``` +fpath=(~/.zsh/completion $fpath) +autoload -U compinit +compinit +``` + +Next, create a directory at `~/.zsh/completion` and copy the completion script to the new directory. + +### Installing Bash Completions + +If you have [`bash-completion`](https://github.com/scop/bash-completion) installed, you can just copy your new completion script to the `/usr/local/etc/bash_completion.d` directory. + +Without `bash-completion`, you'll need to source the completion script directly. Copy it to a directory such as `~/.bash_completions/`, and then add the following line to `~/.bash_profile` or `~/.bashrc`: + +``` +source ~/.bash_completions/example.bash +``` + +### Installing Fish Completions + +Copy the completion script to any path listed in the environment variable `$fish_completion_path`. For example, a typical location is `~/.config/fish/completions/your_script.fish`. From d8d4a1b9064ba2100d739c44826afc3af3a43a97 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 10 Jun 2021 15:36:39 -0500 Subject: [PATCH 03/18] Try out curating one of the property wrapper types --- .../Documentation.docc/Extensions/Argument.md | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Sources/ArgumentParser/Documentation.docc/Extensions/Argument.md diff --git a/Sources/ArgumentParser/Documentation.docc/Extensions/Argument.md b/Sources/ArgumentParser/Documentation.docc/Extensions/Argument.md new file mode 100644 index 000000000..e78a61e22 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/Extensions/Argument.md @@ -0,0 +1,32 @@ +# ``ArgumentParser/Argument`` + +## Topics + +### Single Arguments + +- ``init(help:completion:)-6pqzn`` +- ``init(help:completion:transform:)`` +- ``init(help:completion:)-4p94d`` +- ``init(wrappedValue:help:completion:)`` +- ``init(wrappedValue:help:completion:transform:)`` + +### Array Arguments + +- ``init(parsing:help:completion:)`` +- ``init(parsing:help:completion:transform:)`` +- ``init(wrappedValue:parsing:help:completion:)`` +- ``init(wrappedValue:parsing:help:completion:transform:)`` + +### Infrequently Used APIs + +- ``init()`` +- ``init(from:)`` +- ``wrappedValue`` + +### Supporting Types + +- ``FlagInversion`` +- ``FlagExclusivity`` +- ``SingleValueParsingStrategy`` +- ``ArrayParsingStrategy`` +- ``ArgumentArrayParsingStrategy`` From 54bea2b59c65a7c1dc6ba809e11395eb77ab814d Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 11 Jun 2021 10:40:25 -0500 Subject: [PATCH 04/18] Remove tutorial --- .../Documentation.docc/ArgumentParser.md | 1 - .../Tutorials/ArgumentParser.tutorial | 15 ----------- .../Tutorials/Get Started.tutorial | 27 ------------------- 3 files changed, 43 deletions(-) delete mode 100644 Sources/ArgumentParser/Documentation.docc/Tutorials/ArgumentParser.tutorial delete mode 100644 Sources/ArgumentParser/Documentation.docc/Tutorials/Get Started.tutorial diff --git a/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md b/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md index f043ff8cf..bea932ce6 100644 --- a/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md +++ b/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md @@ -10,7 +10,6 @@ Text... ### Getting Started -- - ### Commands and Subcommands diff --git a/Sources/ArgumentParser/Documentation.docc/Tutorials/ArgumentParser.tutorial b/Sources/ArgumentParser/Documentation.docc/Tutorials/ArgumentParser.tutorial deleted file mode 100644 index d5c08bc53..000000000 --- a/Sources/ArgumentParser/Documentation.docc/Tutorials/ArgumentParser.tutorial +++ /dev/null @@ -1,15 +0,0 @@ -@Tutorials(name: "ArgumentParser") { - @Intro(title: "Get Started with ArgumentParser") { - Do a thing with a CLI tool. - - @Image(source: Image, alt: "<#accessible description#>") - } - - @Chapter(name: "ArgumentParser Essentials") { - Create your thingy - - @Image(source: Image, alt: "<#accessible description#>") - - @TutorialReference(tutorial: "doc:Get-Started") - } -} diff --git a/Sources/ArgumentParser/Documentation.docc/Tutorials/Get Started.tutorial b/Sources/ArgumentParser/Documentation.docc/Tutorials/Get Started.tutorial deleted file mode 100644 index bfa2aeae5..000000000 --- a/Sources/ArgumentParser/Documentation.docc/Tutorials/Get Started.tutorial +++ /dev/null @@ -1,27 +0,0 @@ -@Tutorial(time: 20) { - @Intro(title: "A Command Line App with ArgumentParser") { - This tutorial guides you through building a custom command-line tool using ArgumentParser. - - @Image(source: Image, alt: "<#accessible description#>") - } - - @Section(title: "Create a new project and add ArgumentParser") { - @ContentAndMedia(layout: horizontal) { - <#text#> - - @Image(source: Image, alt: "<#accessible description#>") - } - - @Steps { - @Step { - <#text#> - @Image(source: Image, alt: "<#accessible description#>") - } - - @Step { - <#text#> - @Code(name: "Some Code.txt", file: code.txt) - } - } - } -} From 31547b03cc31d7066b5a5873ec5b494d58dc12ad Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 11 Jun 2021 10:40:32 -0500 Subject: [PATCH 05/18] Update package tools version to 5.5 Docc doesn't recognize catalogs when the tools version is lower than 5.5 --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index a8caf6ccb..eadd748b0 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.2 +// swift-tools-version:5.5 //===----------------------------------------------------------*- swift -*-===// // // This source file is part of the Swift Argument Parser open source project From c5236da82e1726941e173c83d7215168010d7c9e Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 11 Jun 2021 12:05:04 -0500 Subject: [PATCH 06/18] Reorganize articles a bit --- .../{ => Articles}/CommandsAndSubcommands.md | 0 .../{ => Articles}/CustomizingCompletions.md | 0 .../{ => Articles}/GettingStarted.md | 0 .../InstallingCompletionScripts.md | 0 .../Documentation.docc/Articles/Validation.md | 159 ++++++++++++++++++ 5 files changed, 159 insertions(+) rename Sources/ArgumentParser/Documentation.docc/{ => Articles}/CommandsAndSubcommands.md (100%) rename Sources/ArgumentParser/Documentation.docc/{ => Articles}/CustomizingCompletions.md (100%) rename Sources/ArgumentParser/Documentation.docc/{ => Articles}/GettingStarted.md (100%) rename Sources/ArgumentParser/Documentation.docc/{ => Articles}/InstallingCompletionScripts.md (100%) create mode 100644 Sources/ArgumentParser/Documentation.docc/Articles/Validation.md diff --git a/Sources/ArgumentParser/Documentation.docc/CommandsAndSubcommands.md b/Sources/ArgumentParser/Documentation.docc/Articles/CommandsAndSubcommands.md similarity index 100% rename from Sources/ArgumentParser/Documentation.docc/CommandsAndSubcommands.md rename to Sources/ArgumentParser/Documentation.docc/Articles/CommandsAndSubcommands.md diff --git a/Sources/ArgumentParser/Documentation.docc/CustomizingCompletions.md b/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingCompletions.md similarity index 100% rename from Sources/ArgumentParser/Documentation.docc/CustomizingCompletions.md rename to Sources/ArgumentParser/Documentation.docc/Articles/CustomizingCompletions.md diff --git a/Sources/ArgumentParser/Documentation.docc/GettingStarted.md b/Sources/ArgumentParser/Documentation.docc/Articles/GettingStarted.md similarity index 100% rename from Sources/ArgumentParser/Documentation.docc/GettingStarted.md rename to Sources/ArgumentParser/Documentation.docc/Articles/GettingStarted.md diff --git a/Sources/ArgumentParser/Documentation.docc/InstallingCompletionScripts.md b/Sources/ArgumentParser/Documentation.docc/Articles/InstallingCompletionScripts.md similarity index 100% rename from Sources/ArgumentParser/Documentation.docc/InstallingCompletionScripts.md rename to Sources/ArgumentParser/Documentation.docc/Articles/InstallingCompletionScripts.md diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/Validation.md b/Sources/ArgumentParser/Documentation.docc/Articles/Validation.md new file mode 100644 index 000000000..34894e421 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/Articles/Validation.md @@ -0,0 +1,159 @@ +# Validation and Errors + +Provide helpful feedback to users when things go wrong. + +## Overview + +While `ArgumentParser` validates that the inputs given by your user match the requirements and types that you define in each command, there are some requirements that can't easily be described in Swift's type system, such as the number of elements in an array, or an expected integer value. + +### Validating Command-Line Input + +To validate your commands properties after parsing, implement the `validate()` method on any `ParsableCommand` or `ParsableArguments` type. Throwing an error from the `validate()` method causes the program to print a message to standard error and exit with an error code, preventing the `run()` method from being called with invalid inputs. + +Here's a command that prints out one or more random elements from the list you provide. Its `validate()` method catches three different errors that a user can make and throws a relevant error for each one. + +```swift +struct Select: ParsableCommand { + @Option var count: Int = 1 + @Argument var elements: [String] = [] + + mutating func validate() throws { + guard count >= 1 else { + throw ValidationError("Please specify a 'count' of at least 1.") + } + + guard !elements.isEmpty else { + throw ValidationError("Please provide at least one element to choose from.") + } + + guard count <= elements.count else { + throw ValidationError("Please specify a 'count' less than the number of elements.") + } + } + + mutating func run() { + print(elements.shuffled().prefix(count).joined(separator: "\n")) + } +} +``` + +When you provide useful error messages, they can guide new users to success with your command-line tool! + +``` +% select +Error: Please provide at least one element to choose from. +Usage: select [--count ] [ ...] + See 'select --help' for more information. +% select --count 2 hello +Error: Please specify a 'count' less than the number of elements. +Usage: select [--count ] [ ...] + See 'select --help' for more information. +% select --count 0 hello hey hi howdy +Error: Please specify a 'count' of at least 1. +Usage: select [--count ] [ ...] + See 'select --help' for more information. +% select --count 2 hello hey hi howdy +howdy +hey +``` + +## Handling Post-Validation Errors + +The `ValidationError` type is a special `ArgumentParser` error — a validation error's message is always accompanied by an appropriate usage string. You can throw other errors, from either the `validate()` or `run()` method to indicate that something has gone wrong that isn't validation-specific. Errors that conform to `CustomStringConvertible` or `LocalizedError` provide the best experience for users. + +```swift +struct LineCount: ParsableCommand { + @Argument var file: String + + mutating func run() throws { + let contents = try String(contentsOfFile: file, encoding: .utf8) + let lines = contents.split(separator: "\n") + print(lines.count) + } +} +``` + +The throwing `String(contentsOfFile:encoding:)` initializer fails when the user specifies an invalid file. `ArgumentParser` prints its error message to standard error and exits with an error code. + +``` +% line-count file1.swift +37 +% line-count non-existing-file.swift +Error: The file “non-existing-file.swift” couldn’t be opened because +there is no such file. +``` + +If you print your error output yourself, you still need to throw an error from `validate()` or `run()`, so that your command exits with the appropriate exit code. To avoid printing an extra error message, use the `ExitCode` error, which has static properties for success, failure, and validation errors, or lets you specify a specific exit code. + +```swift +struct RuntimeError: Error, CustomStringConvertible { + var description: String +} + +struct Example: ParsableCommand { + @Argument var inputFile: String + + mutating func run() throws { + if !ExampleCore.processFile(inputFile) { + // ExampleCore.processFile(_:) prints its own errors + // and returns `false` on failure. + throw ExitCode.failure + } + } +} +``` + +## Handling Transform Errors + +During argument and option parsing, you can use a closure to transform the command line strings to custom types. If this transformation fails, you can throw a `ValidationError`; its `message` property will be displayed to the user. + +In addition, you can throw your own errors. Errors that conform to `CustomStringConvertible` or `LocalizedError` provide the best experience for users. + +```swift +struct ExampleTransformError: Error, CustomStringConvertible { + var description: String +} + +struct ExampleDataModel: Codable { + let identifier: UUID + let tokens: [String] + let tokenCount: Int + + static func dataModel(_ jsonString: String) throws -> ExampleDataModel { + guard let data = jsonString.data(using: .utf8) else { throw ValidationError("Badly encoded string, should be UTF-8") } + return try JSONDecoder().decode(ExampleDataModel.self, from: data) + } +} + +struct Example: ParsableCommand { + // Reads in the argument string and attempts to transform it to + // an `ExampleDataModel` object using the `JSONDecoder`. If the + // string is not valid JSON, `decode` will throw an error and + // parsing will halt. + @Argument(transform: ExampleDataModel.dataModel) + var inputJSON: ExampleDataModel + + // Specifiying this option will always cause the parser to exit + // and print the custom error. + @Option(transform: { throw ExampleTransformError(description: "Trying to write to failOption always produces an error. Input: \($0)") }) + var failOption: String? +} +``` + +Throwing from a transform closure benefits users by providing context and can reduce development time by pinpointing issues quickly and more precisely. + +``` +% example '{"Bad JSON"}' +Error: The value '{"Bad JSON"}' is invalid for '': dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "No value for key in object around character 11." UserInfo={NSDebugDescription=No value for key in object around character 11.}))) +Usage: example --fail-option + See 'select --help' for more information. +``` + +While throwing standard library or Foundation errors adds context, custom errors provide the best experience for users and developers. + +``` +% example '{"tokenCount":0,"tokens":[],"identifier":"F77D661C-C5B7-448E-9344-267B284F66AD"}' --fail-option="Some Text Here!" +Error: The value 'Some Text Here!' is invalid for '--fail-option ': Trying to write to failOption always produces an error. Input: Some Text Here! +Usage: example --fail-option + See 'select --help' for more information. +``` From a069bbbc6035e17e0ab0f029590ba57c01acfbc1 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 11 Jun 2021 12:05:21 -0500 Subject: [PATCH 07/18] Curation for high-level types --- .../Documentation.docc/ArgumentParser.md | 10 ++--- .../Documentation.docc/Articles/Validation.md | 2 +- .../Documentation.docc/Extensions/Argument.md | 9 +--- .../Documentation.docc/Extensions/Flag.md | 43 +++++++++++++++++++ .../Documentation.docc/Extensions/Option.md | 26 +++++++++++ .../Extensions/ParsableArguments.md | 37 ++++++++++++++++ .../Extensions/ParsableCommand.md | 26 +++++++++++ 7 files changed, 137 insertions(+), 16 deletions(-) create mode 100644 Sources/ArgumentParser/Documentation.docc/Extensions/Flag.md create mode 100644 Sources/ArgumentParser/Documentation.docc/Extensions/Option.md create mode 100644 Sources/ArgumentParser/Documentation.docc/Extensions/ParsableArguments.md create mode 100644 Sources/ArgumentParser/Documentation.docc/Extensions/ParsableCommand.md diff --git a/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md b/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md index bea932ce6..cc9f050e4 100644 --- a/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md +++ b/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md @@ -8,15 +8,11 @@ Text... ## Topics -### Getting Started +### Essentials - - -### Commands and Subcommands - - - ``ParsableCommand`` -- ``CommandConfiguration`` ### Arguments, Options, and Flags @@ -39,8 +35,9 @@ property wrappers. - ``ExpressibleByArgument`` - ``EnumerableFlag`` -### Errors and Validation +### Validation and Errors +- - ``ValidationError`` - ``CleanExit`` - ``ExitCode`` @@ -50,4 +47,3 @@ property wrappers. - - - ``CompletionKind`` -- ``CompletionShell`` diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/Validation.md b/Sources/ArgumentParser/Documentation.docc/Articles/Validation.md index 34894e421..1aa0a87c9 100644 --- a/Sources/ArgumentParser/Documentation.docc/Articles/Validation.md +++ b/Sources/ArgumentParser/Documentation.docc/Articles/Validation.md @@ -1,4 +1,4 @@ -# Validation and Errors +# Providing Custom Validation Provide helpful feedback to users when things go wrong. diff --git a/Sources/ArgumentParser/Documentation.docc/Extensions/Argument.md b/Sources/ArgumentParser/Documentation.docc/Extensions/Argument.md index e78a61e22..63162d3f7 100644 --- a/Sources/ArgumentParser/Documentation.docc/Extensions/Argument.md +++ b/Sources/ArgumentParser/Documentation.docc/Extensions/Argument.md @@ -16,17 +16,10 @@ - ``init(parsing:help:completion:transform:)`` - ``init(wrappedValue:parsing:help:completion:)`` - ``init(wrappedValue:parsing:help:completion:transform:)`` +- ``ArgumentArrayParsingStrategy`` ### Infrequently Used APIs - ``init()`` - ``init(from:)`` - ``wrappedValue`` - -### Supporting Types - -- ``FlagInversion`` -- ``FlagExclusivity`` -- ``SingleValueParsingStrategy`` -- ``ArrayParsingStrategy`` -- ``ArgumentArrayParsingStrategy`` diff --git a/Sources/ArgumentParser/Documentation.docc/Extensions/Flag.md b/Sources/ArgumentParser/Documentation.docc/Extensions/Flag.md new file mode 100644 index 000000000..d2be6d8cd --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/Extensions/Flag.md @@ -0,0 +1,43 @@ +# ``ArgumentParser/Flag`` + +## Topics + +### Boolean Flags + +- ``init(wrappedValue:name:help:)`` + +### Boolean Flags with Inversions + +- ``init(wrappedValue:name:inversion:exclusivity:help:)`` +- ``init(name:inversion:exclusivity:help:)-12okg`` +- ``init(name:inversion:exclusivity:help:)-1h8f7`` +- ``FlagInversion`` + +### Counted Flags + +- ``init(name:help:)-87c7k`` + +### Custom Enumerable Flags + +- ``init(help:)`` +- ``init(exclusivity:help:)-38n7u`` +- ``init(exclusivity:help:)-5fggj`` +- ``init(wrappedValue:exclusivity:help:)`` +- ``init(wrappedValue:help:)`` + +### Infrequently Used APIs + +- ``init(from:)`` +- ``wrappedValue`` + +### Supporting Types + +- ``FlagExclusivity`` + +### Deprecated APIs + +- ``init()`` +- ``init(name:default:exclusivity:help:)`` +- ``init(name:help:)-5iirr`` +- ``init(name:exclusivity:help:)`` +- ``init(name:exclusivity:help:)`` diff --git a/Sources/ArgumentParser/Documentation.docc/Extensions/Option.md b/Sources/ArgumentParser/Documentation.docc/Extensions/Option.md new file mode 100644 index 000000000..3fb9983fc --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/Extensions/Option.md @@ -0,0 +1,26 @@ +# ``ArgumentParser/Option`` + +## Topics + +### Single Options + +- ``init(name:parsing:help:completion:)-4yske`` +- ``init(name:parsing:help:completion:)-7slrf`` +- ``init(name:parsing:help:completion:transform:)-2wf44`` +- ``init(wrappedValue:name:parsing:completion:help:)`` +- ``init(wrappedValue:name:parsing:help:completion:transform:)-2llve`` +- ``SingleValueParsingStrategy`` + +### Array Options + +- ``init(name:parsing:help:completion:)-238hg`` +- ``init(name:parsing:help:completion:transform:)-74hnp`` +- ``init(wrappedValue:name:parsing:help:completion:)`` +- ``init(wrappedValue:name:parsing:help:completion:transform:)-1kpto`` +- ``ArrayParsingStrategy`` + +### Infrequently Used APIs + +- ``init()`` +- ``init(from:)`` +- ``wrappedValue`` diff --git a/Sources/ArgumentParser/Documentation.docc/Extensions/ParsableArguments.md b/Sources/ArgumentParser/Documentation.docc/Extensions/ParsableArguments.md new file mode 100644 index 000000000..e4c0ece92 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/Extensions/ParsableArguments.md @@ -0,0 +1,37 @@ +# ``ArgumentParser/ParsableArguments`` + +## Topics + + + +### Handling Validation + +- ``validate()-5r0ge`` + +### Parsing a Type + +- ``parse(_:)`` +- ``parseOrExit(_:)`` + +### Exiting a Program + +- ``exit(withError:)`` + +### Generating Help Text + +- ``helpMessage(columns:)`` + +### Handling Errors + +- ``message(for:)`` +- ``fullMessage(for:)`` +- ``exitCode(for:)`` + +### Generating Completion Scripts + +- ``completionScript(for:)`` +- ``CompletionShell`` + +### Infrequently Used APIs + +- ``init()`` diff --git a/Sources/ArgumentParser/Documentation.docc/Extensions/ParsableCommand.md b/Sources/ArgumentParser/Documentation.docc/Extensions/ParsableCommand.md new file mode 100644 index 000000000..d7e3400d3 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/Extensions/ParsableCommand.md @@ -0,0 +1,26 @@ +# ``ArgumentParser/ParsableCommand`` + +## Topics + +### Implementing a Command's Behavior + +- ``run()-7p2fr`` + +### Customizing a Command + +- ``configuration-35km1`` +- ``CommandConfiguration`` + +### Generating Help Text + +- ``helpMessage(for:columns:)`` + +### Starting the Program + +- ``main(_:)`` +- ``main()`` + +### Manually Parsing Input + +- ``parseAsRoot(_:)`` + From 01e544f7a0ee5f0d755a317c0ad88759b2f129a9 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Wed, 7 Jul 2021 17:47:14 -0500 Subject: [PATCH 08/18] Fill out the main article page, update some abstracts --- .../Documentation.docc/ArgumentParser.md | 65 ++- .../Articles/CommandsAndSubcommands.md | 4 + .../Articles/CustomizingCompletions.md | 2 +- .../Articles/CustomizingHelp.md | 211 ++++++++ .../Articles/DeclaringArguments.md | 470 ++++++++++++++++++ .../Articles/InstallingCompletionScripts.md | 2 +- .../Articles/ManualParsing.md | 112 +++++ 7 files changed, 859 insertions(+), 7 deletions(-) create mode 100644 Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md create mode 100644 Sources/ArgumentParser/Documentation.docc/Articles/DeclaringArguments.md create mode 100644 Sources/ArgumentParser/Documentation.docc/Articles/ManualParsing.md diff --git a/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md b/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md index cc9f050e4..32d935ce7 100644 --- a/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md +++ b/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md @@ -1,10 +1,62 @@ # ``ArgumentParser`` -Summary.. +Straightforward, type-safe argument parsing for Swift. ## Overview -Text... +`ArgumentParser` uses the names and types of the properties you declare +to parse and validate command-line input. +Begin by declaring a type that defines +the information that you need to collect from the command line. +Decorate each stored property with one of `ArgumentParser`'s property wrappers, +declare conformance to ``ParsableCommand``, +and implement your command's logic in its `run()` method. + +```swift +import ArgumentParser + +@main +struct Repeat: ParsableCommand { + @Option(help: "The number of times to repeat 'phrase'.") + var count: Int? + + @Argument(help: "The phrase to repeat.") + var phrase: String + + mutating func run() throws { + let repeatCount = count ?? .max + for _ in 0..] + +ARGUMENTS: + The phrase to repeat. + +OPTIONS: + --count The number of times to repeat 'phrase'. + -h, --help Show help for this command. +$ repeat --count 3 +Error: Missing expected argument 'phrase'. +Help: The phrase to repeat. +Usage: repeat [--count ] + See 'repeat --help' for more information. +``` ## Topics @@ -16,9 +68,7 @@ Text... ### Arguments, Options, and Flags -Declare properties of commands using the `@Argument`, `@Option`, and `@Flag` -property wrappers. - +- - ``Argument`` - ``Option`` - ``Flag`` @@ -27,6 +77,7 @@ property wrappers. ### Property Customization +- - ``ArgumentHelp`` - ``NameSpecification`` @@ -47,3 +98,7 @@ property wrappers. - - - ``CompletionKind`` + +### Advanced Topics + +- diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/CommandsAndSubcommands.md b/Sources/ArgumentParser/Documentation.docc/Articles/CommandsAndSubcommands.md index 1825af795..e89cf5394 100644 --- a/Sources/ArgumentParser/Documentation.docc/Articles/CommandsAndSubcommands.md +++ b/Sources/ArgumentParser/Documentation.docc/Articles/CommandsAndSubcommands.md @@ -1,5 +1,9 @@ # Defining Commands and Subcommands +Break complex command-line tools into a tree of subcommands. + +## Overview + When command-line programs grow larger, it can be useful to divide them into a group of smaller programs, providing an interface through subcommands. Utilities such as `git` and the Swift package manager are able to provide varied interfaces for each of their sub-functions by implementing subcommands such as `git branch` or `swift package init`. Generally, these subcommands each have their own configuration options, as well as options that are shared across several or all aspects of the larger program. diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingCompletions.md b/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingCompletions.md index 3ce754477..96137afe8 100644 --- a/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingCompletions.md +++ b/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingCompletions.md @@ -1,6 +1,6 @@ # Customizing Completions -Summary +Provide custom shell completions for your command-line tool's arguments and options. ## Overview diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md b/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md new file mode 100644 index 000000000..0bf674ad6 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md @@ -0,0 +1,211 @@ +# Customizing Help + +Support your users (and yourself) by providing rich help for arguments and commands. + +## Overview + +You can provide help text when declaring any `@Argument`, `@Option`, or `@Flag` by passing a string literal as the `help` parameter: + +```swift +struct Example: ParsableCommand { + @Flag(help: "Display extra information while processing.") + var verbose = false + + @Option(help: "The number of extra lines to show.") + var extraLines = 0 + + @Argument(help: "The input file.") + var inputFile: String? +} +``` + +Users see these strings in the automatically-generated help screen, which is triggered by the `-h` or `--help` flags, by default: + +``` +% example --help +USAGE: example [--verbose] [--extra-lines ] + +ARGUMENTS: + The input file. + +OPTIONS: + --verbose Display extra information while processing. + --extra-lines + The number of extra lines to show. (default: 0) + -h, --help Show help information. +``` + +## Customizing Help for Arguments + +You can have more control over the help text by passing an `ArgumentHelp` instance instead. The `ArgumentHelp` type can include an abstract (which is what the string literal becomes), a discussion, a value name to use in the usage string, and a Boolean that indicates whether the argument should be visible in the help screen. + +Here's the same command with some extra customization: + +```swift +struct Example: ParsableCommand { + @Flag(help: "Display extra information while processing.") + var verbose = false + + @Option(help: ArgumentHelp( + "The number of extra lines to show.", + valueName: "n")) + var extraLines = 0 + + @Argument(help: ArgumentHelp( + "The input file.", + discussion: "If no input file is provided, the tool reads from stdin.", + valueName: "file")) + var inputFile: String? +} +``` + +...and the help screen: + +``` +USAGE: example [--verbose] [--extra-lines ] [] + +ARGUMENTS: + The input file. + If no input file is provided, the tool reads from stdin. + +OPTIONS: + --verbose Display extra information while processing. + --extra-lines The number of extra lines to show. (default: 0) + -h, --help Show help information. +``` + +## Customizing Help for Commands + +In addition to configuring the command name and subcommands, as described in [Command and Subcommands](03%20Commands%20and%20Subcommands.md), you can also configure a command's help text by providing an abstract and discussion. + +```swift +struct Repeat: ParsableCommand { + static var configuration = CommandConfiguration( + abstract: "Repeats your input phrase.", + discussion: """ + Prints to stdout forever, or until you halt the program. + """) + + @Argument(help: "The phrase to repeat.") + var phrase: String + + mutating func run() throws { + while true { print(phrase) } + } +} +``` + +The abstract and discussion appear in the generated help screen: + +``` +% repeat --help +OVERVIEW: Repeats your input phrase. + +Prints to stdout forever, or until you halt the program. + +USAGE: repeat + +ARGUMENTS: + The phrase to repeat. + +OPTIONS: + -h, --help Show help information. + +% repeat hello! +hello! +hello! +hello! +hello! +hello! +hello! +... +``` + +## Modifying the Help Flag Names + +Users can see the help screen for a command by passing either the `-h` or the `--help` flag, by default. If you need to use one of those flags for another purpose, you can provide alternative names when configuring a root command. + +```swift +struct Example: ParsableCommand { + static let configuration = CommandConfiguration( + helpNames: [.long, .customShort("?")]) + + @Option(name: .shortAndLong, help: "The number of history entries to show.") + var historyDepth: Int + + mutating func run() throws { + printHistory(depth: historyDepth) + } +} +``` + +When running the command, `-h` matches the short name of the `historyDepth` property, and `-?` displays the help screen. + +``` +% example -h 3 +... +% example -? +USAGE: example --history-depth + +ARGUMENTS: + The phrase to repeat. + +OPTIONS: + -h, --history-depth The number of history entries to show. + -?, --help Show help information. +``` + +When not overridden, custom help names are inherited by subcommands. In this example, the parent command defines `--help` and `-?` as its help names: + +```swift +struct Parent: ParsableCommand { + static let configuration = CommandConfiguration( + subcommands: [Child.self], + helpNames: [.long, .customShort("?")]) + + struct Child: ParsableCommand { + @Option(name: .shortAndLong, help: "The host the server will run on.") + var host: String + } +} +``` + +The `child` subcommand inherits the parent's help names, allowing the user to distinguish between the host argument (`-h`) and help (`-?`). + +``` +% parent child -h 192.0.0.0 +... +% parent child -? +USAGE: parent child --host + +OPTIONS: + -h, --host The host the server will run on. + -?, --help Show help information. +``` + +## Hiding Arguments and Commands + +You may want to suppress features under development or experimental flags from the generated help screen. You can hide an argument or a subcommand by passing `shouldDisplay: false` to the property wrapper or `CommandConfiguration` initializers, respectively. + +`ArgumentHelp` includes a `.hidden` static property that makes it even simpler to hide arguments: + +```swift +struct Example: ParsableCommand { + @Flag(help: .hidden) + var experimentalEnableWidgets: Bool +} +``` + +## Generating Help Text Programmatically + +The help screen is automatically shown to users when they call your command with the help flag. You can generate the same text from within your program by calling the `helpMessage()` method. + +```swift +let help = Repeat.helpMessage() +// `help` matches the output above + +let fortyColumnHelp = Repeat.helpMessage(columns: 40) +// `fortyColumnHelp` is the same help screen, but wrapped to 40 columns +``` + +When generating help text for a subcommand, call `helpMessage(for:)` on the `ParsableCommand` type that represents the root of the command tree and pass the subcommand type as a parameter to ensure the correct display. diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/DeclaringArguments.md b/Sources/ArgumentParser/Documentation.docc/Articles/DeclaringArguments.md new file mode 100644 index 000000000..e53834978 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/Articles/DeclaringArguments.md @@ -0,0 +1,470 @@ +# Declaring Arguments, Options, and Flags + +Use the `@Argument`, `@Option` and `@Flag` property wrappers to declare the command-line interface for your command. + +## Overview + +When creating commands, you can define three primary kinds of command-line inputs: + +- *Arguments* are values given by a user and are read in order from first to last. For example, this command is called with three file names as arguments: + + ``` + % example file1.swift file2.swift file3.swift + ``` + +- *Options* are named key-value pairs. Keys start with one or two dashes (`-` or `--`), and a user can separate the key and value with an equal sign (`=`) or a space. This command is called with two options: + + ``` + % example --count=5 --index 2 + ``` + +- *Flags* are like options, but without a paired value. Instead, their presence indicates a particular value (usually `true`). This command is called with two flags: + + ``` + % example --verbose --strip-whitespace + ``` + +The three preceding examples could be calls of this `Example` command: + +```swift +struct Example: ParsableCommand { + @Argument var files: [String] = [] + @Option var count: Int? + @Option var index = 0 + @Flag var verbose = false + @Flag var stripWhitespace = false +} +``` + +This example shows how `ArgumentParser` provides defaults that speed up your initial development process: + +- Option and flag names are derived from the names of your command's properties. +- What kinds of inputs are valid, and whether arguments are required, is based on your properties' types and default values. + +In this example, all of the properties have default values (optional properties default to `nil`). + +Users must provide values for all properties with no implicit or specified default. For example, this command would require one integer argument and a string with the key `--user-name`. + +```swift +struct Example: ParsableCommand { + @Option var userName: String + @Argument var value: Int +} +``` + +When called without both values, the command exits with an error: + +``` +% example 5 +Error: Missing '--user-name ' +Usage: example --user-name + See 'example --help' for more information. +% example --user-name kjohnson +Error: Missing '' +Usage: example --user-name + See 'example --help' for more information. +``` + +When providing a default value for an array property, any user-supplied values replace the entire default. + +```swift +struct Lucky: ParsableCommand { + @Argument var numbers = [7, 14, 21] + + mutating func run() throws { + print(""" + Your lucky numbers are: + \(numbers.map(String.init).joined(separator: " ")) + """) + } +} +``` + +``` +% lucky +Your lucky numbers are: +7 14 21 +% lucky 1 2 3 +Your lucky numbers are: +1 2 3 +``` + +## Customizing option and flag names + +By default, options and flags derive the name that you use on the command line from the name of the property, such as `--count` and `--index`. Camel-case names are converted to lowercase with hyphen-separated words, like `--strip-whitespace`. + +You can override this default by specifying one or more name specifications in the `@Option` or `@Flag` initializers. This command demonstrates the four name specifications: + +```swift +struct Example: ParsableCommand { + @Flag(name: .long) // Same as the default + var stripWhitespace = false + + @Flag(name: .short) + var verbose = false + + @Option(name: .customLong("count")) + var iterationCount: Int + + @Option(name: [.customShort("I"), .long]) + var inputFile: String +} +``` + +* Specifying `.long` or `.short` uses the property's name as the source of the command-line name. Long names use the whole name, prefixed by two dashes, while short names are a single character prefixed by a single dash. In this example, the `stripWhitespace` and `verbose` flags are specified in this way: + + ``` + % example --strip-whitespace -v + ``` + +* Specifying `.customLong(_:)` or `.customShort(_:)` uses the given string or character as the long or short name for the property. + + ``` + % example --count 10 -I file1.swift + ``` + +* Use array literal syntax to specify multiple names. The `inputFile` property can alternatively be given with the default long name: + + ``` + % example --input-file file1.swift + ``` + +**Note:** You can also pass `withSingleDash: true` to `.customLong` to create a single-dash flag or option, such as `-verbose`. Use this name specification only when necessary, such as when migrating a legacy command-line interface. Using long names with a single-dash prefix can lead to ambiguity with combined short names: it may not be obvious whether `-file` is a single option or the combination of the four short options `-f`, `-i`, `-l`, and `-e`. + + +## Parsing custom types + +Arguments and options can be parsed from any type that conforms to the `ExpressibleByArgument` protocol. Standard library integer and floating-point types, strings, and Booleans all conform to `ExpressibleByArgument`. + +You can make your own custom types conform to `ExpressibleByArgument` by implementing `init?(argument:)`: + +```swift +struct Path: ExpressibleByArgument { + var pathString: String + + init?(argument: String) { + self.pathString = argument + } +} + +struct Example: ParsableCommand { + @Argument var inputFile: Path +} +``` + +The library provides a default implementation for `RawRepresentable` types, like string-backed enumerations, so you only need to declare conformance. + +```swift +enum ReleaseMode: String, ExpressibleByArgument { + case debug, release +} + +struct Example: ParsableCommand { + @Option var mode: ReleaseMode + + mutating func run() throws { + print(mode) + } +} +``` + +The user can provide the raw values on the command line, which are then converted to your custom type. Only valid values are allowed: + +``` +% example --mode release +release +% example --mode future +Error: The value 'future' is invalid for '--mode ' +``` + +To use a non-`ExpressibleByArgument` type for an argument or option, you can instead provide a throwing `transform` function that converts the parsed string to your desired type. This is a good idea for custom types that are more complex than a `RawRepresentable` type, or for types you don't define yourself. + +```swift +enum Format { + case text + case other(String) + + init(_ string: String) throws { + if string == "text" { + self = .text + } else { + self = .other(string) + } + } +} + +struct Example: ParsableCommand { + @Argument(transform: Format.init) + var format: Format +} +``` + +Throw an error from the `transform` function to indicate that the user provided an invalid value for that type. See [Handling Transform Errors](./05%20Validation%20and%20Errors.md#handling-transform-errors) for more about customizing `transform` function errors. + +## Using flag inversions, enumerations, and counts + +Flags are most frequently used for `Bool` properties. You can generate a `true`/`false` pair of flags by specifying a flag inversion: + +```swift +struct Example: ParsableCommand { + @Flag(inversion: .prefixedNo) + var index = true + + @Flag(inversion: .prefixedEnableDisable) + var requiredElement: Bool + + mutating func run() throws { + print(index, requiredElement) + } +} +``` + +When declaring a flag with an inversion, set the default by specifying `true` or `false` as the property's initial value. If you want to require that the user specify one of the two inversions, leave off the default value. + +In the `Example` command defined above, a flag is required for the `requiredElement` property. The specified prefixes are prepended to the long names for the flags: + +``` +% example --enable-required-element +true true +% example --no-index --disable-required-element +false false +% example --index +Error: Missing one of: '--enable-required-element', '--disable-required-element' +``` + +To create a flag with custom names for a Boolean value, to provide an exclusive choice between more than two names, or for collecting multiple values from a set of defined choices, define an enumeration that conforms to the `EnumerableFlag` protocol. + +```swift +enum CacheMethod: String, EnumerableFlag { + case inMemoryCache + case persistentCache +} + +enum Color: String, EnumerableFlag { + case pink, purple, silver +} + +struct Example: ParsableCommand { + @Flag var cacheMethod: CacheMethod + @Flag var colors: [Color] = [] + + mutating func run() throws { + print(cacheMethod) + print(colors) + } +} +``` + +The flag names in this case are drawn from the raw values — for information about customizing the names and help text, see the [`EnumerableFlag` documentation](../Sources/ArgumentParser/Parsable%20Types/EnumerableFlag.swift). + +``` +% example --in-memory-cache --pink --silver +.inMemoryCache +[.pink, .silver] +% example +Error: Missing one of: '--in-memory-cache', '--persistent-cache' +``` + +Finally, when a flag is of type `Int`, the value is parsed as a count of the number of times that the flag is specified. + +```swift +struct Example: ParsableCommand { + @Flag(name: .shortAndLong) + var verbose: Int + + mutating func run() throws { + print("Verbosity level: \(verbose)") + } +} +``` + +In this example, `verbose` defaults to zero, and counts the number of times that `-v` or `--verbose` is given. + +``` +% example --verbose +Verbosity level: 1 +% example -vvvv +Verbosity level: 4 +``` + + +## Specifying default values + +You can specify default values for almost all supported argument, option, and flag types using normal property initialization syntax: + +```swift +enum CustomFlag: String, EnumerableFlag { + case foo, bar, baz +} + +struct Example: ParsableCommand { + @Flag + var booleanFlag = false + + @Flag + var arrayFlag: [CustomFlag] = [.foo, .baz] + + @Option + var singleOption = 0 + + @Option + var arrayOption = ["bar", "qux"] + + @Argument + var singleArgument = "quux" + + @Argument + var arrayArgument = ["quux", "quuz"] +} +``` + +This includes all of the variants of the argument types above (including `@Option(transform: ...)`, etc.), with a few notable exceptions: +- `Optional`-typed values (which default to `nil` and for which a default would not make sense, as the value could never be `nil`) +- `Int` flags (which are used for counting the number of times a flag is specified and therefore default to `0`) + +If a default is not specified, the user must provide a value for that argument/option/flag or will receive an error that the value is missing. + +You must also always specify a default of `false` for a non-optional `Bool` flag, as in the example above. This makes the behavior consistent with both normal Swift properties (which either must be explicitly initialized or optional to initialize a `struct`/`class` containing them) and the other property types. + + +## Specifying a parsing strategy + +When parsing a list of command-line inputs, `ArgumentParser` distinguishes between dash-prefixed keys and un-prefixed values. When looking for the value for a key, only an un-prefixed value will be selected by default. + +For example, this command defines a `--verbose` flag, a `--name` option, and an optional `file` argument: + +```swift +struct Example: ParsableCommand { + @Flag var verbose = false + @Option var name: String + @Argument var file: String? + + mutating func run() throws { + print("Verbose: \(verbose), name: \(name), file: \(file ?? "none")") + } +} +``` + +When calling this command, the value for `--name` must be given immediately after the key. If the `--verbose` flag is placed in between, parsing fails with an error: + +``` +% example --verbose --name Tomás +Verbose: true, name: Tomás, file: none +% example --name --verbose Tomás +Error: Missing value for '--name ' +Usage: example [--verbose] --name [] + See 'example --help' for more information. +``` + +Parsing options as arrays is similar — only adjacent key-value pairs are recognized by default. + +### Alternative single-value parsing strategies + +You can change this behavior by providing a different parsing strategy in the `@Option` initializer. **Be careful when selecting any of the alternative parsing strategies** — they may lead your command-line tool to have unexpected behavior for users! + +The `.unconditional` parsing strategy uses the immediate next input for the value of the option, even if it starts with a dash. If `name` were instead defined as `@Option(parsing: .unconditional) var name: String`, the second attempt would result in `"--verbose"` being read as the value of `name`: + +``` +% example --name --verbose Tomás +Verbose: false, name: --verbose, file: Tomás +``` + +The `.scanningForValue` strategy, on the other hand, looks ahead in the list of command-line inputs and uses the first un-prefixed value as the input, even if that requires skipping over other flags or options. If `name` were defined as `@Option(parsing: .scanningForValue) var name: String`, the parser would look ahead to find `Tomás`, then pick up parsing where it left off to get the `--verbose` flag: + +``` +% example --name --verbose Tomás +Verbose: true, name: Tomás, file: none +``` + +### Alternative array parsing strategies + +The default strategy for parsing options as arrays is to read each value from a key-value pair. For example, this command expects zero or more input file names: + +```swift +struct Example: ParsableCommand { + @Option var file: [String] = [] + @Flag var verbose = false + + mutating func run() throws { + print("Verbose: \(verbose), files: \(file)") + } +} +``` + +As with single values, each time the user provides the `--file` key, they must also provide a value: + +``` +% example --verbose --file file1.swift --file file2.swift +Verbose: true, files: ["file1.swift", "file2.swift"] +% example --file --verbose file1.swift --file file2.swift +Error: Missing value for '--file ' +Usage: example [--file ...] [--verbose] + See 'example --help' for more information. +``` + +The `.unconditionalSingleValue` parsing strategy uses whatever input follows the key as its value, even if that input is dash-prefixed. If `file` were defined as `@Option(parsing: .unconditionalSingleValue) var file: [String]`, then the resulting array could include strings that look like options: + +``` +% example --file file1.swift --file --verbose +Verbose: false, files: ["file1.swift", "--verbose"] +``` + +The `.upToNextOption` parsing strategy uses the inputs that follow the option key until reaching a dash-prefixed input. If `file` were defined as `@Option(parsing: .upToNextOption) var file: [String]`, then the user could specify multiple files without repeating `--file`: + +``` +% example --file file1.swift file2.swift +Verbose: false, files: ["file1.swift", "file2.swift"] +% example --file file1.swift file2.swift --verbose +Verbose: true, files: ["file1.swift", "file2.swift"] +``` + +Finally, the `.remaining` parsing strategy uses all the inputs that follow the option key, regardless of their prefix. If `file` were defined as `@Option(parsing: .remaining) var file: [String]`, then the user would need to specify `--verbose` before the `--file` key for it to be recognized as a flag: + +``` +% example --verbose --file file1.swift file2.swift +Verbose: true, files: ["file1.swift", "file2.swift"] +% example --file file1.swift file2.swift --verbose +Verbose: false, files: ["file1.swift", "file2.swift", "--verbose"] +``` + +### Alternative positional argument parsing strategies + +The default strategy for parsing arrays of positional arguments is to ignore all dash-prefixed command-line inputs. For example, this command accepts a `--verbose` flag and a list of file names as positional arguments: + +```swift +struct Example: ParsableCommand { + @Flag var verbose = false + @Argument var files: [String] = [] + + mutating func run() throws { + print("Verbose: \(verbose), files: \(files)") + } +} +``` + +The `files` argument array uses the default `.remaining` parsing strategy, so it only picks up values that don't have a prefix: + +``` +% example --verbose file1.swift file2.swift +Verbose: true, files: ["file1.swift", "file2.swift"] +% example --verbose file1.swift file2.swift --other +Error: Unexpected argument '--other' +Usage: example [--verbose] [ ...] + See 'example --help' for more information. +``` + +Any input after the `--` terminator is automatically treated as positional input, so users can provide dash-prefixed values that way even with the default configuration: + +``` +% example --verbose -- file1.swift file2.swift --other +Verbose: true, files: ["file1.swift", "file2.swift", "--other"] +``` + +The `.unconditionalRemaining` parsing strategy uses whatever input is left after parsing known options and flags, even if that input is dash-prefixed, including the terminator itself. If `files` were defined as `@Argument(parsing: .unconditionalRemaining) var files: [String]`, then the resulting array would also include strings that look like options: + +``` +% example --verbose file1.swift file2.swift --other +Verbose: true, files: ["file1.swift", "file2.swift", "--other"] +% example -- --verbose file1.swift file2.swift --other +Verbose: false, files: ["--", "--verbose", "file1.swift", "file2.swift", "--other"] +``` diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/InstallingCompletionScripts.md b/Sources/ArgumentParser/Documentation.docc/Articles/InstallingCompletionScripts.md index 6599e51fc..0057a1591 100644 --- a/Sources/ArgumentParser/Documentation.docc/Articles/InstallingCompletionScripts.md +++ b/Sources/ArgumentParser/Documentation.docc/Articles/InstallingCompletionScripts.md @@ -1,6 +1,6 @@ # Generating and Installing Completion Scripts -Summary +Install shell completion scripts generated by your command-line tool. ## Overview diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/ManualParsing.md b/Sources/ArgumentParser/Documentation.docc/Articles/ManualParsing.md new file mode 100644 index 000000000..da70b8895 --- /dev/null +++ b/Sources/ArgumentParser/Documentation.docc/Articles/ManualParsing.md @@ -0,0 +1,112 @@ +# Manual Parsing and Testing + +Provide your own array of command-line inputs and work with parsed results by calling alternatives to `main()`. + +For most programs, calling the static `main()` method on the root command type is all that's necessary. That single call parses the command-line arguments to find the correct command from your tree of nested subcommands, instantiates and validates the result, and executes the chosen command. For more control, however, you can perform each of those steps manually. + +## Parsing Arguments + +For simple Swift scripts, and for those who prefer a straight-down-the-left-edge-of-the-screen scripting style, you can define a single `ParsableArguments` type to parse explicitly from the command-line arguments. + +Let's implement the `Select` command discussed in [Validation and Errors](05%20Validation%20and%20Errors.md), but using a scripty style instead of the typical command. First, we define the options as a `ParsableArguments` type: + +```swift +struct SelectOptions: ParsableArguments { + @Option var count: Int = 1 + @Argument var elements: [String] = [] +} +``` + +The next step is to parse our options from the command-line input: + +```swift +let options = SelectOptions.parseOrExit() +``` + +The static `parseOrExit()` method either returns a fully initialized instance of the type, or exits with an error message and code. Alternatively, you can call the throwing `parse()` method if you'd like to catch any errors that arise during parsing. + +We can perform validation on the inputs and exit the script if necessary: + +```swift +guard let options.elements.count >= options.count else { + let error = ValidationError("Please specify a 'count' less than the number of elements.") + SelectOptions.exit(withError: error) +} +``` + +As you would expect, the `exit(withError:)` method includes usage information when you pass it a `ValidationError`. + +Finally, we print out the requested number of elements: + +```swift +let chosen = options.elements + .shuffled() + .prefix(options.count) +print(chosen.joined(separator: "\n")) +``` + +## Parsing Commands + +Manually parsing commands is a little more complex than parsing a simple `ParsableArguments` type. The result of parsing from a tree of subcommands may be of a different type than the root of the tree, so the static `parseAsRoot()` method returns a type-erased `ParsableCommand`. + +Let's see how this works by using the `Math` command and subcommands defined in [Commands and Subcommands](03%20Commands%20and%20Subcommands.md). This time, instead of calling `Math.main()`, we'll call `Math.parseAsRoot()`, and switch over the result: + +```swift +do { + var command = try Math.parseAsRoot() + + switch command { + case var command as Math.Add: + print("You chose to add \(command.options.values.count) values.") + command.run() + default: + print("You chose to do something else.") + try command.run() + } +} catch { + Math.exit(withError: error) +} +``` +Our new logic intercepts the command between validation and running, and outputs an additional message: + +``` +% math 10 15 7 +You chose to add 3 values. +32 +% math multiply 10 15 7 +You chose to do something else. +1050 +``` + +## Providing Command-Line Input + +All of the parsing methods — `parse()`, `parseOrExit()`, and `parseAsRoot()` — can optionally take an array of command-line inputs as an argument. You can use this capability to test your commands, to perform pre-parse filtering of the command-line arguments, or to manually execute commands from within the same or another target. + +Let's update our `select` script above to strip out any words that contain all capital letters before parsing the inputs. + +```swift +let noShoutingArguments = CommandLine.arguments.dropFirst().filter { phrase in + phrase.uppercased() != phrase +} +let options = SelectOptions.parseOrExit(noShoutingArguments) +``` + +Now when we call our command, the parser won't even see the capitalized words — `HEY` won't ever be printed: + +``` +% select hi howdy HEY --count 2 +hi +howdy +% select hi howdy HEY --count 2 +howdy +hi +``` + + + + + + + + + From cf0c74ada8a7ba7c728b5db13f66447a4a6eb8ef Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Mon, 19 Jul 2021 13:28:01 -0500 Subject: [PATCH 09/18] Remove placeholder resources --- .../Resources/Tutorial Code/code.txt | 288 ------------------ .../Resources/Tutorial Images/Image.png | Bin 97845 -> 0 bytes 2 files changed, 288 deletions(-) delete mode 100644 Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Code/code.txt delete mode 100644 Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Images/Image.png diff --git a/Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Code/code.txt b/Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Code/code.txt deleted file mode 100644 index 175f62c82..000000000 --- a/Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Code/code.txt +++ /dev/null @@ -1,288 +0,0 @@ -# Getting Started with ArgumentParser - -Learn to set up and customize a simple command-line tool. - -## Overview - -This guide walks through building an example command. You'll learn about the different tools that `ArgumentParser` provides for defining a command's options, customizing the interface, and providing help text for your user. - -## Adding `ArgumentParser` as a Dependency - -Let's write a tool called `count` that reads an input file, counts the words, and writes the result to an output file. - -First, we need to add `swift-argument-parser` as a dependency to our package, -and then include `"ArgumentParser"` as a dependency for our executable target. -Our "Package.swift" file ends up looking like this: - -```swift -// swift-tools-version:5.2 -import PackageDescription - -let package = Package( - name: "random", - dependencies: [ - .package(url: "https://github.com/apple/swift-argument-parser.git", from: "0.4.0"), - ], - targets: [ - .target( - name: "count", - dependencies: [.product(name: "ArgumentParser", package: "swift-argument-parser")]), - ] -) -``` - -> **Note:** To read more about creating and configuring packages using Swift Package Manager, see [Using the Package Manager](https://swift.org/getting-started/#using-the-package-manager). - -## Building Our First Command - -Once we've built the `count` tool, we'll be able to run it like this: - -``` -% count readme.md readme.counts -Counting words in 'readme.md' and writing the result into 'readme.counts'. -``` - -We'll define the initial version of the command as a type that conforms to the `ParsableCommand` protocol: - -```swift -import ArgumentParser - -struct Count: ParsableCommand { - @Argument var inputFile: String - @Argument var outputFile: String - - mutating func run() throws { - print(""" - Counting words in '\(inputFile)' \ - and writing the result into '\(outputFile)'. - """) - - // Read 'inputFile', count the words, and save to 'outputFile'. - } -} - -Count.main() -``` - -In the code above, the `inputFile` and `outputFile` properties use the `@Argument` property wrapper. `ArgumentParser` uses this wrapper to denote a positional command-line input — because `inputFile` is specified first in the `Count` type, it's the first value read from the command line, and `outputFile` is read second. - -We've implemented the command's logic in its `run()` method. Here, we're printing out a message confirming the names of the files the user gave. (You can find a full implementation of the completed command at the end of this guide.) - -Finally, you tell the parser to execute the `Count` command by calling its static `main()` method. This method parses the command-line arguments, verifies that they match up with what we've defined in `Count`, and either calls the `run()` method or exits with a helpful message. - - -## Working with Named Options - -Our `count` tool may have a usability problem — it's not immediately clear whether a user should provide the input file first, or the output file. Instead of using positional arguments for our two inputs, let's specify that they should be labeled options: - -``` -% count --input-file readme.md --output-file readme.counts -Counting words in 'readme.md' and writing the result into 'readme.counts'. -``` - -We do this by using the `@Option` property wrapper instead of `@Argument`: - -```swift -struct Count: ParsableCommand { - @Option var inputFile: String - @Option var outputFile: String - - mutating func run() throws { - print(""" - Counting words in '\(inputFile)' \ - and writing the result into '\(outputFile)'. - """) - - // Read 'inputFile', count the words, and save to 'outputFile'. - } -} -``` - -The `@Option` property wrapper denotes a command-line input that looks like `--name `, deriving its name from the name of your property. - -This interface has a trade-off for the users of our `count` tool: With `@Argument`, users don't need to type as much, but they have to remember whether to provide the input file or the output file first. Using `@Option` makes the user type a little more, but the distinction between values is explicit. Options are order-independent, as well, so the user can name the input and output files in either order: - -``` -% count --output-file readme.counts --input-file readme.md -Counting words in 'readme.md' and writing the result into 'readme.counts'. -``` - -## Adding a Flag - -Next, we want to add a `--verbose` flag to our tool, and only print the message if the user specifies that option: - -``` -% count --input-file readme.md --output-file readme.counts -(no output) -% count --verbose --input-file readme.md --output-file readme.counts -Counting words in 'readme.md' and writing the result into 'readme.counts'. -``` - -Let's change our `Count` type to look like this: - -```swift -struct Count: ParsableCommand { - @Option var inputFile: String - @Option var outputFile: String - @Flag var verbose = false - - mutating func run() throws { - if verbose { - print(""" - Counting words in '\(inputFile)' \ - and writing the result into '\(outputFile)'. - """) - } - - // Read 'inputFile', count the words, and save to 'outputFile'. - } -} -``` - -The `@Flag` property wrapper denotes a command-line input that looks like `--name`, deriving its name from the name of your property. Flags are most frequently used for Boolean values, like the `verbose` property here. - - -## Using Custom Names - -We can customize the names of our options and add an alternative to the `verbose` flag so that users can specify `-v` instead of `--verbose`. The new interface will look like this: - -``` -% count -v -i readme.md -o readme.counts -Counting words in 'readme.md' and writing the result into 'readme.counts'. -% count --input readme.md --output readme.counts -v -Counting words in 'readme.md' and writing the result into 'readme.counts'. -% count -o readme.counts -i readme.md --verbose -Counting words in 'readme.md' and writing the result into 'readme.counts'. -``` - -Customize the input names by passing `name` parameters to the `@Option` and `@Flag` initializers: - -```swift -struct Count: ParsableCommand { - @Option(name: [.short, .customLong("input")]) - var inputFile: String - - @Option(name: [.short, .customLong("output")]) - var outputFile: String - - @Flag(name: .shortAndLong) - var verbose = false - - mutating func run() throws { ... } -} -``` - -The default name specification is `.long`, which uses a property's name with a two-dash prefix. `.short` uses only the first letter of a property's name with a single-dash prefix, and allows combining groups of short options. You can specify custom short and long names with the `.customShort(_:)` and `.customLong(_:)` methods, respectively, or use the combined `.shortAndLong` property to specify the common case of both the short and long derived names. - -## Providing Help - -`ArgumentParser` automatically generates help for any command when a user provides the `-h` or `--help` flags: - -``` -% count --help -USAGE: count --input --output [--verbose] - -OPTIONS: - -i, --input - -o, --output - -v, --verbose - -h, --help Show help information. -``` - -This is a great start — you can see that all the custom names are visible, and the help shows that values are expected for the `--input` and `--output` options. However, our custom options and flag don't have any descriptive text. Let's add that now by passing string literals as the `help` parameter: - -```swift -struct Count: ParsableCommand { - @Option(name: [.short, .customLong("input")], help: "A file to read.") - var inputFile: String - - @Option(name: [.short, .customLong("output")], help: "A file to save word counts to.") - var outputFile: String - - @Flag(name: .shortAndLong, help: "Print status updates while counting.") - var verbose = false - - mutating func run() throws { ... } -} -``` - -The help screen now includes descriptions for each parameter: - -``` -% count -h -USAGE: count --input --output [--verbose] - -OPTIONS: - -i, --input A file to read. - -o, --output A file to save word counts to. - -v, --verbose Print status updates while counting. - -h, --help Show help information. - -``` - -## The Complete Utility - -As promised, here's the complete `count` command, for your experimentation: - -```swift -import ArgumentParser -import Foundation - -struct Count: ParsableCommand { - static let configuration = CommandConfiguration(abstract: "Word counter.") - - @Option(name: [.short, .customLong("input")], help: "A file to read.") - var inputFile: String - - @Option(name: [.short, .customLong("output")], help: "A file to save word counts to.") - var outputFile: String - - @Flag(name: .shortAndLong, help: "Print status updates while counting.") - var verbose = false - - mutating func run() throws { - if verbose { - print(""" - Counting words in '\(inputFile)' \ - and writing the result into '\(outputFile)'. - """) - } - - guard let input = try? String(contentsOfFile: inputFile) else { - throw RuntimeError("Couldn't read from '\(inputFile)'!") - } - - let words = input.components(separatedBy: .whitespacesAndNewlines) - .map { word in - word.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) - .lowercased() - } - .compactMap { word in word.isEmpty ? nil : word } - - let counts = Dictionary(grouping: words, by: { $0 }) - .mapValues { $0.count } - .sorted(by: { $0.value > $1.value }) - - if verbose { - print("Found \(counts.count) words.") - } - - let output = counts.map { word, count in "\(word): \(count)" } - .joined(separator: "\n") - - guard let _ = try? output.write(toFile: outputFile, atomically: true, encoding: .utf8) else { - throw RuntimeError("Couldn't write to '\(outputFile)'!") - } - } -} - -struct RuntimeError: Error, CustomStringConvertible { - var description: String - - init(_ description: String) { - self.description = description - } -} - -Count.main() -``` diff --git a/Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Images/Image.png b/Sources/ArgumentParser/Documentation.docc/Resources/Tutorial Images/Image.png deleted file mode 100644 index 0aee5dc76f6fcb4a7c1a2402dce7a5fc38b6d4cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 97845 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%0Dx+@wY+Dih#)d*G)J#aJgWI1NL;`tGSZ0Q| zY{M#f?*PQ_T#&F?LSX09|Z%R%EmrFHJ*39;;@V)^i-hAP~lHvKpD^o*k7<&Ux$x}4Pr$; zb1!}Pv9*cblqoMOU){q?*fKEw5DFm3GbD@H&q9`Ri5$$;g@E-T>wO{{8}T+`mu|( z#(suTO247r?)smZ19tAtHmt}0%+z}oKK;QCXT;LH3sjd$Ujj-H^IP4MEJH6*fk4-s z;^XB**G*sRx|L!Xt9^mMMsF#^Xb$ug%_twiC%0Ak1ufsfLS_&A$L03>GdBGLhUVNY zZNLM$pM@M?oPe0$a3D~~*C1*}QZ3N7b1#`3H!Q-eK`F@puJWe33GR7&u6TXU4Zf=0 za~SnxsbCqX#WacB@gJjZ7GXTvF2a=l)BoZbZ2iy#975r#F%k&iNzBMF4TmL&&_lWd znNN62vF73O7X+L@$=nF$ae;XG@g4$`nNq#f+kfuI+@E*ojRhyS{`>FYzkc;k6#U<{ z#v2QHjZP^mgnuxNI*-IyT3CEYX`?UynDQPxviHReC?_~8D+@p3-K^+7Wi1o%>oZ|S zSPo?imPasbY`pRyv}>SYSnFklfL*gu+hXjqG}|vlgJFdjfj}VHQ9|w^>XXlLD>w-b zk^H!Lx?0P>rl?KWfAj^48!jvM=C$6B3%}%vcENORbaM1Fnw*<69&*W+kqmgN=)yfq zHSutF2i|Gc3m6St9-efRrTB;4#JK7xIz9fWSD|lYX;zIB;nUfhO$x+*W$L@K(=;TW zYrwB?+YL&oO9OD_t|j)-!k>fO^+QnK$X@=;u-~W<_g6Elx3tiobdl*djHK1rpr+!4 z%B;_ye6}(ncTZgcab`#d#oioyB$092>~7-2hebP|qy<4f)18YuK%ymdm$eGlt}Hdz z0E$SJxZ23gX0pY8<~Bc~#K7oa+>*@RNxdSqgFzF=N3WP?c1mg{^cLvla!vC{q~Xl0 ztZ%^^gR1OZii2b_nT<|fwzGD?TVIZV4Ltn$<;9_rhl!_OY+>h1QM=nH?$LFXH$(%% zb9D2@(8i>(R6t7Vz45{3=yH=T8sp)-Me6cxQL6Kd5Z4?ZRna&yGD2qDFYO5ydVP7m zr(s`C?%#$S`b>aQyB5Badj>6&E4|}ik4y)TNyQjOLF^;ppSEr1*+(6qVrZ2kJ!NQ~ z8}0o(IWMmYQ5K=PVF=(EA2!p|8(K``SRm7&oRM5rSb8n8@S7wtcJq<|c2yCD+UwfB zR@3E8^IG~;BQmU_O14H8D&KM5w}x5y8EVR4GPSPxNc5;TQ$`|kpDj+-9)o($qzRZ; zOleiJR9)TE2}-0~fD|4^ap~{^(Rs&~x^b^i`97pvc`R93s+qSAm1))=7&}iYx{fSU zZdKQ1W~aMNAu~3ssT_+FH|)XSo|atQ&S;XkuI}VpgOV<^Tzl0p*Nx_-m+y`xs$zk`+g6;Wn~&9hPY=v$O0vsboAxxG zC(!OqX-Jk`HFmIEHd5D!fuD$)TT>W zI&1lj!KN_m?nUo+x?Tjg^0M> zKEfbqtXWZ+UH(mbzu#>!;|9{1K1S^l{$5#XUDmYkOPMZO6Pf z!z($nY96lTBOO#fR&^W2G!B*V?PDmd4SdiU*yA!Nrx0OE$f@^%+_ttJ3~Z{5yf;$T z#3^12LCX+f(Mh}|T7QMC9CmFXE_Z&W??JT4{9H5cvanO!EEFx?B2`w-3<>4%er_c0 zXyDFG3o(=L3{BdPXt1V2StqW@rF9Mp50?dXDlkN<&4M%Tzz^A8xhI?*_7Tz{b2W!s(?KEC4JEe z+WD1${DA7Nb{0&P4U289d}6dQJ*9NUtTrfodX8K=+U+$@cEzGr!t7Ld75cnVg4>CZ zNLCAo-hl2(=dE|JSiB%(SSCt|RILi>)*EQ3Ssf~V{EqG#P&Ue13-GzE-q6Exu6xx z5D^6*EOlAasIOYMXsp~_6;j+MXnJ`?vPDlf>0N}hvfbJdl zpXkwwkG2$;ORJ(K5LwcfLf58ITl?XL-VyzDK2{jpeeojlR>jFEtV8xJux053)~ojk_zipb&i^2ZPTF5cWq zKiv?qz7PeuG`HFkl+Oq&wAX62;KaU=s-Dm|W@slXe)CsU3DTBvF(Fbh7NLpvL3ZXy zOai+^b)m~Os{Pry(T1oLG0Ww4bc0*J8S`Y=KFMNAh7>Fn#me{gw)Jv4(w~CP7*ab^R8%nn|p~#`U zpnXe5aZo**A8my^9n9&v@w5w!`xvQ1I++18_Fx5tsZB<6X78*XiLdmPLoR!LY>#JZ zO@!UX&pDl_pHot)&(RlFiA|r)SM6b`2YU?;pI=W+;FcdBsIMFqdid3j(^3&RQ!JJU zl(l@!R2g6Mn(+#vQDAbh*Gm^{gD8EMr`L&WYHh(^rlrZw^Pab|Gy}Wxy(;!r_?Z*` zl7x>$p!wDtua8x}u6E}QJd!6NAD$mv?)7c){roQ!yxH^EL)KP@`W+KzDUpOX!s`MT zT}YLhC<=#rfZnw#x}ux8QC6Y}1I2MC^NM`f0*Z42z^Ll`KR%8v_~_mw(YKDQhY8iBQ!x}*=$ za3kgu2F0^&cFw2kTs&nOy$U7%VIZ}=(tS|WlZEdm*Na8FY8ko+M>G=57^IUr9 zc$Q1GF1!4URqd4_^j>+}ed*U&RG%5|($PGWA-Xzf9W^wus6SXeRx_$pIqUsmiE74} zCwBgV+p(PagZu5VxTjy|OQ>~xmhnqlAmzC;uy*ZR6$#@de_ zP1^CW9-U;uzNVt8kJI~_aJ_^6Do)vN8y8-hC}P)mo4h%pbHs$LkUa87oiwJ0wA2t( zAo)Z!lPqDmcG!au$p{3Hgx&3(jvCSgNug=LkJa`K*Fz2K!tq7Kg<7uY!H|;X9N{#U zmLx+VZ$O^%ZM@zYTEUNym6J+u#MImCM z!0v~4Y(nqgQCr-};g&sox}!eQdj77i@2ka+rtvB>R4fT-jk2t<(*szS^eoO?G;Y{7 z(9nX$QkdrWk6vk6S<{7&H79Ver=bT+#}J+kGJbjBU#yYv{BD-WnFU4L`=#)J8awT5 z%UTE3lzhpJYiitid(V)Np!{+Z{aGmxeJ546lQI}(m(Cr{i;(E${%x!39Ct1iksEdX z>1=m`!(Y?P5u5y;Oz=lrGIxJiuJ|g=CZ`jaM3j zt#s2E2liDQ5JDJs=^U+_qvLWNTy}9<>6o;1G0KvL1== zSuCBIvP<=7_b)s6OpMZ!ru7ZxCV;C278ubVzb2MAZYf4bCq%4Oq97yYWvrrU?&`Z-*Q!S8k}M6a^G9{>x&}gA%as-w zpa~yzdF;|&u%kb(J^bdJnNml^MmEixM8^l|mUPHGewfy&Fyl0)HCk;ZlRBS8a|JCI zq4`x1mt>WmwP8&6W(%132>&aqGwH)FLd}6xD5FgJt1>`QkHWvuqJ2%E*rRQp^Z`%P z(I}upfUWI)!GUBC6GOMPH+HOj&?U7@WXKVtPL}E%tEV57#7cB;_!rF{i$9*yS(Tkq zA;0?`fu?@uCw#*a7QCl4=NFb|y-B2GLuXgh_kT~7CVE_`t~s65=Ko~(o3g3r9bRSW zob%l7xkpG2H7V%j`&{`|*SJr*B=H|-z9#_>AAg6>v-eC>ve)Y_>(CdZq^4FbOJY|H zo_H2^#2J>gBTIRy_3Nu=b@VmDMX~&5*oj)i;(hhFD%OK$r^Qxn_8RvaGme;14$WND zHcipt_rFWAED-PA;|>3F{=NncX-@y*y|q~^`0JAz$AzxOO!L&3Qfao>m+ol3^_!tc z5{cAIX>*f0>#i3qL@-zGNB(~?ptkIQ88XJlV$7nQwGo*VBWrLDB*VPSZ5TJ(I&!^v zrZ!;D`KRmIps&K&jy=apnYamdq;hb9SIN$9hY9xAyZ;edYF7?lG36EeK`sgNOg8=i z{;F{a`1{R#(b-hlVXR!F#DA5_(%QkE!}g;;-mBodIEKQBq-RBj|CKSfw9Mbbe-*a> zk#~QaCy SK;O3c+`eIQJ^z~hv;PMW+DW7U From 82c7b61d7703ab714fbf8835bb75dc0f5421d069 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Tue, 20 Jul 2021 12:14:22 -0500 Subject: [PATCH 10/18] Update package.swift to avoid warnings --- Package.swift | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Package.swift b/Package.swift index eadd748b0..ba0db5669 100644 --- a/Package.swift +++ b/Package.swift @@ -23,35 +23,39 @@ var package = Package( targets: [ .target( name: "ArgumentParser", - dependencies: []), + dependencies: [], + exclude: ["CMakeLists.txt"]), .target( name: "ArgumentParserTestHelpers", - dependencies: ["ArgumentParser"]), + dependencies: ["ArgumentParser"], + exclude: ["CMakeLists.txt"]), - .target( + .executableTarget( name: "roll", dependencies: ["ArgumentParser"], path: "Examples/roll"), - .target( + .executableTarget( name: "math", dependencies: ["ArgumentParser"], path: "Examples/math"), - .target( + .executableTarget( name: "repeat", dependencies: ["ArgumentParser"], path: "Examples/repeat"), - .target( + .executableTarget( name: "changelog-authors", dependencies: ["ArgumentParser"], path: "Tools/changelog-authors"), .testTarget( name: "ArgumentParserEndToEndTests", - dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"]), + dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"], + exclude: ["CMakeLists.txt"]), .testTarget( name: "ArgumentParserUnitTests", - dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"]), + dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"], + exclude: ["CMakeLists.txt"]), .testTarget( name: "ArgumentParserExampleTests", dependencies: ["ArgumentParserTestHelpers"]), @@ -63,5 +67,6 @@ var package = Package( package.targets.append( .testTarget( name: "ArgumentParserPackageManagerTests", - dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"])) + dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"], + exclude: ["CMakeLists.txt"])) #endif From 2a019e8102216b3b29e94c11cb254f3c6138c227 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Tue, 20 Jul 2021 12:15:18 -0500 Subject: [PATCH 11/18] Doc revisions for Argument and Option --- .../Documentation.docc/ArgumentParser.md | 10 +++--- .../Parsable Properties/Argument.swift | 33 ++++++++++++++----- .../Parsable Properties/Option.swift | 29 +++++++++++++--- 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md b/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md index 32d935ce7..04bb62300 100644 --- a/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md +++ b/Sources/ArgumentParser/Documentation.docc/ArgumentParser.md @@ -4,8 +4,8 @@ Straightforward, type-safe argument parsing for Swift. ## Overview -`ArgumentParser` uses the names and types of the properties you declare -to parse and validate command-line input. +By using `ArgumentParser`, you can create a command-line interface tool +by declaring simple Swift types. Begin by declaring a type that defines the information that you need to collect from the command line. Decorate each stored property with one of `ArgumentParser`'s property wrappers, @@ -17,12 +17,12 @@ import ArgumentParser @main struct Repeat: ParsableCommand { - @Option(help: "The number of times to repeat 'phrase'.") - var count: Int? - @Argument(help: "The phrase to repeat.") var phrase: String + @Option(help: "The number of times to repeat 'phrase'.") + var count: Int? + mutating func run() throws { let repeatCount = count ?? .max for _ in 0..: Decodable, ParsedWrapper diff --git a/Sources/ArgumentParser/Parsable Properties/Option.swift b/Sources/ArgumentParser/Parsable Properties/Option.swift index c58813b43..3d19fceee 100644 --- a/Sources/ArgumentParser/Parsable Properties/Option.swift +++ b/Sources/ArgumentParser/Parsable Properties/Option.swift @@ -9,23 +9,42 @@ // //===----------------------------------------------------------------------===// -/// A wrapper that represents a command-line option. +/// A property wrapper that represents a command-line option. /// -/// An option is a value that can be specified as a named value on the command -/// line. An option can have a default values specified as part of its +/// Use the `@Option` wrapper to define a property of your custom command as a +/// command-line option. An *option* is a named value passed to a command-line +/// tool, like `--configuration debug`. Options can be specified in any order. +/// `@Option` properties with `Optional` type or a default value are optional +/// for the user of your command-line tool. +/// +/// An option can have a default values specified as part of its /// declaration; options with optional `Value` types implicitly have `nil` as /// their default value. /// -/// struct Options: ParsableArguments { -/// @Option(default: "Hello") var greeting: String +/// @main +/// struct Greet: ParsableCommand { +/// @Option var greeting = "Hello" /// @Option var name: String /// @Option var age: Int? +/// +/// mutating func run() { +/// print("\(greeting) \(name)!") +/// if let age = age { +/// print("Congrats on making it to the ripe old age of \(age)!") +/// } +/// } /// } /// /// `greeting` has a default value of `"Hello"`, which can be overridden by /// providing a different string as an argument. `age` defaults to `nil`, while /// `name` is a required argument because it is non-`nil` and has no default /// value. +/// +/// $ greet --name Alicia +/// Hello Alicia! +/// $ greet --age 28 --name Seungchin --greeting Hi +/// Hi Seungchin! +/// Congrats on making it to the ripe old age of 28! @propertyWrapper public struct Option: Decodable, ParsedWrapper { internal var _parsedValue: Parsed From 6a2a4d65d9a9f40082f3653fff75bb6bfa441b7d Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 23 Jul 2021 18:10:56 -0500 Subject: [PATCH 12/18] Doc revisions for Flag --- .../Parsable Properties/Flag.swift | 49 +++++++++++++++---- .../NameSpecification.swift | 1 + 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/Sources/ArgumentParser/Parsable Properties/Flag.swift b/Sources/ArgumentParser/Parsable Properties/Flag.swift index ae9417649..f14de6ef0 100644 --- a/Sources/ArgumentParser/Parsable Properties/Flag.swift +++ b/Sources/ArgumentParser/Parsable Properties/Flag.swift @@ -9,33 +9,62 @@ // //===----------------------------------------------------------------------===// -/// A wrapper that represents a command-line flag. +/// A property wrapper that represents a command-line flag. /// -/// A flag is a defaulted Boolean or integer value that can be changed by -/// specifying the flag on the command line. For example: +/// Use the `@Flag` wrapper to define a property of your custom type as a +/// command-line flag. A *flag* is a dash-prefixed label that can be provided on +/// the command line, such as `-d` and `--debug`. /// -/// struct Options: ParsableArguments { -/// @Flag var verbose: Bool +/// For example, the following program +/// +/// @main +/// struct Time: ParsableCommand { +/// @Flag var includeSeconds = false +/// +/// mutating func run() { +/// if includeSeconds { +/// print(Date.now.formatted(.dateTime.hour().minute().second())) +/// } else { +/// print(Date.now.formatted(.dateTime.hour().minute())) +/// } +/// } /// } /// -/// `verbose` has a default value of `false`, but becomes `true` if `--verbose` -/// is provided on the command line. +/// `includeSeconds` has a default value of `false`, but becomes `true` if +/// `--include-seconds` is provided on the command line. +/// +/// $ time +/// 11:09 AM +/// $ time --include-seconds +/// 11:09:15 AM /// /// A flag can have a value that is a `Bool`, an `Int`, or any `EnumerableFlag` /// type. When using an `EnumerableFlag` type as a flag, the individual cases /// form the flags that are used on the command line. /// -/// struct Options { +/// @main +/// struct Math: ParsableCommand { /// enum Operation: EnumerableFlag { /// case add /// case multiply /// } /// /// @Flag var operation: Operation +/// +/// mutating func run() { +/// print("Time to \(operation)!") +/// } /// } /// -/// // usage: command --add -/// // or: command --multiply +/// Instead of using the name of the `operation` property as the flag in this +/// case, the two cases of the `Operation` enumeration become valid flags. +/// The `operation` property is neither optional nor given a default value, so +/// one of the flags is required. +/// +/// $ math --add +/// Time to add! +/// $ math +/// Error: Missing one of: '--add', '--multiply' @propertyWrapper public struct Flag: Decodable, ParsedWrapper { internal var _parsedValue: Parsed diff --git a/Sources/ArgumentParser/Parsable Properties/NameSpecification.swift b/Sources/ArgumentParser/Parsable Properties/NameSpecification.swift index aa6747427..7a71c24a7 100644 --- a/Sources/ArgumentParser/Parsable Properties/NameSpecification.swift +++ b/Sources/ArgumentParser/Parsable Properties/NameSpecification.swift @@ -12,6 +12,7 @@ /// A specification for how to represent a property as a command-line argument /// label. public struct NameSpecification: ExpressibleByArrayLiteral { + /// An individual property name translation. public struct Element: Hashable { internal enum Representation: Hashable { case long From 3773c023cba875465fed66e59c9626fcb1826bc5 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Mon, 9 Aug 2021 16:57:04 -0500 Subject: [PATCH 13/18] Move package.swift changes to 5.5-specific file --- Package.swift | 25 ++++++-------- Package@swift-5.5.swift | 72 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 15 deletions(-) create mode 100644 Package@swift-5.5.swift diff --git a/Package.swift b/Package.swift index ba0db5669..a8caf6ccb 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.5 +// swift-tools-version:5.2 //===----------------------------------------------------------*- swift -*-===// // // This source file is part of the Swift Argument Parser open source project @@ -23,39 +23,35 @@ var package = Package( targets: [ .target( name: "ArgumentParser", - dependencies: [], - exclude: ["CMakeLists.txt"]), + dependencies: []), .target( name: "ArgumentParserTestHelpers", - dependencies: ["ArgumentParser"], - exclude: ["CMakeLists.txt"]), + dependencies: ["ArgumentParser"]), - .executableTarget( + .target( name: "roll", dependencies: ["ArgumentParser"], path: "Examples/roll"), - .executableTarget( + .target( name: "math", dependencies: ["ArgumentParser"], path: "Examples/math"), - .executableTarget( + .target( name: "repeat", dependencies: ["ArgumentParser"], path: "Examples/repeat"), - .executableTarget( + .target( name: "changelog-authors", dependencies: ["ArgumentParser"], path: "Tools/changelog-authors"), .testTarget( name: "ArgumentParserEndToEndTests", - dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"], - exclude: ["CMakeLists.txt"]), + dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"]), .testTarget( name: "ArgumentParserUnitTests", - dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"], - exclude: ["CMakeLists.txt"]), + dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"]), .testTarget( name: "ArgumentParserExampleTests", dependencies: ["ArgumentParserTestHelpers"]), @@ -67,6 +63,5 @@ var package = Package( package.targets.append( .testTarget( name: "ArgumentParserPackageManagerTests", - dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"], - exclude: ["CMakeLists.txt"])) + dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"])) #endif diff --git a/Package@swift-5.5.swift b/Package@swift-5.5.swift new file mode 100644 index 000000000..ba0db5669 --- /dev/null +++ b/Package@swift-5.5.swift @@ -0,0 +1,72 @@ +// swift-tools-version:5.5 +//===----------------------------------------------------------*- swift -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +import PackageDescription + +var package = Package( + name: "swift-argument-parser", + products: [ + .library( + name: "ArgumentParser", + targets: ["ArgumentParser"]), + ], + dependencies: [], + targets: [ + .target( + name: "ArgumentParser", + dependencies: [], + exclude: ["CMakeLists.txt"]), + .target( + name: "ArgumentParserTestHelpers", + dependencies: ["ArgumentParser"], + exclude: ["CMakeLists.txt"]), + + .executableTarget( + name: "roll", + dependencies: ["ArgumentParser"], + path: "Examples/roll"), + .executableTarget( + name: "math", + dependencies: ["ArgumentParser"], + path: "Examples/math"), + .executableTarget( + name: "repeat", + dependencies: ["ArgumentParser"], + path: "Examples/repeat"), + + .executableTarget( + name: "changelog-authors", + dependencies: ["ArgumentParser"], + path: "Tools/changelog-authors"), + + .testTarget( + name: "ArgumentParserEndToEndTests", + dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"], + exclude: ["CMakeLists.txt"]), + .testTarget( + name: "ArgumentParserUnitTests", + dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"], + exclude: ["CMakeLists.txt"]), + .testTarget( + name: "ArgumentParserExampleTests", + dependencies: ["ArgumentParserTestHelpers"]), + ] +) + +#if swift(>=5.2) +// Skip if < 5.2 to avoid issue with nested type synthesized 'CodingKeys' +package.targets.append( + .testTarget( + name: "ArgumentParserPackageManagerTests", + dependencies: ["ArgumentParser", "ArgumentParserTestHelpers"], + exclude: ["CMakeLists.txt"])) +#endif From 00501ae771a6eeb40638e9274487656b42a265d3 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Wed, 8 Sep 2021 13:13:02 -0500 Subject: [PATCH 14/18] Remove old documentation files --- Docs/01 Getting Started.md | 286 -------------- Docs/02 Arguments, Options, and Flags.md | 468 ----------------------- Docs/03 Commands and Subcommands.md | 178 --------- Docs/04 Customizing Help.md | 209 ---------- Docs/05 Validation and Errors.md | 157 -------- Docs/06 Manual Parsing and Testing.md | 112 ------ Docs/07 Completion Scripts.md | 62 --- 7 files changed, 1472 deletions(-) delete mode 100644 Docs/01 Getting Started.md delete mode 100644 Docs/02 Arguments, Options, and Flags.md delete mode 100644 Docs/03 Commands and Subcommands.md delete mode 100644 Docs/04 Customizing Help.md delete mode 100644 Docs/05 Validation and Errors.md delete mode 100644 Docs/06 Manual Parsing and Testing.md delete mode 100644 Docs/07 Completion Scripts.md diff --git a/Docs/01 Getting Started.md b/Docs/01 Getting Started.md deleted file mode 100644 index 0a2e14e90..000000000 --- a/Docs/01 Getting Started.md +++ /dev/null @@ -1,286 +0,0 @@ -# Getting Started with `ArgumentParser` - -Learn to set up and customize a simple command-line tool. - -This guide walks through building an example command. You'll learn about the different tools that `ArgumentParser` provides for defining a command's options, customizing the interface, and providing help text for your user. - -## Adding `ArgumentParser` as a Dependency - -Let's write a tool called `count` that reads an input file, counts the words, and writes the result to an output file. - -First, we need to add `swift-argument-parser` as a dependency to our package, -and then include `"ArgumentParser"` as a dependency for our executable target. -Our "Package.swift" file ends up looking like this: - -```swift -// swift-tools-version:5.2 -import PackageDescription - -let package = Package( - name: "random", - dependencies: [ - .package(url: "https://github.com/apple/swift-argument-parser.git", from: "0.5.0"), - ], - targets: [ - .target( - name: "count", - dependencies: [.product(name: "ArgumentParser", package: "swift-argument-parser")]), - ] -) -``` - -> **Note:** To read more about creating and configuring packages using Swift Package Manager, see [Using the Package Manager](https://swift.org/getting-started/#using-the-package-manager). - -## Building Our First Command - -Once we've built the `count` tool, we'll be able to run it like this: - -``` -% count readme.md readme.counts -Counting words in 'readme.md' and writing the result into 'readme.counts'. -``` - -We'll define the initial version of the command as a type that conforms to the `ParsableCommand` protocol: - -```swift -import ArgumentParser - -struct Count: ParsableCommand { - @Argument var inputFile: String - @Argument var outputFile: String - - mutating func run() throws { - print(""" - Counting words in '\(inputFile)' \ - and writing the result into '\(outputFile)'. - """) - - // Read 'inputFile', count the words, and save to 'outputFile'. - } -} - -Count.main() -``` - -In the code above, the `inputFile` and `outputFile` properties use the `@Argument` property wrapper. `ArgumentParser` uses this wrapper to denote a positional command-line input — because `inputFile` is specified first in the `Count` type, it's the first value read from the command line, and `outputFile` is read second. - -We've implemented the command's logic in its `run()` method. Here, we're printing out a message confirming the names of the files the user gave. (You can find a full implementation of the completed command at the end of this guide.) - -Finally, you tell the parser to execute the `Count` command by calling its static `main()` method. This method parses the command-line arguments, verifies that they match up with what we've defined in `Count`, and either calls the `run()` method or exits with a helpful message. - - -## Working with Named Options - -Our `count` tool may have a usability problem — it's not immediately clear whether a user should provide the input file first, or the output file. Instead of using positional arguments for our two inputs, let's specify that they should be labeled options: - -``` -% count --input-file readme.md --output-file readme.counts -Counting words in 'readme.md' and writing the result into 'readme.counts'. -``` - -We do this by using the `@Option` property wrapper instead of `@Argument`: - -```swift -struct Count: ParsableCommand { - @Option var inputFile: String - @Option var outputFile: String - - mutating func run() throws { - print(""" - Counting words in '\(inputFile)' \ - and writing the result into '\(outputFile)'. - """) - - // Read 'inputFile', count the words, and save to 'outputFile'. - } -} -``` - -The `@Option` property wrapper denotes a command-line input that looks like `--name `, deriving its name from the name of your property. - -This interface has a trade-off for the users of our `count` tool: With `@Argument`, users don't need to type as much, but they have to remember whether to provide the input file or the output file first. Using `@Option` makes the user type a little more, but the distinction between values is explicit. Options are order-independent, as well, so the user can name the input and output files in either order: - -``` -% count --output-file readme.counts --input-file readme.md -Counting words in 'readme.md' and writing the result into 'readme.counts'. -``` - -## Adding a Flag - -Next, we want to add a `--verbose` flag to our tool, and only print the message if the user specifies that option: - -``` -% count --input-file readme.md --output-file readme.counts -(no output) -% count --verbose --input-file readme.md --output-file readme.counts -Counting words in 'readme.md' and writing the result into 'readme.counts'. -``` - -Let's change our `Count` type to look like this: - -```swift -struct Count: ParsableCommand { - @Option var inputFile: String - @Option var outputFile: String - @Flag var verbose = false - - mutating func run() throws { - if verbose { - print(""" - Counting words in '\(inputFile)' \ - and writing the result into '\(outputFile)'. - """) - } - - // Read 'inputFile', count the words, and save to 'outputFile'. - } -} -``` - -The `@Flag` property wrapper denotes a command-line input that looks like `--name`, deriving its name from the name of your property. Flags are most frequently used for Boolean values, like the `verbose` property here. - - -## Using Custom Names - -We can customize the names of our options and add an alternative to the `verbose` flag so that users can specify `-v` instead of `--verbose`. The new interface will look like this: - -``` -% count -v -i readme.md -o readme.counts -Counting words in 'readme.md' and writing the result into 'readme.counts'. -% count --input readme.md --output readme.counts -v -Counting words in 'readme.md' and writing the result into 'readme.counts'. -% count -o readme.counts -i readme.md --verbose -Counting words in 'readme.md' and writing the result into 'readme.counts'. -``` - -Customize the input names by passing `name` parameters to the `@Option` and `@Flag` initializers: - -```swift -struct Count: ParsableCommand { - @Option(name: [.short, .customLong("input")]) - var inputFile: String - - @Option(name: [.short, .customLong("output")]) - var outputFile: String - - @Flag(name: .shortAndLong) - var verbose = false - - mutating func run() throws { ... } -} -``` - -The default name specification is `.long`, which uses a property's name with a two-dash prefix. `.short` uses only the first letter of a property's name with a single-dash prefix, and allows combining groups of short options. You can specify custom short and long names with the `.customShort(_:)` and `.customLong(_:)` methods, respectively, or use the combined `.shortAndLong` property to specify the common case of both the short and long derived names. - -## Providing Help - -`ArgumentParser` automatically generates help for any command when a user provides the `-h` or `--help` flags: - -``` -% count --help -USAGE: count --input --output [--verbose] - -OPTIONS: - -i, --input - -o, --output - -v, --verbose - -h, --help Show help information. -``` - -This is a great start — you can see that all the custom names are visible, and the help shows that values are expected for the `--input` and `--output` options. However, our custom options and flag don't have any descriptive text. Let's add that now by passing string literals as the `help` parameter: - -```swift -struct Count: ParsableCommand { - @Option(name: [.short, .customLong("input")], help: "A file to read.") - var inputFile: String - - @Option(name: [.short, .customLong("output")], help: "A file to save word counts to.") - var outputFile: String - - @Flag(name: .shortAndLong, help: "Print status updates while counting.") - var verbose = false - - mutating func run() throws { ... } -} -``` - -The help screen now includes descriptions for each parameter: - -``` -% count -h -USAGE: count --input --output [--verbose] - -OPTIONS: - -i, --input A file to read. - -o, --output A file to save word counts to. - -v, --verbose Print status updates while counting. - -h, --help Show help information. - -``` - -## The Complete Utility - -As promised, here's the complete `count` command, for your experimentation: - -```swift -import ArgumentParser -import Foundation - -struct Count: ParsableCommand { - static let configuration = CommandConfiguration(abstract: "Word counter.") - - @Option(name: [.short, .customLong("input")], help: "A file to read.") - var inputFile: String - - @Option(name: [.short, .customLong("output")], help: "A file to save word counts to.") - var outputFile: String - - @Flag(name: .shortAndLong, help: "Print status updates while counting.") - var verbose = false - - mutating func run() throws { - if verbose { - print(""" - Counting words in '\(inputFile)' \ - and writing the result into '\(outputFile)'. - """) - } - - guard let input = try? String(contentsOfFile: inputFile) else { - throw RuntimeError("Couldn't read from '\(inputFile)'!") - } - - let words = input.components(separatedBy: .whitespacesAndNewlines) - .map { word in - word.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) - .lowercased() - } - .compactMap { word in word.isEmpty ? nil : word } - - let counts = Dictionary(grouping: words, by: { $0 }) - .mapValues { $0.count } - .sorted(by: { $0.value > $1.value }) - - if verbose { - print("Found \(counts.count) words.") - } - - let output = counts.map { word, count in "\(word): \(count)" } - .joined(separator: "\n") - - guard let _ = try? output.write(toFile: outputFile, atomically: true, encoding: .utf8) else { - throw RuntimeError("Couldn't write to '\(outputFile)'!") - } - } -} - -struct RuntimeError: Error, CustomStringConvertible { - var description: String - - init(_ description: String) { - self.description = description - } -} - -Count.main() -``` diff --git a/Docs/02 Arguments, Options, and Flags.md b/Docs/02 Arguments, Options, and Flags.md deleted file mode 100644 index 886bc7fa4..000000000 --- a/Docs/02 Arguments, Options, and Flags.md +++ /dev/null @@ -1,468 +0,0 @@ -# Declaring Arguments, Options, and Flags - -Use the `@Argument`, `@Option` and `@Flag` property wrappers to declare the command-line interface for your command. - -When creating commands, you can define three primary kinds of command-line inputs: - -- *Arguments* are values given by a user and are read in order from first to last. For example, this command is called with three file names as arguments: - - ``` - % example file1.swift file2.swift file3.swift - ``` - -- *Options* are named key-value pairs. Keys start with one or two dashes (`-` or `--`), and a user can separate the key and value with an equal sign (`=`) or a space. This command is called with two options: - - ``` - % example --count=5 --index 2 - ``` - -- *Flags* are like options, but without a paired value. Instead, their presence indicates a particular value (usually `true`). This command is called with two flags: - - ``` - % example --verbose --strip-whitespace - ``` - -The three preceding examples could be calls of this `Example` command: - -```swift -struct Example: ParsableCommand { - @Argument var files: [String] = [] - @Option var count: Int? - @Option var index = 0 - @Flag var verbose = false - @Flag var stripWhitespace = false -} -``` - -This example shows how `ArgumentParser` provides defaults that speed up your initial development process: - -- Option and flag names are derived from the names of your command's properties. -- What kinds of inputs are valid, and whether arguments are required, is based on your properties' types and default values. - -In this example, all of the properties have default values (optional properties default to `nil`). - -Users must provide values for all properties with no implicit or specified default. For example, this command would require one integer argument and a string with the key `--user-name`. - -```swift -struct Example: ParsableCommand { - @Option var userName: String - @Argument var value: Int -} -``` - -When called without both values, the command exits with an error: - -``` -% example 5 -Error: Missing '--user-name ' -Usage: example --user-name - See 'example --help' for more information. -% example --user-name kjohnson -Error: Missing '' -Usage: example --user-name - See 'example --help' for more information. -``` - -When providing a default value for an array property, any user-supplied values replace the entire default. - -```swift -struct Lucky: ParsableCommand { - @Argument var numbers = [7, 14, 21] - - mutating func run() throws { - print(""" - Your lucky numbers are: - \(numbers.map(String.init).joined(separator: " ")) - """) - } -} -``` - -``` -% lucky -Your lucky numbers are: -7 14 21 -% lucky 1 2 3 -Your lucky numbers are: -1 2 3 -``` - -## Customizing option and flag names - -By default, options and flags derive the name that you use on the command line from the name of the property, such as `--count` and `--index`. Camel-case names are converted to lowercase with hyphen-separated words, like `--strip-whitespace`. - -You can override this default by specifying one or more name specifications in the `@Option` or `@Flag` initializers. This command demonstrates the four name specifications: - -```swift -struct Example: ParsableCommand { - @Flag(name: .long) // Same as the default - var stripWhitespace = false - - @Flag(name: .short) - var verbose = false - - @Option(name: .customLong("count")) - var iterationCount: Int - - @Option(name: [.customShort("I"), .long]) - var inputFile: String -} -``` - -* Specifying `.long` or `.short` uses the property's name as the source of the command-line name. Long names use the whole name, prefixed by two dashes, while short names are a single character prefixed by a single dash. In this example, the `stripWhitespace` and `verbose` flags are specified in this way: - - ``` - % example --strip-whitespace -v - ``` - -* Specifying `.customLong(_:)` or `.customShort(_:)` uses the given string or character as the long or short name for the property. - - ``` - % example --count 10 -I file1.swift - ``` - -* Use array literal syntax to specify multiple names. The `inputFile` property can alternatively be given with the default long name: - - ``` - % example --input-file file1.swift - ``` - -**Note:** You can also pass `withSingleDash: true` to `.customLong` to create a single-dash flag or option, such as `-verbose`. Use this name specification only when necessary, such as when migrating a legacy command-line interface. Using long names with a single-dash prefix can lead to ambiguity with combined short names: it may not be obvious whether `-file` is a single option or the combination of the four short options `-f`, `-i`, `-l`, and `-e`. - - -## Parsing custom types - -Arguments and options can be parsed from any type that conforms to the `ExpressibleByArgument` protocol. Standard library integer and floating-point types, strings, and Booleans all conform to `ExpressibleByArgument`. - -You can make your own custom types conform to `ExpressibleByArgument` by implementing `init?(argument:)`: - -```swift -struct Path: ExpressibleByArgument { - var pathString: String - - init?(argument: String) { - self.pathString = argument - } -} - -struct Example: ParsableCommand { - @Argument var inputFile: Path -} -``` - -The library provides a default implementation for `RawRepresentable` types, like string-backed enumerations, so you only need to declare conformance. - -```swift -enum ReleaseMode: String, ExpressibleByArgument { - case debug, release -} - -struct Example: ParsableCommand { - @Option var mode: ReleaseMode - - mutating func run() throws { - print(mode) - } -} -``` - -The user can provide the raw values on the command line, which are then converted to your custom type. Only valid values are allowed: - -``` -% example --mode release -release -% example --mode future -Error: The value 'future' is invalid for '--mode ' -``` - -To use a non-`ExpressibleByArgument` type for an argument or option, you can instead provide a throwing `transform` function that converts the parsed string to your desired type. This is a good idea for custom types that are more complex than a `RawRepresentable` type, or for types you don't define yourself. - -```swift -enum Format { - case text - case other(String) - - init(_ string: String) throws { - if string == "text" { - self = .text - } else { - self = .other(string) - } - } -} - -struct Example: ParsableCommand { - @Argument(transform: Format.init) - var format: Format -} -``` - -Throw an error from the `transform` function to indicate that the user provided an invalid value for that type. See [Handling Transform Errors](./05%20Validation%20and%20Errors.md#handling-transform-errors) for more about customizing `transform` function errors. - -## Using flag inversions, enumerations, and counts - -Flags are most frequently used for `Bool` properties. You can generate a `true`/`false` pair of flags by specifying a flag inversion: - -```swift -struct Example: ParsableCommand { - @Flag(inversion: .prefixedNo) - var index = true - - @Flag(inversion: .prefixedEnableDisable) - var requiredElement: Bool - - mutating func run() throws { - print(index, requiredElement) - } -} -``` - -When declaring a flag with an inversion, set the default by specifying `true` or `false` as the property's initial value. If you want to require that the user specify one of the two inversions, leave off the default value. - -In the `Example` command defined above, a flag is required for the `requiredElement` property. The specified prefixes are prepended to the long names for the flags: - -``` -% example --enable-required-element -true true -% example --no-index --disable-required-element -false false -% example --index -Error: Missing one of: '--enable-required-element', '--disable-required-element' -``` - -To create a flag with custom names for a Boolean value, to provide an exclusive choice between more than two names, or for collecting multiple values from a set of defined choices, define an enumeration that conforms to the `EnumerableFlag` protocol. - -```swift -enum CacheMethod: String, EnumerableFlag { - case inMemoryCache - case persistentCache -} - -enum Color: String, EnumerableFlag { - case pink, purple, silver -} - -struct Example: ParsableCommand { - @Flag var cacheMethod: CacheMethod - @Flag var colors: [Color] = [] - - mutating func run() throws { - print(cacheMethod) - print(colors) - } -} -``` - -The flag names in this case are drawn from the raw values — for information about customizing the names and help text, see the [`EnumerableFlag` documentation](../Sources/ArgumentParser/Parsable%20Types/EnumerableFlag.swift). - -``` -% example --in-memory-cache --pink --silver -.inMemoryCache -[.pink, .silver] -% example -Error: Missing one of: '--in-memory-cache', '--persistent-cache' -``` - -Finally, when a flag is of type `Int`, the value is parsed as a count of the number of times that the flag is specified. - -```swift -struct Example: ParsableCommand { - @Flag(name: .shortAndLong) - var verbose: Int - - mutating func run() throws { - print("Verbosity level: \(verbose)") - } -} -``` - -In this example, `verbose` defaults to zero, and counts the number of times that `-v` or `--verbose` is given. - -``` -% example --verbose -Verbosity level: 1 -% example -vvvv -Verbosity level: 4 -``` - - -## Specifying default values - -You can specify default values for almost all supported argument, option, and flag types using normal property initialization syntax: - -```swift -enum CustomFlag: String, EnumerableFlag { - case foo, bar, baz -} - -struct Example: ParsableCommand { - @Flag - var booleanFlag = false - - @Flag - var arrayFlag: [CustomFlag] = [.foo, .baz] - - @Option - var singleOption = 0 - - @Option - var arrayOption = ["bar", "qux"] - - @Argument - var singleArgument = "quux" - - @Argument - var arrayArgument = ["quux", "quuz"] -} -``` - -This includes all of the variants of the argument types above (including `@Option(transform: ...)`, etc.), with a few notable exceptions: -- `Optional`-typed values (which default to `nil` and for which a default would not make sense, as the value could never be `nil`) -- `Int` flags (which are used for counting the number of times a flag is specified and therefore default to `0`) - -If a default is not specified, the user must provide a value for that argument/option/flag or will receive an error that the value is missing. - -You must also always specify a default of `false` for a non-optional `Bool` flag, as in the example above. This makes the behavior consistent with both normal Swift properties (which either must be explicitly initialized or optional to initialize a `struct`/`class` containing them) and the other property types. - - -## Specifying a parsing strategy - -When parsing a list of command-line inputs, `ArgumentParser` distinguishes between dash-prefixed keys and un-prefixed values. When looking for the value for a key, only an un-prefixed value will be selected by default. - -For example, this command defines a `--verbose` flag, a `--name` option, and an optional `file` argument: - -```swift -struct Example: ParsableCommand { - @Flag var verbose = false - @Option var name: String - @Argument var file: String? - - mutating func run() throws { - print("Verbose: \(verbose), name: \(name), file: \(file ?? "none")") - } -} -``` - -When calling this command, the value for `--name` must be given immediately after the key. If the `--verbose` flag is placed in between, parsing fails with an error: - -``` -% example --verbose --name Tomás -Verbose: true, name: Tomás, file: none -% example --name --verbose Tomás -Error: Missing value for '--name ' -Usage: example [--verbose] --name [] - See 'example --help' for more information. -``` - -Parsing options as arrays is similar — only adjacent key-value pairs are recognized by default. - -### Alternative single-value parsing strategies - -You can change this behavior by providing a different parsing strategy in the `@Option` initializer. **Be careful when selecting any of the alternative parsing strategies** — they may lead your command-line tool to have unexpected behavior for users! - -The `.unconditional` parsing strategy uses the immediate next input for the value of the option, even if it starts with a dash. If `name` were instead defined as `@Option(parsing: .unconditional) var name: String`, the second attempt would result in `"--verbose"` being read as the value of `name`: - -``` -% example --name --verbose Tomás -Verbose: false, name: --verbose, file: Tomás -``` - -The `.scanningForValue` strategy, on the other hand, looks ahead in the list of command-line inputs and uses the first un-prefixed value as the input, even if that requires skipping over other flags or options. If `name` were defined as `@Option(parsing: .scanningForValue) var name: String`, the parser would look ahead to find `Tomás`, then pick up parsing where it left off to get the `--verbose` flag: - -``` -% example --name --verbose Tomás -Verbose: true, name: Tomás, file: none -``` - -### Alternative array parsing strategies - -The default strategy for parsing options as arrays is to read each value from a key-value pair. For example, this command expects zero or more input file names: - -```swift -struct Example: ParsableCommand { - @Option var file: [String] = [] - @Flag var verbose = false - - mutating func run() throws { - print("Verbose: \(verbose), files: \(file)") - } -} -``` - -As with single values, each time the user provides the `--file` key, they must also provide a value: - -``` -% example --verbose --file file1.swift --file file2.swift -Verbose: true, files: ["file1.swift", "file2.swift"] -% example --file --verbose file1.swift --file file2.swift -Error: Missing value for '--file ' -Usage: example [--file ...] [--verbose] - See 'example --help' for more information. -``` - -The `.unconditionalSingleValue` parsing strategy uses whatever input follows the key as its value, even if that input is dash-prefixed. If `file` were defined as `@Option(parsing: .unconditionalSingleValue) var file: [String]`, then the resulting array could include strings that look like options: - -``` -% example --file file1.swift --file --verbose -Verbose: false, files: ["file1.swift", "--verbose"] -``` - -The `.upToNextOption` parsing strategy uses the inputs that follow the option key until reaching a dash-prefixed input. If `file` were defined as `@Option(parsing: .upToNextOption) var file: [String]`, then the user could specify multiple files without repeating `--file`: - -``` -% example --file file1.swift file2.swift -Verbose: false, files: ["file1.swift", "file2.swift"] -% example --file file1.swift file2.swift --verbose -Verbose: true, files: ["file1.swift", "file2.swift"] -``` - -Finally, the `.remaining` parsing strategy uses all the inputs that follow the option key, regardless of their prefix. If `file` were defined as `@Option(parsing: .remaining) var file: [String]`, then the user would need to specify `--verbose` before the `--file` key for it to be recognized as a flag: - -``` -% example --verbose --file file1.swift file2.swift -Verbose: true, files: ["file1.swift", "file2.swift"] -% example --file file1.swift file2.swift --verbose -Verbose: false, files: ["file1.swift", "file2.swift", "--verbose"] -``` - -### Alternative positional argument parsing strategies - -The default strategy for parsing arrays of positional arguments is to ignore all dash-prefixed command-line inputs. For example, this command accepts a `--verbose` flag and a list of file names as positional arguments: - -```swift -struct Example: ParsableCommand { - @Flag var verbose = false - @Argument var files: [String] = [] - - mutating func run() throws { - print("Verbose: \(verbose), files: \(files)") - } -} -``` - -The `files` argument array uses the default `.remaining` parsing strategy, so it only picks up values that don't have a prefix: - -``` -% example --verbose file1.swift file2.swift -Verbose: true, files: ["file1.swift", "file2.swift"] -% example --verbose file1.swift file2.swift --other -Error: Unexpected argument '--other' -Usage: example [--verbose] [ ...] - See 'example --help' for more information. -``` - -Any input after the `--` terminator is automatically treated as positional input, so users can provide dash-prefixed values that way even with the default configuration: - -``` -% example --verbose -- file1.swift file2.swift --other -Verbose: true, files: ["file1.swift", "file2.swift", "--other"] -``` - -The `.unconditionalRemaining` parsing strategy uses whatever input is left after parsing known options and flags, even if that input is dash-prefixed, including the terminator itself. If `files` were defined as `@Argument(parsing: .unconditionalRemaining) var files: [String]`, then the resulting array would also include strings that look like options: - -``` -% example --verbose file1.swift file2.swift --other -Verbose: true, files: ["file1.swift", "file2.swift", "--other"] -% example -- --verbose file1.swift file2.swift --other -Verbose: false, files: ["--", "--verbose", "file1.swift", "file2.swift", "--other"] -``` diff --git a/Docs/03 Commands and Subcommands.md b/Docs/03 Commands and Subcommands.md deleted file mode 100644 index 1825af795..000000000 --- a/Docs/03 Commands and Subcommands.md +++ /dev/null @@ -1,178 +0,0 @@ -# Defining Commands and Subcommands - -When command-line programs grow larger, it can be useful to divide them into a group of smaller programs, providing an interface through subcommands. Utilities such as `git` and the Swift package manager are able to provide varied interfaces for each of their sub-functions by implementing subcommands such as `git branch` or `swift package init`. - -Generally, these subcommands each have their own configuration options, as well as options that are shared across several or all aspects of the larger program. - -You can build a program with commands and subcommands by defining multiple command types and specifying each command's subcommands in its configuration. For example, here's the interface of a `math` utility that performs operations on a series of values given on the command line. - -``` -% math add 10 15 7 -32 -% math multiply 10 15 7 -1050 -% math stats average 3 4 13 15 15 -10.0 -% math stats average --kind median 3 4 13 15 15 -13.0 -% math stats -OVERVIEW: Calculate descriptive statistics. - -USAGE: math stats - -OPTIONS: - -h, --help Show help information. - -SUBCOMMANDS: - average Print the average of the values. - stdev Print the standard deviation of the values. - quantiles Print the quantiles of the values (TBD). - - See 'math help stats ' for detailed help. -``` - -Start by defining the root `Math` command. You can provide a static `configuration` property for a command that specifies its subcommands and a default subcommand, if any. - -```swift -struct Math: ParsableCommand { - static var configuration = CommandConfiguration( - abstract: "A utility for performing maths.", - subcommands: [Add.self, Multiply.self, Statistics.self], - defaultSubcommand: Add.self) -} -``` - -`Math` lists its three subcommands by their types; we'll see the definitions of `Add`, `Multiply`, and `Statistics` below. `Add` is also given as a default subcommand — this means that it is selected if a user leaves out a subcommand name: - -``` -% math 10 15 7 -32 -``` - -Next, define a `ParsableArguments` type with properties that will be shared across multiple subcommands. Types that conform to `ParsableArguments` can be parsed from command-line arguments, but don't provide any execution through a `run()` method. - -In this case, the `Options` type accepts a `--hexadecimal-output` flag and expects a list of integers. - -```swift -struct Options: ParsableArguments { - @Flag(name: [.long, .customShort("x")], help: "Use hexadecimal notation for the result.") - var hexadecimalOutput = false - - @Argument(help: "A group of integers to operate on.") - var values: [Int] -} -``` - -It's time to define our first two subcommands: `Add` and `Multiply`. Both of these subcommands include the arguments defined in the `Options` type by denoting that property with the `@OptionGroup` property wrapper. `@OptionGroup` doesn't define any new arguments for a command; instead, it splats in the arguments defined by another `ParsableArguments` type. - -```swift -extension Math { - struct Add: ParsableCommand { - static var configuration - = CommandConfiguration(abstract: "Print the sum of the values.") - - @OptionGroup var options: Math.Options - - mutating func run() { - let result = options.values.reduce(0, +) - print(format(result: result, usingHex: options.hexadecimalOutput)) - } - } - - struct Multiply: ParsableCommand { - static var configuration - = CommandConfiguration(abstract: "Print the product of the values.") - - @OptionGroup var options: Math.Options - - mutating func run() { - let result = options.values.reduce(1, *) - print(format(result: result, usingHex: options.hexadecimalOutput)) - } - } -} -``` - -Next, we'll define `Statistics`, the third subcommand of `Math`. The `Statistics` command specifies a custom command name (`stats`) in its configuration, overriding the default derived from the type name (`statistics`). It also declares two additional subcommands, meaning that it acts as a forked branch in the command tree, and not a leaf. - -```swift -extension Math { - struct Statistics: ParsableCommand { - static var configuration = CommandConfiguration( - commandName: "stats", - abstract: "Calculate descriptive statistics.", - subcommands: [Average.self, StandardDeviation.self]) - } -} -``` - -Let's finish our subcommands with the `Average` and `StandardDeviation` types. Each of them has slightly different arguments, so they don't use the `Options` type defined above. Each subcommand is ultimately independent and can specify a combination of shared and unique arguments. - -```swift -extension Math.Statistics { - struct Average: ParsableCommand { - static var configuration = CommandConfiguration( - abstract: "Print the average of the values.") - - enum Kind: String, ExpressibleByArgument { - case mean, median, mode - } - - @Option(help: "The kind of average to provide.") - var kind: Kind = .mean - - @Argument(help: "A group of floating-point values to operate on.") - var values: [Double] = [] - - func calculateMean() -> Double { ... } - func calculateMedian() -> Double { ... } - func calculateMode() -> [Double] { ... } - - mutating func run() { - switch kind { - case .mean: - print(calculateMean()) - case .median: - print(calculateMedian()) - case .mode: - let result = calculateMode() - .map(String.init(describing:)) - .joined(separator: " ") - print(result) - } - } - } - - struct StandardDeviation: ParsableCommand { - static var configuration = CommandConfiguration( - commandName: "stdev", - abstract: "Print the standard deviation of the values.") - - @Argument(help: "A group of floating-point values to operate on.") - var values: [Double] = [] - - mutating func run() { - if values.isEmpty { - print(0.0) - } else { - let sum = values.reduce(0, +) - let mean = sum / Double(values.count) - let squaredErrors = values - .map { $0 - mean } - .map { $0 * $0 } - let variance = squaredErrors.reduce(0, +) - let result = variance.squareRoot() - print(result) - } - } - } -} -``` - -Last but not least, we kick off parsing and execution with a call to the static `main` method on the type at the root of our command tree. The call to main parses the command-line arguments, determines whether a subcommand was selected, and then instantiates and calls the `run()` method on that particular subcommand. - -```swift -Math.main() -``` - -That's it for this doubly-nested `math` command! This example is also provided as a part of the `swift-argument-parser` repository, so you can see it all together and experiment with it [here](https://github.com/apple/swift-argument-parser/blob/main/Examples/math/main.swift). diff --git a/Docs/04 Customizing Help.md b/Docs/04 Customizing Help.md deleted file mode 100644 index f50546cdc..000000000 --- a/Docs/04 Customizing Help.md +++ /dev/null @@ -1,209 +0,0 @@ -# Customizing Help - -Support your users (and yourself) by providing rich help for arguments and commands. - -You can provide help text when declaring any `@Argument`, `@Option`, or `@Flag` by passing a string literal as the `help` parameter: - -```swift -struct Example: ParsableCommand { - @Flag(help: "Display extra information while processing.") - var verbose = false - - @Option(help: "The number of extra lines to show.") - var extraLines = 0 - - @Argument(help: "The input file.") - var inputFile: String? -} -``` - -Users see these strings in the automatically-generated help screen, which is triggered by the `-h` or `--help` flags, by default: - -``` -% example --help -USAGE: example [--verbose] [--extra-lines ] - -ARGUMENTS: - The input file. - -OPTIONS: - --verbose Display extra information while processing. - --extra-lines - The number of extra lines to show. (default: 0) - -h, --help Show help information. -``` - -## Customizing Help for Arguments - -You can have more control over the help text by passing an `ArgumentHelp` instance instead. The `ArgumentHelp` type can include an abstract (which is what the string literal becomes), a discussion, a value name to use in the usage string, and a Boolean that indicates whether the argument should be visible in the help screen. - -Here's the same command with some extra customization: - -```swift -struct Example: ParsableCommand { - @Flag(help: "Display extra information while processing.") - var verbose = false - - @Option(help: ArgumentHelp( - "The number of extra lines to show.", - valueName: "n")) - var extraLines = 0 - - @Argument(help: ArgumentHelp( - "The input file.", - discussion: "If no input file is provided, the tool reads from stdin.", - valueName: "file")) - var inputFile: String? -} -``` - -...and the help screen: - -``` -USAGE: example [--verbose] [--extra-lines ] [] - -ARGUMENTS: - The input file. - If no input file is provided, the tool reads from stdin. - -OPTIONS: - --verbose Display extra information while processing. - --extra-lines The number of extra lines to show. (default: 0) - -h, --help Show help information. -``` - -## Customizing Help for Commands - -In addition to configuring the command name and subcommands, as described in [Command and Subcommands](03%20Commands%20and%20Subcommands.md), you can also configure a command's help text by providing an abstract and discussion. - -```swift -struct Repeat: ParsableCommand { - static var configuration = CommandConfiguration( - abstract: "Repeats your input phrase.", - discussion: """ - Prints to stdout forever, or until you halt the program. - """) - - @Argument(help: "The phrase to repeat.") - var phrase: String - - mutating func run() throws { - while true { print(phrase) } - } -} -``` - -The abstract and discussion appear in the generated help screen: - -``` -% repeat --help -OVERVIEW: Repeats your input phrase. - -Prints to stdout forever, or until you halt the program. - -USAGE: repeat - -ARGUMENTS: - The phrase to repeat. - -OPTIONS: - -h, --help Show help information. - -% repeat hello! -hello! -hello! -hello! -hello! -hello! -hello! -... -``` - -## Modifying the Help Flag Names - -Users can see the help screen for a command by passing either the `-h` or the `--help` flag, by default. If you need to use one of those flags for another purpose, you can provide alternative names when configuring a root command. - -```swift -struct Example: ParsableCommand { - static let configuration = CommandConfiguration( - helpNames: [.long, .customShort("?")]) - - @Option(name: .shortAndLong, help: "The number of history entries to show.") - var historyDepth: Int - - mutating func run() throws { - printHistory(depth: historyDepth) - } -} -``` - -When running the command, `-h` matches the short name of the `historyDepth` property, and `-?` displays the help screen. - -``` -% example -h 3 -... -% example -? -USAGE: example --history-depth - -ARGUMENTS: - The phrase to repeat. - -OPTIONS: - -h, --history-depth The number of history entries to show. - -?, --help Show help information. -``` - -When not overridden, custom help names are inherited by subcommands. In this example, the parent command defines `--help` and `-?` as its help names: - -```swift -struct Parent: ParsableCommand { - static let configuration = CommandConfiguration( - subcommands: [Child.self], - helpNames: [.long, .customShort("?")]) - - struct Child: ParsableCommand { - @Option(name: .shortAndLong, help: "The host the server will run on.") - var host: String - } -} -``` - -The `child` subcommand inherits the parent's help names, allowing the user to distinguish between the host argument (`-h`) and help (`-?`). - -``` -% parent child -h 192.0.0.0 -... -% parent child -? -USAGE: parent child --host - -OPTIONS: - -h, --host The host the server will run on. - -?, --help Show help information. -``` - -## Hiding Arguments and Commands - -You may want to suppress features under development or experimental flags from the generated help screen. You can hide an argument or a subcommand by passing `shouldDisplay: false` to the property wrapper or `CommandConfiguration` initializers, respectively. - -`ArgumentHelp` includes a `.hidden` static property that makes it even simpler to hide arguments: - -```swift -struct Example: ParsableCommand { - @Flag(help: .hidden) - var experimentalEnableWidgets: Bool -} -``` - -## Generating Help Text Programmatically - -The help screen is automatically shown to users when they call your command with the help flag. You can generate the same text from within your program by calling the `helpMessage()` method. - -```swift -let help = Repeat.helpMessage() -// `help` matches the output above - -let fortyColumnHelp = Repeat.helpMessage(columns: 40) -// `fortyColumnHelp` is the same help screen, but wrapped to 40 columns -``` - -When generating help text for a subcommand, call `helpMessage(for:)` on the `ParsableCommand` type that represents the root of the command tree and pass the subcommand type as a parameter to ensure the correct display. diff --git a/Docs/05 Validation and Errors.md b/Docs/05 Validation and Errors.md deleted file mode 100644 index 941df831b..000000000 --- a/Docs/05 Validation and Errors.md +++ /dev/null @@ -1,157 +0,0 @@ -# Validation and Errors - -Provide helpful feedback to users when things go wrong. - -## Validating Command-Line Input - -While `ArgumentParser` validates that the inputs given by your user match the requirements and types that you define in each command, there are some requirements that can't easily be described in Swift's type system, such as the number of elements in an array, or an expected integer value. - -To validate your commands properties after parsing, implement the `validate()` method on any `ParsableCommand` or `ParsableArguments` type. Throwing an error from the `validate()` method causes the program to print a message to standard error and exit with an error code, preventing the `run()` method from being called with invalid inputs. - -Here's a command that prints out one or more random elements from the list you provide. Its `validate()` method catches three different errors that a user can make and throws a relevant error for each one. - -```swift -struct Select: ParsableCommand { - @Option var count: Int = 1 - @Argument var elements: [String] = [] - - mutating func validate() throws { - guard count >= 1 else { - throw ValidationError("Please specify a 'count' of at least 1.") - } - - guard !elements.isEmpty else { - throw ValidationError("Please provide at least one element to choose from.") - } - - guard count <= elements.count else { - throw ValidationError("Please specify a 'count' less than the number of elements.") - } - } - - mutating func run() { - print(elements.shuffled().prefix(count).joined(separator: "\n")) - } -} -``` - -When you provide useful error messages, they can guide new users to success with your command-line tool! - -``` -% select -Error: Please provide at least one element to choose from. -Usage: select [--count ] [ ...] - See 'select --help' for more information. -% select --count 2 hello -Error: Please specify a 'count' less than the number of elements. -Usage: select [--count ] [ ...] - See 'select --help' for more information. -% select --count 0 hello hey hi howdy -Error: Please specify a 'count' of at least 1. -Usage: select [--count ] [ ...] - See 'select --help' for more information. -% select --count 2 hello hey hi howdy -howdy -hey -``` - -## Handling Post-Validation Errors - -The `ValidationError` type is a special `ArgumentParser` error — a validation error's message is always accompanied by an appropriate usage string. You can throw other errors, from either the `validate()` or `run()` method to indicate that something has gone wrong that isn't validation-specific. Errors that conform to `CustomStringConvertible` or `LocalizedError` provide the best experience for users. - -```swift -struct LineCount: ParsableCommand { - @Argument var file: String - - mutating func run() throws { - let contents = try String(contentsOfFile: file, encoding: .utf8) - let lines = contents.split(separator: "\n") - print(lines.count) - } -} -``` - -The throwing `String(contentsOfFile:encoding:)` initializer fails when the user specifies an invalid file. `ArgumentParser` prints its error message to standard error and exits with an error code. - -``` -% line-count file1.swift -37 -% line-count non-existing-file.swift -Error: The file “non-existing-file.swift” couldn’t be opened because -there is no such file. -``` - -If you print your error output yourself, you still need to throw an error from `validate()` or `run()`, so that your command exits with the appropriate exit code. To avoid printing an extra error message, use the `ExitCode` error, which has static properties for success, failure, and validation errors, or lets you specify a specific exit code. - -```swift -struct RuntimeError: Error, CustomStringConvertible { - var description: String -} - -struct Example: ParsableCommand { - @Argument var inputFile: String - - mutating func run() throws { - if !ExampleCore.processFile(inputFile) { - // ExampleCore.processFile(_:) prints its own errors - // and returns `false` on failure. - throw ExitCode.failure - } - } -} -``` - -## Handling Transform Errors - -During argument and option parsing, you can use a closure to transform the command line strings to custom types. If this transformation fails, you can throw a `ValidationError`; its `message` property will be displayed to the user. - -In addition, you can throw your own errors. Errors that conform to `CustomStringConvertible` or `LocalizedError` provide the best experience for users. - -```swift -struct ExampleTransformError: Error, CustomStringConvertible { - var description: String -} - -struct ExampleDataModel: Codable { - let identifier: UUID - let tokens: [String] - let tokenCount: Int - - static func dataModel(_ jsonString: String) throws -> ExampleDataModel { - guard let data = jsonString.data(using: .utf8) else { throw ValidationError("Badly encoded string, should be UTF-8") } - return try JSONDecoder().decode(ExampleDataModel.self, from: data) - } -} - -struct Example: ParsableCommand { - // Reads in the argument string and attempts to transform it to - // an `ExampleDataModel` object using the `JSONDecoder`. If the - // string is not valid JSON, `decode` will throw an error and - // parsing will halt. - @Argument(transform: ExampleDataModel.dataModel) - var inputJSON: ExampleDataModel - - // Specifiying this option will always cause the parser to exit - // and print the custom error. - @Option(transform: { throw ExampleTransformError(description: "Trying to write to failOption always produces an error. Input: \($0)") }) - var failOption: String? -} -``` - -Throwing from a transform closure benefits users by providing context and can reduce development time by pinpointing issues quickly and more precisely. - -``` -% example '{"Bad JSON"}' -Error: The value '{"Bad JSON"}' is invalid for '': dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "No value for key in object around character 11." UserInfo={NSDebugDescription=No value for key in object around character 11.}))) -Usage: example --fail-option - See 'select --help' for more information. -``` - -While throwing standard library or Foundation errors adds context, custom errors provide the best experience for users and developers. - -``` -% example '{"tokenCount":0,"tokens":[],"identifier":"F77D661C-C5B7-448E-9344-267B284F66AD"}' --fail-option="Some Text Here!" -Error: The value 'Some Text Here!' is invalid for '--fail-option ': Trying to write to failOption always produces an error. Input: Some Text Here! -Usage: example --fail-option - See 'select --help' for more information. -``` diff --git a/Docs/06 Manual Parsing and Testing.md b/Docs/06 Manual Parsing and Testing.md deleted file mode 100644 index b7fc564b4..000000000 --- a/Docs/06 Manual Parsing and Testing.md +++ /dev/null @@ -1,112 +0,0 @@ -# Manual Parsing and Testing - -Provide your own array of command-line inputs and work with parsed results by calling alternatives to `main()`. - -For most programs, calling the static `main()` method on the root command type is all that's necessary. That single call parses the command-line arguments to find the correct command from your tree of nested subcommands, instantiates and validates the result, and executes the chosen command. For more control, however, you can perform each of those steps manually. - -## Parsing Arguments - -For simple Swift scripts, and for those who prefer a straight-down-the-left-edge-of-the-screen scripting style, you can define a single `ParsableArguments` type to parse explicitly from the command-line arguments. - -Let's implement the `Select` command discussed in [Validation and Errors](05%20Validation%20and%20Errors.md), but using a scripty style instead of the typical command. First, we define the options as a `ParsableArguments` type: - -```swift -struct SelectOptions: ParsableArguments { - @Option var count: Int = 1 - @Argument var elements: [String] = [] -} -``` - -The next step is to parse our options from the command-line input: - -```swift -let options = SelectOptions.parseOrExit() -``` - -The static `parseOrExit()` method either returns a fully initialized instance of the type, or exits with an error message and code. Alternatively, you can call the throwing `parse()` method if you'd like to catch any errors that arise during parsing. - -We can perform validation on the inputs and exit the script if necessary: - -```swift -guard options.elements.count >= options.count else { - let error = ValidationError("Please specify a 'count' less than the number of elements.") - SelectOptions.exit(withError: error) -} -``` - -As you would expect, the `exit(withError:)` method includes usage information when you pass it a `ValidationError`. - -Finally, we print out the requested number of elements: - -```swift -let chosen = options.elements - .shuffled() - .prefix(options.count) -print(chosen.joined(separator: "\n")) -``` - -## Parsing Commands - -Manually parsing commands is a little more complex than parsing a simple `ParsableArguments` type. The result of parsing from a tree of subcommands may be of a different type than the root of the tree, so the static `parseAsRoot()` method returns a type-erased `ParsableCommand`. - -Let's see how this works by using the `Math` command and subcommands defined in [Commands and Subcommands](03%20Commands%20and%20Subcommands.md). This time, instead of calling `Math.main()`, we'll call `Math.parseAsRoot()`, and switch over the result: - -```swift -do { - var command = try Math.parseAsRoot() - - switch command { - case var command as Math.Add: - print("You chose to add \(command.options.values.count) values.") - command.run() - default: - print("You chose to do something else.") - try command.run() - } -} catch { - Math.exit(withError: error) -} -``` -Our new logic intercepts the command between validation and running, and outputs an additional message: - -``` -% math 10 15 7 -You chose to add 3 values. -32 -% math multiply 10 15 7 -You chose to do something else. -1050 -``` - -## Providing Command-Line Input - -All of the parsing methods — `parse()`, `parseOrExit()`, and `parseAsRoot()` — can optionally take an array of command-line inputs as an argument. You can use this capability to test your commands, to perform pre-parse filtering of the command-line arguments, or to manually execute commands from within the same or another target. - -Let's update our `select` script above to strip out any words that contain all capital letters before parsing the inputs. - -```swift -let noShoutingArguments = CommandLine.arguments.dropFirst().filter { phrase in - phrase.uppercased() != phrase -} -let options = SelectOptions.parseOrExit(noShoutingArguments) -``` - -Now when we call our command, the parser won't even see the capitalized words — `HEY` won't ever be printed: - -``` -% select hi howdy HEY --count 2 -hi -howdy -% select hi howdy HEY --count 2 -howdy -hi -``` - - - - - - - - - diff --git a/Docs/07 Completion Scripts.md b/Docs/07 Completion Scripts.md deleted file mode 100644 index f3ddc1cac..000000000 --- a/Docs/07 Completion Scripts.md +++ /dev/null @@ -1,62 +0,0 @@ -# Completion Scripts - -Generate customized completion scripts for your shell of choice. - -## Generating and Installing Completion Scripts - -Command-line tools that you build with `ArgumentParser` include a built-in option for generating completion scripts, with support for Bash, Z shell, and Fish. To generate completions, run your command with the `--generate-completion-script` flag to generate completions for the autodetected shell, or with a value to generate completions for a specific shell. - -``` -$ example --generate-completion-script bash -#compdef example -local context state state_descr line -_example_commandname="example" -typeset -A opt_args - -_example() { - integer ret=1 - local -a args - ... -} - -_example -``` - -The correct method of installing a completion script depends on your shell and your configuration. - -### Installing Zsh Completions - -If you have [`oh-my-zsh`](https://ohmyz.sh) installed, you already have a directory of automatically loading completion scripts — `.oh-my-zsh/completions`. Copy your new completion script to that directory. - -``` -$ example --generate-completion-script zsh > ~/.oh-my-zsh/completions/_example -``` - -> Your completion script must have the following filename format: `_example`. - -Without `oh-my-zsh`, you'll need to add a path for completion scripts to your function path, and turn on completion script autoloading. First, add these lines to `~/.zshrc`: - -``` -fpath=(~/.zsh/completion $fpath) -autoload -U compinit -compinit -``` - -Next, create a directory at `~/.zsh/completion` and copy the completion script to the new directory. - -### Installing Bash Completions - -If you have [`bash-completion`](https://github.com/scop/bash-completion) installed, you can just copy your new completion script to the `/usr/local/etc/bash_completion.d` directory. - -Without `bash-completion`, you'll need to source the completion script directly. Copy it to a directory such as `~/.bash_completions/`, and then add the following line to `~/.bash_profile` or `~/.bashrc`: - -``` -source ~/.bash_completions/example.bash -``` - -### Installing Fish Completions - -Copy the completion script to any path listed in the environment variable `$fish_completion_path`. For example, a typical location is `~/.config/fish/completions/your_script.fish`. - -## Customizing Completions - From 86b5a0f4a2a752e67ec753a7c67aa5639bb58302 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Wed, 8 Sep 2021 13:13:25 -0500 Subject: [PATCH 15/18] Minor article fixes --- .../Articles/InstallingCompletionScripts.md | 4 ++-- .../Documentation.docc/Articles/ManualParsing.md | 11 ++--------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/InstallingCompletionScripts.md b/Sources/ArgumentParser/Documentation.docc/Articles/InstallingCompletionScripts.md index 0057a1591..24265bcaf 100644 --- a/Sources/ArgumentParser/Documentation.docc/Articles/InstallingCompletionScripts.md +++ b/Sources/ArgumentParser/Documentation.docc/Articles/InstallingCompletionScripts.md @@ -4,7 +4,7 @@ Install shell completion scripts generated by your command-line tool. ## Overview -Command-line tools that you build with `ArgumentParser` include a built-in option for generating completion scripts, with support for Bash, Z shell, and Fish. To generate completions, run your command with the `--generate-completion-script` flag to generate completions for the autodetected shell, or with a value to generate completions for a specific shell. +Command-line tools that you build with `ArgumentParser` include a built-in option for generating completion scripts, with support for Bash, Z shell, and Fish. To generate completions, run your command with the `--generate-completion-script` option to generate completions for your specific shell. ``` $ example --generate-completion-script bash @@ -22,7 +22,7 @@ _example() { _example ``` -The correct method of installing a completion script depends on your shell and your configuration. +The correct method of installing a completion script can depend on both your shell and your configuration. ### Installing Zsh Completions diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/ManualParsing.md b/Sources/ArgumentParser/Documentation.docc/Articles/ManualParsing.md index da70b8895..79a5f7da4 100644 --- a/Sources/ArgumentParser/Documentation.docc/Articles/ManualParsing.md +++ b/Sources/ArgumentParser/Documentation.docc/Articles/ManualParsing.md @@ -2,6 +2,8 @@ Provide your own array of command-line inputs and work with parsed results by calling alternatives to `main()`. +## Overview + For most programs, calling the static `main()` method on the root command type is all that's necessary. That single call parses the command-line arguments to find the correct command from your tree of nested subcommands, instantiates and validates the result, and executes the chosen command. For more control, however, you can perform each of those steps manually. ## Parsing Arguments @@ -101,12 +103,3 @@ howdy howdy hi ``` - - - - - - - - - From 49dcc362ecb98103189aa53ebf46b1ffbddda0e3 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 9 Sep 2021 14:31:38 -0500 Subject: [PATCH 16/18] Add ArgumentParserToolInfo to 5.5 Package.swift --- Package@swift-5.5.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Package@swift-5.5.swift b/Package@swift-5.5.swift index ba0db5669..57b94b2cf 100644 --- a/Package@swift-5.5.swift +++ b/Package@swift-5.5.swift @@ -23,12 +23,15 @@ var package = Package( targets: [ .target( name: "ArgumentParser", - dependencies: [], + dependencies: ["ArgumentParserToolInfo"], exclude: ["CMakeLists.txt"]), .target( name: "ArgumentParserTestHelpers", - dependencies: ["ArgumentParser"], + dependencies: ["ArgumentParser", "ArgumentParserToolInfo"], exclude: ["CMakeLists.txt"]), + .target( + name: "ArgumentParserToolInfo", + dependencies: []), .executableTarget( name: "roll", From 57e64233a22bb56d76c393e700c5e8db8a1fc357 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 9 Sep 2021 15:13:12 -0500 Subject: [PATCH 17/18] Documentation corrections --- .../Documentation.docc/Articles/GettingStarted.md | 2 +- .../ArgumentParser/Parsable Properties/Flag.swift | 5 +++-- .../Parsable Properties/Option.swift | 15 ++++++++------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/GettingStarted.md b/Sources/ArgumentParser/Documentation.docc/Articles/GettingStarted.md index 175f62c82..a9289637b 100644 --- a/Sources/ArgumentParser/Documentation.docc/Articles/GettingStarted.md +++ b/Sources/ArgumentParser/Documentation.docc/Articles/GettingStarted.md @@ -6,7 +6,7 @@ Learn to set up and customize a simple command-line tool. This guide walks through building an example command. You'll learn about the different tools that `ArgumentParser` provides for defining a command's options, customizing the interface, and providing help text for your user. -## Adding `ArgumentParser` as a Dependency +## Adding ArgumentParser as a Dependency Let's write a tool called `count` that reads an input file, counts the words, and writes the result to an output file. diff --git a/Sources/ArgumentParser/Parsable Properties/Flag.swift b/Sources/ArgumentParser/Parsable Properties/Flag.swift index a4efd6f56..3415e5199 100644 --- a/Sources/ArgumentParser/Parsable Properties/Flag.swift +++ b/Sources/ArgumentParser/Parsable Properties/Flag.swift @@ -15,7 +15,8 @@ /// command-line flag. A *flag* is a dash-prefixed label that can be provided on /// the command line, such as `-d` and `--debug`. /// -/// For example, the following program +/// For example, the following program declares a flag that lets a user indicate +/// that seconds should be included when printing the time. /// /// @main /// struct Time: ParsableCommand { @@ -59,7 +60,7 @@ /// Instead of using the name of the `operation` property as the flag in this /// case, the two cases of the `Operation` enumeration become valid flags. /// The `operation` property is neither optional nor given a default value, so -/// one of the flags is required. +/// one of the two flags is required. /// /// $ math --add /// Time to add! diff --git a/Sources/ArgumentParser/Parsable Properties/Option.swift b/Sources/ArgumentParser/Parsable Properties/Option.swift index 86c501586..7ef15f9c6 100644 --- a/Sources/ArgumentParser/Parsable Properties/Option.swift +++ b/Sources/ArgumentParser/Parsable Properties/Option.swift @@ -14,18 +14,19 @@ /// Use the `@Option` wrapper to define a property of your custom command as a /// command-line option. An *option* is a named value passed to a command-line /// tool, like `--configuration debug`. Options can be specified in any order. -/// `@Option` properties with `Optional` type or a default value are optional -/// for the user of your command-line tool. /// -/// An option can have a default values specified as part of its +/// An option can have a default value specified as part of its /// declaration; options with optional `Value` types implicitly have `nil` as -/// their default value. +/// their default value. Options that are neither declared as `Optional` nor +/// given a default value are required for users of your command-line tool. +/// +/// For example, the following program defines three options: /// /// @main /// struct Greet: ParsableCommand { /// @Option var greeting = "Hello" -/// @Option var name: String /// @Option var age: Int? +/// @Option var name: String /// /// mutating func run() { /// print("\(greeting) \(name)!") @@ -36,8 +37,8 @@ /// } /// /// `greeting` has a default value of `"Hello"`, which can be overridden by -/// providing a different string as an argument. `age` defaults to `nil`, while -/// `name` is a required argument because it is non-`nil` and has no default +/// providing a different string as an argument, while `age` defaults to `nil`. +/// `name` is a required option because it is non-`nil` and has no default /// value. /// /// $ greet --name Alicia From f24df59f1856421206eab20650badd877f7bf22f Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 10 Sep 2021 10:18:22 -0500 Subject: [PATCH 18/18] Exclude CMakeList file from SPM build --- Package@swift-5.5.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Package@swift-5.5.swift b/Package@swift-5.5.swift index 57b94b2cf..eb096c191 100644 --- a/Package@swift-5.5.swift +++ b/Package@swift-5.5.swift @@ -31,7 +31,8 @@ var package = Package( exclude: ["CMakeLists.txt"]), .target( name: "ArgumentParserToolInfo", - dependencies: []), + dependencies: [], + exclude: ["CMakeLists.txt"]), .executableTarget( name: "roll",