Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Examples/math/Math.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ struct Math: ParsableCommand {
// Optional abstracts and discussions are used for help output.
abstract: "A utility for performing maths.",

// Extended discussion appears at the bottom of the help screen,
// after the list of subcommands.
extendedDiscussion: """
Examples:
math add 10 15 20
math multiply --hex-output 16 32
math stats average --kind median 5 8 12
""",

// Commands can define a version for automatic '--version' support.
version: "1.0.0",

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,41 @@ hello!
...
```

### Adding Extended Discussion

Use the `extendedDiscussion` parameter to provide additional information that
appears at the end of the help screen, after the list of arguments, options,
and subcommands. This keeps the quick-reference argument list near the top of
the help output.

```swift
struct Repeat: ParsableCommand {
static let configuration = CommandConfiguration(
abstract: "Repeats your input phrase.",
extendedDiscussion: """
Use CTRL-C to stop repeating when no count is given.
""")

// ...
}
```

```
% repeat --help
OVERVIEW: Repeats your input phrase.

USAGE: repeat [--count <count>] <phrase>

ARGUMENTS:
<phrase> The phrase to repeat.

OPTIONS:
--count <count> How many times to repeat.
-h, --help Show help information.

Use CTRL-C to stop repeating when no count is given.
```

### Modifying the Help Flag Names

Users can see the help screen for a command by passing either the `-h` or the `--help` flag, by default. If you need to use one of those flags for another purpose, you can provide alternative names when configuring a root command.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@

### Creating a Configuration

- ``init(commandName:abstract:usage:discussion:version:shouldDisplay:subcommands:groupedSubcommands:defaultSubcommand:helpNames:aliases:)``
- ``init(commandName:abstract:usage:discussion:extendedDiscussion:version:shouldDisplay:subcommands:groupedSubcommands:defaultSubcommand:helpNames:aliases:)``

### Customizing the Help Screen

- ``abstract``
- ``discussion``
- ``extendedDiscussion``
- ``usage``
- ``helpNames``

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ public struct CommandConfiguration: Sendable {
/// a static block of text that extends the description of the argument.
public var discussion: String

/// Additional information to be shown at the end of the help display,
/// after the list of arguments, options, and subcommands.
///
/// Use `extendedDiscussion` for information that supplements the quick
/// reference provided by the argument list, such as usage examples,
/// additional details, or notes about the command's behavior.
public var extendedDiscussion: String

/// Version information for this command.
public var version: String

Expand Down Expand Up @@ -97,6 +105,8 @@ public struct CommandConfiguration: Sendable {
/// automatically generating a usage description. Passing an empty string
/// hides the usage string altogether.
/// - discussion: A longer description of the command.
/// - extendedDiscussion: Additional information shown at the end of the
/// help display, after the argument, option, and subcommand lists.
/// - version: The version number for this command. When you provide a
/// non-empty string, the argument parser prints it if the user provides
/// a `--version` flag.
Expand All @@ -120,6 +130,7 @@ public struct CommandConfiguration: Sendable {
abstract: String = "",
usage: String? = nil,
discussion: String = "",
extendedDiscussion: String = "",
version: String = "",
shouldDisplay: Bool = true,
subcommands ungroupedSubcommands: [ParsableCommand.Type] = [],
Expand All @@ -132,6 +143,7 @@ public struct CommandConfiguration: Sendable {
self.abstract = abstract
self.usage = usage
self.discussion = discussion
self.extendedDiscussion = extendedDiscussion
self.version = version
self.shouldDisplay = shouldDisplay
self.ungroupedSubcommands = ungroupedSubcommands
Expand All @@ -149,6 +161,7 @@ public struct CommandConfiguration: Sendable {
abstract: String = "",
usage: String? = nil,
discussion: String = "",
extendedDiscussion: String = "",
version: String = "",
shouldDisplay: Bool = true,
subcommands ungroupedSubcommands: [ParsableCommand.Type] = [],
Expand All @@ -162,6 +175,7 @@ public struct CommandConfiguration: Sendable {
self.abstract = abstract
self.usage = usage
self.discussion = discussion
self.extendedDiscussion = extendedDiscussion
self.version = version
self.shouldDisplay = shouldDisplay
self.ungroupedSubcommands = ungroupedSubcommands
Expand All @@ -173,6 +187,74 @@ public struct CommandConfiguration: Sendable {
}

extension CommandConfiguration {
@available(
*, deprecated,
message:
"Use the memberwise initializer with the extendedDiscussion parameter."
)
public init(
commandName: String? = nil,
abstract: String = "",
usage: String? = nil,
discussion: String = "",
version: String = "",
shouldDisplay: Bool = true,
subcommands: [ParsableCommand.Type] = [],
groupedSubcommands: [CommandGroup] = [],
defaultSubcommand: ParsableCommand.Type? = nil,
helpNames: NameSpecification? = nil,
aliases: [String] = []
) {
self.init(
commandName: commandName,
abstract: abstract,
usage: usage,
discussion: discussion,
extendedDiscussion: "",
version: version,
shouldDisplay: shouldDisplay,
subcommands: subcommands,
groupedSubcommands: groupedSubcommands,
defaultSubcommand: defaultSubcommand,
helpNames: helpNames,
aliases: aliases)
}

@available(
*, deprecated,
message:
"Use the memberwise initializer with the extendedDiscussion parameter."
)
public init(
commandName: String? = nil,
_superCommandName: String,
abstract: String = "",
usage: String? = nil,
discussion: String = "",
version: String = "",
shouldDisplay: Bool = true,
subcommands: [ParsableCommand.Type] = [],
groupedSubcommands: [CommandGroup] = [],
defaultSubcommand: ParsableCommand.Type? = nil,
helpNames: NameSpecification? = nil,
aliases: [String] = []
) {
self.init(
commandName: commandName,
_superCommandName: _superCommandName,
abstract: abstract,
usage: usage,
discussion: discussion,
extendedDiscussion: "",
version: version,
shouldDisplay: shouldDisplay,
subcommands: subcommands,
groupedSubcommands: groupedSubcommands,
defaultSubcommand: defaultSubcommand,
helpNames: helpNames,
aliases: aliases)
}

@available(
*, deprecated,
message: "Use the memberwise initializer with the aliases parameter."
Expand All @@ -193,6 +275,7 @@ extension CommandConfiguration {
abstract: abstract,
usage: usage,
discussion: discussion,
extendedDiscussion: "",
version: version,
shouldDisplay: shouldDisplay,
subcommands: subcommands,
Expand Down Expand Up @@ -221,6 +304,7 @@ extension CommandConfiguration {
abstract: abstract,
usage: "",
discussion: discussion,
extendedDiscussion: "",
version: version,
shouldDisplay: shouldDisplay,
subcommands: subcommands,
Expand Down
1 change: 1 addition & 0 deletions Sources/ArgumentParser/Usage/DumpHelpGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ extension CommandInfoV0 {
aliases: command.configuration.aliases,
abstract: command.configuration.abstract,
discussion: command.configuration.discussion,
extendedDiscussion: command.configuration.extendedDiscussion,
defaultSubcommand: defaultSubcommand,
subcommands: subcommands,
arguments: arguments)
Expand Down
15 changes: 14 additions & 1 deletion Sources/ArgumentParser/Usage/HelpGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ internal struct HelpGenerator {
var abstract: String
var usage: String
var sections: [Section]
var extendedDiscussion: String

init(commandStack: [ParsableCommand.Type], visibility: ArgumentVisibility) {
guard let root = commandStack.first, let currentCommand = commandStack.last
Expand Down Expand Up @@ -191,6 +192,7 @@ internal struct HelpGenerator {

self.sections = HelpGenerator.generateSections(
commandStack: commandStack, visibility: visibility)
self.extendedDiscussion = currentCommand.configuration.extendedDiscussion
}

init(_ type: ParsableArguments.Type, visibility: ArgumentVisibility) {
Expand Down Expand Up @@ -408,6 +410,17 @@ internal struct HelpGenerator {
"""
}

let renderedExtendedDiscussion: String
if extendedDiscussion.isEmpty {
renderedExtendedDiscussion = ""
} else if helpSubcommandMessage.isEmpty {
renderedExtendedDiscussion =
"\n" + extendedDiscussion.wrapped(to: screenWidth)
} else {
renderedExtendedDiscussion =
"\n\n" + extendedDiscussion.wrapped(to: screenWidth)
}

let renderedUsage =
usage.isEmpty
? ""
Expand All @@ -416,7 +429,7 @@ internal struct HelpGenerator {
return """
\(renderedAbstract)\
\(renderedUsage)\
\(renderedSections)\(helpSubcommandMessage)
\(renderedSections)\(helpSubcommandMessage)\(renderedExtendedDiscussion)
"""
}
}
Expand Down
7 changes: 7 additions & 0 deletions Sources/ArgumentParserToolInfo/ToolInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ public struct CommandInfoV0: Codable, Hashable {
/// Extended description of the command's functionality.
public var discussion: String?

/// Additional information shown at the end of help, after the argument list.
public var extendedDiscussion: String?

/// Optional name of the subcommand invoked when the command is invoked with
/// no arguments.
public var defaultSubcommand: String?
Expand All @@ -71,6 +74,7 @@ public struct CommandInfoV0: Codable, Hashable {
aliases: [String]?,
abstract: String,
discussion: String,
extendedDiscussion: String,
defaultSubcommand: String?,
subcommands: [CommandInfoV0],
arguments: [ArgumentInfoV0]
Expand All @@ -82,6 +86,7 @@ public struct CommandInfoV0: Codable, Hashable {
self.aliases = aliases?.nonEmpty
self.abstract = abstract.nonEmpty
self.discussion = discussion.nonEmpty
self.extendedDiscussion = extendedDiscussion.nonEmpty

self.defaultSubcommand = defaultSubcommand?.nonEmpty
self.subcommands = subcommands.nonEmpty
Expand All @@ -99,6 +104,8 @@ public struct CommandInfoV0: Codable, Hashable {
String.self, forKey: .abstract)
self.discussion = try container.decodeIfPresent(
String.self, forKey: .discussion)
self.extendedDiscussion = try container.decodeIfPresent(
String.self, forKey: .extendedDiscussion)
self.shouldDisplay =
try container.decodeIfPresent(Bool.self, forKey: .shouldDisplay) ?? true
self.defaultSubcommand = try container.decodeIfPresent(
Expand Down
5 changes: 5 additions & 0 deletions Tests/ArgumentParserExampleTests/MathExampleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ final class MathExampleTests: XCTestCase {

See 'math help <subcommand>' for detailed help.

Examples:
math add 10 15 20
math multiply --hex-output 16 32
math stats average --kind median 5 8 12

"""

try AssertExecuteCommand(command: "math -h", expected: helpText)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,4 +227,9 @@ math help [<subcommands>...] [--version]



Examples:
math add 10 15 20
math multiply --hex-output 16 32
math stats average --kind median 5 8 12


Original file line number Diff line number Diff line change
Expand Up @@ -223,4 +223,9 @@ math help [<subcommands>...] [--version]



Examples:
math add 10 15 20
math multiply --hex-output 16 32
math stats average --kind median 5 8 12


Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ Show the version.
.It Fl h , -help
Show help information.
.El
.Pp
Examples:
math add 10 15 20
math multiply --hex-output 16 32
math stats average --kind median 5 8 12
.Sh "SEE ALSO"
.Xr math.add 9 ,
.Xr math.help 9 ,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ Show subcommand help information.
Show the version.
.El
.El
.Pp
Examples:
math add 10 15 20
math multiply --hex-output 16 32
math stats average --kind median 5 8 12
.Sh AUTHORS
The
.Nm
Expand Down
14 changes: 14 additions & 0 deletions Tests/ArgumentParserUnitTests/DumpHelpGenerationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ final class DumpHelpGenerationTests: XCTestCase {
func testMathStatsDumpHelp() throws {
try assertDumpHelp(command: "math stats")
}

func testExtendedDiscussionDumpHelp() throws {
try assertDumpHelp(type: ExtendedDiscussionCommand.self)
}
}

extension DumpHelpGenerationTests {
Expand Down Expand Up @@ -128,4 +132,14 @@ extension DumpHelpGenerationTests {
@Option(help: .init(discussion: "A discussion."))
var discussion: String
}

struct ExtendedDiscussionCommand: ParsableCommand {
static let configuration = CommandConfiguration(
abstract: "A command with extended discussion.",
discussion: "Top-level discussion.",
extendedDiscussion: "Additional info after the options.")

@Option(help: "A name.")
var name: String
}
}
Loading
Loading