Created
January 18, 2025 12:35
-
-
Save tkoz0/6648c5ee1573bd1fb5bc424f340a99de to your computer and use it in GitHub Desktop.
improved ansi escape codes for terminal color and text formatting
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
basic utils for ansi escape codes in terminal | |
- foreground color | |
- background color | |
- font styles | |
- 8 bit color | |
- 24 bit rgb color | |
- cursor movement | |
- screen clearing | |
- scrolling | |
''' | |
class _escm: | |
# internal class for ansi escape codes | |
# only supports the 'm' command for text color/format | |
# support concatenations with each other | |
# support concatenations with strings | |
# example: red '\\033[31m' | |
# example: rgb '\\033[38;2;127;255;0m' | |
def __init__(self, *l: int): | |
self.l: tuple[int,...] = l | |
def __eq__(self, l): | |
return isinstance(l,_escm) and self.l == l.l | |
def __str__(self) -> str: | |
return f'\033[{";".join(str(n) for n in self.l)}m' | |
def __repr__(self) -> str: | |
return f'{type(self).__name__}({",".join(str(n) for n in self.l)})' | |
def __iadd__(self, l) -> '_escm': | |
if isinstance(l,_escm): | |
self.l += l.l | |
return self | |
else: | |
return NotImplemented | |
def __add__(self, l) -> '_escm|str': | |
if isinstance(l,str): | |
return str(self) + l | |
elif isinstance(l,_escm): | |
return _escm(*self.l,*l.l) | |
else: | |
return NotImplemented | |
def __radd__(self, l) -> '_escm|str': | |
if isinstance(l,str): | |
return l + str(self) | |
elif isinstance(l,_escm): | |
return _escm(*l.l,*self.l) | |
else: | |
return NotImplemented | |
class TEXT_STYLE: | |
''' | |
text styles | |
''' | |
RESET = _escm(0) | |
BOLD = _escm(1) | |
FAINT = _escm(2) | |
ITALIC = _escm(3) | |
ULINE = _escm(4) | |
BLINK_SLOW = _escm(5) | |
BLINK_FAST = _escm(6) | |
INVERT_ON = _escm(7) | |
HIDE_ON = _escm(8) | |
CROSS_ON = _escm(9) | |
ULINE2 = _escm(21) | |
NORM_INTENSITY = _escm(22) | |
NORM_STYLE = _escm(23) | |
ULINE_OFF = _escm(24) | |
BLINK_OFF = _escm(25) | |
INVERT_OFF = _escm(27) | |
HIDE_OFF = _escm(28) | |
CROSS_OFF = _escm(29) | |
@staticmethod | |
def FONT(n: int = 0) -> _escm: | |
''' | |
font style 0-10, probably not supported in terminal | |
''' | |
if n < 0 or n >= 10: | |
raise ValueError() | |
return _escm(10+n) | |
def _fg8(n: int) -> _escm: | |
if n < 0 or n >= 256: | |
raise ValueError() | |
return _escm(38,5,n) | |
def _fg24(r: int, g: int, b: int) -> _escm: | |
if r < 0 or r >= 256 or g < 0 or g >= 256 or b < 0 or b >= 256: | |
raise ValueError() | |
return _escm(38,2,r,g,b) | |
class FG_COLOR: | |
''' | |
foreground colors | |
- 8 colors (3 bit) | |
- bright (B_) colors (extends to 4 bit) | |
''' | |
BLACK = _escm(30) | |
RED = _escm(31) | |
GREEN = _escm(32) | |
YELLOW = _escm(33) | |
BLUE = _escm(34) | |
MAGENTA = _escm(35) | |
CYAN = _escm(36) | |
WHITE = _escm(37) | |
B_BLACK = _escm(90) | |
B_RED = _escm(91) | |
B_GREEN = _escm(92) | |
B_YELLOW = _escm(93) | |
B_BLUE = _escm(94) | |
B_MAGENTA = _escm(95) | |
B_CYAN = _escm(96) | |
B_WHITE = _escm(97) | |
@staticmethod | |
def FG_8(n: int) -> _escm: | |
''' | |
8 bit color value | |
- 0-7 = standard | |
- 8-15 = bright | |
- 16-231 = 6x66 rgb cube (16+36*r+6*g+b with 0<=r,g,b<6) | |
- 232-255 = grayscale (black to white) | |
''' | |
return _fg8(n) | |
@staticmethod | |
def FG_8_GRAY(n: int) -> _escm: | |
''' | |
8 bit gray color (0-23 black to white) | |
''' | |
if n < 0 or n >= 24: | |
raise ValueError() | |
return _fg8(232+n) | |
@staticmethod | |
def FG_8_RGB(r: int, g: int, b: int) -> _escm: | |
''' | |
8 bit rgb color (each component is 0-5) | |
''' | |
if r < 0 or r >= 6 or g < 0 or g >= 6 or b < 0 or b >= 6: | |
raise ValueError() | |
return _fg8(16+36*r+6*g+b) | |
@staticmethod | |
def FG_24(r: int, g: int, b: int) -> _escm: | |
''' | |
standard 24 bit rgb color | |
''' | |
return _fg24(r,g,b) | |
def _bg8(n: int) -> _escm: | |
if n < 0 or n >= 256: | |
raise ValueError() | |
return _escm(48,5,n) | |
def _bg24(r: int, g: int, b: int) -> _escm: | |
if r < 0 or r >= 256 or g < 0 or g >= 256 or b < 0 or b >= 256: | |
raise ValueError() | |
return _escm(48,2,r,g,b) | |
class BG_COLOR: | |
''' | |
background colors | |
- 8 colors (3 bit) | |
- bright (B_) colors (extends to 4 bit) | |
''' | |
BLACK = _escm(40) | |
RED = _escm(41) | |
GREEN = _escm(42) | |
YELLOW = _escm(43) | |
BLUE = _escm(44) | |
MAGENTA = _escm(45) | |
CYAN = _escm(46) | |
WHITE = _escm(47) | |
B_BLACK = _escm(100) | |
B_RED = _escm(101) | |
B_GREEN = _escm(102) | |
B_YELLOW = _escm(103) | |
B_BLUE = _escm(104) | |
B_MAGENTA = _escm(105) | |
B_CYAN = _escm(106) | |
B_WHITE = _escm(107) | |
@staticmethod | |
def BG_8(n: int) -> _escm: | |
''' | |
8 bit color value | |
- 0-7 = standard | |
- 8-15 = bright | |
- 16-231 = 6x66 rgb cube (16+36*r+6*g+b with 0<=r,g,b<6) | |
- 232-255 = grayscale (black to white) | |
''' | |
return _bg8(n) | |
@staticmethod | |
def BG_8_GRAY(n: int) -> _escm: | |
''' | |
8 bit gray color (0-23 black to white) | |
''' | |
if n < 0 or n >= 24: | |
raise ValueError() | |
return _bg8(232+n) | |
@staticmethod | |
def BG_8_RGB(r: int, g: int, b: int) -> _escm: | |
''' | |
8 bit rgb color (each component is 0-5) | |
''' | |
if r < 0 or r >= 6 or g < 0 or g >= 6 or b < 0 or b >= 6: | |
raise ValueError() | |
return _bg8(16+36*r+6*g+b) | |
@staticmethod | |
def BG_24(r: int, g: int, b: int) -> _escm: | |
''' | |
standard 24 bit rgb color | |
''' | |
return _bg24(r,g,b) | |
FG_ARR_BRIGHT = [_escm(n) for n in range(90,98)] | |
FG_ARR_4BIT = [_escm(n) for n in range(30,38)] + FG_ARR_BRIGHT | |
BG_ARR_BRIGHT = [_escm(n) for n in range(100,108)] | |
BG_ARR_4BIT = [_escm(n) for n in range(40,48)] + BG_ARR_BRIGHT | |
class CURSOR: | |
''' | |
cursor movement | |
''' | |
@staticmethod | |
def MOVE_TO(r: int, c: int) -> str: | |
if r < 0 or c < 0: | |
raise ValueError() | |
return f'\033[{r};{c}H' | |
@staticmethod | |
def MOVE_UP(n: int) -> str: | |
if n < 0: | |
raise ValueError() | |
return f'\033[{n}A' | |
@staticmethod | |
def MOVE_DOWN(n: int) -> str: | |
if n < 0: | |
raise ValueError() | |
return f'\033[{n}B' | |
@staticmethod | |
def MOVE_RIGHT(n: int) -> str: | |
if n < 0: | |
raise ValueError() | |
return f'\033[{n}C' | |
@staticmethod | |
def MOVE_LEFT(n: int) -> str: | |
if n < 0: | |
raise ValueError() | |
return f'\033[{n}D' | |
@staticmethod | |
def MOVE_LINE(n: int) -> str: | |
if n == 0: | |
raise ValueError() | |
elif n > 0: | |
return f'\033[{n}E' | |
else: | |
return f'\033[{n}F' | |
@staticmethod | |
def MOVE_COL(n: int) -> str: | |
if n < 0: | |
raise ValueError() | |
return f'\033[{n}G' | |
class CLEAR: | |
''' | |
screen/line clearing | |
''' | |
SCR_TO_END = '\033[0J' | |
SCR_TO_BEG = '\033[1J' | |
SCR_ALL = '\033[2J' | |
SCR_BUF = '\033[3J' | |
LINE_TO_END = '\033[0K' | |
LINE_TO_BEG = '\033[1K' | |
LINE_ALL = '\033[2K' | |
class SCROLL: | |
''' | |
scrolling | |
''' | |
@staticmethod | |
def UP(n: int) -> str: | |
if n < 1: | |
raise ValueError() | |
return f'\033[{n}S' | |
@staticmethod | |
def DOWN(n: int) -> str: | |
if n < 1: | |
raise ValueError() | |
return f'\033[{n}T' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment