terminal_rb 0.6.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/README.md +55 -0
- data/bin/bbcode +46 -0
- data/examples/24bit-colors.rb +20 -0
- data/examples/3bit-colors.rb +18 -0
- data/examples/8bit-colors.rb +32 -0
- data/examples/attributes.rb +14 -0
- data/examples/bbcode.rb +28 -0
- data/examples/info.rb +15 -0
- data/examples/key-codes.rb +22 -0
- data/lib/terminal/ansi/attributes.rb +209 -0
- data/lib/terminal/ansi/named_colors.rb +668 -0
- data/lib/terminal/ansi.rb +593 -0
- data/lib/terminal/detect.rb +151 -0
- data/lib/terminal/input.rb +187 -0
- data/lib/terminal/preload.rb +8 -0
- data/lib/terminal/rspec/helper.rb +33 -0
- data/lib/terminal/text/char_width.rb +2585 -0
- data/lib/terminal/text.rb +542 -0
- data/lib/terminal/version.rb +6 -0
- data/lib/terminal.rb +269 -0
- data/lib/terminal_rb.rb +3 -0
- metadata +68 -0
@@ -0,0 +1,593 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Terminal
|
4
|
+
#
|
5
|
+
# Fast ANSI control code and BBCode processing.
|
6
|
+
#
|
7
|
+
module Ansi
|
8
|
+
class << self
|
9
|
+
# Supported attribute names.
|
10
|
+
#
|
11
|
+
# @see []
|
12
|
+
#
|
13
|
+
# @attribute [r] attributes
|
14
|
+
# @return [Array<Symbol>] all attribute names
|
15
|
+
def attributes = ATTRIBUTES_S.keys
|
16
|
+
|
17
|
+
# Supported 3/4-bit color names.
|
18
|
+
#
|
19
|
+
# @see []
|
20
|
+
#
|
21
|
+
# @attribute [r] colors
|
22
|
+
# @return [Array<Symbol>] all color names
|
23
|
+
def colors = COLORS_S.keys
|
24
|
+
|
25
|
+
# Supported basic 24-bit (Kitty compatible) color names.
|
26
|
+
#
|
27
|
+
# @see []
|
28
|
+
#
|
29
|
+
# @attribute [r] named_colors
|
30
|
+
# @return [Array<Symbol>] all basic named_colors names
|
31
|
+
def named_colors = NAMED_COLORS.keys.map!(&:to_sym)
|
32
|
+
|
33
|
+
#
|
34
|
+
# @!group ANSI control code generator functions
|
35
|
+
#
|
36
|
+
|
37
|
+
# Combine given ANSI {attributes}, {colors}, {named_colors} and color
|
38
|
+
# codes.
|
39
|
+
#
|
40
|
+
# Colors can specified by their name for ANSI 3-bit and 4-bit colors.
|
41
|
+
# For 8-bit ANSI colors use 2-digit hexadecimal values `00`...`ff`.
|
42
|
+
#
|
43
|
+
# To use RGB ANSI colors (24-bit colors) specify 3-digit or 6-digit
|
44
|
+
# hexadecimal values `000`...`fff` or `000000`...`ffffff`.
|
45
|
+
# This represent the `RRGGBB` values (or `RGB` for short version) like you
|
46
|
+
# may known from CSS color notation.
|
47
|
+
#
|
48
|
+
# To use a color as background color prefix the color attribute with `bg_`
|
49
|
+
# or `on_`.
|
50
|
+
# To use a color as underline color prefix the color attribute with `ul_`.
|
51
|
+
# To clarify that a color attribute have to be used as foreground
|
52
|
+
# color use the prefix `fg_`.
|
53
|
+
#
|
54
|
+
# @example Valid Foreground Color Attributes
|
55
|
+
# Terminal::Ansi[:yellow]
|
56
|
+
# Terminal::Ansi[:fg_fab]
|
57
|
+
# Terminal::Ansi[:fg_00aa00]
|
58
|
+
# Terminal::Ansi[:af]
|
59
|
+
# Terminal::Ansi[:fg_af]
|
60
|
+
# Terminal::Ansi['#fab']
|
61
|
+
# Terminal::Ansi['#00aa00']
|
62
|
+
# Terminal::Ansi['lightblue']
|
63
|
+
#
|
64
|
+
# @example Valid Background Color Attributes
|
65
|
+
# Terminal::Ansi[:bg_yellow]
|
66
|
+
# Terminal::Ansi[:bg_fab]
|
67
|
+
# Terminal::Ansi[:bg_00aa00]
|
68
|
+
# Terminal::Ansi[:bg_af]
|
69
|
+
# Terminal::Ansi['bg#00aa00']
|
70
|
+
# Terminal::Ansi['bg_lightblue']
|
71
|
+
#
|
72
|
+
# Terminal::Ansi[:on_yellow]
|
73
|
+
# Terminal::Ansi[:on_fab]
|
74
|
+
# Terminal::Ansi[:on_00aa00]
|
75
|
+
# Terminal::Ansi[:on_af]
|
76
|
+
# Terminal::Ansi['on#00aa00']
|
77
|
+
# Terminal::Ansi['on_lightblue']
|
78
|
+
#
|
79
|
+
# @example Valid Underline Color Attributes
|
80
|
+
# Terminal::Ansi[:underline, :ul_yellow]
|
81
|
+
# Terminal::Ansi[:underline, :ul_fab]
|
82
|
+
# Terminal::Ansi[:underline, :ul_00aa00]
|
83
|
+
# Terminal::Ansi[:underline, :ul_fa]
|
84
|
+
# Terminal::Ansi[:underline, :ul_bright_yellow]
|
85
|
+
# Terminal::Ansi[:underline, 'ul#00aa00']
|
86
|
+
# Terminal::Ansi['underline', 'ul_lightblue']
|
87
|
+
#
|
88
|
+
# @example Combined attributes:
|
89
|
+
# Terminal::Ansi[:bold, :italic, :bright_white, :on_0000cc]
|
90
|
+
#
|
91
|
+
# @see valid?
|
92
|
+
#
|
93
|
+
# @param attributes [Array<Symbol, String>] attribute names to be used
|
94
|
+
# @return [String] combined ANSI attributes
|
95
|
+
def [](*attributes)
|
96
|
+
return +'' if attributes.empty?
|
97
|
+
"\e[#{
|
98
|
+
attributes
|
99
|
+
.map do |arg|
|
100
|
+
case arg
|
101
|
+
when String
|
102
|
+
ATTRIBUTES[arg] || COLORS[arg] || _color(arg) || _invalid(arg)
|
103
|
+
when Symbol
|
104
|
+
ATTRIBUTES_S[arg] || COLORS_S[arg] || _color(arg) ||
|
105
|
+
_invalid(arg)
|
106
|
+
when (0..255)
|
107
|
+
"38;5;#{arg}"
|
108
|
+
when (256..511)
|
109
|
+
"48;5;#{arg - 256}"
|
110
|
+
when (512..767)
|
111
|
+
"58;5;#{arg - 512}"
|
112
|
+
else
|
113
|
+
_invalid(arg)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
.join(';')
|
117
|
+
}m"
|
118
|
+
end
|
119
|
+
|
120
|
+
# Test if given String contains ANSI control codes.
|
121
|
+
#
|
122
|
+
# @param str [#to_s] object to be tested
|
123
|
+
# @return [true, false] whether if attributes are found
|
124
|
+
def ansi?(str) = TEST.match?(str.to_s)
|
125
|
+
|
126
|
+
# Decorate given argument with ANSI attributes and colors.
|
127
|
+
#
|
128
|
+
# @example
|
129
|
+
# Terminal::Ansi.decorate(
|
130
|
+
# 'Hello World!',
|
131
|
+
# :bold, :italic, :bright_white, :on_00c
|
132
|
+
# )
|
133
|
+
# # => "\e[1;3;97;48;2;0;0;204mHello World!\e[m"
|
134
|
+
#
|
135
|
+
# @see []
|
136
|
+
# @see undecorate
|
137
|
+
#
|
138
|
+
# @param str [#to_s] object to be decorated
|
139
|
+
# @param attributes [Array<Symbol, String>] attribute names to be used
|
140
|
+
# @param reset [true, false] whether to include reset code for ANSI attributes
|
141
|
+
# @return [String] `str` converted and decorated with the ANSI `attributes`
|
142
|
+
def decorate(str, *attributes, reset: true)
|
143
|
+
attributes = self[*attributes]
|
144
|
+
attributes.empty? ? "#{str}" : "#{attributes}#{str}#{"\e[m" if reset}"
|
145
|
+
end
|
146
|
+
|
147
|
+
# Remove ANSI functions, attributes and colors from given string.
|
148
|
+
#
|
149
|
+
# @example
|
150
|
+
# Terminal::Ansi.undecorate("\e[1;3;97;48;2;0;0;204mHello World!\e[m")
|
151
|
+
# # => "Hello World!"
|
152
|
+
#
|
153
|
+
# @see decorate
|
154
|
+
#
|
155
|
+
# @param str [#to_s] string to be modified
|
156
|
+
# @return [String] string without ANSI attributes
|
157
|
+
def undecorate(str) = str.to_s.gsub(TEST, '')
|
158
|
+
|
159
|
+
# Try to combine given ANSI attributes and colors.
|
160
|
+
# The attributes and colors have to be separated by given `separator``.
|
161
|
+
#
|
162
|
+
# @example Valid Attribute String
|
163
|
+
# Terminal::Ansi.try_convert('bold italic blink red on#00ff00')
|
164
|
+
# # => "\e[1;3;5;31;48;2;0;255;0m"
|
165
|
+
#
|
166
|
+
# @example Invalid Attribute String
|
167
|
+
# Terminal::Ansi.try_convert('cool bold on green')
|
168
|
+
# # => nil
|
169
|
+
#
|
170
|
+
# @see []
|
171
|
+
#
|
172
|
+
# @param attributes [#to_s] attributes separated by given `separator`
|
173
|
+
# @param separator [String] attribute separator char
|
174
|
+
# @return [String] combined ANSI attributes
|
175
|
+
# @return [nil] when string does not contain valid attributes
|
176
|
+
def try_convert(attributes, separator: ' ')
|
177
|
+
return unless attributes
|
178
|
+
return if (attributes = attributes.to_s.split(separator)).empty?
|
179
|
+
"\e[#{
|
180
|
+
attributes
|
181
|
+
.map! { ATTRIBUTES[_1] || COLORS[_1] || _color(_1) || return }
|
182
|
+
.join(';')
|
183
|
+
}m"
|
184
|
+
end
|
185
|
+
|
186
|
+
# Test if all given attributes are valid.
|
187
|
+
#
|
188
|
+
# @see []
|
189
|
+
#
|
190
|
+
# @param attributes [Array<Symbol, String>] attribute names to be used
|
191
|
+
# @return [true, false] whether if all given attributes are valid
|
192
|
+
def valid?(*attributes)
|
193
|
+
attributes.all? do |arg|
|
194
|
+
case arg
|
195
|
+
when String
|
196
|
+
ATTRIBUTES[arg] || COLORS[arg] || _color(arg)
|
197
|
+
when Symbol
|
198
|
+
ATTRIBUTES_S[arg] || COLORS_S[arg] || _color(arg)
|
199
|
+
when (0..767)
|
200
|
+
true
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
#
|
206
|
+
# @!endgroup
|
207
|
+
#
|
208
|
+
# @!group BBcode related functions
|
209
|
+
#
|
210
|
+
|
211
|
+
# Replace embedded BBCode-like attributes with ANSI control codes.
|
212
|
+
#
|
213
|
+
# @example
|
214
|
+
# Terminal::Ansi.bbcode "[b]Bold[/b] Text"
|
215
|
+
# # => "\e[1mBold\e[22m Text"
|
216
|
+
#
|
217
|
+
# @see unbbcode
|
218
|
+
# @see []
|
219
|
+
#
|
220
|
+
# @param str [#to_s] string to be modified
|
221
|
+
# @return [String] string with ANSI attributes
|
222
|
+
def bbcode(str)
|
223
|
+
str
|
224
|
+
.to_s
|
225
|
+
.gsub(BBCODE) do |match_str|
|
226
|
+
next match_str if (match = Regexp.last_match[1]).empty?
|
227
|
+
next "[#{match[1..]}]" if match[0] == '\\'
|
228
|
+
try_convert(match) || match_str
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Remove embedded BBCode-like attributes.
|
233
|
+
#
|
234
|
+
# @example
|
235
|
+
# Terminal::Ansi.unbbcode "[b]Bold[/b] Text"
|
236
|
+
# # => "Bold Text"
|
237
|
+
#
|
238
|
+
# @see bbcode
|
239
|
+
#
|
240
|
+
# @param str [#to_s] string to be modified
|
241
|
+
# @return [String] string without BBCode
|
242
|
+
def unbbcode(str)
|
243
|
+
str
|
244
|
+
.to_s
|
245
|
+
.gsub(BBCODE) do |match_str|
|
246
|
+
next match_str if (match = Regexp.last_match[1]).empty?
|
247
|
+
next "[#{match[1..]}]" if match[0] == '\\'
|
248
|
+
next match_str if (match = match.split).empty?
|
249
|
+
next if match.all? { ATTRIBUTES[_1] || COLORS[_1] || _color(_1) }
|
250
|
+
match_str
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
#
|
255
|
+
# @!endgroup
|
256
|
+
#
|
257
|
+
# @!group Other tool functions
|
258
|
+
#
|
259
|
+
|
260
|
+
# Remove any BBCode-like and/or ANSI attributes.
|
261
|
+
#
|
262
|
+
# @see undecorate
|
263
|
+
# @see unbbcode
|
264
|
+
#
|
265
|
+
# @param str [#to_s] string to be modified
|
266
|
+
# @return [String] string without BBCode and ANSI control codes.
|
267
|
+
def plain(str) = unbbcode(str).gsub(TEST, '')
|
268
|
+
|
269
|
+
# Create nice colored text.
|
270
|
+
#
|
271
|
+
# @param str [#to_s] string to enrich with color
|
272
|
+
# @param frequency [Float] color change frequency
|
273
|
+
# @param spread [Float] number of chars with same color
|
274
|
+
# @param seed [Float] start index on sinus curve
|
275
|
+
# @return [String] fancy text
|
276
|
+
def rainbow(str, frequency: 0.3, spread: 0.8, seed: 1.1)
|
277
|
+
pos = -1
|
278
|
+
str
|
279
|
+
.to_s
|
280
|
+
.chars
|
281
|
+
.map! do |char|
|
282
|
+
i = (seed + ((pos += 1) / spread)) * frequency
|
283
|
+
"\e[38;2;#{(Math.sin(i) * 255).abs.to_i};" \
|
284
|
+
"#{(Math.sin(i + PI2_THIRD) * 255).abs.to_i};" \
|
285
|
+
"#{(Math.sin(i + PI4_THIRD) * 255).abs.to_i}m#{char}"
|
286
|
+
end
|
287
|
+
.join << RESET
|
288
|
+
end
|
289
|
+
|
290
|
+
#
|
291
|
+
# @!endgroup
|
292
|
+
#
|
293
|
+
# @!group Cursor manipulation
|
294
|
+
#
|
295
|
+
|
296
|
+
# Move cursor given lines up.
|
297
|
+
#
|
298
|
+
# @param lines [Integer] number of lines to move
|
299
|
+
# @return [String] ANSI control code
|
300
|
+
def cursor_up(lines = 1) = "\e[#{lines}A"
|
301
|
+
|
302
|
+
# Move cursor given lines down.
|
303
|
+
#
|
304
|
+
# @param (see cursor_up)
|
305
|
+
# @return (see cursor_up)
|
306
|
+
def cursor_down(lines = 1) = "\e[#{lines}B"
|
307
|
+
|
308
|
+
# Move cursor given columns forward.
|
309
|
+
#
|
310
|
+
# @param columns [Integer] number of columns to move
|
311
|
+
# @return (see cursor_up)
|
312
|
+
def cursor_forward(columns = 1) = "\e[#{columns}C"
|
313
|
+
|
314
|
+
# Move cursor given columns back.
|
315
|
+
#
|
316
|
+
# @param (see forward)
|
317
|
+
# @return (see cursor_up)
|
318
|
+
def cursor_back(columns = 1) = "\e[#{columns}D"
|
319
|
+
|
320
|
+
# Move cursor to the beginning of the given next line.
|
321
|
+
#
|
322
|
+
# @param (see up)
|
323
|
+
# @return (see cursor_up)
|
324
|
+
def cursor_next_line(lines = 1) = "\e[#{lines}E"
|
325
|
+
|
326
|
+
# Move cursor to the beginning of the given previous line.
|
327
|
+
#
|
328
|
+
# @param (see up)
|
329
|
+
# @return (see cursor_up)
|
330
|
+
def cursor_prev_line(lines = 1) = "\e[#{lines}F"
|
331
|
+
|
332
|
+
# Move cursor to given column in the current row.
|
333
|
+
#
|
334
|
+
# @param column [Integer] column index
|
335
|
+
# @return (see cursor_up)
|
336
|
+
def cursor_column(column = 1) = "\e[#{column}G"
|
337
|
+
|
338
|
+
# Move to given row and column.
|
339
|
+
#
|
340
|
+
# @param row [Integer] row index
|
341
|
+
# @param column [Integer] column index
|
342
|
+
# @return (see cursor_up)
|
343
|
+
def cursor_pos(row, column = nil)
|
344
|
+
return column ? "\e[;#{column}H" : "\e[H" unless row
|
345
|
+
column ? "\e[#{row};#{column}H" : "\e[#{row}H"
|
346
|
+
end
|
347
|
+
|
348
|
+
# Show cursor.
|
349
|
+
#
|
350
|
+
# @return (see cursor_up)
|
351
|
+
def cursor_show = +CURSOR_SHOW
|
352
|
+
|
353
|
+
# Hide cursor.
|
354
|
+
#
|
355
|
+
# @return (see cursor_up)
|
356
|
+
def cursor_hide = +CURSOR_HIDE
|
357
|
+
|
358
|
+
# Save current cursor position.
|
359
|
+
#
|
360
|
+
# @return (see cursor_up)
|
361
|
+
def cursor_save_pos = +CURSOR_POS_SAVE
|
362
|
+
|
363
|
+
# Restore saved cursor position.
|
364
|
+
#
|
365
|
+
# @return (see cursor_up)
|
366
|
+
def cursor_restore_pos = +CURSOR_POS_RESTORE
|
367
|
+
|
368
|
+
#
|
369
|
+
# @!endgroup
|
370
|
+
#
|
371
|
+
# @!group Screen manipulation
|
372
|
+
#
|
373
|
+
|
374
|
+
# Erase screen part.
|
375
|
+
#
|
376
|
+
# @return (see cursor_up)
|
377
|
+
def screen_erase(part = :all)
|
378
|
+
"\e[#{
|
379
|
+
case part
|
380
|
+
when :below
|
381
|
+
# nop
|
382
|
+
when :above
|
383
|
+
'1'
|
384
|
+
when :scrollback
|
385
|
+
'3'
|
386
|
+
else # all
|
387
|
+
'2'
|
388
|
+
end
|
389
|
+
}J"
|
390
|
+
end
|
391
|
+
|
392
|
+
# Safe current screen.
|
393
|
+
#
|
394
|
+
# @return (see cursor_up)
|
395
|
+
def screen_save = +SCREEN_SAVE
|
396
|
+
|
397
|
+
# Restore current screen.
|
398
|
+
#
|
399
|
+
# @return (see cursor_up)
|
400
|
+
def screen_restore = +SCREEN_RESTORE
|
401
|
+
|
402
|
+
# Use alternative screen buffer.
|
403
|
+
#
|
404
|
+
# @return (see cursor_up)
|
405
|
+
def screen_alternate = +SCREEN_ALTERNATE
|
406
|
+
|
407
|
+
# Do not longer use alternative screen buffer.
|
408
|
+
#
|
409
|
+
# @return (see cursor_up)
|
410
|
+
def screen_alternate_off = +SCREEN_ALTERNATE_OFF
|
411
|
+
|
412
|
+
# Scroll window given lines up.
|
413
|
+
#
|
414
|
+
# @param lines [Integer] number of lines to scroll
|
415
|
+
# @return (see cursor_up)
|
416
|
+
def screen_scroll_up(lines = 1) = "\e[#{lines}S"
|
417
|
+
|
418
|
+
# Scroll window given lines down.
|
419
|
+
#
|
420
|
+
# @param (see scroll_up)
|
421
|
+
# @return (see cursor_up)
|
422
|
+
def screen_scroll_down(lines = 1) = "\e[#{lines}T"
|
423
|
+
|
424
|
+
#
|
425
|
+
# @!endgroup
|
426
|
+
#
|
427
|
+
# @!group Other ANSI control functions
|
428
|
+
#
|
429
|
+
|
430
|
+
# Erase part of line.
|
431
|
+
#
|
432
|
+
# @return (see cursor_up)
|
433
|
+
def line_erase(part = :all)
|
434
|
+
"\e[#{
|
435
|
+
case part
|
436
|
+
when :to_end
|
437
|
+
# nop
|
438
|
+
when :to_start
|
439
|
+
'1'
|
440
|
+
else # :all
|
441
|
+
'2'
|
442
|
+
end
|
443
|
+
}K"
|
444
|
+
end
|
445
|
+
|
446
|
+
# Set window title.
|
447
|
+
# This is not widely supported.
|
448
|
+
#
|
449
|
+
# @param [#to_s] title text
|
450
|
+
# @return (see cursor_up)
|
451
|
+
def title(title) = "\e]2;#{title}\a"
|
452
|
+
|
453
|
+
# Set tab title.
|
454
|
+
# This is not widely supported.
|
455
|
+
#
|
456
|
+
# @param (see title)
|
457
|
+
# @return (see cursor_up)
|
458
|
+
def tab_title(title) = "\e]0;#{title}\a"
|
459
|
+
|
460
|
+
# Create a hyperlink.
|
461
|
+
# This is not widely supported.
|
462
|
+
#
|
463
|
+
# @param [#to_s] url URL to link to
|
464
|
+
# @param [#to_s] text text to display for the link
|
465
|
+
# @return (see cursor_up)
|
466
|
+
def link(url, text) = "\e]8;;#{url}\a#{text}\e]8;;\a"
|
467
|
+
|
468
|
+
#
|
469
|
+
# @!endgroup
|
470
|
+
#
|
471
|
+
|
472
|
+
private
|
473
|
+
|
474
|
+
def _invalid(att)
|
475
|
+
raise(
|
476
|
+
ArgumentError,
|
477
|
+
"unknown ANSI attribute - #{att.inspect}",
|
478
|
+
caller(1)
|
479
|
+
)
|
480
|
+
end
|
481
|
+
|
482
|
+
def _color(str)
|
483
|
+
b, v = /\A(fg|bg|on|ul)?_?#?([[:xdigit:]]{1,6})\z/.match(str)&.captures
|
484
|
+
if v
|
485
|
+
return(
|
486
|
+
case v.size
|
487
|
+
when 1, 2
|
488
|
+
"#{COLOR_BASE[b]};5;#{v.hex}"
|
489
|
+
when 3
|
490
|
+
"#{COLOR_BASE[b]};2;#{(v[0] * 2).hex};#{
|
491
|
+
(v[1] * 2).hex
|
492
|
+
};#{(v[2] * 2).hex}"
|
493
|
+
when 6
|
494
|
+
"#{COLOR_BASE[b]};2;#{v[0, 2].hex};#{v[2, 2].hex};#{v[4, 2].hex}"
|
495
|
+
end
|
496
|
+
)
|
497
|
+
end
|
498
|
+
b, v = /\A(fg|bg|on|ul)?_?([a-z]{3,}[0-9]{0,3})\z/.match(str)&.captures
|
499
|
+
return unless v
|
500
|
+
name = NAMED_COLORS[v] and return "#{COLOR_BASE[b]};#{name}"
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
COLOR_BASE =
|
505
|
+
{ 'bg' => '48', 'on' => '48', 'ul' => '58' }.tap { _1.default = '38' }
|
506
|
+
.freeze
|
507
|
+
|
508
|
+
TEST =
|
509
|
+
/
|
510
|
+
(?:\e\[[\d;:\?]*[ABCDEFGHJKSTfminsuhl])
|
511
|
+
|
|
512
|
+
(?:\e\]\d+(?:;[^\a\e]+)*(?:\a|\e\\))
|
513
|
+
/x
|
514
|
+
|
515
|
+
BBCODE = /(?:\[((?~[\[\]]))\])/
|
516
|
+
|
517
|
+
PI2_THIRD = 2.0 * Math::PI / 3.0
|
518
|
+
PI4_THIRD = 4.0 * Math::PI / 3.0
|
519
|
+
|
520
|
+
private_constant :COLOR_BASE, :TEST, :BBCODE, :PI2_THIRD, :PI4_THIRD
|
521
|
+
|
522
|
+
require_relative 'ansi/attributes'
|
523
|
+
|
524
|
+
autoload :NAMED_COLORS, "#{__dir__}/ansi/named_colors.rb"
|
525
|
+
private_constant :NAMED_COLORS
|
526
|
+
|
527
|
+
# @!visibility private
|
528
|
+
RESET = self[:reset].freeze
|
529
|
+
|
530
|
+
# @!visibility private
|
531
|
+
FULL_RESET = "\ec"
|
532
|
+
|
533
|
+
# @!visibility private
|
534
|
+
CURSOR_HOME = cursor_pos(nil, nil).freeze
|
535
|
+
# @!visibility private
|
536
|
+
CURSOR_FIRST_ROW = cursor_pos(1).freeze
|
537
|
+
# @!visibility private
|
538
|
+
CURSOR_FIRST_COLUMN = cursor_column(1).freeze
|
539
|
+
|
540
|
+
# @!visibility private
|
541
|
+
CURSOR_SHOW = "\e[?25h"
|
542
|
+
# @!visibility private
|
543
|
+
CURSOR_HIDE = "\e[?25l"
|
544
|
+
|
545
|
+
# CURSOR_POS_SAVE_SCO = "\e[s"
|
546
|
+
# CURSOR_POS_SAVE_DEC = "\e7"
|
547
|
+
# @!visibility private
|
548
|
+
CURSOR_POS_SAVE = "\e7"
|
549
|
+
|
550
|
+
# CURSOR_POS_RESTORE_SCO = "\e[u"
|
551
|
+
# CURSOR_POS_RESTORE_DEC = "\e8"
|
552
|
+
# @!visibility private
|
553
|
+
CURSOR_POS_RESTORE = "\e8"
|
554
|
+
|
555
|
+
# @!visibility private
|
556
|
+
SCREEN_ERASE = screen_erase.freeze
|
557
|
+
# @!visibility private
|
558
|
+
SCREEN_ERASE_BELOW = screen_erase(:below).freeze
|
559
|
+
# @!visibility private
|
560
|
+
SCREEN_ERASE_ABOVE = screen_erase(:above).freeze
|
561
|
+
# @!visibility private
|
562
|
+
SCREEN_ERASE_SCROLLBACK = screen_erase(:scrollback).freeze
|
563
|
+
|
564
|
+
# @!visibility private
|
565
|
+
SCREEN_SAVE = "\e[?47h"
|
566
|
+
# @!visibility private
|
567
|
+
SCREEN_RESTORE = "\e[?47l"
|
568
|
+
# @!visibility private
|
569
|
+
SCREEN_ALTERNATE = "\e[?1049h"
|
570
|
+
# @!visibility private
|
571
|
+
SCREEN_ALTERNATE_OFF = "\e[?1049l"
|
572
|
+
|
573
|
+
# @!visibility private
|
574
|
+
LINE_ERASE = line_erase.freeze
|
575
|
+
# @!visibility private
|
576
|
+
LINE_ERASE_TO_END = line_erase(:to_end).freeze
|
577
|
+
# @!visibility private
|
578
|
+
LINE_ERASE_TO_START = line_erase(:to_start).freeze
|
579
|
+
# @!visibility private
|
580
|
+
LINE_ERASE_PREV = "#{cursor_prev_line(nil)}#{LINE_ERASE}".freeze
|
581
|
+
|
582
|
+
# @comment seems not widely supported:
|
583
|
+
# @comment doubled!? def cursor_column(column = 1) = "\e[#{column}`"
|
584
|
+
# @comment doubled!? def cursor_row(row = 1) = "\e[#{row}d"
|
585
|
+
# @comment def cursor_column_rel(columns = 1) = "\e[#{columns}a"
|
586
|
+
# @comment def cursor_row_rel(rows = 1) = "\e[#{rows}e"
|
587
|
+
# @comment def cursor_tab(count = 1) = "\e[#{column}I"
|
588
|
+
# @comment def cursor_reverse_tab(count = 1) = "\e[#{count}Z"
|
589
|
+
# @comment def chars_delete(count = 1) = "\e[#{count}P"
|
590
|
+
# @comment def chars_erase(count = 1) = "\e[#{count}X"
|
591
|
+
# @comment def notify(title) = "\e]9;#{title}\a"
|
592
|
+
end
|
593
|
+
end
|