reline 0.2.7 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/reline/ansi.rb +64 -22
- data/lib/reline/config.rb +34 -3
- data/lib/reline/general_io.rb +3 -1
- data/lib/reline/key_actor/emacs.rb +1 -1
- data/lib/reline/key_stroke.rb +64 -14
- data/lib/reline/line_editor.rb +630 -72
- data/lib/reline/terminfo.rb +50 -5
- data/lib/reline/unicode.rb +42 -3
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +151 -49
- data/lib/reline.rb +127 -22
- metadata +3 -3
data/lib/reline/terminfo.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
-
|
2
|
-
require 'fiddle
|
1
|
+
begin
|
2
|
+
require 'fiddle'
|
3
|
+
require 'fiddle/import'
|
4
|
+
rescue LoadError
|
5
|
+
module Reline::Terminfo
|
6
|
+
def self.curses_dl
|
7
|
+
false
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
3
11
|
|
4
12
|
module Reline::Terminfo
|
5
13
|
extend Fiddle::Importer
|
@@ -50,7 +58,7 @@ module Reline::Terminfo
|
|
50
58
|
@curses_dl = nil if @curses_dl == false
|
51
59
|
@curses_dl
|
52
60
|
end
|
53
|
-
end
|
61
|
+
end if not Reline.const_defined?(:Terminfo) or not Reline::Terminfo.respond_to?(:curses_dl)
|
54
62
|
|
55
63
|
module Reline::Terminfo
|
56
64
|
dlload curses_dl
|
@@ -66,12 +74,27 @@ module Reline::Terminfo
|
|
66
74
|
#extern 'char *tparm(const char *str, ...)'
|
67
75
|
@tiparm = Fiddle::Function.new(curses_dl['tparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
|
68
76
|
end
|
69
|
-
|
77
|
+
begin
|
78
|
+
#extern 'int tigetflag(char *str)'
|
79
|
+
@tigetflag = Fiddle::Function.new(curses_dl['tigetflag'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
80
|
+
rescue Fiddle::DLError
|
81
|
+
# OpenBSD lacks tigetflag
|
82
|
+
#extern 'int tgetflag(char *str)'
|
83
|
+
@tigetflag = Fiddle::Function.new(curses_dl['tgetflag'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
84
|
+
end
|
85
|
+
begin
|
86
|
+
#extern 'int tigetnum(char *str)'
|
87
|
+
@tigetnum = Fiddle::Function.new(curses_dl['tigetnum'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
88
|
+
rescue Fiddle::DLError
|
89
|
+
# OpenBSD lacks tigetnum
|
90
|
+
#extern 'int tgetnum(char *str)'
|
91
|
+
@tigetnum = Fiddle::Function.new(curses_dl['tgetnum'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
92
|
+
end
|
70
93
|
|
71
94
|
def self.setupterm(term, fildes)
|
72
95
|
errret_int = String.new("\x00" * 8, encoding: 'ASCII-8BIT')
|
73
96
|
ret = @setupterm.(term, fildes, errret_int)
|
74
|
-
errret = errret_int.
|
97
|
+
errret = errret_int.unpack1('i')
|
75
98
|
case ret
|
76
99
|
when 0 # OK
|
77
100
|
0
|
@@ -114,6 +137,28 @@ module Reline::Terminfo
|
|
114
137
|
@tiparm.(str, *new_args).to_s
|
115
138
|
end
|
116
139
|
|
140
|
+
def self.tigetflag(capname)
|
141
|
+
flag = @tigetflag.(capname).to_i
|
142
|
+
case flag
|
143
|
+
when -1
|
144
|
+
raise TerminfoError, "not boolean capability: #{capname}"
|
145
|
+
when 0
|
146
|
+
raise TerminfoError, "can't find capability: #{capname}"
|
147
|
+
end
|
148
|
+
flag
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.tigetnum(capname)
|
152
|
+
num = @tigetnum.(capname).to_i
|
153
|
+
case num
|
154
|
+
when -2
|
155
|
+
raise TerminfoError, "not numeric capability: #{capname}"
|
156
|
+
when -1
|
157
|
+
raise TerminfoError, "can't find capability: #{capname}"
|
158
|
+
end
|
159
|
+
num
|
160
|
+
end
|
161
|
+
|
117
162
|
def self.enabled?
|
118
163
|
true
|
119
164
|
end
|
data/lib/reline/unicode.rb
CHANGED
@@ -79,6 +79,8 @@ class Reline::Unicode
|
|
79
79
|
|
80
80
|
require 'reline/unicode/east_asian_width'
|
81
81
|
|
82
|
+
HalfwidthDakutenHandakuten = /[\u{FF9E}\u{FF9F}]/
|
83
|
+
|
82
84
|
MBCharWidthRE = /
|
83
85
|
(?<width_2_1>
|
84
86
|
[#{ EscapedChars.map {|c| "\\x%02x" % c.ord }.join }] (?# ^ + char, such as ^M, ^H, ^[, ...)
|
@@ -93,6 +95,12 @@ class Reline::Unicode
|
|
93
95
|
#{ EastAsianWidth::TYPE_H }
|
94
96
|
| #{ EastAsianWidth::TYPE_NA }
|
95
97
|
| #{ EastAsianWidth::TYPE_N }
|
98
|
+
)(?!#{ HalfwidthDakutenHandakuten })
|
99
|
+
| (?<width_2_3>
|
100
|
+
(?: #{ EastAsianWidth::TYPE_H }
|
101
|
+
| #{ EastAsianWidth::TYPE_NA }
|
102
|
+
| #{ EastAsianWidth::TYPE_N })
|
103
|
+
#{ HalfwidthDakutenHandakuten }
|
96
104
|
)
|
97
105
|
| (?<ambiguous_width>
|
98
106
|
#{EastAsianWidth::TYPE_A}
|
@@ -101,15 +109,15 @@ class Reline::Unicode
|
|
101
109
|
|
102
110
|
def self.get_mbchar_width(mbchar)
|
103
111
|
ord = mbchar.ord
|
104
|
-
if (0x00 <= ord and ord <= 0x1F)
|
112
|
+
if (0x00 <= ord and ord <= 0x1F) # in EscapedPairs
|
105
113
|
return 2
|
106
|
-
elsif (0x20 <= ord and ord <= 0x7E)
|
114
|
+
elsif (0x20 <= ord and ord <= 0x7E) # printable ASCII chars
|
107
115
|
return 1
|
108
116
|
end
|
109
117
|
m = mbchar.encode(Encoding::UTF_8).match(MBCharWidthRE)
|
110
118
|
case
|
111
119
|
when m.nil? then 1 # TODO should be U+FFFD � REPLACEMENT CHARACTER
|
112
|
-
when m[:width_2_1], m[:width_2_2] then 2
|
120
|
+
when m[:width_2_1], m[:width_2_2], m[:width_2_3] then 2
|
113
121
|
when m[:width_3] then 3
|
114
122
|
when m[:width_0] then 0
|
115
123
|
when m[:width_1] then 1
|
@@ -185,6 +193,37 @@ class Reline::Unicode
|
|
185
193
|
[lines, height]
|
186
194
|
end
|
187
195
|
|
196
|
+
# Take a chunk of a String cut by width with escape sequences.
|
197
|
+
def self.take_range(str, start_col, max_width, encoding = str.encoding)
|
198
|
+
chunk = String.new(encoding: encoding)
|
199
|
+
total_width = 0
|
200
|
+
rest = str.encode(Encoding::UTF_8)
|
201
|
+
in_zero_width = false
|
202
|
+
rest.scan(WIDTH_SCANNER) do |gc|
|
203
|
+
case
|
204
|
+
when gc[NON_PRINTING_START_INDEX]
|
205
|
+
in_zero_width = true
|
206
|
+
when gc[NON_PRINTING_END_INDEX]
|
207
|
+
in_zero_width = false
|
208
|
+
when gc[CSI_REGEXP_INDEX]
|
209
|
+
chunk << gc[CSI_REGEXP_INDEX]
|
210
|
+
when gc[OSC_REGEXP_INDEX]
|
211
|
+
chunk << gc[OSC_REGEXP_INDEX]
|
212
|
+
when gc[GRAPHEME_CLUSTER_INDEX]
|
213
|
+
gc = gc[GRAPHEME_CLUSTER_INDEX]
|
214
|
+
if in_zero_width
|
215
|
+
chunk << gc
|
216
|
+
else
|
217
|
+
mbchar_width = get_mbchar_width(gc)
|
218
|
+
total_width += mbchar_width
|
219
|
+
break if (start_col + max_width) < total_width
|
220
|
+
chunk << gc if start_col < total_width
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
chunk
|
225
|
+
end
|
226
|
+
|
188
227
|
def self.get_next_mbchar_size(line, byte_pointer)
|
189
228
|
grapheme = line.byteslice(byte_pointer..-1).grapheme_clusters.first
|
190
229
|
grapheme ? grapheme.bytesize : 0
|
data/lib/reline/version.rb
CHANGED
data/lib/reline/windows.rb
CHANGED
@@ -42,6 +42,14 @@ class Reline::Windows
|
|
42
42
|
}.each_pair do |key, func|
|
43
43
|
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
44
44
|
end
|
45
|
+
|
46
|
+
# Emulate ANSI key sequence.
|
47
|
+
{
|
48
|
+
[27, 91, 90] => :completion_journey_up, # S-Tab
|
49
|
+
}.each_pair do |key, func|
|
50
|
+
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
51
|
+
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
52
|
+
end
|
45
53
|
end
|
46
54
|
|
47
55
|
if defined? JRUBY_VERSION
|
@@ -106,6 +114,7 @@ class Reline::Windows
|
|
106
114
|
SCROLLLOCK_ON = 0x0040
|
107
115
|
SHIFT_PRESSED = 0x0010
|
108
116
|
|
117
|
+
VK_TAB = 0x09
|
109
118
|
VK_END = 0x23
|
110
119
|
VK_HOME = 0x24
|
111
120
|
VK_LEFT = 0x25
|
@@ -133,9 +142,11 @@ class Reline::Windows
|
|
133
142
|
@@GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
|
134
143
|
@@GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
|
135
144
|
@@FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
|
145
|
+
@@SetConsoleCursorInfo = Win32API.new('kernel32', 'SetConsoleCursorInfo', ['L', 'P'], 'L')
|
136
146
|
|
137
147
|
@@GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
|
138
148
|
@@SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
|
149
|
+
@@WaitForSingleObject = Win32API.new('kernel32', 'WaitForSingleObject', ['L', 'L'], 'L')
|
139
150
|
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
|
140
151
|
|
141
152
|
private_class_method def self.getconsolemode
|
@@ -157,7 +168,9 @@ class Reline::Windows
|
|
157
168
|
@@input_buf = []
|
158
169
|
@@output_buf = []
|
159
170
|
|
160
|
-
|
171
|
+
@@output = STDOUT
|
172
|
+
|
173
|
+
def self.msys_tty?(io = @@hConsoleInputHandle)
|
161
174
|
# check if fd is a pipe
|
162
175
|
if @@GetFileType.call(io) != FILE_TYPE_PIPE
|
163
176
|
return false
|
@@ -173,7 +186,7 @@ class Reline::Windows
|
|
173
186
|
# DWORD FileNameLength;
|
174
187
|
# WCHAR FileName[1];
|
175
188
|
# } FILE_NAME_INFO
|
176
|
-
len = p_buffer[0, 4].
|
189
|
+
len = p_buffer[0, 4].unpack1("L")
|
177
190
|
name = p_buffer[4, len].encode(Encoding::UTF_8, Encoding::UTF_16LE, invalid: :replace)
|
178
191
|
|
179
192
|
# Check if this could be a MSYS2 pty pipe ('\msys-XXXX-ptyN-XX')
|
@@ -197,10 +210,34 @@ class Reline::Windows
|
|
197
210
|
[ { control_keys: [], virtual_key_code: VK_DELETE }, [0, 83] ],
|
198
211
|
[ { control_keys: [], virtual_key_code: VK_HOME }, [0, 71] ],
|
199
212
|
[ { control_keys: [], virtual_key_code: VK_END }, [0, 79] ],
|
213
|
+
|
214
|
+
# Emulate ANSI key sequence.
|
215
|
+
[ { control_keys: :SHIFT, virtual_key_code: VK_TAB }, [27, 91, 90] ],
|
200
216
|
]
|
201
217
|
|
218
|
+
@@hsg = nil
|
219
|
+
|
202
220
|
def self.process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
|
203
221
|
|
222
|
+
# high-surrogate
|
223
|
+
if 0xD800 <= char_code and char_code <= 0xDBFF
|
224
|
+
@@hsg = char_code
|
225
|
+
return
|
226
|
+
end
|
227
|
+
# low-surrogate
|
228
|
+
if 0xDC00 <= char_code and char_code <= 0xDFFF
|
229
|
+
if @@hsg
|
230
|
+
char_code = 0x10000 + (@@hsg - 0xD800) * 0x400 + char_code - 0xDC00
|
231
|
+
@@hsg = nil
|
232
|
+
else
|
233
|
+
# no high-surrogate. ignored.
|
234
|
+
return
|
235
|
+
end
|
236
|
+
else
|
237
|
+
# ignore high-surrogate without low-surrogate if there
|
238
|
+
@@hsg = nil
|
239
|
+
end
|
240
|
+
|
204
241
|
key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state)
|
205
242
|
|
206
243
|
match = KEY_MAP.find { |args,| key.matches?(**args) }
|
@@ -212,30 +249,42 @@ class Reline::Windows
|
|
212
249
|
# no char, only control keys
|
213
250
|
return if key.char_code == 0 and key.control_keys.any?
|
214
251
|
|
252
|
+
@@output_buf.push("\e".ord) if key.control_keys.include?(:ALT)
|
253
|
+
|
215
254
|
@@output_buf.concat(key.char.bytes)
|
216
255
|
end
|
217
256
|
|
218
257
|
def self.check_input_event
|
219
258
|
num_of_events = 0.chr * 8
|
220
|
-
while @@output_buf.empty?
|
221
|
-
|
222
|
-
|
259
|
+
while @@output_buf.empty?
|
260
|
+
Reline.core.line_editor.resize
|
261
|
+
if @@WaitForSingleObject.(@@hConsoleInputHandle, 100) != 0 # max 0.1 sec
|
262
|
+
# prevent for background consolemode change
|
263
|
+
@@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
|
264
|
+
next
|
265
|
+
end
|
266
|
+
next if @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0
|
267
|
+
input_records = 0.chr * 20 * 80
|
223
268
|
read_event = 0.chr * 4
|
224
|
-
if @@ReadConsoleInputW.(@@hConsoleInputHandle,
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
269
|
+
if @@ReadConsoleInputW.(@@hConsoleInputHandle, input_records, 80, read_event) != 0
|
270
|
+
read_events = read_event.unpack1('L')
|
271
|
+
0.upto(read_events) do |idx|
|
272
|
+
input_record = input_records[idx * 20, 20]
|
273
|
+
event = input_record[0, 2].unpack1('s*')
|
274
|
+
case event
|
275
|
+
when WINDOW_BUFFER_SIZE_EVENT
|
276
|
+
@@winch_handler.()
|
277
|
+
when KEY_EVENT
|
278
|
+
key_down = input_record[4, 4].unpack1('l*')
|
279
|
+
repeat_count = input_record[8, 2].unpack1('s*')
|
280
|
+
virtual_key_code = input_record[10, 2].unpack1('s*')
|
281
|
+
virtual_scan_code = input_record[12, 2].unpack1('s*')
|
282
|
+
char_code = input_record[14, 2].unpack1('S*')
|
283
|
+
control_key_state = input_record[16, 2].unpack1('S*')
|
284
|
+
is_key_down = key_down.zero? ? false : true
|
285
|
+
if is_key_down
|
286
|
+
process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
|
287
|
+
end
|
239
288
|
end
|
240
289
|
end
|
241
290
|
end
|
@@ -256,7 +305,7 @@ class Reline::Windows
|
|
256
305
|
end
|
257
306
|
|
258
307
|
def self.empty_buffer?
|
259
|
-
if not @@
|
308
|
+
if not @@output_buf.empty?
|
260
309
|
false
|
261
310
|
elsif @@kbhit.call == 0
|
262
311
|
true
|
@@ -265,17 +314,37 @@ class Reline::Windows
|
|
265
314
|
end
|
266
315
|
end
|
267
316
|
|
268
|
-
def self.
|
317
|
+
def self.get_console_screen_buffer_info
|
318
|
+
# CONSOLE_SCREEN_BUFFER_INFO
|
319
|
+
# [ 0,2] dwSize.X
|
320
|
+
# [ 2,2] dwSize.Y
|
321
|
+
# [ 4,2] dwCursorPositions.X
|
322
|
+
# [ 6,2] dwCursorPositions.Y
|
323
|
+
# [ 8,2] wAttributes
|
324
|
+
# [10,2] srWindow.Left
|
325
|
+
# [12,2] srWindow.Top
|
326
|
+
# [14,2] srWindow.Right
|
327
|
+
# [16,2] srWindow.Bottom
|
328
|
+
# [18,2] dwMaximumWindowSize.X
|
329
|
+
# [20,2] dwMaximumWindowSize.Y
|
269
330
|
csbi = 0.chr * 22
|
270
|
-
@@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
|
331
|
+
return if @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi) == 0
|
332
|
+
csbi
|
333
|
+
end
|
334
|
+
|
335
|
+
def self.get_screen_size
|
336
|
+
unless csbi = get_console_screen_buffer_info
|
337
|
+
return [1, 1]
|
338
|
+
end
|
271
339
|
csbi[0, 4].unpack('SS').reverse
|
272
340
|
end
|
273
341
|
|
274
342
|
def self.cursor_pos
|
275
|
-
csbi =
|
276
|
-
|
277
|
-
|
278
|
-
|
343
|
+
unless csbi = get_console_screen_buffer_info
|
344
|
+
return Reline::CursorPos.new(0, 0)
|
345
|
+
end
|
346
|
+
x = csbi[4, 2].unpack1('s')
|
347
|
+
y = csbi[6, 2].unpack1('s')
|
279
348
|
Reline::CursorPos.new(x, y)
|
280
349
|
end
|
281
350
|
|
@@ -295,6 +364,7 @@ class Reline::Windows
|
|
295
364
|
|
296
365
|
def self.move_cursor_down(val)
|
297
366
|
if val > 0
|
367
|
+
return unless csbi = get_console_screen_buffer_info
|
298
368
|
screen_height = get_screen_size.first
|
299
369
|
y = cursor_pos.y + val
|
300
370
|
y = screen_height - 1 if y > (screen_height - 1)
|
@@ -305,42 +375,74 @@ class Reline::Windows
|
|
305
375
|
end
|
306
376
|
|
307
377
|
def self.erase_after_cursor
|
308
|
-
csbi =
|
309
|
-
|
310
|
-
cursor = csbi[4, 4].
|
378
|
+
return unless csbi = get_console_screen_buffer_info
|
379
|
+
attributes = csbi[8, 2].unpack1('S')
|
380
|
+
cursor = csbi[4, 4].unpack1('L')
|
311
381
|
written = 0.chr * 4
|
312
382
|
@@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
|
313
|
-
@@FillConsoleOutputAttribute.call(@@hConsoleHandle,
|
383
|
+
@@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, get_screen_size.last - cursor_pos.x, cursor, written)
|
314
384
|
end
|
315
385
|
|
316
386
|
def self.scroll_down(val)
|
317
|
-
return if val
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
@@
|
387
|
+
return if val < 0
|
388
|
+
return unless csbi = get_console_screen_buffer_info
|
389
|
+
buffer_width, buffer_lines, x, y, attributes, window_left, window_top, window_bottom = csbi.unpack('ssssSssx2s')
|
390
|
+
screen_height = window_bottom - window_top + 1
|
391
|
+
val = screen_height if val > screen_height
|
392
|
+
|
393
|
+
if @@legacy_console || window_left != 0
|
394
|
+
# unless ENABLE_VIRTUAL_TERMINAL,
|
395
|
+
# if srWindow.Left != 0 then it's conhost.exe hosted console
|
396
|
+
# and puts "\n" causes horizontal scroll. its glitch.
|
397
|
+
# FYI irb write from culumn 1, so this gives no gain.
|
398
|
+
scroll_rectangle = [0, val, buffer_width, buffer_lines - val].pack('s4')
|
399
|
+
destination_origin = 0 # y * 65536 + x
|
400
|
+
fill = [' '.ord, attributes].pack('SS')
|
401
|
+
@@ScrollConsoleScreenBuffer.call(@@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill)
|
402
|
+
else
|
403
|
+
origin_x = x + 1
|
404
|
+
origin_y = y - window_top + 1
|
405
|
+
@@output.write [
|
406
|
+
(origin_y != screen_height) ? "\e[#{screen_height};H" : nil,
|
407
|
+
"\n" * val,
|
408
|
+
(origin_y != screen_height or !x.zero?) ? "\e[#{origin_y};#{origin_x}H" : nil
|
409
|
+
].join
|
410
|
+
end
|
324
411
|
end
|
325
412
|
|
326
413
|
def self.clear_screen
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
414
|
+
if @@legacy_console
|
415
|
+
return unless csbi = get_console_screen_buffer_info
|
416
|
+
buffer_width, _buffer_lines, attributes, window_top, window_bottom = csbi.unpack('ss@8S@12sx2s')
|
417
|
+
fill_length = buffer_width * (window_bottom - window_top + 1)
|
418
|
+
screen_topleft = window_top * 65536
|
419
|
+
written = 0.chr * 4
|
420
|
+
@@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, fill_length, screen_topleft, written)
|
421
|
+
@@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, fill_length, screen_topleft, written)
|
422
|
+
@@SetConsoleCursorPosition.call(@@hConsoleHandle, screen_topleft)
|
423
|
+
else
|
424
|
+
@@output.write "\e[2J" "\e[H"
|
425
|
+
end
|
338
426
|
end
|
339
427
|
|
340
428
|
def self.set_screen_size(rows, columns)
|
341
429
|
raise NotImplementedError
|
342
430
|
end
|
343
431
|
|
432
|
+
def self.hide_cursor
|
433
|
+
size = 100
|
434
|
+
visible = 0 # 0 means false
|
435
|
+
cursor_info = [size, visible].pack('Li')
|
436
|
+
@@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
|
437
|
+
end
|
438
|
+
|
439
|
+
def self.show_cursor
|
440
|
+
size = 100
|
441
|
+
visible = 1 # 1 means true
|
442
|
+
cursor_info = [size, visible].pack('Li')
|
443
|
+
@@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
|
444
|
+
end
|
445
|
+
|
344
446
|
def self.set_winch_handler(&handler)
|
345
447
|
@@winch_handler = handler
|
346
448
|
end
|