typr 1.1.2 → 1.2.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 +4 -4
- data/CHANGELOG.md +70 -0
- data/README.md +9 -9
- data/example/grid +4 -4
- data/example/text +7 -4
- data/example/top500.csv +1 -0
- data/lib/browser.rb +104 -74
- data/lib/curses.rb +48 -77
- data/lib/frontend.rb +10 -20
- data/lib/graphical.rb +39 -92
- data/lib/grid.rb +76 -29
- data/lib/line.rb +57 -27
- data/lib/space.rb +14 -5
- data/lib/stack.rb +18 -19
- data/lib/terminal.rb +249 -169
- data/lib/text.rb +118 -14
- data/lib/typr.rb +5 -6
- data/share/mimetypes +1298 -1
- data/typr.gemspec +2 -2
- metadata +2 -7
- data/Gemfile +0 -10
data/lib/terminal.rb
CHANGED
|
@@ -1,285 +1,365 @@
|
|
|
1
|
-
#!/usr/bin/ruby
|
|
2
|
-
|
|
3
1
|
require 'io/console'
|
|
4
|
-
require 'readline'
|
|
5
2
|
require 'unicode/display_width'
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
#
|
|
4
|
+
## Terminal control: raw key input, line editing, cursor movement, ANSI colors
|
|
5
|
+
# and terminal geometry. Widgets get the instance helpers via `include Typr`;
|
|
6
|
+
# class-level helpers (Typr.width, Typr.read_key, ...) drive the whole screen.
|
|
7
|
+
|
|
8
|
+
module Typr
|
|
9
|
+
|
|
10
|
+
# Raw /dev/tty used for key input; falls back to $stdin when unavailable.
|
|
11
|
+
INPUT = (IO.new IO.sysopen("/dev/tty", "r")) rescue $stdin
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
`infocmp -L1`.split.each{ |info| key,value = info[0..-2].split("=")
|
|
13
|
+
# KEY_* escape sequences come from the terminfo database (infocmp -L1).
|
|
14
|
+
`infocmp -L1`.split.each{ |info| key,value = info[0..-2].split("=")
|
|
12
15
|
if value
|
|
13
|
-
# p key + value if key[/dis/]
|
|
14
|
-
# value[1] = ?e if value[0,2] == "\\E"
|
|
15
16
|
value.gsub! '\E', '\e'
|
|
16
|
-
# value = '\x' + value[/\d+/].to_i(8).to_s(16).upcase if value[/\\\d+/]
|
|
17
|
-
# value = "\\x" + value[/\d+/].to_i(8).to_s(16).upcase if value[/\\\d+/]
|
|
18
17
|
value += "\\" if value[-1] == "\\"
|
|
19
|
-
|
|
20
|
-
eval "%s=\"%s\"" % [key.upcase,value] if key
|
|
21
|
-
#and key.start_with? "key_"
|
|
18
|
+
eval "%s=\"%s\"" % [key.upcase,value] if key
|
|
22
19
|
end }
|
|
23
|
-
|
|
20
|
+
|
|
21
|
+
# Common key aliases and the line-erase escape sequence.
|
|
22
|
+
ERASE_LINE = "\e[K"
|
|
24
23
|
KEY_ESCAPE = "\e"
|
|
25
24
|
KEY_RETURN = CARRIAGE_RETURN
|
|
26
25
|
KEY_TAB = "\t"
|
|
27
|
-
KEY_ENTER = CARRIAGE_RETURN
|
|
28
26
|
KEY_PAGEDOWN = KEY_NPAGE
|
|
29
27
|
KEY_PAGEUP = KEY_PPAGE
|
|
30
|
-
KEY_INSERT = KEY_IC
|
|
31
|
-
KEY_DELETE = KEY_DC
|
|
32
28
|
|
|
33
|
-
|
|
29
|
+
# Text attributes (reset, bold, italic, ...) and named 8/256-color tables.
|
|
30
|
+
MODES = %i[ reset bold italic underline slow fast invert ]
|
|
34
31
|
COLORS = %i[ black red green yellow blue magenta cyan white ]
|
|
32
|
+
COLOR_MAP = {
|
|
33
|
+
brown: 130, orange: 208, lime: 118, pink: 218,
|
|
34
|
+
maroon: 52, navy: 18, teal: 30, olive: 100,
|
|
35
|
+
coral: 203, tan: 180,
|
|
36
|
+
dark_red: 88, dark_green: 22, dark_yellow: 58,
|
|
37
|
+
dark_blue: 18, dark_magenta: 89, dark_cyan: 30
|
|
38
|
+
}
|
|
35
39
|
|
|
40
|
+
# Pad or clip +str+ to exactly +max+ cells, honoring +align+ (:left/:right),
|
|
41
|
+
# trimming from +side+, with an optional trailing +fade+.
|
|
36
42
|
def prepare str, max, align=:left, side=:right, fade=false
|
|
37
43
|
stop = width = real_size( str )
|
|
38
|
-
# unless str[0..max-1].ascii_only? and width == str.size
|
|
39
44
|
unless str.ascii_only? and width == str.size
|
|
40
45
|
stop = width = 0
|
|
41
46
|
str.each_char do |c|
|
|
42
|
-
if c == ?\e
|
|
47
|
+
if c == ?\e
|
|
43
48
|
width -= str[stop..-1][/^\x1b\[[^m]+m|/].size-1
|
|
44
49
|
stop += 1
|
|
45
50
|
elsif (cwidth = (c.ascii_only? ? 1 : Unicode::DisplayWidth.of(c))) +
|
|
46
|
-
width
|
|
51
|
+
width > max
|
|
47
52
|
break
|
|
48
53
|
else width += cwidth; stop += 1 end
|
|
49
|
-
end
|
|
54
|
+
end
|
|
50
55
|
end
|
|
51
|
-
|
|
52
|
-
if ( space = ( max - width ) ) > 0 #.clamp 0, max
|
|
56
|
+
if ( space = ( max - width ) ) > 0
|
|
53
57
|
str = [ str[0..stop-1], " " * space ]
|
|
54
58
|
str.reverse! if align == :right
|
|
55
59
|
str.join
|
|
56
|
-
else
|
|
57
|
-
|
|
58
|
-
# when :right;
|
|
59
|
-
str = str[side == :left ? -max..-1 : 0..max-1]
|
|
60
|
-
# end
|
|
61
|
-
# str = fade str, align, str.length / 8 + 1 if fade
|
|
60
|
+
else
|
|
61
|
+
str = clip str, max, side
|
|
62
62
|
str = fade str, side, fade if fade
|
|
63
63
|
return str
|
|
64
64
|
end
|
|
65
|
-
# return str.join
|
|
66
65
|
end
|
|
67
|
-
|
|
66
|
+
|
|
67
|
+
# Truncate +str+ to at most +max+ cells, keeping ANSI color tokens intact
|
|
68
|
+
# and clipping from +side+ (:left/:right).
|
|
69
|
+
def clip str, max, side
|
|
70
|
+
tokens = str.scan(/(\e\[[0-9;]*m)|([^\e]+)/).flatten.compact
|
|
71
|
+
tokens.reverse! if side == :left
|
|
72
|
+
kept, used = [], 0
|
|
73
|
+
tokens.each do |token|
|
|
74
|
+
if token[0] == ?\e
|
|
75
|
+
if side == :left
|
|
76
|
+
kept << token unless kept.empty?
|
|
77
|
+
break if used >= max
|
|
78
|
+
else
|
|
79
|
+
kept << token if used < max
|
|
80
|
+
end
|
|
81
|
+
next
|
|
82
|
+
end
|
|
83
|
+
break if used >= max
|
|
84
|
+
size = Unicode::DisplayWidth.of token
|
|
85
|
+
if used + size <= max
|
|
86
|
+
kept << token
|
|
87
|
+
used += size
|
|
88
|
+
elsif used < max
|
|
89
|
+
need = max - used
|
|
90
|
+
chars = token.chars
|
|
91
|
+
chars.reverse! if side == :left
|
|
92
|
+
width = 0
|
|
93
|
+
out = ""
|
|
94
|
+
chars.each do |char|
|
|
95
|
+
width += Unicode::DisplayWidth.of char
|
|
96
|
+
break if width > need
|
|
97
|
+
out << char
|
|
98
|
+
end
|
|
99
|
+
out.reverse! if side == :left
|
|
100
|
+
kept << out
|
|
101
|
+
used = max
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
kept.reverse!.join if side == :left
|
|
105
|
+
kept.join
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Blend the first (or last) +num+ characters of +str+ into greys to hint
|
|
109
|
+
# at clipping; +side+ selects which end fades.
|
|
68
110
|
def fade str, side=:left, num=3
|
|
69
111
|
isleft = side == :left
|
|
70
|
-
# chars = (side == ? 0..num : (-num-1..-2).to_a.reverse)
|
|
71
112
|
chars = str[ isleft ? 0..num : -num..-1 ]
|
|
72
113
|
chars = chars.chars.map.with_index do |char,id|
|
|
73
114
|
id = chars.size-id unless isleft
|
|
74
115
|
color_code( "grey#{(80/chars.size)*id+10}".to_sym ) + char
|
|
75
116
|
end.join
|
|
76
|
-
# chars.each.with_index do |pos,id|
|
|
77
|
-
# str.insert pos, color_code( "grey#{(80/chars.size)*id+10}".to_sym )
|
|
78
|
-
# str.insert pos, color_code( "grey#{(100/id+3)*10}".to_sym )
|
|
79
|
-
# end
|
|
80
117
|
return ( isleft ? chars + color_code($color[0]) + str[num+1..-1] :
|
|
81
118
|
str[0..-num-1] + chars )
|
|
82
|
-
|
|
83
|
-
#+ color_code( $color[1] )
|
|
84
|
-
# return str
|
|
85
|
-
# length.times{|i|
|
|
86
|
-
# color [ ("grey"+((i+3)*10).to_s ).to_sym, @colors[:default][1] ]
|
|
87
|
-
# show @directory[-space+i] }
|
|
88
|
-
# color @colors[:default]
|
|
89
|
-
# show @directory[-space+6..-1]
|
|
90
119
|
end
|
|
91
|
-
|
|
120
|
+
|
|
121
|
+
# Strip ANSI escape sequences from +str+.
|
|
92
122
|
def printables str; str.gsub(/\x1b\[[^m]+m|/,'') end
|
|
93
|
-
|
|
123
|
+
|
|
124
|
+
# Display width of +str+ after stripping ANSI escapes.
|
|
94
125
|
def real_size str; Unicode::DisplayWidth.of( printables(str) ) end
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
126
|
+
|
|
127
|
+
# Coerce a string into Integer, Float, or Boolean when it matches those
|
|
128
|
+
# forms (yes/no, true/false); otherwise return it unchanged.
|
|
129
|
+
def coerce_type value
|
|
130
|
+
s = value.to_s
|
|
131
|
+
return nil if s.empty? or /\A(?:nil|NULL)\z/i.match(s)
|
|
132
|
+
case value
|
|
133
|
+
when /^-?[\d]+$/ then s.to_i
|
|
134
|
+
when /^-?\d*[\.\,]\d+$/ then s.to_f
|
|
135
|
+
when /\byes\z/i then true
|
|
136
|
+
when /\bno(ot)?\z/i then false
|
|
137
|
+
when /true\z/i then true
|
|
138
|
+
when /false\z/i then false
|
|
139
|
+
else value
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Move the cursor to column +x+, row +y+ (0-based); move_code returns the
|
|
144
|
+
# escape sequence without writing it.
|
|
145
|
+
def move x=0,y=0; draw move_code( x, y ) end
|
|
98
146
|
def move_code x=0,y=0; "\e[%i;%if" % [ y+1, x+1 ] end
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
147
|
+
|
|
148
|
+
# Apply a text attribute (+mode+); mode_code returns the escape sequence
|
|
149
|
+
# without writing it.
|
|
150
|
+
def mode name; draw mode_code(name) end
|
|
151
|
+
def mode_code name; if id = MODES.index(name.to_s) then "\e[#{ id }m" end end
|
|
152
|
+
|
|
153
|
+
# Build the ANSI code for +color+ (a Symbol name, greyN, Integer palette id,
|
|
154
|
+
# or [r,g,b] / [fg,bg] Array), optionally as a background; when false the
|
|
155
|
+
# color is emitted as a foreground.
|
|
103
156
|
def color_code color, bg=false
|
|
104
157
|
color = color.to_sym if color.is_a? String
|
|
105
158
|
case color
|
|
106
|
-
when Symbol;
|
|
159
|
+
when Symbol;
|
|
107
160
|
if id = COLORS.index(color); "\e[#{ id + (bg ? 40 : 30) }m"
|
|
108
161
|
elsif color[/^gr[ae]y\d{,2}$/]
|
|
109
162
|
"\e[%i;5;%im" % [bg ? 48 : 38, 232 + (color[/\d+/].to_f/100*23).to_i]
|
|
163
|
+
elsif id = COLOR_MAP[color]
|
|
164
|
+
"\e[%i;5;%im" % [bg ? 48 : 38, id]
|
|
110
165
|
end
|
|
111
166
|
when Integer; "\e[%i;5;%im" % [ bg ? 48 : 38, color]
|
|
112
167
|
when Array; case color.count
|
|
113
|
-
when 3; "\e[%i;2;%i;%i;%im" % [ bg ? 48 : 38, *color ]
|
|
168
|
+
when 3; "\e[%i;2;%i;%i;%im" % [ bg ? 48 : 38, *color ]
|
|
114
169
|
when 2; color_code( color[0] ) + color_code( color[1], true )
|
|
115
170
|
end
|
|
116
171
|
end
|
|
117
172
|
end
|
|
118
|
-
|
|
119
|
-
|
|
173
|
+
|
|
174
|
+
# Read the current background/foreground color pair.
|
|
175
|
+
def get_background; $color[1] end
|
|
120
176
|
def get_foreground; $color[0] end
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
# end
|
|
177
|
+
|
|
178
|
+
# Set and apply the foreground/background color; +color+ sets both from a
|
|
179
|
+
# [fg, bg] pair, a single color, or the module default.
|
|
180
|
+
def foreground c=$default[0]; $color[0]=c; draw color_code(c) end
|
|
181
|
+
def background c=$default[1]; $color[1]=c; draw color_code(c,true) end
|
|
127
182
|
def color c=$default
|
|
128
183
|
c = [c] unless c.is_a? Array and c.count == 2
|
|
129
|
-
foreground c[0] if c[0]
|
|
130
|
-
background c[1] if c[1]
|
|
184
|
+
foreground c[0] if c[0]
|
|
185
|
+
background c[1] if c[1]
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Write raw +str+ to stdout.
|
|
189
|
+
def draw str; $>.print str end
|
|
190
|
+
|
|
191
|
+
# Clear the whole screen (:screen) or just the current line (:line).
|
|
192
|
+
def self.clear mode=:screen
|
|
193
|
+
$>.print( { screen: CLEAR_SCREEN, line: ERASE_LINE }[mode] )
|
|
131
194
|
end
|
|
132
195
|
|
|
133
|
-
|
|
134
|
-
#
|
|
135
|
-
#
|
|
136
|
-
#
|
|
137
|
-
|
|
138
|
-
|
|
196
|
+
## Reads a single keypress in raw mode.
|
|
197
|
+
#
|
|
198
|
+
# Returns the key sequence as a String (e.g. "a" or "\e[A" for up-arrow),
|
|
199
|
+
# or nil when stdin is not a tty or input is unavailable.
|
|
200
|
+
|
|
201
|
+
def self.read_key
|
|
202
|
+
return INPUT.raw{ |tty| tty.sysread 6 } rescue nil unless INPUT.tty?
|
|
203
|
+
INPUT.raw{ |tty| tty.sysread 6 } rescue return
|
|
139
204
|
end
|
|
140
205
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
206
|
+
## Interactive line editor used for string prompts (search, %str, ...).
|
|
207
|
+
#
|
|
208
|
+
# Renders +prompt+ and the query at (left, top) and edits it with
|
|
209
|
+
# arrow keys, ctrl-arrow word jumps, home/end, delete and backspace.
|
|
210
|
+
# Returns the query on enter, nil on escape. A block may inspect each
|
|
211
|
+
# keypress after it is applied; a non-nil return short-circuits the
|
|
212
|
+
# editor and becomes its return value. When stdin is not a tty, the
|
|
213
|
+
# query is read from a single line of piped input instead.
|
|
214
|
+
#
|
|
215
|
+
# Typr.read_line "/" do |key, query, cursor|
|
|
216
|
+
# filter query
|
|
217
|
+
# nil
|
|
218
|
+
# end
|
|
219
|
+
|
|
220
|
+
def self.read_line prompt='', left: 0, top: 0, initial: '', &block
|
|
221
|
+
return $stdin.gets&.chomp unless $stdin.tty?
|
|
222
|
+
query, cursor = initial.dup, initial.length
|
|
223
|
+
loop do
|
|
224
|
+
$>.print "\e[%i;%if" % [ top + 1, left + 1 ]
|
|
225
|
+
$>.print ERASE_LINE
|
|
226
|
+
$>.print prompt + query
|
|
227
|
+
$>.print "\e[%i;%if" % [ top + 1, left + 1 +
|
|
228
|
+
text_width( prompt + query[0...cursor] ) ]
|
|
229
|
+
key = read_key
|
|
230
|
+
return nil if key.nil? or key == KEY_ESCAPE
|
|
231
|
+
return query if key == KEY_RETURN or key == "\n"
|
|
232
|
+
case key
|
|
233
|
+
when KEY_LEFT, "\e[D"; cursor -= 1 if cursor > 0
|
|
234
|
+
when KEY_RIGHT, "\e[C"; cursor += 1 if cursor < query.length
|
|
235
|
+
when "\e[1;5D", "\eOd"; cursor = word_prev query, cursor
|
|
236
|
+
when "\e[1;5C", "\eOc"; cursor = word_next query, cursor
|
|
237
|
+
when KEY_HOME; cursor = 0
|
|
238
|
+
when KEY_END; cursor = query.length
|
|
239
|
+
when KEY_DC, "\e[3~"; query.slice!(cursor, 1) if cursor < query.length
|
|
240
|
+
when KEY_BACKSPACE, "\b"
|
|
241
|
+
if cursor > 0
|
|
242
|
+
query.slice!(cursor - 1, 1)
|
|
243
|
+
cursor -= 1
|
|
244
|
+
end
|
|
245
|
+
else
|
|
246
|
+
if key.is_a?(String) and key.each_char.all?{ |char| char.ord.between?(32, 126) }
|
|
247
|
+
query.insert(cursor, key)
|
|
248
|
+
cursor += key.length
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
cursor = 0 if cursor < 0
|
|
252
|
+
cursor = query.length if cursor > query.length
|
|
253
|
+
result = block.call( key, query, cursor ) if block
|
|
254
|
+
return result unless result.nil?
|
|
145
255
|
end
|
|
146
256
|
end
|
|
147
257
|
|
|
258
|
+
# Display width of +str+ after stripping ANSI escapes.
|
|
259
|
+
def self.text_width str
|
|
260
|
+
Unicode::DisplayWidth.of( str.gsub(/\x1b\[[^m]+m/, '') )
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# Move the cursor back to the start of the previous word in +str+.
|
|
264
|
+
def self.word_prev str, cursor
|
|
265
|
+
cursor -= 1 while cursor > 0 and str[cursor - 1] == ' '
|
|
266
|
+
cursor -= 1 while cursor > 0 and str[cursor - 1] != ' '
|
|
267
|
+
cursor
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Move the cursor forward to the start of the next word in +str+.
|
|
271
|
+
def self.word_next str, cursor
|
|
272
|
+
cursor += 1 while cursor < str.length and str[cursor] == ' '
|
|
273
|
+
cursor += 1 while cursor < str.length and str[cursor] != ' '
|
|
274
|
+
cursor
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Query the terminal for the current [row, column] via DSR; [0, 0] when
|
|
278
|
+
# stdin is not a tty.
|
|
148
279
|
def self.position
|
|
280
|
+
return [0, 0] unless $stdin.tty?
|
|
149
281
|
result = ''
|
|
150
282
|
$stdin.raw do |stdin|
|
|
151
|
-
$stdout << USER7
|
|
283
|
+
$stdout << USER7
|
|
152
284
|
$stdout.flush
|
|
153
285
|
until (char = stdin.getc) == 'R'
|
|
154
286
|
result << char if char
|
|
155
287
|
end
|
|
156
288
|
end
|
|
157
289
|
result[/[\d;]+/].split(?;).map &:to_i
|
|
158
|
-
# m = res.match /(?<row>\d+);(?<column>\d+)/
|
|
159
|
-
# { row: Integer(m[:row]), column: Integer(m[:column]) }
|
|
160
290
|
end
|
|
161
291
|
|
|
162
|
-
|
|
292
|
+
# Terminal [rows, cols] (defaults to 24x80 when undetectable); width/height
|
|
293
|
+
# return the usable last column/row.
|
|
294
|
+
def self.size; IO.console&.winsize || [24, 80] end
|
|
163
295
|
def self.width; size.last-1 end
|
|
164
|
-
def self.height; size.first end
|
|
296
|
+
def self.height; size.first - 1 end
|
|
297
|
+
|
|
298
|
+
# Current cursor row/column (see position).
|
|
165
299
|
def self.row; position.first end
|
|
166
300
|
def self.column; position.last end
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
301
|
+
|
|
302
|
+
# Call +block+ whenever the terminal is resized (SIGWINCH).
|
|
303
|
+
def self.on_resize &block
|
|
304
|
+
trap(:WINCH, &block)
|
|
305
|
+
end
|
|
306
|
+
# Enter interactive mode: seed the default colors, hide the cursor and
|
|
307
|
+
# enable key-mode (application) escapes when stdin is a tty.
|
|
308
|
+
def self.init default=[ :white, :black ]
|
|
309
|
+
$default = default.dup
|
|
310
|
+
$color = $default.dup
|
|
311
|
+
if $stdin.tty?
|
|
312
|
+
print CURSOR_INVISIBLE
|
|
313
|
+
system "tput smkx"
|
|
314
|
+
end
|
|
174
315
|
end
|
|
175
|
-
|
|
176
|
-
|
|
316
|
+
# Restore the terminal: show the cursor, reset colors and clear the screen.
|
|
317
|
+
def self.exit;
|
|
177
318
|
extend self
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
319
|
+
if $stdin.tty?
|
|
320
|
+
$>.print CURSOR_NORMAL;
|
|
321
|
+
$>.print ORIG_COLORS; color; clear
|
|
322
|
+
end
|
|
182
323
|
end
|
|
183
324
|
end
|
|
184
325
|
|
|
185
|
-
# include Typr
|
|
186
|
-
# extend Typr
|
|
187
|
-
|
|
188
326
|
if __FILE__ == $0
|
|
189
327
|
begin
|
|
190
328
|
include Typr
|
|
191
|
-
Typr.init
|
|
329
|
+
Typr.init
|
|
192
330
|
colors = COLORS + (1..9).map{|i| "grey#{i*10}" }
|
|
193
331
|
chars = (33..126).map(&:chr)
|
|
194
332
|
slice = chars.count / colors.count + 1
|
|
195
333
|
characters = chars.each_slice( slice ).map(&:join)
|
|
196
|
-
# key = read :key
|
|
197
334
|
key,fg,bg = "",150,0
|
|
198
335
|
Typr.clear
|
|
199
336
|
loop do
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
background colors[x].to_sym;
|
|
337
|
+
colors.each_with_index{ |color,y|
|
|
338
|
+
characters.each_with_index{ |chars,x|
|
|
339
|
+
foreground color.to_sym;
|
|
340
|
+
background colors[x].to_sym;
|
|
205
341
|
move x*slice,y
|
|
206
|
-
|
|
342
|
+
draw chars
|
|
207
343
|
}
|
|
208
344
|
}
|
|
209
|
-
(0...256).each{ |i| background i;
|
|
210
|
-
|
|
211
|
-
move 0, Typr.height
|
|
345
|
+
(0...256).each{ |i| background i; draw ' ' }
|
|
346
|
+
|
|
347
|
+
move 0, Typr.height
|
|
212
348
|
color [:white, :black]
|
|
213
|
-
# show "KEY: #{key}"
|
|
214
349
|
p "KEY: %s / %s" % [key, key]
|
|
215
|
-
move 15, Typr.height
|
|
350
|
+
move 15, Typr.height
|
|
216
351
|
color [fg,bg]
|
|
217
|
-
print " %s / %s " % [fg,bg]
|
|
218
|
-
key = Typr.
|
|
352
|
+
print " %s / %s " % [fg,bg]
|
|
353
|
+
key = Typr.read_key
|
|
219
354
|
case key
|
|
220
355
|
when KEY_UP; fg+=1
|
|
221
356
|
when KEY_DOWN; fg-=1
|
|
222
357
|
when KEY_LEFT; bg-=1
|
|
223
358
|
when KEY_RIGHT; bg+=1
|
|
224
|
-
when KEY_ESCAPE; exit
|
|
359
|
+
when KEY_ESCAPE; exit
|
|
225
360
|
end
|
|
226
361
|
end
|
|
227
362
|
ensure
|
|
228
363
|
Typr.exit
|
|
229
364
|
end
|
|
230
365
|
end
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
# KEY_ESC = 27
|
|
234
|
-
# KEY_TAB =
|
|
235
|
-
# KEY_ESC = 27
|
|
236
|
-
# A_STANDOUT = :invert
|
|
237
|
-
# BG = :black
|
|
238
|
-
# `infocmp -L`.read.join.split(', ').each{ |info| }
|
|
239
|
-
# .split('=').to_h
|
|
240
|
-
|
|
241
|
-
# KEY_PAGEDOWN = "\e[6~"
|
|
242
|
-
# KEY_PAGEUP = "\e[5~"
|
|
243
|
-
# KEY_LEFT = "\e[D"
|
|
244
|
-
# KEY_RIGHT = "\e[C"
|
|
245
|
-
# KEY_UP = "\e[A"
|
|
246
|
-
# KEY_DOWN = "\e[B"
|
|
247
|
-
# KEY_HOME = "\e[H" #xterm
|
|
248
|
-
# KEY_END = "\e[F" #xterm
|
|
249
|
-
# INSERT = "\e[2~" #xterm
|
|
250
|
-
# DELETE = "\e[3~" #xterm
|
|
251
|
-
# KEY_BACKSPACE = "\b" #xterm
|
|
252
|
-
|
|
253
|
-
# case ENV["TERM"]
|
|
254
|
-
# when
|
|
255
|
-
# DELETE = "\e[P" #st
|
|
256
|
-
# INSERT = "\e[4h" #st
|
|
257
|
-
# BACKSPACE = "\x7F" #st
|
|
258
|
-
# KEY_END = "\e[4~" #st
|
|
259
|
-
|
|
260
|
-
# KEY_HOME = "\e[7~" #urxvt
|
|
261
|
-
# KEY_END = "\e[8~" #urxvt
|
|
262
|
-
|
|
263
|
-
# HIDE_CURSOR = "\e[?25l"
|
|
264
|
-
# SHOW_CURSOR = "\e[?25h"
|
|
265
|
-
# HEIGHT,WIDTH = IO.console.winsize
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
# def mod key,char,extra;
|
|
269
|
-
# if key.length == 1; key = char + key.upcase
|
|
270
|
-
# elsif key[/~$/]; key[0..-2] + char
|
|
271
|
-
# else key[0..-2] + extra + key[-1].downcase end
|
|
272
|
-
# end
|
|
273
|
-
# def shift key; mod key, "$" end
|
|
274
|
-
# def ctrl key; mod key, "^", "O" end
|
|
275
|
-
# def alt key; KEYMAP[:esc] + key end
|
|
276
|
-
# def clear mode=2; IO.console.erase_screen 1 end
|
|
277
|
-
# def mode name; "\e[%im" % [(MODES.index name.to_s)] end
|
|
278
|
-
# def ansi arg, type, inc=0
|
|
279
|
-
# case arg
|
|
280
|
-
# when Integer; show "\e[%i;5;%im" % [ inc + 8, arg]
|
|
281
|
-
# else show "\e[%im" % [ ( type.index arg.to_s ) + inc ]
|
|
282
|
-
# end
|
|
283
|
-
# end
|
|
284
|
-
|
|
285
|
-
|