-
-
Notifications
You must be signed in to change notification settings - Fork 268
/
Copy paththemes.py
220 lines (188 loc) · 6.83 KB
/
themes.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
from typing import Any, Dict, List, Optional, Tuple, Union
from pygments.token import STANDARD_TYPES
from zulipterminal.config.color import term16
from zulipterminal.themes import gruvbox, nord, zt_blue, zt_dark, zt_light
StyleSpec = Union[
Tuple[Optional[str], str, str],
Tuple[Optional[str], str, str, Optional[str]],
Tuple[Optional[str], str, str, Optional[str], str, str],
]
ThemeSpec = List[StyleSpec]
# fmt: off
# The keys in REQUIRED_STYLES specify what styles are necessary for a theme to
# be complete, while the values are those used to style each element in
# monochrome (1-bit) mode - independently of the specified theme
REQUIRED_STYLES = {
# style name : monochrome style
None : '',
'selected' : 'standout',
'msg_selected' : 'standout',
'header' : 'bold',
'general_narrow' : 'standout',
'general_bar' : '',
'name' : '',
'unread' : 'strikethrough',
'user_active' : 'bold',
'user_idle' : '',
'user_offline' : '',
'user_inactive' : '',
'title' : 'bold',
'column_title' : 'bold',
'time' : '',
'bar' : 'standout',
'msg_emoji' : 'bold',
'reaction' : 'bold',
'reaction_mine' : 'standout',
'msg_math' : 'standout',
'msg_mention' : 'bold',
'msg_link' : '',
'msg_link_index' : 'bold',
'msg_quote' : 'underline',
'msg_code' : 'bold',
'msg_bold' : 'bold',
'msg_time' : 'bold',
'footer' : 'standout',
'footer_contrast' : 'standout',
'starred' : 'bold',
'unread_count' : 'bold',
'starred_count' : '',
'table_head' : 'bold',
'filter_results' : 'bold',
'edit_topic' : 'standout',
'edit_tag' : 'standout',
'edit_author' : 'bold',
'edit_time' : 'bold',
'current_user' : '',
'muted' : 'bold',
'popup_border' : 'bold',
'popup_category' : 'bold',
'popup_contrast' : 'standout',
'popup_important' : 'bold',
'widget_disabled' : 'strikethrough',
'area:help' : 'standout',
'area:msg' : 'standout',
'area:stream' : 'standout',
'area:error' : 'standout',
'area:user' : 'standout',
'search_error' : 'standout',
'task:success' : 'standout',
'task:error' : 'standout',
'task:warning' : 'standout',
}
REQUIRED_META = {
'pygments': {
'styles' : None,
'background' : None,
'overrides' : None,
}
}
# fmt: on
THEMES = {
"gruvbox_dark": gruvbox,
"nord_dark": nord,
"zt_dark": zt_dark,
"zt_light": zt_light,
"zt_blue": zt_blue,
}
THEME_ALIASES = {
"default": "zt_dark",
"gruvbox": "gruvbox_dark",
"nord": "nord_dark",
"light": "zt_light",
"blue": "zt_blue",
}
def all_themes() -> List[str]:
return list(THEMES.keys())
def aliased_themes() -> Dict[str, str]:
return dict(THEME_ALIASES)
def complete_and_incomplete_themes() -> Tuple[List[str], List[str]]:
complete = {
name
for name, theme in THEMES.items()
if set(theme.STYLES) == set(REQUIRED_STYLES)
if set(theme.META) == set(REQUIRED_META)
for meta, conf in theme.META.items()
if set(conf) == set(REQUIRED_META.get(meta, {}))
}
incomplete = list(set(THEMES) - complete)
return sorted(list(complete)), sorted(incomplete)
def generate_theme(theme_name: str, color_depth: int) -> ThemeSpec:
theme_styles = THEMES[theme_name].STYLES
urwid_theme = parse_themefile(theme_styles, color_depth)
try:
theme_meta = THEMES[theme_name].META
add_pygments_style(theme_meta, urwid_theme)
except AttributeError:
pass
return urwid_theme
def parse_themefile(
theme_styles: Dict[Optional[str], Tuple[Any, Any]], color_depth: int
) -> ThemeSpec:
urwid_theme = []
for style_name, (fg, bg) in theme_styles.items():
fg_code16, fg_code256, fg_code24, *fg_props = fg.value.split()
bg_code16, bg_code256, bg_code24, *bg_props = bg.value.split()
new_style: StyleSpec
if color_depth == 1:
new_style = (style_name, "", "", REQUIRED_STYLES[style_name])
elif color_depth == 16:
fg = " ".join([fg_code16] + fg_props).replace("_", " ")
bg = " ".join([bg_code16] + bg_props).replace("_", " ")
new_style = (style_name, fg, bg)
elif color_depth == 256:
fg = " ".join([fg_code256] + fg_props)
bg = " ".join([bg_code256] + bg_props)
new_style = (style_name, "", "", "", fg, bg)
elif color_depth == 2 ** 24:
fg = " ".join([fg_code24] + fg_props)
bg = " ".join([bg_code24] + bg_props)
new_style = (style_name, "", "", "", fg, bg)
urwid_theme.append(new_style)
return urwid_theme
def add_pygments_style(theme_meta: Dict[str, Any], urwid_theme: ThemeSpec) -> None:
"""
This function adds pygments styles for use in syntax
highlighting of code blocks and inline code.
pygments["styles"]:
one of those available in pygments/styles.
pygments["background"]:
used to set a different background for codeblocks instead of the
one used in the syntax style, if it doesn't match with
the overall zt theme.
The default is available as Eg: MaterialStyle.background_color
pygments["overrides"]:
used to override certain pygments styles to match to urwid format.
It can also be used to customize the syntax style.
"""
pygments = theme_meta["pygments"]
pygments_styles = pygments["styles"]
pygments_bg = pygments["background"]
pygments_overrides = pygments["overrides"]
term16_styles = term16.styles
term16_bg = term16.background_color
for token, css_class in STANDARD_TYPES.items():
if css_class in pygments_overrides:
pygments_styles[token] = pygments_overrides[css_class]
# Inherit parent pygments style if not defined.
# Eg: Use `String` if `String.Double` is not present.
if pygments_styles[token] == "":
try:
t = [k for k, v in STANDARD_TYPES.items() if v == css_class[0]]
pygments_styles[token] = pygments_styles[t[0]]
except IndexError:
pass
if term16_styles[token] == "":
try:
t = [k for k, v in STANDARD_TYPES.items() if v == css_class[0]]
term16_styles[token] = term16_styles[t[0]]
except IndexError:
pass
new_style = (
f"pygments:{css_class}",
term16_styles[token],
term16_bg,
"bold", # Mono style
pygments_styles[token],
pygments_bg,
)
urwid_theme.append(new_style)