Skip to content

Commit d2b0a1d

Browse files
committed
VirtualTerminal: simplify VTColor.ansi
Inline the `ANSIColor` and add an optional `intensity` attribute, unwrapping the structure as the payload.
1 parent 9c119bb commit d2b0a1d

File tree

4 files changed

+34
-112
lines changed

4 files changed

+34
-112
lines changed

Sources/VTDemo/VTDemo.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ private struct Menu: Scene {
190190
buffer.write(string: subtitle,
191191
at: VTPosition(row: buffer.size.height / 4 + 1,
192192
column: (buffer.size.width - subtitle.width) / 2),
193-
style: VTStyle(foreground: .ansi(.init(color: .cyan, intensity: .bright)),
193+
style: VTStyle(foreground: .ansi(.cyan, intensity: .bright),
194194
attributes: [.bold]))
195195

196196
// Render the menu options

Sources/VirtualTerminal/Buffer/VTStyle.swift

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,14 @@ extension VTAttributes {
4848
}
4949
}
5050

51-
private func pack(_ color: VTColor) -> UInt64 {
52-
return switch color {
53-
case let .rgb(red, green, blue):
54-
// [23-16: red][15-8: green][7-0: blue]
55-
(UInt64(red) << 16) | (UInt64(green) << 8) | (UInt64(blue) << 0)
56-
case let .ansi(color):
57-
// [23-9: reserved][8: intensity][7-0: color]
58-
(UInt64(color.intensity == .bright ? 1 : 0) << 8) | (UInt64(color.color.rawValue) & 0xff)
59-
}
51+
private func pack(_ color: ANSIColor, _ intensity: ANSIColorIntensity) -> UInt64 {
52+
// [23-9: reserved][8: intensity][7-0: color]
53+
return (UInt64(intensity == .bright ? 1 : 0) << 8) | (UInt64(color.rawValue) & 0xff)
54+
}
55+
56+
private func pack(_ red: UInt8, _ green: UInt8, _ blue: UInt8) -> UInt64 {
57+
// [23-16: red][15-8: green][7-0: blue]
58+
return (UInt64(red) << 16) | (UInt64(green) << 8) | (UInt64(blue) << 0)
6059
}
6160

6261
private struct Flags: OptionSet {
@@ -121,22 +120,22 @@ public struct VTStyle: Sendable, Equatable {
121120
public init(foreground: VTColor? = nil, background: VTColor? = nil, attributes: VTAttributes = []) {
122121
var representation = (UInt64(attributes.rawValue) << 8)
123122

124-
if let foreground {
125-
switch foreground {
126-
case .ansi(_):
127-
representation |= (pack(foreground) << 16) | UInt64(Flags.ANSIForeground.rawValue)
128-
case .rgb(_, _, _):
129-
representation |= (pack(foreground) << 16) | UInt64(Flags.RGBForeground.rawValue)
130-
}
123+
switch foreground {
124+
case .none:
125+
representation |= (pack(ANSIColor.default, .normal) << 16) | UInt64(Flags.ANSIForeground.rawValue)
126+
case let .some(.ansi(color, intensity)):
127+
representation |= (pack(color, intensity) << 16) | UInt64(Flags.ANSIForeground.rawValue)
128+
case let .some(.rgb(red, green, blue)):
129+
representation |= (pack(red, green, blue) << 16) | UInt64(Flags.RGBForeground.rawValue)
131130
}
132131

133-
if let background {
134-
switch background {
135-
case .ansi(_):
136-
representation |= (pack(background) << 40) | UInt64(Flags.ANSIBackground.rawValue)
137-
case .rgb(_, _, _):
138-
representation |= (pack(background) << 40) | UInt64(Flags.RGBBackground.rawValue)
139-
}
132+
switch background {
133+
case .none:
134+
representation |= (pack(ANSIColor.default, .normal) << 40) | UInt64(Flags.ANSIBackground.rawValue)
135+
case let .some(.ansi(color, intensity)):
136+
representation |= (pack(color, intensity) << 40) | UInt64(Flags.ANSIBackground.rawValue)
137+
case let .some(.rgb(red, green, blue)):
138+
representation |= (pack(red, green, blue) << 40) | UInt64(Flags.RGBBackground.rawValue)
140139
}
141140

142141
self.representation = representation
@@ -148,12 +147,12 @@ public struct VTStyle: Sendable, Equatable {
148147

149148
if flags.contains(.ANSIForeground) {
150149
let bits = representation >> 16
151-
guard let color = ANSIColorIdentifier(rawValue: (Int(bits) & 0xff)) else {
150+
guard let color = ANSIColor(rawValue: (Int(bits) & 0xff)) else {
152151
return nil
153152
}
154153
let intensity = (bits >> 8) & 1 == 1 ? ANSIColorIntensity.bright
155154
: ANSIColorIntensity.normal
156-
return .ansi(ANSIColor(color: color, intensity: intensity))
155+
return .ansi(color, intensity: intensity)
157156
}
158157

159158
if flags.contains(.RGBForeground) {
@@ -174,12 +173,12 @@ public struct VTStyle: Sendable, Equatable {
174173

175174
if flags.contains(.ANSIBackground) {
176175
let bits = representation >> 40
177-
guard let color = ANSIColorIdentifier(rawValue: (Int(bits) & 0xff)) else {
176+
guard let color = ANSIColor(rawValue: (Int(bits) & 0xff)) else {
178177
return nil
179178
}
180179
let intensity = (bits >> 8) & 1 == 1 ? ANSIColorIntensity.bright
181180
: ANSIColorIntensity.normal
182-
return .ansi(ANSIColor(color: color, intensity: intensity))
181+
return .ansi(color, intensity: intensity)
183182
}
184183

185184
if flags.contains(.RGBBackground) {

Sources/VirtualTerminal/Core/ISO6429.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,8 @@ extension GraphicRendition: CustomStringConvertible {
282282
case .NotCrossedOut: "29"
283283
case .Foreground(let color):
284284
switch color {
285-
case .ansi(let color):
286-
switch (color.color, color.intensity) {
285+
case .ansi(let color, let intensity):
286+
switch (color, intensity) {
287287
case (.black, .normal): "30"
288288
case (.red, .normal): "31"
289289
case (.green, .normal): "32"
@@ -311,8 +311,8 @@ extension GraphicRendition: CustomStringConvertible {
311311
}
312312
case .Background(let color):
313313
switch color {
314-
case .ansi(let color):
315-
switch (color.color, color.intensity) {
314+
case .ansi(let color, let intensity):
315+
switch (color, intensity) {
316316
case (.black, .normal): "40"
317317
case (.red, .normal): "41"
318318
case (.green, .normal): "42"
@@ -333,6 +333,7 @@ extension GraphicRendition: CustomStringConvertible {
333333
case (.white, .bright): "107"
334334
case (.default, .bright): "109"
335335
}
336+
336337
case .rgb(let red, let green, let blue):
337338
// 48;2;<r>;<g>;<b>
338339
"48;2;\(Int(red));\(Int(green));\(Int(blue))"

Sources/VirtualTerminal/Core/VTColor.swift

Lines changed: 2 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
/// has been supported since early terminal systems. The actual appearance
88
/// of these colors depends on the terminal's color scheme and user
99
/// customization.
10-
public enum ANSIColorIdentifier: Int, Equatable, Sendable {
10+
public enum ANSIColor: Int, Equatable, Sendable {
1111
case black
1212
case red
1313
case green
@@ -33,84 +33,6 @@ public enum ANSIColorIntensity: Equatable, Sendable {
3333
case bright
3434
}
3535

36-
/// An ANSI color with optional intensity variation.
37-
///
38-
/// ANSI colors provide excellent terminal compatibility since they're
39-
/// supported by virtually all terminal emulators. They automatically
40-
/// adapt to user color schemes and accessibility settings.
41-
///
42-
/// ## Usage Examples
43-
///
44-
/// ```swift
45-
/// // Standard colors
46-
/// let ANSIRed = ANSIColor(color: .red, intensity: .normal)
47-
/// let ANSIBrightBlue = ANSIColor(color: .blue, intensity: .bright)
48-
///
49-
/// // Using convenience properties
50-
/// let default = ANSIColor.default
51-
/// let ANSIBrightGreen = ANSIColor(color: .green, intensity: .bright)
52-
/// ```
53-
public struct ANSIColor: Equatable, Hashable, Sendable {
54-
@usableFromInline
55-
internal let color: ANSIColorIdentifier
56-
57-
@usableFromInline
58-
internal let intensity: ANSIColorIntensity
59-
60-
/// Creates an ANSI color with the specified identifier and intensity.
61-
///
62-
/// - Parameters:
63-
/// - color: The base color identifier.
64-
/// - intensity: The color intensity. Defaults to `.normal`.
65-
public init(color: ANSIColorIdentifier, intensity: ANSIColorIntensity = .normal) {
66-
self.color = color
67-
self.intensity = intensity
68-
}
69-
}
70-
71-
extension ANSIColor {
72-
/// The terminal's default color as configured by the user.
73-
///
74-
/// This respects terminal color schemes and accessibility settings,
75-
/// making it the best choice for primary text that should integrate
76-
/// naturally with the user's environment.
77-
public static var `default`: ANSIColor {
78-
ANSIColor(color: .default, intensity: .normal)
79-
}
80-
81-
public static var black: ANSIColor {
82-
ANSIColor(color: .black, intensity: .normal)
83-
}
84-
85-
public static var red: ANSIColor {
86-
ANSIColor(color: .red, intensity: .normal)
87-
}
88-
89-
public static var green: ANSIColor {
90-
ANSIColor(color: .green, intensity: .normal)
91-
}
92-
93-
public static var yellow: ANSIColor {
94-
ANSIColor(color: .yellow, intensity: .normal)
95-
}
96-
97-
public static var blue: ANSIColor {
98-
ANSIColor(color: .blue, intensity: .normal)
99-
}
100-
101-
public static var magenta: ANSIColor {
102-
ANSIColor(color: .magenta, intensity: .normal)
103-
}
104-
105-
public static var cyan: ANSIColor {
106-
ANSIColor(color: .cyan, intensity: .normal)
107-
}
108-
109-
public static var white: ANSIColor {
110-
ANSIColor(color: .white, intensity: .normal)
111-
}
112-
}
113-
11436
/// Terminal color representation supporting both ANSI and RGB color spaces.
11537
///
11638
/// `VTColor` provides a unified interface for terminal colors while
@@ -140,7 +62,7 @@ public enum VTColor: Equatable, Hashable, Sendable {
14062
/// A 24-bit RGB color with precise component control.
14163
case rgb(red: UInt8, green: UInt8, blue: UInt8)
14264
/// An ANSI color that adapts to terminal themes and settings.
143-
case ansi(ANSIColor)
65+
case ansi(_ color: ANSIColor, intensity: ANSIColorIntensity = .normal)
14466
}
14567

14668
extension VTColor {

0 commit comments

Comments
 (0)