diff --git a/src/mudlib/render/ansi.py b/src/mudlib/render/ansi.py index 177faad..e423ce0 100644 --- a/src/mudlib/render/ansi.py +++ b/src/mudlib/render/ansi.py @@ -51,3 +51,63 @@ def colorize_map(grid: list[list[str]]) -> str: colored_row = "".join(colorize_terrain(char) for char in row) lines.append(colored_row) return "\n".join(lines) + + +def fg_256(n: int) -> str: + """Generate 256-color foreground escape code. + + Args: + n: Color index (0-255). Values outside range are clamped. + + Returns: + ANSI escape sequence for 256-color foreground. + """ + clamped = max(0, min(255, n)) + return f"\033[38;5;{clamped}m" + + +def bg_256(n: int) -> str: + """Generate 256-color background escape code. + + Args: + n: Color index (0-255). Values outside range are clamped. + + Returns: + ANSI escape sequence for 256-color background. + """ + clamped = max(0, min(255, n)) + return f"\033[48;5;{clamped}m" + + +def fg_rgb(r: int, g: int, b: int) -> str: + """Generate truecolor foreground escape code. + + Args: + r: Red component (0-255). Values outside range are clamped. + g: Green component (0-255). Values outside range are clamped. + b: Blue component (0-255). Values outside range are clamped. + + Returns: + ANSI escape sequence for truecolor foreground. + """ + r_clamped = max(0, min(255, r)) + g_clamped = max(0, min(255, g)) + b_clamped = max(0, min(255, b)) + return f"\033[38;2;{r_clamped};{g_clamped};{b_clamped}m" + + +def bg_rgb(r: int, g: int, b: int) -> str: + """Generate truecolor background escape code. + + Args: + r: Red component (0-255). Values outside range are clamped. + g: Green component (0-255). Values outside range are clamped. + b: Blue component (0-255). Values outside range are clamped. + + Returns: + ANSI escape sequence for truecolor background. + """ + r_clamped = max(0, min(255, r)) + g_clamped = max(0, min(255, g)) + b_clamped = max(0, min(255, b)) + return f"\033[48;2;{r_clamped};{g_clamped};{b_clamped}m" diff --git a/tests/test_ansi.py b/tests/test_ansi.py index 370d923..e1bee99 100644 --- a/tests/test_ansi.py +++ b/tests/test_ansi.py @@ -1,4 +1,12 @@ -from mudlib.render.ansi import RESET, colorize_map, colorize_terrain +from mudlib.render.ansi import ( + RESET, + bg_256, + bg_rgb, + colorize_map, + colorize_terrain, + fg_256, + fg_rgb, +) def test_colorize_terrain_grass(): @@ -45,3 +53,63 @@ def test_colorize_map(): # should have ANSI codes assert "\033[" in result + + +def test_fg_256_basic(): + """Generate 256-color foreground code.""" + assert fg_256(0) == "\033[38;5;0m" + assert fg_256(15) == "\033[38;5;15m" + assert fg_256(42) == "\033[38;5;42m" + assert fg_256(255) == "\033[38;5;255m" + + +def test_bg_256_basic(): + """Generate 256-color background code.""" + assert bg_256(0) == "\033[48;5;0m" + assert bg_256(15) == "\033[48;5;15m" + assert bg_256(42) == "\033[48;5;42m" + assert bg_256(255) == "\033[48;5;255m" + + +def test_fg_256_clamping(): + """Clamp 256-color values to valid range (0-255).""" + assert fg_256(-1) == "\033[38;5;0m" + assert fg_256(256) == "\033[38;5;255m" + assert fg_256(999) == "\033[38;5;255m" + + +def test_bg_256_clamping(): + """Clamp 256-color values to valid range (0-255).""" + assert bg_256(-1) == "\033[48;5;0m" + assert bg_256(256) == "\033[48;5;255m" + assert bg_256(999) == "\033[48;5;255m" + + +def test_fg_rgb_basic(): + """Generate truecolor foreground code.""" + assert fg_rgb(0, 0, 0) == "\033[38;2;0;0;0m" + assert fg_rgb(255, 255, 255) == "\033[38;2;255;255;255m" + assert fg_rgb(128, 64, 192) == "\033[38;2;128;64;192m" + + +def test_bg_rgb_basic(): + """Generate truecolor background code.""" + assert bg_rgb(0, 0, 0) == "\033[48;2;0;0;0m" + assert bg_rgb(255, 255, 255) == "\033[48;2;255;255;255m" + assert bg_rgb(128, 64, 192) == "\033[48;2;128;64;192m" + + +def test_fg_rgb_clamping(): + """Clamp RGB values to valid range (0-255).""" + assert fg_rgb(-1, 0, 0) == "\033[38;2;0;0;0m" + assert fg_rgb(0, 300, 0) == "\033[38;2;0;255;0m" + assert fg_rgb(0, 0, 999) == "\033[38;2;0;0;255m" + assert fg_rgb(-10, 300, 500) == "\033[38;2;0;255;255m" + + +def test_bg_rgb_clamping(): + """Clamp RGB values to valid range (0-255).""" + assert bg_rgb(-1, 0, 0) == "\033[48;2;0;0;0m" + assert bg_rgb(0, 300, 0) == "\033[48;2;0;255;0m" + assert bg_rgb(0, 0, 999) == "\033[48;2;0;0;255m" + assert bg_rgb(-10, 300, 500) == "\033[48;2;0;255;255m"