Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix default display in help for EnumerableFlag and other types #486

Merged
merged 6 commits into from Sep 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 34 additions & 7 deletions Sources/ArgumentParser/Parsable Properties/Flag.swift
Expand Up @@ -391,25 +391,52 @@ extension Flag where Value: EnumerableFlag {
// This gets flipped to `true` the first time one of these flags is
// encountered.
var hasUpdated = false
let defaultValue = initial.map(String.init(describing:))

// Create a string representation of the default value. Since this is a
// flag, the default value to show to the user is the `--value-name`
// flag that a user would provide on the command line, not a Swift value.
let defaultValueFlag = initial.flatMap { value in
let defaultKey = InputKey(rawValue: String(describing: value))
let defaultNames = Value.name(for: value).makeNames(defaultKey)
return defaultNames.first?.synopsisString
}

let caseHelps = Value.allCases.map { Value.help(for: $0) }
let hasCustomCaseHelp = caseHelps.contains(where: { $0 != nil })

let args = Value.allCases.enumerated().map { (i, value) -> ArgumentDefinition in
let caseKey = InputKey(rawValue: String(describing: value))
let name = Value.name(for: value)
let helpForCase = hasCustomCaseHelp ? (caseHelps[i] ?? help) : help

let helpForCase = caseHelps[i] ?? help
var defaultValueString: String? = nil
if hasCustomCaseHelp {
if value == initial {
defaultValueString = defaultValueFlag
}
} else {
defaultValueString = defaultValueFlag
}

let help = ArgumentDefinition.Help(
allValues: [],
options: initial != nil ? [.isOptional] : [],
options: initial != nil ? .isOptional : [],
help: helpForCase,
defaultValue: defaultValue,
defaultValue: defaultValueString,
key: key,
isComposite: !hasCustomCaseHelp)
return ArgumentDefinition.flag(name: name, key: key, caseKey: caseKey, help: help, parsingStrategy: .default, initialValue: initial, update: .nullary({ (origin, name, values) in
hasUpdated = try ArgumentSet.updateFlag(key: key, value: value, origin: origin, values: &values, hasUpdated: hasUpdated, exclusivity: exclusivity)
}))

return ArgumentDefinition.flag(
name: name,
key: key,
caseKey: caseKey,
help: help,
parsingStrategy: .default,
initialValue: initial,
update: .nullary({ (origin, name, values) in
hasUpdated = try ArgumentSet.updateFlag(key: key, value: value, origin: origin, values: &values, hasUpdated: hasUpdated, exclusivity: exclusivity)
})
)
}
return ArgumentSet(args)
})
Expand Down
9 changes: 6 additions & 3 deletions Sources/ArgumentParser/Parsing/ArgumentSet.swift
Expand Up @@ -122,12 +122,15 @@ extension ArgumentSet {
help: ArgumentHelp?) -> ArgumentSet
{
let helpOptions: ArgumentDefinition.Help.Options = required ? [] : .isOptional

let (enableNames, disableNames) = inversion.enableDisableNamePair(for: key, name: name)
let initialValueNames = initialValue.map {
$0 ? enableNames : disableNames
}

let enableHelp = ArgumentDefinition.Help(allValues: [], options: helpOptions, help: help, defaultValue: initialValue.map(String.init), key: key, isComposite: true)
let enableHelp = ArgumentDefinition.Help(allValues: [], options: helpOptions, help: help, defaultValue: initialValueNames?.first?.synopsisString, key: key, isComposite: true)
let disableHelp = ArgumentDefinition.Help(allValues: [], options: [.isOptional], help: help, defaultValue: nil, key: key, isComposite: false)

let (enableNames, disableNames) = inversion.enableDisableNamePair(for: key, name: name)

var hasUpdated = false
let enableArg = ArgumentDefinition(kind: .named(enableNames), help: enableHelp, completion: .default, update: .nullary({ (origin, name, values) in
hasUpdated = try ArgumentSet.updateFlag(key: key, value: true, origin: origin, values: &values, hasUpdated: hasUpdated, exclusivity: exclusivity)
Expand Down
25 changes: 21 additions & 4 deletions Tests/ArgumentParserEndToEndTests/FlagsEndToEndTests.swift
Expand Up @@ -162,11 +162,11 @@ enum Size: String, EnumerableFlag {
static func help(for value: Size) -> ArgumentHelp? {
switch value {
case .small:
return "A smallish size"
return "A smallish size."
case .medium:
return "Not too big, not too small"
return "Not too big, not too small."
case .humongous:
return "Roughly the size of a barge"
return "Roughly the size of a barge."
case .large, .extraLarge:
return nil
}
Expand All @@ -183,7 +183,7 @@ fileprivate struct Baz: ParsableArguments {
@Flag()
var color: Color

@Flag
@Flag(help: "The size to use.")
var size: Size = .small

@Flag()
Expand Down Expand Up @@ -257,6 +257,23 @@ extension FlagsEndToEndTests {
}
}

func testParsingCaseIterable_Help() throws {
AssertHelp(.default, for: Baz.self, equals: """
USAGE: baz --pink --purple --silver [--small] [--medium] [--large] [--extra-large] [--humongous] [--round] [--square] [--oblong]

OPTIONS:
--pink/--purple/--silver
-s, --small A smallish size. (default: --small)
-m, --medium Not too big, not too small.
-l, --large The size to use.
--extra-large The size to use.
--humongous, --huge Roughly the size of a barge.
--round/--square/--oblong
-h, --help Show help information.

""")
}

func testParsingCaseIterable_Fails() throws {
// Missing color
XCTAssertThrowsError(try Baz.parse([]))
Expand Down
17 changes: 10 additions & 7 deletions Tests/ArgumentParserPackageManagerTests/HelpTests.swift
Expand Up @@ -119,21 +119,24 @@ extension HelpTests {
Build with configuration (default: debug)
--enable-automatic-resolution/--disable-automatic-resolution
Use automatic resolution if Package.resolved file is
out-of-date (default: true)
out-of-date (default: --enable-automatic-resolution)
--enable-index-store/--disable-index-store
Use indexing-while-building feature (default: true)
Use indexing-while-building feature (default:
--enable-index-store)
--enable-package-manifest-caching/--disable-package-manifest-caching
Cache Package.swift manifests (default: true)
Cache Package.swift manifests (default:
--enable-package-manifest-caching)
--enable-prefetching/--disable-prefetching
(default: true)
(default: --enable-prefetching)
--enable-sandbox/--disable-sandbox
Use sandbox when executing subprocesses (default:
true)
--enable-sandbox)
--enable-pubgrub-resolver/--disable-pubgrub-resolver
[Experimental] Enable the new Pubgrub dependency
resolver (default: false)
resolver (default: --disable-pubgrub-resolver)
--static-swift-stdlib/--no-static-swift-stdlib
Link Swift stdlib statically (default: false)
Link Swift stdlib statically (default:
--no-static-swift-stdlib)
--package-path <package-path>
Change working directory before any other operation
(default: .)
Expand Down
8 changes: 4 additions & 4 deletions Tests/ArgumentParserUnitTests/HelpGenerationTests.swift
Expand Up @@ -84,7 +84,7 @@ extension HelpGenerationTests {
--hidden-title <hidden-title>
--hidden-flag
--hidden-inverted-flag/--no-hidden-inverted-flag
(default: true)
(default: --hidden-inverted-flag)
-h, --help Show help information.

""")
Expand Down Expand Up @@ -207,7 +207,7 @@ extension HelpGenerationTests {
--age <age> Your age. (default: 20)
--logging <logging> Whether logging is enabled. (default: false)
--lucky <numbers> Your lucky numbers. (default: 7, 14)
--optional/--required Vegan diet. (default: optional)
--optional/--required Vegan diet. (default: --optional)
--degree <degree> Your degree.
--directory <directory> Directory. (default: current directory)
--manual <manual> Manual Option. (default: default-value)
Expand Down Expand Up @@ -264,7 +264,7 @@ extension HelpGenerationTests {
USAGE: f [-s] [-c] [-l]

OPTIONS:
-s/-c/-l Change the program output (default: list)
-s/-c/-l Change the program output (default: -l)
-h, --help Show help information.

""")
Expand All @@ -273,7 +273,7 @@ extension HelpGenerationTests {
USAGE: g [--flag] [--no-flag]

OPTIONS:
--flag/--no-flag Whether to flag (default: false)
--flag/--no-flag Whether to flag (default: --no-flag)
-h, --help Show help information.

""")
Expand Down