From faa0fd9eb6853450147ca83108b7a0764aab6df3 Mon Sep 17 00:00:00 2001 From: rysson Date: Wed, 17 Jan 2024 09:26:08 +0100 Subject: [PATCH] WIP: base underline extension support --- sty/__init__.py | 2 + sty/register.py | 117 ++++++++++++++++++++++++++++++++++++---------- sty/renderfunc.py | 23 +++++++++ sty/rendertype.py | 39 +++++++--------- 4 files changed, 133 insertions(+), 48 deletions(-) diff --git a/sty/__init__.py b/sty/__init__.py index 1aa433e..963a927 100644 --- a/sty/__init__.py +++ b/sty/__init__.py @@ -43,9 +43,11 @@ def __init__(self): from sty.register import EfRegister as EfRegister from sty.register import FgRegister as FgRegister from sty.register import RsRegister as RsRegister +from sty.register import UnderlineRegister as UnderlineRegister from sty.register import bg as bg from sty.register import ef as ef from sty.register import fg as fg from sty.register import rs as rs +from sty.register import ul as ul from sty.rendertype import * diff --git a/sty/register.py b/sty/register.py index 4fdbc74..c6eaeb5 100644 --- a/sty/register.py +++ b/sty/register.py @@ -3,7 +3,7 @@ """ from sty import renderfunc from sty.primitive import Register, Style -from sty.rendertype import EightbitBg, EightbitFg, RgbBg, RgbFg, Sgr +from sty.rendertype import Eightbit, Rgb, Sgr, SgrArgs class EfRegister(Register): @@ -56,11 +56,11 @@ def __init__(self): super().__init__() self.renderfuncs[Sgr] = renderfunc.sgr - self.renderfuncs[EightbitFg] = renderfunc.eightbit_fg - self.renderfuncs[RgbFg] = renderfunc.rgb_fg + self.renderfuncs[Eightbit] = renderfunc.eightbit_fg + self.renderfuncs[Rgb] = renderfunc.rgb_fg - self.set_eightbit_call(EightbitFg) - self.set_rgb_call(RgbFg) + self.set_eightbit_call(Eightbit) + self.set_rgb_call(Rgb) # Classic terminal foreground color preset. # These are well supported. @@ -86,14 +86,14 @@ def __init__(self): self.white = Style(Sgr(97)) # These are least supported. - self.da_black = Style(EightbitFg(0)) - self.da_red = Style(EightbitFg(88)) - self.da_green = Style(EightbitFg(22)) - self.da_yellow = Style(EightbitFg(58)) - self.da_blue = Style(EightbitFg(18)) - self.da_magenta = Style(EightbitFg(89)) - self.da_cyan = Style(EightbitFg(23)) - self.grey = Style(EightbitFg(249)) + self.da_black = Style(Eightbit(0)) + self.da_red = Style(Eightbit(88)) + self.da_green = Style(Eightbit(22)) + self.da_yellow = Style(Eightbit(58)) + self.da_blue = Style(Eightbit(18)) + self.da_magenta = Style(Eightbit(89)) + self.da_cyan = Style(Eightbit(23)) + self.grey = Style(Eightbit(249)) class BgRegister(Register): @@ -112,11 +112,11 @@ def __init__(self): super().__init__() self.renderfuncs[Sgr] = renderfunc.sgr - self.renderfuncs[EightbitBg] = renderfunc.eightbit_bg - self.renderfuncs[RgbBg] = renderfunc.rgb_bg + self.renderfuncs[Eightbit] = renderfunc.eightbit_bg + self.renderfuncs[Rgb] = renderfunc.rgb_bg - self.set_eightbit_call(EightbitBg) - self.set_rgb_call(RgbBg) + self.set_eightbit_call(Eightbit) + self.set_rgb_call(Rgb) # Classic terminal background color preset. # These are well supported. @@ -142,14 +142,80 @@ def __init__(self): self.white = Style(Sgr(107)) # These are least supported. - self.da_black = Style(EightbitBg(0)) - self.da_red = Style(EightbitBg(88)) - self.da_green = Style(EightbitBg(22)) - self.da_yellow = Style(EightbitBg(58)) - self.da_blue = Style(EightbitBg(18)) - self.da_magenta = Style(EightbitBg(89)) - self.da_cyan = Style(EightbitBg(23)) - self.grey = Style(EightbitBg(249)) + self.da_black = Style(Eightbit(0)) + self.da_red = Style(Eightbit(88)) + self.da_green = Style(Eightbit(22)) + self.da_yellow = Style(Eightbit(58)) + self.da_blue = Style(Eightbit(18)) + self.da_magenta = Style(Eightbit(89)) + self.da_cyan = Style(Eightbit(23)) + self.grey = Style(Eightbit(249)) + + +class UnderlineRegister(Register): + """ + The default 'underline register'. + + Instances from this class can be used to create text with colored underlines. + + For example: + + print(f"{ul.red}{ul.on}Red Underline{ul.rs}") + print(f"{ul.green}{ul.on}Green Underline{ul.rs}") + """ + + def __init__(self): + super().__init__() + + self.renderfuncs[Sgr] = renderfunc.sgr + self.renderfuncs[SgrArgs] = renderfunc.sgr_args + self.renderfuncs[Eightbit] = renderfunc.eightbit_underline + self.renderfuncs[Rgb] = renderfunc.rgb_underline + + self.set_eightbit_call(Eightbit) + self.set_rgb_call(Rgb) + + self.on = Style(Sgr(4)) + self.off = Style(Sgr(24)) + self.line = Style(Sgr(4)) + self.double = Style(SgrArgs(4, 2)) + self.curly = Style(SgrArgs(4, 3)) + self.dotted = Style(SgrArgs(4, 4)) + self.dashed = Style(SgrArgs(4, 5)) + + # Classic terminal background color preset. + # These are well supported. + self.black = Style(Eightbit(0)) + self.red = Style(Eightbit(1)) + self.green = Style(Eightbit(2)) + self.yellow = Style(Eightbit(3)) + self.blue = Style(Eightbit(4)) + self.magenta = Style(Eightbit(5)) + self.cyan = Style(Eightbit(6)) + self.li_grey = Style(Eightbit(7)) + + self.rs = Style(Sgr(59), Sgr(24)) + self.default = Style(Sgr(59)) + + # These are less supported. + self.da_grey = Style(Eightbit(8)) + self.li_red = Style(Eightbit(9)) + self.li_green = Style(Eightbit(10)) + self.li_yellow = Style(Eightbit(11)) + self.li_blue = Style(Eightbit(12)) + self.li_magenta = Style(Eightbit(13)) + self.li_cyan = Style(Eightbit(14)) + self.white = Style(Eightbit(15)) + + # These are least supported. + self.da_black = Style(Eightbit(0)) + self.da_red = Style(Eightbit(88)) + self.da_green = Style(Eightbit(22)) + self.da_yellow = Style(Eightbit(58)) + self.da_blue = Style(Eightbit(18)) + self.da_magenta = Style(Eightbit(89)) + self.da_cyan = Style(Eightbit(23)) + self.grey = Style(Eightbit(249)) class RsRegister(Register): @@ -193,3 +259,4 @@ def __init__(self): fg = FgRegister() bg = BgRegister() rs = RsRegister() +ul = UnderlineRegister() diff --git a/sty/renderfunc.py b/sty/renderfunc.py index ddb0b57..1b920a4 100644 --- a/sty/renderfunc.py +++ b/sty/renderfunc.py @@ -13,6 +13,15 @@ def sgr(num: int) -> str: return "\033[" + str(num) + "m" +def sgr_args(*num: int) -> str: + """ + Create a extended SGR escape sequence. + """ + if not num: + raise TypeError("Need at least one argument") + return "\033[" + ":".join(map(str, num)) + "m" + + def eightbit_fg(num: int) -> str: """ Create a 8bit (256-color) foreground escape sequence. @@ -20,6 +29,13 @@ def eightbit_fg(num: int) -> str: return "\033[38;5;" + str(num) + "m" +def eightbit_underline(num: int) -> str: + """ + Create a 8bit (256-color) underline escape sequence. + """ + return "\033[58;5;" + str(num) + "m" + + def eightbit_bg(num: int) -> str: """ Create a 8bit (256-color) background escape sequence. @@ -39,3 +55,10 @@ def rgb_bg(r: int, g: int, b: int) -> str: Create a 24bit (true color) background escape sequence. """ return "\x1b[48;2;" + str(r) + ";" + str(g) + ";" + str(b) + "m" + + +def rgb_underline(r: int, g: int, b: int) -> str: + """ + Create a 24bit (true color) underline escape sequence. + """ + return "\x1b[58;2;" + str(r) + ";" + str(g) + ";" + str(b) + "m" diff --git a/sty/rendertype.py b/sty/rendertype.py index 00e77bc..216ff82 100644 --- a/sty/rendertype.py +++ b/sty/rendertype.py @@ -22,22 +22,23 @@ def __init__(self, num: int): self.args = [num] -class EightbitFg(RenderType): +class SgrArgs(RenderType): """ - Define Eightbit Foreground. + Define SGR styling extended rule, rule with argument. - More info about 8-bit terminal colors: https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit + Example of underline extension: https://sw.kovidgoyal.net/kitty/underlines/ - :param num: Eightbit number. + :param num: A SGR number. + :param args: A list of argument numbers. """ - def __init__(self, num: int): - self.args = [num] + def __init__(self, num: int, *args: int): + self.args = [num, *args] -class EightbitBg(RenderType): +class Eightbit(RenderType): """ - Define Eightbit Background. + Define Eightbit color (foreground, background, underline). More info about 8-bit terminal colors: https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit @@ -48,9 +49,9 @@ def __init__(self, num: int): self.args = [num] -class RgbFg(RenderType): +class Rgb(RenderType): """ - Define RGB Foreground. + Define RGB color (foreground, background, underline). More info about 24-bit terminal colors: https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit @@ -63,16 +64,8 @@ def __init__(self, r: int, g: int, b: int): self.args = [r, g, b] -class RgbBg(RenderType): - """ - Define RGB Background. - - More info about 24-bit terminal colors: https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit - - :param r: Red. - :param g: Green. - :param b: Blue. - """ - - def __init__(self, r: int, g: int, b: int): - self.args = [r, g, b] +# Backward compatibility. +EightbitFg = Eightbit +EightbitBg = Eightbit +RgbFg = Rgb +RgbBg = Rgb