summaryrefslogtreecommitdiffstats
path: root/powerline/theme.py
diff options
context:
space:
mode:
Diffstat (limited to 'powerline/theme.py')
-rw-r--r--powerline/theme.py182
1 files changed, 182 insertions, 0 deletions
diff --git a/powerline/theme.py b/powerline/theme.py
new file mode 100644
index 0000000..b3a23a1
--- /dev/null
+++ b/powerline/theme.py
@@ -0,0 +1,182 @@
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+import itertools
+
+from powerline.segment import gen_segment_getter, process_segment, get_fallback_segment
+from powerline.lib.unicode import u, safe_unicode
+
+
+def requires_segment_info(func):
+ func.powerline_requires_segment_info = True
+ return func
+
+
+def requires_filesystem_watcher(func):
+ func.powerline_requires_filesystem_watcher = True
+ return func
+
+
+def new_empty_segment_line():
+ return {
+ 'left': [],
+ 'right': []
+ }
+
+
+def add_spaces_left(pl, amount, segment):
+ return (' ' * amount) + segment['contents']
+
+
+def add_spaces_right(pl, amount, segment):
+ return segment['contents'] + (' ' * amount)
+
+
+def add_spaces_center(pl, amount, segment):
+ amount, remainder = divmod(amount, 2)
+ return (' ' * (amount + remainder)) + segment['contents'] + (' ' * amount)
+
+
+expand_functions = {
+ 'l': add_spaces_right,
+ 'r': add_spaces_left,
+ 'c': add_spaces_center,
+}
+
+
+class Theme(object):
+ def __init__(self,
+ ext,
+ theme_config,
+ common_config,
+ pl,
+ get_module_attr,
+ top_theme,
+ colorscheme,
+ main_theme_config=None,
+ run_once=False,
+ shutdown_event=None):
+ self.colorscheme = colorscheme
+ self.dividers = theme_config['dividers']
+ self.dividers = dict((
+ (key, dict((k, u(v))
+ for k, v in val.items()))
+ for key, val in self.dividers.items()
+ ))
+ try:
+ self.cursor_space_multiplier = 1 - (theme_config['cursor_space'] / 100)
+ except KeyError:
+ self.cursor_space_multiplier = None
+ self.cursor_columns = theme_config.get('cursor_columns')
+ self.spaces = theme_config['spaces']
+ self.outer_padding = int(theme_config.get('outer_padding', 1))
+ self.segments = []
+ self.EMPTY_SEGMENT = {
+ 'contents': None,
+ 'highlight': {'fg': False, 'bg': False, 'attrs': 0}
+ }
+ self.pl = pl
+ theme_configs = [theme_config]
+ if main_theme_config:
+ theme_configs.append(main_theme_config)
+ get_segment = gen_segment_getter(
+ pl,
+ ext,
+ common_config,
+ theme_configs,
+ theme_config.get('default_module'),
+ get_module_attr,
+ top_theme
+ )
+ for segdict in itertools.chain((theme_config['segments'],),
+ theme_config['segments'].get('above', ())):
+ self.segments.append(new_empty_segment_line())
+ for side in ['left', 'right']:
+ for segment in segdict.get(side, []):
+ segment = get_segment(segment, side)
+ if segment:
+ if not run_once:
+ if segment['startup']:
+ try:
+ segment['startup'](pl, shutdown_event)
+ except Exception as e:
+ pl.error('Exception during {0} startup: {1}', segment['name'], str(e))
+ continue
+ self.segments[-1][side].append(segment)
+
+ def shutdown(self):
+ for line in self.segments:
+ for segments in line.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_line_number(self):
+ return len(self.segments)
+
+ def get_segments(self, side=None, line=0, segment_info=None, mode=None):
+ '''Return all segments.
+
+ Function segments are called, and all segments get their before/after
+ and ljust/rjust properties applied.
+
+ :param int line:
+ Line number for which segments should be obtained. Is counted from
+ zero (botmost line).
+ '''
+ for side in [side] if side else ['left', 'right']:
+ parsed_segments = []
+ for segment in self.segments[line][side]:
+ if segment['display_condition'](self.pl, segment_info, mode):
+ process_segment(
+ self.pl,
+ side,
+ segment_info,
+ parsed_segments,
+ segment,
+ mode,
+ self.colorscheme,
+ )
+ for segment in parsed_segments:
+ self.pl.prefix = segment['name']
+ try:
+ width = segment['width']
+ align = segment['align']
+ if width == 'auto' and segment['expand'] is None:
+ segment['expand'] = expand_functions.get(align)
+ if segment['expand'] is None:
+ self.pl.error('Align argument must be “r”, “l” or “c”, not “{0}”', align)
+
+ try:
+ segment['contents'] = segment['before'] + u(
+ segment['contents'] if segment['contents'] is not None else ''
+ ) + segment['after']
+ except Exception as e:
+ self.pl.exception('Failed to compute segment contents: {0}', str(e))
+ segment['contents'] = safe_unicode(segment.get('contents'))
+ # 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()
+ except Exception as e:
+ self.pl.exception('Failed to compute segment: {0}', str(e))
+ fallback = get_fallback_segment()
+ fallback.update(side=side)
+ yield fallback