Split Powerline.__init__ into __init__ and create_renderer
Target: with long-living Powerline objects periodically reload configuration recreating renderer. Use file watchers to watch for configuration. Configuration should be able to be safely reloaded in non-blocking mode in a separate thread up to the time when it comes to recreating renderer. This commit does not add anything that actually reloads the configuration, multiple runs of .create_renderer were not tested.
This commit is contained in:
parent
bc7c5b784d
commit
80ddbfbf9a
|
@ -8,6 +8,8 @@ import logging
|
|||
|
||||
from powerline.colorscheme import Colorscheme
|
||||
|
||||
from threading import Lock
|
||||
|
||||
|
||||
DEFAULT_SYSTEM_CONFIG_DIR = None
|
||||
|
||||
|
@ -97,64 +99,124 @@ class Powerline(object):
|
|||
environ=os.environ,
|
||||
getcwd=getattr(os, 'getcwdu', os.getcwd),
|
||||
home=None):
|
||||
self.ext = ext
|
||||
self.renderer_module = renderer_module or ext
|
||||
self.run_once = run_once
|
||||
self.logger = logger
|
||||
self.environ = environ
|
||||
self.getcwd = getcwd
|
||||
self.home = home
|
||||
|
||||
self.config_paths = self.get_config_paths()
|
||||
|
||||
# Load main config file
|
||||
config = self.load_main_config()
|
||||
common_config = config['common']
|
||||
ext_config = config['ext'][ext]
|
||||
self.ext = ext
|
||||
self.renderer_lock = Lock()
|
||||
|
||||
# Load and initialize colorscheme
|
||||
colorscheme_config = self.load_colorscheme_config(ext_config['colorscheme'])
|
||||
colors_config = self.load_colors_config()
|
||||
colorscheme = Colorscheme(colorscheme_config, colors_config)
|
||||
self.prev_common_config = None
|
||||
self.prev_ext_config = None
|
||||
|
||||
# Load and initialize extension theme
|
||||
theme_config = self.load_theme_config(ext_config.get('theme', 'default'))
|
||||
common_config['paths'] = [os.path.expanduser(path) for path in common_config.get('paths', [])]
|
||||
self.import_paths = common_config['paths']
|
||||
theme_kwargs = {
|
||||
'ext': ext,
|
||||
'common_config': common_config,
|
||||
'run_once': run_once,
|
||||
}
|
||||
local_themes = self.get_local_themes(ext_config.get('local_themes'))
|
||||
self.create_renderer(load_main_config=True, load_colors=True, load_colorscheme=True, load_theme=True)
|
||||
|
||||
# Load and initialize extension renderer
|
||||
renderer_module_name = renderer_module or ext
|
||||
renderer_module_import = 'powerline.renderers.{0}'.format(renderer_module_name)
|
||||
try:
|
||||
Renderer = __import__(renderer_module_import, fromlist=['renderer']).renderer
|
||||
except ImportError as e:
|
||||
sys.stderr.write('Error while importing renderer module: {0}\n'.format(e))
|
||||
sys.exit(1)
|
||||
options = {
|
||||
'term_truecolor': common_config.get('term_truecolor', False),
|
||||
'ambiwidth': common_config.get('ambiwidth', 1),
|
||||
'tmux_escape': common_config.get('additional_escapes') == 'tmux',
|
||||
'screen_escape': common_config.get('additional_escapes') == 'screen',
|
||||
}
|
||||
def create_renderer(self, load_main_config=False, load_colors=False, load_colorscheme=False, load_theme=False):
|
||||
'''(Re)create renderer object. Can be used after Powerline object was
|
||||
successfully initialized. If any of the below parameters except
|
||||
``load_main_config`` is True renderer object will be recreated.
|
||||
|
||||
# Create logger
|
||||
if not logger:
|
||||
log_format = common_config.get('log_format', '%(asctime)s:%(levelname)s:%(message)s')
|
||||
formatter = logging.Formatter(log_format)
|
||||
:param bool load_main_config:
|
||||
Determines whether main configuration file (:file:`config.json`)
|
||||
should be loaded. If appropriate configuration changes implies
|
||||
``load_colorscheme`` and ``load_theme`` and recreation of renderer
|
||||
object. Won’t trigger recreation if only unrelated configuration
|
||||
changed.
|
||||
:param bool load_colors:
|
||||
Determines whether colors configuration from :file:`colors.json`
|
||||
should be (re)loaded.
|
||||
:param bool load_colorscheme:
|
||||
Determines whether colorscheme configuration should be (re)loaded.
|
||||
:param bool load_theme:
|
||||
Determines whether theme configuration should be reloaded.
|
||||
|
||||
level = getattr(logging, common_config.get('log_level', 'WARNING'))
|
||||
handler = self.get_log_handler(common_config)
|
||||
handler.setLevel(level)
|
||||
handler.setFormatter(formatter)
|
||||
Note: reloading of local themes should be taken care of in renderer.
|
||||
'''
|
||||
common_config_differs = False
|
||||
ext_config_differs = False
|
||||
if load_main_config:
|
||||
config = self.load_main_config()
|
||||
self.common_config = config['common']
|
||||
if self.common_config != self.prev_common_config:
|
||||
common_config_differs = True
|
||||
self.prev_common_config = self.common_config
|
||||
self.common_config['paths'] = [os.path.expanduser(path) for path in self.common_config.get('paths', [])]
|
||||
self.import_paths = self.common_config['paths']
|
||||
|
||||
logger = logging.getLogger('powerline')
|
||||
logger.setLevel(level)
|
||||
logger.addHandler(handler)
|
||||
if not self.logger:
|
||||
log_format = self.common_config.get('log_format', '%(asctime)s:%(levelname)s:%(message)s')
|
||||
formatter = logging.Formatter(log_format)
|
||||
|
||||
pl = PowerlineState(logger=logger, environ=environ, getcwd=getcwd, home=home)
|
||||
level = getattr(logging, self.common_config.get('log_level', 'WARNING'))
|
||||
handler = self.get_log_handler()
|
||||
handler.setLevel(level)
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
self.renderer = Renderer(theme_config, local_themes, theme_kwargs, colorscheme, pl, **options)
|
||||
self.logger = logging.getLogger('powerline')
|
||||
self.logger.setLevel(level)
|
||||
self.logger.addHandler(handler)
|
||||
|
||||
def get_log_handler(self, common_config):
|
||||
self.pl = PowerlineState(logger=self.logger, environ=self.environ, getcwd=self.getcwd, home=self.home)
|
||||
|
||||
self.renderer_options = {
|
||||
'term_truecolor': self.common_config.get('term_truecolor', False),
|
||||
'ambiwidth': self.common_config.get('ambiwidth', 1),
|
||||
'tmux_escape': self.common_config.get('additional_escapes') == 'tmux',
|
||||
'screen_escape': self.common_config.get('additional_escapes') == 'screen',
|
||||
}
|
||||
|
||||
self.theme_kwargs = {
|
||||
'ext': self.ext,
|
||||
'common_config': self.common_config,
|
||||
'run_once': self.run_once,
|
||||
}
|
||||
|
||||
self.ext_config = config['ext'][self.ext]
|
||||
if self.ext_config != self.prev_ext_config:
|
||||
ext_config_differs = True
|
||||
if not self.prev_ext_config or self.ext_config.get('local_themes') != self.prev_ext_config.get('local_themes'):
|
||||
self.local_themes = self.get_local_themes(self.ext_config.get('local_themes'))
|
||||
load_colorscheme = (load_colorscheme
|
||||
or not self.prev_ext_config
|
||||
or self.prev_ext_config['colorscheme'] != self.ext_config['colorscheme'])
|
||||
load_theme = (load_theme
|
||||
or not self.prev_ext_config
|
||||
or self.prev_ext_config['theme'] != self.ext_config['theme'])
|
||||
|
||||
create_renderer = load_colors or load_colorscheme or load_theme or common_config_differs or ext_config_differs
|
||||
|
||||
if load_colors:
|
||||
colors_config = self.load_colors_config()
|
||||
|
||||
if load_colorscheme or load_colors:
|
||||
colorscheme_config = self.load_colorscheme_config(self.ext_config['colorscheme'])
|
||||
self.colorscheme = Colorscheme(colorscheme_config, colors_config)
|
||||
|
||||
if load_theme:
|
||||
self.theme_config = self.load_theme_config(self.ext_config.get('theme', 'default'))
|
||||
|
||||
if create_renderer:
|
||||
renderer_module_import = 'powerline.renderers.{0}'.format(self.renderer_module)
|
||||
try:
|
||||
Renderer = __import__(renderer_module_import, fromlist=['renderer']).renderer
|
||||
except Exception as e:
|
||||
self.pl.exception('Failed to import renderer module: {0}', str(e))
|
||||
sys.exit(1)
|
||||
|
||||
with self.renderer_lock:
|
||||
self.renderer = Renderer(self.theme_config,
|
||||
self.local_themes,
|
||||
self.theme_kwargs,
|
||||
self.colorscheme,
|
||||
self.pl,
|
||||
**self.renderer_options)
|
||||
|
||||
def get_log_handler(self):
|
||||
'''Get log handler.
|
||||
|
||||
:param dict common_config:
|
||||
|
@ -162,7 +224,7 @@ class Powerline(object):
|
|||
|
||||
:return: logging.Handler subclass.
|
||||
'''
|
||||
log_file = common_config.get('log_file', None)
|
||||
log_file = self.common_config.get('log_file', None)
|
||||
if log_file:
|
||||
log_file = os.path.expanduser(log_file)
|
||||
log_dir = os.path.dirname(log_file)
|
||||
|
@ -237,3 +299,16 @@ class Powerline(object):
|
|||
``__init__`` arguments, refer to its documentation.
|
||||
'''
|
||||
return None
|
||||
|
||||
def render(self, *args, **kwargs):
|
||||
'''Lock renderer from modifications and pass all arguments further to
|
||||
``self.renderer.render()``.
|
||||
'''
|
||||
with self.renderer_lock:
|
||||
return self.renderer.render(*args, **kwargs)
|
||||
|
||||
def shutdown(self):
|
||||
'''Lock renderer from modifications and run its ``.shutdown()`` method.
|
||||
'''
|
||||
with self.renderer_lock:
|
||||
self.renderer.shutdown()
|
||||
|
|
|
@ -24,7 +24,7 @@ class PowerlinePromptManager(PromptManager):
|
|||
|
||||
def render(self, name, color=True, *args, **kwargs):
|
||||
width = None if name == 'in' else self.width
|
||||
res, res_nocolor = self.powerline.renderer.render(output_raw=True, width=width, matcher_info=name, segment_info=self.powerline_segment_info)
|
||||
res, res_nocolor = self.powerline.render(output_raw=True, width=width, matcher_info=name, segment_info=self.powerline_segment_info)
|
||||
self.txtwidth = len(res_nocolor)
|
||||
self.width = self.txtwidth
|
||||
return res if color else res_nocolor
|
||||
|
@ -51,7 +51,7 @@ def load_ipython_extension(ip):
|
|||
ip.prompt_manager = PowerlinePromptManager(powerline=powerline, shell=ip.prompt_manager.shell)
|
||||
|
||||
def shutdown_hook():
|
||||
powerline.renderer.shutdown()
|
||||
powerline.shutdown()
|
||||
raise TryNext()
|
||||
|
||||
ip.hooks.shutdown_hook.add(shutdown_hook)
|
||||
|
|
|
@ -56,7 +56,7 @@ class PowerlinePrompt(BasePrompt):
|
|||
|
||||
def set_p_str(self, width=None):
|
||||
self.p_str, self.p_str_nocolor = (
|
||||
self.powerline.renderer.render(output_raw=True,
|
||||
self.powerline.render(output_raw=True,
|
||||
segment_info=self.powerline_segment_info,
|
||||
matcher_info=self.powerline_prompt_type,
|
||||
width=width)
|
||||
|
@ -85,7 +85,7 @@ class PowerlinePrompt1(PowerlinePrompt):
|
|||
self.powerline_last_in['prompt_text_len'] = self.prompt_text_len
|
||||
|
||||
def auto_rewrite(self):
|
||||
return RewriteResult(self.powerline.renderer.render(matcher_info='rewrite', width=self.prompt_text_len, segment_info=self.powerline_segment_info)
|
||||
return RewriteResult(self.powerline.render(matcher_info='rewrite', width=self.prompt_text_len, segment_info=self.powerline_segment_info)
|
||||
+ (' ' * self.nrspaces))
|
||||
|
||||
|
||||
|
@ -128,7 +128,7 @@ def setup(**kwargs):
|
|||
raise TryNext()
|
||||
|
||||
def shutdown_hook():
|
||||
powerline.renderer.shutdown()
|
||||
powerline.shutdown()
|
||||
raise TryNext()
|
||||
|
||||
ip.IP.hooks.late_startup_hook.add(late_startup_hook)
|
||||
|
|
|
@ -15,7 +15,7 @@ class Powerline(base._TextBox):
|
|||
def update(self):
|
||||
if not self.configured:
|
||||
return True
|
||||
self.text = self.powerline.renderer.render(side='right')
|
||||
self.text = self.powerline.render(side='right')
|
||||
self.bar.draw()
|
||||
return True
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ endfunction
|
|||
function! Powerline(window_id)
|
||||
let winidx = index(map(range(1, winnr('$')), 's:GetWinID(v:val)'), a:window_id)
|
||||
let current = w:window_id is# a:window_id
|
||||
return s:pyeval('powerline.renderer.render('. a:window_id .', '. winidx .', '. current .')')
|
||||
return s:pyeval('powerline.render('. a:window_id .', '. winidx .', '. current .')')
|
||||
endfunction
|
||||
|
||||
function! PowerlineNew()
|
||||
|
@ -84,7 +84,7 @@ endfunction
|
|||
augroup Powerline
|
||||
autocmd! ColorScheme * :exec s:powerline_pycmd 'powerline.renderer.reset_highlight()'
|
||||
autocmd! VimEnter * :redrawstatus!
|
||||
autocmd! VimLeave * :exec s:powerline_pycmd 'powerline.renderer.shutdown()'
|
||||
autocmd! VimLeave * :exec s:powerline_pycmd 'powerline.shutdown()'
|
||||
augroup END
|
||||
|
||||
exec s:powerline_pycmd 'powerline = VimPowerline()'
|
||||
|
|
|
@ -10,7 +10,7 @@ used_powerlines = []
|
|||
|
||||
def shutdown():
|
||||
for powerline in used_powerlines:
|
||||
powerline.renderer.shutdown()
|
||||
powerline.shutdown()
|
||||
|
||||
|
||||
def get_var_config(var):
|
||||
|
@ -88,7 +88,7 @@ class Prompt(object):
|
|||
self.args = powerline.args
|
||||
|
||||
def __str__(self):
|
||||
r = self.powerline.renderer.render(width=zsh.columns(), side=self.side, segment_info=self.args)
|
||||
r = self.powerline.render(width=zsh.columns(), side=self.side, segment_info=self.args)
|
||||
if type(r) is not str:
|
||||
if type(r) is bytes:
|
||||
return r.decode('utf-8')
|
||||
|
@ -101,7 +101,7 @@ class Prompt(object):
|
|||
zsh.setvalue(self.savedpsvar, self.savedps)
|
||||
used_powerlines.remove(self.powerline)
|
||||
if self.powerline not in used_powerlines:
|
||||
self.powerline.renderer.shutdown()
|
||||
self.powerline.shutdown()
|
||||
|
||||
|
||||
def set_prompt(powerline, psvar, side):
|
||||
|
|
|
@ -17,7 +17,7 @@ if __name__ == '__main__':
|
|||
if 'PWD' in os.environ:
|
||||
kwargs['getcwd'] = lambda: os.environ['PWD']
|
||||
powerline = ShellPowerline(args, run_once=True, **kwargs)
|
||||
rendered = powerline.renderer.render(width=args.width, side=args.side, segment_info=args)
|
||||
rendered = powerline.render(width=args.width, side=args.side, segment_info=args)
|
||||
try:
|
||||
sys.stdout.write(rendered)
|
||||
except UnicodeEncodeError:
|
||||
|
|
|
@ -18,7 +18,7 @@ SBLOCK = chr(ord('S') - 0x40)
|
|||
def shutdown(powerline):
|
||||
from powerline.segments import common, vim
|
||||
try:
|
||||
powerline.renderer.shutdown()
|
||||
powerline.shutdown()
|
||||
finally:
|
||||
# After shutdown threads are useless, it is needed to recreate them.
|
||||
from imp import reload
|
||||
|
@ -39,7 +39,7 @@ class TestConfig(TestCase):
|
|||
powerline = VimPowerline()
|
||||
|
||||
def check_output(*args):
|
||||
out = powerline.renderer.render(*args + (0 if mode == 'nc' else 1,))
|
||||
out = powerline.render(*args + (0 if mode == 'nc' else 1,))
|
||||
if out in outputs:
|
||||
self.fail('Duplicate in set #{0} for mode {1!r} (previously defined in set #{2} for mode {3!r})'.format(i, mode, *outputs[out]))
|
||||
outputs[out] = (i, mode)
|
||||
|
@ -69,27 +69,27 @@ class TestConfig(TestCase):
|
|||
from powerline.shell import ShellPowerline
|
||||
with replace_attr(common, 'urllib_read', urllib_read):
|
||||
powerline = ShellPowerline(Args(ext=['tmux']), run_once=False)
|
||||
powerline.renderer.render()
|
||||
powerline.render()
|
||||
powerline = ShellPowerline(Args(ext=['tmux']), run_once=False)
|
||||
powerline.renderer.render()
|
||||
powerline.render()
|
||||
shutdown(powerline)
|
||||
|
||||
def test_zsh(self):
|
||||
from powerline.shell import ShellPowerline
|
||||
args = Args(last_pipe_status=[1, 0], ext=['shell'], renderer_module='zsh_prompt')
|
||||
powerline = ShellPowerline(args, run_once=False)
|
||||
powerline.renderer.render(segment_info=args)
|
||||
powerline.render(segment_info=args)
|
||||
powerline = ShellPowerline(args, run_once=False)
|
||||
powerline.renderer.render(segment_info=args)
|
||||
powerline.render(segment_info=args)
|
||||
shutdown(powerline)
|
||||
|
||||
def test_bash(self):
|
||||
from powerline.shell import ShellPowerline
|
||||
args = Args(last_exit_code=1, ext=['shell'], renderer_module='bash_prompt', config=[('ext', {'shell': {'theme': 'default_leftonly'}})])
|
||||
powerline = ShellPowerline(args, run_once=False)
|
||||
powerline.renderer.render(segment_info=args)
|
||||
powerline.render(segment_info=args)
|
||||
powerline = ShellPowerline(args, run_once=False)
|
||||
powerline.renderer.render(segment_info=args)
|
||||
powerline.render(segment_info=args)
|
||||
shutdown(powerline)
|
||||
|
||||
def test_ipython(self):
|
||||
|
@ -103,8 +103,8 @@ class TestConfig(TestCase):
|
|||
powerline = IpyPowerline()
|
||||
segment_info = Args(prompt_count=1)
|
||||
for prompt_type in ['in', 'in2', 'out', 'rewrite']:
|
||||
powerline.renderer.render(matcher_info=prompt_type, segment_info=segment_info)
|
||||
powerline.renderer.render(matcher_info=prompt_type, segment_info=segment_info)
|
||||
powerline.render(matcher_info=prompt_type, segment_info=segment_info)
|
||||
powerline.render(matcher_info=prompt_type, segment_info=segment_info)
|
||||
shutdown(powerline)
|
||||
|
||||
def test_wm(self):
|
||||
|
@ -113,7 +113,7 @@ class TestConfig(TestCase):
|
|||
reload(common)
|
||||
from powerline import Powerline
|
||||
with replace_attr(common, 'urllib_read', urllib_read):
|
||||
Powerline(ext='wm', renderer_module='pango_markup', run_once=True).renderer.render()
|
||||
Powerline(ext='wm', renderer_module='pango_markup', run_once=True).render()
|
||||
reload(common)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue