# 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()