summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Van Brunt <kmvanbrunt@gmail.com>2018-04-17 01:23:07 -0400
committerKevin Van Brunt <kmvanbrunt@gmail.com>2018-04-17 01:23:07 -0400
commit9e24c983806c3cb6ff0722f5f2314ff56de2933c (patch)
tree36f24729faefb958ee84c1738bfa1a1d3ace748e
parent07c283eb484c9f2513f23594b364ad331b2b0e81 (diff)
downloadcmd2-git-9e24c983806c3cb6ff0722f5f2314ff56de2933c.tar.gz
Added common file to provide readline utility functions
-rwxr-xr-xAutoCompleter.py5
-rwxr-xr-xcmd2.py81
-rw-r--r--rl_utils.py61
3 files changed, 90 insertions, 57 deletions
diff --git a/AutoCompleter.py b/AutoCompleter.py
index 83228b3b..f188a46e 100755
--- a/AutoCompleter.py
+++ b/AutoCompleter.py
@@ -3,6 +3,7 @@ import argparse
import re as _re
import sys
from argparse import OPTIONAL, ZERO_OR_MORE, ONE_OR_MORE, REMAINDER, PARSER, ArgumentError, _
+from rl_utils import rl_force_redisplay
try:
from typing import List, Dict, Tuple, Callable, Union
except:
@@ -488,8 +489,8 @@ class AutoCompleter(object):
out_str += '\n{0: <{width}}'.format('', width=pref_len).join(help_lines)
print('\nHint:' + out_str + '\n')
- from cmd2 import readline_lib
- readline_lib.rl_forced_update_display()
+ # Redraw prompt and input line
+ rl_force_redisplay()
# noinspection PyUnusedLocal
@staticmethod
diff --git a/cmd2.py b/cmd2.py
index 54eff811..bdf8c95c 100755
--- a/cmd2.py
+++ b/cmd2.py
@@ -45,21 +45,38 @@ import traceback
import unittest
from code import InteractiveConsole
-try:
- from enum34 import Enum
-except ImportError:
- from enum import Enum
-
import pyparsing
import pyperclip
+# Set up readline
+from rl_utils import rl_force_redisplay, readline, rl_type, RlType
+
+if rl_type == RlType.PYREADLINE:
+
+ # Save the original pyreadline display completion function since we need to override it and restore it
+ # noinspection PyProtectedMember
+ orig_pyreadline_display = readline.rl.mode._display_completions
+
+elif rl_type == RlType.GNU:
+
+ # We need wcswidth to calculate display width of tab completions
+ from wcwidth import wcswidth
+
+ # Get the readline lib so we can make changes to it
+ import ctypes
+ from rl_utils import readline_lib
+
+ # Save address that rl_basic_quote_characters is pointing to since we need to override and restore it
+ rl_basic_quote_characters = ctypes.c_char_p.in_dll(readline_lib, "rl_basic_quote_characters")
+ orig_rl_basic_quote_characters_addr = ctypes.cast(rl_basic_quote_characters, ctypes.c_void_p).value
+
# Newer versions of pyperclip are released as a single file, but older versions had a more complicated structure
try:
from pyperclip.exceptions import PyperclipException
except ImportError:
# noinspection PyUnresolvedReferences
from pyperclip import PyperclipException
-
+
# Collection is a container that is sizable and iterable
# It was introduced in Python 3.6. We will try to import it, otherwise use our implementation
try:
@@ -96,47 +113,6 @@ try:
except ImportError:
ipython_available = False
-# 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:
- pass
-
-# Check what implementation of readline we are using
-class RlType(Enum):
- GNU = 1
- PYREADLINE = 2
- NONE = 3
-
-rl_type = RlType.NONE
-
-if 'pyreadline' in sys.modules:
- rl_type = RlType.PYREADLINE
-
- # Save the original pyreadline display completion function since we need to override it and restore it
- # noinspection PyProtectedMember
- orig_pyreadline_display = readline.rl.mode._display_completions
-
-elif 'gnureadline' in sys.modules or 'readline' in sys.modules:
- rl_type = RlType.GNU
-
- # We need wcswidth to calculate display width of tab completions
- from wcwidth import wcswidth
-
- # Load the readline lib so we can make changes to it
- import ctypes
- readline_lib = ctypes.CDLL(readline.__file__)
-
- # Save address that rl_basic_quote_characters is pointing to since we need to override and restore it
- rl_basic_quote_characters = ctypes.c_char_p.in_dll(readline_lib, "rl_basic_quote_characters")
- orig_rl_basic_quote_characters_addr = ctypes.cast(rl_basic_quote_characters, ctypes.c_void_p).value
-
__version__ = '0.9.0'
# Pyparsing enablePackrat() can greatly speed up parsing, but problems have been seen in Python 3 in the past
@@ -1669,13 +1645,8 @@ class Cmd(cmd.Cmd):
# rl_display_match_list(strings_array, number of completion matches, longest match length)
readline_lib.rl_display_match_list(strings_array, len(encoded_matches), longest_match_length)
- # rl_forced_update_display() is the proper way to redraw the prompt and line, but we
- # have to use ctypes to do it since Python's readline API does not wrap the function
- readline_lib.rl_forced_update_display()
-
- # Since we updated the display, readline asks that rl_display_fixed be set for efficiency
- display_fixed = ctypes.c_int.in_dll(readline_lib, "rl_display_fixed")
- display_fixed.value = 1
+ # Redraw prompt and input line
+ rl_force_redisplay()
def _display_matches_pyreadline(self, matches):
"""
@@ -1695,7 +1666,7 @@ class Cmd(cmd.Cmd):
# Add padding for visual appeal
matches_to_display, _ = self._pad_matches_to_display(matches_to_display)
- # Display the matches
+ # Display matches using actual display function. This also redraws the prompt and line.
orig_pyreadline_display(matches_to_display)
# ----- Methods which override stuff in cmd -----
diff --git a/rl_utils.py b/rl_utils.py
new file mode 100644
index 00000000..11c45ee4
--- /dev/null
+++ b/rl_utils.py
@@ -0,0 +1,61 @@
+# coding=utf-8
+"""
+Imports the proper readline for the platform and provides utility functions for it
+"""
+import sys
+
+try:
+ from enum34 import Enum
+except ImportError:
+ from enum import Enum
+
+# 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:
+ pass
+
+
+# Check what implementation of readline we are using
+class RlType(Enum):
+ GNU = 1
+ PYREADLINE = 2
+ NONE = 3
+
+
+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
+
+elif 'gnureadline' in sys.modules or 'readline' in sys.modules:
+ rl_type = RlType.GNU
+
+ # Load the readline lib so we can access members of it
+ import ctypes
+ readline_lib = ctypes.CDLL(readline.__file__)
+
+
+def rl_force_redisplay() -> None:
+ """
+ Causes readline to redraw prompt and input line
+ """
+ if rl_type == RlType.GNU:
+ # rl_forced_update_display() is the proper way to redraw the prompt and line, but we
+ # have to use ctypes to do it since Python's readline API does not wrap the function
+ 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:
+ # noinspection PyProtectedMember
+ readline.rl.mode._print_prompt()