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:

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.