diff --git a/Sources/ArgumentParser/Documentation.docc/Articles/CommandsAndSubcommands.md b/Sources/ArgumentParser/Documentation.docc/Articles/CommandsAndSubcommands.md index 5e341e92a..0c16cf403 100644 --- a/Sources/ArgumentParser/Documentation.docc/Articles/CommandsAndSubcommands.md +++ b/Sources/ArgumentParser/Documentation.docc/Articles/CommandsAndSubcommands.md @@ -131,7 +131,7 @@ extension Math.Statistics { abstract: "Print the average of the values.", aliases: ["avg"]) - enum Kind: String, ExpressibleByArgument { + enum Kind: String, ExpressibleByArgument, CaseIterable { case mean, median, mode } diff --git a/Sources/ArgumentParser/Usage/HelpGenerator.swift b/Sources/ArgumentParser/Usage/HelpGenerator.swift index 719ecd250..060ca4b96 100644 --- a/Sources/ArgumentParser/Usage/HelpGenerator.swift +++ b/Sources/ArgumentParser/Usage/HelpGenerator.swift @@ -114,9 +114,9 @@ internal struct HelpGenerator { } else { var usage = UsageGenerator(toolName: toolName, definition: [currentArgSet]) .synopsis - if !currentCommand.configuration.subcommands.isEmpty { + if !currentCommand.configuration.subcommands.isEmpty { if usage.last != " " { usage += " " } - usage += "" + usage += "" } self.usage = usage } diff --git a/Sources/ArgumentParser/Usage/UsageGenerator.swift b/Sources/ArgumentParser/Usage/UsageGenerator.swift index e34b94ee6..19076dba3 100644 --- a/Sources/ArgumentParser/Usage/UsageGenerator.swift +++ b/Sources/ArgumentParser/Usage/UsageGenerator.swift @@ -104,7 +104,12 @@ extension ArgumentDefinition { switch update { case .unary: - return "\(name.synopsisString) <\(valueName)>" + let joinedValues = help.allValueStrings.joined(separator: "|") + if help.allValueStrings.count > 1 && joinedValues.count <= 40 { + return "\(name.synopsisString) <\(joinedValues)>" + } else { + return "\(name.synopsisString) <\(valueName)>" + } case .nullary: return name.synopsisString } diff --git a/Tests/ArgumentParserExampleTests/MathExampleTests.swift b/Tests/ArgumentParserExampleTests/MathExampleTests.swift index ee677a6a0..c0bc147fe 100644 --- a/Tests/ArgumentParserExampleTests/MathExampleTests.swift +++ b/Tests/ArgumentParserExampleTests/MathExampleTests.swift @@ -73,11 +73,33 @@ final class MathExampleTests: XCTestCase { try AssertExecuteCommand(command: "math help add --help", expected: helpText) } + func testMath_StatsHelp() throws { + let helpText = """ + OVERVIEW: Calculate descriptive statistics. + + USAGE: math stats + + OPTIONS: + --version Show the version. + -h, --help Show help information. + + SUBCOMMANDS: + average, avg 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. + """ + try AssertExecuteCommand(command: "math stats -h", expected: helpText) + try AssertExecuteCommand(command: "math stats --help", expected: helpText) + try AssertExecuteCommand(command: "math help stats", expected: helpText) + } + func testMath_StatsMeanHelp() throws { let helpText = """ OVERVIEW: Print the average of the values. - USAGE: math stats average [--kind ] [ ...] + USAGE: math stats average [--kind ] [ ...] ARGUMENTS: A group of floating-point values to operate on. @@ -128,7 +150,7 @@ final class MathExampleTests: XCTestCase { command: "math stats average --kind mode", expected: """ Error: Please provide at least one value to calculate the mode. - Usage: math stats average [--kind ] [ ...] + Usage: math stats average [--kind ] [ ...] See 'math stats average --help' for more information. """, exitCode: .validationFailure) diff --git a/Tests/ArgumentParserUnitTests/HelpGenerationTests+ExpandedSynopses.swift b/Tests/ArgumentParserUnitTests/HelpGenerationTests+ExpandedSynopses.swift new file mode 100644 index 000000000..1d11ed97a --- /dev/null +++ b/Tests/ArgumentParserUnitTests/HelpGenerationTests+ExpandedSynopses.swift @@ -0,0 +1,68 @@ +//===----------------------------------------------------------*- swift -*-===// +// +// This source file is part of the Swift Argument Parser open source project +// +// Copyright (c) 2024 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 XCTest +import ArgumentParserTestHelpers +@testable import ArgumentParser + +extension HelpGenerationTests { + enum Fruit: String, ExpressibleByArgument, CaseIterable { + case apple, banana, coconut, dragonFruit = "dragon-fruit", elderberry, fig, grape, honeydew + } + + enum Action: String, ExpressibleByArgument, CaseIterable { + case purchase, sample, refund = "return" + } + + enum Count: Int, ExpressibleByArgument, CaseIterable { + case zero, one, two, three, four, five, six, seven, eight, nine, ten, eleven, twelve, thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty + } + + enum Ripeness: String, ExpressibleByArgument, CaseIterable { + case under, perfect, over + } + + struct FruitStore: ParsableArguments { + @Argument(help: "The transaction type") + var action: Action = .purchase + + @Argument(help: "The fruit to purchase") + var fruit: Fruit + + @Option(help: "The number of fruit to purchase") + var quantity: Count = .one + + @Option(help: "The desired ripeness of fruit") + var ripeness: Ripeness = .perfect + } + + func testFruitStoreHelp() { + AssertHelp(.default, for: FruitStore.self, equals: """ + USAGE: fruit_store [] [--quantity ] [--ripeness ] + + ARGUMENTS: + The transaction type (values: purchase, sample, + return; default: purchase) + The fruit to purchase (values: apple, banana, + coconut, dragon-fruit, elderberry, fig, grape, + honeydew) + + OPTIONS: + --quantity The number of fruit to purchase (values: 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20; default: 1) + --ripeness The desired ripeness of fruit (values: under, + perfect, over; default: perfect) + -h, --help Show help information. + + """) + } +} diff --git a/Tests/ArgumentParserUnitTests/HelpGenerationTests.swift b/Tests/ArgumentParserUnitTests/HelpGenerationTests.swift index e7a4f0408..e82a40d59 100644 --- a/Tests/ArgumentParserUnitTests/HelpGenerationTests.swift +++ b/Tests/ArgumentParserUnitTests/HelpGenerationTests.swift @@ -197,7 +197,7 @@ extension HelpGenerationTests { func testHelpWithDefaultValues() { AssertHelp(.default, for: D.self, equals: """ - USAGE: d [] [--name ] [--age ] [--logging ] [--lucky ...] [--optional] [--required] [--degree ] [--directory ] [--manual ] [--unspecial ] [--special ] + USAGE: d [] [--name ] [--age ] [--logging ] [--lucky ...] [--optional] [--required] [--degree ] [--directory ] [--manual ] [--unspecial <0|1>] [--special ] ARGUMENTS: Your occupation. (default: --)