Skip to content

Commit 66291b5

Browse files
authored
Get console handle again and retry when Win32API call fails (#734)
1 parent 59e4ade commit 66291b5

File tree

1 file changed

+24
-14
lines changed

1 file changed

+24
-14
lines changed

lib/reline/io/windows.rb

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,24 @@ def call(*args)
159159
FILE_NAME_INFO = 2
160160
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
161161

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+
162172
private def getconsolemode
163173
mode = "\000\000\000\000"
164-
@GetConsoleMode.call(@hConsoleHandle, mode)
174+
call_with_console_handle(@GetConsoleMode, mode)
165175
mode.unpack1('L')
166176
end
167177

168178
private def setconsolemode(mode)
169-
@SetConsoleMode.call(@hConsoleHandle, mode)
179+
call_with_console_handle(@SetConsoleMode, mode)
170180
end
171181

172182
#if @legacy_console
@@ -334,7 +344,7 @@ def get_console_screen_buffer_info
334344
# [18,2] dwMaximumWindowSize.X
335345
# [20,2] dwMaximumWindowSize.Y
336346
csbi = 0.chr * 22
337-
return if @GetConsoleScreenBufferInfo.call(@hConsoleHandle, csbi) == 0
347+
return if call_with_console_handle(@GetConsoleScreenBufferInfo, csbi) == 0
338348
csbi
339349
end
340350

@@ -355,14 +365,14 @@ def cursor_pos
355365
end
356366

357367
def move_cursor_column(val)
358-
@SetConsoleCursorPosition.call(@hConsoleHandle, cursor_pos.y * 65536 + val)
368+
call_with_console_handle(@SetConsoleCursorPosition, cursor_pos.y * 65536 + val)
359369
end
360370

361371
def move_cursor_up(val)
362372
if val > 0
363373
y = cursor_pos.y - val
364374
y = 0 if y < 0
365-
@SetConsoleCursorPosition.call(@hConsoleHandle, y * 65536 + cursor_pos.x)
375+
call_with_console_handle(@SetConsoleCursorPosition, y * 65536 + cursor_pos.x)
366376
elsif val < 0
367377
move_cursor_down(-val)
368378
end
@@ -374,7 +384,7 @@ def move_cursor_down(val)
374384
screen_height = get_screen_size.first
375385
y = cursor_pos.y + val
376386
y = screen_height - 1 if y > (screen_height - 1)
377-
@SetConsoleCursorPosition.call(@hConsoleHandle, (cursor_pos.y + val) * 65536 + cursor_pos.x)
387+
call_with_console_handle(@SetConsoleCursorPosition, (cursor_pos.y + val) * 65536 + cursor_pos.x)
378388
elsif val < 0
379389
move_cursor_up(-val)
380390
end
@@ -385,8 +395,8 @@ def erase_after_cursor
385395
attributes = csbi[8, 2].unpack1('S')
386396
cursor = csbi[4, 4].unpack1('L')
387397
written = 0.chr * 4
388-
@FillConsoleOutputCharacter.call(@hConsoleHandle, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
389-
@FillConsoleOutputAttribute.call(@hConsoleHandle, attributes, get_screen_size.last - cursor_pos.x, cursor, written)
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)
390400
end
391401

392402
def scroll_down(val)
@@ -404,7 +414,7 @@ def scroll_down(val)
404414
scroll_rectangle = [0, val, buffer_width, buffer_lines - val].pack('s4')
405415
destination_origin = 0 # y * 65536 + x
406416
fill = [' '.ord, attributes].pack('SS')
407-
@ScrollConsoleScreenBuffer.call(@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill)
417+
call_with_console_handle(@ScrollConsoleScreenBuffer, scroll_rectangle, nil, destination_origin, fill)
408418
else
409419
origin_x = x + 1
410420
origin_y = y - window_top + 1
@@ -423,9 +433,9 @@ def clear_screen
423433
fill_length = buffer_width * (window_bottom - window_top + 1)
424434
screen_topleft = window_top * 65536
425435
written = 0.chr * 4
426-
@FillConsoleOutputCharacter.call(@hConsoleHandle, 0x20, fill_length, screen_topleft, written)
427-
@FillConsoleOutputAttribute.call(@hConsoleHandle, attributes, fill_length, screen_topleft, written)
428-
@SetConsoleCursorPosition.call(@hConsoleHandle, screen_topleft)
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)
429439
else
430440
@output.write "\e[2J" "\e[H"
431441
end
@@ -439,14 +449,14 @@ def hide_cursor
439449
size = 100
440450
visible = 0 # 0 means false
441451
cursor_info = [size, visible].pack('Li')
442-
@SetConsoleCursorInfo.call(@hConsoleHandle, cursor_info)
452+
call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
443453
end
444454

445455
def show_cursor
446456
size = 100
447457
visible = 1 # 1 means true
448458
cursor_info = [size, visible].pack('Li')
449-
@SetConsoleCursorInfo.call(@hConsoleHandle, cursor_info)
459+
call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
450460
end
451461

452462
def set_winch_handler(&handler)

0 commit comments

Comments
 (0)