feat: Adds extension to argument parser's command configuration
This commit is contained in:
36
Sources/CliDoc/CommandConfiguration+TextNode.swift
Normal file
36
Sources/CliDoc/CommandConfiguration+TextNode.swift
Normal file
@@ -0,0 +1,36 @@
|
||||
import ArgumentParser
|
||||
|
||||
public extension CommandConfiguration {
|
||||
|
||||
/// Generate a new command configuration, using ``TextNode``'s for the abstract,
|
||||
/// usage, and discussion parameters.
|
||||
///
|
||||
///
|
||||
init<A: TextNode, U: TextNode, D: TextNode>(
|
||||
commandName: String? = nil,
|
||||
abstract: Abstract<A>,
|
||||
usage: Usage<U>,
|
||||
discussion: Discussion<D>,
|
||||
version: String = "",
|
||||
shouldDisplay: Bool = true,
|
||||
subcommands ungroupedSubcommands: [ParsableCommand.Type] = [],
|
||||
groupedSubcommands: [CommandGroup] = [],
|
||||
defaultSubcommand: ParsableCommand.Type? = nil,
|
||||
helpNames: NameSpecification? = nil,
|
||||
aliases: [String] = []
|
||||
) {
|
||||
self.init(
|
||||
commandName: commandName,
|
||||
abstract: abstract.render(),
|
||||
usage: usage.render(),
|
||||
discussion: discussion.render(),
|
||||
version: version,
|
||||
shouldDisplay: shouldDisplay,
|
||||
subcommands: ungroupedSubcommands,
|
||||
groupedSubcommands: groupedSubcommands,
|
||||
defaultSubcommand: defaultSubcommand,
|
||||
helpNames: helpNames,
|
||||
aliases: aliases
|
||||
)
|
||||
}
|
||||
}
|
||||
14
Sources/CliDoc/Nodes/Abstract.swift
Normal file
14
Sources/CliDoc/Nodes/Abstract.swift
Normal file
@@ -0,0 +1,14 @@
|
||||
import CliDocCore
|
||||
|
||||
public struct Abstract<Content: TextNode>: TextNode {
|
||||
@usableFromInline
|
||||
let content: Content
|
||||
|
||||
public init(@TextBuilder content: () -> Content) {
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
public var body: some TextNode {
|
||||
content
|
||||
}
|
||||
}
|
||||
14
Sources/CliDoc/Nodes/Discussion.swift
Normal file
14
Sources/CliDoc/Nodes/Discussion.swift
Normal file
@@ -0,0 +1,14 @@
|
||||
import CliDocCore
|
||||
|
||||
public struct Discussion<Content: TextNode>: TextNode {
|
||||
@usableFromInline
|
||||
let content: Content
|
||||
|
||||
public init(@TextBuilder content: () -> Content) {
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
public var body: some TextNode {
|
||||
content
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import CliDocCore
|
||||
import Rainbow
|
||||
|
||||
// TODO: Use labeled content.
|
||||
public struct Note<Label: TextNode, Content: TextNode>: TextNode {
|
||||
@usableFromInline
|
||||
let label: Label
|
||||
|
||||
14
Sources/CliDoc/Nodes/Usage.swift
Normal file
14
Sources/CliDoc/Nodes/Usage.swift
Normal file
@@ -0,0 +1,14 @@
|
||||
import CliDocCore
|
||||
|
||||
public struct Usage<Content: TextNode>: TextNode {
|
||||
@usableFromInline
|
||||
let content: Content
|
||||
|
||||
public init(@TextBuilder content: () -> Content) {
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
public var body: some TextNode {
|
||||
content
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 129 B |
114
Sources/CliDocCore/Nodes/LabeledContent.swift
Normal file
114
Sources/CliDocCore/Nodes/LabeledContent.swift
Normal file
@@ -0,0 +1,114 @@
|
||||
/// A text node that consists of a label and content.
|
||||
///
|
||||
///
|
||||
public struct LabeledContent<Label: TextNode, Content: TextNode>: TextNode {
|
||||
|
||||
@usableFromInline
|
||||
let label: Label
|
||||
|
||||
@usableFromInline
|
||||
let content: Content
|
||||
|
||||
@inlinable
|
||||
public init(
|
||||
@TextBuilder _ content: () -> Content,
|
||||
@TextBuilder label: () -> Label
|
||||
) {
|
||||
self.label = label()
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public var body: some TextNode {
|
||||
style(.default)
|
||||
}
|
||||
}
|
||||
|
||||
public extension LabeledContent {
|
||||
|
||||
/// Apply the given style to the labeled content.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - style: The labeled content style to apply.
|
||||
@inlinable
|
||||
func style<S: LabeledContentStyle>(_ style: S) -> some TextNode {
|
||||
style.render(content: .init(label: label, content: content))
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds the type-erased label and content of a ``LabeledContent`` text node.
|
||||
///
|
||||
/// This is used when creating custom styles for the ``LabeledContent``.
|
||||
///
|
||||
public struct LabeledContentConfiguration {
|
||||
|
||||
/// The type-erased label text node.
|
||||
public let label: any TextNode
|
||||
|
||||
/// The type-erased content text node.
|
||||
public let content: any TextNode
|
||||
|
||||
@usableFromInline
|
||||
init(label: any TextNode, content: any TextNode) {
|
||||
self.label = label
|
||||
self.content = content
|
||||
}
|
||||
}
|
||||
|
||||
public protocol LabeledContentStyle: TextModifier where Content == LabeledContentConfiguration {}
|
||||
|
||||
public extension LabeledContentStyle where Self == HorizontalLabeledContentStyle {
|
||||
|
||||
static var `default`: Self {
|
||||
horizontal()
|
||||
}
|
||||
|
||||
@inlinable
|
||||
static func horizontal(separator: Separator.Horizontal = .space()) -> Self {
|
||||
HorizontalLabeledContentStyle(separator: separator)
|
||||
}
|
||||
}
|
||||
|
||||
public extension LabeledContentStyle where Self == VerticalLabeledContentStyle {
|
||||
|
||||
@inlinable
|
||||
static func vertical(separator: Separator.Vertical = .newLine()) -> Self {
|
||||
VerticalLabeledContentStyle(separator: separator)
|
||||
}
|
||||
}
|
||||
|
||||
public struct HorizontalLabeledContentStyle: LabeledContentStyle {
|
||||
|
||||
@usableFromInline
|
||||
let separator: Separator.Horizontal
|
||||
|
||||
@usableFromInline
|
||||
init(separator: Separator.Horizontal) {
|
||||
self.separator = separator
|
||||
}
|
||||
|
||||
public func render(content: LabeledContentConfiguration) -> some TextNode {
|
||||
HStack(separator: separator) {
|
||||
content.label
|
||||
content.content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct VerticalLabeledContentStyle: LabeledContentStyle {
|
||||
|
||||
@usableFromInline
|
||||
let separator: Separator.Vertical
|
||||
|
||||
@usableFromInline
|
||||
init(separator: Separator.Vertical) {
|
||||
self.separator = separator
|
||||
}
|
||||
|
||||
public func render(content: LabeledContentConfiguration) -> some TextNode {
|
||||
VStack(separator: separator) {
|
||||
content.label
|
||||
content.content
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user