feat: Working on node builder
This commit is contained in:
14
Sources/CliDoc/Modifiers/AnyModifier.swift
Normal file
14
Sources/CliDoc/Modifiers/AnyModifier.swift
Normal file
@@ -0,0 +1,14 @@
|
||||
public struct AnyNodeModifier: NodeModifier {
|
||||
@usableFromInline
|
||||
let modifier: any NodeModifier
|
||||
|
||||
@inlinable
|
||||
public init<N: NodeModifier>(_ modifier: N) {
|
||||
self.modifier = modifier
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func render(_ node: any NodeRepresentable) -> any NodeRepresentable {
|
||||
modifier.render(node)
|
||||
}
|
||||
}
|
||||
35
Sources/CliDoc/Modifiers/Color.swift
Normal file
35
Sources/CliDoc/Modifiers/Color.swift
Normal file
@@ -0,0 +1,35 @@
|
||||
import Rainbow
|
||||
|
||||
public extension NodeRepresentable {
|
||||
|
||||
@inlinable
|
||||
func color(_ color: NamedColor) -> any NodeRepresentable {
|
||||
modifier(ColorModifier(color: color))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public extension NodeModifier {
|
||||
|
||||
@inlinable
|
||||
static func color(_ color: NamedColor) -> Self where Self == AnyNodeModifier {
|
||||
.init(ColorModifier(color: color))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
struct ColorModifier: NodeModifier, @unchecked Sendable {
|
||||
@usableFromInline
|
||||
let color: NamedColor
|
||||
|
||||
@usableFromInline
|
||||
init(color: NamedColor) {
|
||||
self.color = color
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
func render(_ node: any NodeRepresentable) -> any NodeRepresentable {
|
||||
node.render().applyingColor(color)
|
||||
}
|
||||
}
|
||||
48
Sources/CliDoc/Modifiers/LabelStyle.swift
Normal file
48
Sources/CliDoc/Modifiers/LabelStyle.swift
Normal file
@@ -0,0 +1,48 @@
|
||||
import Rainbow
|
||||
|
||||
public extension NodeRepresentable {
|
||||
|
||||
@inlinable
|
||||
func labelStyle(_ style: any NodeModifier) -> any NodeRepresentable {
|
||||
return modifier(LabelStyleModifier(style))
|
||||
}
|
||||
|
||||
@inlinable
|
||||
func labelStyle(_ color: NamedColor) -> any NodeRepresentable {
|
||||
return modifier(LabelStyleModifier(.color(color)))
|
||||
}
|
||||
|
||||
@inlinable
|
||||
func labelStyle(_ style: Style) -> any NodeRepresentable {
|
||||
return modifier(LabelStyleModifier(.style(style)))
|
||||
}
|
||||
|
||||
@inlinable
|
||||
func labelStyle(_ styles: Style...) -> any NodeRepresentable {
|
||||
return modifier(LabelStyleModifier(.style(styles)))
|
||||
}
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
struct LabelStyleModifier: NodeModifier {
|
||||
|
||||
@usableFromInline
|
||||
let modifier: any NodeModifier
|
||||
|
||||
@usableFromInline
|
||||
init(_ modifier: any NodeModifier) {
|
||||
self.modifier = modifier
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
func render(_ node: any NodeRepresentable) -> any NodeRepresentable {
|
||||
if let node = node as? LabeledContent {
|
||||
return LabeledContent(separator: node.separator) {
|
||||
node.label.modifier(modifier)
|
||||
} content: {
|
||||
node.content
|
||||
}
|
||||
}
|
||||
return node
|
||||
}
|
||||
}
|
||||
44
Sources/CliDoc/Modifiers/Repeating.swift
Normal file
44
Sources/CliDoc/Modifiers/Repeating.swift
Normal file
@@ -0,0 +1,44 @@
|
||||
public extension NodeRepresentable {
|
||||
@inlinable
|
||||
func repeating(_ count: Int, separator: (any NodeRepresentable)? = nil) -> any NodeRepresentable {
|
||||
modifier(RepeatingNode(count: count, separator: separator))
|
||||
}
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
struct RepeatingNode: NodeModifier {
|
||||
|
||||
@usableFromInline
|
||||
let count: Int
|
||||
|
||||
@usableFromInline
|
||||
let separator: (any NodeRepresentable)?
|
||||
|
||||
@usableFromInline
|
||||
init(
|
||||
count: Int,
|
||||
separator: (any NodeRepresentable)?
|
||||
) {
|
||||
self.count = count
|
||||
self.separator = separator
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
func render(_ node: any NodeRepresentable) -> any NodeRepresentable {
|
||||
let input = node.render()
|
||||
var output = input
|
||||
let separator = self.separator != nil
|
||||
? self.separator!.render()
|
||||
: ""
|
||||
|
||||
guard count > 0 else { return output }
|
||||
|
||||
var count = count - 1
|
||||
while count > 0 {
|
||||
output = "\(output)\(separator)\(input)"
|
||||
count -= 1
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
}
|
||||
41
Sources/CliDoc/Modifiers/Style.swift
Normal file
41
Sources/CliDoc/Modifiers/Style.swift
Normal file
@@ -0,0 +1,41 @@
|
||||
import Rainbow
|
||||
|
||||
public extension NodeRepresentable {
|
||||
@inlinable
|
||||
func style(_ styles: Style...) -> any NodeRepresentable {
|
||||
modifier(StyleModifier(styles: styles))
|
||||
}
|
||||
|
||||
@inlinable
|
||||
func style(_ styles: [Style]) -> any NodeRepresentable {
|
||||
modifier(StyleModifier(styles: styles))
|
||||
}
|
||||
}
|
||||
|
||||
public extension NodeModifier {
|
||||
@inlinable
|
||||
static func style(_ styles: Style...) -> Self where Self == AnyNodeModifier {
|
||||
.init(StyleModifier(styles: styles))
|
||||
}
|
||||
|
||||
@inlinable
|
||||
static func style(_ styles: [Style]) -> Self where Self == AnyNodeModifier {
|
||||
.init(StyleModifier(styles: styles))
|
||||
}
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
struct StyleModifier: NodeModifier, @unchecked Sendable {
|
||||
@usableFromInline
|
||||
let styles: [Style]
|
||||
|
||||
@usableFromInline
|
||||
init(styles: [Style]) {
|
||||
self.styles = styles
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
func render(_ node: any NodeRepresentable) -> any NodeRepresentable {
|
||||
styles.reduce(node.render()) { $0.applyingStyle($1) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user