# vim:fileencoding=utf-8:noet from __future__ import (unicode_literals, division, absolute_import, print_function) import atexit from weakref import WeakValueDictionary, ref import zsh from powerline.shell import ShellPowerline from powerline.lib.overrides import parsedotval, parse_override_var from powerline.lib.unicode import unicode, u from powerline.lib.encoding import (get_preferred_output_encoding, get_preferred_environment_encoding) from powerline.lib.dict import mergeargs used_powerlines = WeakValueDictionary() def shutdown(): for powerline in tuple(used_powerlines.values()): powerline.shutdown() def get_var_config(var): try: val = zsh.getvalue(var) if isinstance(val, dict): return mergeargs([parsedotval((u(k), u(v))) for k, v in val.items()]) elif isinstance(val, (unicode, str, bytes)): return mergeargs(parse_override_var(u(val))) else: return None except: return None class Args(object): __slots__ = ('last_pipe_status', 'last_exit_code') ext = ['shell'] renderer_module = '.zsh' @property def config_override(self): return get_var_config('POWERLINE_CONFIG_OVERRIDES') @property def theme_override(self): return get_var_config('POWERLINE_THEME_OVERRIDES') @property def config_path(self): try: ret = zsh.getvalue('POWERLINE_CONFIG_PATHS') except IndexError: return None else: if isinstance(ret, (unicode, str, bytes)): return [ path for path in ret.split((b':' if isinstance(ret, bytes) else ':')) if path ] else: return ret @property def jobnum(self): return zsh.getvalue('_POWERLINE_JOBNUM') def string(s): if type(s) is bytes: return s.decode(get_preferred_environment_encoding(), 'replace') else: return str(s) class Environment(object): @staticmethod def __getitem__(key): try: return string(zsh.getvalue(key)) except IndexError as e: raise KeyError(*e.args) @staticmethod def get(key, default=None): try: return string(zsh.getvalue(key)) except IndexError: return default @staticmethod def __contains__(key): try: zsh.getvalue(key) return True except IndexError: return False if hasattr(getattr(zsh, 'environ', None), '__contains__'): environ = zsh.environ else: environ = Environment() if hasattr(zsh, 'expand') and zsh.expand('${:-}') == '': zsh_expand = zsh.expand else: def zsh_expand(s): zsh.eval('local _POWERLINE_REPLY="' + s + '"') ret = zsh.getvalue('_POWERLINE_REPLY') zsh.setvalue('_POWERLINE_REPLY', None) return ret class ZshPowerline(ShellPowerline): def init(self, **kwargs): super(ZshPowerline, self).init(Args(), **kwargs) def precmd(self): self.args.last_pipe_status = zsh.pipestatus() self.args.last_exit_code = zsh.last_exit_code() def do_setup(self, zsh_globals): set_prompt(self, 'PS1', 'left', None, above=True) set_prompt(self, 'RPS1', 'right', None) set_prompt(self, 'PS2', 'left', 'continuation') set_prompt(self, 'RPS2', 'right', 'continuation') set_prompt(self, 'PS3', 'left', 'select') used_powerlines[id(self)] = self zsh_globals['_powerline'] = self class Prompt(object): __slots__ = ('powerline', 'side', 'savedpsvar', 'savedps', 'args', 'theme', 'above', '__weakref__') def __init__(self, powerline, side, theme, savedpsvar=None, savedps=None, above=False): self.powerline = powerline self.side = side self.above = above self.savedpsvar = savedpsvar self.savedps = savedps self.args = powerline.args self.theme = theme def __str__(self): parser_state = u(zsh_expand('${(%):-%_}')) shortened_path = u(zsh_expand('${(%):-%~}')) try: mode = u(zsh.getvalue('_POWERLINE_MODE')) except IndexError: mode = None try: default_mode = u(zsh.getvalue('_POWERLINE_DEFAULT_MODE')) except IndexError: default_mode = None segment_info = { 'args': self.args, 'environ': environ, 'client_id': 1, 'local_theme': self.theme, 'parser_state': parser_state, 'shortened_path': shortened_path, 'mode': mode, 'default_mode': default_mode, } try: zle_rprompt_indent = zsh.getvalue('ZLE_RPROMPT_INDENT') except IndexError: zle_rprompt_indent = 1 r = '' if self.above: for line in self.powerline.render_above_lines( width=zsh.columns() - zle_rprompt_indent, segment_info=segment_info, ): if line: r += line + '\n' r += self.powerline.render( width=zsh.columns(), side=self.side, segment_info=segment_info, mode=mode, ) if type(r) is not str: if type(r) is bytes: return r.decode(get_preferred_output_encoding(), 'replace') else: return r.encode(get_preferred_output_encoding(), 'replace') return r def __del__(self): if self.savedps: zsh.setvalue(self.savedpsvar, self.savedps) self.powerline.shutdown() def set_prompt(powerline, psvar, side, theme, above=False): try: savedps = zsh.getvalue(psvar) except IndexError: savedps = None zpyvar = 'ZPYTHON_POWERLINE_' + psvar prompt = Prompt(powerline, side, theme, psvar, savedps, above) zsh.setvalue(zpyvar, None) zsh.set_special_string(zpyvar, prompt) zsh.setvalue(psvar, '${' + zpyvar + '}') return ref(prompt) def reload(): for powerline in tuple(used_powerlines.values()): powerline.reload() def reload_config(): for powerline in used_powerlines.values(): powerline.create_renderer(load_main=True, load_colors=True, load_colorscheme=True, load_theme=True) def setup(zsh_globals): powerline = ZshPowerline() powerline.setup(zsh_globals) atexit.register(shutdown)