Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/python/blessed/blessed/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 18 kB image not shown  

Quelle  formatters.py   Sprache: Python

 
"""Sub-module providing sequence-formatting functions."""
# std imports
import platform

# 3rd party
import six

# local
from blessed.colorspace import CGA_COLORS, X11_COLORNAMES_TO_RGB

# isort: off
# curses
if platform.system() == 'Windows':
    import jinxed as curses   # pylint: disable=import-error
else:
    import curses


def _make_colors():
    """
    Return set of valid colors and their derivatives.

    :rtype: set
    :returns: Color names with prefixes
    """
    colors = set()
    # basic CGA foreground color, background, high intensity, and bold
    # background ('iCE colors' in my day).
    for cga_color in CGA_COLORS:
        colors.add(cga_color)
        colors.add('on_' + cga_color)
        colors.add('bright_' + cga_color)
        colors.add('on_bright_' + cga_color)

    # foreground and background VGA color
    for vga_color in X11_COLORNAMES_TO_RGB:
        colors.add(vga_color)
        colors.add('on_' + vga_color)
    return colors


#: Valid colors and their background (on), bright, and bright-background
#: derivatives.
COLORS = _make_colors()

#: Attributes that may be compounded with colors, by underscore, such as
#: 'reverse_indigo'.
COMPOUNDABLES = set('bold underline reverse blink italic standout'.split())


class ParameterizingString(six.text_type):
    r"""
    A Unicode string which can be called as a parameterizing termcap.

    For example::

        >>> from blessed import Terminal
        >>> term = Terminal()
        >>> color = ParameterizingString(term.color, term.normal, 'color')
        >>> color(9)('color #9')
        u'\x1b[91mcolor #9\x1b(B\x1b[m'
    """

    def __new__(cls, cap, normal=u'', name=u''):
        # pylint: disable = missing-return-doc, missing-return-type-doc
        """
        Class constructor accepting 3 positional arguments.

        :arg str cap: parameterized string suitable for curses.tparm()
        :arg str normal: terminating sequence for this capability (optional).
        :arg str name: name of this terminal capability (optional).
        """
        new = six.text_type.__new__(cls, cap)
        new._normal = normal
        new._name = name
        return new

    def __call__(self, *args):
        """
        Returning :class:`FormattingString` instance for given parameters.

        Return evaluated terminal capability (self), receiving arguments
        ``*args``, followed by the terminating sequence (self.normal) into
        a :class:`FormattingString` capable of being called.

        :raises TypeError: Mismatch between capability and arguments
        :raises curses.error: :func:`curses.tparm` raised an exception
        :rtype: :class:`FormattingString` or :class:`NullCallableString`
        :returns: Callable string for given parameters
        """
        try:
            # Re-encode the cap, because tparm() takes a bytestring in Python
            # 3. However, appear to be a plain Unicode string otherwise so
            # concats work.
            attr = curses.tparm(self.encode('latin1'), *args).decode('latin1')
            return FormattingString(attr, self._normal)
        except TypeError as err:
            # If the first non-int (i.e. incorrect) arg was a string, suggest
            # something intelligent:
            if args and isinstance(args[0], six.string_types):
                raise TypeError(
                    "Unknown terminal capability, %r, or, TypeError "
                    "for arguments %r: %s" % (self._name, args, err))
            # Somebody passed a non-string; I don't feel confident
            # guessing what they were trying to do.
            raise
        except curses.error as err:
            # ignore 'tparm() returned NULL', you won't get any styling,
            # even if does_styling is True. This happens on win32 platforms
            # with http://www.lfd.uci.edu/~gohlke/pythonlibs/#curses installed
            if "tparm() returned NULL" not in six.text_type(err):
                raise
            return NullCallableString()


class ParameterizingProxyString(six.text_type):
    r"""
    A Unicode string which can be called to proxy missing termcap entries.

    This class supports the function :func:`get_proxy_string`, and mirrors
    the behavior of :class:`ParameterizingString`, except that instead of
    a capability name, receives a format string, and callable to filter the
    given positional ``*args`` of :meth:`ParameterizingProxyString.__call__`
    into a terminal sequence.

    For example::

        >>> from blessed import Terminal
        >>> term = Terminal('screen')
        >>> hpa = ParameterizingString(term.hpa, term.normal, 'hpa')
        >>> hpa(9)
        u''
        >>> fmt = u'\x1b[{0}G'
        >>> fmt_arg = lambda *arg: (arg[0] + 1,)
        >>> hpa = ParameterizingProxyString((fmt, fmt_arg), term.normal, 'hpa')
        >>> hpa(9)
        u'\x1b[10G'
    """

    def __new__(cls, fmt_pair, normal=u'', name=u''):
        # pylint: disable = missing-return-doc, missing-return-type-doc
        """
        Class constructor accepting 4 positional arguments.

        :arg tuple fmt_pair: Two element tuple containing:
            - format string suitable for displaying terminal sequences
            - callable suitable for receiving  __call__ arguments for formatting string
        :arg str normal: terminating sequence for this capability (optional).
        :arg str name: name of this terminal capability (optional).
        """
        assert isinstance(fmt_pair, tuple), fmt_pair
        assert callable(fmt_pair[1]), fmt_pair[1]
        new = six.text_type.__new__(cls, fmt_pair[0])
        new._fmt_args = fmt_pair[1]
        new._normal = normal
        new._name = name
        return new

    def __call__(self, *args):
        """
        Returning :class:`FormattingString` instance for given parameters.

        Arguments are determined by the capability.  For example, ``hpa``
        (move_x) receives only a single integer, whereas ``cup`` (move)
        receives two integers.  See documentation in terminfo(5) for the
        given capability.

        :rtype: FormattingString
        :returns: Callable string for given parameters
        """
        return FormattingString(self.format(*self._fmt_args(*args)),
                                self._normal)


class FormattingString(six.text_type):
    r"""
    A Unicode string which doubles as a callable.

    This is used for terminal attributes, so that it may be used both
    directly, or as a callable.  When used directly, it simply emits
    the given terminal sequence.  When used as a callable, it wraps the
    given (string) argument with the 2nd argument used by the class
    constructor::

        >>> from blessed import Terminal
        >>> term = Terminal()
        >>> style = FormattingString(term.bright_blue, term.normal)
        >>> print(repr(style))
        u'\x1b[94m'
        >>> style('Big Blue')
        u'\x1b[94mBig Blue\x1b(B\x1b[m'
    """

    def __new__(cls, sequence, normal=u''):
        # pylint: disable = missing-return-doc, missing-return-type-doc
        """
        Class constructor accepting 2 positional arguments.

        :arg str sequence: terminal attribute sequence.
        :arg str normal: terminating sequence for this attribute (optional).
        """
        new = six.text_type.__new__(cls, sequence)
        new._normal = normal
        return new

    def __call__(self, *args):
        """
        Return ``text`` joined by ``sequence`` and ``normal``.

        :raises TypeError: Not a string type
        :rtype: str
        :returns: Arguments wrapped in sequence and normal
        """
        # Jim Allman brings us this convenience of allowing existing
        # unicode strings to be joined as a call parameter to a formatting
        # string result, allowing nestation:
        #
        # >>> t.red('This is ', t.bold('extremely'), ' dangerous!')
        for idx, ucs_part in enumerate(args):
            if not isinstance(ucs_part, six.string_types):
                expected_types = ', '.join(_type.__name__ for _type in six.string_types)
                raise TypeError(
                    "TypeError for FormattingString argument, "
                    "%r, at position %s: expected type %s, "
                    "got %s" % (ucs_part, idx, expected_types,
                                type(ucs_part).__name__))
        postfix = u''
        if self and self._normal:
            postfix = self._normal
            _refresh = self._normal + self
            args = [_refresh.join(ucs_part.split(self._normal))
                    for ucs_part in args]

        return self + u''.join(args) + postfix


class FormattingOtherString(six.text_type):
    r"""
    A Unicode string which doubles as a callable for another sequence when called.

    This is used for the :meth:`~.Terminal.move_up`, ``down``, ``left``, and ``right()``
    family of functions::

        >>> from blessed import Terminal
        >>> term = Terminal()
        >>> move_right = FormattingOtherString(term.cuf1, term.cuf)
        >>> print(repr(move_right))
        u'\x1b[C'
        >>> print(repr(move_right(666)))
        u'\x1b[666C'
        >>> print(repr(move_right()))
        u'\x1b[C'
    """

    def __new__(cls, direct, target):
        # pylint: disable = missing-return-doc, missing-return-type-doc
        """
        Class constructor accepting 2 positional arguments.

        :arg str direct: capability name for direct formatting, eg ``('x' + term.right)``.
        :arg str target: capability name for callable, eg ``('x' + term.right(99))``.
        """
        new = six.text_type.__new__(cls, direct)
        new._callable = target
        return new

    def __getnewargs__(self):
        # return arguments used for the __new__ method upon unpickling.
        return six.text_type.__new__(six.text_type, self), self._callable

    def __call__(self, *args):
        """Return ``text`` by ``target``."""
        if args:
            return self._callable(*args)
        return self


class NullCallableString(six.text_type):
    """
    A dummy callable Unicode alternative to :class:`FormattingString`.

    This is used for colors on terminals that do not support colors, it is just a basic form of
    unicode that may also act as a callable.
    """

    def __new__(cls):
        """Class constructor."""
        return six.text_type.__new__(cls, u'')

    def __call__(self, *args):
        """
        Allow empty string to be callable, returning given string, if any.

        When called with an int as the first arg, return an empty Unicode. An
        int is a good hint that I am a :class:`ParameterizingString`, as there
        are only about half a dozen string-returning capabilities listed in
        terminfo(5) which accept non-int arguments, they are seldom used.

        When called with a non-int as the first arg (no no args at all), return
        the first arg, acting in place of :class:`FormattingString` without
        any attributes.
        """
        if not args or isinstance(args[0], int):
            # As a NullCallableString, even when provided with a parameter,
            # such as t.color(5), we must also still be callable, fe:
            #
            # >>> t.color(5)('shmoo')
            #
            # is actually simplified result of NullCallable()() on terminals
            # without color support, so turtles all the way down: we return
            # another instance.
            return NullCallableString()
        return u''.join(args)


def get_proxy_string(term, attr):
    """
    Proxy and return callable string for proxied attributes.

    :arg Terminal term: :class:`~.Terminal` instance.
    :arg str attr: terminal capability name that may be proxied.
    :rtype: None or :class:`ParameterizingProxyString`.
    :returns: :class:`ParameterizingProxyString` for some attributes
        of some terminal types that support it, where the terminfo(5)
        database would otherwise come up empty, such as ``move_x``
        attribute for ``term.kind`` of ``screen``.  Otherwise, None.
    """
    # normalize 'screen-256color', or 'ansi.sys' to its basic names
    term_kind = next(iter(_kind for _kind in ('screen''ansi',)
                          if term.kind.startswith(_kind)), term)
    _proxy_table = {  # pragma: no cover
        'screen': {
            # proxy move_x/move_y for 'screen' terminal type, used by tmux(1).
            'hpa': ParameterizingProxyString(
                (u'\x1b[{0}G'lambda *arg: (arg[0] + 1,)), term.normal, attr),
            'vpa': ParameterizingProxyString(
                (u'\x1b[{0}d'lambda *arg: (arg[0] + 1,)), term.normal, attr),
        },
        'ansi': {
            # proxy show/hide cursor for 'ansi' terminal type.  There is some
            # demand for a richly working ANSI terminal type for some reason.
            'civis': ParameterizingProxyString(
                (u'\x1b[?25l'lambda *arg: ()), term.normal, attr),
            'cnorm': ParameterizingProxyString(
                (u'\x1b[?25h'lambda *arg: ()), term.normal, attr),
            'hpa': ParameterizingProxyString(
                (u'\x1b[{0}G'lambda *arg: (arg[0] + 1,)), term.normal, attr),
            'vpa': ParameterizingProxyString(
                (u'\x1b[{0}d'lambda *arg: (arg[0] + 1,)), term.normal, attr),
            'sc''\x1b[s',
            'rc''\x1b[u',
        }
    }
    return _proxy_table.get(term_kind, {}).get(attr, None)


def split_compound(compound):
    """
    Split compound formating string into segments.

    >>> split_compound('bold_underline_bright_blue_on_red')
    ['bold''underline''bright_blue''on_red']

    :arg str compound: a string that may contain compounds, separated by
        underline (``_``).
    :rtype: list
    :returns: List of formating string segments
    """
    merged_segs = []
    # These occur only as prefixes, so they can always be merged:
    mergeable_prefixes = ['on''bright''on_bright']
    for segment in compound.split('_'):
        if merged_segs and merged_segs[-1] in mergeable_prefixes:
            merged_segs[-1] += '_' + segment
        else:
            merged_segs.append(segment)
    return merged_segs


def resolve_capability(term, attr):
    """
    Resolve a raw terminal capability using :func:`tigetstr`.

    :arg Terminal term: :class:`~.Terminal` instance.
    :arg str attr: terminal capability name.
    :returns: string of the given terminal capability named by ``attr``,
       which may be empty (u''if not found or not supported by the
       given :attr:`~.Terminal.kind`.
    :rtype: str
    """
    if not term.does_styling:
        return u''
    val = curses.tigetstr(term._sugar.get(attr, attr))  # pylint: disable=protected-access
    # Decode sequences as latin1, as they are always 8-bit bytes, so when
    # b'\xff' is returned, this is decoded as u'\xff'.
    return u'' if val is None else val.decode('latin1')


def resolve_color(term, color):
    """
    Resolve a simple color name to a callable capability.

    This function supports :func:`resolve_attribute`.

    :arg Terminal term: :class:`~.Terminal` instance.
    :arg str color: any string found in set :const:`COLORS`.
    :returns: a string class instance which emits the terminal sequence
        for the given color, and may be used as a callable to wrap the
        given string with such sequence.
    :returns: :class:`NullCallableString` when
        :attr:`~.Terminal.number_of_colors` is 0,
        otherwise :class:`FormattingString`.
    :rtype: :class:`NullCallableString` or :class:`FormattingString`
    """
    # pylint: disable=protected-access
    if term.number_of_colors == 0:
        return NullCallableString()

    # fg/bg capabilities terminals that support 0-256+ colors.
    vga_color_cap = (term._background_color if 'on_' in color else
                     term._foreground_color)

    base_color = color.rsplit('_', 1)[-1]
    if base_color in CGA_COLORS:
        # curses constants go up to only 7, so add an offset to get at the
        # bright colors at 8-15:
        offset = 8 if 'bright_' in color else 0
        base_color = color.rsplit('_', 1)[-1]
        attr = 'COLOR_%s' % (base_color.upper(),)
        fmt_attr = vga_color_cap(getattr(curses, attr) + offset)
        return FormattingString(fmt_attr, term.normal)

    assert base_color in X11_COLORNAMES_TO_RGB, (
        'color not known', base_color)
    rgb = X11_COLORNAMES_TO_RGB[base_color]

    # downconvert X11 colors to CGA, EGA, or VGA color spaces
    if term.number_of_colors <= 256:
        fmt_attr = vga_color_cap(term.rgb_downconvert(*rgb))
        return FormattingString(fmt_attr, term.normal)

    # Modern 24-bit color terminals are written pretty basically.  The
    # foreground and background sequences are:
    # - ^[38;2;<r>;<g>;<b>m
    # - ^[48;2;<r>;<g>;<b>m
    fgbg_seq = ('48' if 'on_' in color else '38')
    assert term.number_of_colors == 1 << 24
    fmt_attr = u'\x1b[' + fgbg_seq + ';2;{0};{1};{2}m'
    return FormattingString(fmt_attr.format(*rgb), term.normal)


def resolve_attribute(term, attr):
    """
    Resolve a terminal attribute name into a capability class.

    :arg Terminal term: :class:`~.Terminal` instance.
    :arg str attr: Sugary, ordinary, or compound formatted terminal
        capability, such as "red_on_white""normal""red"or
        "bold_on_black".
    :returns: a string class instance which emits the terminal sequence
        for the given terminal capability, or may be used as a callable to
        wrap the given string with such sequence.
    :returns: :class:`NullCallableString` when
        :attr:`~.Terminal.number_of_colors` is 0,
        otherwise :class:`FormattingString`.
    :rtype: :class:`NullCallableString` or :class:`FormattingString`
    """
    if attr in COLORS:
        return resolve_color(term, attr)

    # A direct compoundable, such as `bold' or `on_red'.
    if attr in COMPOUNDABLES:
        sequence = resolve_capability(term, attr)
        return FormattingString(sequence, term.normal)

    # Given `bold_on_red', resolve to ('bold', 'on_red'), RECURSIVE
    # call for each compounding section, joined and returned as
    # a completed completed FormattingString.
    formatters = split_compound(attr)
    if all((fmt in COLORS or fmt in COMPOUNDABLES) for fmt in formatters):
        resolution = (resolve_attribute(term, fmt) for fmt in formatters)
        return FormattingString(u''.join(resolution), term.normal)

    # otherwise, this is our end-game: given a sequence such as 'csr'
    # (change scrolling region), return a ParameterizingString instance,
    # that when called, performs and returns the final string after curses
    # capability lookup is performed.
    tparm_capseq = resolve_capability(term, attr)
    if not tparm_capseq:
        # and, for special terminals, such as 'screen', provide a Proxy
        # ParameterizingString for attributes they do not claim to support,
        # but actually do! (such as 'hpa' and 'vpa').
        proxy = get_proxy_string(term,
                                 term._sugar.get(attr, attr))  # pylint: disable=protected-access
        if proxy is not None:
            return proxy

    return ParameterizingString(tparm_capseq, term.normal, attr)

92%


¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.