Skip to content

Commit ae645fb

Browse files
committed
WIP: supplemental discussion
- IDEA: additional discussion for commands and arguments which is exported to dump-help and can be consumed by supplemental content generators to contains much more detailed information than you may want to include in a help screen. Maybe a better idea would be to have --help-detailed flag that would include this information in the help output. Suggestions are welcome.
1 parent f94e4b9 commit ae645fb

File tree

10 files changed

+181
-53
lines changed

10 files changed

+181
-53
lines changed

Sources/ArgumentParser/Parsable Properties/ArgumentHelp.swift

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ public struct ArgumentHelp {
1616

1717
/// An expanded description of the argument, in plain text form.
1818
public var discussion: String = ""
19-
19+
20+
/// Additional description of the argument for supplemental content, in plain
21+
/// text form.
22+
public var supplementalDiscussion: String = ""
23+
2024
/// An alternative name to use for the argument's value when showing usage
2125
/// information.
2226
///
@@ -28,41 +32,17 @@ public struct ArgumentHelp {
2832
/// the extended help display.
2933
public var visibility: ArgumentVisibility = .default
3034

31-
/// A Boolean value indicating whether this argument should be shown in
32-
/// the extended help display.
33-
@available(*, deprecated, message: "Use visibility level instead.")
34-
public var shouldDisplay: Bool {
35-
get {
36-
return visibility.base == .default
37-
}
38-
set {
39-
visibility = newValue ? .default : .hidden
40-
}
41-
}
42-
43-
/// Creates a new help instance.
44-
@available(*, deprecated, message: "Use init(_:discussion:valueName:visibility:) instead.")
45-
public init(
46-
_ abstract: String = "",
47-
discussion: String = "",
48-
valueName: String? = nil,
49-
shouldDisplay: Bool)
50-
{
51-
self.abstract = abstract
52-
self.discussion = discussion
53-
self.valueName = valueName
54-
self.shouldDisplay = shouldDisplay
55-
}
56-
5735
/// Creates a new help instance.
5836
public init(
5937
_ abstract: String = "",
6038
discussion: String = "",
39+
supplementalDiscussion: String = "",
6140
valueName: String? = nil,
6241
visibility: ArgumentVisibility = .default)
6342
{
6443
self.abstract = abstract
6544
self.discussion = discussion
45+
self.supplementalDiscussion = supplementalDiscussion
6646
self.valueName = valueName
6747
self.visibility = visibility
6848
}
@@ -83,3 +63,34 @@ extension ArgumentHelp: ExpressibleByStringInterpolation {
8363
self.abstract = value
8464
}
8565
}
66+
67+
// MARK: - Deprecated API
68+
extension ArgumentHelp {
69+
/// A Boolean value indicating whether this argument should be shown in
70+
/// the extended help display.
71+
@available(*, deprecated, message: "Use visibility level instead.")
72+
public var shouldDisplay: Bool {
73+
get {
74+
return visibility.base == .default
75+
}
76+
set {
77+
visibility = newValue ? .default : .hidden
78+
}
79+
}
80+
81+
/// Creates a new help instance.
82+
@available(*, deprecated, message: "Use init(_:discussion:supplementalDiscussion:valueName:visibility:) instead.")
83+
public init(
84+
_ abstract: String = "",
85+
discussion: String = "",
86+
valueName: String? = nil,
87+
shouldDisplay: Bool)
88+
{
89+
self.init(
90+
abstract,
91+
discussion: discussion,
92+
supplementalDiscussion: "",
93+
valueName: valueName,
94+
visibility: shouldDisplay ? .default : .hidden)
95+
}
96+
}

Sources/ArgumentParser/Parsable Types/CommandConfiguration.swift

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ public struct CommandConfiguration {
3838
/// A longer description of this command, to be shown in the extended help
3939
/// display.
4040
public var discussion: String
41+
42+
/// Additional description of this command to be shown in supplemental content
43+
/// such as manuals.
44+
public var supplementalDiscussion: String
4145

4246
/// Version information for this command.
4347
public var version: String
@@ -67,6 +71,8 @@ public struct CommandConfiguration {
6771
/// automatically generating a usage description. Passing an empty string
6872
/// hides the usage string altogether.
6973
/// - discussion: A longer description of the command.
74+
/// - supplementalDiscussion: Additional description of the command for
75+
/// supplemental content.
7076
/// - version: The version number for this command. When you provide a
7177
/// non-empty string, the argument parser prints it if the user provides
7278
/// a `--version` flag.
@@ -85,6 +91,7 @@ public struct CommandConfiguration {
8591
abstract: String = "",
8692
usage: String? = nil,
8793
discussion: String = "",
94+
supplementalDiscussion: String = "",
8895
version: String = "",
8996
shouldDisplay: Bool = true,
9097
subcommands: [ParsableCommand.Type] = [],
@@ -95,6 +102,7 @@ public struct CommandConfiguration {
95102
self.abstract = abstract
96103
self.usage = usage
97104
self.discussion = discussion
105+
self.supplementalDiscussion = supplementalDiscussion
98106
self.version = version
99107
self.shouldDisplay = shouldDisplay
100108
self.subcommands = subcommands
@@ -110,6 +118,7 @@ public struct CommandConfiguration {
110118
abstract: String = "",
111119
usage: String? = nil,
112120
discussion: String = "",
121+
supplementalDiscussion: String = "",
113122
version: String = "",
114123
shouldDisplay: Bool = true,
115124
subcommands: [ParsableCommand.Type] = [],
@@ -121,6 +130,7 @@ public struct CommandConfiguration {
121130
self.abstract = abstract
122131
self.usage = usage
123132
self.discussion = discussion
133+
self.supplementalDiscussion = ""
124134
self.version = version
125135
self.shouldDisplay = shouldDisplay
126136
self.subcommands = subcommands
@@ -130,7 +140,7 @@ public struct CommandConfiguration {
130140
}
131141

132142
extension CommandConfiguration {
133-
@available(*, deprecated, message: "Use the memberwise initializer with the usage parameter.")
143+
@available(*, deprecated, message: "Use the member-wise initializer with the usage parameter.")
134144
public init(
135145
commandName: String?,
136146
abstract: String,
@@ -146,6 +156,32 @@ extension CommandConfiguration {
146156
abstract: abstract,
147157
usage: "",
148158
discussion: discussion,
159+
supplementalDiscussion: "",
160+
version: version,
161+
shouldDisplay: shouldDisplay,
162+
subcommands: subcommands,
163+
defaultSubcommand: defaultSubcommand,
164+
helpNames: helpNames)
165+
}
166+
167+
@available(*, deprecated, message: "Use the member-wise initializer with the extendedDiscussion parameter.")
168+
public init(
169+
commandName: String?,
170+
abstract: String,
171+
usage: String,
172+
discussion: String,
173+
version: String,
174+
shouldDisplay: Bool,
175+
subcommands: [ParsableCommand.Type],
176+
defaultSubcommand: ParsableCommand.Type?,
177+
helpNames: NameSpecification?
178+
) {
179+
self.init(
180+
commandName: commandName,
181+
abstract: abstract,
182+
usage: usage,
183+
discussion: discussion,
184+
supplementalDiscussion: "",
149185
version: version,
150186
shouldDisplay: shouldDisplay,
151187
subcommands: subcommands,

Sources/ArgumentParser/Parsing/ArgumentDefinition.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ struct ArgumentDefinition {
5252
var isComposite: Bool
5353
var abstract: String
5454
var discussion: String
55+
var supplementalDiscussion: String
5556
var valueName: String
5657
var visibility: ArgumentVisibility
5758
var parentTitle: String
@@ -71,6 +72,7 @@ struct ArgumentDefinition {
7172
self.isComposite = isComposite
7273
self.abstract = help?.abstract ?? ""
7374
self.discussion = help?.discussion ?? ""
75+
self.supplementalDiscussion = help?.supplementalDiscussion ?? ""
7476
self.valueName = help?.valueName ?? ""
7577
self.visibility = help?.visibility ?? .default
7678
self.parentTitle = ""

Sources/ArgumentParser/Usage/DumpHelpGenerator.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ fileprivate extension CommandInfoV0 {
114114
commandName: command._commandName,
115115
abstract: command.configuration.abstract,
116116
discussion: command.configuration.discussion,
117+
supplementalDiscussion: command.configuration.supplementalDiscussion,
117118
defaultSubcommand: defaultSubcommand,
118119
subcommands: subcommands,
119120
arguments: arguments)
@@ -135,7 +136,8 @@ fileprivate extension ArgumentInfoV0 {
135136
defaultValue: argument.help.defaultValue,
136137
allValues: argument.help.allValues,
137138
abstract: argument.help.abstract,
138-
discussion: argument.help.discussion)
139+
discussion: argument.help.discussion,
140+
supplementalDiscussion: argument.help.supplementalDiscussion)
139141
}
140142
}
141143

Sources/ArgumentParserToolInfo/ToolInfo.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ public struct CommandInfoV0: Codable, Hashable {
5151
public var abstract: String?
5252
/// Extended description of the command's functionality.
5353
public var discussion: String?
54+
/// Additional description of the command's functionality for supplemental
55+
/// content.
56+
public var supplementalDiscussion: String?
5457

5558
/// Optional name of the subcommand invoked when the command is invoked with
5659
/// no arguments.
@@ -65,6 +68,7 @@ public struct CommandInfoV0: Codable, Hashable {
6568
commandName: String,
6669
abstract: String,
6770
discussion: String,
71+
supplementalDiscussion: String,
6872
defaultSubcommand: String?,
6973
subcommands: [CommandInfoV0],
7074
arguments: [ArgumentInfoV0]
@@ -74,6 +78,7 @@ public struct CommandInfoV0: Codable, Hashable {
7478
self.commandName = commandName
7579
self.abstract = abstract.nonEmpty
7680
self.discussion = discussion.nonEmpty
81+
self.supplementalDiscussion = supplementalDiscussion.nonEmpty
7782

7883
self.defaultSubcommand = defaultSubcommand?.nonEmpty
7984
self.subcommands = subcommands.nonEmpty
@@ -146,6 +151,9 @@ public struct ArgumentInfoV0: Codable, Hashable {
146151
public var abstract: String?
147152
/// Extended description of the argument's functionality.
148153
public var discussion: String?
154+
/// Additional description of the argument's functionality for supplemental
155+
/// content.
156+
public var supplementalDiscussion: String?
149157

150158
public init(
151159
kind: KindV0,
@@ -159,7 +167,8 @@ public struct ArgumentInfoV0: Codable, Hashable {
159167
defaultValue: String?,
160168
allValues: [String]?,
161169
abstract: String?,
162-
discussion: String?
170+
discussion: String?,
171+
supplementalDiscussion: String?
163172
) {
164173
self.kind = kind
165174

@@ -178,5 +187,6 @@ public struct ArgumentInfoV0: Codable, Hashable {
178187

179188
self.abstract = abstract?.nonEmpty
180189
self.discussion = discussion?.nonEmpty
190+
self.supplementalDiscussion = supplementalDiscussion?.nonEmpty
181191
}
182192
}

Tests/ArgumentParserUnitTests/HelpGenerationTests+AtArgument.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ extension HelpGenerationTests {
221221
var arg0: A? = nil
222222
}
223223

224+
@available(*, deprecated, message: "Included for test coverage")
224225
struct OptionalDefault: ParsableCommand {
225226
@Argument(help: "example")
226227
var arg0: A? = A()

Tests/ArgumentParserUnitTests/HelpGenerationTests+AtOption.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ extension HelpGenerationTests {
179179
var arg0: A? = nil
180180
}
181181

182+
@available(*, deprecated, message: "Included for test coverage")
182183
struct OptionalDefault: ParsableCommand {
183184
@Option(help: "example")
184185
var arg0: A? = A()

Tools/generate-manual/DSL/SinglePageDescription.swift renamed to Tools/generate-manual/DSL/Description.swift

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
import ArgumentParser
1313
import ArgumentParserToolInfo
1414

15-
struct SinglePageDescription: MDocComponent {
15+
struct Description: MDocComponent {
16+
var multipage: Bool
1617
var command: CommandInfoV0
1718

1819
var body: MDocComponent {
@@ -27,6 +28,14 @@ struct SinglePageDescription: MDocComponent {
2728
discussion
2829
}
2930

31+
if command.discussion != nil, command.supplementalDiscussion != nil {
32+
MDocMacro.ParagraphBreak()
33+
}
34+
35+
if let supplementalDiscussion = command.supplementalDiscussion {
36+
supplementalDiscussion
37+
}
38+
3039
List {
3140
for argument in command.arguments ?? [] {
3241
MDocMacro.ListItem(title: argument.manualPageDescription)
@@ -42,11 +51,23 @@ struct SinglePageDescription: MDocComponent {
4251
if let discussion = argument.discussion {
4352
discussion
4453
}
54+
55+
if argument.discussion != nil, argument.supplementalDiscussion != nil {
56+
MDocMacro.ParagraphBreak()
57+
}
58+
59+
if let supplementalDiscussion = argument.supplementalDiscussion {
60+
supplementalDiscussion
61+
}
4562
}
4663

47-
for subcommand in command.subcommands ?? [] {
48-
MDocMacro.ListItem(title: MDocMacro.Emphasis(arguments: [subcommand.commandName]))
49-
SinglePageDescription(command: subcommand).core
64+
if !multipage {
65+
for subcommand in command.subcommands ?? [] {
66+
MDocMacro.ListItem(title: MDocMacro.Emphasis(arguments: [subcommand.commandName]))
67+
Description(
68+
multipage: multipage,
69+
command: subcommand).core
70+
}
5071
}
5172
}
5273
}

Tools/generate-manual/DSL/Document.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,7 @@ struct Document: MDocComponent {
2424
Preamble(date: date, section: section, command: command)
2525
Name(command: command)
2626
Synopsis(command: command)
27-
if multiPage {
28-
MultiPageDescription(command: command)
29-
} else {
30-
SinglePageDescription(command: command)
31-
}
27+
Description(multipage: multiPage, command: command)
3228
Exit(section: section)
3329
if multiPage {
3430
SeeAlso(section: section, command: command)

0 commit comments

Comments
 (0)