def _ansi_partial_color_format_main(template, style="default", cmap=None, hide=False): cmap = _ensure_color_map(style=style, cmap=cmap) esc = ("\001" if hide else "") + "\033[" m = "m" + ("\002" if hide else "") bopen = "{" bclose = "}" colon = ":" expl = "!" toks = [] for literal, field, spec, conv in FORMATTER.parse(template): toks.append(literal) if field is None: pass elif field in cmap: toks.extend([esc, cmap[field], m]) elif iscolor(field): color = ansi_color_name_to_escape_code(field, cmap=cmap) cmap[field] = color toks.extend([esc, color, m]) elif field is not None: toks.append(bopen) toks.append(field) if conv is not None and len(conv) > 0: toks.append(expl) toks.append(conv) if spec is not None and len(spec) > 0: toks.append(colon) toks.append(spec) toks.append(bclose) return "".join(toks)
def _ansi_partial_color_format_main(template, style="default", cmap=None, hide=False): cmap = _ensure_color_map(style=style, cmap=cmap) esc = ("\001" if hide else "") + "\033[" m = "m" + ("\002" if hide else "") bopen = "{" bclose = "}" colon = ":" expl = "!" toks = [] for literal, field, spec, conv in FORMATTER.parse(template): toks.append(literal) if field is None: pass elif field in cmap: toks.extend([esc, cmap[field], m]) elif iscolor(field): color = ansi_color_name_to_escape_code(field, cmap=cmap) cmap[field] = color toks.extend([esc, color, m]) elif field is not None: toks.append(bopen) toks.append(field) if conv is not None and len(conv) > 0: toks.append(expl) toks.append(conv) if spec is not None and len(spec) > 0: toks.append(colon) toks.append(spec) toks.append(bclose) return "".join(toks)
def _partial_color_tokenize_main(template, styles): bopen = "{" bclose = "}" colon = ":" expl = "!" color = Color.DEFAULT fg = bg = None value = "" toks = [] for literal, field, spec, conv in FORMATTER.parse(template): if field is None: value += literal elif iscolor(field): value += literal next_color, fg, bg = color_by_name(field, fg, bg) if next_color is not color: if len(value) > 0: toks.append((color, value)) if styles is not None: styles[color] # ensure color is available color = next_color value = "" elif field is not None: parts = [literal, bopen, field] if conv is not None and len(conv) > 0: parts.append(expl) parts.append(conv) if spec is not None and len(spec) > 0: parts.append(colon) parts.append(spec) parts.append(bclose) value += "".join(parts) else: value += literal toks.append((color, value)) return toks, color
def _partial_color_tokenize_main(template, styles): bopen = "{" bclose = "}" colon = ":" expl = "!" color = Color.NO_COLOR fg = bg = None value = "" toks = [] for literal, field, spec, conv in FORMATTER.parse(template): if field is None: value += literal elif iscolor(field): value += literal next_color, fg, bg = color_by_name(field, fg, bg) if next_color is not color: if len(value) > 0: toks.append((color, value)) if styles is not None: styles[color] # ensure color is available color = next_color value = "" elif field is not None: parts = [literal, bopen, field] if conv is not None and len(conv) > 0: parts.append(expl) parts.append(conv) if spec is not None and len(spec) > 0: parts.append(colon) parts.append(spec) parts.append(bclose) value += "".join(parts) else: value += literal toks.append((color, value)) return toks, color
def ansi_color_escape_code_to_name(escape_code, style, reversed_style=None): """Converts an ANSI color code escape sequence to a tuple of color names in the provided style ('default' should almost be the style). For example, '0' becomes ('RESET',) and '32;41' becomes ('GREEN', 'BACKGROUND_RED'). The style keyword may either be a string, in which the style is looked up, or an actual style dict. You can also provide a reversed style mapping, too, which is just the keys/values of the style dict swapped. If reversed style is not provided, it is computed. """ key = (escape_code, style) # todo: see the cache ever used? if key in _ANSI_COLOR_ESCAPE_CODE_TO_NAME_CACHE: return _ANSI_COLOR_ESCAPE_CODE_TO_NAME_CACHE[key] if reversed_style is None: style, reversed_style = ansi_reverse_style(style, return_style=True) # strip some actual escape codes, if needed. match = ANSI_ESCAPE_CODE_RE.match(escape_code) if not match: msg = 'Invalid ANSI color sequence "{0}", using "RESET" instead.'.format( escape_code) warnings.warn(msg, RuntimeWarning) return ("RESET", ) ec = match.group(2) names = [] n_ints = 0 seen_set_foreback = False for e in ec.split(";"): no_left_zero = e.lstrip("0") if len(e) > 1 else e if seen_set_foreback and n_ints > 0: names.append(e) n_ints -= 1 if n_ints == 0: seen_set_foreback = False continue else: names.append(reversed_style.get(no_left_zero, no_left_zero)) # set the flags for next time if "38" == e or "48" == e: seen_set_foreback = True elif seen_set_foreback and "2" == e: n_ints = 3 elif seen_set_foreback and "5" == e: n_ints = 1 # normalize names n = "" norm_names = [] prefixes = "" for name in names: if name in ("RESET", "NO_COLOR"): # skip most '0' entries continue elif "BACKGROUND_" in name and n: prefixes += n n = "" n = n + name if n else name if n.endswith("_"): continue elif ANSI_COLOR_NAME_SET_SHORT_RE.match(n) is not None: pre, fore_back, short = ANSI_COLOR_NAME_SET_SHORT_RE.match( n).groups() n = _color_name_from_ints(short_to_ints(short), background=(fore_back == "BACK"), prefix=pre) elif ANSI_COLOR_NAME_SET_3INTS_RE.match(n) is not None: pre, fore_back, r, g, b = ANSI_COLOR_NAME_SET_3INTS_RE.match( n).groups() n = _color_name_from_ints((int(r), int(g), int(b)), background=(fore_back == "BACK"), prefix=pre) elif "GROUND_FAINT_" in n: # have 1 or 2, but not 3 ints n += "_" continue # error check if not iscolor(n): msg = ( "Could not translate ANSI color code {escape_code!r} " "into a known color in the palette. Specifically, the {n!r} " "portion of {name!r} in {names!r} seems to missing.") raise ValueError( msg.format(escape_code=escape_code, names=names, name=name, n=n)) norm_names.append(n) n = "" # check if we have pre- & post-fixes to apply to the last, non-background element prefixes += n if prefixes.endswith("_"): for i in range(-1, -len(norm_names) - 1, -1): if "BACKGROUND_" not in norm_names[i]: norm_names[i] = prefixes + norm_names[i] break else: # only have background colors, so select WHITE as default color norm_names.append(prefixes + "WHITE") # return if len(norm_names) == 0: return ("RESET", ) else: return tuple(norm_names)
def test_iscolor(inp, exp): obs = iscolor(inp) if exp: assert obs else: assert not obs
def ansi_color_escape_code_to_name(escape_code, style, reversed_style=None): """Converts an ASNI color code escape sequence to a tuple of color names in the provided style ('default' should almost be the style). For example, '0' becomes ('NO_COLOR',) and '32;41' becomes ('GREEN', 'BACKGROUND_RED'). The style keyword may either be a string, in which the style is looked up, or an actual style dict. You can also provide a reversed style mapping, too, which is just the keys/values of the style dict swapped. If reversed style is not provided, it is computed. """ key = (escape_code, style) if key in _ANSI_COLOR_ESCAPE_CODE_TO_NAME_CACHE: return _ANSI_COLOR_ESCAPE_CODE_TO_NAME_CACHE[key] if reversed_style is None: style, reversed_style = ansi_reverse_style(style, return_style=True) # strip some actual escape codes, if needed. ec = ANSI_ESCAPE_CODE_RE.match(escape_code).group(2) names = [] n_ints = 0 seen_set_foreback = False for e in ec.split(";"): no_left_zero = e.lstrip("0") if len(e) > 1 else e if seen_set_foreback and n_ints > 0: names.append(e) n_ints -= 1 if n_ints == 0: seen_set_foreback = False continue else: names.append(reversed_style.get(no_left_zero, no_left_zero)) # set the flags for next time if "38" == e or "48" == e: seen_set_foreback = True elif "2" == e: n_ints = 3 elif "5" == e: n_ints = 1 # normalize names n = "" norm_names = [] prefixes = "" for name in names: if name == "NO_COLOR": # skip most '0' entries continue elif "BACKGROUND_" in name and n: prefixes += n n = "" n = n + name if n else name if n.endswith("_"): continue elif ANSI_COLOR_NAME_SET_SHORT_RE.match(n) is not None: pre, fore_back, short = ANSI_COLOR_NAME_SET_SHORT_RE.match(n).groups() n = _color_name_from_ints( short_to_ints(short), background=(fore_back == "BACK"), prefix=pre ) elif ANSI_COLOR_NAME_SET_3INTS_RE.match(n) is not None: pre, fore_back, r, g, b = ANSI_COLOR_NAME_SET_3INTS_RE.match(n).groups() n = _color_name_from_ints( (int(r), int(g), int(b)), background=(fore_back == "BACK"), prefix=pre ) elif "GROUND_FAINT_" in n: # have 1 or 2, but not 3 ints n += "_" continue # error check if not iscolor(n): msg = ( "Could not translate ANSI color code {escape_code!r} " "into a known color in the palette. Specifically, the {n!r} " "portion of {name!r} in {names!r} seems to missing." ) raise ValueError( msg.format(escape_code=escape_code, names=names, name=name, n=n) ) norm_names.append(n) n = "" # check if we have pre- & post-fixes to apply to the last, non-background element prefixes += n if prefixes.endswith("_"): for i in range(-1, -len(norm_names) - 1, -1): if "BACKGROUND_" not in norm_names[i]: norm_names[i] = prefixes + norm_names[i] break else: # only have background colors, so select WHITE as default color norm_names.append(prefixes + "WHITE") # return if len(norm_names) == 0: return ("NO_COLOR",) else: return tuple(norm_names)