Customizing
Sty allows you to change or to extend the default registers as you like. You can also create a complete new register. More on these things in the following chapters.
Caution
If you use sty for a library that is shared among other projects, I highly suggest not to customize the “global” register-objects (sty.fg ,sty.bg, sty.ef, sty.rs) directly, because that might cause conflicts with other packages that share the same sty dependency.
If you want to customize sty’s register-objects in a library you should either:
Use the copy method to create copies of them, which you can customize safely.
Create custom register-classes and create new customized register-objects from them.
Add custom styles to a register-object
In order to add new or update existing styles for a register-object, you can simply assing a new styling rule to an attribute:
Example:
from sty import RgbFg, Sgr, Style, ef, fg, rs
fg.my_red = Style(RgbFg(255, 0, 0))
a = fg.my_red + "This text has red fg." + fg.rs
print(a)
There are multiple Render Types that you can use to define different styles.
The Style()
type allows you to compose styles from multiple new rules, as well as from existing register-objects:
from sty import RgbFg, Sgr, Style, ef, fg, rs
fg.blue_bold = Style(RgbFg(0, 100, 200), Sgr(1))
fg.green_italic = Style(fg.green, ef.i)
a = fg.blue_bold + "This text has bold blue fg." + rs.all
b = fg.green_italic + "This text has italic green fg" + rs.all
print(a, b, sep="\n")
Render Types
These are the render-types, which you can use to create custom styles:
- class sty.Sgr(num)[source]
Define SGR styling rule.
More info about SGR parameters: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR
- Parameters
num (
int
) – A SGR number.
- class sty.EightbitFg(num)[source]
Define Eightbit Foreground.
More info about 8-bit terminal colors: https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
- Parameters
num (
int
) – Eightbit number.
- class sty.EightbitBg(num)[source]
Define Eightbit Background.
More info about 8-bit terminal colors: https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
- Parameters
num (
int
) – Eightbit number.
- class sty.RgbFg(r, g, b)[source]
Define RGB Foreground.
More info about 24-bit terminal colors: https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit
- Parameters
r (
int
) – Red.g (
int
) – Green.b (
int
) – Blue.
- class sty.RgbBg(r, g, b)[source]
Define RGB Background.
More info about 24-bit terminal colors: https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit
- Parameters
r (
int
) – Red.g (
int
) – Green.b (
int
) – Blue.
Changing the render-functions for a register-object
If you want to fix compatibility issues with old terminals, you might want to customize the render-functions.
- Register.set_renderfunc(rendertype, func)[source]
With this method you can add or replace render-functions for a given register-object:
- Parameters
rendertype (
Type
[RenderType
]) – The render type for which the new renderfunc is used.func (
Callable
) – The new render function.
- Return type
None
Example:
from sty import bg, fg, EightbitFg
def my_eightbit_bg_render_func(num: int) -> str:
return "\033[48;5;" + str(num) + "m"
# Replace fg render-function with the above bg render-function:
fg.set_renderfunc(EightbitFg, my_eightbit_bg_render_func)
a = fg.da_green + "I have a green bg because my render-func was replaced" + bg.rs
print(a)
Changing the __call__
behaviour for a register-object
Remember that you can call the register-objects like a function? You can change the behaviour for such calls.
- Register.set_eightbit_call(rendertype)[source]
You can call a register-object directly. A call like this
fg(144)
is a Eightbit-call. With this method you can define the render-type for such calls.- Parameters
rendertype (
Type
[RenderType
]) – The new rendertype that is used for Eightbit-calls.- Return type
None
- Register.set_rgb_call(rendertype)[source]
You can call a register-object directly. A call like this
fg(10, 42, 255)
is a RGB-call. With this method you can define the render-type for such calls.- Parameters
rendertype (
Type
[RenderType
]) – The new rendertype that is used for RGB-calls.- Return type
None
Example:
from sty import EightbitBg, RgbBg, fg, renderfunc, rs
fg.set_renderfunc(EightbitBg, renderfunc.eightbit_bg)
fg.set_renderfunc(RgbBg, renderfunc.rgb_bg)
fg.set_eightbit_call(EightbitBg)
fg.set_rgb_call(RgbBg)
a = fg(201) + "I have a pink bg since fg was replaced with bg." + rs.all
b = fg(255, 10, 10) + "I have a red bg since fg was replaced with bg." + rs.all
print(a, b, sep="\n")
Extending register-classes and creating new instances
If you want to create a large register of custom styles, it may be convenient to extend the default register-classes and create new register-objects from them.
Customizing sty this way has some advantages:
You get better editor support (auto-completion, mypy, pylint, etc) for the register-objects.
You aren’t mutating sty’s global register-objects (
sty.ef
,sty.fg
, etc.). This is important for library projects to prevent conflicts with other packages that use sty.
from sty import FgRegister, RgbFg, Sgr
# Extend the default foreground register-class.
class MyFgRegister(FgRegister):
def __init__(self):
super().__init__()
# Add custom style attributes.
self.purple = Style(Sgr(35))
self.blue = Style(Sgr(34))
self.orange = Style(RgbFg(255, 128, 0))
# ...
# Create new register-object from extended register-class.
fg = MyFgRegister()
# Use your new register-object.
a = fg.purple + "I have purple foreground" + fg.rs
b = fg.blue + "I have blue foreground" + fg.rs
c = fg.orange + "I have orange foreground" + fg.rs
d = fg.green + "I have a green foreground" + fg.rs
print(a, b, c, d, sep="\n")
A register-class from scratch
This example shows how to create a complete register class from scratch, including custom render-functions:
from sty import EightbitFg, Register, RgbFg, Sgr, renderfunc
def my_eightbit_fg_render_func(num: int) -> str:
return "\033[38;5;" + str(num) + "m"
def my_rgb_fg_render_func(r: int, g: int, b: int) -> str:
return "\x1b[38;2;" + str(r) + ";" + str(g) + ";" + str(b) + "m"
class FgRegister(Register):
def __init__(self):
super().__init__()
self.set_renderfunc(Sgr, renderfunc.sgr)
self.set_renderfunc(EightbitFg, renderfunc.eightbit_fg)
self.set_renderfunc(RgbFg, renderfunc.rgb_fg)
self.set_eightbit_call(EightbitFg)
self.set_rgb_call(RgbFg)
self.red = Style(Sgr(31))
self.green = Style(Sgr(32))
self.rs = Style(Sgr(39))
self.yellow = Style(RgbFg(250, 250, 70))
# ...
# Create new register-object from register-class.
fg = FgRegister()
# Use your new register-object.
a = fg.yellow + "I have yellow foreground" + fg.rs
b = fg.red + "I have red foreground" + fg.rs
c = fg.green + "I have green foreground" + fg.rs
print(a, b, c, sep="\n")
This is exactly how sty’s default register-classes are created.