...

Text file src/github.com/emissary-ingress/emissary/v3/releng/lib/ansiterm.py

Documentation: github.com/emissary-ingress/emissary/v3/releng/lib

     1#!/hint/python3
     2"""Generate terminal "control seqences" for ANSI X3.64 terminals.
     3Or rather, ECMA-48 terminals, because ANSI withdrew X3.64 in favor of
     4ECMA-48.
     5(https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf)
     6"control sequences" are a subset of "escape codes"; which are so named
     7because they start with the ASCII ESC character ("\033").
     8If you're going to try to read ECMA-48, be aware the notation they use
     9for a byte is "AB/CD" where AB and CD are zero-padded decimal numbers
    10that represent 4-bit sequences.  It's easiest to think of them as
    11hexadecimal byte; for example, when ECMA-48 says "11/15", think
    12"hexadecimal 0xBF".  And then to make sense of that hexadecimal
    13number, you'll want to have an ASCII reference table handy.
    14This implementation is not complete/exhaustive; it only supports the
    15things that we've found it handy to support.
    16"""
    17
    18from typing import List, Union, cast, overload
    19
    20_number = Union[int, float]
    21
    22
    23@overload
    24def cs(params: List[_number], op: str) -> str:
    25    ...
    26
    27
    28@overload
    29def cs(op: str) -> str:
    30    ...
    31
    32
    33def cs(arg1, arg2=None):  # type: ignore
    34    """cs returns a formatted 'control sequence' (ECMA-48 §5.4).
    35    This only supports text/ASCII ("7-bit") control seqences, and does
    36    support binary ("8-bit") control seqeneces.
    37    This only supports standard parameters (ECMA-48 §5.4.1.a /
    38    §5.4.2), and does NOT support "experimental"/"private" parameters
    39    (ECMA-48 §5.4.1.b).
    40    """
    41    csi = '\033['
    42    if arg2:
    43        params: List[_number] = arg1
    44        op: str = arg2
    45    else:
    46        params = []
    47        op = arg1
    48    return csi + (';'.join(str(n).replace('.', ':') for n in params)) + op
    49
    50
    51# The "EL" ("Erase in Line") control seqence (ECMA-48 §8.3.41) with no
    52# parameters.
    53clear_rest_of_line = cs('K')
    54
    55# The "ED" ("Erase in Display^H^H^H^H^H^H^HPage") control seqence
    56# (ECMA-48 §8.3.39) with no parameters.
    57clear_rest_of_screen = cs('J')
    58
    59
    60def cursor_up(lines: int = 1) -> str:
    61    """Generate the "CUU" ("CUrsor Up") control sequence (ECMA-48 §8.3.22)."""
    62    if lines == 1:
    63        return cs('A')
    64    return cs([lines], 'A')
    65
    66
    67def _sgr_code(code: int) -> '_SGR':
    68    def get(self: '_SGR') -> '_SGR':
    69        return _SGR(self.params + [code])
    70
    71    return cast('_SGR', property(get))
    72
    73
    74class _SGR:
    75    def __init__(self, params: List[_number] = []) -> None:
    76        self.params = params
    77
    78    def __str__(self) -> str:
    79        return cs(self.params, 'm')
    80
    81    reset = _sgr_code(0)
    82    bold = _sgr_code(1)
    83    fg_blk = _sgr_code(30)
    84    fg_red = _sgr_code(31)
    85    fg_grn = _sgr_code(32)
    86    fg_yel = _sgr_code(33)
    87    fg_blu = _sgr_code(34)
    88    fg_prp = _sgr_code(35)
    89    fg_cyn = _sgr_code(36)
    90    fg_wht = _sgr_code(37)
    91    # 38 is 8bit/24bit color
    92    fg_def = _sgr_code(39)
    93
    94
    95# sgr builds "Set Graphics Rendition" control sequences (ECMA-48
    96# §8.3.117).
    97sgr = _SGR()

View as plain text