-
Notifications
You must be signed in to change notification settings - Fork 990
/
theme.py
148 lines (131 loc) · 4.7 KB
/
theme.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
# vim:fileencoding=utf-8:noet
from .segment import gen_segment_getter
try:
from __builtin__ import unicode
except ImportError:
unicode = str # NOQA
def u(s):
if type(s) is unicode:
return s
else:
return unicode(s, 'utf-8')
def requires_segment_info(func):
func.powerline_requires_segment_info = True
return func
class Theme(object):
def __init__(self,
ext,
theme_config,
common_config,
pl,
top_theme_config=None,
run_once=False,
shutdown_event=None):
self.dividers = theme_config.get('dividers', common_config['dividers'])
self.spaces = theme_config.get('spaces', common_config['spaces'])
self.segments = {
'left': [],
'right': [],
}
self.EMPTY_SEGMENT = {
'contents': None,
'highlight': {'fg': False, 'bg': False, 'attr': 0}
}
self.pl = pl
theme_configs = [theme_config]
if top_theme_config:
theme_configs.append(top_theme_config)
get_segment = gen_segment_getter(pl, ext, common_config['paths'], theme_configs, theme_config.get('default_module'))
for side in ['left', 'right']:
for segment in theme_config['segments'].get(side, []):
segment = get_segment(segment, side)
if not run_once:
if segment['startup']:
try:
segment['startup'](pl=pl, shutdown_event=shutdown_event, **segment['args'])
except Exception as e:
pl.error('Exception during {0} startup: {1}', segment['name'], str(e))
continue
self.segments[side].append(segment)
def shutdown(self):
for segments in self.segments.values():
for segment in segments:
try:
segment['shutdown']()
except TypeError:
pass
def get_divider(self, side='left', type='soft'):
'''Return segment divider.'''
return self.dividers[side][type]
def get_spaces(self):
return self.spaces
def get_segments(self, side=None, segment_info=None):
'''Return all segments.
Function segments are called, and all segments get their before/after
and ljust/rjust properties applied.
'''
for side in [side] if side else ['left', 'right']:
parsed_segments = []
for segment in self.segments[side]:
if segment['type'] == 'function':
self.pl.prefix = segment['name']
try:
if (hasattr(segment['contents_func'], 'powerline_requires_segment_info')
and segment['contents_func'].powerline_requires_segment_info):
contents = segment['contents_func'](pl=self.pl, segment_info=segment_info, **segment['args'])
else:
contents = segment['contents_func'](pl=self.pl, **segment['args'])
except Exception as e:
self.pl.exception('Exception while computing segment: {0}', str(e))
continue
if contents is None:
continue
if isinstance(contents, list):
segment_base = segment.copy()
if contents:
draw_divider_position = -1 if side == 'left' else 0
for key, i, newval in (
('before', 0, ''),
('after', -1, ''),
('draw_soft_divider', draw_divider_position, True),
('draw_hard_divider', draw_divider_position, True),
):
try:
contents[i][key] = segment_base.pop(key)
segment_base[key] = newval
except KeyError:
pass
draw_inner_divider = None
if side == 'right':
append = parsed_segments.append
else:
pslen = len(parsed_segments)
append = lambda item: parsed_segments.insert(pslen, item)
for subsegment in (contents if side == 'right' else reversed(contents)):
segment_copy = segment_base.copy()
segment_copy.update(subsegment)
if draw_inner_divider is not None:
segment_copy['draw_soft_divider'] = draw_inner_divider
draw_inner_divider = segment_copy.pop('draw_inner_divider', None)
append(segment_copy)
else:
segment['contents'] = contents
parsed_segments.append(segment)
elif segment['width'] == 'auto' or (segment['type'] == 'string' and segment['contents'] is not None):
parsed_segments.append(segment)
else:
continue
for segment in parsed_segments:
segment['contents'] = segment['before'] + u(segment['contents'] if segment['contents'] is not None else '') + segment['after']
# Align segment contents
if segment['width'] and segment['width'] != 'auto':
if segment['align'] == 'l':
segment['contents'] = segment['contents'].ljust(segment['width'])
elif segment['align'] == 'r':
segment['contents'] = segment['contents'].rjust(segment['width'])
elif segment['align'] == 'c':
segment['contents'] = segment['contents'].center(segment['width'])
# We need to yield a copy of the segment, or else mode-dependent
# segment contents can't be cached correctly e.g. when caching
# non-current window contents for vim statuslines
yield segment.copy()