reline 0.5.8 → 0.5.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/reline/config.rb +40 -43
- data/lib/reline/face.rb +1 -1
- data/lib/reline/{ansi.rb → io/ansi.rb} +95 -85
- data/lib/reline/io/dumb.rb +106 -0
- data/lib/reline/{windows.rb → io/windows.rb} +112 -102
- data/lib/reline/io.rb +41 -0
- data/lib/reline/key_actor/base.rb +22 -6
- data/lib/reline/key_actor/composite.rb +17 -0
- data/lib/reline/key_actor/emacs.rb +2 -2
- data/lib/reline/key_actor/vi_command.rb +2 -2
- data/lib/reline/key_actor/vi_insert.rb +2 -2
- data/lib/reline/key_actor.rb +1 -0
- data/lib/reline/key_stroke.rb +65 -104
- data/lib/reline/line_editor.rb +70 -76
- data/lib/reline/terminfo.rb +6 -1
- data/lib/reline/unicode/east_asian_width.rb +1262 -1191
- data/lib/reline/unicode.rb +14 -39
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +42 -127
- metadata +8 -9
- data/lib/reline/general_io.rb +0 -111
@@ -1,21 +1,49 @@
|
|
1
1
|
require 'fiddle/import'
|
2
2
|
|
3
|
-
class Reline::Windows
|
4
|
-
|
3
|
+
class Reline::Windows < Reline::IO
|
4
|
+
def initialize
|
5
|
+
@input_buf = []
|
6
|
+
@output_buf = []
|
7
|
+
|
8
|
+
@output = STDOUT
|
9
|
+
@hsg = nil
|
10
|
+
@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
|
11
|
+
@kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
|
12
|
+
@GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
|
13
|
+
@GetConsoleScreenBufferInfo = Win32API.new('kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L')
|
14
|
+
@SetConsoleCursorPosition = Win32API.new('kernel32', 'SetConsoleCursorPosition', ['L', 'L'], 'L')
|
15
|
+
@GetStdHandle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
|
16
|
+
@FillConsoleOutputCharacter = Win32API.new('kernel32', 'FillConsoleOutputCharacter', ['L', 'L', 'L', 'L', 'P'], 'L')
|
17
|
+
@ScrollConsoleScreenBuffer = Win32API.new('kernel32', 'ScrollConsoleScreenBuffer', ['L', 'P', 'P', 'L', 'P'], 'L')
|
18
|
+
@hConsoleHandle = @GetStdHandle.call(STD_OUTPUT_HANDLE)
|
19
|
+
@hConsoleInputHandle = @GetStdHandle.call(STD_INPUT_HANDLE)
|
20
|
+
@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
|
21
|
+
@ReadConsoleInputW = Win32API.new('kernel32', 'ReadConsoleInputW', ['L', 'P', 'L', 'P'], 'L')
|
22
|
+
@GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
|
23
|
+
@GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
|
24
|
+
@FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
|
25
|
+
@SetConsoleCursorInfo = Win32API.new('kernel32', 'SetConsoleCursorInfo', ['L', 'P'], 'L')
|
26
|
+
|
27
|
+
@GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
|
28
|
+
@SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
|
29
|
+
@WaitForSingleObject = Win32API.new('kernel32', 'WaitForSingleObject', ['L', 'L'], 'L')
|
30
|
+
|
31
|
+
@legacy_console = getconsolemode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0
|
32
|
+
end
|
5
33
|
|
6
|
-
def
|
34
|
+
def encoding
|
7
35
|
Encoding::UTF_8
|
8
36
|
end
|
9
37
|
|
10
|
-
def
|
38
|
+
def win?
|
11
39
|
true
|
12
40
|
end
|
13
41
|
|
14
|
-
def
|
15
|
-
|
42
|
+
def win_legacy_console?
|
43
|
+
@legacy_console
|
16
44
|
end
|
17
45
|
|
18
|
-
def
|
46
|
+
def set_default_key_bindings(config)
|
19
47
|
{
|
20
48
|
[224, 72] => :ed_prev_history, # ↑
|
21
49
|
[224, 80] => :ed_next_history, # ↓
|
@@ -129,58 +157,42 @@ class Reline::Windows
|
|
129
157
|
STD_OUTPUT_HANDLE = -11
|
130
158
|
FILE_TYPE_PIPE = 0x0003
|
131
159
|
FILE_NAME_INFO = 2
|
132
|
-
@@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
|
133
|
-
@@kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
|
134
|
-
@@GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
|
135
|
-
@@GetConsoleScreenBufferInfo = Win32API.new('kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L')
|
136
|
-
@@SetConsoleCursorPosition = Win32API.new('kernel32', 'SetConsoleCursorPosition', ['L', 'L'], 'L')
|
137
|
-
@@GetStdHandle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
|
138
|
-
@@FillConsoleOutputCharacter = Win32API.new('kernel32', 'FillConsoleOutputCharacter', ['L', 'L', 'L', 'L', 'P'], 'L')
|
139
|
-
@@ScrollConsoleScreenBuffer = Win32API.new('kernel32', 'ScrollConsoleScreenBuffer', ['L', 'P', 'P', 'L', 'P'], 'L')
|
140
|
-
@@hConsoleHandle = @@GetStdHandle.call(STD_OUTPUT_HANDLE)
|
141
|
-
@@hConsoleInputHandle = @@GetStdHandle.call(STD_INPUT_HANDLE)
|
142
|
-
@@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
|
143
|
-
@@ReadConsoleInputW = Win32API.new('kernel32', 'ReadConsoleInputW', ['L', 'P', 'L', 'P'], 'L')
|
144
|
-
@@GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
|
145
|
-
@@GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
|
146
|
-
@@FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
|
147
|
-
@@SetConsoleCursorInfo = Win32API.new('kernel32', 'SetConsoleCursorInfo', ['L', 'P'], 'L')
|
148
|
-
|
149
|
-
@@GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
|
150
|
-
@@SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
|
151
|
-
@@WaitForSingleObject = Win32API.new('kernel32', 'WaitForSingleObject', ['L', 'L'], 'L')
|
152
160
|
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
|
153
161
|
|
154
|
-
|
162
|
+
# Calling Win32API with console handle is reported to fail after executing some external command.
|
163
|
+
# We need to refresh console handle and retry the call again.
|
164
|
+
private def call_with_console_handle(win32func, *args)
|
165
|
+
val = win32func.call(@hConsoleHandle, *args)
|
166
|
+
return val if val != 0
|
167
|
+
|
168
|
+
@hConsoleHandle = @GetStdHandle.call(STD_OUTPUT_HANDLE)
|
169
|
+
win32func.call(@hConsoleHandle, *args)
|
170
|
+
end
|
171
|
+
|
172
|
+
private def getconsolemode
|
155
173
|
mode = "\000\000\000\000"
|
156
|
-
|
174
|
+
call_with_console_handle(@GetConsoleMode, mode)
|
157
175
|
mode.unpack1('L')
|
158
176
|
end
|
159
177
|
|
160
|
-
|
161
|
-
|
178
|
+
private def setconsolemode(mode)
|
179
|
+
call_with_console_handle(@SetConsoleMode, mode)
|
162
180
|
end
|
163
181
|
|
164
|
-
|
165
|
-
#if @@legacy_console
|
182
|
+
#if @legacy_console
|
166
183
|
# setconsolemode(getconsolemode() | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
167
|
-
#
|
184
|
+
# @legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
|
168
185
|
#end
|
169
186
|
|
170
|
-
|
171
|
-
@@output_buf = []
|
172
|
-
|
173
|
-
@@output = STDOUT
|
174
|
-
|
175
|
-
def self.msys_tty?(io = @@hConsoleInputHandle)
|
187
|
+
def msys_tty?(io = @hConsoleInputHandle)
|
176
188
|
# check if fd is a pipe
|
177
|
-
if
|
189
|
+
if @GetFileType.call(io) != FILE_TYPE_PIPE
|
178
190
|
return false
|
179
191
|
end
|
180
192
|
|
181
193
|
bufsize = 1024
|
182
194
|
p_buffer = "\0" * bufsize
|
183
|
-
res =
|
195
|
+
res = @GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2)
|
184
196
|
return false if res == 0
|
185
197
|
|
186
198
|
# get pipe name: p_buffer layout is:
|
@@ -217,65 +229,63 @@ class Reline::Windows
|
|
217
229
|
[ { control_keys: :SHIFT, virtual_key_code: VK_TAB }, [27, 91, 90] ],
|
218
230
|
]
|
219
231
|
|
220
|
-
|
221
|
-
|
222
|
-
def self.process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
|
232
|
+
def process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
|
223
233
|
|
224
234
|
# high-surrogate
|
225
235
|
if 0xD800 <= char_code and char_code <= 0xDBFF
|
226
|
-
|
236
|
+
@hsg = char_code
|
227
237
|
return
|
228
238
|
end
|
229
239
|
# low-surrogate
|
230
240
|
if 0xDC00 <= char_code and char_code <= 0xDFFF
|
231
|
-
if
|
232
|
-
char_code = 0x10000 + (
|
233
|
-
|
241
|
+
if @hsg
|
242
|
+
char_code = 0x10000 + (@hsg - 0xD800) * 0x400 + char_code - 0xDC00
|
243
|
+
@hsg = nil
|
234
244
|
else
|
235
245
|
# no high-surrogate. ignored.
|
236
246
|
return
|
237
247
|
end
|
238
248
|
else
|
239
249
|
# ignore high-surrogate without low-surrogate if there
|
240
|
-
|
250
|
+
@hsg = nil
|
241
251
|
end
|
242
252
|
|
243
253
|
key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state)
|
244
254
|
|
245
255
|
match = KEY_MAP.find { |args,| key.matches?(**args) }
|
246
256
|
unless match.nil?
|
247
|
-
|
257
|
+
@output_buf.concat(match.last)
|
248
258
|
return
|
249
259
|
end
|
250
260
|
|
251
261
|
# no char, only control keys
|
252
262
|
return if key.char_code == 0 and key.control_keys.any?
|
253
263
|
|
254
|
-
|
264
|
+
@output_buf.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL)
|
255
265
|
|
256
|
-
|
266
|
+
@output_buf.concat(key.char.bytes)
|
257
267
|
end
|
258
268
|
|
259
|
-
def
|
269
|
+
def check_input_event
|
260
270
|
num_of_events = 0.chr * 8
|
261
|
-
while
|
271
|
+
while @output_buf.empty?
|
262
272
|
Reline.core.line_editor.handle_signal
|
263
|
-
if
|
273
|
+
if @WaitForSingleObject.(@hConsoleInputHandle, 100) != 0 # max 0.1 sec
|
264
274
|
# prevent for background consolemode change
|
265
|
-
|
275
|
+
@legacy_console = getconsolemode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0
|
266
276
|
next
|
267
277
|
end
|
268
|
-
next if
|
278
|
+
next if @GetNumberOfConsoleInputEvents.(@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0
|
269
279
|
input_records = 0.chr * 20 * 80
|
270
280
|
read_event = 0.chr * 4
|
271
|
-
if
|
281
|
+
if @ReadConsoleInputW.(@hConsoleInputHandle, input_records, 80, read_event) != 0
|
272
282
|
read_events = read_event.unpack1('L')
|
273
283
|
0.upto(read_events) do |idx|
|
274
284
|
input_record = input_records[idx * 20, 20]
|
275
285
|
event = input_record[0, 2].unpack1('s*')
|
276
286
|
case event
|
277
287
|
when WINDOW_BUFFER_SIZE_EVENT
|
278
|
-
|
288
|
+
@winch_handler.()
|
279
289
|
when KEY_EVENT
|
280
290
|
key_down = input_record[4, 4].unpack1('l*')
|
281
291
|
repeat_count = input_record[8, 2].unpack1('s*')
|
@@ -293,34 +303,34 @@ class Reline::Windows
|
|
293
303
|
end
|
294
304
|
end
|
295
305
|
|
296
|
-
def
|
306
|
+
def with_raw_input
|
297
307
|
yield
|
298
308
|
end
|
299
309
|
|
300
|
-
def
|
310
|
+
def getc(_timeout_second)
|
301
311
|
check_input_event
|
302
|
-
|
312
|
+
@output_buf.shift
|
303
313
|
end
|
304
314
|
|
305
|
-
def
|
306
|
-
|
315
|
+
def ungetc(c)
|
316
|
+
@output_buf.unshift(c)
|
307
317
|
end
|
308
318
|
|
309
|
-
def
|
310
|
-
not
|
319
|
+
def in_pasting?
|
320
|
+
not empty_buffer?
|
311
321
|
end
|
312
322
|
|
313
|
-
def
|
314
|
-
if not
|
323
|
+
def empty_buffer?
|
324
|
+
if not @output_buf.empty?
|
315
325
|
false
|
316
|
-
elsif
|
326
|
+
elsif @kbhit.call == 0
|
317
327
|
true
|
318
328
|
else
|
319
329
|
false
|
320
330
|
end
|
321
331
|
end
|
322
332
|
|
323
|
-
def
|
333
|
+
def get_console_screen_buffer_info
|
324
334
|
# CONSOLE_SCREEN_BUFFER_INFO
|
325
335
|
# [ 0,2] dwSize.X
|
326
336
|
# [ 2,2] dwSize.Y
|
@@ -334,18 +344,18 @@ class Reline::Windows
|
|
334
344
|
# [18,2] dwMaximumWindowSize.X
|
335
345
|
# [20,2] dwMaximumWindowSize.Y
|
336
346
|
csbi = 0.chr * 22
|
337
|
-
return if
|
347
|
+
return if call_with_console_handle(@GetConsoleScreenBufferInfo, csbi) == 0
|
338
348
|
csbi
|
339
349
|
end
|
340
350
|
|
341
|
-
def
|
351
|
+
def get_screen_size
|
342
352
|
unless csbi = get_console_screen_buffer_info
|
343
353
|
return [1, 1]
|
344
354
|
end
|
345
355
|
csbi[0, 4].unpack('SS').reverse
|
346
356
|
end
|
347
357
|
|
348
|
-
def
|
358
|
+
def cursor_pos
|
349
359
|
unless csbi = get_console_screen_buffer_info
|
350
360
|
return Reline::CursorPos.new(0, 0)
|
351
361
|
end
|
@@ -354,49 +364,49 @@ class Reline::Windows
|
|
354
364
|
Reline::CursorPos.new(x, y)
|
355
365
|
end
|
356
366
|
|
357
|
-
def
|
358
|
-
|
367
|
+
def move_cursor_column(val)
|
368
|
+
call_with_console_handle(@SetConsoleCursorPosition, cursor_pos.y * 65536 + val)
|
359
369
|
end
|
360
370
|
|
361
|
-
def
|
371
|
+
def move_cursor_up(val)
|
362
372
|
if val > 0
|
363
373
|
y = cursor_pos.y - val
|
364
374
|
y = 0 if y < 0
|
365
|
-
|
375
|
+
call_with_console_handle(@SetConsoleCursorPosition, y * 65536 + cursor_pos.x)
|
366
376
|
elsif val < 0
|
367
377
|
move_cursor_down(-val)
|
368
378
|
end
|
369
379
|
end
|
370
380
|
|
371
|
-
def
|
381
|
+
def move_cursor_down(val)
|
372
382
|
if val > 0
|
373
383
|
return unless csbi = get_console_screen_buffer_info
|
374
384
|
screen_height = get_screen_size.first
|
375
385
|
y = cursor_pos.y + val
|
376
386
|
y = screen_height - 1 if y > (screen_height - 1)
|
377
|
-
|
387
|
+
call_with_console_handle(@SetConsoleCursorPosition, (cursor_pos.y + val) * 65536 + cursor_pos.x)
|
378
388
|
elsif val < 0
|
379
389
|
move_cursor_up(-val)
|
380
390
|
end
|
381
391
|
end
|
382
392
|
|
383
|
-
def
|
393
|
+
def erase_after_cursor
|
384
394
|
return unless csbi = get_console_screen_buffer_info
|
385
395
|
attributes = csbi[8, 2].unpack1('S')
|
386
396
|
cursor = csbi[4, 4].unpack1('L')
|
387
397
|
written = 0.chr * 4
|
388
|
-
|
389
|
-
|
398
|
+
call_with_console_handle(@FillConsoleOutputCharacter, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
|
399
|
+
call_with_console_handle(@FillConsoleOutputAttribute, attributes, get_screen_size.last - cursor_pos.x, cursor, written)
|
390
400
|
end
|
391
401
|
|
392
|
-
def
|
402
|
+
def scroll_down(val)
|
393
403
|
return if val < 0
|
394
404
|
return unless csbi = get_console_screen_buffer_info
|
395
405
|
buffer_width, buffer_lines, x, y, attributes, window_left, window_top, window_bottom = csbi.unpack('ssssSssx2s')
|
396
406
|
screen_height = window_bottom - window_top + 1
|
397
407
|
val = screen_height if val > screen_height
|
398
408
|
|
399
|
-
if
|
409
|
+
if @legacy_console || window_left != 0
|
400
410
|
# unless ENABLE_VIRTUAL_TERMINAL,
|
401
411
|
# if srWindow.Left != 0 then it's conhost.exe hosted console
|
402
412
|
# and puts "\n" causes horizontal scroll. its glitch.
|
@@ -404,11 +414,11 @@ class Reline::Windows
|
|
404
414
|
scroll_rectangle = [0, val, buffer_width, buffer_lines - val].pack('s4')
|
405
415
|
destination_origin = 0 # y * 65536 + x
|
406
416
|
fill = [' '.ord, attributes].pack('SS')
|
407
|
-
|
417
|
+
call_with_console_handle(@ScrollConsoleScreenBuffer, scroll_rectangle, nil, destination_origin, fill)
|
408
418
|
else
|
409
419
|
origin_x = x + 1
|
410
420
|
origin_y = y - window_top + 1
|
411
|
-
|
421
|
+
@output.write [
|
412
422
|
(origin_y != screen_height) ? "\e[#{screen_height};H" : nil,
|
413
423
|
"\n" * val,
|
414
424
|
(origin_y != screen_height or !x.zero?) ? "\e[#{origin_y};#{origin_x}H" : nil
|
@@ -416,49 +426,49 @@ class Reline::Windows
|
|
416
426
|
end
|
417
427
|
end
|
418
428
|
|
419
|
-
def
|
420
|
-
if
|
429
|
+
def clear_screen
|
430
|
+
if @legacy_console
|
421
431
|
return unless csbi = get_console_screen_buffer_info
|
422
432
|
buffer_width, _buffer_lines, attributes, window_top, window_bottom = csbi.unpack('ss@8S@12sx2s')
|
423
433
|
fill_length = buffer_width * (window_bottom - window_top + 1)
|
424
434
|
screen_topleft = window_top * 65536
|
425
435
|
written = 0.chr * 4
|
426
|
-
|
427
|
-
|
428
|
-
|
436
|
+
call_with_console_handle(@FillConsoleOutputCharacter, 0x20, fill_length, screen_topleft, written)
|
437
|
+
call_with_console_handle(@FillConsoleOutputAttribute, attributes, fill_length, screen_topleft, written)
|
438
|
+
call_with_console_handle(@SetConsoleCursorPosition, screen_topleft)
|
429
439
|
else
|
430
|
-
|
440
|
+
@output.write "\e[2J" "\e[H"
|
431
441
|
end
|
432
442
|
end
|
433
443
|
|
434
|
-
def
|
444
|
+
def set_screen_size(rows, columns)
|
435
445
|
raise NotImplementedError
|
436
446
|
end
|
437
447
|
|
438
|
-
def
|
448
|
+
def hide_cursor
|
439
449
|
size = 100
|
440
450
|
visible = 0 # 0 means false
|
441
451
|
cursor_info = [size, visible].pack('Li')
|
442
|
-
|
452
|
+
call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
|
443
453
|
end
|
444
454
|
|
445
|
-
def
|
455
|
+
def show_cursor
|
446
456
|
size = 100
|
447
457
|
visible = 1 # 1 means true
|
448
458
|
cursor_info = [size, visible].pack('Li')
|
449
|
-
|
459
|
+
call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
|
450
460
|
end
|
451
461
|
|
452
|
-
def
|
453
|
-
|
462
|
+
def set_winch_handler(&handler)
|
463
|
+
@winch_handler = handler
|
454
464
|
end
|
455
465
|
|
456
|
-
def
|
466
|
+
def prep
|
457
467
|
# do nothing
|
458
468
|
nil
|
459
469
|
end
|
460
470
|
|
461
|
-
def
|
471
|
+
def deprep(otio)
|
462
472
|
# do nothing
|
463
473
|
end
|
464
474
|
|
data/lib/reline/io.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
module Reline
|
3
|
+
class IO
|
4
|
+
RESET_COLOR = "\e[0m"
|
5
|
+
|
6
|
+
def self.decide_io_gate
|
7
|
+
if ENV['TERM'] == 'dumb'
|
8
|
+
Reline::Dumb.new
|
9
|
+
else
|
10
|
+
require 'reline/io/ansi'
|
11
|
+
|
12
|
+
case RbConfig::CONFIG['host_os']
|
13
|
+
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
14
|
+
require 'reline/io/windows'
|
15
|
+
io = Reline::Windows.new
|
16
|
+
if io.msys_tty?
|
17
|
+
Reline::ANSI.new
|
18
|
+
else
|
19
|
+
io
|
20
|
+
end
|
21
|
+
else
|
22
|
+
Reline::ANSI.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def dumb?
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def win?
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
def reset_color_sequence
|
36
|
+
self.class::RESET_COLOR
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
require 'reline/io/dumb'
|
@@ -1,15 +1,31 @@
|
|
1
1
|
class Reline::KeyActor::Base
|
2
|
-
|
2
|
+
def initialize(mapping = [])
|
3
|
+
@mapping = mapping
|
4
|
+
@matching_bytes = {}
|
5
|
+
@key_bindings = {}
|
6
|
+
end
|
3
7
|
|
4
8
|
def get_method(key)
|
5
|
-
|
9
|
+
@mapping[key]
|
10
|
+
end
|
11
|
+
|
12
|
+
def add(key, func)
|
13
|
+
(1...key.size).each do |size|
|
14
|
+
@matching_bytes[key.take(size)] = true
|
15
|
+
end
|
16
|
+
@key_bindings[key] = func
|
17
|
+
end
|
18
|
+
|
19
|
+
def matching?(key)
|
20
|
+
@matching_bytes[key]
|
6
21
|
end
|
7
22
|
|
8
|
-
def
|
9
|
-
@
|
23
|
+
def get(key)
|
24
|
+
@key_bindings[key]
|
10
25
|
end
|
11
26
|
|
12
|
-
def
|
13
|
-
@
|
27
|
+
def clear
|
28
|
+
@matching_bytes.clear
|
29
|
+
@key_bindings.clear
|
14
30
|
end
|
15
31
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Reline::KeyActor::Composite
|
2
|
+
def initialize(key_actors)
|
3
|
+
@key_actors = key_actors
|
4
|
+
end
|
5
|
+
|
6
|
+
def matching?(key)
|
7
|
+
@key_actors.any? { |key_actor| key_actor.matching?(key) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(key)
|
11
|
+
@key_actors.each do |key_actor|
|
12
|
+
func = key_actor.get(key)
|
13
|
+
return func if func
|
14
|
+
end
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
end
|