"""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)