blob: 7e49ea47d7c8ec379d4a1932d422e4c839ef07b2 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
# coding=utf-8
"""
Imports the proper readline for the platform and provides utility functions for it
"""
from enum import Enum
import sys
# Prefer statically linked gnureadline if available (for macOS compatibility due to issues with libedit)
try:
import gnureadline as readline
except ImportError:
# Try to import readline, but allow failure for convenience in Windows unit testing
# Note: If this actually fails, you should install readline on Linux or Mac or pyreadline on Windows
try:
# noinspection PyUnresolvedReferences
import readline
except ImportError: # pragma: no cover
pass
class RlType(Enum):
"""Readline library types we recognize"""
GNU = 1
PYREADLINE = 2
NONE = 3
# Check what implementation of readline we are using
rl_type = RlType.NONE
# The order of this check matters since importing pyreadline will also show readline in the modules list
if 'pyreadline' in sys.modules:
rl_type = RlType.PYREADLINE
############################################################################################################
# pyreadline is incomplete in terms of the Python readline API. Add the missing functions we need.
############################################################################################################
# readline.redisplay()
try:
getattr(readline, 'redisplay')
except AttributeError:
# noinspection PyProtectedMember
readline.redisplay = readline.rl.mode._update_line
# readline.remove_history_item()
try:
getattr(readline, 'remove_history_item')
except AttributeError:
# noinspection PyProtectedMember
def pyreadline_remove_history_item(pos: int) -> None:
"""
An implementation of remove_history_item() for pyreadline
:param pos: The 0-based position in history to remove
"""
# Save of the current location of the history cursor
saved_cursor = readline.rl.mode._history.history_cursor
# Delete the history item
del(readline.rl.mode._history.history[pos])
# Update the cursor if needed
if saved_cursor > pos:
readline.rl.mode._history.history_cursor -= 1
readline.remove_history_item = pyreadline_remove_history_item
elif 'gnureadline' in sys.modules or 'readline' in sys.modules:
# We don't support libedit
if 'libedit' not in readline.__doc__:
rl_type = RlType.GNU
# Load the readline lib so we can access members of it
import ctypes
readline_lib = ctypes.CDLL(readline.__file__)
# noinspection PyProtectedMember
def rl_force_redisplay() -> None:
"""
Causes readline to display the prompt and input text wherever the cursor is and start
reading input from this location. This is the proper way to restore the input line after
printing to the screen
"""
if not sys.stdout.isatty():
return
if rl_type == RlType.GNU: # pragma: no cover
readline_lib.rl_forced_update_display()
# After manually updating the display, readline asks that rl_display_fixed be set to 1 for efficiency
display_fixed = ctypes.c_int.in_dll(readline_lib, "rl_display_fixed")
display_fixed.value = 1
elif rl_type == RlType.PYREADLINE: # pragma: no cover
# Call _print_prompt() first to set the new location of the prompt
readline.rl.mode._print_prompt()
readline.rl.mode._update_line()
|