sai 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +11 -0
- data/CHANGELOG.md +18 -0
- data/LICENSE +21 -0
- data/README.md +275 -0
- data/lib/sai/ansi.rb +94 -0
- data/lib/sai/conversion/color_sequence.rb +167 -0
- data/lib/sai/conversion/rgb.rb +322 -0
- data/lib/sai/decorator.rb +856 -0
- data/lib/sai/support.rb +115 -0
- data/lib/sai/terminal/capabilities.rb +121 -0
- data/lib/sai/terminal/color_mode.rb +63 -0
- data/lib/sai.rb +185 -0
- data/sig/sai/ansi.rbs +51 -0
- data/sig/sai/conversion/color_sequence.rbs +114 -0
- data/sig/sai/conversion/rgb.rbs +243 -0
- data/sig/sai/decorator.rbs +246 -0
- data/sig/sai/support.rbs +108 -0
- data/sig/sai/terminal/capabilities.rbs +81 -0
- data/sig/sai/terminal/color_mode.rbs +63 -0
- data/sig/sai.rbs +207 -0
- metadata +67 -0
@@ -0,0 +1,856 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sai/ansi'
|
4
|
+
require 'sai/conversion/color_sequence'
|
5
|
+
|
6
|
+
module Sai
|
7
|
+
# A decorator for applying ANSI styles and colors to text
|
8
|
+
#
|
9
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
10
|
+
# @since unreleased
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
class Decorator
|
14
|
+
# Initialize a new instance of Decorator
|
15
|
+
#
|
16
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
17
|
+
# @since unreleased
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
#
|
21
|
+
# @param color_mode [Integer] the color mode to use
|
22
|
+
#
|
23
|
+
# @return [Decorator] the new instance of Decorator
|
24
|
+
# @rbs (Integer color_mode) -> void
|
25
|
+
def initialize(color_mode)
|
26
|
+
@background = nil
|
27
|
+
@color_mode = color_mode
|
28
|
+
@foreground = nil
|
29
|
+
@styles = [] #: Array[Symbol]
|
30
|
+
end
|
31
|
+
|
32
|
+
# @!method black
|
33
|
+
# Apply the named ANSI color "black" to the foreground
|
34
|
+
#
|
35
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
36
|
+
# @since unreleased
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# decorator.black.decorate('Hello, world!') #=> "\e[30mHello, world!\e[0m"
|
42
|
+
#
|
43
|
+
# @return [self] the instance of Decorator for chaining
|
44
|
+
#
|
45
|
+
# @!method blue
|
46
|
+
# Apply the named ANSI color "blue" to the foreground
|
47
|
+
#
|
48
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
49
|
+
# @since unreleased
|
50
|
+
#
|
51
|
+
# @api public
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
# decorator.blue.decorate('Hello, world!') #=> "\e[34mHello, world!\e[0m"
|
55
|
+
#
|
56
|
+
# @return [self] the instance of Decorator for chaining
|
57
|
+
#
|
58
|
+
# @!method bright_black
|
59
|
+
# Apply the named ANSI color "bright_black" to the foreground
|
60
|
+
#
|
61
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
62
|
+
# @since unreleased
|
63
|
+
#
|
64
|
+
# @api public
|
65
|
+
#
|
66
|
+
# @example
|
67
|
+
# decorator.bright_black.decorate('Hello, world!') #=> "\e[90mHello, world!\e[0m"
|
68
|
+
#
|
69
|
+
# @return [self] the instance of Decorator for chaining
|
70
|
+
#
|
71
|
+
# @!method bright_blue
|
72
|
+
# Apply the named ANSI color "bright_blue" to the foreground
|
73
|
+
#
|
74
|
+
# @api public
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# decorator.bright_blue.decorate('Hello, world!') #=> "\e[94mHello, world!\e[0m"
|
78
|
+
#
|
79
|
+
# @return [self] the instance of Decorator for chaining
|
80
|
+
#
|
81
|
+
# @!method bright_cyan
|
82
|
+
# Apply the named ANSI color "bright_cyan" to the foreground
|
83
|
+
#
|
84
|
+
# @api public
|
85
|
+
#
|
86
|
+
# @example
|
87
|
+
# decorator.bright_cyan.decorate('Hello, world!') #=> "\e[96mHello, world!\e[0m"
|
88
|
+
#
|
89
|
+
# @return [self] the instance of Decorator for chaining
|
90
|
+
#
|
91
|
+
# @!method bright_green
|
92
|
+
# Apply the named ANSI color "bright_green" to the foreground
|
93
|
+
#
|
94
|
+
# @api public
|
95
|
+
#
|
96
|
+
# @example
|
97
|
+
# decorator.bright_green.decorate('Hello, world!') #=> "\e[92mHello, world!\e[0m"
|
98
|
+
#
|
99
|
+
# @return [self] the instance of Decorator for chaining
|
100
|
+
#
|
101
|
+
# @!method bright_magenta
|
102
|
+
# Apply the named ANSI color "bright_magenta" to the foreground
|
103
|
+
#
|
104
|
+
# @api public
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
# decorator.bright_magenta.decorate('Hello, world!') #=> "\e[95mHello, world!\e[0m"
|
108
|
+
#
|
109
|
+
# @return [self] the instance of Decorator for chaining
|
110
|
+
#
|
111
|
+
# @!method bright_red
|
112
|
+
# Apply the named ANSI color "bright_red" to the foreground
|
113
|
+
#
|
114
|
+
# @api public
|
115
|
+
#
|
116
|
+
# @example
|
117
|
+
# decorator.bright_red.decorate('Hello, world!') #=> "\e[91mHello, world!\e[0m"
|
118
|
+
#
|
119
|
+
# @return [self] the instance of Decorator for chaining
|
120
|
+
#
|
121
|
+
# @!method bright_white
|
122
|
+
# Apply the named ANSI color "bright_white" to the foreground
|
123
|
+
#
|
124
|
+
# @api public
|
125
|
+
#
|
126
|
+
# @example
|
127
|
+
# decorator.bright_white.decorate('Hello, world!') #=> "\e[97mHello, world!\e[0m"
|
128
|
+
#
|
129
|
+
# @return [self] the instance of Decorator for chaining
|
130
|
+
#
|
131
|
+
# @!method bright_yellow
|
132
|
+
# Apply the named ANSI color "bright_yellow" to the foreground
|
133
|
+
#
|
134
|
+
# @api public
|
135
|
+
#
|
136
|
+
# @example
|
137
|
+
# decorator.bright_yellow.decorate('Hello, world!') #=> "\e[93mHello, world!\e[0m"
|
138
|
+
#
|
139
|
+
# @return [self] the instance of Decorator for chaining
|
140
|
+
#
|
141
|
+
# @!method cyan
|
142
|
+
# Apply the named ANSI color "cyan" to the foreground
|
143
|
+
#
|
144
|
+
# @api public
|
145
|
+
#
|
146
|
+
# @example
|
147
|
+
# decorator.cyan.decorate('Hello, world!') #=> "\e[36mHello, world!\e[0m"
|
148
|
+
#
|
149
|
+
# @return [self] the instance of Decorator for chaining
|
150
|
+
#
|
151
|
+
# @!method green
|
152
|
+
# Apply the named ANSI color "green" to the foreground
|
153
|
+
#
|
154
|
+
# @api public
|
155
|
+
#
|
156
|
+
# @example
|
157
|
+
# decorator.green.decorate('Hello, world!') #=> "\e[32mHello, world!\e[0m"
|
158
|
+
#
|
159
|
+
# @return [self] the instance of Decorator for chaining
|
160
|
+
#
|
161
|
+
# @!method magenta
|
162
|
+
# Apply the named ANSI color "magenta" to the foreground
|
163
|
+
#
|
164
|
+
# @api public
|
165
|
+
#
|
166
|
+
# @example
|
167
|
+
# decorator.magenta.decorate('Hello, world!') #=> "\e[35mHello, world!\e[0m"
|
168
|
+
#
|
169
|
+
# @return [self] the instance of Decorator for chaining
|
170
|
+
#
|
171
|
+
# @!method on_black
|
172
|
+
# Apply the named ANSI color "black" to the background
|
173
|
+
#
|
174
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
175
|
+
# @since unreleased
|
176
|
+
#
|
177
|
+
# @api public
|
178
|
+
#
|
179
|
+
# @example
|
180
|
+
# decorator.on_black.decorate('Hello, world!') #=> "\e[40mHello, world!\e[0m"
|
181
|
+
#
|
182
|
+
# @return [self] the instance of Decorator for chaining
|
183
|
+
#
|
184
|
+
# @!method on_blue
|
185
|
+
# Apply the named ANSI color "blue" to the background
|
186
|
+
#
|
187
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
188
|
+
# @since unreleased
|
189
|
+
#
|
190
|
+
# @api public
|
191
|
+
#
|
192
|
+
# @example
|
193
|
+
# decorator.on_blue.decorate('Hello, world!') #=> "\e[44mHello, world!\e[0m"
|
194
|
+
#
|
195
|
+
# @return [self] the instance of Decorator for chaining
|
196
|
+
#
|
197
|
+
# @!method on_bright_black
|
198
|
+
# Apply the named ANSI color "bright_black" to the background
|
199
|
+
#
|
200
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
201
|
+
# @since unreleased
|
202
|
+
#
|
203
|
+
# @api public
|
204
|
+
#
|
205
|
+
# @example
|
206
|
+
# decorator.on_bright_black.decorate('Hello, world!') #=> "\e[100mHello, world!\e[0m"
|
207
|
+
#
|
208
|
+
# @return [self] the instance of Decorator for chaining
|
209
|
+
#
|
210
|
+
# @!method on_bright_blue
|
211
|
+
# Apply the named ANSI color "bright_blue" to the background
|
212
|
+
#
|
213
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
214
|
+
# @since unreleased
|
215
|
+
#
|
216
|
+
# @api public
|
217
|
+
#
|
218
|
+
# @example
|
219
|
+
# decorator.on_bright_blue.decorate('Hello, world!') #=> "\e[104mHello, world!\e[0m"
|
220
|
+
#
|
221
|
+
# @return [self] the instance of Decorator for chaining
|
222
|
+
#
|
223
|
+
# @!method on_bright_cyan
|
224
|
+
# Apply the named ANSI color "bright_cyan" to the background
|
225
|
+
#
|
226
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
227
|
+
# @since unreleased
|
228
|
+
#
|
229
|
+
# @api public
|
230
|
+
#
|
231
|
+
# @example
|
232
|
+
# decorator.on_bright_cyan.decorate('Hello, world!') #=> "\e[106mHello, world!\e[0m"
|
233
|
+
#
|
234
|
+
# @return [self] the instance of Decorator for chaining
|
235
|
+
#
|
236
|
+
# @!method on_bright_green
|
237
|
+
# Apply the named ANSI color "bright_green" to the background
|
238
|
+
#
|
239
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
240
|
+
# @since unreleased
|
241
|
+
#
|
242
|
+
# @api public
|
243
|
+
#
|
244
|
+
# @example
|
245
|
+
# decorator.on_bright_green.decorate('Hello, world!') #=> "\e[102mHello, world!\e[0m"
|
246
|
+
#
|
247
|
+
# @return [self] the instance of Decorator for chaining
|
248
|
+
#
|
249
|
+
# @!method on_bright_magenta
|
250
|
+
# Apply the named ANSI color "bright_magenta" to the background
|
251
|
+
#
|
252
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
253
|
+
# @since unreleased
|
254
|
+
#
|
255
|
+
# @api public
|
256
|
+
#
|
257
|
+
# @example
|
258
|
+
# decorator.on_bright_magenta.decorate('Hello, world!') #=> "\e[105mHello, world!\e[0m"
|
259
|
+
#
|
260
|
+
# @return [self] the instance of Decorator for chaining
|
261
|
+
#
|
262
|
+
# @!method on_bright_red
|
263
|
+
# Apply the named ANSI color "bright_red" to the background
|
264
|
+
#
|
265
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
266
|
+
# @since unreleased
|
267
|
+
#
|
268
|
+
# @api public
|
269
|
+
#
|
270
|
+
# @example
|
271
|
+
# decorator.on_bright_red.decorate('Hello, world!') #=> "\e[101mHello, world!\e[0m"
|
272
|
+
#
|
273
|
+
# @return [self] the instance of Decorator for chaining
|
274
|
+
#
|
275
|
+
# @!method on_bright_white
|
276
|
+
# Apply the named ANSI color "bright_white" to the background
|
277
|
+
#
|
278
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
279
|
+
# @since unreleased
|
280
|
+
#
|
281
|
+
# @api public
|
282
|
+
#
|
283
|
+
# @example
|
284
|
+
# decorator.on_bright_white.decorate('Hello, world!') #=> "\e[107mHello, world!\e[0m"
|
285
|
+
#
|
286
|
+
# @return [self] the instance of Decorator for chaining
|
287
|
+
#
|
288
|
+
# @!method on_bright_yellow
|
289
|
+
# Apply the named ANSI color "bright_yellow" to the background
|
290
|
+
#
|
291
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
292
|
+
# @since unreleased
|
293
|
+
#
|
294
|
+
# @api public
|
295
|
+
#
|
296
|
+
# @example
|
297
|
+
# decorator.on_bright_yellow.decorate('Hello, world!') #=> "\e[103mHello, world!\e[0m"
|
298
|
+
#
|
299
|
+
# @return [self] the instance of Decorator for chaining
|
300
|
+
#
|
301
|
+
# @!method on_cyan
|
302
|
+
# Apply the named ANSI color "cyan" to the background
|
303
|
+
#
|
304
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
305
|
+
# @since unreleased
|
306
|
+
#
|
307
|
+
# @api public
|
308
|
+
#
|
309
|
+
# @example
|
310
|
+
# decorator.on_cyan.decorate('Hello, world!') #=> "\e[46mHello, world!\e[0m"
|
311
|
+
#
|
312
|
+
# @return [self] the instance of Decorator for chaining
|
313
|
+
#
|
314
|
+
# @!method on_green
|
315
|
+
# Apply the named ANSI color "green" to the background
|
316
|
+
#
|
317
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
318
|
+
# @since unreleased
|
319
|
+
#
|
320
|
+
# @api public
|
321
|
+
#
|
322
|
+
# @example
|
323
|
+
# decorator.on_green.decorate('Hello, world!') #=> "\e[42mHello, world!\e[0m"
|
324
|
+
#
|
325
|
+
# @return [self] the instance of Decorator for chaining
|
326
|
+
#
|
327
|
+
# @!method on_magenta
|
328
|
+
# Apply the named ANSI color "magenta" to the background
|
329
|
+
#
|
330
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
331
|
+
# @since unreleased
|
332
|
+
#
|
333
|
+
# @api public
|
334
|
+
#
|
335
|
+
# @example
|
336
|
+
# decorator.on_magenta.decorate('Hello, world!') #=> "\e[45mHello, world!\e[0m"
|
337
|
+
#
|
338
|
+
# @return [self] the instance of Decorator for chaining
|
339
|
+
#
|
340
|
+
# @!method on_red
|
341
|
+
# Apply the named ANSI color "red" to the background
|
342
|
+
#
|
343
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
344
|
+
# @since unreleased
|
345
|
+
#
|
346
|
+
# @api public
|
347
|
+
#
|
348
|
+
# @example
|
349
|
+
# decorator.on_red.decorate('Hello, world!') #=> "\e[41mHello, world!\e[0m"
|
350
|
+
#
|
351
|
+
# @return [self] the instance of Decorator for chaining
|
352
|
+
#
|
353
|
+
# @!method on_white
|
354
|
+
# Apply the named ANSI color "white" to the background
|
355
|
+
#
|
356
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
357
|
+
# @since unreleased
|
358
|
+
#
|
359
|
+
# @api public
|
360
|
+
#
|
361
|
+
# @example
|
362
|
+
# decorator.on_white.decorate('Hello, world!') #=> "\e[47mHello, world!\e[0m"
|
363
|
+
#
|
364
|
+
# @return [self] the instance of Decorator for chaining
|
365
|
+
#
|
366
|
+
# @!method on_yellow
|
367
|
+
# Apply the named ANSI color "yellow" to the background
|
368
|
+
#
|
369
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
370
|
+
# @since unreleased
|
371
|
+
#
|
372
|
+
# @api public
|
373
|
+
#
|
374
|
+
# @example
|
375
|
+
# decorator.on_yellow.decorate('Hello, world!') #=> "\e[43mHello, world!\e[0m"
|
376
|
+
#
|
377
|
+
# @return [self] the instance of Decorator for chaining
|
378
|
+
#
|
379
|
+
# @!method red
|
380
|
+
# Apply the named ANSI color "red" to the foreground
|
381
|
+
#
|
382
|
+
# @api public
|
383
|
+
#
|
384
|
+
# @example
|
385
|
+
# decorator.red.decorate('Hello, world!') #=> "\e[31mHello, world!\e[0m"
|
386
|
+
#
|
387
|
+
# @return [self] the instance of Decorator for chaining
|
388
|
+
#
|
389
|
+
# @!method white
|
390
|
+
# Apply the named ANSI color "white" to the foreground
|
391
|
+
#
|
392
|
+
# @api public
|
393
|
+
#
|
394
|
+
# @example
|
395
|
+
# decorator.white.decorate('Hello, world!') #=> "\e[37mHello, world!\e[0m"
|
396
|
+
#
|
397
|
+
# @return [self] the instance of Decorator for chaining
|
398
|
+
#
|
399
|
+
# @!method yellow
|
400
|
+
# Apply the named ANSI color "yellow" to the foreground
|
401
|
+
#
|
402
|
+
# @api public
|
403
|
+
#
|
404
|
+
# @example
|
405
|
+
# decorator.yellow.decorate('Hello, world!') #=> "\e[33mHello, world!\e[0m"
|
406
|
+
#
|
407
|
+
# @return [self] the instance of Decorator for chaining
|
408
|
+
ANSI::COLOR_NAMES.each_key do |color|
|
409
|
+
define_method(color) do
|
410
|
+
apply_named_color(:foreground, color)
|
411
|
+
end
|
412
|
+
define_method(:"on_#{color}") do
|
413
|
+
apply_named_color(:background, color)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
# @rbs!
|
417
|
+
# def black: () -> self
|
418
|
+
# def blue: () -> self
|
419
|
+
# def bright_black: () -> self
|
420
|
+
# def bright_blue: () -> self
|
421
|
+
# def bright_cyan: () -> self
|
422
|
+
# def bright_green: () -> self
|
423
|
+
# def bright_magenta: () -> self
|
424
|
+
# def bright_red: () -> self
|
425
|
+
# def bright_white: () -> self
|
426
|
+
# def bright_yellow: () -> self
|
427
|
+
# def cyan: () -> self
|
428
|
+
# def green: () -> self
|
429
|
+
# def magenta: () -> self
|
430
|
+
# def on_black: () -> self
|
431
|
+
# def on_blue: () -> self
|
432
|
+
# def on_bright_black: () -> self
|
433
|
+
# def on_bright_blue: () -> self
|
434
|
+
# def on_bright_cyan: () -> self
|
435
|
+
# def on_bright_green: () -> self
|
436
|
+
# def on_bright_magenta: () -> self
|
437
|
+
# def on_bright_red: () -> self
|
438
|
+
# def on_bright_white: () -> self
|
439
|
+
# def on_bright_yellow: () -> self
|
440
|
+
# def on_cyan: () -> self
|
441
|
+
# def on_green: () -> self
|
442
|
+
# def on_magenta: () -> self
|
443
|
+
# def on_red: () -> self
|
444
|
+
# def on_white: () -> self
|
445
|
+
# def on_yellow: () -> self
|
446
|
+
# def red: () -> self
|
447
|
+
# def white: () -> self
|
448
|
+
# def yellow: () -> self
|
449
|
+
|
450
|
+
# @!method blink
|
451
|
+
# Apply the ANSI style "blink" to the text
|
452
|
+
#
|
453
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
454
|
+
# @since unreleased
|
455
|
+
#
|
456
|
+
# @api public
|
457
|
+
#
|
458
|
+
# @example
|
459
|
+
# decorator.blink.decorate('Hello, world!') #=> "\e[5mHello, world!\e[0m"
|
460
|
+
#
|
461
|
+
# @return [self] the instance of Decorator for chaining
|
462
|
+
#
|
463
|
+
# @!method bold
|
464
|
+
# Apply the ANSI style "bold" to the text
|
465
|
+
#
|
466
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
467
|
+
# @since unreleased
|
468
|
+
#
|
469
|
+
# @api public
|
470
|
+
#
|
471
|
+
# @example
|
472
|
+
# decorator.bold.decorate('Hello, world!') #=> "\e[1mHello, world!\e[0m"
|
473
|
+
#
|
474
|
+
# @return [self] the instance of Decorator for chaining
|
475
|
+
#
|
476
|
+
# @!method conceal
|
477
|
+
# Apply the ANSI style "conceal" to the text
|
478
|
+
#
|
479
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
480
|
+
# @since unreleased
|
481
|
+
#
|
482
|
+
# @api public
|
483
|
+
#
|
484
|
+
# @example
|
485
|
+
# decorator.conceal.decorate('Hello, world!') #=> "\e[8mHello, world!\e[0m"
|
486
|
+
#
|
487
|
+
# @return [self] the instance of Decorator for chaining
|
488
|
+
#
|
489
|
+
# @!method dim
|
490
|
+
# Apply the ANSI style "dim" to the text
|
491
|
+
#
|
492
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
493
|
+
# @since unreleased
|
494
|
+
#
|
495
|
+
# @api public
|
496
|
+
#
|
497
|
+
# @example
|
498
|
+
# decorator.dim.decorate('Hello, world!') #=> "\e[2mHello, world!\e[0m"
|
499
|
+
#
|
500
|
+
# @return [self] the instance of Decorator for chaining
|
501
|
+
#
|
502
|
+
# @!method italic
|
503
|
+
# Apply the ANSI style "italic" to the text
|
504
|
+
#
|
505
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
506
|
+
# @since unreleased
|
507
|
+
#
|
508
|
+
# @api public
|
509
|
+
#
|
510
|
+
# @example
|
511
|
+
# decorator.italic.decorate('Hello, world!') #=> "\e[3mHello, world!\e[0m"
|
512
|
+
#
|
513
|
+
# @return [self] the instance of Decorator for chaining
|
514
|
+
#
|
515
|
+
# @!method no_blink
|
516
|
+
# Remove the ANSI style "blink" from the text
|
517
|
+
#
|
518
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
519
|
+
# @since unreleased
|
520
|
+
#
|
521
|
+
# @api public
|
522
|
+
#
|
523
|
+
# @example
|
524
|
+
# decorator.no_blink.decorate('Hello, world!') #=> "\e[25mHello, world!\e[0m"
|
525
|
+
#
|
526
|
+
# @return [self] the instance of Decorator for chaining
|
527
|
+
#
|
528
|
+
# @!method no_conceal
|
529
|
+
# Remove the ANSI style "conceal" from the text
|
530
|
+
#
|
531
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
532
|
+
# @since unreleased
|
533
|
+
#
|
534
|
+
# @api public
|
535
|
+
#
|
536
|
+
# @example
|
537
|
+
# decorator.no_conceal.decorate('Hello, world!') #=> "\e[28mHello, world!\e[0m"
|
538
|
+
#
|
539
|
+
# @return [self] the instance of Decorator for chaining
|
540
|
+
#
|
541
|
+
# @!method no_italic
|
542
|
+
# Remove the ANSI style "italic" from the text
|
543
|
+
#
|
544
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
545
|
+
# @since unreleased
|
546
|
+
#
|
547
|
+
# @api public
|
548
|
+
#
|
549
|
+
# @example
|
550
|
+
# decorator.no_italic.decorate('Hello, world!') #=> "\e[23mHello, world!\e[0m"
|
551
|
+
#
|
552
|
+
# @return [self] the instance of Decorator for chaining
|
553
|
+
#
|
554
|
+
# @!method no_reverse
|
555
|
+
# Remove the ANSI style "reverse" from the text
|
556
|
+
#
|
557
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
558
|
+
# @since unreleased
|
559
|
+
#
|
560
|
+
# @api public
|
561
|
+
#
|
562
|
+
# @example
|
563
|
+
# decorator.no_reverse.decorate('Hello, world!') #=> "\e[27mHello, world!\e[0m"
|
564
|
+
#
|
565
|
+
# @return [self] the instance of Decorator for chaining
|
566
|
+
#
|
567
|
+
# @!method no_strike
|
568
|
+
# Remove the ANSI style "strike" from the text
|
569
|
+
#
|
570
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
571
|
+
# @since unreleased
|
572
|
+
#
|
573
|
+
# @api public
|
574
|
+
#
|
575
|
+
# @example
|
576
|
+
# decorator.no_strike.decorate('Hello, world!') #=> "\e[29mHello, world!\e[0m"
|
577
|
+
#
|
578
|
+
# @return [self] the instance of Decorator for chaining
|
579
|
+
#
|
580
|
+
# @!method no_underline
|
581
|
+
# Remove the ANSI style "underline" from the text
|
582
|
+
#
|
583
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
584
|
+
# @since unreleased
|
585
|
+
#
|
586
|
+
# @api public
|
587
|
+
#
|
588
|
+
# @example
|
589
|
+
# decorator.no_underline.decorate('Hello, world!') #=> "\e[24mHello, world!\e[0m"
|
590
|
+
#
|
591
|
+
# @return [self] the instance of Decorator for chaining
|
592
|
+
#
|
593
|
+
# @!method normal_intensity
|
594
|
+
# Remove any intensity styles (bold or dim) from the text
|
595
|
+
#
|
596
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
597
|
+
# @since unreleased
|
598
|
+
#
|
599
|
+
# @api public
|
600
|
+
#
|
601
|
+
# @example
|
602
|
+
# decorator.normal_intensity.decorate('Hello, world!') #=> "\e[22mHello, world!\e[0m"
|
603
|
+
#
|
604
|
+
# @return [self] the instance of Decorator for chaining
|
605
|
+
#
|
606
|
+
# @!method rapid_blink
|
607
|
+
# Apply the ANSI style "rapid_blink" to the text
|
608
|
+
#
|
609
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
610
|
+
# @since unreleased
|
611
|
+
#
|
612
|
+
# @api public
|
613
|
+
#
|
614
|
+
# @example
|
615
|
+
# decorator.rapid_blink.decorate('Hello, world!') #=> "\e[6mHello, world!\e[0m"
|
616
|
+
#
|
617
|
+
# @return [self] the instance of Decorator for chaining
|
618
|
+
#
|
619
|
+
# @!method reverse
|
620
|
+
# Apply the ANSI style "reverse" to the text
|
621
|
+
#
|
622
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
623
|
+
# @since unreleased
|
624
|
+
#
|
625
|
+
# @api public
|
626
|
+
#
|
627
|
+
# @example
|
628
|
+
# decorator.reverse.decorate('Hello, world!') #=> "\e[7mHello, world!\e[0m"
|
629
|
+
#
|
630
|
+
# @return [self] the instance of Decorator for chaining
|
631
|
+
#
|
632
|
+
# @!method strike
|
633
|
+
# Apply the ANSI style "strike" to the text
|
634
|
+
#
|
635
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
636
|
+
# @since unreleased
|
637
|
+
#
|
638
|
+
# @api public
|
639
|
+
#
|
640
|
+
# @example
|
641
|
+
# decorator.strike.decorate('Hello, world!') #=> "\e[9mHello, world!\e[0m"
|
642
|
+
#
|
643
|
+
# @return [self] the instance of Decorator for chaining
|
644
|
+
#
|
645
|
+
# @!method underline
|
646
|
+
# Apply the ANSI style "underline" to the text
|
647
|
+
#
|
648
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
649
|
+
# @since unreleased
|
650
|
+
#
|
651
|
+
# @api public
|
652
|
+
#
|
653
|
+
# @example
|
654
|
+
# decorator.underline.decorate('Hello, world!') #=> "\e[4mHello, world!\e[0m"
|
655
|
+
#
|
656
|
+
# @return [self] the instance of Decorator for chaining
|
657
|
+
ANSI::STYLES.each_key do |style|
|
658
|
+
define_method(style) do
|
659
|
+
apply_style(style)
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
# @rbs!
|
664
|
+
# def blink: () -> self
|
665
|
+
# def bold: () -> self
|
666
|
+
# def conceal: () -> self
|
667
|
+
# def dim: () -> self
|
668
|
+
# def italic: () -> self
|
669
|
+
# def no_blink: () -> self
|
670
|
+
# def no_conceal: () -> self
|
671
|
+
# def no_italic: () -> self
|
672
|
+
# def no_reverse: () -> self
|
673
|
+
# def no_strike: () -> self
|
674
|
+
# def no_underline: () -> self
|
675
|
+
# def normal_intensity: () -> self
|
676
|
+
# def rapid_blink: () -> self
|
677
|
+
# def reverse: () -> self
|
678
|
+
# def strike: () -> self
|
679
|
+
# def underline: () -> self
|
680
|
+
|
681
|
+
# Apply the styles and colors to the text
|
682
|
+
#
|
683
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
684
|
+
# @since unreleased
|
685
|
+
#
|
686
|
+
# @api public
|
687
|
+
#
|
688
|
+
# @example
|
689
|
+
# decorator.red.on_blue.bold.decorate('Hello, world!')
|
690
|
+
# #=> "\e[38;2;205;0;0m\e[48;2;0;0;238m\e[1mHello, world!\e[0m"
|
691
|
+
#
|
692
|
+
# @param text [String] the text to decorate
|
693
|
+
#
|
694
|
+
# @return [String] the decorated text
|
695
|
+
# @rbs (String text) -> String
|
696
|
+
def decorate(text)
|
697
|
+
return text if @foreground.nil? && @background.nil? && @styles.empty?
|
698
|
+
|
699
|
+
sequences = [
|
700
|
+
@foreground && Conversion::ColorSequence.resolve(@foreground, @color_mode),
|
701
|
+
@background && Conversion::ColorSequence.resolve(@background, @color_mode, :background),
|
702
|
+
@styles.map { |style| "\e[#{ANSI::STYLES[style]}m" }.join
|
703
|
+
].compact.join
|
704
|
+
|
705
|
+
"#{sequences}#{text}#{ANSI::RESET}"
|
706
|
+
end
|
707
|
+
alias apply decorate
|
708
|
+
alias call decorate
|
709
|
+
alias encode decorate
|
710
|
+
|
711
|
+
# Apply a hexadecimal color to the foreground
|
712
|
+
#
|
713
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
714
|
+
# @since unreleased
|
715
|
+
#
|
716
|
+
# @api public
|
717
|
+
#
|
718
|
+
# @example
|
719
|
+
# decorator.hex("#EB4133").decorate('Hello, world!') #=> "\e[38;2;235;65;51mHello, world!\e[0m"
|
720
|
+
#
|
721
|
+
# @param code [String] the hex color code
|
722
|
+
#
|
723
|
+
# @raise [ArgumentError] if the hex code is invalid
|
724
|
+
# @return [self] the instance of Decorator for chaining
|
725
|
+
# @rbs (String code) -> self
|
726
|
+
def hex(code)
|
727
|
+
raise ArgumentError, "Invalid hex color code: #{code}" unless /^#?([A-Fa-f0-9]{6})$/.match?(code)
|
728
|
+
|
729
|
+
@foreground = code
|
730
|
+
self
|
731
|
+
end
|
732
|
+
|
733
|
+
# Apply a hexadecimal color to the background
|
734
|
+
#
|
735
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
736
|
+
# @since unreleased
|
737
|
+
#
|
738
|
+
# @api public
|
739
|
+
#
|
740
|
+
# @example
|
741
|
+
# decorator.on_hex("#EB4133").decorate('Hello, world!') #=> "\e[48;2;235;65;51mHello, world!\e[0m"
|
742
|
+
#
|
743
|
+
# @param code [String] the hex color code
|
744
|
+
#
|
745
|
+
# @raise [ArgumentError] if the hex code is invalid
|
746
|
+
# @return [self] the instance of Decorator for chaining
|
747
|
+
# @rbs (String code) -> self
|
748
|
+
def on_hex(code)
|
749
|
+
raise ArgumentError, "Invalid hex color code: #{code}" unless /^#?([A-Fa-f0-9]{6})$/.match?(code)
|
750
|
+
|
751
|
+
@background = code
|
752
|
+
self
|
753
|
+
end
|
754
|
+
|
755
|
+
# Apply an RGB color to the background
|
756
|
+
#
|
757
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
758
|
+
# @since unreleased
|
759
|
+
#
|
760
|
+
# @api public
|
761
|
+
#
|
762
|
+
# @example
|
763
|
+
# decorator.on_rgb(235, 65, 51).decorate('Hello, world!') #=> "\e[48;2;235;65;51mHello, world!\e[0m"
|
764
|
+
#
|
765
|
+
# @param red [Integer] the red component
|
766
|
+
# @param green [Integer] the green component
|
767
|
+
# @param blue [Integer] the blue component
|
768
|
+
#
|
769
|
+
# @raise [ArgumentError] if the RGB values are out of range
|
770
|
+
# @return [self] the instance of Decorator for chaining
|
771
|
+
# @rbs (Integer red, Integer green, Integer blue) -> self
|
772
|
+
def on_rgb(red, green, blue)
|
773
|
+
[red, green, blue].each do |value|
|
774
|
+
raise ArgumentError, "Invalid RGB value: #{red}, #{green}, #{blue}" unless value >= 0 && value <= 255
|
775
|
+
end
|
776
|
+
|
777
|
+
@background = [red, green, blue]
|
778
|
+
self
|
779
|
+
end
|
780
|
+
|
781
|
+
# Apply an RGB color to the foreground
|
782
|
+
#
|
783
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
784
|
+
# @since unreleased
|
785
|
+
#
|
786
|
+
# @api public
|
787
|
+
#
|
788
|
+
# @example
|
789
|
+
# decorator.rgb(235, 65, 51).decorate('Hello, world!') #=> "\e[38;2;235;65;51mHello, world!\e[0m"
|
790
|
+
#
|
791
|
+
# @param red [Integer] the red component
|
792
|
+
# @param green [Integer] the green component
|
793
|
+
# @param blue [Integer] the blue component
|
794
|
+
#
|
795
|
+
# @raise [ArgumentError] if the RGB values are out of range
|
796
|
+
# @return [self] the instance of Decorator for chaining
|
797
|
+
# @rbs (Integer red, Integer green, Integer blue) -> self
|
798
|
+
def rgb(red, green, blue)
|
799
|
+
[red, green, blue].each do |value|
|
800
|
+
raise ArgumentError, "Invalid RGB value: #{red}, #{green}, #{blue}" unless value >= 0 && value <= 255
|
801
|
+
end
|
802
|
+
|
803
|
+
@foreground = [red, green, blue]
|
804
|
+
self
|
805
|
+
end
|
806
|
+
|
807
|
+
private
|
808
|
+
|
809
|
+
# Apply a named color to the specified style type
|
810
|
+
#
|
811
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
812
|
+
# @since unreleased
|
813
|
+
#
|
814
|
+
# @api private
|
815
|
+
#
|
816
|
+
# @param style_type [Symbol] the style type to apply the color to
|
817
|
+
# @param color [Symbol] the color to apply
|
818
|
+
#
|
819
|
+
# @raise [ArgumentError] if the color is invalid
|
820
|
+
# @return [self] the instance of Decorator for chaining
|
821
|
+
# @rbs (Conversion::ColorSequence::style_type style_type, Symbol color) -> self
|
822
|
+
def apply_named_color(style_type, color)
|
823
|
+
unless ANSI::COLOR_NAMES.key?(color.to_s.downcase.to_sym)
|
824
|
+
e = ArgumentError.new("Invalid color: #{color}")
|
825
|
+
e.set_backtrace(caller_locations(1, 1)&.map(&:to_s)) # steep:ignore UnresolvedOverloading
|
826
|
+
raise e
|
827
|
+
end
|
828
|
+
|
829
|
+
instance_variable_set(:"@#{style_type}", color)
|
830
|
+
self
|
831
|
+
end
|
832
|
+
|
833
|
+
# Apply a style to the text
|
834
|
+
#
|
835
|
+
# @author {https://aaronmallen.me Aaron Allen}
|
836
|
+
# @since unreleased
|
837
|
+
#
|
838
|
+
# @api private
|
839
|
+
#
|
840
|
+
# @param style [String, Symbol] the style to apply
|
841
|
+
#
|
842
|
+
# @raise [ArgumentError] if the style is invalid
|
843
|
+
# @return [self] the instance of Decorator for chaining
|
844
|
+
# @rbs (String | Symbol style) -> self
|
845
|
+
def apply_style(style)
|
846
|
+
unless ANSI::STYLES.key?(style.to_s.downcase.to_sym)
|
847
|
+
e = ArgumentError.new("Invalid style: #{style}")
|
848
|
+
e.set_backtrace(caller_locations(1, 1)&.map(&:to_s)) # steep:ignore UnresolvedOverloading
|
849
|
+
raise e
|
850
|
+
end
|
851
|
+
|
852
|
+
@styles = @styles.push(style.to_s.downcase.to_sym).uniq
|
853
|
+
self
|
854
|
+
end
|
855
|
+
end
|
856
|
+
end
|