Add ParsableArguments/Command.usageString (#634)

Adds a new API to ParsableArguments and ParsableCommand for getting the
usage string. This allows clients to use argument-parser in a more
piecemeal way to construct their own error screens.
This commit is contained in:
Rauhul Varma
2024-04-30 17:12:01 -07:00
committed by GitHub
parent 2b962934d1
commit cfac15f2cd
3 changed files with 149 additions and 22 deletions
@@ -231,6 +231,18 @@ extension ParsableArguments {
exit(withError: error)
}
}
/// Returns the usage text for this type.
///
/// - Parameters:
/// - includeHidden: Include hidden help information in the generated
/// message.
/// - Returns: The usage text for this type.
public static func usageString(
includeHidden: Bool = false
) -> String {
HelpGenerator(self, visibility: includeHidden ? .hidden : .default).usage
}
}
/// Unboxes the given value if it is a `nil` value.
@@ -113,6 +113,22 @@ extension ParsableCommand {
.rendered(screenWidth: columns)
}
/// Returns the usage text for the given subcommand of this command.
///
/// - Parameters:
/// - includeHidden: Include hidden help information in the generated
/// message.
/// - Returns: The usage text for this type.
public static func usageString(
for subcommand: ParsableCommand.Type,
includeHidden: Bool = false
) -> String {
HelpGenerator(
commandStack: CommandParser(self).commandStack(for: subcommand),
visibility: includeHidden ? .hidden : .default)
.usage
}
/// Executes this command, or one of its subcommands, with the given
/// arguments.
///
@@ -680,7 +680,7 @@ extension HelpGenerationTests {
static let configuration = CommandConfiguration(
commandName: "parserBug",
subcommands: [Sub.self])
struct CommonOptions: ParsableCommand {
@Flag(help: "example flag")
var example: Bool = false
@@ -689,12 +689,12 @@ extension HelpGenerationTests {
struct Sub: ParsableCommand {
@OptionGroup()
var commonOptions: CommonOptions
@Argument(help: "Non-mandatory argument")
var argument: String?
}
}
func testIssue278() {
AssertHelp(.default, for: ParserBug.Sub.self, root: ParserBug.self, equals: """
USAGE: parserBug sub [--example] [<argument>]
@@ -708,42 +708,87 @@ extension HelpGenerationTests {
""")
}
}
extension HelpGenerationTests {
struct NonCustomUsage: ParsableCommand {
struct ExampleSubcommand: ParsableCommand {
static let configuration = CommandConfiguration()
@Argument var output: String
}
static let configuration = CommandConfiguration(
subcommands: [ExampleSubcommand.self])
@Argument var file: String
@Flag var verboseMode = false
}
struct CustomUsageShort: ParsableCommand {
static var configuration: CommandConfiguration {
CommandConfiguration(usage: """
static let configuration = CommandConfiguration(
usage: """
example [--verbose] <file-name>
""")
}
@Argument var file: String
@Flag var verboseMode = false
}
struct CustomUsageLong: ParsableCommand {
static var configuration: CommandConfiguration {
CommandConfiguration(usage: """
static let configuration = CommandConfiguration(
usage: """
example <file-name>
example --verbose <file-name>
example --help
""")
}
@Argument var file: String
@Flag var verboseMode = false
}
struct CustomUsageHidden: ParsableCommand {
static var configuration: CommandConfiguration {
CommandConfiguration(usage: "")
}
static let configuration = CommandConfiguration(usage: "")
@Argument var file: String
@Flag var verboseMode = false
}
func testCustomUsageHelp() {
XCTAssertEqual(CustomUsageShort.helpMessage(columns: 80), """
func test_usageCustomization_helpMessage() {
AssertEqualStrings(
actual: NonCustomUsage.helpMessage(columns: 80),
expected: """
USAGE: non-custom-usage <file> [--verbose-mode] <subcommand>
ARGUMENTS:
<file>
OPTIONS:
--verbose-mode
-h, --help Show help information.
SUBCOMMANDS:
example-subcommand
See 'non-custom-usage help <subcommand>' for detailed help.
""")
AssertEqualStrings(
actual: NonCustomUsage.helpMessage(
for: NonCustomUsage.ExampleSubcommand.self, columns: 80),
expected: """
USAGE: non-custom-usage example-subcommand <output>
ARGUMENTS:
<output>
OPTIONS:
-h, --help Show help information.
""")
AssertEqualStrings(
actual: CustomUsageShort.helpMessage(columns: 80),
expected: """
USAGE: example [--verbose] <file-name>
ARGUMENTS:
@@ -755,7 +800,9 @@ extension HelpGenerationTests {
""")
XCTAssertEqual(CustomUsageLong.helpMessage(columns: 80), """
AssertEqualStrings(
actual: CustomUsageLong.helpMessage(columns: 80),
expected: """
USAGE: example <file-name>
example --verbose <file-name>
example --help
@@ -769,7 +816,9 @@ extension HelpGenerationTests {
""")
XCTAssertEqual(CustomUsageHidden.helpMessage(columns: 80), """
AssertEqualStrings(
actual: CustomUsageHidden.helpMessage(columns: 80),
expected: """
ARGUMENTS:
<file>
@@ -780,24 +829,74 @@ extension HelpGenerationTests {
""")
}
func testCustomUsageError() {
XCTAssertEqual(CustomUsageShort.fullMessage(for: ValidationError("Test")), """
func test_usageCustomization_fullMessage() {
AssertEqualStrings(
actual: NonCustomUsage.fullMessage(for: ValidationError("Test")),
expected: """
Error: Test
Usage: non-custom-usage <file> [--verbose-mode] <subcommand>
See 'non-custom-usage --help' for more information.
""")
AssertEqualStrings(
actual: CustomUsageShort.fullMessage(for: ValidationError("Test")),
expected: """
Error: Test
Usage: example [--verbose] <file-name>
See 'custom-usage-short --help' for more information.
""")
XCTAssertEqual(CustomUsageLong.fullMessage(for: ValidationError("Test")), """
AssertEqualStrings(
actual: CustomUsageLong.fullMessage(for: ValidationError("Test")),
expected: """
Error: Test
Usage: example <file-name>
example --verbose <file-name>
example --help
See 'custom-usage-long --help' for more information.
""")
XCTAssertEqual(CustomUsageHidden.fullMessage(for: ValidationError("Test")), """
AssertEqualStrings(
actual: CustomUsageHidden.fullMessage(for: ValidationError("Test")),
expected: """
Error: Test
See 'custom-usage-hidden --help' for more information.
""")
}
func test_usageCustomization_usageString() {
AssertEqualStrings(
actual: NonCustomUsage.usageString(),
expected: """
non-custom-usage <file> [--verbose-mode] <subcommand>
""")
AssertEqualStrings(
actual: NonCustomUsage.usageString(
for: NonCustomUsage.ExampleSubcommand.self),
expected: """
non-custom-usage example-subcommand <output>
""")
AssertEqualStrings(
actual: CustomUsageShort.usageString(),
expected: """
example [--verbose] <file-name>
""")
AssertEqualStrings(
actual: CustomUsageLong.usageString(),
expected: """
example <file-name>
example --verbose <file-name>
example --help
""")
AssertEqualStrings(
actual: CustomUsageHidden.usageString(),
expected: """
""")
}
}
extension HelpGenerationTests {