From d0de5fbdd970c85e4967e93758053c11508a331b Mon Sep 17 00:00:00 2001 From: Louis Qian Date: Fri, 3 Oct 2025 19:31:33 -0700 Subject: [PATCH 1/3] doc: add detailed doc for enum descriptions. --- .../Articles/CustomizingHelp.md | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md b/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md index 163565b9d..3017d9398 100644 --- a/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md +++ b/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md @@ -150,6 +150,150 @@ OPTIONS: For an ``ExpressibleByArgument`` and `CaseIterable` type with many cases, you may still want to implement ``ExpressibleByArgument/allValueStrings`` to avoid an overly long list of values appearing in the help screen. For these types it is recommended to include the most common possible values. +## Providing Descriptions for Individual Enum Values + +When your argument or option uses an enum type, you can provide detailed descriptions for each enum value that will appear in the help screen. This is especially useful when the enum cases represent complex concepts that benefit from explanation. + +### Basic Enum Value Descriptions + +To provide descriptions for individual enum values, implement a custom `defaultValueDescription` property for each case. The ArgumentParser will automatically detect when descriptions differ from the enum's string representation and display them in an enumerated format. + +```swift +enum LogLevel: String, CaseIterable, ExpressibleByArgument { + case error + case warning + case info + case debug + + var defaultValueDescription: String { + switch self { + case .error: + return "Show only error messages" + case .warning: + return "Show warnings and errors" + case .info: + return "Show informational messages and above" + case .debug: + return "Show all messages including debug output" + } + } +} + +struct Logger: ParsableCommand { + @Option(help: "Set the logging level") + var level: LogLevel = .info +} +``` + +This produces help output with detailed descriptions for each enum value: + +``` +USAGE: logger [--level ] + +OPTIONS: + --level Set the logging level (default: info) + error - Show only error messages + warning - Show warnings and errors + info - Show informational messages and above + debug - Show all messages including debug output + -h, --help Show help information. +``` + +### Array Options with Enum Descriptions + +The same enum value descriptions work seamlessly with array options, allowing users to understand each possible value when multiple selections are allowed: + +```swift +enum OutputFormat: String, CaseIterable, ExpressibleByArgument { + case json + case yaml + case xml + case csv + + var defaultValueDescription: String { + switch self { + case .json: + return "JavaScript Object Notation format" + case .yaml: + return "YAML Ain't Markup Language format" + case .xml: + return "eXtensible Markup Language format" + case .csv: + return "Comma-Separated Values format" + } + } +} + +struct DataExporter: ParsableCommand { + @Option(help: "Output formats to generate") + var formats: [OutputFormat] = [.json] +} +``` + +The help screen displays descriptions for each format option: + +``` +USAGE: data-exporter [--formats ...] + +OPTIONS: + --formats Output formats to generate (default: json) + json - JavaScript Object Notation format + yaml - YAML Ain't Markup Language format + xml - eXtensible Markup Language format + csv - Comma-Separated Values format + -h, --help Show help information. +``` + +### Working with Raw Values + +For enums with custom raw values, the descriptions work with the raw value representation: + +```swift +enum CompressionAlgorithm: String, CaseIterable, ExpressibleByArgument { + case gzip = "gzip" + case bzip2 = "bzip2" + case lzma = "lzma" + case none = "none" + + var defaultValueDescription: String { + switch self { + case .gzip: + return "GNU zip compression (good speed, decent compression)" + case .bzip2: + return "Burrows-Wheeler compression (slower, better compression)" + case .lzma: + return "Lempel-Ziv-Markov compression (slowest, best compression)" + case .none: + return "No compression applied" + } + } +} + +struct Archive: ParsableCommand { + @Option(help: "Compression algorithm to use") + var compression: CompressionAlgorithm = .gzip +} +``` + +### Tips for Effective Enum Descriptions + +1. **Keep descriptions concise but informative** - Aim for one line that clearly explains the option's purpose or behavior. + +2. **Use consistent formatting** - Maintain a consistent style across all your descriptions (e.g., all sentences or all phrases). + +3. **Explain the impact** - Help users understand what choosing each option will do, not just what it is. + +4. **Order logically** - The descriptions appear in the same order as your enum cases, so consider ordering them by frequency of use or logical progression. + +5. **Only provide descriptions when helpful** - If your enum values are self-explanatory, you don't need custom descriptions. The system will only show the detailed format when descriptions differ from the raw values. + +The enum value descriptions feature works automatically with: +- Single enum options (`@Option var value: MyEnum`) +- Optional enum options (`@Option var value: MyEnum?`) +- Array enum options (`@Option var values: [MyEnum]`) +- Enum arguments (`@Argument var value: MyEnum`) +- Default values and value display formatting + ### Controlling Argument Visibility You can specify the visibility of any argument, option, or flag. From 5f5dc1099fbf5cc90e45c4edf9ba239b122ca2d5 Mon Sep 17 00:00:00 2001 From: Louis Qian Date: Sat, 4 Oct 2025 12:56:31 -0700 Subject: [PATCH 2/3] doc: remove tips section --- .../Articles/CustomizingHelp.md | 51 ++++++------------- 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md b/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md index 3017d9398..da06cac6b 100644 --- a/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md +++ b/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md @@ -37,7 +37,7 @@ OPTIONS: ### Customizing Help for Arguments -For more control over the help text, pass an ``ArgumentHelp`` instance instead of a string literal. 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 visibility level for that argument. +For more control over the help text, pass an `ArgumentHelp` instance instead of a string literal. 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 visibility level for that argument. Here's the same command with some extra customization: @@ -76,7 +76,7 @@ OPTIONS: ### Enumerating Possible Values -When an argument or option has a fixed set of possible values, listing these values in the help screen can simplify use of your tool. You can customize the displayed set of values for custom ``ExpressibleByArgument`` types by implementing ``ExpressibleByArgument/allValueStrings``. Despite the name, ``ExpressibleByArgument/allValueStrings`` does _not_ need to be an exhaustive list of possible values. +When an argument or option has a fixed set of possible values, listing these values in the help screen can simplify use of your tool. You can customize the displayed set of values for custom `ExpressibleByArgument` types by implementing `ExpressibleByArgument/allValueStrings`. Despite the name, `ExpressibleByArgument/allValueStrings` does _not_ need to be an exhaustive list of possible values. ```swift enum Fruit: String, ExpressibleByArgument { @@ -93,7 +93,7 @@ enum Fruit: String, ExpressibleByArgument { struct FruitStore: ParsableCommand { @Argument(help: "The fruit to purchase") var fruit: Fruit - + @Option(help: "The number of fruit to purchase") var quantity: Int = 1 } @@ -115,7 +115,7 @@ OPTIONS: #### Deriving Possible Values -ExpressibleByArgument types that conform to `CaseIterable` do not need to manually specify ``ExpressibleByArgument/allValueStrings``. Instead, a list of possible values is derived from the type's cases, as in this updated example: +ExpressibleByArgument types that conform to `CaseIterable` do not need to manually specify `ExpressibleByArgument/allValueStrings`. Instead, a list of possible values is derived from the type's cases, as in this updated example: ```swift enum Fruit: String, CaseIterable, ExpressibleByArgument { @@ -128,7 +128,7 @@ enum Fruit: String, CaseIterable, ExpressibleByArgument { struct FruitStore: ParsableCommand { @Argument(help: "The fruit to purchase") var fruit: Fruit - + @Option(help: "The number of fruit to purchase") var quantity: Int = 1 } @@ -148,7 +148,7 @@ OPTIONS: -h, --help Show help information. ``` -For an ``ExpressibleByArgument`` and `CaseIterable` type with many cases, you may still want to implement ``ExpressibleByArgument/allValueStrings`` to avoid an overly long list of values appearing in the help screen. For these types it is recommended to include the most common possible values. +For an `ExpressibleByArgument` and `CaseIterable` type with many cases, you may still want to implement `ExpressibleByArgument/allValueStrings` to avoid an overly long list of values appearing in the help screen. For these types it is recommended to include the most common possible values. ## Providing Descriptions for Individual Enum Values @@ -161,16 +161,16 @@ To provide descriptions for individual enum values, implement a custom `defaultV ```swift enum LogLevel: String, CaseIterable, ExpressibleByArgument { case error - case warning + case warning case info case debug - + var defaultValueDescription: String { switch self { case .error: return "Show only error messages" case .warning: - return "Show warnings and errors" + return "Show warnings and errors" case .info: return "Show informational messages and above" case .debug: @@ -209,12 +209,12 @@ enum OutputFormat: String, CaseIterable, ExpressibleByArgument { case yaml case xml case csv - + var defaultValueDescription: String { switch self { case .json: return "JavaScript Object Notation format" - case .yaml: + case .yaml: return "YAML Ain't Markup Language format" case .xml: return "eXtensible Markup Language format" @@ -238,7 +238,7 @@ USAGE: data-exporter [--formats ...] OPTIONS: --formats Output formats to generate (default: json) json - JavaScript Object Notation format - yaml - YAML Ain't Markup Language format + yaml - YAML Ain't Markup Language format xml - eXtensible Markup Language format csv - Comma-Separated Values format -h, --help Show help information. @@ -254,7 +254,7 @@ enum CompressionAlgorithm: String, CaseIterable, ExpressibleByArgument { case bzip2 = "bzip2" case lzma = "lzma" case none = "none" - + var defaultValueDescription: String { switch self { case .gzip: @@ -275,25 +275,6 @@ struct Archive: ParsableCommand { } ``` -### Tips for Effective Enum Descriptions - -1. **Keep descriptions concise but informative** - Aim for one line that clearly explains the option's purpose or behavior. - -2. **Use consistent formatting** - Maintain a consistent style across all your descriptions (e.g., all sentences or all phrases). - -3. **Explain the impact** - Help users understand what choosing each option will do, not just what it is. - -4. **Order logically** - The descriptions appear in the same order as your enum cases, so consider ordering them by frequency of use or logical progression. - -5. **Only provide descriptions when helpful** - If your enum values are self-explanatory, you don't need custom descriptions. The system will only show the detailed format when descriptions differ from the raw values. - -The enum value descriptions feature works automatically with: -- Single enum options (`@Option var value: MyEnum`) -- Optional enum options (`@Option var value: MyEnum?`) -- Array enum options (`@Option var values: [MyEnum]`) -- Enum arguments (`@Argument var value: MyEnum`) -- Default values and value display formatting - ### Controlling Argument Visibility You can specify the visibility of any argument, option, or flag. @@ -308,7 +289,7 @@ struct Example: ParsableCommand { } ``` -The `--verbose` flag is only visible in the extended help screen. The `--use-legacy-format` stays hidden even in the extended help screen, due to its `.private` visibility. +The `--verbose` flag is only visible in the extended help screen. The `--use-legacy-format` stays hidden even in the extended help screen, due to its `.private` visibility. ``` % example --help @@ -325,7 +306,7 @@ OPTIONS: -h, --help Show help information. ``` -Alternatively, you can group multiple arguments, options, and flags together as part of a ``ParsableArguments`` type, and set the visibility when including them as an `@OptionGroup` property. +Alternatively, you can group multiple arguments, options, and flags together as part of a `ParsableArguments` type, and set the visibility when including them as an `@OptionGroup` property. ```swift struct ExperimentalFlags: ParsableArguments { @@ -364,7 +345,7 @@ OPTIONS: ### Grouping Arguments in the Help Screen -When you provide a title in an `@OptionGroup` declaration, that type's properties are grouped together under your title in the help screen. For example, this command bundles similar arguments together under a "Build Options" title: +When you provide a title in an `@OptionGroup` declaration, that type's properties are grouped together under your title in the help screen. For example, this command bundles similar arguments together under a "Build Options" title: ```swift struct BuildOptions: ParsableArguments { From c0672d945b3142e04dceaaed98c3feeea7837ced Mon Sep 17 00:00:00 2001 From: Louis Qian Date: Sat, 4 Oct 2025 12:59:47 -0700 Subject: [PATCH 3/3] doc: use the output format example for all variations. --- .../Articles/CustomizingHelp.md | 100 +++++++----------- 1 file changed, 41 insertions(+), 59 deletions(-) diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md b/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md index da06cac6b..66df5496e 100644 --- a/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md +++ b/Sources/ArgumentParser/Documentation.docc/Articles/CustomizingHelp.md @@ -159,43 +159,43 @@ When your argument or option uses an enum type, you can provide detailed descrip To provide descriptions for individual enum values, implement a custom `defaultValueDescription` property for each case. The ArgumentParser will automatically detect when descriptions differ from the enum's string representation and display them in an enumerated format. ```swift -enum LogLevel: String, CaseIterable, ExpressibleByArgument { - case error - case warning - case info - case debug +enum OutputFormat: String, CaseIterable, ExpressibleByArgument { + case json + case yaml + case xml + case csv var defaultValueDescription: String { switch self { - case .error: - return "Show only error messages" - case .warning: - return "Show warnings and errors" - case .info: - return "Show informational messages and above" - case .debug: - return "Show all messages including debug output" + case .json: + return "JavaScript Object Notation format" + case .yaml: + return "YAML Ain't Markup Language format" + case .xml: + return "eXtensible Markup Language format" + case .csv: + return "Comma-Separated Values format" } } } -struct Logger: ParsableCommand { - @Option(help: "Set the logging level") - var level: LogLevel = .info +struct DataExporter: ParsableCommand { + @Option(help: "Select output format") + var format: OutputFormat = .json } ``` This produces help output with detailed descriptions for each enum value: ``` -USAGE: logger [--level ] +USAGE: data-exporter [--format ] OPTIONS: - --level Set the logging level (default: info) - error - Show only error messages - warning - Show warnings and errors - info - Show informational messages and above - debug - Show all messages including debug output + --format Select output format (default: json) + json - JavaScript Object Notation format + yaml - YAML Ain't Markup Language format + xml - eXtensible Markup Language format + csv - Comma-Separated Values format -h, --help Show help information. ``` @@ -204,26 +204,6 @@ OPTIONS: The same enum value descriptions work seamlessly with array options, allowing users to understand each possible value when multiple selections are allowed: ```swift -enum OutputFormat: String, CaseIterable, ExpressibleByArgument { - case json - case yaml - case xml - case csv - - var defaultValueDescription: String { - switch self { - case .json: - return "JavaScript Object Notation format" - case .yaml: - return "YAML Ain't Markup Language format" - case .xml: - return "eXtensible Markup Language format" - case .csv: - return "Comma-Separated Values format" - } - } -} - struct DataExporter: ParsableCommand { @Option(help: "Output formats to generate") var formats: [OutputFormat] = [.json] @@ -246,35 +226,37 @@ OPTIONS: ### Working with Raw Values -For enums with custom raw values, the descriptions work with the raw value representation: +For enums with custom raw values, the descriptions work with the raw value representation. Here's the same `OutputFormat` enum with custom raw values: ```swift -enum CompressionAlgorithm: String, CaseIterable, ExpressibleByArgument { - case gzip = "gzip" - case bzip2 = "bzip2" - case lzma = "lzma" - case none = "none" +enum OutputFormat: String, CaseIterable, ExpressibleByArgument { + case json = "json" + case yaml = "yml" + case xml = "xml" + case csv = "csv" var defaultValueDescription: String { switch self { - case .gzip: - return "GNU zip compression (good speed, decent compression)" - case .bzip2: - return "Burrows-Wheeler compression (slower, better compression)" - case .lzma: - return "Lempel-Ziv-Markov compression (slowest, best compression)" - case .none: - return "No compression applied" + case .json: + return "JavaScript Object Notation format" + case .yaml: + return "YAML Ain't Markup Language format" + case .xml: + return "eXtensible Markup Language format" + case .csv: + return "Comma-Separated Values format" } } } -struct Archive: ParsableCommand { - @Option(help: "Compression algorithm to use") - var compression: CompressionAlgorithm = .gzip +struct DataExporter: ParsableCommand { + @Option(help: "Select output format") + var format: OutputFormat = .json } ``` +In this example, users would specify `--format yml` to get YAML output, but the help screen still shows the descriptive text. + ### Controlling Argument Visibility You can specify the visibility of any argument, option, or flag.