feat: Adds vertical and horizontal separators, renames modifier protocol.
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
/// An empty text node.
|
||||
///
|
||||
/// This gets removed from any output when rendering text nodes.
|
||||
public struct Empty: TextNode {
|
||||
|
||||
@inlinable
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
/// A group of text nodes.
|
||||
///
|
||||
/// This allows you to group content together, which can optionally be
|
||||
/// styled.
|
||||
public struct Group<Content: TextNode>: TextNode {
|
||||
|
||||
@usableFromInline
|
||||
var content: Content
|
||||
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
/// A horizontal group of text nodes.
|
||||
public struct HStack: TextNode {
|
||||
|
||||
@usableFromInline
|
||||
let content: [any TextNode]
|
||||
|
||||
@usableFromInline
|
||||
let separator: any TextNode
|
||||
let separator: Separator.Horizontal
|
||||
|
||||
@inlinable
|
||||
public init(
|
||||
spacing: Int = 1,
|
||||
separator: Separator.Horizontal = .space(count: 1),
|
||||
@TextBuilder content: () -> any TextNode
|
||||
) {
|
||||
self.content = array(from: content())
|
||||
self.separator = seperator(" ", count: spacing > 0 ? spacing - 1 : 0)
|
||||
self.separator = separator
|
||||
}
|
||||
|
||||
@inlinable
|
||||
|
||||
@@ -78,7 +78,7 @@ public struct SectionConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
public protocol SectionStyle: NodeModifier where Content == SectionConfiguration {}
|
||||
public protocol SectionStyle: TextModifier where Content == SectionConfiguration {}
|
||||
|
||||
public extension SectionStyle where Self == DefaultSectionStyle {
|
||||
static var `default`: Self { DefaultSectionStyle() }
|
||||
@@ -87,7 +87,7 @@ public extension SectionStyle where Self == DefaultSectionStyle {
|
||||
public struct DefaultSectionStyle: SectionStyle {
|
||||
|
||||
public func render(content: SectionConfiguration) -> some TextNode {
|
||||
VStack(spacing: 2) {
|
||||
VStack(separator: .newLine(count: 2)) {
|
||||
content.header
|
||||
content.content
|
||||
content.footer
|
||||
|
||||
66
Sources/CliDocCore/Nodes/Separator.swift
Normal file
66
Sources/CliDocCore/Nodes/Separator.swift
Normal file
@@ -0,0 +1,66 @@
|
||||
public enum Separator {
|
||||
|
||||
/// Represents a horizontal separator that can be used between text nodes, typically inside
|
||||
/// an ``HStack``
|
||||
public enum Horizontal: TextNode {
|
||||
/// Separate nodes by spaces of the given count.
|
||||
case space(count: Int = 1)
|
||||
|
||||
/// Separate nodes by tabs of the given count.
|
||||
case tab(count: Int = 1)
|
||||
|
||||
/// Separate nodes by the provided string of the given count.
|
||||
case custom(String, count: Int = 1)
|
||||
|
||||
@TextBuilder
|
||||
@inlinable
|
||||
public var body: some TextNode {
|
||||
switch self {
|
||||
case let .tab(count: count):
|
||||
seperator("\t", count: count)
|
||||
case let .space(count: count):
|
||||
seperator(" ", count: count)
|
||||
case let .custom(string, count: count):
|
||||
seperator(string, count: count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a vertical separator that can be used between text nodes, typically inside
|
||||
/// a ``VStack``
|
||||
public enum Vertical: TextNode {
|
||||
case newLine(count: Int = 1)
|
||||
case custom(String, count: Int = 1)
|
||||
|
||||
@TextBuilder
|
||||
@inlinable
|
||||
public var body: some TextNode {
|
||||
switch self {
|
||||
case let .newLine(count: count):
|
||||
seperator("\n", count: count)
|
||||
case let .custom(string, count: count):
|
||||
seperator(string, count: count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
func ensuredCount(_ count: Int) -> Int {
|
||||
guard count >= 1 else { return 1 }
|
||||
return count
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
func seperator(_ separator: String, count: Int) -> some TextNode {
|
||||
let count = ensuredCount(count)
|
||||
|
||||
assert(count >= 1, "Invalid count while creating a separator")
|
||||
|
||||
var output = ""
|
||||
for _ in 1 ... count {
|
||||
output += separator
|
||||
}
|
||||
return output
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
public struct VStack: TextNode {
|
||||
/// A vertical stack of text nodes.
|
||||
///
|
||||
///
|
||||
|
||||
public struct VStack: TextNode {
|
||||
@usableFromInline
|
||||
let content: [any TextNode]
|
||||
|
||||
@usableFromInline
|
||||
let separator: any TextNode
|
||||
let separator: Separator.Vertical
|
||||
|
||||
@inlinable
|
||||
public init(
|
||||
spacing: Int = 1,
|
||||
separator: Separator.Vertical = .newLine(count: 1),
|
||||
@TextBuilder content: () -> any TextNode
|
||||
) {
|
||||
self.content = array(from: content())
|
||||
self.separator = seperator("\n", count: spacing > 0 ? spacing - 1 : 0)
|
||||
self.separator = separator
|
||||
}
|
||||
|
||||
@inlinable
|
||||
|
||||
Reference in New Issue
Block a user