From 59f80590a742a6461d5a3535f25853a34aae13c8 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Thu, 11 May 2017 20:56:29 -0400 Subject: [PATCH 1/5] Reverting change which prefers gnureadline if available The current version of gnureadline available in pip and conda has a malloc error, at least on Mac OS --- cmd2.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/cmd2.py b/cmd2.py index ed481330e..ab16472c0 100755 --- a/cmd2.py +++ b/cmd2.py @@ -62,15 +62,6 @@ # noinspection PyUnresolvedReferences from six.moves.urllib.request import urlopen -# Prefer statically linked gnureadline if available (for Mac OS X compatibility due to issues with libedit) -try: - import gnureadline as readline -except ImportError: - try: - import readline - except ImportError: - pass - # Python 3 compatibility hack due to no built-in file keyword in Python 3 # Due to one occurrence of isinstance(, file) checking to see if something is of file type try: From ecf5a11315fc0bcab575182820f8c06e348813d2 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Thu, 11 May 2017 21:03:12 -0400 Subject: [PATCH 2/5] Documentation update --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index c532c1c61..84ba4a927 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -35,7 +35,7 @@ The basic use of ``cmd2`` is identical to that of cmd_. The tab-completion feature provided by cmd_ relies on underlying capability provided by GNU readline or an equivalent library. Linux distros will almost always come with the required library installed. - For Mac OS X, we recommend installing the `gnureadline `_ Python module. + For Mac OS X, we recommend using the `Homebrew `_ package manager to install the ``readline`` package. For Windows, we recommend installing the `pyreadline `_ Python module. Resources From 2bd17dbc34ce88a4cd5375dadb0406b891a1fdb6 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Thu, 11 May 2017 21:41:36 -0400 Subject: [PATCH 3/5] Added code to protect against GNU Readline bug GNU Readline has a bug in calculating prompt length when ANSI escape codes are present in the prompt. It requires you to escape the escape codes to tell it where sections of invisible characters begin and end. So before calling input(), cmd2 now makes the prompt safe by escaping any ANSI escape codes present. --- cmd2.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/cmd2.py b/cmd2.py index ab16472c0..b5dbcfbd2 100755 --- a/cmd2.py +++ b/cmd2.py @@ -34,6 +34,7 @@ import os import platform import re +import readline import shlex import six import subprocess @@ -1096,12 +1097,37 @@ def _default(self, statement): return False + @staticmethod + def _surround_ansi_escapes(prompt, start="\x01", end="\x02"): + """Overcome bug in GNU Readline in relation to calculation of prompt length in presence of ASNI escape codes. + + :param prompt: str - original prompt + :param start: str - start code to tell GNU Readline about beginning of invisible characters + :param end: str - end code to tell GNU Readline about end of invisible characters + :return: str - prompt safe to pass to GNU Readline + """ + escaped = False + result = "" + + for c in prompt: + if c == "\x1b" and not escaped: + result += start + c + escaped = True + elif c.isalpha() and escaped: + result += c + end + escaped = False + else: + result += c + + return result + def pseudo_raw_input(self, prompt): """copied from cmd's cmdloop; like raw_input, but accounts for changed stdin, stdout""" if self.use_rawinput: + safe_prompt = self._surround_ansi_escapes(prompt) try: - line = sm.input(prompt) + line = sm.input(safe_prompt) except EOFError: line = 'EOF' else: From 3a2af4d81effe0c8701146c98d12b08dc0622214 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Thu, 11 May 2017 21:48:24 -0400 Subject: [PATCH 4/5] Windows terminal doesn't use ANSI escape codes --- cmd2.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd2.py b/cmd2.py index b5dbcfbd2..bd48c404e 100755 --- a/cmd2.py +++ b/cmd2.py @@ -1106,6 +1106,10 @@ def _surround_ansi_escapes(prompt, start="\x01", end="\x02"): :param end: str - end code to tell GNU Readline about end of invisible characters :return: str - prompt safe to pass to GNU Readline """ + # Windows terminals don't use ANSI escape codes and Windows readline isn't based on GNU Readline + if sys.platform == "win32": + return prompt + escaped = False result = "" From 75ca51652af1fa2ee8b8374f99cf5a75df4e0d9a Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Thu, 11 May 2017 21:52:39 -0400 Subject: [PATCH 5/5] Fix Windows unit tests --- cmd2.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmd2.py b/cmd2.py index bd48c404e..3504d7d42 100755 --- a/cmd2.py +++ b/cmd2.py @@ -34,7 +34,6 @@ import os import platform import re -import readline import shlex import six import subprocess @@ -80,6 +79,13 @@ except ImportError: ipython_available = False +# 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: + import readline +except ImportError: + pass + __version__ = '0.7.1a' # Pyparsing enablePackrat() can greatly speed up parsing, but problems have been seen in Python 3 in the past