sai 0.2.0 → 0.3.1

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