summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md4
-rwxr-xr-xREADME.md9
-rw-r--r--cmd2/cmd2.py43
-rwxr-xr-xsetup.py4
4 files changed, 34 insertions, 26 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dee53e86..d51baadd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.9.6 (TBD)
+* Enhancements
+ * All platforms now depend on [wcwidth](https://pypi.python.org/pypi/wcwidth) to assist with asynchronous alerts.
+
## 0.9.5 (October 11, 2018)
* Bug Fixes
* Fixed bug where ``get_all_commands`` could return non-callable attributes
diff --git a/README.md b/README.md
index efb9f122..b3ca5fc8 100755
--- a/README.md
+++ b/README.md
@@ -60,11 +60,10 @@ pip install -U cmd2
cmd2 works with Python 3.4+ on Windows, macOS, and Linux. It is pure Python code with
the only 3rd-party dependencies being on [attrs](https://github.com/python-attrs/attrs),
-[colorama](https://github.com/tartley/colorama), and [pyperclip](https://github.com/asweigart/pyperclip).
-Windows has an additional dependency on [pyreadline](https://pypi.python.org/pypi/pyreadline). Non-Windows platforms
-have an additional dependency on [wcwidth](https://pypi.python.org/pypi/wcwidth). Finally, Python
-3.4 has additional dependencies on [contextlib2](https://pypi.python.org/pypi/contextlib2) and the
-[typing](https://pypi.org/project/typing/) backport.
+[colorama](https://github.com/tartley/colorama), [pyperclip](https://github.com/asweigart/pyperclip), and
+[wcwidth](https://pypi.python.org/pypi/wcwidth). Windows has an additional dependency on
+[pyreadline](https://pypi.python.org/pypi/pyreadline). Finally, Python 3.4 has additional dependencies
+on [contextlib2](https://pypi.python.org/pypi/contextlib2) and the [typing](https://pypi.org/project/typing/) backport.
For information on other installation options, see
[Installation Instructions](https://cmd2.readthedocs.io/en/latest/install.html) in the cmd2
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 830cd045..eef662d0 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -32,8 +32,6 @@ Git repository on GitHub at https://github.com/python-cmd2/cmd2
import argparse
import cmd
import collections
-import colorama
-from colorama import Fore
import glob
import inspect
import os
@@ -43,15 +41,20 @@ import sys
import threading
from typing import Any, Callable, Dict, List, Mapping, Optional, Tuple, Type, Union, IO
+import colorama
+from colorama import Fore
+from wcwidth import wcswidth
+
from . import constants
-from . import utils
from . import plugin
+from . import utils
from .argparse_completer import AutoCompleter, ACArgumentParser, ACTION_ARG_CHOICES
from .clipboard import can_clip, get_paste_buffer, write_to_paste_buffer
from .parsing import StatementParser, Statement, Macro, MacroArg
# Set up readline
from .rl_utils import rl_type, RlType, rl_get_point, rl_set_prompt, vt100_support, rl_make_safe_prompt
+
if rl_type == RlType.NONE: # pragma: no cover
rl_warning = "Readline features including tab completion have been disabled since no \n" \
"supported version of readline was found. To resolve this, install \n" \
@@ -71,9 +74,6 @@ else:
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
@@ -3436,11 +3436,12 @@ a..b, a:b, a:, ..b items by indices (inclusive)
runner = unittest.TextTestRunner()
runner.run(testcase)
- def _clear_input_lines_str(self) -> str: # pragma: no cover
+ def _clear_input_lines_str(self, current_prompt: str) -> str: # pragma: no cover
"""
Returns a string that if printed will clear the prompt and input lines in the terminal,
leaving the cursor at the beginning of the first input line
- :return: the string to print
+
+ :param current_prompt: the currently displayed prompt
"""
if not (vt100_support and self.use_rawinput):
return ''
@@ -3449,17 +3450,18 @@ a..b, a:b, a:, ..b items by indices (inclusive)
import colorama.ansi as ansi
from colorama import Cursor
- visible_prompt = self.visible_prompt
+ # Remove ansi characters to get the visible width of the prompt
+ prompt_width = wcswidth(utils.strip_ansi(current_prompt))
# Get the size of the terminal
terminal_size = shutil.get_terminal_size()
# Figure out how many lines the prompt and user input take up
- total_str_size = len(visible_prompt) + len(readline.get_line_buffer())
+ total_str_size = prompt_width + wcswidth(readline.get_line_buffer())
num_input_lines = int(total_str_size / terminal_size.columns) + 1
# Get the cursor's offset from the beginning of the first input line
- cursor_input_offset = len(visible_prompt) + rl_get_point()
+ cursor_input_offset = prompt_width + rl_get_point()
# Calculate what input line the cursor is on
cursor_input_line = int(cursor_input_offset / terminal_size.columns) + 1
@@ -3505,16 +3507,20 @@ a..b, a:b, a:, ..b items by indices (inclusive)
do_update = False
# Generate a string to clear the prompt and input lines and replace with the alert
- terminal_str = self._clear_input_lines_str()
+ current_prompt = self.continuation_prompt if self.at_continuation_prompt else self.prompt
+ terminal_str = self._clear_input_lines_str(current_prompt)
+
if alert_msg:
terminal_str += alert_msg + '\n'
do_update = True
- # Set the new prompt now that _clear_input_lines_str is done using the old prompt
- if new_prompt is not None and not self.at_continuation_prompt:
+ # Set the prompt if its changed
+ if new_prompt is not None and new_prompt != self.prompt:
self.prompt = new_prompt
- rl_set_prompt(self.prompt)
- do_update = True
+
+ if not self.at_continuation_prompt:
+ rl_set_prompt(self.prompt)
+ do_update = True
if do_update:
# Print terminal_str to erase the lines
@@ -3543,8 +3549,9 @@ a..b, a:b, a:, ..b items by indices (inclusive)
a prompt is onscreen. Therefore it is best to acquire the lock before calling this function
to guarantee the prompt changes.
- The prompt will not update if a continuation prompt is being displayed
- while entering a multiline command.
+ If a continuation prompt is currently being displayed while entering a multiline
+ command, the onscreen prompt will not change. However self.prompt will still be updated
+ and display immediately after the multiline line command completes.
:param new_prompt: what to change the prompt to
:raises RuntimeError if called while another thread holds terminal_lock
diff --git a/setup.py b/setup.py
index 861813c7..764ac8d3 100755
--- a/setup.py
+++ b/setup.py
@@ -66,13 +66,11 @@ Topic :: Software Development :: Libraries :: Python Modules
SETUP_REQUIRES = ['setuptools_scm']
-INSTALL_REQUIRES = ['pyperclip >= 1.5.27', 'colorama', 'attrs >= 16.3.0']
+INSTALL_REQUIRES = ['pyperclip >= 1.5.27', 'colorama', 'attrs >= 16.3.0', 'wcwidth']
EXTRAS_REQUIRE = {
# Windows also requires pyreadline to ensure tab completion works
":sys_platform=='win32'": ['pyreadline'],
- # POSIX OSes also require wcwidth for correctly estimating the displayed width of unicode chars
- ":sys_platform!='win32'": ['wcwidth'],
# Python 3.4 and earlier require contextlib2 for temporarily redirecting stderr and stdout
":python_version<'3.5'": ['contextlib2', 'typing'],
# Extra dependencies for running unit tests