This commit is contained in:
@@ -1,86 +1,146 @@
|
||||
import CliDoc
|
||||
|
||||
extension CliDoc.Discussion {
|
||||
extension CliDoc.Discussion where Content == AnyTextNode {
|
||||
static func playbook(
|
||||
examples: [(label: String, example: String)]
|
||||
examples: [Example]
|
||||
) -> Self {
|
||||
.init {
|
||||
Section {
|
||||
VStack {
|
||||
Note.mostOptionsNotRequired
|
||||
Examples(examples: examples)
|
||||
ExampleSection.default(examples: examples)
|
||||
SeeAlso(label: "Ansible playbook options.", command: "ansible-playbook --help")
|
||||
ImportantNote.passingExtraArgs
|
||||
}
|
||||
.labeledContentStyle(.custom("foo:"))
|
||||
.separator(.newLine(count: 2))
|
||||
.eraseToAnyTextNode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ShellCommand {
|
||||
extension Array where Element == Example {
|
||||
func addingPassingOptions(command: String) -> Self {
|
||||
var output = self
|
||||
output.append((
|
||||
label: "Passing extra arguments / options",
|
||||
example: "\(command) -- --vaultId=myId@$SCRIPTS/vault-gopass-client"
|
||||
))
|
||||
return output
|
||||
}
|
||||
|
||||
func addingPipeToOtherCommand(command: String) -> Self {
|
||||
var output = self
|
||||
output.append((
|
||||
label: "Piping output to other command.",
|
||||
example: "\(command) --quiet | xargs open"
|
||||
))
|
||||
return output
|
||||
}
|
||||
}
|
||||
|
||||
extension ExampleSection where Header == String, Label == String {
|
||||
static func `default`(
|
||||
examples: [Example],
|
||||
usesPassingExtraOptions: Bool = true,
|
||||
usesPipeToOtherCommand: Bool = true
|
||||
) -> some TextNode {
|
||||
var examples = examples
|
||||
|
||||
if let first = examples.first {
|
||||
if usesPassingExtraOptions {
|
||||
examples = examples.addingPassingOptions(command: first.example)
|
||||
}
|
||||
if usesPipeToOtherCommand {
|
||||
examples = examples.addingPipeToOtherCommand(command: first.example)
|
||||
}
|
||||
}
|
||||
return Self(examples: examples) {
|
||||
"EXAMPLES:"
|
||||
} label: {
|
||||
"Some common usage examples."
|
||||
}
|
||||
.exampleStyle(HPAExampleStyle())
|
||||
}
|
||||
}
|
||||
|
||||
struct HPAExampleStyle: ExampleStyle {
|
||||
|
||||
func render(content: ExampleConfiguration) -> some TextNode {
|
||||
VStack {
|
||||
content.examples.map { example in
|
||||
VStack {
|
||||
example.label.color(.green).bold()
|
||||
ShellCommand.hpaCommand(example.example)
|
||||
}
|
||||
}
|
||||
}
|
||||
.separator(.newLine(count: 2))
|
||||
}
|
||||
}
|
||||
|
||||
extension ShellCommand where Content == String, Symbol == String {
|
||||
static func hpaCommand(_ command: String) -> Self {
|
||||
.init(command: "\(Constants.appName) \(command)")
|
||||
.init { "\(Constants.appName) \(command)" } symbol: { "$" }
|
||||
}
|
||||
}
|
||||
|
||||
struct SeeAlso: NodeRepresentable {
|
||||
struct SeeAlso<Label: TextNode, Content: TextNode>: TextNode {
|
||||
|
||||
let node: any NodeRepresentable
|
||||
|
||||
init(label: String, command: String) {
|
||||
self.node = Group(separator: "\n") {
|
||||
Note("SEE ALSO:") {
|
||||
label
|
||||
}
|
||||
ShellCommand(command: command)
|
||||
}
|
||||
}
|
||||
|
||||
func render() -> String {
|
||||
node.render()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct Examples: NodeRepresentable {
|
||||
typealias Example = (label: String, example: String)
|
||||
let examples: [Example]
|
||||
|
||||
func render() -> String {
|
||||
Group(separator: "\n") {
|
||||
Note("EXAMPLES:") { "Common usage examples." }
|
||||
for (label, command) in examples {
|
||||
LabeledContent("\t\(label.green.bold)", separator: "\n") {
|
||||
ShellCommand.hpaCommand(command)
|
||||
}
|
||||
}
|
||||
if let first = examples.first {
|
||||
LabeledContent("\n\tPassing extra options.".green.bold, separator: "\n") {
|
||||
ShellCommand.hpaCommand("\(first.example) -- --vault-id \"myId@$SCRIPTS/vault-gopass-client\"")
|
||||
}
|
||||
}
|
||||
}.render()
|
||||
}
|
||||
}
|
||||
|
||||
struct Note: NodeRepresentable {
|
||||
|
||||
let node: any NodeRepresentable
|
||||
let title = "SEE ALSO:"
|
||||
let label: Label
|
||||
let content: Content
|
||||
|
||||
init(
|
||||
_ label: String = "NOTE:",
|
||||
@NodeBuilder _ content: () -> any NodeRepresentable
|
||||
@TextBuilder content: () -> Content,
|
||||
@TextBuilder label: () -> Label
|
||||
) {
|
||||
self.node = LabeledContent(
|
||||
separator: " ",
|
||||
label: { label.yellow.bold },
|
||||
content: { content().style(.italic) }
|
||||
)
|
||||
self.content = content()
|
||||
self.label = label()
|
||||
}
|
||||
|
||||
func render() -> String {
|
||||
node.render()
|
||||
var body: some TextNode {
|
||||
VStack {
|
||||
LabeledContent {
|
||||
label.italic()
|
||||
} label: {
|
||||
title.color(.yellow).bold().underline()
|
||||
}
|
||||
ShellCommand { content } symbol: { "$" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SeeAlso where Content == String, Label == Empty {
|
||||
init(command: String) {
|
||||
self.init { "\(Constants.appName) \(command)" } label: { Empty() }
|
||||
}
|
||||
}
|
||||
|
||||
extension SeeAlso where Content == String, Label == String {
|
||||
init(label: String, command: String) {
|
||||
self.init { "\(Constants.appName) \(command)" } label: { label }
|
||||
}
|
||||
}
|
||||
|
||||
struct Note<Content: TextNode>: TextNode {
|
||||
|
||||
let label: String = "NOTE:"
|
||||
let content: Content
|
||||
|
||||
init(
|
||||
@TextBuilder _ content: () -> Content
|
||||
) {
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
var body: some TextNode {
|
||||
HStack {
|
||||
label.color(.yellow).bold()
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Note where Content == String {
|
||||
static var mostOptionsNotRequired: Self {
|
||||
.init {
|
||||
"Most options are not required if you have a configuration file setup."
|
||||
@@ -88,26 +148,27 @@ struct Note: NodeRepresentable {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Fix the text.
|
||||
struct ImportantNote: NodeRepresentable {
|
||||
struct ImportantNote<Content: TextNode>: TextNode {
|
||||
|
||||
let node: any NodeRepresentable
|
||||
let label: String = "IMPORTANT NOTE:"
|
||||
let content: Content
|
||||
|
||||
init(
|
||||
_ label: String = "IMPORTANT NOTE:",
|
||||
@NodeBuilder _ content: () -> any NodeRepresentable
|
||||
@TextBuilder _ content: () -> Content
|
||||
) {
|
||||
self.node = LabeledContent(
|
||||
separator: "\n",
|
||||
label: { label.red.bold.underline },
|
||||
content: { content().style(.italic) }
|
||||
)
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
func render() -> String {
|
||||
node.render()
|
||||
var body: some TextNode {
|
||||
HStack {
|
||||
label.color(.red).bold().underline()
|
||||
content
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ImportantNote where Content == String {
|
||||
static var passingExtraArgs: Self {
|
||||
.init {
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user