Merge branch 'top-theme-extend' into develop
This commit is contained in:
commit
9fe0b66125
|
@ -265,6 +265,8 @@ extension-specific key <config-ext-top_theme>` or from :ref:`default_top_theme
|
|||
common configuration key <config-common-default_top_theme>`. Powerline ships
|
||||
with the following top themes:
|
||||
|
||||
.. _config-top_themes-list:
|
||||
|
||||
========================== ====================================================
|
||||
Theme Description
|
||||
========================== ====================================================
|
||||
|
|
|
@ -29,6 +29,52 @@ object it should receive the following arguments:
|
|||
And also any other argument(s) specified by user in :ref:`args key
|
||||
<config-themes-seg-args>` (no additional arguments by default).
|
||||
|
||||
Object representing segment may have the following attributes used by
|
||||
powerline:
|
||||
|
||||
``powerline_requires_segment_info``
|
||||
This attribute controls whether segment will receive ``segment_info``
|
||||
argument: if it is present argument will be received.
|
||||
|
||||
``powerline_requires_filesystem_watcher``
|
||||
This attribute controls whether segment will receive ``create_watcher``
|
||||
argument: if it is present argument will be received.
|
||||
|
||||
``powerline_segment_datas``
|
||||
This attribute must be a dictionary containing ``top_theme: segment_data``
|
||||
mapping where ``top_theme`` is any theme name (it is expected that all of
|
||||
the names from :ref:`top-level themes list <config-top_themes-list>` are
|
||||
present) and ``segment_data`` is a dictionary like the one that is contained
|
||||
inside :ref:`segment_data dictionary in configuration
|
||||
<config-themes-segment_data>`. This attribute should be used to specify
|
||||
default theme-specific values for *third-party* segments: powerline
|
||||
theme-specific values go directly to :ref:`top-level themes
|
||||
<config-themes>`.
|
||||
|
||||
``startup``
|
||||
This attribute must be a callable which accepts the following keyword
|
||||
arguments:
|
||||
|
||||
* ``pl``: :py:class:`powerline.PowerlineLogger` instance which is to be used
|
||||
for logging.
|
||||
* ``shutdown_event``: :py:class:`Event` object which will be set when
|
||||
powerline will be shut down.
|
||||
* Any arguments found in user configuration for the given segment (i.e.
|
||||
:ref:`args key <config-themes-seg-args>`).
|
||||
|
||||
This function is called at powerline startup when using long-running
|
||||
processes (e.g. powerline in vim, in zsh with libzpython, in ipython or in
|
||||
powerline daemon) and not called when ``powerline-render`` executable is
|
||||
used (more specific: when :py:class:`powerline.Powerline` constructor
|
||||
received true ``run_once`` argument).
|
||||
|
||||
``shutdown``
|
||||
This attribute must be a callable that accepts no arguments and shuts down
|
||||
threads and frees any other resources allocated in ``startup`` method of the
|
||||
segment in question.
|
||||
|
||||
This function is not called when ``startup`` method is not called.
|
||||
|
||||
This callable object should may return either a string (``unicode`` in Python2
|
||||
or ``str`` in Python3, *not* ``str`` in Python2 or ``bytes`` in Python3) object
|
||||
or a list of dictionaries. String object is a short form of the following return
|
||||
|
|
|
@ -485,13 +485,15 @@ class Powerline(object):
|
|||
|
||||
self.ext_config = config['ext'][self.ext]
|
||||
|
||||
self.theme_levels = (
|
||||
os.path.join('themes', (
|
||||
top_theme = (
|
||||
self.ext_config.get('top_theme')
|
||||
or self.common_config['default_top_theme']
|
||||
)),
|
||||
)
|
||||
self.theme_levels = (
|
||||
os.path.join('themes', top_theme),
|
||||
os.path.join('themes', self.ext, '__main__'),
|
||||
)
|
||||
self.renderer_options['theme_kwargs']['top_theme'] = top_theme
|
||||
|
||||
if self.ext_config != self.prev_ext_config:
|
||||
ext_config_differs = True
|
||||
|
|
|
@ -15,7 +15,9 @@ def wraps_saveargs(wrapped):
|
|||
|
||||
|
||||
def mergedicts(d1, d2):
|
||||
'''Recursively merge two dictionaries. First dictionary is modified in-place.
|
||||
'''Recursively merge two dictionaries
|
||||
|
||||
First dictionary is modified in-place.
|
||||
'''
|
||||
for k in d2:
|
||||
if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict):
|
||||
|
@ -26,11 +28,23 @@ def mergedicts(d1, d2):
|
|||
d1[k] = d2[k]
|
||||
|
||||
|
||||
def mergedefaults(d1, d2):
|
||||
'''Recursively merge two dictionaries, keeping existing values
|
||||
|
||||
First dictionary is modified in-place.
|
||||
'''
|
||||
for k in d2:
|
||||
if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict):
|
||||
mergedefaults(d1[k], d2[k])
|
||||
else:
|
||||
d1.setdefault(k, d2[k])
|
||||
|
||||
|
||||
def mergedicts_copy(d1, d2):
|
||||
'''Recursively merge two dictionaries.
|
||||
|
||||
Dictionaries are not modified. Copying happens only if necessary. Assumes
|
||||
that first dictionary support .copy() method.
|
||||
that first dictionary supports .copy() method.
|
||||
'''
|
||||
ret = d1.copy()
|
||||
for k in d2:
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from inspect import ArgSpec, getargspec
|
||||
from itertools import count
|
||||
|
||||
from powerline.lib.threaded import ThreadedSegment, KwThreadedSegment
|
||||
from powerline.segments import Segment
|
||||
|
||||
|
||||
|
@ -31,8 +29,8 @@ def getconfigargspec(obj):
|
|||
if len(arg) > 1:
|
||||
defaults.append(arg[1])
|
||||
|
||||
requires_segment_info = getattr(obj, 'powerline_requires_segment_info', False)
|
||||
requires_filesystem_watcher = getattr(obj, 'powerline_requires_filesystem_watcher', False)
|
||||
requires_segment_info = hasattr(obj, 'powerline_requires_segment_info')
|
||||
requires_filesystem_watcher = hasattr(obj, 'powerline_requires_filesystem_watcher')
|
||||
|
||||
for name, method in argspecobjs:
|
||||
argspec = getargspec(method)
|
||||
|
|
|
@ -4,7 +4,7 @@ from __future__ import absolute_import, unicode_literals, division, print_functi
|
|||
from powerline.lib.watcher import create_file_watcher
|
||||
|
||||
|
||||
def list_segment_key_values(segment, theme_configs, key, module=None, default=None):
|
||||
def list_segment_key_values(segment, theme_configs, segment_data, key, module=None, default=None):
|
||||
try:
|
||||
yield segment[key]
|
||||
except KeyError:
|
||||
|
@ -32,6 +32,11 @@ def list_segment_key_values(segment, theme_configs, key, module=None, default=No
|
|||
yield segment_data[name][key]
|
||||
except KeyError:
|
||||
pass
|
||||
if segment_data is not None:
|
||||
try:
|
||||
yield segment_data[key]
|
||||
except KeyError:
|
||||
pass
|
||||
yield default
|
||||
|
||||
|
||||
|
@ -173,14 +178,15 @@ def process_segment(pl, side, segment_info, parsed_segments, segment, mode):
|
|||
parsed_segments.append(segment)
|
||||
|
||||
|
||||
def gen_segment_getter(pl, ext, common_config, theme_configs, default_module, get_module_attr):
|
||||
def gen_segment_getter(pl, ext, common_config, theme_configs, default_module, get_module_attr, top_theme):
|
||||
data = {
|
||||
'default_module': default_module or 'powerline.segments.' + ext,
|
||||
'get_module_attr': get_module_attr,
|
||||
'segment_data': None,
|
||||
}
|
||||
|
||||
def get_key(merge, segment, module, key, default=None):
|
||||
return get_segment_key(merge, segment, theme_configs, key, module, default)
|
||||
return get_segment_key(merge, segment, theme_configs, data['segment_data'], key, module, default)
|
||||
data['get_key'] = get_key
|
||||
|
||||
def get(segment, side):
|
||||
|
@ -199,6 +205,13 @@ def gen_segment_getter(pl, ext, common_config, theme_configs, default_module, ge
|
|||
if not get_key(False, segment, module, 'display', True):
|
||||
return None
|
||||
|
||||
segment_datas = getattr(_contents_func, 'powerline_segment_datas', None)
|
||||
if segment_datas:
|
||||
try:
|
||||
data['segment_data'] = segment_datas[top_theme]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if segment_type == 'function':
|
||||
highlight_group = [module + '.' + segment['name'], segment['name']]
|
||||
else:
|
||||
|
|
|
@ -30,6 +30,7 @@ class Theme(object):
|
|||
common_config,
|
||||
pl,
|
||||
get_module_attr,
|
||||
top_theme,
|
||||
main_theme_config=None,
|
||||
run_once=False,
|
||||
shutdown_event=None):
|
||||
|
@ -54,7 +55,15 @@ class Theme(object):
|
|||
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)
|
||||
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())
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import unicode_literals, absolute_import, division
|
||||
import tests.vim as vim_module
|
||||
from tests import TestCase
|
||||
from tests.lib.config_mock import get_powerline, get_powerline_raw, swap_attributes
|
||||
from functools import wraps
|
||||
from copy import deepcopy
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
from functools import wraps
|
||||
from copy import deepcopy
|
||||
|
||||
import tests.vim as vim_module
|
||||
|
||||
from tests import TestCase
|
||||
from tests.lib.config_mock import get_powerline, get_powerline_raw, swap_attributes
|
||||
from tests.lib import Args
|
||||
|
||||
|
||||
def highlighted_string(s, group, **kwargs):
|
||||
ret = {
|
||||
|
@ -428,6 +433,50 @@ class TestModes(TestRender):
|
|||
self.assertRenderEqual(p, '{56} s2{6-}>>{--}', mode='m3')
|
||||
|
||||
|
||||
class TestSegmentAttributes(TestRender):
|
||||
@add_args
|
||||
def test_no_attributes(self, p, config):
|
||||
def m1(divider=',', **kwargs):
|
||||
return divider.join(kwargs.keys()) + divider
|
||||
sys.modules['bar'] = Args(m1=m1)
|
||||
config['themes/test/default']['segments'] = {
|
||||
'left': [
|
||||
{
|
||||
'name': 'm1',
|
||||
'module': 'bar'
|
||||
}
|
||||
]
|
||||
}
|
||||
self.assertRenderEqual(p, '{56} pl,{6-}>>{--}')
|
||||
|
||||
@add_args
|
||||
def test_segment_datas(self, p, config):
|
||||
def m1(divider=',', **kwargs):
|
||||
return divider.join(kwargs.keys()) + divider
|
||||
m1.powerline_segment_datas = {
|
||||
'powerline': {
|
||||
'args': {
|
||||
'divider': ';'
|
||||
}
|
||||
},
|
||||
'ascii': {
|
||||
'args': {
|
||||
'divider': '--'
|
||||
}
|
||||
}
|
||||
}
|
||||
sys.modules['bar'] = Args(m1=m1)
|
||||
config['themes/test/default']['segments'] = {
|
||||
'left': [
|
||||
{
|
||||
'name': 'm1',
|
||||
'module': 'bar'
|
||||
}
|
||||
]
|
||||
}
|
||||
self.assertRenderEqual(p, '{56} pl;{6-}>>{--}')
|
||||
|
||||
|
||||
class TestVim(TestCase):
|
||||
def test_environ_update(self):
|
||||
# Regression test: test that segment obtains environment from vim, not
|
||||
|
|
Loading…
Reference in New Issue