Skip to content

Commit aa824fe

Browse files
authored
Merge pull request #93 from python-cmd2/gnureadline
cmd2 now protects against GNU Readline bug when ANSI escapes in prompt
2 parents fcb7026 + 75ca516 commit aa824fe

File tree

2 files changed

+38
-11
lines changed

2 files changed

+38
-11
lines changed

cmd2.py

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,6 @@
6262
# noinspection PyUnresolvedReferences
6363
from six.moves.urllib.request import urlopen
6464

65-
# Prefer statically linked gnureadline if available (for Mac OS X compatibility due to issues with libedit)
66-
try:
67-
import gnureadline as readline
68-
except ImportError:
69-
try:
70-
import readline
71-
except ImportError:
72-
pass
73-
7465
# Python 3 compatibility hack due to no built-in file keyword in Python 3
7566
# Due to one occurrence of isinstance(<foo>, file) checking to see if something is of file type
7667
try:
@@ -88,6 +79,13 @@
8879
except ImportError:
8980
ipython_available = False
9081

82+
# Try to import readline, but allow failure for convenience in Windows unit testing
83+
# Note: If this actually fails, you should install readline on Linux or Mac or pyreadline on Windows
84+
try:
85+
import readline
86+
except ImportError:
87+
pass
88+
9189
__version__ = '0.7.1a'
9290

9391
# Pyparsing enablePackrat() can greatly speed up parsing, but problems have been seen in Python 3 in the past
@@ -1105,12 +1103,41 @@ def _default(self, statement):
11051103

11061104
return False
11071105

1106+
@staticmethod
1107+
def _surround_ansi_escapes(prompt, start="\x01", end="\x02"):
1108+
"""Overcome bug in GNU Readline in relation to calculation of prompt length in presence of ASNI escape codes.
1109+
1110+
:param prompt: str - original prompt
1111+
:param start: str - start code to tell GNU Readline about beginning of invisible characters
1112+
:param end: str - end code to tell GNU Readline about end of invisible characters
1113+
:return: str - prompt safe to pass to GNU Readline
1114+
"""
1115+
# Windows terminals don't use ANSI escape codes and Windows readline isn't based on GNU Readline
1116+
if sys.platform == "win32":
1117+
return prompt
1118+
1119+
escaped = False
1120+
result = ""
1121+
1122+
for c in prompt:
1123+
if c == "\x1b" and not escaped:
1124+
result += start + c
1125+
escaped = True
1126+
elif c.isalpha() and escaped:
1127+
result += c + end
1128+
escaped = False
1129+
else:
1130+
result += c
1131+
1132+
return result
1133+
11081134
def pseudo_raw_input(self, prompt):
11091135
"""copied from cmd's cmdloop; like raw_input, but accounts for changed stdin, stdout"""
11101136

11111137
if self.use_rawinput:
1138+
safe_prompt = self._surround_ansi_escapes(prompt)
11121139
try:
1113-
line = sm.input(prompt)
1140+
line = sm.input(safe_prompt)
11141141
except EOFError:
11151142
line = 'EOF'
11161143
else:

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ The basic use of ``cmd2`` is identical to that of cmd_.
3535

3636
The tab-completion feature provided by cmd_ relies on underlying capability provided by GNU readline or an
3737
equivalent library. Linux distros will almost always come with the required library installed.
38-
For Mac OS X, we recommend installing the `gnureadline <https://pypi.python.org/pypi/gnureadline>`_ Python module.
38+
For Mac OS X, we recommend using the `Homebrew <https://brew.sh>`_ package manager to install the ``readline`` package.
3939
For Windows, we recommend installing the `pyreadline <https://pypi.python.org/pypi/pyreadline>`_ Python module.
4040

4141
Resources

0 commit comments

Comments
 (0)