diff --git a/Sources/ArgumentParser/Parsable Types/ParsableArguments.swift b/Sources/ArgumentParser/Parsable Types/ParsableArguments.swift index be11770e..46db0cdc 100644 --- a/Sources/ArgumentParser/Parsable Types/ParsableArguments.swift +++ b/Sources/ArgumentParser/Parsable Types/ParsableArguments.swift @@ -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. diff --git a/Sources/ArgumentParser/Parsable Types/ParsableCommand.swift b/Sources/ArgumentParser/Parsable Types/ParsableCommand.swift index 2773c4ac..b0832a0d 100644 --- a/Sources/ArgumentParser/Parsable Types/ParsableCommand.swift +++ b/Sources/ArgumentParser/Parsable Types/ParsableCommand.swift @@ -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. /// diff --git a/Tests/ArgumentParserUnitTests/HelpGenerationTests.swift b/Tests/ArgumentParserUnitTests/HelpGenerationTests.swift index fbc1fb33..047eae80 100644 --- a/Tests/ArgumentParserUnitTests/HelpGenerationTests.swift +++ b/Tests/ArgumentParserUnitTests/HelpGenerationTests.swift @@ -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] [] @@ -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] """) - } - + @Argument var file: String @Flag var verboseMode = false } struct CustomUsageLong: ParsableCommand { - static var configuration: CommandConfiguration { - CommandConfiguration(usage: """ + static let configuration = CommandConfiguration( + usage: """ example example --verbose 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 [--verbose-mode] + + ARGUMENTS: + + + OPTIONS: + --verbose-mode + -h, --help Show help information. + + SUBCOMMANDS: + example-subcommand + + See 'non-custom-usage help ' for detailed help. + """) + + AssertEqualStrings( + actual: NonCustomUsage.helpMessage( + for: NonCustomUsage.ExampleSubcommand.self, columns: 80), + expected: """ + USAGE: non-custom-usage example-subcommand + + ARGUMENTS: + + + OPTIONS: + -h, --help Show help information. + + """) + + AssertEqualStrings( + actual: CustomUsageShort.helpMessage(columns: 80), + expected: """ USAGE: example [--verbose] ARGUMENTS: @@ -755,7 +800,9 @@ extension HelpGenerationTests { """) - XCTAssertEqual(CustomUsageLong.helpMessage(columns: 80), """ + AssertEqualStrings( + actual: CustomUsageLong.helpMessage(columns: 80), + expected: """ USAGE: example example --verbose example --help @@ -769,7 +816,9 @@ extension HelpGenerationTests { """) - XCTAssertEqual(CustomUsageHidden.helpMessage(columns: 80), """ + AssertEqualStrings( + actual: CustomUsageHidden.helpMessage(columns: 80), + expected: """ ARGUMENTS: @@ -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 [--verbose-mode] + See 'non-custom-usage --help' for more information. + """) + + AssertEqualStrings( + actual: CustomUsageShort.fullMessage(for: ValidationError("Test")), + expected: """ Error: Test Usage: example [--verbose] 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 example --verbose 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 [--verbose-mode] + """) + + AssertEqualStrings( + actual: NonCustomUsage.usageString( + for: NonCustomUsage.ExampleSubcommand.self), + expected: """ + non-custom-usage example-subcommand + """) + + AssertEqualStrings( + actual: CustomUsageShort.usageString(), + expected: """ + example [--verbose] + """) + + AssertEqualStrings( + actual: CustomUsageLong.usageString(), + expected: """ + example + example --verbose + example --help + """) + + AssertEqualStrings( + actual: CustomUsageHidden.usageString(), + expected: """ + """) + } } extension HelpGenerationTests {