teddecor.TED.formatting
Colors
Colors must be RGB, Xterm index, predefined, or hex.
- RGB = 255,255,255 ...
[@F 255,255,255]
- Xterm = 0-255 ...
[@B 123]
- hex = #aaa or #aaaaaa ...
[@F #abc]
or[@B #abcabc]
- predefined = black, red, green, yellow, blue, magenta, cyan, and white ...
[@F green]
Function macros can be of types rainbow, gradient, esc, and repr
- rainbow takes a string and returns a rainbow formatted string
- gradient is more complex. It takes a comma seperated string with the format {color n}...,string.
- All but last value is the color value. Must have at least two colors which are hex.
- Finally, the last value is the string that the gradient will be applied too.
- esc takes a string and returns the literal value thus escaping the markup
- repr takes a given string and returns the literal value surrounded by
'
1"""Colors 2 3Colors must be RGB, Xterm index, predefined, or hex. 4 5* RGB = 255,255,255 ... `[@F 255,255,255]` 6* Xterm = 0-255 ... `[@B 123]` 7* hex = #aaa or #aaaaaa ... `[@F #abc]` or `[@B #abcabc]` 8* predefined = black, red, green, yellow, blue, magenta, cyan, and white ... `[@F green]` 9 10Function macros can be of types rainbow, gradient, esc, and repr 11 12* rainbow takes a string and returns a rainbow formatted string 13* gradient is more complex. It takes a comma seperated string with the format {color n}...,string. 14 * All but last value is the color value. Must have at least two colors which are hex. 15 * Finally, the last value is the string that the gradient will be applied too. 16* esc takes a string and returns the literal value thus escaping the markup 17* repr takes a given string and returns the literal value surrounded by `'` 18""" 19from __future__ import annotations 20from dataclasses import dataclass 21from typing import Callable, Union 22 23__all__ = [ 24 "UNDERLINE", 25 "BOLD", 26 "RESET", 27 "FUNC", 28 "build_color", 29] 30 31 32@dataclass 33class ColorType: 34 FG: int = 30 35 BG: int = 40 36 BOTH: list = (30, 40) 37 38 39FUNC = { 40 "rainbow": lambda string: __RAINBOW(string), 41 "repr": lambda string: repr(string), 42} 43 44PREDEFINED = { 45 "black": lambda c: f"{c + 0}", 46 "red": lambda c: f"{c + 1}", 47 "green": lambda c: f"{c + 2}", 48 "yellow": lambda c: f"{c + 3}", 49 "blue": lambda c: f"{c + 4}", 50 "magenta": lambda c: f"{c + 5}", 51 "cyan": lambda c: f"{c + 6}", 52 "white": lambda c: f"{c + 7}", 53} 54RGB = lambda c, r, g, b: f"{c + 8};2;{r};{g};{b}" 55XTERM = lambda c, v: f"{c + 8};5;{v}" 56RESETCOLOR = lambda ctype: f"{ctype + 9}" 57RESET = "\x1b[0m" 58 59 60def HEX(context: int, hex: str) -> str: 61 """Converts 3 or 6 digit hex into an rgb literal 62 63 Args: 64 context (int): Whether the hex is for the foreground or background 65 hex (str): The hex code 66 67 Raises: 68 ValueError: If the hex code is not in the valid format 69 70 Returns: 71 str: Ansi RGB color 72 """ 73 hex = hex.lstrip("#") 74 l = len(hex) 75 76 if l == 6: 77 r, g, b = tuple(int(hex[i : i + 2], 16) for i in (0, 2, 4)) 78 return RGB(context, r, g, b) 79 elif l == 3: 80 hex = "".join(h + h for h in hex) 81 r, g, b = tuple(int(hex[i : i + 2], 16) for i in (0, 2)) 82 return RGB(context, r, g, b) 83 84 raise ValueError(f"Expected hex with length of 3 or 6") 85 86 87@dataclass 88class BOLD: 89 """The bold value based on the current toggle value.""" 90 91 POP: int = 22 92 PUSH: int = 1 93 94 @staticmethod 95 def inverse(current: int) -> BOLD: 96 return BOLD.POP if current == BOLD.PUSH else BOLD.PUSH 97 98 99@dataclass 100class UNDERLINE: 101 """The bold value based on the current toggle value.""" 102 103 POP: int = 24 104 PUSH: int = 4 105 106 @staticmethod 107 def inverse(current: int): 108 return UNDERLINE.POP if current == UNDERLINE.PUSH else UNDERLINE.PUSH 109 110 111@dataclass 112class LINK: 113 CLOSE: str = "\x1b]8;;\x1b\\" 114 OPEN: str = lambda url: f"\x1b]8;;{url}\x1b\\" 115 116 117def get_color(types: Union[int, list[int]], content: str) -> Union[int, list[int]]: 118 """Parse and translate the color value from hex, xterm, rgb, and predefined color values. 119 120 Args: 121 types (Union[int, list[int]]): Tells what types to generate the color for. This include fg, bg, and both fg and bg. 122 content (str): The color string that is to be parsed 123 124 Returns: 125 Union[int, list[int]]: List of color code values according to the needed types 126 """ 127 from re import match 128 129 results = [] 130 content = content.lower() 131 for ctype in types: 132 if len(content) == 0: 133 results.append(RESETCOLOR(ctype)) 134 elif content.startswith("#"): 135 if len(content) == 4 and match(r"#[a-fA-F0-9]{3}", content): 136 results.append(HEX(ctype, content)) 137 elif len(content) == 7 and match(r"#[a-fA-F0-9]{6}", content): 138 results.append(HEX(ctype, content)) 139 elif match(r"\d{1,3}\s*[,;]\s*\d{1,3}\s*[,;]\s*\d{1,3}", content): 140 rgb = content.replace(";", ",").split(",") 141 results.append(RGB(ctype, rgb[0].strip(), rgb[1].strip(), rgb[2].strip())) 142 elif match(r"\d{1,3}", content): 143 results.append(XTERM(ctype, content)) 144 else: 145 if content in PREDEFINED: 146 results.append(PREDEFINED[content](ctype)) 147 else: 148 raise ValueError( 149 f"The color, \x1b[1;31m{content}\x1b[0m, does not match any valid format" 150 ) 151 152 return results 153 154 155def build_color(color: str) -> tuple[ColorType, str]: 156 """Takes a color macro and determines if it is type fg, bg, or both. 157 It will get the color string and produce color codes for each type that was specified. 158 159 Args: 160 color (str): The color macro to parse 161 162 Returns: 163 tuple[ColorType, str]: Tuple of the ColorType fg, bg, or both, along with the color codes 164 """ 165 color = color[1:] 166 ctype = ColorType.BOTH 167 content = color.strip() 168 169 if color.startswith(("F", "B")): 170 ctype = color[0] 171 content = color[1:].strip(" ") 172 if ctype == "F": 173 ctype = [ColorType.FG] 174 elif ctype == "B": 175 ctype = [ColorType.BG] 176 177 return ctype, get_color(ctype, content) 178 179 180def __RAINBOW(input: str) -> str: 181 """Take a string input and make each character rainbow 182 183 Args: 184 input (str): The string to make into a rainbow 185 186 Returns: 187 str: Rainbow string 188 """ 189 # red orange yellow green blue purple 190 context = 30 191 colors = [ 192 f"\x1b[{XTERM(context, 196)}m", 193 f"\x1b[{XTERM(context, 202)}m", 194 f"\x1b[{XTERM(context, 190)}m", 195 f"\x1b[{XTERM(context, 41)}m", 196 f"\x1b[{XTERM(context, 39)}m", 197 f"\x1b[{XTERM(context, 92)}m", 198 ] 199 200 out = [] 201 for i, char in enumerate(input): 202 out.append(colors[i % len(colors)] + char) 203 out.append("\x1b[39;49m") 204 205 return "".join(out)
@dataclass
class
UNDERLINE:
100@dataclass 101class UNDERLINE: 102 """The bold value based on the current toggle value.""" 103 104 POP: int = 24 105 PUSH: int = 4 106 107 @staticmethod 108 def inverse(current: int): 109 return UNDERLINE.POP if current == UNDERLINE.PUSH else UNDERLINE.PUSH
The bold value based on the current toggle value.
@dataclass
class
BOLD:
88@dataclass 89class BOLD: 90 """The bold value based on the current toggle value.""" 91 92 POP: int = 22 93 PUSH: int = 1 94 95 @staticmethod 96 def inverse(current: int) -> BOLD: 97 return BOLD.POP if current == BOLD.PUSH else BOLD.PUSH
The bold value based on the current toggle value.
RESET = '\x1b[0m'
FUNC = {'rainbow': <function <lambda>>, 'repr': <function <lambda>>}
def
build_color(color: str) -> tuple[teddecor.TED.formatting.ColorType, str]:
156def build_color(color: str) -> tuple[ColorType, str]: 157 """Takes a color macro and determines if it is type fg, bg, or both. 158 It will get the color string and produce color codes for each type that was specified. 159 160 Args: 161 color (str): The color macro to parse 162 163 Returns: 164 tuple[ColorType, str]: Tuple of the ColorType fg, bg, or both, along with the color codes 165 """ 166 color = color[1:] 167 ctype = ColorType.BOTH 168 content = color.strip() 169 170 if color.startswith(("F", "B")): 171 ctype = color[0] 172 content = color[1:].strip(" ") 173 if ctype == "F": 174 ctype = [ColorType.FG] 175 elif ctype == "B": 176 ctype = [ColorType.BG] 177 178 return ctype, get_color(ctype, content)
Takes a color macro and determines if it is type fg, bg, or both. It will get the color string and produce color codes for each type that was specified.
Args: color (str): The color macro to parse
Returns: tuple[ColorType, str]: Tuple of the ColorType fg, bg, or both, along with the color codes