Skip to content

Commit bb5bcd2

Browse files
makenowjustRX14
authored andcommittedApr 3, 2018
Colorize: abstract colors and support 8bit and true color (#5902)
* Colorize: abstract colors and support 8bit and true color Closes #5900 * Color#fore and #back take io to avoid memory allocation * Use character literal instead of 1 length string
1 parent 7eae5aa commit bb5bcd2

File tree

2 files changed

+97
-46
lines changed

2 files changed

+97
-46
lines changed
 

Diff for: ‎spec/std/colorize_spec.cr

+16
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ describe "colorize" do
3333
colorize("hello").white.to_s.should eq("\e[97mhello\e[0m")
3434
end
3535

36+
it "colorizes foreground with 8-bit color" do
37+
colorize("hello").fore(Colorize::Color256.new(123u8)).to_s.should eq("\e[38;5;123mhello\e[0m")
38+
end
39+
40+
it "colorizes foreground with true color" do
41+
colorize("hello").fore(Colorize::ColorRGB.new(12u8, 34u8, 56u8)).to_s.should eq("\e[38;2;12;34;56mhello\e[0m")
42+
end
43+
3644
it "colorizes background" do
3745
colorize("hello").on_black.to_s.should eq("\e[40mhello\e[0m")
3846
colorize("hello").on_red.to_s.should eq("\e[41mhello\e[0m")
@@ -52,6 +60,14 @@ describe "colorize" do
5260
colorize("hello").on_white.to_s.should eq("\e[107mhello\e[0m")
5361
end
5462

63+
it "colorizes background with 8-bit color" do
64+
colorize("hello").back(Colorize::Color256.new(123u8)).to_s.should eq("\e[48;5;123mhello\e[0m")
65+
end
66+
67+
it "colorizes background with true color" do
68+
colorize("hello").back(Colorize::ColorRGB.new(12u8, 34u8, 56u8)).to_s.should eq("\e[48;2;12;34;56mhello\e[0m")
69+
end
70+
5571
it "colorizes mode" do
5672
colorize("hello").bold.to_s.should eq("\e[1mhello\e[0m")
5773
colorize("hello").bright.to_s.should eq("\e[1mhello\e[0m")

Diff for: ‎src/colorize.cr

+81-46
Original file line numberDiff line numberDiff line change
@@ -123,43 +123,67 @@ class Object
123123
include Colorize::ObjectExtensions
124124
end
125125

126-
struct Colorize::Object(T)
127-
private FORE_DEFAULT = "39"
128-
private FORE_BLACK = "30"
129-
private FORE_RED = "31"
130-
private FORE_GREEN = "32"
131-
private FORE_YELLOW = "33"
132-
private FORE_BLUE = "34"
133-
private FORE_MAGENTA = "35"
134-
private FORE_CYAN = "36"
135-
private FORE_LIGHT_GRAY = "37"
136-
private FORE_DARK_GRAY = "90"
137-
private FORE_LIGHT_RED = "91"
138-
private FORE_LIGHT_GREEN = "92"
139-
private FORE_LIGHT_YELLOW = "93"
140-
private FORE_LIGHT_BLUE = "94"
141-
private FORE_LIGHT_MAGENTA = "95"
142-
private FORE_LIGHT_CYAN = "96"
143-
private FORE_WHITE = "97"
144-
145-
private BACK_DEFAULT = "49"
146-
private BACK_BLACK = "40"
147-
private BACK_RED = "41"
148-
private BACK_GREEN = "42"
149-
private BACK_YELLOW = "43"
150-
private BACK_BLUE = "44"
151-
private BACK_MAGENTA = "45"
152-
private BACK_CYAN = "46"
153-
private BACK_LIGHT_GRAY = "47"
154-
private BACK_DARK_GRAY = "100"
155-
private BACK_LIGHT_RED = "101"
156-
private BACK_LIGHT_GREEN = "102"
157-
private BACK_LIGHT_YELLOW = "103"
158-
private BACK_LIGHT_BLUE = "104"
159-
private BACK_LIGHT_MAGENTA = "105"
160-
private BACK_LIGHT_CYAN = "106"
161-
private BACK_WHITE = "107"
126+
module Colorize
127+
alias Color = ColorANSI | Color256 | ColorRGB
128+
129+
enum ColorANSI
130+
Default = 39
131+
Black = 30
132+
Red = 31
133+
Green = 32
134+
Yellow = 33
135+
Blue = 34
136+
Magenta = 35
137+
Cyan = 36
138+
LightGray = 37
139+
DarkGray = 90
140+
LightRed = 91
141+
LightGreen = 92
142+
LightYellow = 93
143+
LightBlue = 94
144+
LightMagenta = 95
145+
LightCyan = 96
146+
White = 97
147+
148+
def fore(io : IO) : Nil
149+
to_i.to_s io
150+
end
151+
152+
def back(io : IO) : Nil
153+
(to_i + 10).to_s io
154+
end
155+
end
156+
157+
record Color256,
158+
value : UInt8 do
159+
def fore(io : IO) : Nil
160+
io << "38;5;"
161+
value.to_s io
162+
end
163+
164+
def back(io : IO) : Nil
165+
io << "48;5;"
166+
value.to_s io
167+
end
168+
end
169+
170+
record ColorRGB,
171+
red : UInt8,
172+
green : UInt8,
173+
blue : UInt8 do
174+
def fore(io : IO) : Nil
175+
io << "38;2;"
176+
{red, green, blue}.join(';', io, &.to_s io)
177+
end
162178

179+
def back(io : IO) : Nil
180+
io << "48;2;"
181+
{red, green, blue}.join(';', io, &.to_s io)
182+
end
183+
end
184+
end
185+
186+
struct Colorize::Object(T)
163187
private MODE_DEFAULT = '0'
164188
private MODE_BOLD = '1'
165189
private MODE_BRIGHT = '1'
@@ -180,21 +204,24 @@ struct Colorize::Object(T)
180204
private COLORS = %w(black red green yellow blue magenta cyan light_gray dark_gray light_red light_green light_yellow light_blue light_magenta light_cyan white)
181205
private MODES = %w(bold bright dim underline blink reverse hidden)
182206

207+
@fore : Color
208+
@back : Color
209+
183210
def initialize(@object : T)
184-
@fore = FORE_DEFAULT
185-
@back = BACK_DEFAULT
211+
@fore = ColorANSI::Default
212+
@back = ColorANSI::Default
186213
@mode = 0
187214
@enabled = Colorize.enabled?
188215
end
189216

190217
{% for name in COLORS %}
191218
def {{name.id}}
192-
@fore = FORE_{{name.upcase.id}}
219+
@fore = ColorANSI::{{name.camelcase.id}}
193220
self
194221
end
195222

196223
def on_{{name.id}}
197-
@back = BACK_{{name.upcase.id}}
224+
@back = ColorANSI::{{name.camelcase.id}}
198225
self
199226
end
200227
{% end %}
@@ -209,25 +236,33 @@ struct Colorize::Object(T)
209236
def fore(color : Symbol)
210237
{% for name in COLORS %}
211238
if color == :{{name.id}}
212-
@fore = FORE_{{name.upcase.id}}
239+
@fore = ColorANSI::{{name.camelcase.id}}
213240
return self
214241
end
215242
{% end %}
216243

217244
raise ArgumentError.new "Unknown color: #{color}"
218245
end
219246

247+
def fore(@fore : Color)
248+
self
249+
end
250+
220251
def back(color : Symbol)
221252
{% for name in COLORS %}
222253
if color == :{{name.id}}
223-
@back = BACK_{{name.upcase.id}}
254+
@back = ColorANSI::{{name.camelcase.id}}
224255
return self
225256
end
226257
{% end %}
227258

228259
raise ArgumentError.new "Unknown color: #{color}"
229260
end
230261

262+
def back(@back : Color)
263+
self
264+
end
265+
231266
def mode(mode : Symbol)
232267
{% for name in MODES %}
233268
if mode == :{{name.id}}
@@ -287,8 +322,8 @@ struct Colorize::Object(T)
287322
protected def append_start(io, reset = false)
288323
return false unless @enabled
289324

290-
fore_is_default = @fore == FORE_DEFAULT
291-
back_is_default = @back == BACK_DEFAULT
325+
fore_is_default = @fore == ColorANSI::Default
326+
back_is_default = @back == ColorANSI::Default
292327
mode_is_default = @mode == 0
293328

294329
if fore_is_default && back_is_default && mode_is_default && !reset
@@ -305,13 +340,13 @@ struct Colorize::Object(T)
305340

306341
unless fore_is_default
307342
io << ';' if printed
308-
io << @fore
343+
@fore.fore io
309344
printed = true
310345
end
311346

312347
unless back_is_default
313348
io << ';' if printed
314-
io << @back
349+
@back.back io
315350
printed = true
316351
end
317352

0 commit comments

Comments
 (0)
Please sign in to comment.