natty-ui 0.7.0 → 0.9.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +7 -3
  3. data/README.md +25 -47
  4. data/examples/24bit-colors.rb +27 -0
  5. data/examples/3bit-colors.rb +14 -0
  6. data/examples/8bit-colors.rb +31 -0
  7. data/examples/animate.rb +24 -0
  8. data/examples/attributes.rb +25 -159
  9. data/examples/demo.rb +53 -0
  10. data/examples/illustration.png +0 -0
  11. data/examples/illustration.rb +29 -0
  12. data/examples/{list_in_columns.rb → ls.rb} +13 -20
  13. data/examples/message.rb +30 -0
  14. data/examples/progress.rb +25 -30
  15. data/examples/query.rb +26 -28
  16. data/examples/read_key.rb +13 -0
  17. data/examples/table.rb +36 -0
  18. data/lib/natty-ui/ansi.rb +351 -305
  19. data/lib/natty-ui/ansi_constants.rb +73 -0
  20. data/lib/natty-ui/ansi_wrapper.rb +136 -162
  21. data/lib/natty-ui/features.rb +11 -18
  22. data/lib/natty-ui/key_map.rb +119 -0
  23. data/lib/natty-ui/line_animation/default.rb +35 -0
  24. data/lib/natty-ui/line_animation/matrix.rb +28 -0
  25. data/lib/natty-ui/line_animation/rainbow.rb +30 -0
  26. data/lib/natty-ui/line_animation/test.rb +29 -0
  27. data/lib/natty-ui/line_animation/type_writer.rb +64 -0
  28. data/lib/natty-ui/line_animation.rb +54 -0
  29. data/lib/natty-ui/version.rb +2 -2
  30. data/lib/natty-ui/wrapper/animate.rb +17 -0
  31. data/lib/natty-ui/wrapper/ask.rb +21 -21
  32. data/lib/natty-ui/wrapper/element.rb +19 -23
  33. data/lib/natty-ui/wrapper/framed.rb +29 -19
  34. data/lib/natty-ui/wrapper/heading.rb +26 -53
  35. data/lib/natty-ui/wrapper/horizontal_rule.rb +37 -0
  36. data/lib/natty-ui/wrapper/list_in_columns.rb +71 -12
  37. data/lib/natty-ui/wrapper/message.rb +20 -27
  38. data/lib/natty-ui/wrapper/progress.rb +40 -13
  39. data/lib/natty-ui/wrapper/query.rb +34 -31
  40. data/lib/natty-ui/wrapper/quote.rb +25 -0
  41. data/lib/natty-ui/wrapper/request.rb +21 -10
  42. data/lib/natty-ui/wrapper/section.rb +55 -39
  43. data/lib/natty-ui/wrapper/table.rb +298 -0
  44. data/lib/natty-ui/wrapper/task.rb +6 -7
  45. data/lib/natty-ui/wrapper.rb +123 -41
  46. data/lib/natty-ui.rb +65 -40
  47. metadata +28 -9
  48. data/examples/basic.rb +0 -62
data/lib/natty-ui/ansi.rb CHANGED
@@ -6,141 +6,147 @@ module NattyUI
6
6
  #
7
7
  module Ansi
8
8
  class << self
9
- # @return [String] ANSI code to reset all attributes
10
- def reset = "\e[0m"
11
-
12
- # @return [String] ANSI code to save current screen state
13
- def screen_save = "\e[?47h"
14
-
15
- # @return [String] ANSI code to restore screen state
16
- def screen_restore = "\e[?47l"
17
-
18
- # @return [String] ANSI code to alternate screen
19
- def screen_alternative = "\e[?1049h"
20
-
21
- # @return [String] ANSI code to set alternate screen off
22
- def screen_alternative_off = "\e[?1049l"
23
-
24
- # @return [String] ANSI code to erase screen
25
- def screen_erase = "\e[2J"
26
-
27
- # @return [String] ANSI code to erase screen below current cursor position
28
- def screen_erase_below = "\e[0J"
29
-
30
- # @return [String] ANSI code to erase screen above current cursor position
31
- def screen_erase_above = "\e[1J"
32
-
33
- # @return [String] ANSI code to erase current line
34
- def line_erase = "\e[2K"
35
-
36
- # @return [String] ANSI code to erase to end of current line
37
- def line_erase_to_end = "\e[0K"
38
-
39
- # @return [String] ANSI code to erase to begin of current line
40
- def line_erase_to_begin = "\e[1K"
41
-
42
- # @return [String] ANSI code to erase current line and position to first
43
- # column
44
- def line_clear = "\e[1K\e[0G"
45
-
46
- # @param lines [Integer] number of lines
47
- # @return [String] ANSI code to move the cursor up
48
- def cursor_up(lines = nil) = "\e[#{lines}A"
49
-
50
- # @param lines [Integer] number of lines
51
- # @return [String] ANSI code to move the cursor down
52
- def cursor_down(lines = nil) = "\e[#{lines}B"
53
-
54
- # @param columns [Integer] number of columns
55
- # @return [String] ANSI code to move the cursor right
56
- def cursor_right(columns = nil) = "\e[#{columns}C"
57
-
58
- # @param columns [Integer] number of columns
59
- # @return [String] ANSI code to move the cursor left
60
- def cursor_left(columns = nil) = "\e[#{columns}D"
9
+ # Supported attribute names.
10
+ # @see []
11
+ #
12
+ # @attribute [r] attribute_names
13
+ # @return [Array<Symbol>] supported attribute names
14
+ def attribute_names = SATTR.keys.sort!
61
15
 
62
- # @param lines [Integer] number of lines
63
- # @return [String] ANSI code to move the cursor to beginning of the line
64
- # some lines down
65
- def cursor_line_down(lines = nil) = "\e[#{lines}E"
16
+ # Supported color names.
17
+ # @see []
18
+ #
19
+ # @attribute [r] color_names
20
+ # @return [Array<Symbol>] supported color names
21
+ def color_names = SCLR.keys
66
22
 
67
- # @param lines [Integer] number of lines
68
- # @return [String] ANSI code to move the cursor to beginning of the line
69
- # some lines up
70
- def cursor_line_up(lines = nil) = "\e[#{lines}F"
23
+ # @!group Control functions
71
24
 
72
- # @param columns [Integer] number of columns
73
- # @return [String] ANSI code to move the cursor to given column
74
- def cursor_column(columns = nil) = "\e[#{columns}G"
25
+ # Move cursor given lines up.
26
+ #
27
+ # @param lines [Integer] number of lines to move
28
+ # @return [String] ANSI control code
29
+ def cursor_up(lines = 1) = "\e[#{lines}A"
75
30
 
76
- # @return [String] ANSI code positioning the cursor on right hand side of
77
- # the terminal
78
- def cursor_right_aligned = "\e[9999G\e[D\e[C"
31
+ # Move cursor given lines down.
32
+ #
33
+ # @param (see cursor_up)
34
+ # @return (see cursor_up)
35
+ def cursor_down(lines = 1) = "\e[#{lines}B"
79
36
 
80
- # @return [String] ANSI code to hide the cursor
81
- def cursor_hide = "\e[?25l"
37
+ # Move cursor given colums forward.
38
+ #
39
+ # @param columns [Integer] number of columns to move
40
+ # @return (see cursor_up)
41
+ def cursor_forward(columns = 1) = "\e[#{columns}C"
82
42
 
83
- # @return [String] ANSI code to show the cursor (again)
84
- def cursor_show = "\e[?25h"
43
+ # Move cursor given colums back.
44
+ #
45
+ # @param (see cursor_forward)
46
+ # @return (see cursor_up)
47
+ def cursor_back(columns = 1) = "\e[#{columns}D"
85
48
 
86
- # @return [String] ANSI code to save current cursor position
87
- def cursor_save_pos = "\e[s"
49
+ # Move cursor of beginning of the given next line.
50
+ #
51
+ # @param (see cursor_up)
52
+ # @return (see cursor_up)
53
+ def cursor_next_line(lines = 1) = "\e[#{lines}E"
88
54
 
89
- # @return [String] ANSI code to restore saved cursor position
90
- def cursor_restore_pos = "\e[u"
55
+ # Move cursor of beginning of the given previous line.
56
+ #
57
+ # @param (see cursor_up)
58
+ # @return (see cursor_up)
59
+ def cursor_previous_line(lines = 1) = "\e[#{lines}F"
60
+ alias cursor_prev_line cursor_previous_line
91
61
 
92
- # @return [String] ANSI code to set cursor position on upper left corner
93
- def cursor_home = "\e[H"
62
+ # Move cursor to given column in the current row.
63
+ #
64
+ # @param column [Integer] column index
65
+ # @return (see cursor_up)
66
+ def cursor_column(column = 1) = "\e[#{column}G"
94
67
 
95
- # @param row [Integer] row to set cursor
96
- # @param column [Integer] column to set cursor
97
- # @return [String] ANSI code to set cursor position
68
+ # Move cursor to given row and column counting from the top left corner.
69
+ #
70
+ # @param row [Integer] row index
71
+ # @param column [Integer] column index
72
+ # @return (see cursor_up)
98
73
  def cursor_pos(row, column = nil)
99
74
  return column ? "\e[#{row};#{column}H" : "\e[#{row}H" if row
100
75
  column ? "\e[;#{column}H" : "\e[H"
101
76
  end
102
77
 
103
- # Decorate given `obj` with ANSI `attributes`.
104
- #
105
- # @see []
78
+ # @comment ??? def cursor_tab(count = 1) = "\e[#{column}I"
79
+
80
+ # Erase screen.
106
81
  #
107
- # @param obj [#to_s] object to be decorated
108
- # @param attributes [Symbol, String] attribute names to be used
109
- # @param reset [Boolean] whether to include reset code for ANSI attributes
110
- # @return [String] `obj` converted and decorated with the ANSI `attributes`
111
- def embellish(obj, *attributes, reset: true)
112
- attributes = self[*attributes]
113
- attributes.empty? ? "#{obj}" : "#{attributes}#{obj}#{"\e[0m" if reset}"
82
+ # @param part [:below, :above, :scrollback, :entire] part to erase
83
+ # @return (see cursor_up)
84
+ def screen_erase(part = :entire)
85
+ return "\e[0J" if part == :below
86
+ return "\e[1J" if part == :above
87
+ return "\e[3J" if part == :scrollback
88
+ "\e[2J"
114
89
  end
115
90
 
116
- # Remove ANSI attribtes from given string.
91
+ # Clear part of current line.
117
92
  #
118
- # @see embellish
93
+ # @param part [:to_end, :to_start, :entire] part to delete
94
+ # @return (see cursor_up)
95
+ def line_erase(part = :entire)
96
+ return "\e[0K" if part == :to_end
97
+ return "\e[1K" if part == :to_start
98
+ "\e[2K"
99
+ end
100
+
101
+ # @comment ??? def line_insert(lines = 1) = "\e[#{lines}L"
102
+ # @comment ??? def line_delete(lines = 1) = "\e[#{lines}M"
103
+ # @comment ??? def chars_delete(count = 1) = "\e[#{count}P"
104
+
105
+ # Scroll window given lines up.
119
106
  #
120
- # @param str [#to_s] string to be modified
121
- # @return [String] string without ANSI attributes
122
- def blemish(str) = str.to_s.gsub(/(\x1b\[(?~[a-zA-Z])[a-zA-Z])/, '')
107
+ # @param lines [Integer] number of lines to scroll
108
+ # @return (see cursor_up)
109
+ def scroll_up(lines = 1) = "\e[;#{lines}S"
123
110
 
124
- # Combine given ANSI `attributes`.
111
+ # Scroll window given lines down.
125
112
  #
126
- # ANSI attribute names are:
113
+ # @param (see scroll_up)
114
+ # @return (see cursor_up)
115
+ def scroll_down(lines = 1) = "\e[;#{lines}T"
116
+
117
+ # @comment ??? def chars_erase(count = 1) = "\e[#{count}X"
118
+ # @comment ??? def cursor_reverse_tab(count = 1) = "\e[#{count}Z"
119
+
120
+ # set absolute col
121
+ # @comment ??? doubled! def cursor_column(column = 1) = "\e[#{column}`"
122
+ # set relative column
123
+ # @comment ??? def cursor_column_rel(column = 1) = "\e[#{column}a"
124
+ # set absolute row
125
+ # @comment ??? def cursor_row(row = 1) = "\e[#{row}d"
126
+ # set relative row
127
+ # @comment ??? def cursor_row_rel(row = 1) = "\e[#{row}e"
128
+
129
+ # Change window title.
130
+ # This is not widely supported but by XTerm and iTerm.
127
131
  #
128
- # `reset`, `bold`, `faint`, `italic`, `underline`, `slow_blink`, `blink`,
129
- # `rapid_blink`, `invert`, `reverse`, `conceal`, `hide`, `strike`,
130
- # `primary_font`, `default_font`, `font1`, `font2`, `font3`, `font4`,
131
- # `font5`, `font6`, `font7`, `font8`, `font9`, `fraktur`,
132
- # `double_underline`, `doubly`, `bold_off`, `normal`, `italic_off`,
133
- # `fraktur_off`, `underline_off`, `blink_off`, `proportional`, `spacing`,
134
- # `invert_off`, `reverse_off`, `reveal`, `strike_off`, `proportional_off`,
135
- # `spacing_off`, `framed`, `encircled`, `overlined`, `framed_off`,
136
- # `encircled_off`, `overlined_off`.
132
+ # @param [String] title text
133
+ # @return (see cursor_up)
134
+ def window_title(title) = "\e]2;#{title}\e\\"
135
+
136
+ # Change tab title.
137
+ # This is not widely supported but by iTerm.
137
138
  #
138
- # Colors can specified by their name for ANSI 3-bit and 4-bit colors:
139
- # `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`,
140
- # `default`, `bright_black`, `bright_red`, `bright_green`,
141
- # `bright_yellow`, `bright_blue`, `bright_magenta`, `bright_cyan`,
142
- # `bright_white`.
139
+ # @param [String] title text
140
+ # @return (see cursor_up)
141
+ def tab_title(title) = "\e]0;#{title}\a"
142
+
143
+ # @!endgroup
144
+
145
+ # @!group Tool functions
146
+
147
+ # Combine given ANSI {.attribute_names}, {.color_names} and color codes.
143
148
  #
149
+ # Colors can specified by their name for ANSI 3-bit and 4-bit colors.
144
150
  # For 8-bit ANSI colors use 2-digit hexadecimal values `00`...`ff`.
145
151
  #
146
152
  # To use RGB ANSI colors (24-bit colors) specify 3-digit or 6-digit
@@ -150,11 +156,9 @@ module NattyUI
150
156
  #
151
157
  # To use a color as background color prefix the color attribute with `bg_`
152
158
  # or `on_`.
153
- #
154
159
  # To use a color as underline color prefix the color attribute with `ul_`.
155
- #
156
- # To make it more clear a color attribute have to be used as foreground
157
- # color the color value can be prefixed with `fg_`.
160
+ # To clarify that a color attribute have to be used as foreground
161
+ # color use the prefix `fg_`.
158
162
  #
159
163
  # @example Valid Foreground Color Attributes
160
164
  # Ansi[:yellow]
@@ -197,12 +201,17 @@ module NattyUI
197
201
  attributes
198
202
  .map do |arg|
199
203
  case arg
200
- when Symbol, String
201
- ATTRIBUTES[arg] || color(arg) || invalid_argument(arg)
204
+ when Symbol
205
+ SATTR[arg] || SCLR[arg] || color(arg.to_s) ||
206
+ invalid_argument(arg)
207
+ when String
208
+ ATTR[arg] || CLR[arg] || color(arg) || invalid_argument(arg)
202
209
  when (0..255)
203
210
  "38;5;#{arg}"
204
- when (256..512)
211
+ when (256..511)
205
212
  "48;5;#{arg}"
213
+ when (512..767)
214
+ "58;5;#{arg}"
206
215
  else
207
216
  invalid_argument(arg)
208
217
  end
@@ -211,8 +220,29 @@ module NattyUI
211
220
  }m"
212
221
  end
213
222
 
214
- # Try to combine given ANSI `attributes`. The `attributes` have to be a
215
- # string containing attributes separated by space char (" ").
223
+ # Decorate given `str` with ANSI attributes and colors.
224
+ #
225
+ # @see []
226
+ #
227
+ # @param str [#to_s] object to be decorated
228
+ # @param attributes [Symbol, String] attribute names to be used
229
+ # @param reset [Boolean] whether to include reset code for ANSI attributes
230
+ # @return [String] `str` converted and decorated with the ANSI `attributes`
231
+ def embellish(str, *attributes, reset: true)
232
+ attributes = self[*attributes]
233
+ attributes.empty? ? str.to_s : "#{attributes}#{str}#{"\e[0m" if reset}"
234
+ end
235
+
236
+ # Remove ANSI functions, attributes and colors from given string.
237
+ #
238
+ # @see embellish
239
+ #
240
+ # @param str [#to_s] string to be modified
241
+ # @return [String] string without ANSI attributes
242
+ def blemish(str) = str.to_s.gsub(/(\e\[(?~[a-zA-Z])[a-zA-Z])/, '')
243
+
244
+ # Try to combine given ANSI attributes and colors.
245
+ # The attributes and colors have to be seperated by space char (" ").
216
246
  #
217
247
  # @example Valid Attribute String
218
248
  # Ansi.try_convert('bold italic blink red on#00ff00')
@@ -230,11 +260,40 @@ module NattyUI
230
260
  return if (attributes = attributes.to_s.split).empty?
231
261
  "\e[#{
232
262
  attributes
233
- .map { |arg| ATTRIBUTES[arg] || color(arg) || return }
263
+ .map! { |a| ATTR[a] || CLR[a] || color(a) || return }
234
264
  .join(';')
235
265
  }m"
236
266
  end
237
267
 
268
+ # @param str [#to_s] plain text string to enrich with color
269
+ # @param type [:foreground, :background, :underline] type of coloring
270
+ # @param frequence [Float] color change frequency
271
+ # @param spread [Float] number of chars with same color
272
+ # @param seed [Float] start index on sinus curve
273
+ # @return [String] fancy text
274
+ def rainbow(
275
+ str,
276
+ type: :foreground,
277
+ frequence: 0.3,
278
+ spread: 0.8,
279
+ seed: 1.1
280
+ )
281
+ type = color_type(type)
282
+ pos = -1
283
+ str
284
+ .to_s
285
+ .chars
286
+ .map! do |char|
287
+ i = (seed + ((pos += 1) / spread)) * frequence
288
+ "\e[#{type};2;#{(Math.sin(i) * 255).abs.to_i};" \
289
+ "#{(Math.sin(i + PI2_THIRD) * 255).abs.to_i};" \
290
+ "#{(Math.sin(i + PI4_THIRD) * 255).abs.to_i}m#{char}"
291
+ end
292
+ .join
293
+ end
294
+
295
+ # @!endgroup
296
+
238
297
  private
239
298
 
240
299
  def invalid_argument(name)
@@ -245,195 +304,182 @@ module NattyUI
245
304
  )
246
305
  end
247
306
 
307
+ def color_type(type)
308
+ case type
309
+ when :background, :bg, 'background', 'bg'
310
+ 48
311
+ when :underline, :ul, 'underline', 'ul'
312
+ 58
313
+ else
314
+ 38
315
+ end
316
+ end
317
+
248
318
  def color(val)
249
- val = val.to_s.downcase
250
- base =
251
- if val.delete_prefix!('fg')
252
- val.delete_prefix!(':') || val.delete_prefix!('_')
253
- '38;'
254
- elsif val.delete_prefix!('ul')
255
- val.delete_prefix!(':') || val.delete_prefix!('_')
256
- '58;'
257
- elsif val.delete_prefix!('bg') || val.delete_prefix!('on')
258
- val.delete_prefix!(':') || val.delete_prefix!('_')
259
- '48;'
260
- else
261
- '38;'
262
- end
263
- val.delete_prefix!('#')
264
- case val.size
265
- when 2
266
- "#{base}5;#{val.hex}" if /\A[[:xdigit:]]+\z/.match?(val)
267
- when 3
268
- if /\A[[:xdigit:]]+\z/.match?(val)
269
- "#{base}2;#{(val[0] * 2).hex};#{(val[1] * 2).hex};#{
270
- (val[2] * 2).hex
271
- }"
272
- end
273
- when 6
274
- if /\A[[:xdigit:]]+\z/.match?(val)
275
- "#{base}2;#{val[0, 2].hex};#{val[2, 2].hex};#{val[4, 2].hex}"
276
- end
319
+ base = CLR_PREFIX[val[0, 2]]
320
+ idx = base ? 2 : 0
321
+ base ||= '38'
322
+ idx += 1 if val[idx] == '_' || val[idx] == ':'
323
+ idx += 1 if val[idx] == '#'
324
+ val = val[idx..]
325
+ return "#{base};5;#{val.hex}" if /\A[[:xdigit:]]{1,2}\z/.match?(val)
326
+ if /\A[[:xdigit:]]{6}\z/.match?(val)
327
+ return "#{base};2;#{val[0, 2].hex};#{val[2, 2].hex};#{val[4, 2].hex}"
277
328
  end
329
+ return unless /\A[[:xdigit:]]{3}\z/.match?(val)
330
+ "#{base};2;#{(val[0] * 2).hex};#{(val[1] * 2).hex};#{(val[2] * 2).hex}"
278
331
  end
279
332
  end
280
333
 
281
- ATTRIBUTES =
282
- {
283
- reset: 0,
284
- # ---
285
- bold: 1,
286
- faint: 2,
287
- italic: 3,
288
- underline: 4,
289
- # ---
290
- slow_blink: 5,
291
- blink: 5,
292
- # ---
293
- rapid_blink: 6,
294
- # ---
295
- invert: 7,
296
- # ---
297
- conceal: 8,
298
- hide: 8,
299
- # ---
300
- strike: 9,
301
- # ---
302
- primary_font: 10,
303
- default_font: 10,
304
- # ---
305
- font1: 11,
306
- font2: 12,
307
- font3: 13,
308
- font4: 14,
309
- font5: 15,
310
- font6: 16,
311
- font7: 17,
312
- font8: 18,
313
- font9: 19,
314
- fraktur: 20,
315
- # ---
316
- double_underline: 21,
317
- doubly: 21,
318
- bold_off: 21,
319
- # ---
320
- normal: 22,
321
- # ---
322
- italic_off: 23,
323
- fraktur_off: 23,
324
- # ---
325
- underline_off: 24,
326
- blink_off: 25,
327
- # ---
328
- proportional: 26,
329
- spacing: 26,
330
- # ---
331
- invert_off: 27,
332
- # ---
333
- reveal: 28,
334
- # ---
335
- strike_off: 29,
336
- # ---
337
- proportional_off: 50,
338
- spacing_off: 50,
339
- # ---
340
- framed: 51,
341
- encircled: 52,
342
- overlined: 53,
343
- framed_off: 54,
344
- encircled_off: 54,
345
- overlined_off: 55,
346
- # foreground colors
347
- black: 30,
348
- red: 31,
349
- green: 32,
350
- yellow: 33,
351
- blue: 34,
352
- magenta: 35,
353
- cyan: 36,
354
- white: 37,
355
- default: 39,
356
- bright_black: 90,
357
- bright_red: 91,
358
- bright_green: 92,
359
- bright_yellow: 93,
360
- bright_blue: 94,
361
- bright_magenta: 95,
362
- bright_cyan: 96,
363
- bright_white: 97,
364
- # background colors
365
- on_black: 40,
366
- on_red: 41,
367
- on_green: 42,
368
- on_yellow: 43,
369
- on_blue: 44,
370
- on_magenta: 45,
371
- on_cyan: 46,
372
- on_white: 47,
373
- on_default: 49,
374
- on_bright_black: 100,
375
- on_bright_red: 101,
376
- on_bright_green: 102,
377
- on_bright_yellow: 103,
378
- on_bright_blue: 104,
379
- on_bright_magenta: 105,
380
- on_bright_cyan: 106,
381
- on_bright_white: 107,
382
- # foreground colors
383
- fg_black: 30,
384
- fg_red: 31,
385
- fg_green: 32,
386
- fg_yellow: 33,
387
- fg_blue: 34,
388
- fg_magenta: 35,
389
- fg_cyan: 36,
390
- fg_white: 37,
391
- fg_default: 39,
392
- fg_bright_black: 90,
393
- fg_bright_red: 91,
394
- fg_bright_green: 92,
395
- fg_bright_yellow: 93,
396
- fg_bright_blue: 94,
397
- fg_bright_magenta: 95,
398
- fg_bright_cyan: 96,
399
- fg_bright_white: 97,
400
- # background colors
401
- bg_black: 40,
402
- bg_red: 41,
403
- bg_green: 42,
404
- bg_yellow: 43,
405
- bg_blue: 44,
406
- bg_magenta: 45,
407
- bg_cyan: 46,
408
- bg_white: 47,
409
- bg_default: 49,
410
- bg_bright_black: 100,
411
- bg_bright_red: 101,
412
- bg_bright_green: 102,
413
- bg_bright_yellow: 103,
414
- bg_bright_blue: 104,
415
- bg_bright_magenta: 105,
416
- bg_bright_cyan: 106,
417
- bg_bright_white: 107,
418
- # underline colors
419
- ul_black: '58;2;0;0;0',
420
- ul_red: '58;2;128;0;0',
421
- ul_green: '58;2;0;128;0',
422
- ul_yellow: '58;2;128;128;0',
423
- ul_blue: '58;2;0;0;128',
424
- ul_magenta: '58;2;128;0;128',
425
- ul_cyan: '58;2;0;128;128',
426
- ul_white: '58;2;128;128;128',
427
- ul_default: '59',
428
- ul_bright_black: '58;2;64;64;64',
429
- ul_bright_red: '58;2;255;0;0',
430
- ul_bright_green: '58;2;0;255;0',
431
- ul_bright_yellow: '58;2;255;255;0',
432
- ul_bright_blue: '58;2;0;0;255',
433
- ul_bright_magenta: '58;2;255;0;255',
434
- ul_bright_cyan: '58;2;0;255;255',
435
- ul_bright_white: '58;2;255;255;255'
436
- }.tap { |ret| ret.merge!(ret.transform_keys(&:to_s)).freeze }
437
- private_constant :ATTRIBUTES
334
+ CLR_PREFIX = {
335
+ 'fg' => '38',
336
+ 'bg' => '48',
337
+ 'ul' => '58',
338
+ 'on' => '48'
339
+ }.freeze
340
+
341
+ PI2_THIRD = 2 * Math::PI / 3.0
342
+ PI4_THIRD = 4 * Math::PI / 3.0
343
+
344
+ SATTR =
345
+ Module
346
+ .new do
347
+ def self.to_hash
348
+ map = {
349
+ # alternative names
350
+ slow_blink: 5,
351
+ conceal: 8,
352
+ default_font: 10,
353
+ doubly: 21,
354
+ faint_off: 22,
355
+ fraktur_off: 23,
356
+ spacing: 26,
357
+ conceal_off: 28,
358
+ spacing_off: 50,
359
+ encircled_off: 54,
360
+ subscript_off: 75,
361
+ # special
362
+ curly_underline_off: '4:0',
363
+ dotted_underline_off: '4:0',
364
+ dashed_underline_off: '4:0',
365
+ curly_underline: '4:3',
366
+ dotted_underline: '4:4',
367
+ dashed_underline: '4:5'
368
+ }
369
+ add = ->(s, n) { n.each_with_index { |a, idx| map[a] = s + idx } }
370
+ add[
371
+ 0,
372
+ %i[
373
+ reset
374
+ bold
375
+ faint
376
+ italic
377
+ underline
378
+ blink
379
+ rapid_blink
380
+ invert
381
+ hide
382
+ strike
383
+ primary_font
384
+ font1
385
+ font2
386
+ font3
387
+ font4
388
+ font5
389
+ font6
390
+ font7
391
+ font8
392
+ font9
393
+ fraktur
394
+ double_underline
395
+ bold_off
396
+ italic_off
397
+ underline_off
398
+ blink_off
399
+ proportional
400
+ invert_off
401
+ reveal
402
+ strike_off
403
+ ]
404
+ ]
405
+ add[
406
+ 50,
407
+ %i[
408
+ proportional_off
409
+ framed
410
+ encircled
411
+ overlined
412
+ framed_off
413
+ overlined_off
414
+ ]
415
+ ]
416
+ add[73, %i[superscript subscript superscript_off]]
417
+ map
418
+ end
419
+ end
420
+ .to_hash
421
+ .compare_by_identity
422
+ .freeze
423
+
424
+ CLR =
425
+ Module
426
+ .new do
427
+ def self.to_hash
428
+ clr = {
429
+ 0 => 'black',
430
+ 1 => 'red',
431
+ 2 => 'green',
432
+ 3 => 'yellow',
433
+ 4 => 'blue',
434
+ 5 => 'magenta',
435
+ 6 => 'cyan',
436
+ 7 => 'white'
437
+ }
438
+ map = {}
439
+ add = ->(s, p) { clr.each_pair { |i, n| map["#{p}#{n}"] = s + i } }
440
+ ul = ->(r, g, b) { "58;2;#{r};#{g};#{b}" }
441
+ add[30, nil]
442
+ map['default'] = 39
443
+ add[90, 'bright_']
444
+ add[30, 'fg_']
445
+ map['fg_default'] = 39
446
+ add[90, 'fg_bright_']
447
+ add[40, 'bg_']
448
+ map['bg_default'] = 49
449
+ add[100, 'bg_bright_']
450
+ add[40, 'on_']
451
+ map['on_default'] = 49
452
+ add[100, 'on_bright_']
453
+ map.merge!(
454
+ 'ul_black' => ul[0, 0, 0],
455
+ 'ul_red' => ul[128, 0, 0],
456
+ 'ul_green' => ul[0, 128, 0],
457
+ 'ul_yellow' => ul[128, 128, 0],
458
+ 'ul_blue' => ul[0, 0, 128],
459
+ 'ul_magenta' => ul[128, 0, 128],
460
+ 'ul_cyan' => ul[0, 128, 128],
461
+ 'ul_white' => ul[128, 128, 128],
462
+ 'ul_default' => '59',
463
+ 'ul_bright_black' => ul[64, 64, 64],
464
+ 'ul_bright_red' => ul[255, 0, 0],
465
+ 'ul_bright_green' => ul[0, 255, 0],
466
+ 'ul_bright_yellow' => ul[255, 255, 0],
467
+ 'ul_bright_blue' => ul[0, 0, 255],
468
+ 'ul_bright_magenta' => ul[255, 0, 255],
469
+ 'ul_bright_cyan' => ul[0, 255, 255],
470
+ 'ul_bright_white' => ul[255, 255, 255]
471
+ )
472
+ end
473
+ end
474
+ .to_hash
475
+ .freeze
476
+
477
+ ATTR = SATTR.transform_keys(&:to_s).freeze
478
+ SCLR = CLR.transform_keys(&:to_sym).compare_by_identity.freeze
479
+
480
+ private_constant :CLR_PREFIX, :PI2_THIRD, :PI4_THIRD
481
+ private_constant :SATTR, :SCLR, :ATTR, :CLR
438
482
  end
439
483
  end
484
+
485
+ require_relative 'ansi_constants'