diff options
-rw-r--r-- | CHANGELOG.md | 6 | ||||
-rw-r--r-- | cmd2/cmd2.py | 9 | ||||
-rw-r--r-- | cmd2/utils.py | 39 | ||||
-rw-r--r-- | tests/test_utils.py | 64 |
4 files changed, 60 insertions, 58 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index c6ec13f1..41e5e7bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,11 @@ -## 0.9.22 (December 10, 2019) +## 0.9.22 (December 9, 2019) * Bug Fixes * Fixed bug where a redefined `ansi.style_error` was not being used in all `cmd2` files * Enhancements * Enabled line buffering when redirecting output to a file - * Added `ljustify_text()`, `center_text()`, and `rjustify_text()` to utils.py. All 3 of these functions support + * Added `align_left()`, `align_center()`, and `align_right()` to utils.py. All 3 of these functions support ANSI escape sequences and characters with display widths greater than 1. - + ## 0.9.21 (November 26, 2019) * Bug Fixes * Fixed bug where pipe processes were not being stopped by Ctrl-C diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 9c48b222..28a9dedb 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -2718,6 +2718,7 @@ class Cmd(cmd.Cmd): self.stdout.write("\n") shortcuts_parser = DEFAULT_ARGUMENT_PARSER(description="List available shortcuts") + @with_argparser(shortcuts_parser) def do_shortcuts(self, _: argparse.Namespace) -> None: """List available shortcuts""" @@ -2727,6 +2728,7 @@ class Cmd(cmd.Cmd): self.poutput("Shortcuts for other commands:\n{}".format(result)) eof_parser = DEFAULT_ARGUMENT_PARSER(description="Called when <Ctrl>-D is pressed", epilog=INTERNAL_COMMAND_EPILOG) + @with_argparser(eof_parser) def do_eof(self, _: argparse.Namespace) -> bool: """Called when <Ctrl>-D is pressed""" @@ -2734,6 +2736,7 @@ class Cmd(cmd.Cmd): return True quit_parser = DEFAULT_ARGUMENT_PARSER(description="Exit this application") + @with_argparser(quit_parser) def do_quit(self, _: argparse.Namespace) -> bool: """Exit this application""" @@ -3215,6 +3218,7 @@ class Cmd(cmd.Cmd): # Only include the do_ipy() method if IPython is available on the system if ipython_available: # pragma: no cover ipython_parser = DEFAULT_ARGUMENT_PARSER(description="Enter an interactive IPython shell") + @with_argparser(ipython_parser) def do_ipy(self, _: argparse.Namespace) -> None: """Enter an interactive IPython shell""" @@ -3223,6 +3227,7 @@ class Cmd(cmd.Cmd): 'Run Python code from external files with: run filename.py\n') exit_msg = 'Leaving IPython, back to {}'.format(sys.argv[0]) + # noinspection PyUnusedLocal def load_ipy(cmd2_app: Cmd, py_bridge: PyBridge): """ Embed an IPython shell in an environment that is restricted to only the variables in this function @@ -3715,7 +3720,7 @@ class Cmd(cmd.Cmd): verinfo = ".".join(map(str, sys.version_info[:3])) num_transcripts = len(transcripts_expanded) plural = '' if len(transcripts_expanded) == 1 else 's' - self.poutput(ansi.style(utils.center_text(' cmd2 transcript test ', fill_char='='), bold=True)) + self.poutput(ansi.style(utils.align_center(' cmd2 transcript test ', fill_char='='), bold=True)) self.poutput('platform {} -- Python {}, cmd2-{}, readline-{}'.format(sys.platform, verinfo, cmd2.__version__, rl_type)) self.poutput('cwd: {}'.format(os.getcwd())) @@ -3734,7 +3739,7 @@ class Cmd(cmd.Cmd): if test_results.wasSuccessful(): ansi.ansi_aware_write(sys.stderr, stream.read()) finish_msg = ' {0} transcript{1} passed in {2:.3f} seconds '.format(num_transcripts, plural, execution_time) - finish_msg = ansi.style_success(utils.center_text(finish_msg, fill_char='=')) + finish_msg = ansi.style_success(utils.align_center(finish_msg, fill_char='=')) self.poutput(finish_msg) else: # Strip off the initial traceback which isn't particularly useful for end users diff --git a/cmd2/utils.py b/cmd2/utils.py index 4235db7d..9dd7a30b 100644 --- a/cmd2/utils.py +++ b/cmd2/utils.py @@ -637,21 +637,21 @@ class TextAlignment(Enum): RIGHT = 3 -def align_text(text: str, *, fill_char: str = ' ', width: Optional[int] = None, tab_width: int = 4, - alignment: TextAlignment) -> str: +def align_text(text: str, alignment: TextAlignment, *, fill_char: str = ' ', + width: Optional[int] = None, tab_width: int = 4) -> str: """ Align text for display within a given width. Supports characters with display widths greater than 1. ANSI escape sequences are safely ignored and do not count toward the display width. This means colored text is supported. If text has line breaks, then each line is aligned independently. - There are convenience wrappers around this function: ljustify_text(), center_text(), and rjustify_text() + There are convenience wrappers around this function: align_left(), align_center(), and align_right() - :param text: text to align (Can contain multiple lines) + :param text: text to align (can contain multiple lines) + :param alignment: how to align the text :param fill_char: character that fills the alignment gap. Defaults to space. (Cannot be a line breaking character) :param width: display width of the aligned text. Defaults to width of the terminal. :param tab_width: any tabs in the text will be replaced with this many spaces. if fill_char is a tab, then it will be converted to a space. - :param alignment: how to align the text :return: aligned text :raises: TypeError if fill_char is more than one character ValueError if text or fill_char contains an unprintable character @@ -725,32 +725,31 @@ def align_text(text: str, *, fill_char: str = ' ', width: Optional[int] = None, return text_buf.getvalue() -def ljustify_text(text: str, *, fill_char: str = ' ', width: Optional[int] = None, tab_width: int = 4) -> str: +def align_left(text: str, *, fill_char: str = ' ', width: Optional[int] = None, tab_width: int = 4) -> str: """ - Left justify text for display within a given width. Supports characters with display widths greater than 1. + Left align text for display within a given width. Supports characters with display widths greater than 1. ANSI escape sequences are safely ignored and do not count toward the display width. This means colored text is supported. If text has line breaks, then each line is aligned independently. - :param text: text to left justify (Can contain multiple lines) + :param text: text to left align (can contain multiple lines) :param fill_char: character that fills the alignment gap. Defaults to space. (Cannot be a line breaking character) :param width: display width of the aligned text. Defaults to width of the terminal. :param tab_width: any tabs in the text will be replaced with this many spaces. if fill_char is a tab, then it will be converted to a space. - :return: left-justified text + :return: left-aligned text :raises: TypeError if fill_char is more than one character ValueError if text or fill_char contains an unprintable character """ - return align_text(text, fill_char=fill_char, width=width, - tab_width=tab_width, alignment=TextAlignment.LEFT) + return align_text(text, TextAlignment.LEFT, fill_char=fill_char, width=width, tab_width=tab_width) -def center_text(text: str, *, fill_char: str = ' ', width: Optional[int] = None, tab_width: int = 4) -> str: +def align_center(text: str, *, fill_char: str = ' ', width: Optional[int] = None, tab_width: int = 4) -> str: """ Center text for display within a given width. Supports characters with display widths greater than 1. ANSI escape sequences are safely ignored and do not count toward the display width. This means colored text is supported. If text has line breaks, then each line is aligned independently. - :param text: text to center (Can contain multiple lines) + :param text: text to center (can contain multiple lines) :param fill_char: character that fills the alignment gap. Defaults to space. (Cannot be a line breaking character) :param width: display width of the aligned text. Defaults to width of the terminal. :param tab_width: any tabs in the text will be replaced with this many spaces. if fill_char is a tab, then it will @@ -759,24 +758,22 @@ def center_text(text: str, *, fill_char: str = ' ', width: Optional[int] = None, :raises: TypeError if fill_char is more than one character ValueError if text or fill_char contains an unprintable character """ - return align_text(text, fill_char=fill_char, width=width, - tab_width=tab_width, alignment=TextAlignment.CENTER) + return align_text(text, TextAlignment.CENTER, fill_char=fill_char, width=width, tab_width=tab_width) -def rjustify_text(text: str, *, fill_char: str = ' ', width: Optional[int] = None, tab_width: int = 4) -> str: +def align_right(text: str, *, fill_char: str = ' ', width: Optional[int] = None, tab_width: int = 4) -> str: """ - Right justify text for display within a given width. Supports characters with display widths greater than 1. + Right align text for display within a given width. Supports characters with display widths greater than 1. ANSI escape sequences are safely ignored and do not count toward the display width. This means colored text is supported. If text has line breaks, then each line is aligned independently. - :param text: text to right justify (Can contain multiple lines) + :param text: text to right align (can contain multiple lines) :param fill_char: character that fills the alignment gap. Defaults to space. (Cannot be a line breaking character) :param width: display width of the aligned text. Defaults to width of the terminal. :param tab_width: any tabs in the text will be replaced with this many spaces. if fill_char is a tab, then it will be converted to a space. - :return: right-justified text + :return: right-aligned text :raises: TypeError if fill_char is more than one character ValueError if text or fill_char contains an unprintable character """ - return align_text(text, fill_char=fill_char, width=width, - tab_width=tab_width, alignment=TextAlignment.RIGHT) + return align_text(text, TextAlignment.RIGHT, fill_char=fill_char, width=width, tab_width=tab_width) diff --git a/tests/test_utils.py b/tests/test_utils.py index 233b3b70..27b0e3bb 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -354,121 +354,121 @@ def test_align_text_term_width(): aligned = cu.align_text(text, fill_char=fill_char, alignment=cu.TextAlignment.LEFT) assert aligned == text + expected_fill -def test_left_text(): +def test_align_left(): text = 'foo' fill_char = '-' width = 5 - aligned = cu.ljustify_text(text, fill_char=fill_char, width=width) + aligned = cu.align_left(text, fill_char=fill_char, width=width) assert aligned == text + fill_char + fill_char -def test_left_text_multiline(): +def test_align_left_multiline(): text = "foo\nshoes" fill_char = '-' width = 7 - aligned = cu.ljustify_text(text, fill_char=fill_char, width=width) + aligned = cu.align_left(text, fill_char=fill_char, width=width) assert aligned == ('foo----\n' 'shoes--') -def test_left_wide_display_text(): +def test_align_left_wide_text(): text = '苹' fill_char = '-' width = 4 - aligned = cu.ljustify_text(text, fill_char=fill_char, width=width) + aligned = cu.align_left(text, fill_char=fill_char, width=width) assert aligned == text + fill_char + fill_char -def test_left_text_wide_display_fill(): +def test_align_left_wide_fill(): text = 'foo' fill_char = '苹' width = 5 - aligned = cu.ljustify_text(text, fill_char=fill_char, width=width) + aligned = cu.align_left(text, fill_char=fill_char, width=width) assert aligned == text + fill_char -def test_left_text_wide_display_fill_needs_padding(): +def test_align_left_wide_fill_needs_padding(): """Test when fill_char's display width does not divide evenly into gap""" text = 'foo' fill_char = '苹' width = 6 - aligned = cu.ljustify_text(text, fill_char=fill_char, width=width) + aligned = cu.align_left(text, fill_char=fill_char, width=width) assert aligned == text + fill_char + ' ' -def test_center_text(): +def test_align_center(): text = 'foo' fill_char = '-' width = 5 - aligned = cu.center_text(text,fill_char=fill_char, width=width) + aligned = cu.align_center(text, fill_char=fill_char, width=width) assert aligned == fill_char + text + fill_char -def test_center_text_multiline(): +def test_align_center_multiline(): text = "foo\nshoes" fill_char = '-' width = 7 - aligned = cu.center_text(text, fill_char=fill_char, width=width) + aligned = cu.align_center(text, fill_char=fill_char, width=width) assert aligned == ('--foo--\n' '-shoes-') -def test_center_wide_display_text(): +def test_align_center_wide_text(): text = '苹' fill_char = '-' width = 4 - aligned = cu.center_text(text, fill_char=fill_char, width=width) + aligned = cu.align_center(text, fill_char=fill_char, width=width) assert aligned == fill_char + text + fill_char -def test_center_text_wide_display_fill(): +def test_align_center_wide_fill(): text = 'foo' fill_char = '苹' width = 7 - aligned = cu.center_text(text, fill_char=fill_char, width=width) + aligned = cu.align_center(text, fill_char=fill_char, width=width) assert aligned == fill_char + text + fill_char -def test_center_text_wide_display_fill_needs_right_padding(): +def test_align_center_wide_fill_needs_right_padding(): """Test when fill_char's display width does not divide evenly into right gap""" text = 'foo' fill_char = '苹' width = 8 - aligned = cu.center_text(text, fill_char=fill_char, width=width) + aligned = cu.align_center(text, fill_char=fill_char, width=width) assert aligned == fill_char + text + fill_char + ' ' -def test_center_text_wide_display_fill_needs_left_and_right_padding(): +def test_align_center_wide_fill_needs_left_and_right_padding(): """Test when fill_char's display width does not divide evenly into either gap""" text = 'foo' fill_char = '苹' width = 9 - aligned = cu.center_text(text, fill_char=fill_char, width=width) + aligned = cu.align_center(text, fill_char=fill_char, width=width) assert aligned == fill_char + ' ' + text + fill_char + ' ' -def test_right_text(): +def test_align_right(): text = 'foo' fill_char = '-' width = 5 - aligned = cu.rjustify_text(text, fill_char=fill_char, width=width) + aligned = cu.align_right(text, fill_char=fill_char, width=width) assert aligned == fill_char + fill_char + text -def test_right_text_multiline(): +def test_align_right_multiline(): text = "foo\nshoes" fill_char = '-' width = 7 - aligned = cu.rjustify_text(text, fill_char=fill_char, width=width) + aligned = cu.align_right(text, fill_char=fill_char, width=width) assert aligned == ('----foo\n' '--shoes') -def test_right_wide_display_text(): +def test_align_right_wide_text(): text = '苹' fill_char = '-' width = 4 - aligned = cu.rjustify_text(text, fill_char=fill_char, width=width) + aligned = cu.align_right(text, fill_char=fill_char, width=width) assert aligned == fill_char + fill_char + text -def test_right_text_wide_display_fill(): +def test_align_right_wide_fill(): text = 'foo' fill_char = '苹' width = 5 - aligned = cu.rjustify_text(text, fill_char=fill_char, width=width) + aligned = cu.align_right(text, fill_char=fill_char, width=width) assert aligned == fill_char + text -def test_right_text_wide_display_fill_needs_padding(): +def test_align_right_wide_fill_needs_padding(): """Test when fill_char's display width does not divide evenly into gap""" text = 'foo' fill_char = '苹' width = 6 - aligned = cu.rjustify_text(text, fill_char=fill_char, width=width) + aligned = cu.align_right(text, fill_char=fill_char, width=width) assert aligned == fill_char + ' ' + text |