summaryrefslogtreecommitdiff
path: root/cmd2/ansi.py
diff options
context:
space:
mode:
Diffstat (limited to 'cmd2/ansi.py')
-rw-r--r--cmd2/ansi.py162
1 files changed, 102 insertions, 60 deletions
diff --git a/cmd2/ansi.py b/cmd2/ansi.py
index d3af525a..abe7b3dc 100644
--- a/cmd2/ansi.py
+++ b/cmd2/ansi.py
@@ -3,9 +3,10 @@
Support for ANSI escape sequences which are used for things like applying style to text,
setting the window title, and asynchronous alerts.
"""
+from enum import Enum, unique
import functools
import re
-from typing import Any, IO
+from typing import Any, IO, List, Union
import colorama
from colorama import Fore, Back, Style
@@ -25,57 +26,91 @@ allow_style = STYLE_TERMINAL
# Regular expression to match ANSI style sequences (including 8-bit and 24-bit colors)
ANSI_STYLE_RE = re.compile(r'\x1b\[[^m]*m')
-# Foreground color presets
-FG_COLORS = {
- 'black': Fore.BLACK,
- 'red': Fore.RED,
- 'green': Fore.GREEN,
- 'yellow': Fore.YELLOW,
- 'blue': Fore.BLUE,
- 'magenta': Fore.MAGENTA,
- 'cyan': Fore.CYAN,
- 'white': Fore.WHITE,
- 'bright_black': Fore.LIGHTBLACK_EX,
- 'bright_red': Fore.LIGHTRED_EX,
- 'bright_green': Fore.LIGHTGREEN_EX,
- 'bright_yellow': Fore.LIGHTYELLOW_EX,
- 'bright_blue': Fore.LIGHTBLUE_EX,
- 'bright_magenta': Fore.LIGHTMAGENTA_EX,
- 'bright_cyan': Fore.LIGHTCYAN_EX,
- 'bright_white': Fore.LIGHTWHITE_EX,
- 'reset': Fore.RESET,
-}
-
-# Background color presets
-BG_COLORS = {
- 'black': Back.BLACK,
- 'red': Back.RED,
- 'green': Back.GREEN,
- 'yellow': Back.YELLOW,
- 'blue': Back.BLUE,
- 'magenta': Back.MAGENTA,
- 'cyan': Back.CYAN,
- 'white': Back.WHITE,
- 'bright_black': Back.LIGHTBLACK_EX,
- 'bright_red': Back.LIGHTRED_EX,
- 'bright_green': Back.LIGHTGREEN_EX,
- 'bright_yellow': Back.LIGHTYELLOW_EX,
- 'bright_blue': Back.LIGHTBLUE_EX,
- 'bright_magenta': Back.LIGHTMAGENTA_EX,
- 'bright_cyan': Back.LIGHTCYAN_EX,
- 'bright_white': Back.LIGHTWHITE_EX,
- 'reset': Back.RESET,
-}
-
-FG_RESET = FG_COLORS['reset']
-BG_RESET = BG_COLORS['reset']
+
+# Foreground colors
+# noinspection PyPep8Naming,DuplicatedCode
+@unique
+class fg(Enum):
+ """Enum class for foreground colors (to support IDE autocompletion)."""
+ black = Fore.BLACK
+ red = Fore.RED
+ green = Fore.GREEN
+ yellow = Fore.YELLOW
+ blue = Fore.BLUE
+ magenta = Fore.MAGENTA
+ cyan = Fore.CYAN
+ white = Fore.WHITE
+ bright_black = Fore.LIGHTBLACK_EX
+ bright_red = Fore.LIGHTRED_EX
+ bright_green = Fore.LIGHTGREEN_EX
+ bright_yellow = Fore.LIGHTYELLOW_EX
+ bright_blue = Fore.LIGHTBLUE_EX
+ bright_magenta = Fore.LIGHTMAGENTA_EX
+ bright_cyan = Fore.LIGHTCYAN_EX
+ bright_white = Fore.LIGHTWHITE_EX
+ reset = Fore.RESET
+
+ def __str__(self) -> str:
+ """Make the value the string representation instead of the enum name."""
+ return self.value
+
+ @staticmethod
+ def colors() -> List[str]:
+ """Return a list of color names."""
+ return [color.name for color in fg]
+
+ @staticmethod
+ def get_value(name: str) -> str:
+ """Retrieve color code by name string."""
+ return fg.__members__[name].value
+
+
+# Background colors
+# noinspection PyPep8Naming,DuplicatedCode
+@unique
+class bg(Enum):
+ """Enum class for background colors (to support IDE autocompletion)."""
+ black = Back.BLACK
+ red = Back.RED
+ green = Back.GREEN
+ yellow = Back.YELLOW
+ blue = Back.BLUE
+ magenta = Back.MAGENTA
+ cyan = Back.CYAN
+ white = Back.WHITE
+ bright_black = Back.LIGHTBLACK_EX
+ bright_red = Back.LIGHTRED_EX
+ bright_green = Back.LIGHTGREEN_EX
+ bright_yellow = Back.LIGHTYELLOW_EX
+ bright_blue = Back.LIGHTBLUE_EX
+ bright_magenta = Back.LIGHTMAGENTA_EX
+ bright_cyan = Back.LIGHTCYAN_EX
+ bright_white = Back.LIGHTWHITE_EX
+ reset = Back.RESET
+
+ def __str__(self) -> str:
+ """Make the value the string representation instead of the enum name."""
+ return self.value
+
+ @staticmethod
+ def colors() -> List[str]:
+ """Return a list of color names."""
+ return [color.name for color in bg]
+
+ @staticmethod
+ def get_value(name: str) -> str:
+ """Retrieve color code by name string."""
+ return bg.__members__[name].value
+
+
+FG_RESET = fg.reset.value
+BG_RESET = bg.reset.value
RESET_ALL = Style.RESET_ALL
# Text intensities
INTENSITY_BRIGHT = Style.BRIGHT
INTENSITY_DIM = Style.DIM
INTENSITY_NORMAL = Style.NORMAL
-
# ANSI style sequences not provided by colorama
UNDERLINE_ENABLE = colorama.ansi.code_to_chars(4)
UNDERLINE_DISABLE = colorama.ansi.code_to_chars(24)
@@ -115,37 +150,44 @@ def style_aware_write(fileobj: IO, msg: str) -> None:
fileobj.write(msg)
-def fg_lookup(fg_name: str) -> str:
+def fg_lookup(fg_name: Union[str, fg]) -> str:
"""
Look up ANSI escape codes based on foreground color name.
- :param fg_name: foreground color name to look up ANSI escape code(s) for
+ :param fg_name: foreground color name or enum to look up ANSI escape code(s) for
:return: ANSI escape code(s) associated with this color
:raises ValueError: if the color cannot be found
"""
+ if isinstance(fg_name, fg):
+ return fg_name.value
+
try:
- ansi_escape = FG_COLORS[fg_name.lower()]
+ ansi_escape = fg.get_value(fg_name.lower())
except KeyError:
- raise ValueError('Foreground color {!r} does not exist.'.format(fg_name))
+ raise ValueError('Foreground color {!r} does not exist; must be one of: {}'.format(fg_name, fg.colors()))
return ansi_escape
-def bg_lookup(bg_name: str) -> str:
+def bg_lookup(bg_name: Union[str, bg]) -> str:
"""
Look up ANSI escape codes based on background color name.
- :param bg_name: background color name to look up ANSI escape code(s) for
+ :param bg_name: background color name or enum to look up ANSI escape code(s) for
:return: ANSI escape code(s) associated with this color
:raises ValueError: if the color cannot be found
"""
+ if isinstance(bg_name, bg):
+ return bg_name.value
+
try:
- ansi_escape = BG_COLORS[bg_name.lower()]
+ ansi_escape = bg.get_value(bg_name.lower())
except KeyError:
- raise ValueError('Background color {!r} does not exist.'.format(bg_name))
+ raise ValueError('Background color {!r} does not exist; must be one of: {}'.format(bg_name, bg.colors()))
return ansi_escape
-def style(text: Any, *, fg: str = '', bg: str = '', bold: bool = False,
+# noinspection PyShadowingNames
+def style(text: Any, *, fg: Union[str, fg] = '', bg: Union[str, bg] = '', bold: bool = False,
dim: bool = False, underline: bool = False) -> str:
"""
Apply ANSI colors and/or styles to a string and return it.
@@ -153,8 +195,8 @@ def style(text: Any, *, fg: str = '', bg: str = '', bold: bool = False,
to undo whatever styling was done at the beginning.
:param text: Any object compatible with str.format()
- :param fg: foreground color. Relies on `fg_lookup()` to retrieve ANSI escape based on name. Defaults to no color.
- :param bg: background color. Relies on `bg_lookup()` to retrieve ANSI escape based on name. Defaults to no color.
+ :param fg: foreground color. Relies on `fg_lookup()` to retrieve ANSI escape based on name or enum. Defaults to no color.
+ :param bg: background color. Relies on `bg_lookup()` to retrieve ANSI escape based on name or enum. Defaults to no color.
:param bold: apply the bold style if True. Can be combined with dim. Defaults to False.
:param dim: apply the dim style if True. Can be combined with bold. Defaults to False.
:param underline: apply the underline style if True. Defaults to False.
@@ -197,13 +239,13 @@ def style(text: Any, *, fg: str = '', bg: str = '', bold: bool = False,
# Default styles for printing strings of various types.
# These can be altered to suit an application's needs and only need to be a
# function with the following structure: func(str) -> str
-style_success = functools.partial(style, fg='green')
+style_success = functools.partial(style, fg=fg.green)
"""Partial function supplying arguments to :meth:`cmd2.ansi.style()` which colors text to signify success"""
-style_warning = functools.partial(style, fg='bright_yellow')
+style_warning = functools.partial(style, fg=fg.bright_yellow)
"""Partial function supplying arguments to :meth:`cmd2.ansi.style()` which colors text to signify a warning"""
-style_error = functools.partial(style, fg='bright_red')
+style_error = functools.partial(style, fg=fg.bright_red)
"""Partial function supplying arguments to :meth:`cmd2.ansi.style()` which colors text to signify an error"""