Ansi Module β
Provides the S and Term classes for typed, operator-based terminal styling,
as well as terminal cursor and screen control.
The Easy Styling β
First, let's take a look at a small example of what a highly styled output could look like using this module:
S(
("First normal & unstyled text. ", (S.BOLD | S.UNDERLINE | S.BR.GREEN)("Bright green, bold, and underlined text.")),
((S.hex("#000") | S.BG.hex("#A8F"))("Black text with a purple background."), " And then ", S.ITALIC("(boring)"), " plain text again."),
sep="\n",
).print()First normal & unstyled text. Bright green, bold, and underlined text.
Black text with a purple background. And then (boring) plain text again.How all of this exactly works is explained in the sections below. π «
Styles and Groups β
In this module, you apply styles and colors using S attributes.
Every style attribute supports two operators:
|combines two or more styles into a single immutable group, e.g.,S.BOLD | S.REDβββbold + red foreground()applies the style (or group) to the given text and auto-resets the style after it, e.g.,S.BOLD("hello")βββbold "hello", reset back to normal afterwards(S.BOLD | S.RED)("hello")βββsame idea, combined
A list of all possible style attributes can be found below.
Auto Resetting Styles β
Every _Style, _StyleGroup, _ColorStyle or _Link call automatically generates the
matching reset sequence behind its text, just like shown in the following example:
S(
("This is plain text, ", S.BR.BLUE("which is bright blue now.")),
"Now it was automatically reset to plain again.",
sep="\n",
).print()This is plain text, which is bright blue now.
Now it was automatically reset to plain again.Only the specific styles that were applied are reset; other styling in scope is left intact:
S.CYAN(
"This is cyan text, ", S.DIM("which is dimmed now."),
"\nNow it's not dimmed anymore but still cyan.",
).print()This is cyan text, which is dimmed now.
Now it's not dimmed anymore but still cyan.Bare (Open-Only) Styles β
Passing a style object without calling it emits only its opening ANSI sequence at that position,
with no matching close/reset appended.
This is the typed equivalent of [β¦] (open bracket without closing braces) from the legacy string syntax:
[ERROR] Something went wrong! Back to normal.Any style type supports bare usage: S.RED (_Style), S.hex("#A8F") (_ColorStyle),
S.link("url") (_Link), and S.BOLD | S.RED (_StyleGroup).
Bare styles can also appear inside tuples and nested calls:
aBcNesting and Multi-Segment Groups β
A style call accepts either a single piece of text or any number of mixed segments.
Strings, S objects, bare style objects, and raw tuples can be mixed freely:
S.X("text")β ApplyXto"text", auto-reset after.S.X | S.Yβ CombineXandYinto a single group.(S.X | S.Y)("text")β Apply the group to"text".S.X("a", S.Y("b"), "c")β Nested multi-segment:Yis applied only to"b".S.Xβ Bare: emit only the opening sequence, no auto-reset.("a", S.X("b"), "c")β Same-line group; passed as a single tuple toS(β¦).
Inside S(*segments, sep="\n"), every positional argument is treated as one logical line and joined by sep.
An empty string argument "" therefore produces a blank line.
All Possible Style Attributes β
- Text styles:
S.BOLDS.DIMS.ITALICS.UNDERLINES.INVERSES.BLINKS.HIDDENS.STRIKES.DOUBLE_UNDERLINE
- Standard foreground colors:
S.BLACK,S.RED,S.GREEN,S.YELLOW,S.BLUE,S.MAGENTA,S.CYAN,S.WHITE
- Bright foreground colors (
S.BR.*):S.BR.BLACK,S.BR.RED,S.BR.GREEN, β¦
- Standard background colors (
S.BG.*):S.BG.BLACK,S.BG.RED,S.BG.GREEN, β¦
- Bright background colors (
S.BG.BR.*):S.BG.BR.RED,S.BG.BR.GREEN, β¦
- 24-bit true-color (foreground / background):
S.rgb(255, 96, 112)S.hex("#FF6070")orS.hex("F67")S.BG.rgb(0, 100, 255)S.BG.hex("#0064FF")orS.BG.hex("06F")
- 256-color palette (foreground / background):
S.color256(210)S.BG.color256(69)
- Hyperlinks (OSC 8):
S.link("https://example.com")("click here")(S.link("β¦") | S.BR.BLUE)("click here")
- Specific resets (only needed in advanced use; auto-reset usually covers it):
S.RESET_BOLD,S.RESET_DIM,S.RESET_ITALIC,S.RESET_UNDERLINE,S.RESET_BLINK,S.RESET_INVERSE,S.RESET_HIDDEN,S.RESET_STRIKE,S.RESET_FG,S.RESET_BG
- Total reset (resets every previously applied styles):
S.RESET
Terminal Control β the Term class β
Term exposes commonly used non-styling ANSI sequences for cursor- and screen-control.
These are plain strings (or string-returning helpers),
so they can be passed directly into a S(β¦) call or written to sys.stdout:
CLEAR_LINEβ Erase the entire current line.CLEAR_LINE_TO_ENDβ Erase from the cursor to the end of the line.CLEAR_LINE_TO_STARTβ Erase from the line start to the cursor.CLEAR_SCREENβ Erase the whole screen.CLEAR_SCREEN_TO_ENDβ Erase from the cursor to the end of the screen.CLEAR_SCREEN_TO_STARTβ Erase from the screen start to the cursor.CLEAR_SCROLLBACKβ Erase the scrollback buffer.CUR_HIDE/CUR_SHOWβ Hide/show the cursor.CUR_HOMEβ Move cursor to home position (0, 0).CUR_SAVE/CUR_RESTOREβ Save/restore cursor position (ANSI.SYS).CUR_SAVE_DEC/CUR_RESTORE_DECβ Save/restore cursor position (DEC ESC 7/8).ALT_SCREENβ Enter the alternate screen buffer.MAIN_SCREENβ Leave the alternate screen buffer.BELLβ Terminal bell signal (\x07).up(n)β Move the cursor up bynrows.down(n)β Move the cursor down bynrows.right(n)β Move the cursor right byncolumns.left(n)β Move the cursor left byncolumns.row(row)β Move the cursor to an absolute row position (1-based, VPA).col(col)β Move the cursor to an absolute column position (1-based, CHA).move(row, col)β Move the cursor to an absolute(row, col)position.scroll_up(n)β Scroll page up bynlines.scroll_down(n)β Scroll page down bynlines.title(text)β Set the terminal window / tab title (OSC 2).cursor_shape(shape)β Change cursor shape (DECSCUSR 1-6).clipboard_copy(text)β Copy text to system clipboard via OSC 52.cwd(path)β Notify terminal of current working directory via OSC 7.
ColorInput β
Supported color representations for ANSI gradient styles.
GradientStop β
type GradientStop = ColorInput | tuple[ColorInput, float | int]A color stop for ANSI gradients: a color or a (color, position) tuple.
S β
class S(self, /, *segments: Renderable, sep: str = "", _reset_codes: tuple[int, ...] = )Build a styled string from a sequence of segments
(strings, S objects, bare styles, or raw tuples), joined by sep,
or use class-level style attributes and methods to apply ANSI styling.
segmentsβ Any number of segments to render. Each positional argument represents one logical line.sepβ The separator inserted between two adjacent positional arguments (default"").
After construction the instance exposes:
ansiβ The fully rendered ANSI escape string, ready to be written to a terminal.rawβansiwith every ANSI escape sequence stripped (computed on demand).code_positionsβ A tuple of(position, sequence)pairs giving the start offset of every ANSI escape sequence insideansi(computed on demand).
Every style attribute supports | for combining and () for applying to text.
Example Usage β
from xulbux import S
# Combine styles using operator `|`:
status = (S.BOLD | S.BR.GREEN)("SUCCESS")
# Nesting and joining styled items:
header = S(S.BOLD("Options: "), S(", ").join([S.CYAN("fast"), S.CYAN("safe")]))
# Direct terminal printing:
status.print().join() β
def join(self, iterable: Iterable[Renderable], /) -> S.ljust() β
def ljust(self, width: int, fill_char: Renderable = " ", /) -> S.rjust() β
def rjust(self, width: int, fill_char: Renderable = " ", /) -> S.center() β
def center(self, width: int, fill_char: Renderable = " ", /) -> S.wrap() β
def wrap(self, width: int, /) -> list[S]Wrap the object to fit within a given line width (in visible characters), preserving ANSI styling across all wrapped lines.
widthβ The maximum visible width of each line.
.print() β
def print(self, /, *, end: str = "\n", flush: bool = True, file: TextIO | None = None) -> NoneWrite the rendered ANSI string straight to sys.stdout
(configuring the terminal for ANSI on first use) or to a custom file-like object.
endβ The string to append at the end of the output (default"\n").flushβ Whether to flush the output stream after writing (defaultTrue).fileβ The file-like object to write to (defaultsys.stdout).
Example Usage β
S.GREEN("Operation successful!").print()Operation successful!.input() β
def input(self, /, *, reset_ansi: bool = False) -> str.RESET_BOLD β
RESET_BOLD: ClassVar[_Style] = _Style(22)Reset bold (also resets dim, as they share the same code).
.RESET_DIM β
RESET_DIM: ClassVar[_Style] = _Style(22)Reset dim (also resets bold, as they share the same code).
.RESET_UNDERLINE β
RESET_UNDERLINE: ClassVar[_Style] = _Style(24)Reset underline and double underline.
.RESET_STRIKETHROUGH β
RESET_STRIKETHROUGH: ClassVar[_Style] = _Style(29)Reset strikethrough.
.BOLD β
BOLD: ClassVar[_Style] = _Style(1)Bold text.
Note that this is also reset by RESET_DIM.
.DIM β
DIM: ClassVar[_Style] = _Style(2)Dim text.
Note that this is also reset by RESET_BOLD.
.INVERSE β
INVERSE: ClassVar[_Style] = _Style(7)Inverse colors (swap foreground and background colors).
.BR β
BR: ClassVar[type[_BrNS]] = _BrNS.BG β
BG: ClassVar[type[_BgNS]] = _BgNS.rgb() β
def rgb(*args: Any) -> _FgColorStyle24-bit foreground color from RGB components or an rgba object.
S.rgb(170, 136, 255)("text") or S.rgb(my_rgba)("text")
.hex() β
def hex(color: str | int | hexa, /) -> _FgColorStyle24-bit foreground color from hex string, hex integer, or hexa object.
S.hex("#A8F")("text"), S.hex(0xAA88FF), or S.hex(my_hexa)("text")
.color256() β
def color256(code: int, /) -> _FgColor256Style256-color palette foreground color (code in range [0, 255] inclusive).
S.color256(196)("text")
.link() β
def link(url: str | Path, /) -> _Link.gradient() β
def gradient(
*colors: GradientStop | Sequence[GradientStop],
angle: float | int = 0.0,
space: Literal["rgb", "hsl", "hsl_long", "linear_rgb", "oklab"] = "hsl",
granularity: Literal["char", "word", "line"] = "char",
skip_whitespace: bool = True,
cell_aspect_ratio: float = 2.0,
color_depth: Literal["truecolor", "256", "auto"] = "auto",
) -> _GradientStyleCreate a gradient style that smoothly transitions colors across text or terminal blocks.
colorsβ Sequence of colors or(color, position)tuples defining the gradient stops.angleβ Direction angle in degrees (0.0= left-to-right,90.0= top-to-bottom,180.0= right-to-left,270.0= bottom-to-top,45.0= top-left to bottom-right).spaceβ Color space to interpolate in ("rgb","hsl","hsl_long","linear_rgb", or"oklab"). Default is"hsl".granularityβ Coloring granularity ("char","word", or"line").skip_whitespaceβ Whether to skip emitting color escape sequences over whitespace.cell_aspect_ratioβ Font cell aspect ratio for 2D geometry correction (default2.0).color_depthβ Color mode ("truecolor","256", or"auto").
Raises ValueError if colors is empty or any option is invalid.
FgColorStyle β
type FgColorStyle = _FgStyle | _FgColorStyle | _FgColor256StyleA single foreground color style code (e.g., S.RED, S.BR.BLUE, S.hex("#A8F"), S.color256(196)).
Excludes background colors and non-color styles like S.BOLD.
is_fg_color_style() β
def is_fg_color_style(obj: object, /) -> TypeIs[FgColorStyle]Returns true if obj is an instance that matches the FgColorStyle type.
BgColorStyle β
type BgColorStyle = _BgStyle | _BgColorStyle | _BgColor256StyleA single background color style code (e.g., S.BG.RED, S.BG.hex("#A8F"), S.BG.color256(196)).
Excludes foreground colors and non-color styles like S.BOLD.
is_bg_color_style() β
def is_bg_color_style(obj: object, /) -> TypeIs[BgColorStyle]Returns true if obj is an instance that matches the BgColorStyle type.
ColorStyle β
type ColorStyle = FgColorStyle | BgColorStyleAny single foreground or background color style code (e.g., S.RED, S.BG.BLUE, S.hex("#A8F")).
Excludes non-color styles like S.BOLD.
is_color_style() β
def is_color_style(obj: object, /) -> TypeIs[ColorStyle]Returns true if obj is an instance that matches the ColorStyle type.
BaseStyle β
type BaseStyle = _Style | _ColorStyle | _Color256Style | _GradientStyle | _LinkAny single style code, color style, link, or gradient style that can be combined via | and applied to text.
is_base_style() β
def is_base_style(obj: object, /) -> TypeIs[BaseStyle]Returns true if obj is an instance that matches the BaseStyle type.
AnyStyle β
type AnyStyle = BaseStyle | _StyleGroupAny single style or group of styles that can be combined via | and applied to text.
is_any_style() β
def is_any_style(obj: object, /) -> TypeIs[AnyStyle]Returns true if obj is an instance that matches the AnyStyle type.
TextSegment β
type TextSegment = str | SA single segment that contains actual text: a plain string or a styled S object.
Strictly excludes bare style objects (e.g., S.RED, S.BOLD | S.BLUE) that do not contain text.
is_text_segment() β
def is_text_segment(obj: object, /) -> TypeIs[TextSegment]Returns true if obj is an instance that matches the TextSegment type (has actual text).
RenderSegment β
type RenderSegment = str | _SBaseA single segment: a plain string, a bare style object (open-only), or a styled S object.
is_render_segment() β
def is_render_segment(obj: object, /) -> TypeIs[RenderSegment]Returns true if obj is an instance that matches the RenderSegment type.
TextRenderable β
type TextRenderable = TextSegment | tuple[TextRenderable, ...]Anything that contains actual textual content to be rendered, strictly excluding bare styles.
Can be passed to a _Style call, or as a positional argument to S(β¦). Can be arbitrarily nested in tuples.
is_text_renderable() β
def is_text_renderable(obj: object, /) -> TypeIs[TextRenderable]Returns true if obj is an instance that matches the TextRenderable type.
Renderable β
type Renderable = RenderSegment | tuple[Renderable, ...]Anything that can be styled or rendered.
Can be passed to a _Style call, or as a positional argument to S(β¦). Can be arbitrarily nested in tuples.
is_renderable() β
def is_renderable(obj: object, /) -> TypeIs[Renderable]Returns true if obj is an instance that matches the Renderable type.
Term β
class TermCommon ANSI terminal control sequences (cursor, screen, title, clipboard, modes) as plain strings or string-returning static methods.
Values can be passed straight into an S(β¦) call or written to sys.stdout.
Example Usage β
import sys
from xulbux import Term
# Switch to alternate screen and hide cursor:
sys.stdout.write(Term.ALT_SCREEN + Term.CUR_HIDE)
sys.stdout.flush()
# Move cursor up 2 rows and clear line:
sys.stdout.write(Term.up(2) + Term.CLEAR_LINE)
sys.stdout.flush()
# Restore main screen and cursor:
sys.stdout.write(Term.CUR_SHOW + Term.MAIN_SCREEN)
sys.stdout.flush().BELL β
BELL: ClassVar[str] = "\x07"Terminal bell character to trigger an audio or visual alert.
.CLEAR_LINE_TO_END β
CLEAR_LINE_TO_END: ClassVar[str] = "\x1b[0K"Erase from the cursor to the end of the current line.
.CLEAR_LINE_TO_START β
CLEAR_LINE_TO_START: ClassVar[str] = "\x1b[1K"Erase from the beginning of the line up to the cursor.
.CLEAR_SCREEN_TO_END β
CLEAR_SCREEN_TO_END: ClassVar[str] = "\x1b[0J"Erase from the cursor to the end of the screen.
.CLEAR_SCREEN_TO_START β
CLEAR_SCREEN_TO_START: ClassVar[str] = "\x1b[1J"Erase from the beginning of the screen up to the cursor.
.CLEAR_SCROLLBACK β
CLEAR_SCROLLBACK: ClassVar[str] = "\x1b[3J"Erase the terminal scrollback history buffer.
.CUR_HOME β
CUR_HOME: ClassVar[str] = "\x1b[H"Move the cursor to the home position (0,0) (CUP/HVP).
.CUR_SAVE β
CUR_SAVE: ClassVar[str] = "\x1b[s"Save the current cursor position (ANSI.SYS / SCO).
.CUR_RESTORE β
CUR_RESTORE: ClassVar[str] = "\x1b[u"Restore the previously saved cursor position (ANSI.SYS / SCO).
.CUR_SAVE_DEC β
CUR_SAVE_DEC: ClassVar[str] = "\x1b7"Save cursor position and attributes (DEC private sequence ESC 7).
.CUR_RESTORE_DEC β
CUR_RESTORE_DEC: ClassVar[str] = "\x1b8"Restore cursor position and attributes (DEC private sequence ESC 8).
.MAIN_SCREEN β
MAIN_SCREEN: ClassVar[str] = "\x1b[?1049l"Leave the alternate screen buffer.
.BRACKETED_PASTE_ENABLE β
BRACKETED_PASTE_ENABLE: ClassVar[str] = "\x1b[?2004h"Enable bracketed paste mode (wraps pasted text in paste brackets).
.BRACKETED_PASTE_DISABLE β
BRACKETED_PASTE_DISABLE: ClassVar[str] = "\x1b[?2004l"Disable bracketed paste mode.
.LINE_WRAP_ENABLE β
LINE_WRAP_ENABLE: ClassVar[str] = "\x1b[?7h"Enable line wrapping (DECAWM).
.LINE_WRAP_DISABLE β
LINE_WRAP_DISABLE: ClassVar[str] = "\x1b[?7l"Disable line wrapping (DECAWM).
.SOFT_RESET β
SOFT_RESET: ClassVar[str] = "\x1b[!p"Soft terminal reset to sensible defaults (DECSTR).
.prev_line() β
def prev_line(n: int = 1, /) -> strMove the cursor to the beginning of the previous line, n lines up.
.next_line() β
def next_line(n: int = 1, /) -> strMove the cursor to the beginning of the next line, n lines down.
.row() β
def row(row: int = 1, /) -> strMove the cursor to absolute row row in the current column (1-based, VPA).
.col() β
def col(col: int = 1, /) -> strMove the cursor to absolute column col in the current row (1-based, CHA).
.move() β
def move(row: int, col: int, /) -> strMove the cursor to absolute position (row, col) (1-based, CUP).
.insert_lines() β
def insert_lines(n: int = 1, /) -> strInsert n blank lines at the current row (IL).
.delete_lines() β
def delete_lines(n: int = 1, /) -> strDelete n lines starting from the current row (DL).
.insert_chars() β
def insert_chars(n: int = 1, /) -> strInsert n blank characters at the current cursor position (ICH).
.delete_chars() β
def delete_chars(n: int = 1, /) -> strDelete n characters at the current cursor position (DCH).
.cursor_shape() β
def cursor_shape(
shape: Literal[
1,
2,
3,
4,
5,
6,
"blinking_block",
"steady_block",
"blinking_underline",
"steady_underline",
"blinking_bar",
"steady_bar",
],
/,
) -> strSet the terminal cursor shape (DECSCUSR).
shapeβ An integer in range [1, 6] inclusive, or a string name of the shape:1"blinking_block"2"steady_block"3"blinking_underline"4"steady_underline"5"blinking_bar"6"steady_bar"
.clipboard_copy() β
def clipboard_copy(text: str, /) -> strCopy text to the system clipboard (OSC 52).
.cwd() β
def cwd(path: str | Path, /) -> strNotify the terminal of the current working directory (OSC 7).