106 lines
2.8 KiB
Python
106 lines
2.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Various utility functions and helpers."""
|
|
|
|
import binascii
|
|
import re
|
|
from functools import lru_cache
|
|
from typing import Dict
|
|
|
|
from typing import TYPE_CHECKING
|
|
if TYPE_CHECKING:
|
|
from pygments.style import StyleMeta
|
|
|
|
from cli_helpers.compat import binary_type, text_type, Terminal256Formatter, StringIO
|
|
|
|
|
|
def bytes_to_string(b):
|
|
"""Convert bytes *b* to a string.
|
|
|
|
Hexlify bytes that can't be decoded.
|
|
|
|
"""
|
|
if isinstance(b, binary_type):
|
|
try:
|
|
return b.decode('utf8')
|
|
except UnicodeDecodeError:
|
|
return '0x' + binascii.hexlify(b).decode('ascii')
|
|
return b
|
|
|
|
|
|
def to_string(value):
|
|
"""Convert *value* to a string."""
|
|
if isinstance(value, binary_type):
|
|
return bytes_to_string(value)
|
|
else:
|
|
return text_type(value)
|
|
|
|
|
|
def truncate_string(value, max_width=None, skip_multiline_string=True):
|
|
"""Truncate string values."""
|
|
if skip_multiline_string and isinstance(value, text_type) and '\n' in value:
|
|
return value
|
|
elif isinstance(value, text_type) and max_width is not None and len(value) > max_width:
|
|
return value[:max_width-3] + "..."
|
|
return value
|
|
|
|
|
|
def intlen(n):
|
|
"""Find the length of the integer part of a number *n*."""
|
|
pos = n.find('.')
|
|
return len(n) if pos < 0 else pos
|
|
|
|
|
|
def filter_dict_by_key(d, keys):
|
|
"""Filter the dict *d* to remove keys not in *keys*."""
|
|
return {k: v for k, v in d.items() if k in keys}
|
|
|
|
|
|
def unique_items(seq):
|
|
"""Return the unique items from iterable *seq* (in order)."""
|
|
seen = set()
|
|
return [x for x in seq if not (x in seen or seen.add(x))]
|
|
|
|
|
|
_ansi_re = re.compile('\033\\[((?:\\d|;)*)([a-zA-Z])')
|
|
|
|
|
|
def strip_ansi(value):
|
|
"""Strip the ANSI escape sequences from a string."""
|
|
return _ansi_re.sub('', value)
|
|
|
|
|
|
def replace(s, replace):
|
|
"""Replace multiple values in a string"""
|
|
for r in replace:
|
|
s = s.replace(*r)
|
|
return s
|
|
|
|
|
|
@lru_cache()
|
|
def _get_formatter(style) -> Terminal256Formatter:
|
|
return Terminal256Formatter(style=style)
|
|
|
|
|
|
def style_field(token, field, style):
|
|
"""Get the styled text for a *field* using *token* type."""
|
|
formatter = _get_formatter(style)
|
|
s = StringIO()
|
|
formatter.format(((token, field),), s)
|
|
return s.getvalue()
|
|
|
|
|
|
def filter_style_table(style: "StyleMeta", *relevant_styles: str) -> Dict:
|
|
"""
|
|
get a dictionary of styles for given tokens. Typical usage:
|
|
|
|
filter_style_table(style, 'Token.Output.EvenRow', 'Token.Output.OddRow') == {
|
|
'Token.Output.EvenRow': "",
|
|
'Token.Output.OddRow': "",
|
|
}
|
|
"""
|
|
_styles_iter = ((str(key), val) for key, val in getattr(style, 'styles', {}).items())
|
|
_relevant_styles_iter = filter(
|
|
lambda tpl: tpl[0] in relevant_styles,
|
|
_styles_iter
|
|
)
|
|
return {key: val for key, val in _relevant_styles_iter}
|