feat: Working on node builder

This commit is contained in:
2024-12-01 11:45:05 -05:00
parent 55d8888961
commit ff49b12198
20 changed files with 495 additions and 227 deletions

View File

@@ -1,4 +1,3 @@
public struct Group: NodeRepresentable {
@usableFromInline
let node: any NodeRepresentable
@@ -25,10 +24,10 @@ public struct Group: NodeRepresentable {
@inlinable
public init(
separator: AnyNode = Space().eraseToAnyNode(),
separator: String = " ",
@NodeBuilder _ build: () -> any NodeRepresentable
) {
self.init(separator: separator, node: build())
self.init(separator: separator.eraseToAnyNode(), node: build())
}
@inlinable

View File

@@ -1,32 +1,45 @@
@preconcurrency import Rainbow
public struct Header: NodeRepresentable {
public struct Header: NodeRepresentable, @unchecked Sendable {
@usableFromInline
let node: Text
let node: any NodeRepresentable
@usableFromInline
let styles: [Style]
let color: NamedColor?
@usableFromInline
let styles: [Style]?
@inlinable
public init(
@NodeBuilder _ build: () -> any NodeRepresentable
) {
self.node = build()
self.color = nil
self.styles = nil
}
@inlinable
public init(
_ text: String,
color: NamedColor? = .yellow,
styles: [Style] = [.bold]
styles: [Style]? = [.bold]
) {
var text = Text(text)
if let color {
text = text.color(color)
}
self.node = text
self.color = color
self.node = Text(text)
self.styles = styles
}
@inlinable
public func render() -> String {
styles.reduce(node) { node, style in
node.style(style)
var node = node
if let color {
node = node.color(color)
}
.render()
if let styles {
node = node.style(styles)
}
return node.render()
}
}

View File

@@ -0,0 +1,46 @@
public struct LabeledContent: NodeRepresentable {
@usableFromInline
let label: any NodeRepresentable
@usableFromInline
let content: any NodeRepresentable
@usableFromInline
let separator: any NodeRepresentable
@inlinable
public init(
separator: (any NodeRepresentable)? = nil,
@NodeBuilder label: () -> any NodeRepresentable,
@NodeBuilder content: () -> any NodeRepresentable
) {
self.separator = separator ?? "\n"
self.label = label()
self.content = content()
}
@inlinable
public func render() -> String {
Group(separator: separator) {
label
content
}.render()
}
}
public extension LabeledContent {
@inlinable
init(
_ label: String,
separator: (any NodeRepresentable)? = nil,
@NodeBuilder content: () -> any NodeRepresentable
) {
self.init(separator: separator) {
Text(label)
} content: {
content()
}
}
}

View File

@@ -1,34 +0,0 @@
public extension NodeRepresentable {
@inlinable
func repeating(_ count: Int) -> some NodeRepresentable {
RepeatingNode(self, count: count)
}
}
@usableFromInline
struct RepeatingNode: NodeRepresentable {
@usableFromInline
let node: any NodeRepresentable
@usableFromInline
let count: Int
@usableFromInline
init(_ node: any NodeRepresentable, count: Int) {
self.node = node
self.count = count
}
@usableFromInline
func render() -> String {
var string = node.render()
guard count > 0 else { return string }
var count = count - 1
while count > 0 {
string = "\(string)\(node.render())"
count -= 1
}
return string
}
}

View File

@@ -1,41 +0,0 @@
// TODO: Remove init(header:...) initializers.
public struct Section: NodeRepresentable {
@usableFromInline
let node: any NodeRepresentable
@inlinable
public init<N: NodeRepresentable>(@NodeBuilder _ build: () -> N) {
self.node = build()
}
@inlinable
public func render() -> String {
node.render()
}
@inlinable
public init<Content: NodeRepresentable, Separator: NodeRepresentable>(
header: String,
separator: Separator,
@NodeBuilder content: () -> Content
) {
self.init {
Text(header)
separator
content()
}
}
@inlinable
public init<Content: NodeRepresentable>(
header: String,
inline: Bool = false,
@NodeBuilder content: () -> Content
) {
self.init(
header: header,
separator: inline ? Space().eraseToAnyNode() : NewLine().eraseToAnyNode(),
content: content
)
}
}

View File

@@ -0,0 +1,6 @@
extension String: NodeRepresentable {
@inlinable
public func render() -> String {
self
}
}

View File

@@ -13,43 +13,6 @@ public struct Text: NodeRepresentable {
public func render() -> String {
text
}
@inlinable
public func color(_ color: NamedColor) -> Self {
.init(text.applyingColor(color))
}
@inlinable
public func style(_ style: Style) -> Self {
.init(text.applyingStyle(style))
}
}
public struct NewLine: NodeRepresentable {
@usableFromInline
let node: any NodeRepresentable
@inlinable
public init(count: Int = 1) {
self.node = Text("\n").repeating(count)
}
@inlinable
public func render() -> String {
node.render()
}
}
public struct Space: NodeRepresentable {
let node: any NodeRepresentable
public init(count: Int = 1) {
self.node = Text(" ").repeating(count)
}
public func render() -> String {
node.render()
}
}
public extension NodeRepresentable {
@@ -58,12 +21,12 @@ public extension NodeRepresentable {
Text("")
}
static func newLine(count: Int = 1) -> Self where Self == NewLine {
NewLine(count: count)
static func newLine(count: Int = 1) -> Self where Self == AnyNode {
"\n".repeating(count).eraseToAnyNode()
}
static func space(count: Int = 1) -> Self where Self == Space {
Space(count: count)
static func space(count: Int = 1) -> Self where Self == AnyNode {
" ".repeating(count).eraseToAnyNode()
}
}