mud/src/mudlib/render/colors.py

116 lines
3.5 KiB
Python

"""Color markup engine for prompt templates."""
import re
from mudlib.render import ansi
# Tag to ANSI code mapping for 16-color mode
COLOR_TAGS_16 = {
"red": ansi.RED,
"green": ansi.GREEN,
"yellow": ansi.YELLOW,
"blue": ansi.BLUE,
"magenta": ansi.MAGENTA,
"cyan": ansi.CYAN,
"white": ansi.WHITE,
"black": ansi.BLACK,
"RED": "\033[91m",
"GREEN": "\033[92m",
"YELLOW": "\033[93m",
"BLUE": "\033[94m",
"MAGENTA": "\033[95m",
"CYAN": "\033[96m",
"WHITE": "\033[97m",
"BLACK": "\033[90m",
"bold": ansi.BOLD,
"dim": "\033[2m",
"/": ansi.RESET,
"reset": ansi.RESET,
}
# Tag to ANSI code mapping for 256-color mode
COLOR_TAGS_256 = {
"red": ansi.fg_256(196),
"green": ansi.fg_256(46),
"yellow": ansi.fg_256(226),
"blue": ansi.fg_256(33),
"magenta": ansi.fg_256(201),
"cyan": ansi.fg_256(51),
"white": ansi.fg_256(231),
"black": ansi.fg_256(16),
"RED": ansi.fg_256(9),
"GREEN": ansi.fg_256(10),
"YELLOW": ansi.fg_256(11),
"BLUE": ansi.fg_256(12),
"MAGENTA": ansi.fg_256(13),
"CYAN": ansi.fg_256(14),
"WHITE": ansi.fg_256(15),
"BLACK": ansi.fg_256(8),
"bold": ansi.BOLD,
"dim": "\033[2m",
"/": ansi.RESET,
"reset": ansi.RESET,
}
# Tag to ANSI code mapping for truecolor mode
COLOR_TAGS_TRUECOLOR = {
"red": ansi.fg_rgb(244, 67, 54),
"green": ansi.fg_rgb(76, 175, 80),
"yellow": ansi.fg_rgb(255, 235, 59),
"blue": ansi.fg_rgb(33, 150, 243),
"magenta": ansi.fg_rgb(156, 39, 176),
"cyan": ansi.fg_rgb(0, 188, 212),
"white": ansi.fg_rgb(255, 255, 255),
"black": ansi.fg_rgb(0, 0, 0),
"RED": ansi.fg_rgb(255, 82, 82),
"GREEN": ansi.fg_rgb(105, 240, 174),
"YELLOW": ansi.fg_rgb(255, 255, 130),
"BLUE": ansi.fg_rgb(68, 138, 255),
"MAGENTA": ansi.fg_rgb(224, 64, 251),
"CYAN": ansi.fg_rgb(0, 229, 255),
"WHITE": ansi.fg_rgb(255, 255, 255),
"BLACK": ansi.fg_rgb(96, 96, 96),
"bold": ansi.BOLD,
"dim": "\033[2m",
"/": ansi.RESET,
"reset": ansi.RESET,
}
def colorize(text: str, color_depth: str | None) -> str:
"""Convert color markup tags to ANSI codes based on client color depth.
Processes markup tags like {red}, {bold}, {/} in template strings and
converts them to ANSI escape codes. Unknown tags that don't match known
color tags are preserved (assumed to be template variables like {hp}).
Args:
text: String with color markup tags
color_depth: Color mode - "16", "256", "truecolor", or None/empty to strip
Returns:
Text with markup tags replaced by ANSI codes (or stripped if no color support)
"""
# If no color support, strip all known color tags
if not color_depth:
# Build pattern of all known tag names
known_tags = set(COLOR_TAGS_16.keys())
pattern = r"\{(" + "|".join(re.escape(tag) for tag in known_tags) + r")\}"
return re.sub(pattern, "", text)
# Select tag mapping based on color depth
if color_depth == "truecolor":
tag_map = COLOR_TAGS_TRUECOLOR
elif color_depth == "256":
tag_map = COLOR_TAGS_256
else: # default to 16-color
tag_map = COLOR_TAGS_16
# Replace known color tags with ANSI codes
def replace_tag(match):
return tag_map[match.group(1)]
# Pattern matches {tagname} where tagname is in our known tags
known_tags = "|".join(re.escape(tag) for tag in tag_map)
pattern = r"\{(" + known_tags + r")\}"
return re.sub(pattern, replace_tag, text)