diff options
-rw-r--r-- | cmd2/ansi.py | 51 | ||||
-rw-r--r-- | cmd2/cmd2.py | 7 | ||||
-rwxr-xr-x | examples/pirate.py | 2 | ||||
-rw-r--r-- | tests/test_cmd2.py | 4 | ||||
-rw-r--r-- | tests/test_utils.py | 6 |
5 files changed, 48 insertions, 22 deletions
diff --git a/cmd2/ansi.py b/cmd2/ansi.py index 5b3dff2c..f10c29ea 100644 --- a/cmd2/ansi.py +++ b/cmd2/ansi.py @@ -1,7 +1,7 @@ # coding=utf-8 """Support for ANSI escape codes which are used for things like applying style to text""" import re -from typing import Any +from typing import Any, Optional import colorama from colorama import Fore, Back, Style @@ -95,17 +95,32 @@ class TextStyle: # Default styles. These can be altered to suit an application's needs. -SuccessStyle = TextStyle(fg='green') +SuccessStyle = TextStyle(fg='green', bold=True) WarningStyle = TextStyle(fg='lightyellow') ErrorStyle = TextStyle(fg='lightred') -def style(text: Any, text_style: TextStyle) -> str: +def style(text: Any, text_style: Optional[TextStyle] = None, *, + fg: Optional[str] = None, bg: Optional[str] = None, + bold: Optional[bool] = None, underline: Optional[bool] = None) -> str: """ Applies a style to text :param text: Any object compatible with str.format() - :param text_style: the style to be applied + :param text_style: a TextStyle object. Defaults to None. + + The following are keyword-only parameters which allow calling style without creating a TextStyle object + style(text, fg='blue') + + They can also be used to override a setting in a provided TextStyle + style(text, ErrorStyle, underline=True) + + :param fg: foreground color. Expects color names in FG_COLORS (e.g. 'lightred'). Defaults to None. + :param bg: background color. Expects color names in BG_COLORS (e.g. 'black'). Defaults to None. + :param bold: apply the bold style if True. Defaults to None. + :param underline: apply the underline style if True. Defaults to None. + + :return: the stylized string """ # List of strings that add style additions = [] @@ -116,26 +131,38 @@ def style(text: Any, text_style: TextStyle) -> str: # Convert the text object into a string if it isn't already one text = "{}".format(text) - if text_style.fg: + # Figure out what parameters to use + if fg is None and text_style is not None: + fg = text_style.fg + if bg is None and text_style is not None: + bg = text_style.bg + if bold is None and text_style is not None: + bold = text_style.bold + if underline is None and text_style is not None: + underline = text_style.underline + + # Process the style settings + if fg: try: - additions.append(FG_COLORS[text_style.fg.lower()]) + additions.append(FG_COLORS[fg.lower()]) removals.append(FG_COLORS['reset']) except KeyError: - raise ValueError('Color {} does not exist.'.format(text_style.fg)) + raise ValueError('Color {} does not exist.'.format(fg)) - if text_style.bg: + if bg: try: - additions.append(BG_COLORS[text_style.bg.lower()]) + additions.append(BG_COLORS[bg.lower()]) removals.append(BG_COLORS['reset']) except KeyError: - raise ValueError('Color {} does not exist.'.format(text_style.bg)) + raise ValueError('Color {} does not exist.'.format(bg)) - if text_style.bold: + if bold: additions.append(Style.BRIGHT) removals.append(Style.NORMAL) - if text_style.underline: + if underline: additions.append(UNDERLINE_ENABLE) removals.append(UNDERLINE_DISABLE) + # Combine the ANSI escape strings with the text return "".join(additions) + text + "".join(removals) diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 0ea958b0..dbc540cd 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -3738,13 +3738,12 @@ 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', pad='='), ansi.TextStyle(bold=True))) + self.poutput(ansi.style(utils.center_text('cmd2 transcript test', pad='='), bold=True)) self.poutput('platform {} -- Python {}, cmd2-{}, readline-{}'.format(sys.platform, verinfo, cmd2.__version__, rl_type)) self.poutput('cwd: {}'.format(os.getcwd())) self.poutput('cmd2 app: {}'.format(sys.argv[0])) - self.poutput(ansi.style('collected {} transcript{}'.format(num_transcripts, plural), - ansi.TextStyle(bold=True))) + self.poutput(ansi.style('collected {} transcript{}'.format(num_transcripts, plural), bold=True)) self.__class__.testfiles = transcripts_expanded sys.argv = [sys.argv[0]] # the --test argument upsets unittest.main() @@ -3757,7 +3756,7 @@ class Cmd(cmd.Cmd): if test_results.wasSuccessful(): self._decolorized_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(utils.center_text(finish_msg, pad='='), ansi.TextStyle(fg="green", bold=True)) + finish_msg = ansi.style(utils.center_text(finish_msg, pad='='), ansi.SuccessStyle) self.poutput(finish_msg) else: # Strip off the initial traceback which isn't particularly useful for end users diff --git a/examples/pirate.py b/examples/pirate.py index fad6e2c9..eda3994e 100755 --- a/examples/pirate.py +++ b/examples/pirate.py @@ -70,7 +70,7 @@ class Pirate(cmd2.Cmd): def do_sing(self, arg): """Sing a colorful song.""" - self.poutput(cmd2.ansi.style(arg, cmd2.ansi.TextStyle(fg=self.songcolor))) + self.poutput(cmd2.ansi.style(arg, fg=self.songcolor)) yo_parser = argparse.ArgumentParser() yo_parser.add_argument('--ho', type=int, default=2, help="How often to chant 'ho'") diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index 80077a68..3b6089f4 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -1460,7 +1460,7 @@ def test_poutput_none(outsim_app): def test_poutput_color_always(outsim_app): msg = 'Hello World' outsim_app.colors = 'Always' - outsim_app.poutput(ansi.style(msg, ansi.TextStyle(fg='cyan'))) + outsim_app.poutput(ansi.style(msg, fg='cyan')) out = outsim_app.stdout.getvalue() expected = Fore.CYAN + msg + Fore.RESET + '\n' assert out == expected @@ -1468,7 +1468,7 @@ def test_poutput_color_always(outsim_app): def test_poutput_color_never(outsim_app): msg = 'Hello World' outsim_app.colors = 'Never' - outsim_app.poutput(ansi.style(msg, ansi.TextStyle(fg='cyan'))) + outsim_app.poutput(ansi.style(msg, fg='cyan')) out = outsim_app.stdout.getvalue() expected = msg + '\n' assert out == expected diff --git a/tests/test_utils.py b/tests/test_utils.py index 6e3600db..a4db3132 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -29,18 +29,18 @@ def test_ansi_safe_wcswidth(): def test_style(): base_str = HELLO_WORLD ansi_str = Fore.BLUE + Back.GREEN + base_str + Fore.RESET + Back.RESET - assert ansi.style(base_str, ansi.TextStyle(fg='blue', bg='green')) == ansi_str + assert ansi.style(base_str, fg='blue', bg='green') == ansi_str def test_style_color_not_exist(): base_str = HELLO_WORLD try: - ansi.style(base_str, ansi.TextStyle(fg='fake', bg='green')) + ansi.style(base_str, fg='fake', bg='green') assert False except ValueError: assert True try: - ansi.style(base_str, ansi.TextStyle(fg='blue', bg='fake')) + ansi.style(base_str, fg='blue', bg='fake') assert False except ValueError: assert True |