diff --git a/.gitignore b/.gitignore index 894a44cc..fddc0135 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.DS_Store + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 2a7b387a..00000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 Will McGugan - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..85e6ff19 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# WIP diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..a1fa85fd --- /dev/null +++ b/poetry.lock @@ -0,0 +1,7 @@ +package = [] + +[metadata] +content-hash = "fafb334cb038533f851c23d0b63254223abf72ce4f02987e7064b0c95566699a" +python-versions = "^3.8" + +[metadata.hashes] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..8f59cf36 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,15 @@ +[tool.poetry] +name = "rich" +version = "0.1.0" +description = "Rich Console" +authors = ["Will McGugan "] +license = "MIT" + +[tool.poetry.dependencies] +python = "^3.8" + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry>=0.12"] +build-backend = "poetry.masonry.api" diff --git a/rich/__init__.py b/rich/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rich/_version.py b/rich/_version.py new file mode 100644 index 00000000..16ef924a --- /dev/null +++ b/rich/_version.py @@ -0,0 +1 @@ +VERSION = "0.0.1a" diff --git a/rich/color.py b/rich/color.py new file mode 100644 index 00000000..420d17c3 --- /dev/null +++ b/rich/color.py @@ -0,0 +1,490 @@ +from __future__ import annotations + +import re +from dataclasses import dataclass +from enum import IntEnum +from functools import lru_cache +from math import sqrt +from typing import Iterable, List, NamedTuple, Tuple, Optional + + +STANDARD_COLORS_NAMES = { + "black": 0, + "red": 1, + "green": 2, + "yellow": 3, + "blue": 4, + "magenta": 5, + "cyan": 6, + "white": 7, +} + +STANDARD_PALLETTE = ( + (0, 0, 0), + (255, 0, 0), + (0, 255, 0), + (255, 255, 0), + (0, 0, 255), + (255, 0, 255), + (0, 255, 255), + (255, 255, 255), +) + +EIGHT_BIT_COLORS = { + 0: (0, 0, 0), + 1: (128, 0, 0), + 2: (0, 128, 0), + 3: (128, 128, 0), + 4: (0, 0, 128), + 5: (128, 0, 128), + 6: (0, 128, 128), + 7: (192, 192, 192), + 8: (128, 128, 128), + 9: (255, 0, 0), + 10: (0, 255, 0), + 11: (255, 255, 0), + 12: (0, 0, 255), + 13: (255, 0, 255), + 14: (0, 255, 255), + 15: (255, 255, 255), + 16: (0, 0, 0), + 17: (0, 0, 95), + 18: (0, 0, 135), + 19: (0, 0, 175), + 20: (0, 0, 215), + 21: (0, 0, 255), + 22: (0, 95, 0), + 23: (0, 95, 95), + 24: (0, 95, 135), + 25: (0, 95, 175), + 26: (0, 95, 215), + 27: (0, 95, 255), + 28: (0, 135, 0), + 29: (0, 135, 95), + 30: (0, 135, 135), + 31: (0, 135, 175), + 32: (0, 135, 215), + 33: (0, 135, 255), + 34: (0, 175, 0), + 35: (0, 175, 95), + 36: (0, 175, 135), + 37: (0, 175, 175), + 38: (0, 175, 215), + 39: (0, 175, 255), + 40: (0, 215, 0), + 41: (0, 215, 95), + 42: (0, 215, 135), + 43: (0, 215, 175), + 44: (0, 215, 215), + 45: (0, 215, 255), + 46: (0, 255, 0), + 47: (0, 255, 95), + 48: (0, 255, 135), + 49: (0, 255, 175), + 50: (0, 255, 215), + 51: (0, 255, 255), + 52: (95, 0, 0), + 53: (95, 0, 95), + 54: (95, 0, 135), + 55: (95, 0, 175), + 56: (95, 0, 215), + 57: (95, 0, 255), + 58: (95, 95, 0), + 59: (95, 95, 95), + 60: (95, 95, 135), + 61: (95, 95, 175), + 62: (95, 95, 215), + 63: (95, 95, 255), + 64: (95, 135, 0), + 65: (95, 135, 95), + 66: (95, 135, 135), + 67: (95, 135, 175), + 68: (95, 135, 215), + 69: (95, 135, 255), + 70: (95, 175, 0), + 71: (95, 175, 95), + 72: (95, 175, 135), + 73: (95, 175, 175), + 74: (95, 175, 215), + 75: (95, 175, 255), + 76: (95, 215, 0), + 77: (95, 215, 95), + 78: (95, 215, 135), + 79: (95, 215, 175), + 80: (95, 215, 215), + 81: (95, 215, 255), + 82: (95, 255, 0), + 83: (95, 255, 95), + 84: (95, 255, 135), + 85: (95, 255, 175), + 86: (95, 255, 215), + 87: (95, 255, 255), + 88: (135, 0, 0), + 89: (135, 0, 95), + 90: (135, 0, 135), + 91: (135, 0, 175), + 92: (135, 0, 215), + 93: (135, 0, 255), + 94: (135, 95, 0), + 95: (135, 95, 95), + 96: (135, 95, 135), + 97: (135, 95, 175), + 98: (135, 95, 215), + 99: (135, 95, 255), + 100: (135, 135, 0), + 101: (135, 135, 95), + 102: (135, 135, 135), + 103: (135, 135, 175), + 104: (135, 135, 215), + 105: (135, 135, 255), + 106: (135, 175, 0), + 107: (135, 175, 95), + 108: (135, 175, 135), + 109: (135, 175, 175), + 110: (135, 175, 215), + 111: (135, 175, 255), + 112: (135, 215, 0), + 113: (135, 215, 95), + 114: (135, 215, 135), + 115: (135, 215, 175), + 116: (135, 215, 215), + 117: (135, 215, 255), + 118: (135, 255, 0), + 119: (135, 255, 95), + 120: (135, 255, 135), + 121: (135, 255, 175), + 122: (135, 255, 215), + 123: (135, 255, 255), + 124: (175, 0, 0), + 125: (175, 0, 95), + 126: (175, 0, 135), + 127: (175, 0, 175), + 128: (175, 0, 215), + 129: (175, 0, 255), + 130: (175, 95, 0), + 131: (175, 95, 95), + 132: (175, 95, 135), + 133: (175, 95, 175), + 134: (175, 95, 215), + 135: (175, 95, 255), + 136: (175, 135, 0), + 137: (175, 135, 95), + 138: (175, 135, 135), + 139: (175, 135, 175), + 140: (175, 135, 215), + 141: (175, 135, 255), + 142: (175, 175, 0), + 143: (175, 175, 95), + 144: (175, 175, 135), + 145: (175, 175, 175), + 146: (175, 175, 215), + 147: (175, 175, 255), + 148: (175, 215, 0), + 149: (175, 215, 95), + 150: (175, 215, 135), + 151: (175, 215, 175), + 152: (175, 215, 215), + 153: (175, 215, 255), + 154: (175, 255, 0), + 155: (175, 255, 95), + 156: (175, 255, 135), + 157: (175, 255, 175), + 158: (175, 255, 215), + 159: (175, 255, 255), + 160: (215, 0, 0), + 161: (215, 0, 95), + 162: (215, 0, 135), + 163: (215, 0, 175), + 164: (215, 0, 215), + 165: (215, 0, 255), + 166: (215, 95, 0), + 167: (215, 95, 95), + 168: (215, 95, 135), + 169: (215, 95, 175), + 170: (215, 95, 215), + 171: (215, 95, 255), + 172: (215, 135, 0), + 173: (215, 135, 95), + 174: (215, 135, 135), + 175: (215, 135, 175), + 176: (215, 135, 215), + 177: (215, 135, 255), + 178: (215, 175, 0), + 179: (215, 175, 95), + 180: (215, 175, 135), + 181: (215, 175, 175), + 182: (215, 175, 215), + 183: (215, 175, 255), + 184: (215, 215, 0), + 185: (215, 215, 95), + 186: (215, 215, 135), + 187: (215, 215, 175), + 188: (215, 215, 215), + 189: (215, 215, 255), + 190: (215, 255, 0), + 191: (215, 255, 95), + 192: (215, 255, 135), + 193: (215, 255, 175), + 194: (215, 255, 215), + 195: (215, 255, 255), + 196: (255, 0, 0), + 197: (255, 0, 95), + 198: (255, 0, 135), + 199: (255, 0, 175), + 200: (255, 0, 215), + 201: (255, 0, 255), + 202: (255, 95, 0), + 203: (255, 95, 95), + 204: (255, 95, 135), + 205: (255, 95, 175), + 206: (255, 95, 215), + 207: (255, 95, 255), + 208: (255, 135, 0), + 209: (255, 135, 95), + 210: (255, 135, 135), + 211: (255, 135, 175), + 212: (255, 135, 215), + 213: (255, 135, 255), + 214: (255, 175, 0), + 215: (255, 175, 95), + 216: (255, 175, 135), + 217: (255, 175, 175), + 218: (255, 175, 215), + 219: (255, 175, 255), + 220: (255, 215, 0), + 221: (255, 215, 95), + 222: (255, 215, 135), + 223: (255, 215, 175), + 224: (255, 215, 215), + 225: (255, 215, 255), + 226: (255, 255, 0), + 227: (255, 255, 95), + 228: (255, 255, 135), + 229: (255, 255, 175), + 230: (255, 255, 215), + 231: (255, 255, 255), + 232: (8, 8, 8), + 233: (18, 18, 18), + 234: (28, 28, 28), + 235: (38, 38, 38), + 236: (48, 48, 48), + 237: (58, 58, 58), + 238: (68, 68, 68), + 239: (78, 78, 78), + 240: (88, 88, 88), + 241: (98, 98, 98), + 242: (108, 108, 108), + 243: (118, 118, 118), + 244: (128, 128, 128), + 245: (138, 138, 138), + 246: (148, 148, 148), + 247: (158, 158, 158), + 248: (168, 168, 168), + 249: (178, 178, 178), + 250: (188, 188, 188), + 251: (198, 198, 198), + 252: (208, 208, 208), + 253: (218, 218, 218), + 254: (228, 228, 228), + 255: (238, 238, 238), +} + + +class ColorSystem(IntEnum): + """One of the 3 color system supported by terminals.""" + + STANDARD = 1 + EIGHT_BIT = 2 + FULL = 3 + + +class ColorType(IntEnum): + """Type of color stored in Color class.""" + + DEFAULT = 0 + STANDARD = 1 + EIGHT_BIT = 2 + FULL = 3 + + +class ColorTriplet(NamedTuple): + """The red, green, and blue components of a color.""" + + red: int + green: int + blue: int + + +class ColorParseError(Exception): + """The color could not be parsed.""" + + +RE_COLOR = re.compile( + r"""^ +\#([0-9a-f]{6})$| +([0-9]{1,3})$| +rgb\(([\d\s,]+)\)$ +""", + re.VERBOSE, +) + + +class Color(NamedTuple): + """Terminal color definition.""" + + name: str + type: ColorType + number: Optional[int] = None + triplet: Optional[ColorTriplet] = None + + def __str__(self): + """Render the color to the terminal.""" + attrs = self.get_ansi_codes(foreground=True) + return ( + f"" + f"\x1b[{';'.join(attrs)}m ⬤ \x1b[0m" + ) + + def __repr__(self) -> str: + return f"" + + @property + def system(self) -> ColorSystem: + if self.type == ColorType.DEFAULT: + return ColorSystem.STANDARD + return ColorSystem(int(self.type)) + + @classmethod + @lru_cache(maxsize=1000) + def parse(cls, color: str) -> Optional[Color]: + """Parse a color definition.""" + color = color.lower().strip() + + if color == "default": + return cls(color, type=ColorType.DEFAULT) + + standard_color_number = STANDARD_COLORS_NAMES.get(color) + if standard_color_number is not None: + return cls(color, type=ColorType.STANDARD, number=standard_color_number) + + color_match = RE_COLOR.match(color) + if color_match is None: + return None + + color_24, color_8, color_rgb = color_match.groups() + if color_8: + return cls(color, ColorType.EIGHT_BIT, number=int(color_8)) + + elif color_24: + triplet = ColorTriplet( + int(color_24[0:2], 16), int(color_24[2:4], 16), int(color_24[4:6], 16) + ) + if not all(component <= 255 for component in triplet): + raise ColorParseError(f"color components must be <= 255 in {color!r}") + return cls(color, ColorType.FULL, triplet=triplet) + + else: # color_rgb: + components = color_rgb.split(",") + if len(components) != 3: + raise ColorParseError(f"expected three components in {color!r}") + red, green, blue = components + triplet = ColorTriplet(int(red), int(green), int(blue)) + if not all(component <= 255 for component in triplet): + raise ColorParseError(f"color components must be <= 255 in {color!r}") + return cls(color, ColorType.FULL, triplet=triplet) + + @classmethod + def _match_color( + cls, color: ColorTriplet, pallette: Iterable[Tuple[int, int, int]] + ) -> int: + """Find a color from a pallette that most closely matches a given color""" + red1, green1, blue1 = color + _sqrt = sqrt + + def get_color_distance(color: Tuple[int, int, int]) -> float: + """Get the distance to a color.""" + red2, green2, blue2 = color + distance = _sqrt( + (red2 - red1) * (red2 - red1) + + (green2 - green1) * (green2 - green1) + + (blue2 - blue1) * (blue2 - blue1) + ) + return distance + + min_index, _min_color = min( + enumerate(pallette), + key=lambda pallette_color: get_color_distance(pallette_color[1]), + ) + return min_index + + def get_ansi_codes(self, foreground: bool = True) -> List[str]: + """Get the ANSI escape codes for this color.""" + if self.type == ColorType.DEFAULT: + return ["39" if foreground else "49"] + + elif self.type == ColorType.STANDARD: + assert self.number is not None + return [str(30 + self.number if foreground else 40 + self.number)] + + elif self.type == ColorType.EIGHT_BIT: + assert self.number is not None + return ["38" if foreground else "48", "5", str(self.number)] + + else: # self.standard == ColorStandard.FULL: + assert self.triplet is not None + red, green, blue = self.triplet + return ["38" if foreground else "48", "2", str(red), str(green), str(blue)] + + def downgrade(self, system: ColorSystem) -> Color: + """Downgrade a color system to a system with fewer colors.""" + if system >= self.system: + return self + + # Convert to 8-bit color from full color + if system == ColorSystem.EIGHT_BIT and self.system == ColorSystem.FULL: + + assert self.triplet is not None + red, green, blue = self.triplet + if red == green and green == blue: + if red < 8: + color_number = 16 + elif red > 248: + color_number = 231 + else: + color_number = round(((red - 8) / 247.0) * 24) + 232 + return Color(self.name, ColorType.EIGHT_BIT, number=color_number) + ansi_red = 36 * round(red / 255.0 * 5.0) + ansi_green = 6 * round(green / 255.0 * 5.0) + ansi_blue = round(blue / 255.0 * 5.0) + color_number = 16 + ansi_red + ansi_green + ansi_blue + return Color(self.name, ColorType.EIGHT_BIT, number=color_number) + + # Convert to standard from full color or 8-bit + elif system == ColorSystem.STANDARD: + if self.system == ColorSystem.FULL: + assert self.triplet is not None + triplet = self.triplet + else: # self.system == ColorSystem.EIGHT_BUT + assert self.number is not None + triplet = ColorTriplet(*EIGHT_BIT_COLORS[self.number]) + color_number = self._match_color(triplet, STANDARD_PALLETTE) + return Color(self.name, ColorType.STANDARD, number=color_number) + + return self + + +if __name__ == "__main__": + print(Color.parse("default")) + print(Color.parse("red")) + print(Color.parse("#ff0000")) + print(Color.parse("0")) + print(Color.parse("100")) + print(Color.parse("rgb( 12, 130, 200)")) + + color = Color.parse("#339a2e") + print(color) + print(color.downgrade(ColorSystem.EIGHT_BIT)) + print(color.downgrade(ColorSystem.STANDARD)) + import sys + + # sys.stdout.write(Color.parse("#00ffff").foreground_sequence + "Hello") diff --git a/rich/colors.py b/rich/colors.py new file mode 100644 index 00000000..1420cfa7 --- /dev/null +++ b/rich/colors.py @@ -0,0 +1,6 @@ +TERM_COLORS = [{"colorId":0,"hexString":"#000000","rgb":{"r":0,"g":0,"b":0},"hsl":{"h":0,"s":0,"l":0},"name":"Black"},{"colorId":1,"hexString":"#800000","rgb":{"r":128,"g":0,"b":0},"hsl":{"h":0,"s":100,"l":25},"name":"Maroon"},{"colorId":2,"hexString":"#008000","rgb":{"r":0,"g":128,"b":0},"hsl":{"h":120,"s":100,"l":25},"name":"Green"},{"colorId":3,"hexString":"#808000","rgb":{"r":128,"g":128,"b":0},"hsl":{"h":60,"s":100,"l":25},"name":"Olive"},{"colorId":4,"hexString":"#000080","rgb":{"r":0,"g":0,"b":128},"hsl":{"h":240,"s":100,"l":25},"name":"Navy"},{"colorId":5,"hexString":"#800080","rgb":{"r":128,"g":0,"b":128},"hsl":{"h":300,"s":100,"l":25},"name":"Purple"},{"colorId":6,"hexString":"#008080","rgb":{"r":0,"g":128,"b":128},"hsl":{"h":180,"s":100,"l":25},"name":"Teal"},{"colorId":7,"hexString":"#c0c0c0","rgb":{"r":192,"g":192,"b":192},"hsl":{"h":0,"s":0,"l":75},"name":"Silver"},{"colorId":8,"hexString":"#808080","rgb":{"r":128,"g":128,"b":128},"hsl":{"h":0,"s":0,"l":50},"name":"Grey"},{"colorId":9,"hexString":"#ff0000","rgb":{"r":255,"g":0,"b":0},"hsl":{"h":0,"s":100,"l":50},"name":"Red"},{"colorId":10,"hexString":"#00ff00","rgb":{"r":0,"g":255,"b":0},"hsl":{"h":120,"s":100,"l":50},"name":"Lime"},{"colorId":11,"hexString":"#ffff00","rgb":{"r":255,"g":255,"b":0},"hsl":{"h":60,"s":100,"l":50},"name":"Yellow"},{"colorId":12,"hexString":"#0000ff","rgb":{"r":0,"g":0,"b":255},"hsl":{"h":240,"s":100,"l":50},"name":"Blue"},{"colorId":13,"hexString":"#ff00ff","rgb":{"r":255,"g":0,"b":255},"hsl":{"h":300,"s":100,"l":50},"name":"Fuchsia"},{"colorId":14,"hexString":"#00ffff","rgb":{"r":0,"g":255,"b":255},"hsl":{"h":180,"s":100,"l":50},"name":"Aqua"},{"colorId":15,"hexString":"#ffffff","rgb":{"r":255,"g":255,"b":255},"hsl":{"h":0,"s":0,"l":100},"name":"White"},{"colorId":16,"hexString":"#000000","rgb":{"r":0,"g":0,"b":0},"hsl":{"h":0,"s":0,"l":0},"name":"Grey0"},{"colorId":17,"hexString":"#00005f","rgb":{"r":0,"g":0,"b":95},"hsl":{"h":240,"s":100,"l":18},"name":"NavyBlue"},{"colorId":18,"hexString":"#000087","rgb":{"r":0,"g":0,"b":135},"hsl":{"h":240,"s":100,"l":26},"name":"DarkBlue"},{"colorId":19,"hexString":"#0000af","rgb":{"r":0,"g":0,"b":175},"hsl":{"h":240,"s":100,"l":34},"name":"Blue3"},{"colorId":20,"hexString":"#0000d7","rgb":{"r":0,"g":0,"b":215},"hsl":{"h":240,"s":100,"l":42},"name":"Blue3"},{"colorId":21,"hexString":"#0000ff","rgb":{"r":0,"g":0,"b":255},"hsl":{"h":240,"s":100,"l":50},"name":"Blue1"},{"colorId":22,"hexString":"#005f00","rgb":{"r":0,"g":95,"b":0},"hsl":{"h":120,"s":100,"l":18},"name":"DarkGreen"},{"colorId":23,"hexString":"#005f5f","rgb":{"r":0,"g":95,"b":95},"hsl":{"h":180,"s":100,"l":18},"name":"DeepSkyBlue4"},{"colorId":24,"hexString":"#005f87","rgb":{"r":0,"g":95,"b":135},"hsl":{"h":197.777777777778,"s":100,"l":26},"name":"DeepSkyBlue4"},{"colorId":25,"hexString":"#005faf","rgb":{"r":0,"g":95,"b":175},"hsl":{"h":207.428571428571,"s":100,"l":34},"name":"DeepSkyBlue4"},{"colorId":26,"hexString":"#005fd7","rgb":{"r":0,"g":95,"b":215},"hsl":{"h":213.488372093023,"s":100,"l":42},"name":"DodgerBlue3"},{"colorId":27,"hexString":"#005fff","rgb":{"r":0,"g":95,"b":255},"hsl":{"h":217.647058823529,"s":100,"l":50},"name":"DodgerBlue2"},{"colorId":28,"hexString":"#008700","rgb":{"r":0,"g":135,"b":0},"hsl":{"h":120,"s":100,"l":26},"name":"Green4"},{"colorId":29,"hexString":"#00875f","rgb":{"r":0,"g":135,"b":95},"hsl":{"h":162.222222222222,"s":100,"l":26},"name":"SpringGreen4"},{"colorId":30,"hexString":"#008787","rgb":{"r":0,"g":135,"b":135},"hsl":{"h":180,"s":100,"l":26},"name":"Turquoise4"},{"colorId":31,"hexString":"#0087af","rgb":{"r":0,"g":135,"b":175},"hsl":{"h":193.714285714286,"s":100,"l":34},"name":"DeepSkyBlue3"},{"colorId":32,"hexString":"#0087d7","rgb":{"r":0,"g":135,"b":215},"hsl":{"h":202.325581395349,"s":100,"l":42},"name":"DeepSkyBlue3"},{"colorId":33,"hexString":"#0087ff","rgb":{"r":0,"g":135,"b":255},"hsl":{"h":208.235294117647,"s":100,"l":50},"name":"DodgerBlue1"},{"colorId":34,"hexString":"#00af00","rgb":{"r":0,"g":175,"b":0},"hsl":{"h":120,"s":100,"l":34},"name":"Green3"},{"colorId":35,"hexString":"#00af5f","rgb":{"r":0,"g":175,"b":95},"hsl":{"h":152.571428571429,"s":100,"l":34},"name":"SpringGreen3"},{"colorId":36,"hexString":"#00af87","rgb":{"r":0,"g":175,"b":135},"hsl":{"h":166.285714285714,"s":100,"l":34},"name":"DarkCyan"},{"colorId":37,"hexString":"#00afaf","rgb":{"r":0,"g":175,"b":175},"hsl":{"h":180,"s":100,"l":34},"name":"LightSeaGreen"},{"colorId":38,"hexString":"#00afd7","rgb":{"r":0,"g":175,"b":215},"hsl":{"h":191.162790697674,"s":100,"l":42},"name":"DeepSkyBlue2"},{"colorId":39,"hexString":"#00afff","rgb":{"r":0,"g":175,"b":255},"hsl":{"h":198.823529411765,"s":100,"l":50},"name":"DeepSkyBlue1"},{"colorId":40,"hexString":"#00d700","rgb":{"r":0,"g":215,"b":0},"hsl":{"h":120,"s":100,"l":42},"name":"Green3"},{"colorId":41,"hexString":"#00d75f","rgb":{"r":0,"g":215,"b":95},"hsl":{"h":146.511627906977,"s":100,"l":42},"name":"SpringGreen3"},{"colorId":42,"hexString":"#00d787","rgb":{"r":0,"g":215,"b":135},"hsl":{"h":157.674418604651,"s":100,"l":42},"name":"SpringGreen2"},{"colorId":43,"hexString":"#00d7af","rgb":{"r":0,"g":215,"b":175},"hsl":{"h":168.837209302326,"s":100,"l":42},"name":"Cyan3"},{"colorId":44,"hexString":"#00d7d7","rgb":{"r":0,"g":215,"b":215},"hsl":{"h":180,"s":100,"l":42},"name":"DarkTurquoise"},{"colorId":45,"hexString":"#00d7ff","rgb":{"r":0,"g":215,"b":255},"hsl":{"h":189.411764705882,"s":100,"l":50},"name":"Turquoise2"},{"colorId":46,"hexString":"#00ff00","rgb":{"r":0,"g":255,"b":0},"hsl":{"h":120,"s":100,"l":50},"name":"Green1"},{"colorId":47,"hexString":"#00ff5f","rgb":{"r":0,"g":255,"b":95},"hsl":{"h":142.352941176471,"s":100,"l":50},"name":"SpringGreen2"},{"colorId":48,"hexString":"#00ff87","rgb":{"r":0,"g":255,"b":135},"hsl":{"h":151.764705882353,"s":100,"l":50},"name":"SpringGreen1"},{"colorId":49,"hexString":"#00ffaf","rgb":{"r":0,"g":255,"b":175},"hsl":{"h":161.176470588235,"s":100,"l":50},"name":"MediumSpringGreen"},{"colorId":50,"hexString":"#00ffd7","rgb":{"r":0,"g":255,"b":215},"hsl":{"h":170.588235294118,"s":100,"l":50},"name":"Cyan2"},{"colorId":51,"hexString":"#00ffff","rgb":{"r":0,"g":255,"b":255},"hsl":{"h":180,"s":100,"l":50},"name":"Cyan1"},{"colorId":52,"hexString":"#5f0000","rgb":{"r":95,"g":0,"b":0},"hsl":{"h":0,"s":100,"l":18},"name":"DarkRed"},{"colorId":53,"hexString":"#5f005f","rgb":{"r":95,"g":0,"b":95},"hsl":{"h":300,"s":100,"l":18},"name":"DeepPink4"},{"colorId":54,"hexString":"#5f0087","rgb":{"r":95,"g":0,"b":135},"hsl":{"h":282.222222222222,"s":100,"l":26},"name":"Purple4"},{"colorId":55,"hexString":"#5f00af","rgb":{"r":95,"g":0,"b":175},"hsl":{"h":272.571428571429,"s":100,"l":34},"name":"Purple4"},{"colorId":56,"hexString":"#5f00d7","rgb":{"r":95,"g":0,"b":215},"hsl":{"h":266.511627906977,"s":100,"l":42},"name":"Purple3"},{"colorId":57,"hexString":"#5f00ff","rgb":{"r":95,"g":0,"b":255},"hsl":{"h":262.352941176471,"s":100,"l":50},"name":"BlueViolet"},{"colorId":58,"hexString":"#5f5f00","rgb":{"r":95,"g":95,"b":0},"hsl":{"h":60,"s":100,"l":18},"name":"Orange4"},{"colorId":59,"hexString":"#5f5f5f","rgb":{"r":95,"g":95,"b":95},"hsl":{"h":0,"s":0,"l":37},"name":"Grey37"},{"colorId":60,"hexString":"#5f5f87","rgb":{"r":95,"g":95,"b":135},"hsl":{"h":240,"s":17,"l":45},"name":"MediumPurple4"},{"colorId":61,"hexString":"#5f5faf","rgb":{"r":95,"g":95,"b":175},"hsl":{"h":240,"s":33,"l":52},"name":"SlateBlue3"},{"colorId":62,"hexString":"#5f5fd7","rgb":{"r":95,"g":95,"b":215},"hsl":{"h":240,"s":60,"l":60},"name":"SlateBlue3"},{"colorId":63,"hexString":"#5f5fff","rgb":{"r":95,"g":95,"b":255},"hsl":{"h":240,"s":100,"l":68},"name":"RoyalBlue1"},{"colorId":64,"hexString":"#5f8700","rgb":{"r":95,"g":135,"b":0},"hsl":{"h":77.7777777777778,"s":100,"l":26},"name":"Chartreuse4"},{"colorId":65,"hexString":"#5f875f","rgb":{"r":95,"g":135,"b":95},"hsl":{"h":120,"s":17,"l":45},"name":"DarkSeaGreen4"},{"colorId":66,"hexString":"#5f8787","rgb":{"r":95,"g":135,"b":135},"hsl":{"h":180,"s":17,"l":45},"name":"PaleTurquoise4"},{"colorId":67,"hexString":"#5f87af","rgb":{"r":95,"g":135,"b":175},"hsl":{"h":210,"s":33,"l":52},"name":"SteelBlue"},{"colorId":68,"hexString":"#5f87d7","rgb":{"r":95,"g":135,"b":215},"hsl":{"h":220,"s":60,"l":60},"name":"SteelBlue3"},{"colorId":69,"hexString":"#5f87ff","rgb":{"r":95,"g":135,"b":255},"hsl":{"h":225,"s":100,"l":68},"name":"CornflowerBlue"},{"colorId":70,"hexString":"#5faf00","rgb":{"r":95,"g":175,"b":0},"hsl":{"h":87.4285714285714,"s":100,"l":34},"name":"Chartreuse3"},{"colorId":71,"hexString":"#5faf5f","rgb":{"r":95,"g":175,"b":95},"hsl":{"h":120,"s":33,"l":52},"name":"DarkSeaGreen4"},{"colorId":72,"hexString":"#5faf87","rgb":{"r":95,"g":175,"b":135},"hsl":{"h":150,"s":33,"l":52},"name":"CadetBlue"},{"colorId":73,"hexString":"#5fafaf","rgb":{"r":95,"g":175,"b":175},"hsl":{"h":180,"s":33,"l":52},"name":"CadetBlue"},{"colorId":74,"hexString":"#5fafd7","rgb":{"r":95,"g":175,"b":215},"hsl":{"h":200,"s":60,"l":60},"name":"SkyBlue3"},{"colorId":75,"hexString":"#5fafff","rgb":{"r":95,"g":175,"b":255},"hsl":{"h":210,"s":100,"l":68},"name":"SteelBlue1"},{"colorId":76,"hexString":"#5fd700","rgb":{"r":95,"g":215,"b":0},"hsl":{"h":93.4883720930233,"s":100,"l":42},"name":"Chartreuse3"},{"colorId":77,"hexString":"#5fd75f","rgb":{"r":95,"g":215,"b":95},"hsl":{"h":120,"s":60,"l":60},"name":"PaleGreen3"},{"colorId":78,"hexString":"#5fd787","rgb":{"r":95,"g":215,"b":135},"hsl":{"h":140,"s":60,"l":60},"name":"SeaGreen3"},{"colorId":79,"hexString":"#5fd7af","rgb":{"r":95,"g":215,"b":175},"hsl":{"h":160,"s":60,"l":60},"name":"Aquamarine3"},{"colorId":80,"hexString":"#5fd7d7","rgb":{"r":95,"g":215,"b":215},"hsl":{"h":180,"s":60,"l":60},"name":"MediumTurquoise"},{"colorId":81,"hexString":"#5fd7ff","rgb":{"r":95,"g":215,"b":255},"hsl":{"h":195,"s":100,"l":68},"name":"SteelBlue1"},{"colorId":82,"hexString":"#5fff00","rgb":{"r":95,"g":255,"b":0},"hsl":{"h":97.6470588235294,"s":100,"l":50},"name":"Chartreuse2"},{"colorId":83,"hexString":"#5fff5f","rgb":{"r":95,"g":255,"b":95},"hsl":{"h":120,"s":100,"l":68},"name":"SeaGreen2"},{"colorId":84,"hexString":"#5fff87","rgb":{"r":95,"g":255,"b":135},"hsl":{"h":135,"s":100,"l":68},"name":"SeaGreen1"},{"colorId":85,"hexString":"#5fffaf","rgb":{"r":95,"g":255,"b":175},"hsl":{"h":150,"s":100,"l":68},"name":"SeaGreen1"},{"colorId":86,"hexString":"#5fffd7","rgb":{"r":95,"g":255,"b":215},"hsl":{"h":165,"s":100,"l":68},"name":"Aquamarine1"},{"colorId":87,"hexString":"#5fffff","rgb":{"r":95,"g":255,"b":255},"hsl":{"h":180,"s":100,"l":68},"name":"DarkSlateGray2"},{"colorId":88,"hexString":"#870000","rgb":{"r":135,"g":0,"b":0},"hsl":{"h":0,"s":100,"l":26},"name":"DarkRed"},{"colorId":89,"hexString":"#87005f","rgb":{"r":135,"g":0,"b":95},"hsl":{"h":317.777777777778,"s":100,"l":26},"name":"DeepPink4"},{"colorId":90,"hexString":"#870087","rgb":{"r":135,"g":0,"b":135},"hsl":{"h":300,"s":100,"l":26},"name":"DarkMagenta"},{"colorId":91,"hexString":"#8700af","rgb":{"r":135,"g":0,"b":175},"hsl":{"h":286.285714285714,"s":100,"l":34},"name":"DarkMagenta"},{"colorId":92,"hexString":"#8700d7","rgb":{"r":135,"g":0,"b":215},"hsl":{"h":277.674418604651,"s":100,"l":42},"name":"DarkViolet"},{"colorId":93,"hexString":"#8700ff","rgb":{"r":135,"g":0,"b":255},"hsl":{"h":271.764705882353,"s":100,"l":50},"name":"Purple"},{"colorId":94,"hexString":"#875f00","rgb":{"r":135,"g":95,"b":0},"hsl":{"h":42.2222222222222,"s":100,"l":26},"name":"Orange4"},{"colorId":95,"hexString":"#875f5f","rgb":{"r":135,"g":95,"b":95},"hsl":{"h":0,"s":17,"l":45},"name":"LightPink4"},{"colorId":96,"hexString":"#875f87","rgb":{"r":135,"g":95,"b":135},"hsl":{"h":300,"s":17,"l":45},"name":"Plum4"},{"colorId":97,"hexString":"#875faf","rgb":{"r":135,"g":95,"b":175},"hsl":{"h":270,"s":33,"l":52},"name":"MediumPurple3"},{"colorId":98,"hexString":"#875fd7","rgb":{"r":135,"g":95,"b":215},"hsl":{"h":260,"s":60,"l":60},"name":"MediumPurple3"},{"colorId":99,"hexString":"#875fff","rgb":{"r":135,"g":95,"b":255},"hsl":{"h":255,"s":100,"l":68},"name":"SlateBlue1"},{"colorId":100,"hexString":"#878700","rgb":{"r":135,"g":135,"b":0},"hsl":{"h":60,"s":100,"l":26},"name":"Yellow4"},{"colorId":101,"hexString":"#87875f","rgb":{"r":135,"g":135,"b":95},"hsl":{"h":60,"s":17,"l":45},"name":"Wheat4"},{"colorId":102,"hexString":"#878787","rgb":{"r":135,"g":135,"b":135},"hsl":{"h":0,"s":0,"l":52},"name":"Grey53"},{"colorId":103,"hexString":"#8787af","rgb":{"r":135,"g":135,"b":175},"hsl":{"h":240,"s":20,"l":60},"name":"LightSlateGrey"},{"colorId":104,"hexString":"#8787d7","rgb":{"r":135,"g":135,"b":215},"hsl":{"h":240,"s":50,"l":68},"name":"MediumPurple"},{"colorId":105,"hexString":"#8787ff","rgb":{"r":135,"g":135,"b":255},"hsl":{"h":240,"s":100,"l":76},"name":"LightSlateBlue"},{"colorId":106,"hexString":"#87af00","rgb":{"r":135,"g":175,"b":0},"hsl":{"h":73.7142857142857,"s":100,"l":34},"name":"Yellow4"},{"colorId":107,"hexString":"#87af5f","rgb":{"r":135,"g":175,"b":95},"hsl":{"h":90,"s":33,"l":52},"name":"DarkOliveGreen3"},{"colorId":108,"hexString":"#87af87","rgb":{"r":135,"g":175,"b":135},"hsl":{"h":120,"s":20,"l":60},"name":"DarkSeaGreen"},{"colorId":109,"hexString":"#87afaf","rgb":{"r":135,"g":175,"b":175},"hsl":{"h":180,"s":20,"l":60},"name":"LightSkyBlue3"},{"colorId":110,"hexString":"#87afd7","rgb":{"r":135,"g":175,"b":215},"hsl":{"h":210,"s":50,"l":68},"name":"LightSkyBlue3"},{"colorId":111,"hexString":"#87afff","rgb":{"r":135,"g":175,"b":255},"hsl":{"h":220,"s":100,"l":76},"name":"SkyBlue2"},{"colorId":112,"hexString":"#87d700","rgb":{"r":135,"g":215,"b":0},"hsl":{"h":82.3255813953488,"s":100,"l":42},"name":"Chartreuse2"},{"colorId":113,"hexString":"#87d75f","rgb":{"r":135,"g":215,"b":95},"hsl":{"h":100,"s":60,"l":60},"name":"DarkOliveGreen3"},{"colorId":114,"hexString":"#87d787","rgb":{"r":135,"g":215,"b":135},"hsl":{"h":120,"s":50,"l":68},"name":"PaleGreen3"},{"colorId":115,"hexString":"#87d7af","rgb":{"r":135,"g":215,"b":175},"hsl":{"h":150,"s":50,"l":68},"name":"DarkSeaGreen3"},{"colorId":116,"hexString":"#87d7d7","rgb":{"r":135,"g":215,"b":215},"hsl":{"h":180,"s":50,"l":68},"name":"DarkSlateGray3"},{"colorId":117,"hexString":"#87d7ff","rgb":{"r":135,"g":215,"b":255},"hsl":{"h":200,"s":100,"l":76},"name":"SkyBlue1"},{"colorId":118,"hexString":"#87ff00","rgb":{"r":135,"g":255,"b":0},"hsl":{"h":88.2352941176471,"s":100,"l":50},"name":"Chartreuse1"},{"colorId":119,"hexString":"#87ff5f","rgb":{"r":135,"g":255,"b":95},"hsl":{"h":105,"s":100,"l":68},"name":"LightGreen"},{"colorId":120,"hexString":"#87ff87","rgb":{"r":135,"g":255,"b":135},"hsl":{"h":120,"s":100,"l":76},"name":"LightGreen"},{"colorId":121,"hexString":"#87ffaf","rgb":{"r":135,"g":255,"b":175},"hsl":{"h":140,"s":100,"l":76},"name":"PaleGreen1"},{"colorId":122,"hexString":"#87ffd7","rgb":{"r":135,"g":255,"b":215},"hsl":{"h":160,"s":100,"l":76},"name":"Aquamarine1"},{"colorId":123,"hexString":"#87ffff","rgb":{"r":135,"g":255,"b":255},"hsl":{"h":180,"s":100,"l":76},"name":"DarkSlateGray1"},{"colorId":124,"hexString":"#af0000","rgb":{"r":175,"g":0,"b":0},"hsl":{"h":0,"s":100,"l":34},"name":"Red3"},{"colorId":125,"hexString":"#af005f","rgb":{"r":175,"g":0,"b":95},"hsl":{"h":327.428571428571,"s":100,"l":34},"name":"DeepPink4"},{"colorId":126,"hexString":"#af0087","rgb":{"r":175,"g":0,"b":135},"hsl":{"h":313.714285714286,"s":100,"l":34},"name":"MediumVioletRed"},{"colorId":127,"hexString":"#af00af","rgb":{"r":175,"g":0,"b":175},"hsl":{"h":300,"s":100,"l":34},"name":"Magenta3"},{"colorId":128,"hexString":"#af00d7","rgb":{"r":175,"g":0,"b":215},"hsl":{"h":288.837209302326,"s":100,"l":42},"name":"DarkViolet"},{"colorId":129,"hexString":"#af00ff","rgb":{"r":175,"g":0,"b":255},"hsl":{"h":281.176470588235,"s":100,"l":50},"name":"Purple"},{"colorId":130,"hexString":"#af5f00","rgb":{"r":175,"g":95,"b":0},"hsl":{"h":32.5714285714286,"s":100,"l":34},"name":"DarkOrange3"},{"colorId":131,"hexString":"#af5f5f","rgb":{"r":175,"g":95,"b":95},"hsl":{"h":0,"s":33,"l":52},"name":"IndianRed"},{"colorId":132,"hexString":"#af5f87","rgb":{"r":175,"g":95,"b":135},"hsl":{"h":330,"s":33,"l":52},"name":"HotPink3"},{"colorId":133,"hexString":"#af5faf","rgb":{"r":175,"g":95,"b":175},"hsl":{"h":300,"s":33,"l":52},"name":"MediumOrchid3"},{"colorId":134,"hexString":"#af5fd7","rgb":{"r":175,"g":95,"b":215},"hsl":{"h":280,"s":60,"l":60},"name":"MediumOrchid"},{"colorId":135,"hexString":"#af5fff","rgb":{"r":175,"g":95,"b":255},"hsl":{"h":270,"s":100,"l":68},"name":"MediumPurple2"},{"colorId":136,"hexString":"#af8700","rgb":{"r":175,"g":135,"b":0},"hsl":{"h":46.2857142857143,"s":100,"l":34},"name":"DarkGoldenrod"},{"colorId":137,"hexString":"#af875f","rgb":{"r":175,"g":135,"b":95},"hsl":{"h":30,"s":33,"l":52},"name":"LightSalmon3"},{"colorId":138,"hexString":"#af8787","rgb":{"r":175,"g":135,"b":135},"hsl":{"h":0,"s":20,"l":60},"name":"RosyBrown"},{"colorId":139,"hexString":"#af87af","rgb":{"r":175,"g":135,"b":175},"hsl":{"h":300,"s":20,"l":60},"name":"Grey63"},{"colorId":140,"hexString":"#af87d7","rgb":{"r":175,"g":135,"b":215},"hsl":{"h":270,"s":50,"l":68},"name":"MediumPurple2"},{"colorId":141,"hexString":"#af87ff","rgb":{"r":175,"g":135,"b":255},"hsl":{"h":260,"s":100,"l":76},"name":"MediumPurple1"},{"colorId":142,"hexString":"#afaf00","rgb":{"r":175,"g":175,"b":0},"hsl":{"h":60,"s":100,"l":34},"name":"Gold3"},{"colorId":143,"hexString":"#afaf5f","rgb":{"r":175,"g":175,"b":95},"hsl":{"h":60,"s":33,"l":52},"name":"DarkKhaki"},{"colorId":144,"hexString":"#afaf87","rgb":{"r":175,"g":175,"b":135},"hsl":{"h":60,"s":20,"l":60},"name":"NavajoWhite3"},{"colorId":145,"hexString":"#afafaf","rgb":{"r":175,"g":175,"b":175},"hsl":{"h":0,"s":0,"l":68},"name":"Grey69"},{"colorId":146,"hexString":"#afafd7","rgb":{"r":175,"g":175,"b":215},"hsl":{"h":240,"s":33,"l":76},"name":"LightSteelBlue3"},{"colorId":147,"hexString":"#afafff","rgb":{"r":175,"g":175,"b":255},"hsl":{"h":240,"s":100,"l":84},"name":"LightSteelBlue"},{"colorId":148,"hexString":"#afd700","rgb":{"r":175,"g":215,"b":0},"hsl":{"h":71.1627906976744,"s":100,"l":42},"name":"Yellow3"},{"colorId":149,"hexString":"#afd75f","rgb":{"r":175,"g":215,"b":95},"hsl":{"h":80,"s":60,"l":60},"name":"DarkOliveGreen3"},{"colorId":150,"hexString":"#afd787","rgb":{"r":175,"g":215,"b":135},"hsl":{"h":90,"s":50,"l":68},"name":"DarkSeaGreen3"},{"colorId":151,"hexString":"#afd7af","rgb":{"r":175,"g":215,"b":175},"hsl":{"h":120,"s":33,"l":76},"name":"DarkSeaGreen2"},{"colorId":152,"hexString":"#afd7d7","rgb":{"r":175,"g":215,"b":215},"hsl":{"h":180,"s":33,"l":76},"name":"LightCyan3"},{"colorId":153,"hexString":"#afd7ff","rgb":{"r":175,"g":215,"b":255},"hsl":{"h":210,"s":100,"l":84},"name":"LightSkyBlue1"},{"colorId":154,"hexString":"#afff00","rgb":{"r":175,"g":255,"b":0},"hsl":{"h":78.8235294117647,"s":100,"l":50},"name":"GreenYellow"},{"colorId":155,"hexString":"#afff5f","rgb":{"r":175,"g":255,"b":95},"hsl":{"h":90,"s":100,"l":68},"name":"DarkOliveGreen2"},{"colorId":156,"hexString":"#afff87","rgb":{"r":175,"g":255,"b":135},"hsl":{"h":100,"s":100,"l":76},"name":"PaleGreen1"},{"colorId":157,"hexString":"#afffaf","rgb":{"r":175,"g":255,"b":175},"hsl":{"h":120,"s":100,"l":84},"name":"DarkSeaGreen2"},{"colorId":158,"hexString":"#afffd7","rgb":{"r":175,"g":255,"b":215},"hsl":{"h":150,"s":100,"l":84},"name":"DarkSeaGreen1"},{"colorId":159,"hexString":"#afffff","rgb":{"r":175,"g":255,"b":255},"hsl":{"h":180,"s":100,"l":84},"name":"PaleTurquoise1"},{"colorId":160,"hexString":"#d70000","rgb":{"r":215,"g":0,"b":0},"hsl":{"h":0,"s":100,"l":42},"name":"Red3"},{"colorId":161,"hexString":"#d7005f","rgb":{"r":215,"g":0,"b":95},"hsl":{"h":333.488372093023,"s":100,"l":42},"name":"DeepPink3"},{"colorId":162,"hexString":"#d70087","rgb":{"r":215,"g":0,"b":135},"hsl":{"h":322.325581395349,"s":100,"l":42},"name":"DeepPink3"},{"colorId":163,"hexString":"#d700af","rgb":{"r":215,"g":0,"b":175},"hsl":{"h":311.162790697674,"s":100,"l":42},"name":"Magenta3"},{"colorId":164,"hexString":"#d700d7","rgb":{"r":215,"g":0,"b":215},"hsl":{"h":300,"s":100,"l":42},"name":"Magenta3"},{"colorId":165,"hexString":"#d700ff","rgb":{"r":215,"g":0,"b":255},"hsl":{"h":290.588235294118,"s":100,"l":50},"name":"Magenta2"},{"colorId":166,"hexString":"#d75f00","rgb":{"r":215,"g":95,"b":0},"hsl":{"h":26.5116279069767,"s":100,"l":42},"name":"DarkOrange3"},{"colorId":167,"hexString":"#d75f5f","rgb":{"r":215,"g":95,"b":95},"hsl":{"h":0,"s":60,"l":60},"name":"IndianRed"},{"colorId":168,"hexString":"#d75f87","rgb":{"r":215,"g":95,"b":135},"hsl":{"h":340,"s":60,"l":60},"name":"HotPink3"},{"colorId":169,"hexString":"#d75faf","rgb":{"r":215,"g":95,"b":175},"hsl":{"h":320,"s":60,"l":60},"name":"HotPink2"},{"colorId":170,"hexString":"#d75fd7","rgb":{"r":215,"g":95,"b":215},"hsl":{"h":300,"s":60,"l":60},"name":"Orchid"},{"colorId":171,"hexString":"#d75fff","rgb":{"r":215,"g":95,"b":255},"hsl":{"h":285,"s":100,"l":68},"name":"MediumOrchid1"},{"colorId":172,"hexString":"#d78700","rgb":{"r":215,"g":135,"b":0},"hsl":{"h":37.6744186046512,"s":100,"l":42},"name":"Orange3"},{"colorId":173,"hexString":"#d7875f","rgb":{"r":215,"g":135,"b":95},"hsl":{"h":20,"s":60,"l":60},"name":"LightSalmon3"},{"colorId":174,"hexString":"#d78787","rgb":{"r":215,"g":135,"b":135},"hsl":{"h":0,"s":50,"l":68},"name":"LightPink3"},{"colorId":175,"hexString":"#d787af","rgb":{"r":215,"g":135,"b":175},"hsl":{"h":330,"s":50,"l":68},"name":"Pink3"},{"colorId":176,"hexString":"#d787d7","rgb":{"r":215,"g":135,"b":215},"hsl":{"h":300,"s":50,"l":68},"name":"Plum3"},{"colorId":177,"hexString":"#d787ff","rgb":{"r":215,"g":135,"b":255},"hsl":{"h":280,"s":100,"l":76},"name":"Violet"},{"colorId":178,"hexString":"#d7af00","rgb":{"r":215,"g":175,"b":0},"hsl":{"h":48.8372093023256,"s":100,"l":42},"name":"Gold3"},{"colorId":179,"hexString":"#d7af5f","rgb":{"r":215,"g":175,"b":95},"hsl":{"h":40,"s":60,"l":60},"name":"LightGoldenrod3"},{"colorId":180,"hexString":"#d7af87","rgb":{"r":215,"g":175,"b":135},"hsl":{"h":30,"s":50,"l":68},"name":"Tan"},{"colorId":181,"hexString":"#d7afaf","rgb":{"r":215,"g":175,"b":175},"hsl":{"h":0,"s":33,"l":76},"name":"MistyRose3"},{"colorId":182,"hexString":"#d7afd7","rgb":{"r":215,"g":175,"b":215},"hsl":{"h":300,"s":33,"l":76},"name":"Thistle3"},{"colorId":183,"hexString":"#d7afff","rgb":{"r":215,"g":175,"b":255},"hsl":{"h":270,"s":100,"l":84},"name":"Plum2"},{"colorId":184,"hexString":"#d7d700","rgb":{"r":215,"g":215,"b":0},"hsl":{"h":60,"s":100,"l":42},"name":"Yellow3"},{"colorId":185,"hexString":"#d7d75f","rgb":{"r":215,"g":215,"b":95},"hsl":{"h":60,"s":60,"l":60},"name":"Khaki3"},{"colorId":186,"hexString":"#d7d787","rgb":{"r":215,"g":215,"b":135},"hsl":{"h":60,"s":50,"l":68},"name":"LightGoldenrod2"},{"colorId":187,"hexString":"#d7d7af","rgb":{"r":215,"g":215,"b":175},"hsl":{"h":60,"s":33,"l":76},"name":"LightYellow3"},{"colorId":188,"hexString":"#d7d7d7","rgb":{"r":215,"g":215,"b":215},"hsl":{"h":0,"s":0,"l":84},"name":"Grey84"},{"colorId":189,"hexString":"#d7d7ff","rgb":{"r":215,"g":215,"b":255},"hsl":{"h":240,"s":100,"l":92},"name":"LightSteelBlue1"},{"colorId":190,"hexString":"#d7ff00","rgb":{"r":215,"g":255,"b":0},"hsl":{"h":69.4117647058823,"s":100,"l":50},"name":"Yellow2"},{"colorId":191,"hexString":"#d7ff5f","rgb":{"r":215,"g":255,"b":95},"hsl":{"h":75,"s":100,"l":68},"name":"DarkOliveGreen1"},{"colorId":192,"hexString":"#d7ff87","rgb":{"r":215,"g":255,"b":135},"hsl":{"h":80,"s":100,"l":76},"name":"DarkOliveGreen1"},{"colorId":193,"hexString":"#d7ffaf","rgb":{"r":215,"g":255,"b":175},"hsl":{"h":90,"s":100,"l":84},"name":"DarkSeaGreen1"},{"colorId":194,"hexString":"#d7ffd7","rgb":{"r":215,"g":255,"b":215},"hsl":{"h":120,"s":100,"l":92},"name":"Honeydew2"},{"colorId":195,"hexString":"#d7ffff","rgb":{"r":215,"g":255,"b":255},"hsl":{"h":180,"s":100,"l":92},"name":"LightCyan1"},{"colorId":196,"hexString":"#ff0000","rgb":{"r":255,"g":0,"b":0},"hsl":{"h":0,"s":100,"l":50},"name":"Red1"},{"colorId":197,"hexString":"#ff005f","rgb":{"r":255,"g":0,"b":95},"hsl":{"h":337.647058823529,"s":100,"l":50},"name":"DeepPink2"},{"colorId":198,"hexString":"#ff0087","rgb":{"r":255,"g":0,"b":135},"hsl":{"h":328.235294117647,"s":100,"l":50},"name":"DeepPink1"},{"colorId":199,"hexString":"#ff00af","rgb":{"r":255,"g":0,"b":175},"hsl":{"h":318.823529411765,"s":100,"l":50},"name":"DeepPink1"},{"colorId":200,"hexString":"#ff00d7","rgb":{"r":255,"g":0,"b":215},"hsl":{"h":309.411764705882,"s":100,"l":50},"name":"Magenta2"},{"colorId":201,"hexString":"#ff00ff","rgb":{"r":255,"g":0,"b":255},"hsl":{"h":300,"s":100,"l":50},"name":"Magenta1"},{"colorId":202,"hexString":"#ff5f00","rgb":{"r":255,"g":95,"b":0},"hsl":{"h":22.3529411764706,"s":100,"l":50},"name":"OrangeRed1"},{"colorId":203,"hexString":"#ff5f5f","rgb":{"r":255,"g":95,"b":95},"hsl":{"h":0,"s":100,"l":68},"name":"IndianRed1"},{"colorId":204,"hexString":"#ff5f87","rgb":{"r":255,"g":95,"b":135},"hsl":{"h":345,"s":100,"l":68},"name":"IndianRed1"},{"colorId":205,"hexString":"#ff5faf","rgb":{"r":255,"g":95,"b":175},"hsl":{"h":330,"s":100,"l":68},"name":"HotPink"},{"colorId":206,"hexString":"#ff5fd7","rgb":{"r":255,"g":95,"b":215},"hsl":{"h":315,"s":100,"l":68},"name":"HotPink"},{"colorId":207,"hexString":"#ff5fff","rgb":{"r":255,"g":95,"b":255},"hsl":{"h":300,"s":100,"l":68},"name":"MediumOrchid1"},{"colorId":208,"hexString":"#ff8700","rgb":{"r":255,"g":135,"b":0},"hsl":{"h":31.7647058823529,"s":100,"l":50},"name":"DarkOrange"},{"colorId":209,"hexString":"#ff875f","rgb":{"r":255,"g":135,"b":95},"hsl":{"h":15,"s":100,"l":68},"name":"Salmon1"},{"colorId":210,"hexString":"#ff8787","rgb":{"r":255,"g":135,"b":135},"hsl":{"h":0,"s":100,"l":76},"name":"LightCoral"},{"colorId":211,"hexString":"#ff87af","rgb":{"r":255,"g":135,"b":175},"hsl":{"h":340,"s":100,"l":76},"name":"PaleVioletRed1"},{"colorId":212,"hexString":"#ff87d7","rgb":{"r":255,"g":135,"b":215},"hsl":{"h":320,"s":100,"l":76},"name":"Orchid2"},{"colorId":213,"hexString":"#ff87ff","rgb":{"r":255,"g":135,"b":255},"hsl":{"h":300,"s":100,"l":76},"name":"Orchid1"},{"colorId":214,"hexString":"#ffaf00","rgb":{"r":255,"g":175,"b":0},"hsl":{"h":41.1764705882353,"s":100,"l":50},"name":"Orange1"},{"colorId":215,"hexString":"#ffaf5f","rgb":{"r":255,"g":175,"b":95},"hsl":{"h":30,"s":100,"l":68},"name":"SandyBrown"},{"colorId":216,"hexString":"#ffaf87","rgb":{"r":255,"g":175,"b":135},"hsl":{"h":20,"s":100,"l":76},"name":"LightSalmon1"},{"colorId":217,"hexString":"#ffafaf","rgb":{"r":255,"g":175,"b":175},"hsl":{"h":0,"s":100,"l":84},"name":"LightPink1"},{"colorId":218,"hexString":"#ffafd7","rgb":{"r":255,"g":175,"b":215},"hsl":{"h":330,"s":100,"l":84},"name":"Pink1"},{"colorId":219,"hexString":"#ffafff","rgb":{"r":255,"g":175,"b":255},"hsl":{"h":300,"s":100,"l":84},"name":"Plum1"},{"colorId":220,"hexString":"#ffd700","rgb":{"r":255,"g":215,"b":0},"hsl":{"h":50.5882352941176,"s":100,"l":50},"name":"Gold1"},{"colorId":221,"hexString":"#ffd75f","rgb":{"r":255,"g":215,"b":95},"hsl":{"h":45,"s":100,"l":68},"name":"LightGoldenrod2"},{"colorId":222,"hexString":"#ffd787","rgb":{"r":255,"g":215,"b":135},"hsl":{"h":40,"s":100,"l":76},"name":"LightGoldenrod2"},{"colorId":223,"hexString":"#ffd7af","rgb":{"r":255,"g":215,"b":175},"hsl":{"h":30,"s":100,"l":84},"name":"NavajoWhite1"},{"colorId":224,"hexString":"#ffd7d7","rgb":{"r":255,"g":215,"b":215},"hsl":{"h":0,"s":100,"l":92},"name":"MistyRose1"},{"colorId":225,"hexString":"#ffd7ff","rgb":{"r":255,"g":215,"b":255},"hsl":{"h":300,"s":100,"l":92},"name":"Thistle1"},{"colorId":226,"hexString":"#ffff00","rgb":{"r":255,"g":255,"b":0},"hsl":{"h":60,"s":100,"l":50},"name":"Yellow1"},{"colorId":227,"hexString":"#ffff5f","rgb":{"r":255,"g":255,"b":95},"hsl":{"h":60,"s":100,"l":68},"name":"LightGoldenrod1"},{"colorId":228,"hexString":"#ffff87","rgb":{"r":255,"g":255,"b":135},"hsl":{"h":60,"s":100,"l":76},"name":"Khaki1"},{"colorId":229,"hexString":"#ffffaf","rgb":{"r":255,"g":255,"b":175},"hsl":{"h":60,"s":100,"l":84},"name":"Wheat1"},{"colorId":230,"hexString":"#ffffd7","rgb":{"r":255,"g":255,"b":215},"hsl":{"h":60,"s":100,"l":92},"name":"Cornsilk1"},{"colorId":231,"hexString":"#ffffff","rgb":{"r":255,"g":255,"b":255},"hsl":{"h":0,"s":0,"l":100},"name":"Grey100"},{"colorId":232,"hexString":"#080808","rgb":{"r":8,"g":8,"b":8},"hsl":{"h":0,"s":0,"l":3},"name":"Grey3"},{"colorId":233,"hexString":"#121212","rgb":{"r":18,"g":18,"b":18},"hsl":{"h":0,"s":0,"l":7},"name":"Grey7"},{"colorId":234,"hexString":"#1c1c1c","rgb":{"r":28,"g":28,"b":28},"hsl":{"h":0,"s":0,"l":10},"name":"Grey11"},{"colorId":235,"hexString":"#262626","rgb":{"r":38,"g":38,"b":38},"hsl":{"h":0,"s":0,"l":14},"name":"Grey15"},{"colorId":236,"hexString":"#303030","rgb":{"r":48,"g":48,"b":48},"hsl":{"h":0,"s":0,"l":18},"name":"Grey19"},{"colorId":237,"hexString":"#3a3a3a","rgb":{"r":58,"g":58,"b":58},"hsl":{"h":0,"s":0,"l":22},"name":"Grey23"},{"colorId":238,"hexString":"#444444","rgb":{"r":68,"g":68,"b":68},"hsl":{"h":0,"s":0,"l":26},"name":"Grey27"},{"colorId":239,"hexString":"#4e4e4e","rgb":{"r":78,"g":78,"b":78},"hsl":{"h":0,"s":0,"l":30},"name":"Grey30"},{"colorId":240,"hexString":"#585858","rgb":{"r":88,"g":88,"b":88},"hsl":{"h":0,"s":0,"l":34},"name":"Grey35"},{"colorId":241,"hexString":"#626262","rgb":{"r":98,"g":98,"b":98},"hsl":{"h":0,"s":0,"l":37},"name":"Grey39"},{"colorId":242,"hexString":"#6c6c6c","rgb":{"r":108,"g":108,"b":108},"hsl":{"h":0,"s":0,"l":40},"name":"Grey42"},{"colorId":243,"hexString":"#767676","rgb":{"r":118,"g":118,"b":118},"hsl":{"h":0,"s":0,"l":46},"name":"Grey46"},{"colorId":244,"hexString":"#808080","rgb":{"r":128,"g":128,"b":128},"hsl":{"h":0,"s":0,"l":50},"name":"Grey50"},{"colorId":245,"hexString":"#8a8a8a","rgb":{"r":138,"g":138,"b":138},"hsl":{"h":0,"s":0,"l":54},"name":"Grey54"},{"colorId":246,"hexString":"#949494","rgb":{"r":148,"g":148,"b":148},"hsl":{"h":0,"s":0,"l":58},"name":"Grey58"},{"colorId":247,"hexString":"#9e9e9e","rgb":{"r":158,"g":158,"b":158},"hsl":{"h":0,"s":0,"l":61},"name":"Grey62"},{"colorId":248,"hexString":"#a8a8a8","rgb":{"r":168,"g":168,"b":168},"hsl":{"h":0,"s":0,"l":65},"name":"Grey66"},{"colorId":249,"hexString":"#b2b2b2","rgb":{"r":178,"g":178,"b":178},"hsl":{"h":0,"s":0,"l":69},"name":"Grey70"},{"colorId":250,"hexString":"#bcbcbc","rgb":{"r":188,"g":188,"b":188},"hsl":{"h":0,"s":0,"l":73},"name":"Grey74"},{"colorId":251,"hexString":"#c6c6c6","rgb":{"r":198,"g":198,"b":198},"hsl":{"h":0,"s":0,"l":77},"name":"Grey78"},{"colorId":252,"hexString":"#d0d0d0","rgb":{"r":208,"g":208,"b":208},"hsl":{"h":0,"s":0,"l":81},"name":"Grey82"},{"colorId":253,"hexString":"#dadada","rgb":{"r":218,"g":218,"b":218},"hsl":{"h":0,"s":0,"l":85},"name":"Grey85"},{"colorId":254,"hexString":"#e4e4e4","rgb":{"r":228,"g":228,"b":228},"hsl":{"h":0,"s":0,"l":89},"name":"Grey89"},{"colorId":255,"hexString":"#eeeeee","rgb":{"r":238,"g":238,"b":238},"hsl":{"h":0,"s":0,"l":93},"name":"Grey93"}] + + + +EXTENDED_COLORS = {color["colorId"]: (color["rgb"]["r"], color["rgb"]["g"], color["rgb"]["b"]) for color in TERM_COLORS} +print(EXTENDED_COLORS) \ No newline at end of file diff --git a/rich/console.py b/rich/console.py new file mode 100644 index 00000000..b32129fa --- /dev/null +++ b/rich/console.py @@ -0,0 +1,306 @@ +from __future__ import annotations + + +from collections import ChainMap +from contextlib import contextmanager +from dataclasses import dataclass +from enum import Enum +import re +import shutil +import sys +from typing import ( + Any, + Dict, + IO, + Iterable, + List, + Optional, + NamedTuple, + overload, + Protocol, + runtime_checkable, + Union, +) + +from .default_styles import DEFAULT_STYLES +from . import errors +from .style import Style + + +@dataclass +class ConsoleOptions: + """Options for __console__ method.""" + + max_width: int + min_width: int = 1 + + +@runtime_checkable +class SupportsConsole(Protocol): + def __console__(self) -> StyledText: + ... + + +class SupportsStr(Protocol): + def __str__(self) -> str: + ... + + +@runtime_checkable +class ConsoleRenderable(Protocol): + """An object that supports the console protocol.""" + + def __console_render__( + self, console: Console, options: ConsoleOptions + ) -> Iterable[Union[SupportsConsole, StyledText]]: + ... + + +class StyledText(NamedTuple): + """A piece of text with associated style.""" + + text: str + style: Optional[Style] = None + + def __repr__(self) -> str: + """Simplified repr.""" + return f"StyleText({self.text!r}, {self.style!r})" + + +class ConsoleDimensions(NamedTuple): + """Size of the terminal.""" + + width: int + height: int + + +class StyleContext: + """A context manager to manage a style.""" + + def __init__(self, console: Console, style: Style): + self.console = console + self.style = style + + def __enter__(self) -> Console: + self.console._enter_buffer() + self.console.push_style(self.style) + return self.console + + def __exit__(self, exc_type, exc_value, traceback) -> None: + self.console.pop_style() + self.console._exit_buffer() + + +class Console: + """A high level console interface.""" + + default_style = Style.reset() + + def __init__(self, styles: Dict[str, Style] = DEFAULT_STYLES, file: IO = None): + self._styles = ChainMap(styles) + self.file = file or sys.stdout + self.style_stack: List[Style] = [Style()] + self.buffer: List[StyledText] = [] + self.current_style = Style() + self._buffer_index = 0 + + # def push_styles(self, styles: Dict[str, Style]) -> None: + # """Push a new set of styles on to the style stack. + + # Args: + # styles (Dict[str, Style]): A mapping of styles. + + # """ + # self._styles.maps.insert(0, styles) + + # def pop_styles(self) -> None: + # if len(self._styles.maps) == 1: + # raise StyleError("Can't pop default styles") + # self._styles.maps.pop(0) + + def _enter_buffer(self) -> None: + self._buffer_index += 1 + + def _exit_buffer(self) -> None: + self._buffer_index -= 1 + self._check_buffer() + + def __enter__(self) -> Console: + self._enter_buffer() + return self + + def __exit__(self, exc_type, exc_value, traceback) -> None: + self._exit_buffer() + + def get_style(self, name: str) -> Optional[Style]: + """Get a named style, or `None` if it doesn't exist. + + Args: + name (str): The name of a style. + + Returns: + Optional[Style]: A Style object for the given name, or `None`. + """ + return self._styles.get(name, None) + + def push_style(self, style: Union[str, Style]) -> None: + """Push a style on to the stack. + + The new style will be applied to all `write` calls, until + `pop_style` is called. + + Args: + style (Union[str, Style]): New style to merge with current style. + + Returns: + None: [description] + """ + if isinstance(style, str): + style = Style.parse(style) + self.current_style = self.current_style.apply(style) + self.style_stack.append(self.current_style) + + def pop_style(self) -> Style: + """Pop a style from the stack. + + This will revert to the style applied prior to the corresponding `push_style`. + + Returns: + Style: The previously applied style. + """ + if len(self.style_stack) == 1: + raise errors.StyleStackError( + "Can't pop the default style (check there is `push_style` for every `pop_style`)" + ) + style = self.style_stack.pop() + self.current_style = self.style_stack[-1] + return style + + def style(self, style: Union[str, Style]) -> StyleContext: + """A context manager to apply a new style. + + Example: + with context.style("bold red"): + context.print("Danger Will Robinson!") + + Args: + style (Union[str, Style]): New style to apply. + + Returns: + StyleContext: A style context manager. + """ + if isinstance(style, str): + style = Style.parse(style) + return StyleContext(self, style) + + def write(self, text: str, style: str = None) -> None: + """Write text in the current style. + + Args: + text (str): Text to write + + Returns: + None: + """ + write_style = self.current_style or self.get_style(style) + self.buffer.append(StyledText(text, write_style)) + self._check_buffer() + + def print(self, *objects: Union[ConsoleRenderable, SupportsStr]) -> None: + options = ConsoleOptions(max_width=self.width) + buffer_append = self.buffer.append + with self: + for console_object in objects: + if isinstance(console_object, ConsoleRenderable): + render = console_object.__console_render__(self, options) + for console_output in render: + if isinstance(console_output, SupportsConsole): + styled_text = console_output.__console__() + else: + styled_text = console_output + buffer_append(styled_text) + else: + styled_text = StyledText(str(console_object), None) + buffer_append(styled_text) + buffer_append(StyledText("\n")) + + def _check_buffer(self) -> None: + """Check if the buffer may be rendered.""" + if self._buffer_index == 0: + text = self._render_buffer() + self.file.write(text) + + def _render_buffer(self) -> str: + """Render buffered output, and clear buffer.""" + output: List[str] = [] + append = output.append + for text, style in self.buffer: + if style: + append(style.render(text, reset=True)) + else: + append(text) + rendered = "".join(output) + del self.buffer[:] + return rendered + + @property + def size(self) -> ConsoleDimensions: + """Get the size of the console. + + Returns: + ConsoleDimensions: A named tuple containing the dimensions. + """ + width, height = shutil.get_terminal_size() + return ConsoleDimensions(width, height) + + @property + def width(self) -> int: + """Get the width of the console. + + Returns: + int: The width (in characters) of the console. + """ + width, _ = shutil.get_terminal_size() + return width + + # def write(self, console_object: Any) -> Console: + # if isinstance(console_object, SupportsConsole): + # return self.write_object(console_object) + # else: + # text = str(console_object) + # return self.write_text(text) + + # def write_object(self, console_object: SupportsConsole) -> Console: + # console_object.__console__(self) + # return self + + # def write_text( + # self, text: str, style: Union[str, Style] = None, *, end="\n" + # ) -> Console: + # if isinstance(style, str): + # render_style = Style.parse(style) + # elif isinstance(style, Style): + # render_style = style + + # prefix = render_style.render(Style()) + # self.file.write(f"{prefix}{text}\x1b[0m{end}") + # return self + + # def new_line(self) -> Console: + # return self + + +if __name__ == "__main__": + console = Console() + # console.write_text("Hello", style="bold magenta on white", end="").write_text( + # " World!", "italic blue" + # ) + # "[b]This is bold [style not bold]This is not[/style] this is[/b]" + + console.write("Hello ") + with console.style("bold blue"): + console.write("World ") + with console.style("italic"): + console.write("in style") + console.write("!") + diff --git a/rich/default_styles.py b/rich/default_styles.py new file mode 100644 index 00000000..4e67efe1 --- /dev/null +++ b/rich/default_styles.py @@ -0,0 +1,51 @@ +from typing import Dict + +from .style import Style + +DEFAULT_STYLES: Dict[str, Style] = { + "none": Style(), + "reset": Style.reset(), + "dim": Style(dim=True), + "bright": Style(dim=False), + "bold": Style(bold=True), + "b": Style(bold=True), + "italic": Style(italic=True), + "i": Style(italic=True), + "underline": Style(underline=True), + "u": Style(underline=True), + "blink": Style(blink=True), + "blink2": Style(blink2=True), + "reverse": Style(reverse=True), + "strike": Style(strike=True), + "s": Style(strike=True), + "black": Style(color="black"), + "red": Style(color="red"), + "green": Style(color="green"), + "yellow": Style(color="yellow"), + "magenta": Style(color="magenta"), + "cyan": Style(color="cyan"), + "white": Style(color="white"), + "on_black": Style(back="black"), + "on_red": Style(back="red"), + "on_green": Style(back="green"), + "on_yellow": Style(back="yellow"), + "on_magenta": Style(back="magenta"), + "on_cyan": Style(back="cyan"), + "on_white": Style(back="white"), +} + +MARKDOWN_STYLES = { + "markdown.text": Style(), + "markdown.emph": Style(italic=True), + "markdown.strong": Style(bold=True), + "markdown.code": Style(dim=True), + "markdown.code_block": Style(dim=True), + "markdown.heading1": Style(bold=True), + "markdown.heading2": Style(bold=True, dim=True), + "markdown.heading3": Style(bold=True), + "markdown.heading4": Style(bold=True), + "markdown.heading5": Style(bold=True), + "markdown.heading6": Style(bold=True), + "markdown.heading7": Style(bold=True), +} +DEFAULT_STYLES.update(MARKDOWN_STYLES) diff --git a/rich/errors.py b/rich/errors.py new file mode 100644 index 00000000..fc3bed53 --- /dev/null +++ b/rich/errors.py @@ -0,0 +1,18 @@ +class ConsoleError(Exception): + """An error in console operation.""" + + +class StyleError(Exception): + """An error in styles.""" + + +class StyleSyntaxError(ConsoleError): + """Style was badly formatted.""" + + +class MissingStyle(StyleError): + """No such style.""" + + +class StyleStackError(ConsoleError): + """Style stack is invalid.""" diff --git a/rich/escape.py b/rich/escape.py new file mode 100644 index 00000000..e48eceab --- /dev/null +++ b/rich/escape.py @@ -0,0 +1,10 @@ +ESC = "\x1b" +CSI = f"{ESC}[" + +BOLD = f"{CSI}21m" + +import sys + +sys.stdout.write(BOLD) + +sys.stdout.write("hello world") diff --git a/rich/markdown.py b/rich/markdown.py new file mode 100644 index 00000000..52b41d37 --- /dev/null +++ b/rich/markdown.py @@ -0,0 +1,83 @@ +from dataclasses import dataclass +from typing import Dict, Iterable, List, Optional + +from commonmark.blocks import Parser + +from .console import Console, ConsoleOptions, StyledText +from .style import Style + + +@dataclass +class MarkdownHeading: + """A Markdown document heading.""" + + text: str + level: int + width: int + + def __console__(self) -> str: + pass + + +class Markdown: + """Render markdown to the console.""" + + def __init__(self, markup): + self.markup = markup + + def __console_render__( + self, console: Console, options: ConsoleOptions + ) -> Iterable[StyledText]: + + width = options.max_width + parser = Parser() + + nodes = parser.parse(self.markup).walker() + + rendered: List[StyledText] = [] + append = rendered.append + stack = [Style()] + + style: Optional[Style] + for current, entering in nodes: + node_type = current.t + if node_type == "text": + style = stack[-1].apply(console.get_style("markdown.text")) + append(StyledText(current.literal, style)) + elif node_type == "paragraph": + if not entering: + append(StyledText("\n\n", stack[-1])) + else: + if entering: + style = console.get_style(f"markdown.{node_type}") + if style is not None: + stack.append(stack[-1].apply(style)) + else: + stack.append(stack[-1]) + if current.literal: + append(StyledText(current.literal, stack[-1])) + else: + stack.pop() + + print(rendered) + return rendered + + +markup = """*hello*, **world**! + +# Hi + +```python +code +``` + +""" + +if __name__ == "__main__": + from .console import Console + + console = Console() + md = Markdown(markup) + + console.print(md) + # print(console.render_spans()) diff --git a/rich/style.py b/rich/style.py new file mode 100644 index 00000000..72e4f630 --- /dev/null +++ b/rich/style.py @@ -0,0 +1,252 @@ +from __future__ import annotations + +from dataclasses import dataclass, field, replace, InitVar +from functools import lru_cache +import sys +from typing import Dict, Iterable, List, Mapping, Optional + +from . import errors +from .color import Color + + +@dataclass +class Style: + """A terminal style.""" + + color: Optional[str] = None + back: Optional[str] = None + bold: Optional[bool] = None + dim: Optional[bool] = None + italic: Optional[bool] = None + underline: Optional[bool] = None + blink: Optional[bool] = None + blink2: Optional[bool] = None + reverse: Optional[bool] = None + strike: Optional[bool] = None + + _color: Optional[Color] = field(init=False, default=None, repr=False) + _back: Optional[Color] = field(init=False, default=None, repr=False) + + def __str__(self) -> str: + """Re-generate style definition from attributes.""" + attributes: List[str] = [] + append = attributes.append + if self.bold is not None: + append("bold" if self.bold else "not bold") + if self.dim is not None: + append("dim" if self.dim else "not dim") + if self.italic is not None: + append("italic" if self.italic else "not italic") + if self.underline is not None: + append("underline" if self.underline else "not underline") + if self.blink is not None: + append("blink" if self.blink else "not blink") + if self.blink2 is not None: + append("blink2" if self.blink2 else "not blink2") + if self.reverse is not None: + append("reverse" if self.reverse else "not reverse") + if self.strike is not None: + append("strike" if self.strike else "not strike") + if self._color is not None: + append(self._color.name) + if self._back is not None: + append("on") + append(self._back.name) + return " ".join(attributes) or "none" + + def __repr__(self): + return f"