diff --git a/docs/source/configure.rst b/docs/source/configure.rst index 67a3ccd5..58052f34 100644 --- a/docs/source/configure.rst +++ b/docs/source/configure.rst @@ -28,7 +28,8 @@ Color and displayname --------------------- - You can set a color for each task list by creating a ``color`` file containing - a color code in the hex format: ``#RRGGBB``. + either a named ANSI color (such as ``red``, ``bright blue``, etc) or a color + code in hex format: ``#RRGGBB`` (the latter requires 24-bit color support). - A file named ``displayname`` indicates how the task list should be named and is needed when there are multiple directories sharing a name, e.g.: when using multiple $CloudInstances. The default is the directory name. diff --git a/tests/test_formatter.py b/tests/test_formatter.py index ed1ea254..b45ecf19 100644 --- a/tests/test_formatter.py +++ b/tests/test_formatter.py @@ -9,7 +9,7 @@ from tests.helpers import pyicu_sensitive from todoman.cli import cli -from todoman.formatters import rgb_to_ansi +from todoman.formatters import colour_to_ansi @pyicu_sensitive @@ -155,12 +155,14 @@ def test_formatting_parsing_consitency(default_formatter): assert default_formatter.parse_datetime(formatted) == dt -def test_rgb_to_ansi(): - assert rgb_to_ansi(None) is None - assert rgb_to_ansi("#8ab6d") is None - assert rgb_to_ansi("#8ab6d2f") == "\x1b[38;2;138;182;210m" - assert rgb_to_ansi("red") is None - assert rgb_to_ansi("#8ab6d2") == "\x1b[38;2;138;182;210m" +def test_colour_to_ansi(): + assert colour_to_ansi(None) is None + assert colour_to_ansi("#8ab6d") is None + assert colour_to_ansi("#8ab6d2f") == "\x1b[38;2;138;182;210m" + assert colour_to_ansi("#8ab6d2") == "\x1b[38;2;138;182;210m" + assert colour_to_ansi("red") == "\x1b[31m" + assert colour_to_ansi("bright cyan") == "\x1b[36;1m" + assert colour_to_ansi("salmon") is None def test_format_multiple_with_list(default_formatter, todo_factory): diff --git a/todoman/formatters.py b/todoman/formatters.py index 0dc187c3..dc9aa9d4 100644 --- a/todoman/formatters.py +++ b/todoman/formatters.py @@ -19,12 +19,10 @@ from todoman.model import TodoList -def rgb_to_ansi(colour: Optional[str]) -> Optional[str]: +def rgb_to_ansi(colour: str) -> Optional[str]: """ Convert a string containing an RGB colour to ANSI escapes """ - if not colour or not colour.startswith("#"): - return None r, g, b = colour[1:3], colour[3:5], colour[5:7] @@ -34,6 +32,30 @@ def rgb_to_ansi(colour: Optional[str]) -> Optional[str]: return f"\33[38;2;{int(r, 16)!s};{int(g, 16)!s};{int(b, 16)!s}m" +def colour_to_ansi(colour: Optional[str]) -> Optional[str]: + """ + Convert a string containing a colour (either RGB or a standard colour name) + """ + if not colour: + return None + if colour.startswith("#"): + return rgb_to_ansi(colour) + + bright = "bright" in colour + + colour = colour.replace("bright ", "") + + colours = ["black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"] + + try: + ansi_number = colours.index(colour) + except ValueError: + return None + + suffix = ";1" if bright else "" + return f"\33[3{ansi_number}{suffix}m" + + class DefaultFormatter: def __init__( self, @@ -227,7 +249,7 @@ def _parse_datetime_naive(self, dt: str) -> date: def format_database(self, database: TodoList): return "{}@{}".format( - rgb_to_ansi(database.colour) or "", click.style(database.name) + colour_to_ansi(database.colour) or "", click.style(database.name) )