Skip to content

Commit c95818d

Browse files
authored
Merge pull request #460 from seeM/style
Add `fastcore.style`: fast styling for friendly CLIs
2 parents 3ad1bca + db049f6 commit c95818d

File tree

4 files changed

+547
-1
lines changed

4 files changed

+547
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,4 @@ checklink/cookies.txt
142142
# .gitconfig is now autogenerated
143143
.gitconfig
144144

145+
_docs

fastcore/_modidx.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
'title': 'fastcore',
3232
'tst_flags': '',
3333
'user': 'fastai',
34-
'version': '1.5.16'},
34+
'version': '1.5.17'},
3535
'syms': { 'fastcore.all': {},
3636
'fastcore.basics': { 'fastcore.basics.AttrDict': 'https://fastcore.fast.ai/basics.html#attrdict',
3737
'fastcore.basics.AttrDict.copy': 'https://fastcore.fast.ai/basics.html#attrdict.copy',
@@ -361,6 +361,11 @@
361361
'fastcore.shutil.disk_usage': 'https://fastcore.fast.ai/shutil.html#disk_usage',
362362
'fastcore.shutil.move': 'https://fastcore.fast.ai/shutil.html#move',
363363
'fastcore.shutil.rmtree': 'https://fastcore.fast.ai/shutil.html#rmtree'},
364+
'fastcore.style': { 'fastcore.style.S': 'https://fastcore.fast.ai/style.html#s',
365+
'fastcore.style.Style': 'https://fastcore.fast.ai/style.html#style',
366+
'fastcore.style.StyleCode': 'https://fastcore.fast.ai/style.html#stylecode',
367+
'fastcore.style.demo': 'https://fastcore.fast.ai/style.html#demo',
368+
'fastcore.style.style_codes': 'https://fastcore.fast.ai/style.html#style_codes'},
364369
'fastcore.test': { 'fastcore.test.ExceptionExpected': 'https://fastcore.fast.ai/test.html#exceptionexpected',
365370
'fastcore.test.TEST_IMAGE': 'https://fastcore.fast.ai/test.html#test_image',
366371
'fastcore.test.TEST_IMAGE_BW': 'https://fastcore.fast.ai/test.html#test_image_bw',

fastcore/style.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/10_style.ipynb.
2+
3+
# %% auto 0
4+
__all__ = ['style_codes', 'S', 'StyleCode', 'Style', 'demo']
5+
6+
# %% ../nbs/10_style.ipynb 3
7+
# Source: https://misc.flogisoft.com/bash/tip_colors_and_formatting
8+
_base = 'red green yellow blue magenta cyan'
9+
_regular = f'black {_base} light_gray'
10+
_intense = 'dark_gray ' + ' '.join('light_'+o for o in _base.split()) + ' white'
11+
_fmt = dict(bold=1,dim=2,underline=4,reverse=7,hidden=8)
12+
13+
# %% ../nbs/10_style.ipynb 4
14+
class StyleCode:
15+
"An escape sequence for styling terminal text."
16+
def __init__(self, name, code, typ): self.name,self.code,self.typ = name,code,typ
17+
def __str__(self): return f'\033[{self.code}m'
18+
19+
# %% ../nbs/10_style.ipynb 7
20+
def _mk_codes(s, start, typ, fmt=None, **kwargs):
21+
d = {k:i for i,k in enumerate(s.split())} if isinstance(s, str) else s
22+
res = {k if fmt is None else fmt.format(k):start+v for k,v in d.items()}
23+
res.update(kwargs)
24+
return {k:StyleCode(k,v,typ) for k,v in res.items()}
25+
26+
# %% ../nbs/10_style.ipynb 8
27+
# Hardcode `reset_bold=22` since 21 is not always supported
28+
# See: https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
29+
style_codes = {**_mk_codes(_regular, 30, 'fg', default=39),
30+
**_mk_codes(_intense, 90, 'fg'),
31+
**_mk_codes(_regular, 40, 'bg', '{}_bg', default_bg=49),
32+
**_mk_codes(_intense, 100, 'bg', '{}_bg'),
33+
**_mk_codes(_fmt, 0, 'fmt'),
34+
**_mk_codes(_fmt, 21, 'reset', 'reset_{}', reset=0, reset_bold=22)}
35+
36+
# %% ../nbs/10_style.ipynb 9
37+
def _reset_code(s):
38+
if s.typ == 'fg': return style_codes['default']
39+
if s.typ == 'bg': return style_codes['default_bg']
40+
if s.typ == 'fmt': return style_codes['reset_'+s.name]
41+
42+
# %% ../nbs/10_style.ipynb 10
43+
class Style:
44+
"A minimal terminal text styler."
45+
def __init__(self, codes=None): self.codes = [] if codes is None else codes
46+
def __dir__(self): return style_codes.keys()
47+
def __getattr__(self, k): return Style(self.codes+[style_codes[k]])
48+
def __call__(self, obj):
49+
set_ = ''.join(str(o) for o in self.codes)
50+
reset = ''.join('' if o is None else str(o) for o in set(_reset_code(o) for o in self.codes))
51+
return set_ + str(obj) + reset
52+
def __repr__(self):
53+
nm = type(self).__name__
54+
res = f'<{nm}: '
55+
res += ' '.join(o.name for o in self.codes) if self.codes else 'none'
56+
return res+'>'
57+
58+
# %% ../nbs/10_style.ipynb 12
59+
S = Style()
60+
61+
# %% ../nbs/10_style.ipynb 25
62+
def _demo(name, code):
63+
s = getattr(S,name)
64+
print(s(f'{code.code:>3} {name:16}'))
65+
66+
# %% ../nbs/10_style.ipynb 26
67+
def demo():
68+
"Demonstrate all available styles and their codes."
69+
for k,v in style_codes.items(): _demo(k,v)

0 commit comments

Comments
 (0)