summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Leonhardt <todd.leonhardt@gmail.com>2020-02-06 21:28:06 -0500
committerTodd Leonhardt <todd.leonhardt@gmail.com>2020-02-06 21:28:06 -0500
commitede9f3e77a59281a442227ed9b4b92e62e85d2b9 (patch)
treeb87239799cf71c67704d3ffe7bc0879d57056d3e
parentc7ac2e965d025806ce5baddfc718814e3e58d639 (diff)
downloadcmd2-git-ede9f3e77a59281a442227ed9b4b92e62e85d2b9.tar.gz
Added convenience `ansi.fg` and `ansi.bg` enums of foreground and background colors which style() can now optionally use
This is to make it easier to autocomplete color names in an IDE
-rw-r--r--CHANGELOG.md4
-rw-r--r--cmd2/__init__.py2
-rw-r--r--cmd2/ansi.py84
-rwxr-xr-xexamples/basic.py4
-rw-r--r--tests/test_ansi.py14
5 files changed, 93 insertions, 15 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 77ba6b00..07225efc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,10 @@
* Enhancements
* Changed the default help text to make `help -v` more discoverable
* Added `add_settable()` and `remove_settable()` convenience methods to update `self.settable` dictionary
+ * Added convenience `ansi.fg` and `ansi.bg` enums of foreground and background colors
+ * `ansi.style()` `fg` argument can now either be of type `str` or `ansi.fg`
+ * `ansi.style()` `bg` argument can now either be of type `str` or `ansi.bg`
+ * This supports IDE auto-completion of color names
* Breaking changes
* Renamed `locals_in_py` attribute of `cmd2.Cmd` to `self_in_py`
* The following public attributes of `cmd2.Cmd` are no longer settable at runtime by default:
diff --git a/cmd2/__init__.py b/cmd2/__init__.py
index cc5a0963..43578e46 100644
--- a/cmd2/__init__.py
+++ b/cmd2/__init__.py
@@ -10,7 +10,7 @@ except DistributionNotFound:
# package is not installed
pass
-from .ansi import style
+from .ansi import style, fg, bg
from .argparse_custom import Cmd2ArgumentParser, CompletionError, CompletionItem, set_default_argument_parser
# Check if user has defined a module that sets a custom value for argparse_custom.DEFAULT_ARGUMENT_PARSER
diff --git a/cmd2/ansi.py b/cmd2/ansi.py
index d3af525a..39175d3f 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, Union
import colorama
from colorama import Fore, Back, Style
@@ -46,6 +47,33 @@ FG_COLORS = {
'reset': Fore.RESET,
}
+
+@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):
+ """Make the value the string representation instead of the enum name."""
+ return self.value
+
+
# Background color presets
BG_COLORS = {
'black': Back.BLACK,
@@ -67,6 +95,33 @@ BG_COLORS = {
'reset': Back.RESET,
}
+
+@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):
+ """Make the value the string representation instead of the enum name."""
+ return self.value
+
+
FG_RESET = FG_COLORS['reset']
BG_RESET = BG_COLORS['reset']
RESET_ALL = Style.RESET_ALL
@@ -75,7 +130,6 @@ RESET_ALL = Style.RESET_ALL
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,14 +169,17 @@ 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()]
except KeyError:
@@ -130,14 +187,17 @@ def fg_lookup(fg_name: str) -> str:
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()]
except KeyError:
@@ -145,7 +205,7 @@ def bg_lookup(bg_name: str) -> str:
return ansi_escape
-def style(text: Any, *, fg: str = '', bg: str = '', bold: bool = False,
+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 +213,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 +257,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"""
diff --git a/examples/basic.py b/examples/basic.py
index 37db6501..5df3d1b5 100755
--- a/examples/basic.py
+++ b/examples/basic.py
@@ -9,7 +9,7 @@
6) Shell-like capabilities
"""
import cmd2
-from cmd2 import style
+from cmd2 import style, fg, bg
class BasicApp(cmd2.Cmd):
@@ -19,7 +19,7 @@ class BasicApp(cmd2.Cmd):
super().__init__(multiline_commands=['echo'], persistent_history_file='cmd2_history.dat',
startup_script='scripts/startup.txt', use_ipython=True)
- self.intro = style('Welcome to PyOhio 2019 and cmd2!', fg='red', bg='white', bold=True) + ' 😀'
+ self.intro = style('Welcome to PyOhio 2019 and cmd2!', fg=fg.red, bg=bg.white, bold=True) + ' 😀'
# Allow access to your application in py and ipy via self
self.self_in_py = True
diff --git a/tests/test_ansi.py b/tests/test_ansi.py
index cb68cb28..f711fc1a 100644
--- a/tests/test_ansi.py
+++ b/tests/test_ansi.py
@@ -119,3 +119,17 @@ def test_async_alert_str(cols, prompt, line, cursor, msg, expected):
alert_str = ansi.async_alert_str(terminal_columns=cols, prompt=prompt, line=line, cursor_offset=cursor,
alert_msg=msg)
assert alert_str == expected
+
+
+def test_fg_enum():
+ assert ansi.fg_lookup('bright_red') == ansi.fg_lookup(ansi.fg.bright_red)
+
+def test_fg_enum_to_str():
+ assert str(ansi.fg.black) == ansi.fg_lookup('black')
+
+def test_bg_enum():
+ assert ansi.bg_lookup('green') == ansi.bg_lookup(ansi.bg.green)
+
+def test_bg_enum_to_str():
+ assert str(ansi.bg.blue) == ansi.bg_lookup('blue')
+