mirror of
https://github.com/powerline/powerline.git
synced 2025-07-24 22:36:01 +02:00
parent
1451b4261f
commit
917dfed842
@ -67,11 +67,82 @@ Powerline script has a number of options controlling powerline behavior. Here
|
|||||||
performed by powerline script itself, but ``-p ~/.powerline`` will likely be
|
performed by powerline script itself, but ``-p ~/.powerline`` will likely be
|
||||||
expanded by the shell to something like ``-p /home/user/.powerline``.
|
expanded by the shell to something like ``-p /home/user/.powerline``.
|
||||||
|
|
||||||
|
Environment variables overrides
|
||||||
|
===============================
|
||||||
|
|
||||||
|
All bindings that use ``POWERLINE_COMMAND`` environment variable support taking
|
||||||
|
overrides from environment variables. In this case overrides should look like
|
||||||
|
the following::
|
||||||
|
|
||||||
|
OVERRIDE='key1.key2.key3=value;key4.key5={"value":1};key6=true;key1.key7=10'
|
||||||
|
|
||||||
|
. This will be parsed into
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
{
|
||||||
|
"key1": {
|
||||||
|
"key2": {
|
||||||
|
"key3": "value"
|
||||||
|
},
|
||||||
|
"key7": 10,
|
||||||
|
},
|
||||||
|
"key4": {
|
||||||
|
"key5": {
|
||||||
|
"value": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"key6": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
. Rules:
|
||||||
|
|
||||||
|
#. Environment variable must form a semicolon-separated list of key-value pairs:
|
||||||
|
``key=value;key2=value2``.
|
||||||
|
#. Keys are always dot-separated strings that must not contain equals sign (as
|
||||||
|
well as semicolon) or start with an underscore. They are interpreted
|
||||||
|
literally and create a nested set of dictionaries: ``k1.k2.k3`` creates
|
||||||
|
``{"k1":{"k2":{}}}`` and inside the innermost dictionary last key (``k3`` in
|
||||||
|
the example) is contained with its value.
|
||||||
|
#. Value may be empty in which case they are interpreted as an order to remove
|
||||||
|
some value: ``k1.k2=`` will form ``{"k1":{"k2":REMOVE_THIS_KEY}}`` nested
|
||||||
|
dictionary where ``k2`` value is a special value that tells
|
||||||
|
dictionary-merging function to remove ``k2`` rather then replace it with
|
||||||
|
something.
|
||||||
|
#. Value may be a JSON strings like ``{"a":1}`` (JSON dictionary), ``["a",1]``
|
||||||
|
(JSON list), ``1`` or ``-1`` (JSON number), ``"abc"`` (JSON string) or
|
||||||
|
``true``, ``false`` and ``null`` (JSON boolean objects and ``Null`` object
|
||||||
|
from JSON). General rule is that anything starting with a digit (U+0030 till
|
||||||
|
U+0039, inclusive), a hyphenminus (U+002D), a quotation mark (U+0022), a left
|
||||||
|
curly bracket (U+007B) or a left square bracket (U+005B) is considered to be
|
||||||
|
some JSON object, same for *exact* values ``true``, ``false`` and ``null``.
|
||||||
|
#. Any other value is considered to be literal string: ``k1=foo:bar`` parses to
|
||||||
|
``{"k1": "foo:bar"}``.
|
||||||
|
|
||||||
|
The following environment variables may be used for overrides according to the
|
||||||
|
above rules:
|
||||||
|
|
||||||
|
``POWERLINE_CONFIG_OVERRIDES``
|
||||||
|
Overrides values from :file:`powerline/config.json`.
|
||||||
|
|
||||||
|
``POWERLINE_THEME_OVERRIDES``
|
||||||
|
Overrides values from :file:`powerline/themes/{ext}/{key}.json`. Top-level
|
||||||
|
key is treated as a name of the theme for which overrides are used: e.g. to
|
||||||
|
disable cwd segment defined in :file:`powerline/themes/shell/default.json`
|
||||||
|
one needs to use::
|
||||||
|
|
||||||
|
POWERLINE_THEME_OVERRIDES=default.segment_data.cwd.display=false
|
||||||
|
|
||||||
|
Additionally one environment variable is a usual *colon*-separated list of
|
||||||
|
directories: ``POWERLINE_CONFIG_PATHS``. This one defines paths which will be
|
||||||
|
searched for configuration.
|
||||||
|
|
||||||
Zsh/zpython overrides
|
Zsh/zpython overrides
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
Here overrides are controlled by similarly to the powerline script, but values
|
Here overrides are controlled by similarly to the powerline script, but values
|
||||||
are taken from zsh variables.
|
are taken from zsh variables. :ref:`Environment variable overrides` are also
|
||||||
|
supported: if variable is a string this variant is used.
|
||||||
|
|
||||||
``POWERLINE_CONFIG_OVERRIDES``
|
``POWERLINE_CONFIG_OVERRIDES``
|
||||||
Overrides options from :file:`powerline/config.json`. Should be a zsh
|
Overrides options from :file:`powerline/config.json`. Should be a zsh
|
||||||
|
@ -8,7 +8,7 @@ from weakref import WeakValueDictionary, ref
|
|||||||
import zsh
|
import zsh
|
||||||
|
|
||||||
from powerline.shell import ShellPowerline
|
from powerline.shell import ShellPowerline
|
||||||
from powerline.lib import parsedotval
|
from powerline.lib.overrides import parsedotval
|
||||||
from powerline.lib.unicode import unicode, u
|
from powerline.lib.unicode import unicode, u
|
||||||
from powerline.lib.encoding import (get_preferred_output_encoding,
|
from powerline.lib.encoding import (get_preferred_output_encoding,
|
||||||
get_preferred_environment_encoding)
|
get_preferred_environment_encoding)
|
||||||
|
@ -5,7 +5,9 @@ from __future__ import (division, absolute_import, print_function)
|
|||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from powerline.lib import parsedotval
|
from itertools import chain
|
||||||
|
|
||||||
|
from powerline.lib.overrides import parsedotval, parse_override_var
|
||||||
from powerline.lib.dict import mergeargs
|
from powerline.lib.dict import mergeargs
|
||||||
from powerline.lib.encoding import get_preferred_arguments_encoding
|
from powerline.lib.encoding import get_preferred_arguments_encoding
|
||||||
|
|
||||||
@ -14,21 +16,23 @@ if sys.version_info < (3,):
|
|||||||
encoding = get_preferred_arguments_encoding()
|
encoding = get_preferred_arguments_encoding()
|
||||||
|
|
||||||
def arg_to_unicode(s):
|
def arg_to_unicode(s):
|
||||||
return unicode(s, encoding, 'replace') if not isinstance(s, unicode) else s
|
return unicode(s, encoding, 'replace') if not isinstance(s, unicode) else s # NOQA
|
||||||
else:
|
else:
|
||||||
def arg_to_unicode(s):
|
def arg_to_unicode(s):
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
def finish_args(args):
|
def finish_args(environ, args):
|
||||||
if args.config_override:
|
args.config_override = mergeargs(chain(
|
||||||
args.config_override = mergeargs((parsedotval(v) for v in args.config_override))
|
(parsedotval(v) for v in args.config_override or ()),
|
||||||
if args.theme_override:
|
parse_override_var(environ.get('POWERLINE_CONFIG_OVERRIDES', '')),
|
||||||
args.theme_override = mergeargs((parsedotval(v) for v in args.theme_override))
|
))
|
||||||
else:
|
args.theme_override = mergeargs(chain(
|
||||||
args.theme_override = {}
|
(parsedotval(v) for v in args.theme_override or ()),
|
||||||
|
parse_override_var(environ.get('POWERLINE_THEME_OVERRIDES', '')),
|
||||||
|
))
|
||||||
if args.renderer_arg:
|
if args.renderer_arg:
|
||||||
args.renderer_arg = mergeargs((parsedotval(v) for v in args.renderer_arg))
|
args.renderer_arg = mergeargs((parsedotval(v) for v in args.renderer_arg), remove=True)
|
||||||
|
|
||||||
|
|
||||||
def get_argparser(ArgumentParser=argparse.ArgumentParser):
|
def get_argparser(ArgumentParser=argparse.ArgumentParser):
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
# vim:fileencoding=utf-8:noet
|
# vim:fileencoding=utf-8:noet
|
||||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from powerline.lib.dict import REMOVE_THIS_KEY
|
|
||||||
|
|
||||||
|
|
||||||
def wraps_saveargs(wrapped):
|
def wraps_saveargs(wrapped):
|
||||||
def dec(wrapper):
|
def dec(wrapper):
|
||||||
@ -30,59 +26,3 @@ def add_divider_highlight_group(highlight_group):
|
|||||||
return None
|
return None
|
||||||
return f
|
return f
|
||||||
return dec
|
return dec
|
||||||
|
|
||||||
|
|
||||||
def parse_value(s):
|
|
||||||
'''Convert string to Python object
|
|
||||||
|
|
||||||
Rules:
|
|
||||||
|
|
||||||
* Empty string means that corresponding key should be removed from the
|
|
||||||
dictionary.
|
|
||||||
* Strings that start with a minus, digit or with some character that starts
|
|
||||||
JSON collection or string object are parsed as JSON.
|
|
||||||
* JSON special values ``null``, ``true``, ``false`` (case matters) are
|
|
||||||
parsed as JSON.
|
|
||||||
* All other values are considered to be raw strings.
|
|
||||||
|
|
||||||
:param str s: Parsed string.
|
|
||||||
|
|
||||||
:return: Python object.
|
|
||||||
'''
|
|
||||||
if not s:
|
|
||||||
return REMOVE_THIS_KEY
|
|
||||||
elif s[0] in '"{[0193456789-' or s in ('null', 'true', 'false'):
|
|
||||||
return json.loads(s)
|
|
||||||
else:
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
def keyvaluesplit(s):
|
|
||||||
if '=' not in s:
|
|
||||||
raise TypeError('Option must look like option=json_value')
|
|
||||||
if s[0] == '_':
|
|
||||||
raise ValueError('Option names must not start with `_\'')
|
|
||||||
idx = s.index('=')
|
|
||||||
o = s[:idx]
|
|
||||||
val = parse_value(s[idx + 1:])
|
|
||||||
return (o, val)
|
|
||||||
|
|
||||||
|
|
||||||
def parsedotval(s):
|
|
||||||
if type(s) is tuple:
|
|
||||||
o, val = s
|
|
||||||
val = parse_value(val)
|
|
||||||
else:
|
|
||||||
o, val = keyvaluesplit(s)
|
|
||||||
|
|
||||||
keys = o.split('.')
|
|
||||||
if len(keys) > 1:
|
|
||||||
r = (keys[0], {})
|
|
||||||
rcur = r[1]
|
|
||||||
for key in keys[1:-1]:
|
|
||||||
rcur[key] = {}
|
|
||||||
rcur = rcur[key]
|
|
||||||
rcur[keys[-1]] = val
|
|
||||||
return r
|
|
||||||
else:
|
|
||||||
return (o, val)
|
|
||||||
|
@ -5,26 +5,44 @@ from __future__ import (unicode_literals, division, absolute_import, print_funct
|
|||||||
REMOVE_THIS_KEY = object()
|
REMOVE_THIS_KEY = object()
|
||||||
|
|
||||||
|
|
||||||
def mergeargs(argvalue):
|
def mergeargs(argvalue, remove=False):
|
||||||
if not argvalue:
|
if not argvalue:
|
||||||
return None
|
return None
|
||||||
r = {}
|
r = {}
|
||||||
for subval in argvalue:
|
for subval in argvalue:
|
||||||
mergedicts(r, dict([subval]))
|
mergedicts(r, dict([subval]), remove=remove)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def mergedicts(d1, d2):
|
def _clear_special_values(d):
|
||||||
|
'''Remove REMOVE_THIS_KEY values from dictionary
|
||||||
|
'''
|
||||||
|
l = [d]
|
||||||
|
while l:
|
||||||
|
i = l.pop()
|
||||||
|
pops = []
|
||||||
|
for k, v in i.items():
|
||||||
|
if v is REMOVE_THIS_KEY:
|
||||||
|
pops.append(k)
|
||||||
|
elif isinstance(v, dict):
|
||||||
|
l.append(v)
|
||||||
|
for k in pops:
|
||||||
|
i.pop(k)
|
||||||
|
|
||||||
|
|
||||||
|
def mergedicts(d1, d2, remove=True):
|
||||||
'''Recursively merge two dictionaries
|
'''Recursively merge two dictionaries
|
||||||
|
|
||||||
First dictionary is modified in-place.
|
First dictionary is modified in-place.
|
||||||
'''
|
'''
|
||||||
for k in d2:
|
for k in d2:
|
||||||
if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict):
|
if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict):
|
||||||
mergedicts(d1[k], d2[k])
|
mergedicts(d1[k], d2[k], remove)
|
||||||
elif d2[k] is REMOVE_THIS_KEY:
|
elif remove and d2[k] is REMOVE_THIS_KEY:
|
||||||
d1.pop(k, None)
|
d1.pop(k, None)
|
||||||
else:
|
else:
|
||||||
|
if remove and isinstance(d2[k], dict):
|
||||||
|
_clear_special_values(d2[k])
|
||||||
d1[k] = d2[k]
|
d1[k] = d2[k]
|
||||||
|
|
||||||
|
|
||||||
|
80
powerline/lib/overrides.py
Normal file
80
powerline/lib/overrides.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# vim:fileencoding=utf-8:noet
|
||||||
|
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from powerline.lib.dict import REMOVE_THIS_KEY
|
||||||
|
|
||||||
|
|
||||||
|
def parse_value(s):
|
||||||
|
'''Convert string to Python object
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
|
||||||
|
* Empty string means that corresponding key should be removed from the
|
||||||
|
dictionary.
|
||||||
|
* Strings that start with a minus, digit or with some character that starts
|
||||||
|
JSON collection or string object are parsed as JSON.
|
||||||
|
* JSON special values ``null``, ``true``, ``false`` (case matters) are
|
||||||
|
parsed as JSON.
|
||||||
|
* All other values are considered to be raw strings.
|
||||||
|
|
||||||
|
:param str s: Parsed string.
|
||||||
|
|
||||||
|
:return: Python object.
|
||||||
|
'''
|
||||||
|
if not s:
|
||||||
|
return REMOVE_THIS_KEY
|
||||||
|
elif s[0] in '"{[0193456789-' or s in ('null', 'true', 'false'):
|
||||||
|
return json.loads(s)
|
||||||
|
else:
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def keyvaluesplit(s):
|
||||||
|
'''Split K1.K2=VAL into K1.K2 and parsed VAL
|
||||||
|
'''
|
||||||
|
if '=' not in s:
|
||||||
|
raise TypeError('Option must look like option=json_value')
|
||||||
|
if s[0] == '_':
|
||||||
|
raise ValueError('Option names must not start with `_\'')
|
||||||
|
idx = s.index('=')
|
||||||
|
o = s[:idx]
|
||||||
|
val = parse_value(s[idx + 1:])
|
||||||
|
return (o, val)
|
||||||
|
|
||||||
|
|
||||||
|
def parsedotval(s):
|
||||||
|
'''Parse K1.K2=VAL into {"K1":{"K2":VAL}}
|
||||||
|
|
||||||
|
``VAL`` is processed according to rules defined in :py:func:`parse_value`.
|
||||||
|
'''
|
||||||
|
if type(s) is tuple:
|
||||||
|
o, val = s
|
||||||
|
val = parse_value(val)
|
||||||
|
else:
|
||||||
|
o, val = keyvaluesplit(s)
|
||||||
|
|
||||||
|
keys = o.split('.')
|
||||||
|
if len(keys) > 1:
|
||||||
|
r = (keys[0], {})
|
||||||
|
rcur = r[1]
|
||||||
|
for key in keys[1:-1]:
|
||||||
|
rcur[key] = {}
|
||||||
|
rcur = rcur[key]
|
||||||
|
rcur[keys[-1]] = val
|
||||||
|
return r
|
||||||
|
else:
|
||||||
|
return (o, val)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_override_var(s):
|
||||||
|
'''Parse a semicolon-separated list of strings into a sequence of values
|
||||||
|
|
||||||
|
Emits the same items in sequence as :py:func:`parsedotval` does.
|
||||||
|
'''
|
||||||
|
return (
|
||||||
|
parsedotval(item)
|
||||||
|
for item in s.split(';')
|
||||||
|
if item
|
||||||
|
)
|
@ -78,8 +78,11 @@ def render(args, environ, cwd):
|
|||||||
tuple(args.config_override) if args.config_override else None,
|
tuple(args.config_override) if args.config_override else None,
|
||||||
tuple(args.theme_override) if args.theme_override else None,
|
tuple(args.theme_override) if args.theme_override else None,
|
||||||
tuple(args.config_path) if args.config_path else None,
|
tuple(args.config_path) if args.config_path else None,
|
||||||
|
environ.get('POWERLINE_THEME_OVERRIDES', ''),
|
||||||
|
environ.get('POWERLINE_CONFIG_OVERRIDES', ''),
|
||||||
|
environ.get('POWERLINE_CONFIG_PATHS', ''),
|
||||||
)
|
)
|
||||||
finish_args(args)
|
finish_args(environ, args)
|
||||||
powerline = None
|
powerline = None
|
||||||
try:
|
try:
|
||||||
powerline = powerlines[key]
|
powerline = powerlines[key]
|
||||||
|
@ -24,7 +24,7 @@ else:
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
args = get_argparser().parse_args()
|
args = get_argparser().parse_args()
|
||||||
finish_args(args)
|
finish_args(os.environ, args)
|
||||||
powerline = ShellPowerline(args, run_once=True)
|
powerline = ShellPowerline(args, run_once=True)
|
||||||
segment_info = {'args': args, 'environ': os.environ}
|
segment_info = {'args': args, 'environ': os.environ}
|
||||||
write_output(args, powerline, segment_info, write, get_preferred_output_encoding())
|
write_output(args, powerline, segment_info, write, get_preferred_output_encoding())
|
||||||
|
@ -114,7 +114,7 @@ class TestParser(TestCase):
|
|||||||
(['shell', '-c', 'common={ }'], {'ext': ['shell'], 'config_override': {'common': {}}}),
|
(['shell', '-c', 'common={ }'], {'ext': ['shell'], 'config_override': {'common': {}}}),
|
||||||
]:
|
]:
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
finish_args(args)
|
finish_args({}, args)
|
||||||
for key, val in expargs.items():
|
for key, val in expargs.items():
|
||||||
self.assertEqual(getattr(args, key), val)
|
self.assertEqual(getattr(args, key), val)
|
||||||
for key, val in args.__dict__.items():
|
for key, val in args.__dict__.items():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user