# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/10_style.ipynb.

# %% auto 0
__all__ = ['style_codes', 'S', 'StyleCode', 'Style', 'demo']

# %% ../nbs/10_style.ipynb 3
# Source: https://misc.flogisoft.com/bash/tip_colors_and_formatting
_base = 'red green yellow blue magenta cyan'
_regular = f'black {_base} light_gray'
_intense = 'dark_gray ' + ' '.join('light_'+o for o in _base.split()) + ' white'
_fmt = 'bold dim italic underline blink <na> invert hidden strikethrough'

# %% ../nbs/10_style.ipynb 4
class StyleCode:
    "An escape sequence for styling terminal text."
    def __init__(self, name, code, typ): self.name,self.code,self.typ = name,code,typ
    def __str__(self): return f'\033[{self.code}m'

# %% ../nbs/10_style.ipynb 7
def _mk_codes(s, start, typ, fmt=None, **kwargs):
    d = {k:i for i,k in enumerate(s.split())} if isinstance(s, str) else s
    res = {k if fmt is None else fmt.format(k):start+v for k,v in d.items()}
    res.update(kwargs)
    return {k:StyleCode(k,v,typ) for k,v in res.items()}

# %% ../nbs/10_style.ipynb 8
# Hardcode `reset_bold=22` since 21 is not always supported
# See: https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
style_codes = {**_mk_codes(_regular, 30,  'fg',                default=39),
               **_mk_codes(_intense, 90,  'fg'),
               **_mk_codes(_regular, 40,  'bg',    '{}_bg',    default_bg=49),
               **_mk_codes(_intense, 100, 'bg',    '{}_bg'),
               **_mk_codes(_fmt,     1,   'fmt'),
               **_mk_codes(_fmt,     21,  'reset', 'reset_{}', reset=0, reset_bold=22)}
style_codes = {k:v for k,v in style_codes.items() if '<na>' not in k}

# %% ../nbs/10_style.ipynb 9
def _reset_code(s):
    if s.typ == 'fg':  return style_codes['default']
    if s.typ == 'bg':  return style_codes['default_bg']
    if s.typ == 'fmt': return style_codes['reset_'+s.name]

# %% ../nbs/10_style.ipynb 10
class Style:
    "A minimal terminal text styler."
    def __init__(self, codes=None): self.codes = [] if codes is None else codes
    def __dir__(self): return style_codes.keys()
    def __getattr__(self, k):
        try: return Style(self.codes+[style_codes[k]])
        except KeyError: return super().__getattr__(k)
    def __call__(self, obj):
        set_ = ''.join(str(o) for o in self.codes)
        reset = ''.join(sorted('' if o is None else str(o) for o in set(_reset_code(o) for o in self.codes)))
        return set_ + str(obj) + reset
    def __repr__(self):
        nm = type(self).__name__
        res = f'<{nm}: '
        res += ' '.join(o.name for o in self.codes) if self.codes else 'none'
        return res+'>'

# %% ../nbs/10_style.ipynb 12
S = Style()

# %% ../nbs/10_style.ipynb 25
def _demo(name, code):
    s = getattr(S,name)
    print(s(f'{code.code:>3}    {name:16}'))

# %% ../nbs/10_style.ipynb 26
def demo():
    "Demonstrate all available styles and their codes."
    for k,v in style_codes.items(): _demo(k,v)
