mirror of
https://github.com/powerline/powerline.git
synced 2025-07-20 12:25:04 +02:00
Release 2.4
- Added `short` parameter for `system_load` segment that leaves only one load average number out of three. - Added `powerline.segments.i3wm.scratchpad` segment used to list windows that are currently on the scratchpad. - Added support for multiple batteries in battery segment. - Added `….i3wm.workspace` segment which describes single i3wm workspace and workspaces lister. Old `….i3wm.workspaces` segment was deprecated. - Added support for multiple monitors in lemonbar bindings. - Added support for most recent tmux version (2.2). - Fixed battery status support on some linux systems. - Fixed MPD bindings: they sometimes were not able to handle names if they did not fit ASCII. - Fixed MPD bindings: they did not correctly get elapsed time. - Fixed AttributeError on some systems: LC_MESSAGES is not always available. - Fixed Mac OS-specific variant of spotify player support when Python-3 is used. - Fixed performance of the tabline.
This commit is contained in:
commit
d77cc30a3b
@ -24,12 +24,9 @@ matrix:
|
||||
- python: "3.2"
|
||||
- python: "3.3"
|
||||
- python: "3.4"
|
||||
- python: "3.5"
|
||||
- python: "pypy"
|
||||
- python: "pypy3"
|
||||
- python: "2.6"
|
||||
env: >-
|
||||
USE_UCS2_PYTHON=1
|
||||
UCS2_PYTHON_VARIANT="2.6"
|
||||
- python: "2.7"
|
||||
env: >-
|
||||
USE_UCS2_PYTHON=1
|
||||
|
@ -1,6 +1,7 @@
|
||||
recursive-include powerline *.json *.vim
|
||||
recursive-include powerline/bindings *.*
|
||||
recursive-exclude powerline/bindings *.pyc *.pyo
|
||||
recursive-include powerline/dist *.*
|
||||
recursive-include client *.*
|
||||
recursive-include docs/source *.rst *.py
|
||||
include docs/Makefile
|
||||
|
@ -16,8 +16,6 @@ their type and ``segments`` key with a list of segments (a bit more details in
|
||||
|
||||
More information in :ref:`Writing listers <dev-listers>` section.
|
||||
|
||||
Currently only Vim listers are available.
|
||||
|
||||
Vim listers
|
||||
-----------
|
||||
|
||||
@ -29,3 +27,9 @@ Pdb listers
|
||||
|
||||
.. automodule:: powerline.listers.pdb
|
||||
:members:
|
||||
|
||||
i3wm listers
|
||||
----------
|
||||
|
||||
.. automodule:: powerline.listers.i3wm
|
||||
:members:
|
||||
|
@ -12,6 +12,8 @@ Vim overrides
|
||||
|
||||
Vim configuration can be overridden using the following options:
|
||||
|
||||
.. _local-configuration-overrides-vim-config:
|
||||
|
||||
``g:powerline_config_overrides``
|
||||
Dictionary, recursively merged with contents of
|
||||
:file:`powerline/config.json`.
|
||||
@ -37,6 +39,17 @@ Vim configuration can be overridden using the following options:
|
||||
was configured in :ref:`log_* options <config-common-log>`. Level is always
|
||||
:ref:`log_level <config-common-log_level>`, same for format.
|
||||
|
||||
.. warning::
|
||||
This variable is deprecated. Use :ref:`log_file option
|
||||
<config-common-log>` in conjunction with
|
||||
:py:class:`powerline.vim.VimVarHandler` class and :ref:`Vim config
|
||||
overrides variable <local-configuration-overrides-vim-config>`. Using
|
||||
this is also the only variant to make saving into the environment
|
||||
variable the *only* place where log is saved or save into different
|
||||
variable.
|
||||
|
||||
.. autoclass:: powerline.vim.VimVarHandler
|
||||
|
||||
.. _local-configuration-overrides-script:
|
||||
|
||||
Powerline script overrides
|
||||
|
@ -94,14 +94,38 @@ Common configuration is a subdictionary that is a value of ``common`` key in
|
||||
.. _config-common-log:
|
||||
|
||||
``log_file``
|
||||
Defines path which will hold powerline logs. If not present, logging will be
|
||||
done to stderr.
|
||||
Defines how logs will be handled. There are three variants here:
|
||||
|
||||
#. Absent. In this case logging will be done to stderr: equivalent to
|
||||
``[["logging.StreamHandler", []]]`` or ``[null]``.
|
||||
#. Plain string. In this case logging will be done to the given file:
|
||||
``"/file/name"`` is equivalent to ``[["logging.FileHandler",
|
||||
[["/file/name"]]]]`` or ``["/file/name"]``. Leading ``~/`` is expanded in
|
||||
the file name, so using ``"~/.log/foo"`` is permitted. If directory
|
||||
pointed by the option is absent, it will be created, but not its parent.
|
||||
#. List of handler definitions. Handler definition may either be ``null``,
|
||||
a string or a list with two or three elements:
|
||||
|
||||
#. Logging class name and module. If module name is absent, it is
|
||||
equivalent to ``logging.handlers``.
|
||||
#. Class constructor arguments in a form ``[[args[, kwargs]]]``: accepted
|
||||
variants are ``[]`` (no arguments), ``[args]`` (e.g.
|
||||
``[["/file/name"]]``: only positional arguments) or ``[args, kwargs]``
|
||||
(e.g. ``[[], {"host": "localhost", "port": 6666}]``: positional and
|
||||
keyword arguments, but no positional arguments in the example).
|
||||
#. Optional logging level. Overrides :ref:`log_level key
|
||||
<config-common-log_level>` and has the same format.
|
||||
#. Optional format string. Partially overrides :ref:`log_format key
|
||||
<config-common-log_format>` and has the same format. “Partially” here
|
||||
means that it may only specify more critical level.
|
||||
|
||||
.. _config-common-log_level:
|
||||
|
||||
``log_level``
|
||||
String, determines logging level. Defaults to ``WARNING``.
|
||||
|
||||
.. _config-common-log_format:
|
||||
|
||||
``log_format``
|
||||
String, determines format of the log messages. Defaults to
|
||||
``'%(asctime)s:%(level)s:%(message)s'``.
|
||||
@ -163,6 +187,10 @@ Common configuration is a subdictionary that is a value of ``ext`` key in
|
||||
``out`` and ``rewrite`` prompts (refer to IPython documentation for more
|
||||
details) while ``in`` prompt is the default.
|
||||
|
||||
For wm (:ref:`lemonbar <lemonbar-usage>` only) it is a dictionary
|
||||
``{output : theme_name}`` that maps the ``xrandr`` output names to the
|
||||
local themes to use on that output.
|
||||
|
||||
``components``
|
||||
Determines which extension components should be enabled. This key is highly
|
||||
extension-specific, here is the table of extensions and corresponding
|
||||
|
@ -305,7 +305,7 @@ Segment dictionary contains the following keys:
|
||||
``side``
|
||||
Segment side: ``right`` or ``left``.
|
||||
|
||||
``display_condition```
|
||||
``display_condition``
|
||||
Contains function that takes three position parameters:
|
||||
:py:class:`powerline.PowerlineLogger` instance, :ref:`segment_info
|
||||
<dev-segments-info>` dictionary and current mode and returns either ``True``
|
||||
@ -517,6 +517,22 @@ Pdb
|
||||
Equal to the length of :py:attr:`pdb.Pdb.stack` at the first invocation of
|
||||
the prompt decremented by one.
|
||||
|
||||
i3wm
|
||||
----
|
||||
|
||||
``mode``
|
||||
Currently active i3 mode (as a string).
|
||||
|
||||
``output``
|
||||
``xrandr`` output name currently drawing to. Currently only available
|
||||
in lemonbar bindings.
|
||||
|
||||
``workspace``
|
||||
dictionary containing the workspace name under the key ``"name"`` and
|
||||
boolean values for the ``"visible"``, ``"urgent"`` and ``"focused"``
|
||||
keys, indicating the state of the workspace. Currently only provided by
|
||||
the :py:func:`powerline.listers.i3wm.workspace_lister` lister.
|
||||
|
||||
Segment class
|
||||
=============
|
||||
|
||||
|
@ -30,8 +30,9 @@ Generic requirements
|
||||
with bazaar repositories.
|
||||
* ``pyuv`` python package. Required for :ref:`libuv-based watcher
|
||||
<config-common-watcher>` to work.
|
||||
* ``i3-py``, `available on github <https://github.com/ziberna/i3-py>`_. Required
|
||||
for i3wm bindings and segments.
|
||||
* ``i3-ipc`` python package. Required for i3wm bindings and segments.
|
||||
* ``xrandr`` program. Required for the multi-monitor lemonbar binding and the
|
||||
:py:func:`powerline.listers.i3wm.output_lister`.
|
||||
|
||||
.. note::
|
||||
Until mercurial and bazaar support Python-3 or PyPy powerline will not
|
||||
|
@ -11,12 +11,10 @@ Python package
|
||||
|
||||
sudo port select python python27-apple
|
||||
|
||||
. Homebrew may be used here::
|
||||
Homebrew may be used here::
|
||||
|
||||
brew install python
|
||||
|
||||
.
|
||||
|
||||
.. note::
|
||||
In case :file:`powerline.sh` as a client ``socat`` and ``coreutils`` need
|
||||
to be installed. ``coreutils`` may be installed using ``brew install
|
||||
@ -56,13 +54,13 @@ Vim installation
|
||||
Any terminal vim version with Python 3.2+ or Python 2.6+ support should work,
|
||||
but MacVim users need to install it using the following command::
|
||||
|
||||
brew install macvim --env-std --override-system-vim
|
||||
brew install macvim --env-std --with-override-system-vim
|
||||
|
||||
Fonts installation
|
||||
==================
|
||||
|
||||
Install downloaded patched font by double-clicking the font file in Finder, then
|
||||
clicking :guilabel:`Install this font` in the preview window.
|
||||
To install patched font double-click the font file in Finder, then click
|
||||
:guilabel:`Install this font` in the preview window.
|
||||
|
||||
After installing the patched font MacVim or terminal emulator (whatever
|
||||
application powerline should work with) need to be configured to use the patched
|
||||
|
@ -6,6 +6,7 @@ import re
|
||||
import codecs
|
||||
|
||||
from collections import namedtuple
|
||||
from argparse import REMAINDER
|
||||
|
||||
from functools import reduce
|
||||
|
||||
@ -61,9 +62,9 @@ def parse_argument(*args, **kwargs):
|
||||
is_option = args[0].startswith('-')
|
||||
is_long_option = args[0].startswith('--')
|
||||
is_short_option = is_option and not is_long_option
|
||||
action = kwargs.get('action', 'store_true')
|
||||
multi = kwargs.get('action') in ('append',)
|
||||
nargs = kwargs.get('nargs') or (1 if kwargs.get('metavar') or action in ('append',) else 0)
|
||||
action = kwargs.get('action', 'store')
|
||||
multi = kwargs.get('action') in ('append',) or kwargs.get('nargs') is REMAINDER
|
||||
nargs = kwargs.get('nargs', (1 if action in ('append', 'store') else 0))
|
||||
return Argument(
|
||||
names=args,
|
||||
help=u(kwargs.get('help', '')),
|
||||
@ -165,9 +166,20 @@ def format_usage_arguments(arguments, base_length=None):
|
||||
# `--` is automatically transformed into – (EN DASH)
|
||||
# when parsing into HTML. We do not need this.
|
||||
line[-1] += [nodes.Text(char) for char in name]
|
||||
elif argument.nargs is REMAINDER:
|
||||
line.append(nodes.Text('['))
|
||||
line.append(nodes.strong())
|
||||
line[-1] += [nodes.Text(char) for char in '--']
|
||||
line.append(nodes.Text('] '))
|
||||
if argument.nargs:
|
||||
assert(argument.nargs in (1, '?'))
|
||||
with SurroundWith(line, argument.nargs == '?' and argument.is_option):
|
||||
assert(argument.nargs in (1, '?', REMAINDER))
|
||||
with SurroundWith(
|
||||
line, (
|
||||
True
|
||||
if argument.nargs is REMAINDER
|
||||
else (argument.nargs == '?' and argument.is_option)
|
||||
)
|
||||
):
|
||||
if argument.is_long_option:
|
||||
line.append(nodes.Text('='))
|
||||
line.append(nodes.emphasis(text=argument.metavar))
|
||||
@ -337,15 +349,21 @@ class AutoManParser(object):
|
||||
class AutoMan(Directive):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
option_spec = dict(prog=unchanged_required)
|
||||
option_spec = dict(prog=unchanged_required, minimal=bool)
|
||||
has_content = False
|
||||
|
||||
def run(self):
|
||||
minimal = self.options.get('minimal')
|
||||
module = self.arguments[0]
|
||||
template_args = {}
|
||||
template_args.update(get_authors())
|
||||
get_argparser = __import__(str(module), fromlist=[str('get_argparser')]).get_argparser
|
||||
parser = get_argparser(AutoManParser)
|
||||
if minimal:
|
||||
container = nodes.container()
|
||||
container += parser.automan_usage(self.options['prog'])
|
||||
container += parser.automan_description()
|
||||
return [container]
|
||||
synopsis_section = nodes.section(
|
||||
'',
|
||||
nodes.title(text='Synopsis'),
|
||||
|
@ -7,7 +7,8 @@ I can’t see any fancy symbols, what’s wrong?
|
||||
|
||||
* If you’re using iTerm2, please update to `this revision
|
||||
<https://github.com/gnachman/iTerm2/commit/8e3ad6dabf83c60b8cf4a3e3327c596401744af6>`_
|
||||
or newer.
|
||||
or newer. Also make sure that Preferences>Profiles>Text>Non-ASCII Font is the same as
|
||||
your main Font.
|
||||
* You need to set your ``LANG`` and ``LC_*`` environment variables to
|
||||
a UTF-8 locale (e.g. ``LANG=en_US.utf8``). Consult your Linux distro’s
|
||||
documentation for information about setting these variables correctly.
|
||||
|
@ -89,8 +89,8 @@ root <repository-root>`)::
|
||||
|
||||
.. note::
|
||||
The availability of the ``powerline-config`` command is required for
|
||||
powerline support. DLlocation of this script may be specified via
|
||||
``$POWERLINE_CONFIG_COMMAND`` environment variable.
|
||||
powerline support. The location of this script may be specified via
|
||||
the ``$POWERLINE_CONFIG_COMMAND`` environment variable.
|
||||
|
||||
.. note::
|
||||
It is advised to run ``powerline-daemon`` before adding the above line to
|
||||
@ -114,11 +114,12 @@ For IPython<0.11 add the following lines to :file:`.ipython/ipy_user_conf.py`:
|
||||
# create skeleton ipy_user_conf.py file):
|
||||
powerline_setup()
|
||||
|
||||
For IPython>=0.11 add the following line to :file:`ipython_config.py` file in
|
||||
the used profile:
|
||||
For IPython>=0.11 add the following line to
|
||||
:file:`~/.ipython/profile_default/ipython_config.py` file in the used profile:
|
||||
|
||||
.. code-block:: Python
|
||||
|
||||
c = get_config()
|
||||
c.InteractiveShellApp.extensions = [
|
||||
'powerline.bindings.ipython.post_0_11'
|
||||
]
|
||||
|
@ -50,26 +50,35 @@ Add the following to :file:`~/.config/qtile/config.py`:
|
||||
),
|
||||
]
|
||||
|
||||
.. _bar-usage:
|
||||
.. _lemonbar-usage:
|
||||
|
||||
bar-aint-recursive
|
||||
==================
|
||||
lemonbar (formerly bar-aint-recursive)
|
||||
======================================
|
||||
|
||||
To run the bar simply pipe the output of the binding script into ``bar`` and
|
||||
specify appropriate options, for example like this::
|
||||
To run the bar simply start the binding script:
|
||||
|
||||
python /path/to/powerline/bindings/bar/powerline-bar.py | bar
|
||||
python /path/to/powerline/bindings/lemonbar/powerline-lemonbar.py
|
||||
|
||||
to run with i3, simply ``exec`` this in i3 config file::
|
||||
You can specify options to be passed to ``lemonbar`` after ``--``, like so:
|
||||
|
||||
exec python /path/to/powerline/bindings/bar/powerline-bar.py --i3 | bar
|
||||
python /path/to/powerline/bindings/lemonbar/powerline-lemonbar.py --height 16 -- -f "Source Code Pro for Powerline-9"
|
||||
|
||||
to run with i3, simply ``exec`` this in the i3 config file and set the ``--i3`` switch:
|
||||
|
||||
exec python /path/to/powerline/bindings/lemonbar/powerline-lemonbar.py --i3
|
||||
|
||||
Running the binding in i3-mode will require `i3ipc <https://github.com/acrisci/i3ipc-python>`_
|
||||
(or the outdated `i3-py <https://github.com/ziberna/i3-py>`_).
|
||||
|
||||
See the `bar documentation <https://github.com/LemonBoy/bar>`_ for more
|
||||
See the `lemonbar documentation <https://github.com/LemonBoy/bar>`_ for more
|
||||
information and options.
|
||||
|
||||
All ``powerline-lemonbar.py`` arguments:
|
||||
|
||||
.. automan:: powerline.commands.lemonbar
|
||||
:prog: powerline-lemonbar.py
|
||||
:minimal: true
|
||||
|
||||
I3 bar
|
||||
======
|
||||
|
||||
|
@ -9,7 +9,7 @@ from threading import Lock, Event
|
||||
|
||||
from powerline.colorscheme import Colorscheme
|
||||
from powerline.lib.config import ConfigLoader
|
||||
from powerline.lib.unicode import safe_unicode, FailedUnicode
|
||||
from powerline.lib.unicode import unicode, safe_unicode, FailedUnicode
|
||||
from powerline.config import DEFAULT_SYSTEM_CONFIG_DIR
|
||||
from powerline.lib.dict import mergedicts
|
||||
from powerline.lib.encoding import get_preferred_output_encoding
|
||||
@ -121,7 +121,7 @@ def get_fallback_logger(stream=None):
|
||||
handler.setLevel(level)
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
logger = logging.getLogger('powerline')
|
||||
logger = logging.Logger('powerline')
|
||||
logger.setLevel(level)
|
||||
logger.addHandler(handler)
|
||||
_fallback_logger = PowerlineLogger(None, logger, '_fallback_')
|
||||
@ -200,40 +200,102 @@ def load_config(cfg_path, find_config_files, config_loader, loader_callback=None
|
||||
return ret
|
||||
|
||||
|
||||
def _get_log_handler(common_config, stream=None):
|
||||
'''Get log handler.
|
||||
def _set_log_handlers(common_config, logger, get_module_attr, stream=None):
|
||||
'''Set log handlers
|
||||
|
||||
:param dict common_config:
|
||||
Configuration dictionary used to create handler.
|
||||
|
||||
:return: logging.Handler subclass.
|
||||
:param logging.Logger logger:
|
||||
Logger to which handlers will be attached.
|
||||
:param func get_module_attr:
|
||||
:py:func:`gen_module_attr_getter` output.
|
||||
:param file stream:
|
||||
Stream to use by default for :py:class:`logging.StreamHandler` in place
|
||||
of :py:attr:`sys.stderr`. May be ``None``.
|
||||
'''
|
||||
log_file = common_config['log_file']
|
||||
if log_file:
|
||||
log_file = os.path.expanduser(log_file)
|
||||
log_dir = os.path.dirname(log_file)
|
||||
if not os.path.isdir(log_dir):
|
||||
log_targets = common_config['log_file']
|
||||
num_handlers = 0
|
||||
for log_target in log_targets:
|
||||
if log_target is None:
|
||||
log_target = ['logging.StreamHandler', []]
|
||||
elif isinstance(log_target, unicode):
|
||||
log_target = os.path.expanduser(log_target)
|
||||
log_dir = os.path.dirname(log_target)
|
||||
if log_dir and not os.path.isdir(log_dir):
|
||||
os.mkdir(log_dir)
|
||||
return logging.FileHandler(log_file)
|
||||
log_target = ['logging.FileHandler', [[log_target]]]
|
||||
module, handler_class_name = log_target[0].rpartition('.')[::2]
|
||||
module = module or 'logging.handlers'
|
||||
try:
|
||||
handler_class_args = log_target[1][0]
|
||||
except IndexError:
|
||||
if module == 'logging' and handler_class_name == 'StreamHandler':
|
||||
handler_class_args = [stream]
|
||||
else:
|
||||
return logging.StreamHandler(stream)
|
||||
|
||||
|
||||
def create_logger(common_config, stream=None):
|
||||
'''Create logger according to provided configuration
|
||||
'''
|
||||
log_format = common_config['log_format']
|
||||
formatter = logging.Formatter(log_format)
|
||||
|
||||
level = getattr(logging, common_config['log_level'])
|
||||
handler = _get_log_handler(common_config, stream)
|
||||
handler.setLevel(level)
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
logger = logging.getLogger('powerline')
|
||||
logger.setLevel(level)
|
||||
handler_class_args = ()
|
||||
try:
|
||||
handler_class_kwargs = log_target[1][1]
|
||||
except IndexError:
|
||||
handler_class_kwargs = {}
|
||||
module = str(module)
|
||||
handler_class_name = str(handler_class_name)
|
||||
handler_class = get_module_attr(module, handler_class_name)
|
||||
if not handler_class:
|
||||
continue
|
||||
handler = handler_class(*handler_class_args, **handler_class_kwargs)
|
||||
try:
|
||||
handler_level_name = log_target[2]
|
||||
except IndexError:
|
||||
handler_level_name = common_config['log_level']
|
||||
try:
|
||||
handler_format = log_target[3]
|
||||
except IndexError:
|
||||
handler_format = common_config['log_format']
|
||||
handler.setLevel(getattr(logging, handler_level_name))
|
||||
handler.setFormatter(logging.Formatter(handler_format))
|
||||
logger.addHandler(handler)
|
||||
return logger
|
||||
num_handlers += 1
|
||||
if num_handlers == 0 and log_targets:
|
||||
raise ValueError('Failed to set up any handlers')
|
||||
|
||||
|
||||
def create_logger(common_config, use_daemon_threads=True, ext='__unknown__',
|
||||
import_paths=None, imported_modules=None, stream=None):
|
||||
'''Create logger according to provided configuration
|
||||
|
||||
:param dict common_config:
|
||||
Common configuration, from :py:func:`finish_common_config`.
|
||||
:param bool use_daemon_threads:
|
||||
Whether daemon threads should be used. Argument to
|
||||
:py:class:`PowerlineLogger` constructor.
|
||||
:param str ext:
|
||||
Used extension. Argument to :py:class:`PowerlineLogger` constructor.
|
||||
:param set imported_modules:
|
||||
Set where imported modules are saved. Argument to
|
||||
:py:func:`gen_module_attr_getter`. May be ``None``, in this case new
|
||||
empty set is used.
|
||||
:param file stream:
|
||||
Stream to use by default for :py:class:`logging.StreamHandler` in place
|
||||
of :py:attr:`sys.stderr`. May be ``None``.
|
||||
|
||||
:return: Three objects:
|
||||
|
||||
#. :py:class:`logging.Logger` instance.
|
||||
#. :py:class:`PowerlineLogger` instance.
|
||||
#. Function, output of :py:func:`gen_module_attr_getter`.
|
||||
'''
|
||||
logger = logging.Logger('powerline')
|
||||
level = getattr(logging, common_config['log_level'])
|
||||
logger.setLevel(level)
|
||||
|
||||
pl = PowerlineLogger(use_daemon_threads, logger, ext)
|
||||
get_module_attr = gen_module_attr_getter(
|
||||
pl, common_config['paths'],
|
||||
set() if imported_modules is None else imported_modules)
|
||||
|
||||
_set_log_handlers(common_config, logger, get_module_attr, stream)
|
||||
|
||||
return logger, pl, get_module_attr
|
||||
|
||||
|
||||
def finish_common_config(encoding, common_config):
|
||||
@ -264,7 +326,10 @@ def finish_common_config(encoding, common_config):
|
||||
common_config.setdefault('additional_escapes', None)
|
||||
common_config.setdefault('reload_config', True)
|
||||
common_config.setdefault('interval', None)
|
||||
common_config.setdefault('log_file', None)
|
||||
common_config.setdefault('log_file', [None])
|
||||
|
||||
if not isinstance(common_config['log_file'], list):
|
||||
common_config['log_file'] = [common_config['log_file']]
|
||||
|
||||
common_config['paths'] = [
|
||||
os.path.expanduser(path) for path in common_config['paths']
|
||||
@ -324,6 +389,26 @@ def gen_module_attr_getter(pl, import_paths, imported_modules):
|
||||
return get_module_attr
|
||||
|
||||
|
||||
LOG_KEYS = set(('log_format', 'log_level', 'log_file', 'paths'))
|
||||
'''List of keys related to logging
|
||||
'''
|
||||
|
||||
|
||||
def _get_log_keys(common_config):
|
||||
'''Return a common configuration copy with only log-related config left
|
||||
|
||||
:param dict common_config:
|
||||
Common configuration.
|
||||
|
||||
:return:
|
||||
:py:class:`dict` instance which has only keys from
|
||||
:py:attr:`powerline.LOG_KEYS` left.
|
||||
'''
|
||||
return dict((
|
||||
(k, v) for k, v in common_config.items() if k in LOG_KEYS
|
||||
))
|
||||
|
||||
|
||||
class Powerline(object):
|
||||
'''Main powerline class, entrance point for all powerline uses. Sets
|
||||
powerline up and loads the configuration.
|
||||
@ -380,6 +465,7 @@ class Powerline(object):
|
||||
self.ext = ext
|
||||
self.run_once = run_once
|
||||
self.logger = logger
|
||||
self.had_logger = bool(self.logger)
|
||||
self.use_daemon_threads = use_daemon_threads
|
||||
|
||||
if not renderer_module:
|
||||
@ -430,8 +516,20 @@ class Powerline(object):
|
||||
|
||||
This function is used to create logger unless it was already specified
|
||||
at initialization.
|
||||
|
||||
:return: Three objects:
|
||||
|
||||
#. :py:class:`logging.Logger` instance.
|
||||
#. :py:class:`PowerlineLogger` instance.
|
||||
#. Function, output of :py:func:`gen_module_attr_getter`.
|
||||
'''
|
||||
return create_logger(self.common_config, self.default_log_stream)
|
||||
return create_logger(
|
||||
common_config=self.common_config,
|
||||
use_daemon_threads=self.use_daemon_threads,
|
||||
ext=self.ext,
|
||||
imported_modules=self.imported_modules,
|
||||
stream=self.default_log_stream,
|
||||
)
|
||||
|
||||
def create_renderer(self, load_main=False, load_colors=False, load_colorscheme=False, load_theme=False):
|
||||
'''(Re)create renderer object. Can be used after Powerline object was
|
||||
@ -465,22 +563,24 @@ class Powerline(object):
|
||||
or not self.prev_common_config
|
||||
or self.prev_common_config['default_top_theme'] != self.common_config['default_top_theme'])
|
||||
|
||||
log_keys_differ = (not self.prev_common_config or (
|
||||
_get_log_keys(self.prev_common_config) != _get_log_keys(self.common_config)
|
||||
))
|
||||
|
||||
self.prev_common_config = self.common_config
|
||||
|
||||
self.import_paths = self.common_config['paths']
|
||||
|
||||
if not self.logger:
|
||||
self.logger = self.create_logger()
|
||||
|
||||
if not self.pl:
|
||||
if log_keys_differ:
|
||||
if self.had_logger:
|
||||
self.pl = PowerlineLogger(self.use_daemon_threads, self.logger, self.ext)
|
||||
self.get_module_attr = gen_module_attr_getter(
|
||||
self.pl, self.common_config['paths'], self.imported_modules)
|
||||
else:
|
||||
self.logger, self.pl, self.get_module_attr = self.create_logger()
|
||||
self.config_loader.pl = self.pl
|
||||
|
||||
if not self.run_once:
|
||||
self.config_loader.set_watcher(self.common_config['watcher'])
|
||||
|
||||
self.get_module_attr = gen_module_attr_getter(self.pl, self.import_paths, self.imported_modules)
|
||||
|
||||
mergedicts(self.renderer_options, dict(
|
||||
pl=self.pl,
|
||||
term_truecolor=self.common_config['term_truecolor'],
|
||||
|
@ -2,31 +2,27 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from threading import Lock, Timer
|
||||
from argparse import ArgumentParser
|
||||
|
||||
from powerline import Powerline
|
||||
from powerline.lemonbar import LemonbarPowerline
|
||||
from powerline.lib.encoding import get_unicode_writer
|
||||
|
||||
|
||||
class BarPowerline(Powerline):
|
||||
get_encoding = staticmethod(lambda: 'utf-8')
|
||||
|
||||
def init(self):
|
||||
super(BarPowerline, self).init(ext='wm', renderer_module='bar')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = ArgumentParser(description='Powerline BAR bindings.')
|
||||
parser = ArgumentParser(description='Powerline lemonbar bindings.')
|
||||
parser.add_argument(
|
||||
'--i3', action='store_true',
|
||||
help='Subscribe for i3 events.'
|
||||
)
|
||||
args = parser.parse_args()
|
||||
powerline = BarPowerline()
|
||||
powerline = LemonbarPowerline()
|
||||
powerline.update_renderer()
|
||||
powerline.pl.warn("The 'bar' bindings are deprecated, please switch to 'lemonbar'")
|
||||
lock = Lock()
|
||||
modes = ['default']
|
||||
write = get_unicode_writer(encoding='utf-8')
|
||||
@ -60,4 +56,4 @@ if __name__ == '__main__':
|
||||
conn.main()
|
||||
|
||||
while True:
|
||||
time.sleep(1e10)
|
||||
time.sleep(1e8)
|
||||
|
@ -9,7 +9,7 @@ import shlex
|
||||
|
||||
from powerline.config import POWERLINE_ROOT, TMUX_CONFIG_DIRECTORY
|
||||
from powerline.lib.config import ConfigLoader
|
||||
from powerline import generate_config_finder, load_config, create_logger, PowerlineLogger, finish_common_config
|
||||
from powerline import generate_config_finder, load_config, create_logger, finish_common_config
|
||||
from powerline.shell import ShellPowerline
|
||||
from powerline.lib.shell import which
|
||||
from powerline.bindings.tmux import (TmuxVersionInfo, run_tmux_command, set_tmux_environment, get_tmux_version,
|
||||
@ -221,8 +221,8 @@ def get_main_config(args):
|
||||
def create_powerline_logger(args):
|
||||
config = get_main_config(args)
|
||||
common_config = finish_common_config(get_preferred_output_encoding(), config['common'])
|
||||
logger = create_logger(common_config)
|
||||
return PowerlineLogger(use_daemon_threads=True, logger=logger, ext='config')
|
||||
logger, pl, get_module_attr = create_logger(common_config)
|
||||
return pl
|
||||
|
||||
|
||||
def check_command(cmd):
|
||||
|
61
powerline/bindings/lemonbar/powerline-lemonbar.py
Executable file
61
powerline/bindings/lemonbar/powerline-lemonbar.py
Executable file
@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
import time
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
from threading import Lock, Timer
|
||||
|
||||
from powerline.lemonbar import LemonbarPowerline
|
||||
from powerline.commands.lemonbar import get_argparser
|
||||
from powerline.bindings.wm import get_connected_xrandr_outputs
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = get_argparser()
|
||||
args = parser.parse_args()
|
||||
|
||||
powerline = LemonbarPowerline()
|
||||
powerline.update_renderer()
|
||||
bars = []
|
||||
|
||||
for screen in get_connected_xrandr_outputs(powerline.pl):
|
||||
command = [args.bar_command, '-g', '{0}x{1}+{2}'.format(screen['width'], args.height, screen['x'])] + args.args[1:]
|
||||
process = subprocess.Popen(command, stdin=subprocess.PIPE)
|
||||
bars.append((screen['name'], process, int(screen['width']) / 5))
|
||||
|
||||
lock = Lock()
|
||||
modes = ['default']
|
||||
|
||||
def render(reschedule=False):
|
||||
if reschedule:
|
||||
Timer(args.interval, render, kwargs={'reschedule': True}).start()
|
||||
|
||||
global lock
|
||||
with lock:
|
||||
for output, process, width in bars:
|
||||
process.stdin.write(powerline.render(mode=modes[0], width=width, matcher_info=output).encode('utf-8') + b'\n')
|
||||
process.stdin.flush()
|
||||
|
||||
def update(evt):
|
||||
modes[0] = evt.change
|
||||
render()
|
||||
|
||||
render(reschedule=True)
|
||||
|
||||
if args.i3:
|
||||
try:
|
||||
import i3ipc
|
||||
except ImportError:
|
||||
import i3
|
||||
i3.Subscription(lambda evt, data, sub: render(), 'workspace')
|
||||
else:
|
||||
conn = i3ipc.Connection()
|
||||
conn.on('workspace::focus', lambda conn, evt: render())
|
||||
conn.on('mode', lambda conn, evt: update(evt))
|
||||
conn.main()
|
||||
|
||||
while True:
|
||||
time.sleep(1e8)
|
@ -1,5 +1,4 @@
|
||||
set -g status on
|
||||
set -g status-utf8 on
|
||||
set -g status-interval 2
|
||||
set -g status-left-length 20
|
||||
set -g status-right '#(env "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS tmux right -R pane_id=\"`tmux display -p "#D"`\")'
|
||||
|
@ -273,7 +273,7 @@ def _vim_to_python(value):
|
||||
|
||||
if hasattr(vim, 'options'):
|
||||
def vim_getbufoption(info, option):
|
||||
return info['buffer'].options[str(option)]
|
||||
return _vim_to_python(info['buffer'].options[str(option)])
|
||||
|
||||
def vim_getoption(option):
|
||||
return vim.options[str(option)]
|
||||
|
38
powerline/bindings/wm/__init__.py
Normal file
38
powerline/bindings/wm/__init__.py
Normal file
@ -0,0 +1,38 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
import re
|
||||
|
||||
from powerline.theme import requires_segment_info
|
||||
from powerline.lib.shell import run_cmd
|
||||
|
||||
|
||||
conn = None
|
||||
|
||||
|
||||
def get_i3_connection():
|
||||
'''Return a valid, cached i3 Connection instance
|
||||
'''
|
||||
global conn
|
||||
if not conn:
|
||||
try:
|
||||
import i3ipc
|
||||
except ImportError:
|
||||
import i3 as conn
|
||||
else:
|
||||
conn = i3ipc.Connection()
|
||||
return conn
|
||||
|
||||
|
||||
XRANDR_OUTPUT_RE = re.compile(r'^(?P<name>[0-9A-Za-z-]+) connected(?P<primary> primary)? (?P<width>\d+)x(?P<height>\d+)\+(?P<x>\d+)\+(?P<y>\d+)', re.MULTILINE)
|
||||
|
||||
|
||||
def get_connected_xrandr_outputs(pl):
|
||||
'''Iterate over xrandr outputs
|
||||
|
||||
Outputs are represented by a dictionary with ``name``, ``width``,
|
||||
``height``, ``primary``, ``x`` and ``y`` keys.
|
||||
'''
|
||||
return (match.groupdict() for match in XRANDR_OUTPUT_RE.finditer(
|
||||
run_cmd(pl, ['xrandr', '-q'])
|
||||
))
|
35
powerline/commands/lemonbar.py
Normal file
35
powerline/commands/lemonbar.py
Normal file
@ -0,0 +1,35 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
# WARNING: using unicode_literals causes errors in argparse
|
||||
from __future__ import (division, absolute_import, print_function)
|
||||
|
||||
import argparse
|
||||
|
||||
|
||||
def get_argparser(ArgumentParser=argparse.ArgumentParser):
|
||||
parser = ArgumentParser(
|
||||
description='Powerline BAR bindings.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--i3', action='store_true',
|
||||
help='Subscribe for i3 events.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--height', default='',
|
||||
metavar='PIXELS', help='Bar height.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--interval', '-i',
|
||||
type=float, default=0.5,
|
||||
metavar='SECONDS', help='Refresh interval.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--bar-command', '-C',
|
||||
default='lemonbar',
|
||||
metavar='CMD', help='Name of the lemonbar executable to use.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'args', nargs=argparse.REMAINDER,
|
||||
help='Extra arguments for lemonbar. Should be preceded with ``--`` '
|
||||
'argument in order not to be confused with script own arguments.'
|
||||
)
|
||||
return parser
|
@ -23,16 +23,25 @@
|
||||
"csv:column_number": "line_current",
|
||||
"csv:column_name": "line_current_symbol",
|
||||
|
||||
"tab:background": "background",
|
||||
"tab:divider": "background:divider",
|
||||
|
||||
"tab_nc:modified_indicator": "modified_indicator",
|
||||
"tab_nc:file_directory": "information:unimportant",
|
||||
"tab_nc:file_name": "tab_nc:file_directory",
|
||||
"tab_nc:tabnr": "tab_nc:file_directory",
|
||||
|
||||
"buf_nc:file_directory": "tab_nc:file_directory",
|
||||
"buf_nc:file_name": "tab_nc:file_name",
|
||||
"buf_nc:bufnr": "tab_nc:tabnr",
|
||||
"buf_nc:file_name": "buf_nc:file_directory",
|
||||
"buf_nc:bufnr": "buf_nc:file_directory",
|
||||
"buf_nc:modified_indicator": "tab_nc:modified_indicator",
|
||||
|
||||
"buf_nc_mod:file_directory": "tab_nc:file_directory",
|
||||
"buf_nc_mod:file_name": "buf_nc_mod:file_directory",
|
||||
"buf_nc_mod:bufnr": "buf_nc_mod:file_directory",
|
||||
"buf_nc_mod:modified_indicator": "tab_nc:modified_indicator",
|
||||
|
||||
|
||||
"commandt:label": "file_name",
|
||||
"commandt:background": "background",
|
||||
"commandt:finder": "file_name",
|
||||
|
@ -131,6 +131,15 @@
|
||||
"args": {
|
||||
"text": "+"
|
||||
}
|
||||
},
|
||||
|
||||
"powerline.segments.i3wm.scratchpad": {
|
||||
"args": {
|
||||
"icons": {
|
||||
"fresh": "O",
|
||||
"changed": "X"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,6 +129,15 @@
|
||||
"args": {
|
||||
"text": "+"
|
||||
}
|
||||
},
|
||||
|
||||
"powerline.segments.i3wm.scratchpad": {
|
||||
"args": {
|
||||
"icons": {
|
||||
"fresh": "●",
|
||||
"changed": "○"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,6 +143,15 @@
|
||||
"args": {
|
||||
"text": "🖫⃥"
|
||||
}
|
||||
},
|
||||
|
||||
"powerline.segments.i3wm.scratchpad": {
|
||||
"args": {
|
||||
"icons": {
|
||||
"fresh": "●",
|
||||
"changed": "○"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,6 +129,15 @@
|
||||
"args": {
|
||||
"text": "+"
|
||||
}
|
||||
},
|
||||
|
||||
"powerline.segments.i3wm.scratchpad": {
|
||||
"args": {
|
||||
"icons": {
|
||||
"fresh": "●",
|
||||
"changed": "○"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,6 +129,15 @@
|
||||
"args": {
|
||||
"text": "+"
|
||||
}
|
||||
},
|
||||
|
||||
"powerline.segments.i3wm.scratchpad": {
|
||||
"args": {
|
||||
"icons": {
|
||||
"fresh": "●",
|
||||
"changed": "○"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -130,6 +130,15 @@
|
||||
"args": {
|
||||
"text": "+"
|
||||
}
|
||||
},
|
||||
|
||||
"powerline.segments.i3wm.scratchpad": {
|
||||
"args": {
|
||||
"icons": {
|
||||
"fresh": "●",
|
||||
"changed": "○"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +67,7 @@
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"highlight_groups": ["background"],
|
||||
"highlight_groups": ["tab:background"],
|
||||
"draw_soft_divider": false,
|
||||
"draw_hard_divider": false,
|
||||
"width": "auto"
|
||||
|
21
powerline/lemonbar.py
Normal file
21
powerline/lemonbar.py
Normal file
@ -0,0 +1,21 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
from powerline import Powerline
|
||||
from powerline.lib.dict import mergedicts
|
||||
|
||||
|
||||
class LemonbarPowerline(Powerline):
|
||||
def init(self):
|
||||
super(LemonbarPowerline, self).init(ext='wm', renderer_module='lemonbar')
|
||||
|
||||
get_encoding = staticmethod(lambda: 'utf-8')
|
||||
|
||||
def get_local_themes(self, local_themes):
|
||||
if not local_themes:
|
||||
return {}
|
||||
|
||||
return dict((
|
||||
(key, {'config': self.load_theme_config(val)})
|
||||
for key, val in local_themes.items()
|
||||
))
|
@ -78,3 +78,11 @@ def mergedicts_copy(d1, d2):
|
||||
else:
|
||||
ret[k] = d2[k]
|
||||
return ret
|
||||
|
||||
|
||||
def updated(d, *args, **kwargs):
|
||||
'''Copy dictionary and update it with provided arguments
|
||||
'''
|
||||
d = d.copy()
|
||||
d.update(*args, **kwargs)
|
||||
return d
|
||||
|
@ -43,12 +43,18 @@ def get_preferred_output_encoding():
|
||||
Falls back to ASCII, so that output is most likely to be displayed
|
||||
correctly.
|
||||
'''
|
||||
if hasattr(locale, 'LC_MESSAGES'):
|
||||
return (
|
||||
locale.getlocale(locale.LC_MESSAGES)[1]
|
||||
or locale.getdefaultlocale()[1]
|
||||
or 'ascii'
|
||||
)
|
||||
|
||||
return (
|
||||
locale.getdefaultlocale()[1]
|
||||
or 'ascii'
|
||||
)
|
||||
|
||||
|
||||
def get_preferred_input_encoding():
|
||||
'''Get encoding that should be used for reading shell command output
|
||||
@ -57,12 +63,18 @@ def get_preferred_input_encoding():
|
||||
Falls back to latin1 so that function is less likely to throw as decoded
|
||||
output is primary searched for ASCII values.
|
||||
'''
|
||||
if hasattr(locale, 'LC_MESSAGES'):
|
||||
return (
|
||||
locale.getlocale(locale.LC_MESSAGES)[1]
|
||||
or locale.getdefaultlocale()[1]
|
||||
or 'latin1'
|
||||
)
|
||||
|
||||
return (
|
||||
locale.getdefaultlocale()[1]
|
||||
or 'latin1'
|
||||
)
|
||||
|
||||
|
||||
def get_preferred_arguments_encoding():
|
||||
'''Get encoding that should be used for command-line arguments
|
||||
|
@ -7,7 +7,7 @@ import os
|
||||
from subprocess import Popen, PIPE
|
||||
from functools import partial
|
||||
|
||||
from powerline.lib.encoding import get_preferred_input_encoding
|
||||
from powerline.lib.encoding import get_preferred_input_encoding, get_preferred_output_encoding
|
||||
|
||||
|
||||
if sys.platform.startswith('win32'):
|
||||
@ -36,7 +36,8 @@ def run_cmd(pl, cmd, stdin=None, strip=True):
|
||||
pl.exception('Could not execute command ({0}): {1}', e, cmd)
|
||||
return None
|
||||
else:
|
||||
stdout, err = p.communicate(stdin)
|
||||
stdout, err = p.communicate(
|
||||
stdin if stdin is None else stdin.encode(get_preferred_output_encoding()))
|
||||
stdout = stdout.decode(get_preferred_input_encoding())
|
||||
return stdout.strip() if strip else stdout
|
||||
|
||||
|
@ -22,7 +22,7 @@ from powerline.lint.checks import (check_matcher_func, check_ext, check_config,
|
||||
check_segment_function, check_args, get_one_segment_function,
|
||||
check_highlight_groups, check_highlight_group, check_full_segment_data,
|
||||
get_all_possible_functions, check_segment_data_key, register_common_name,
|
||||
highlight_group_spec)
|
||||
highlight_group_spec, check_log_file_level, check_logging_handler)
|
||||
from powerline.lint.spec import Spec
|
||||
from powerline.lint.context import Context
|
||||
|
||||
@ -56,6 +56,11 @@ ext_spec = Spec(
|
||||
top_theme=top_theme_spec().optional(),
|
||||
).copy
|
||||
gen_components_spec = (lambda *components: Spec().list(Spec().type(unicode).oneof(set(components))))
|
||||
log_level_spec = Spec().re('^[A-Z]+$').func(
|
||||
(lambda value, *args: (True, True, not hasattr(logging, value))),
|
||||
(lambda value: 'unknown debugging level {0}'.format(value))
|
||||
).copy
|
||||
log_format_spec = Spec().type(unicode).copy
|
||||
main_spec = (Spec(
|
||||
common=Spec(
|
||||
default_top_theme=top_theme_spec().optional(),
|
||||
@ -67,7 +72,8 @@ main_spec = (Spec(
|
||||
(lambda value, *args: (True, True, not os.path.exists(os.path.expanduser(value.value)))),
|
||||
(lambda value: 'path does not exist: {0}'.format(value))
|
||||
).optional(),
|
||||
log_file=Spec().type(unicode).func(
|
||||
log_file=Spec().either(
|
||||
Spec().type(unicode).func(
|
||||
(
|
||||
lambda value, *args: (
|
||||
True,
|
||||
@ -76,12 +82,22 @@ main_spec = (Spec(
|
||||
)
|
||||
),
|
||||
(lambda value: 'directory does not exist: {0}'.format(os.path.dirname(value)))
|
||||
),
|
||||
Spec().list(Spec().either(
|
||||
Spec().type(unicode, type(None)),
|
||||
Spec().tuple(
|
||||
Spec().re(function_name_re).func(check_logging_handler),
|
||||
Spec().tuple(
|
||||
Spec().type(list).optional(),
|
||||
Spec().type(dict).optional(),
|
||||
),
|
||||
log_level_spec().func(check_log_file_level).optional(),
|
||||
log_format_spec().optional(),
|
||||
),
|
||||
))
|
||||
).optional(),
|
||||
log_level=Spec().re('^[A-Z]+$').func(
|
||||
(lambda value, *args: (True, True, not hasattr(logging, value))),
|
||||
(lambda value: 'unknown debugging level {0}'.format(value))
|
||||
).optional(),
|
||||
log_format=Spec().type(unicode).optional(),
|
||||
log_level=log_level_spec().optional(),
|
||||
log_format=log_format_spec().optional(),
|
||||
interval=Spec().either(Spec().cmp('gt', 0.0), Spec().type(type(None))).optional(),
|
||||
reload_config=Spec().type(bool).optional(),
|
||||
watcher=Spec().type(unicode).oneof(set(('auto', 'inotify', 'stat'))).optional(),
|
||||
@ -110,6 +126,12 @@ main_spec = (Spec(
|
||||
select=ext_theme_spec(),
|
||||
),
|
||||
).optional(),
|
||||
wm=ext_spec().update(
|
||||
local_themes=Spec().unknown_spec(
|
||||
Spec().re('^[0-9A-Za-z-]+$'),
|
||||
ext_theme_spec()
|
||||
).optional()
|
||||
).optional(),
|
||||
).unknown_spec(
|
||||
check_ext,
|
||||
ext_spec(),
|
||||
|
@ -800,3 +800,67 @@ def check_exinclude_function(name, data, context, echoerr):
|
||||
if not func:
|
||||
return True, False, True
|
||||
return True, False, False
|
||||
|
||||
|
||||
def check_log_file_level(this_level, data, context, echoerr):
|
||||
'''Check handler level specified in :ref:`log_file key <config-common-log>`
|
||||
|
||||
This level must be greater or equal to the level in :ref:`log_level key
|
||||
<config-common-log_level>`.
|
||||
'''
|
||||
havemarks(this_level)
|
||||
hadproblem = False
|
||||
top_level = context[0][1].get('common', {}).get('log_level', 'WARNING')
|
||||
top_level_str = top_level
|
||||
top_level_mark = getattr(top_level, 'mark', None)
|
||||
if (
|
||||
not isinstance(top_level, unicode) or not hasattr(logging, top_level)
|
||||
or not isinstance(this_level, unicode) or not hasattr(logging, this_level)
|
||||
):
|
||||
return True, False, hadproblem
|
||||
top_level = getattr(logging, top_level)
|
||||
this_level_str = this_level
|
||||
this_level_mark = this_level.mark
|
||||
this_level = getattr(logging, this_level)
|
||||
if this_level < top_level:
|
||||
echoerr(
|
||||
context='Error while checking log level index (key {key})'.format(
|
||||
key=context.key),
|
||||
context_mark=this_level_mark,
|
||||
problem='found level that is less critical then top level ({0} < {0})'.format(
|
||||
this_level_str, top_level_str),
|
||||
problem_mark=top_level_mark,
|
||||
)
|
||||
hadproblem = True
|
||||
return True, False, hadproblem
|
||||
|
||||
|
||||
def check_logging_handler(handler_name, data, context, echoerr):
|
||||
havemarks(handler_name)
|
||||
import_paths = [os.path.expanduser(path) for path in context[0][1].get('common', {}).get('paths', [])]
|
||||
|
||||
handler_module, separator, handler_class = handler_name.rpartition('.')
|
||||
if not separator:
|
||||
handler_module = 'logging.handlers'
|
||||
handler_class = handler_name
|
||||
with WithPath(import_paths):
|
||||
try:
|
||||
handler = getattr(__import__(str(handler_module), fromlist=[str(handler_class)]), str(handler_class))
|
||||
except ImportError:
|
||||
echoerr(context='Error while loading logger class (key {key})'.format(key=context.key),
|
||||
problem='failed to load module {0}'.format(handler_module),
|
||||
problem_mark=handler_name.mark)
|
||||
return True, False, True
|
||||
except AttributeError:
|
||||
echoerr(context='Error while loading logger class (key {key})'.format(key=context.key),
|
||||
problem='failed to load handler class {0}'.format(handler_class),
|
||||
problem_mark=handler_name.mark)
|
||||
return True, False, True
|
||||
|
||||
if not issubclass(handler, logging.Handler):
|
||||
echoerr(context='Error while loading logger class (key {key})'.format(key=context.key),
|
||||
problem='loaded class {0} is not a logging.Handler subclass'.format(handler_class),
|
||||
problem_mark=handler_name.mark)
|
||||
return True, False, True
|
||||
|
||||
return True, False, False
|
||||
|
@ -21,6 +21,12 @@ class WithPath(object):
|
||||
def import_function(function_type, name, data, context, echoerr, module):
|
||||
havemarks(name, module)
|
||||
|
||||
if module == 'powerline.segments.i3wm' and name == 'workspaces':
|
||||
echoerr(context='Warning while checking segments (key {key})'.format(key=context.key),
|
||||
context_mark=name.mark,
|
||||
problem='segment {0} from {1} is deprecated'.format(name, module),
|
||||
problem_mark=module.mark)
|
||||
|
||||
with WithPath(data['import_paths']):
|
||||
try:
|
||||
func = getattr(__import__(str(module), fromlist=[str(name)]), str(name))
|
||||
|
@ -531,6 +531,7 @@ class Spec(object):
|
||||
if max_len == min_len:
|
||||
self.len('eq', len(specs))
|
||||
else:
|
||||
if min_len > 0:
|
||||
self.len('ge', min_len)
|
||||
self.len('le', max_len)
|
||||
|
||||
|
68
powerline/listers/i3wm.py
Normal file
68
powerline/listers/i3wm.py
Normal file
@ -0,0 +1,68 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
from powerline.theme import requires_segment_info
|
||||
from powerline.lib.dict import updated
|
||||
from powerline.bindings.wm import get_i3_connection, get_connected_xrandr_outputs
|
||||
|
||||
|
||||
@requires_segment_info
|
||||
def output_lister(pl, segment_info):
|
||||
'''List all outputs in segment_info format
|
||||
'''
|
||||
|
||||
return (
|
||||
(
|
||||
updated(segment_info, output=output['name']),
|
||||
{
|
||||
'draw_inner_divider': None
|
||||
}
|
||||
)
|
||||
for output in get_connected_xrandr_outputs(pl)
|
||||
)
|
||||
|
||||
|
||||
@requires_segment_info
|
||||
def workspace_lister(pl, segment_info, only_show=None, output=None):
|
||||
'''List all workspaces in segment_info format
|
||||
|
||||
Sets the segment info values of ``workspace`` and ``output`` to the name of
|
||||
the i3 workspace and the ``xrandr`` output respectively and the keys
|
||||
``"visible"``, ``"urgent"`` and ``"focused"`` to a boolean indicating these
|
||||
states.
|
||||
|
||||
:param list only_show:
|
||||
Specifies which workspaces to list. Valid entries are ``"visible"``,
|
||||
``"urgent"`` and ``"focused"``. If omitted or ``null`` all workspaces
|
||||
are listed.
|
||||
|
||||
:param str output:
|
||||
May be set to the name of an X output. If specified, only workspaces
|
||||
on that output are listed. Overrides automatic output detection by
|
||||
the lemonbar renderer and bindings. Set to ``false`` to force
|
||||
all workspaces to be shown.
|
||||
'''
|
||||
|
||||
if output == None:
|
||||
output = output or segment_info.get('output')
|
||||
|
||||
return (
|
||||
(
|
||||
updated(
|
||||
segment_info,
|
||||
output=w['output'],
|
||||
workspace={
|
||||
'name': w['name'],
|
||||
'visible': w['visible'],
|
||||
'urgent': w['urgent'],
|
||||
'focused': w['focused'],
|
||||
},
|
||||
),
|
||||
{
|
||||
'draw_inner_divider': None
|
||||
}
|
||||
)
|
||||
for w in get_i3_connection().get_workspaces()
|
||||
if (((not only_show or any(w[typ] for typ in only_show))
|
||||
and (not output or w['output'] == output)))
|
||||
)
|
@ -2,12 +2,12 @@
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
from powerline.theme import requires_segment_info
|
||||
from powerline.bindings.vim import (current_tabpage, list_tabpages, vim_getbufoption)
|
||||
from powerline.bindings.vim import (current_tabpage, list_tabpages)
|
||||
|
||||
try:
|
||||
import vim
|
||||
except ImportError:
|
||||
vim = {}
|
||||
vim = object()
|
||||
|
||||
|
||||
def tabpage_updated_segment_info(segment_info, tabpage):
|
||||
@ -49,7 +49,10 @@ def tablister(pl, segment_info, **kwargs):
|
||||
return (
|
||||
(lambda tabpage, prefix: (
|
||||
tabpage_updated_segment_info(segment_info, tabpage),
|
||||
add_multiplier(tabpage, {'highlight_group_prefix': prefix})
|
||||
add_multiplier(tabpage, {
|
||||
'highlight_group_prefix': prefix,
|
||||
'divider_highlight_group': 'tab:divider'
|
||||
})
|
||||
))(tabpage, 'tab' if tabpage == cur_tabpage else 'tab_nc')
|
||||
for tabpage in list_tabpages()
|
||||
)
|
||||
@ -75,7 +78,8 @@ def bufferlister(pl, segment_info, show_unlisted=False, **kwargs):
|
||||
and ``bufnr`` keys set to buffer-specific ones, ``window``, ``winnr`` and
|
||||
``window_id`` keys set to None.
|
||||
|
||||
Adds either ``buf:`` or ``buf_nc:`` prefix to all segment highlight groups.
|
||||
Adds one of ``buf:``, ``buf_nc:``, ``buf_mod:``, or ``buf_nc_mod``
|
||||
prefix to all segment highlight groups.
|
||||
|
||||
:param bool show_unlisted:
|
||||
True if unlisted buffers should be shown as well. Current buffer is
|
||||
@ -89,22 +93,31 @@ def bufferlister(pl, segment_info, show_unlisted=False, **kwargs):
|
||||
return dct
|
||||
|
||||
return (
|
||||
(
|
||||
buf_segment_info,
|
||||
add_multiplier(buf_segment_info['buffer'], {'highlight_group_prefix': prefix})
|
||||
(lambda buffer, current, modified: (
|
||||
buffer_updated_segment_info(segment_info, buffer),
|
||||
add_multiplier(buffer, {
|
||||
'highlight_group_prefix': '{0}{1}'.format(current, modified),
|
||||
'divider_highlight_group': 'tab:divider'
|
||||
})
|
||||
))(
|
||||
buffer,
|
||||
'buf' if buffer is cur_buffer else 'buf_nc',
|
||||
'_mod' if int(vim.eval('getbufvar({0}, \'&modified\')'.format(buffer.number))) > 0 else ''
|
||||
)
|
||||
for buf_segment_info, prefix in (
|
||||
(
|
||||
buffer_updated_segment_info(
|
||||
segment_info,
|
||||
buffer
|
||||
),
|
||||
('buf' if buffer is cur_buffer else 'buf_nc')
|
||||
)
|
||||
for buffer in vim.buffers
|
||||
) if (
|
||||
buf_segment_info['buffer'] is cur_buffer
|
||||
for buffer in vim.buffers if (
|
||||
buffer is cur_buffer
|
||||
or show_unlisted
|
||||
or int(vim_getbufoption(buf_segment_info, 'buflisted'))
|
||||
# We can't use vim_getbufoption(segment_info, 'buflisted')
|
||||
# here for performance reasons. Querying the buffer options
|
||||
# through the vim python module's option attribute caused
|
||||
# vim to think it needed to update the tabline for every
|
||||
# keystroke after any event that changed the buffer's
|
||||
# options.
|
||||
#
|
||||
# Using the vim module's eval method to directly use the
|
||||
# buflisted(nr) vim method instead does not cause vim to
|
||||
# update the tabline after every keystroke, but rather after
|
||||
# events that would change that status. Fixes #1281
|
||||
or int(vim.eval('buflisted(%s)' % buffer.number)) > 0
|
||||
)
|
||||
)
|
||||
|
@ -7,7 +7,7 @@ from powerline.bindings.vim import vim_getbufoption, buffer_name
|
||||
|
||||
|
||||
def help(matcher_info):
|
||||
return str(vim_getbufoption(matcher_info, 'buftype')) == 'help'
|
||||
return vim_getbufoption(matcher_info, 'buftype') == 'help'
|
||||
|
||||
|
||||
def cmdwin(matcher_info):
|
||||
@ -16,4 +16,4 @@ def cmdwin(matcher_info):
|
||||
|
||||
|
||||
def quickfix(matcher_info):
|
||||
return str(vim_getbufoption(matcher_info, 'buftype')) == 'quickfix'
|
||||
return vim_getbufoption(matcher_info, 'buftype') == 'quickfix'
|
||||
|
@ -3,9 +3,12 @@ from __future__ import (unicode_literals, division, absolute_import, print_funct
|
||||
|
||||
import os
|
||||
|
||||
from powerline.bindings.vim import buffer_name
|
||||
from powerline.bindings.vim import vim_getbufoption, buffer_name
|
||||
|
||||
|
||||
def commandt(matcher_info):
|
||||
name = buffer_name(matcher_info)
|
||||
return name and os.path.basename(name) == b'GoToFile'
|
||||
return (
|
||||
vim_getbufoption(matcher_info, 'filetype') == 'command-t'
|
||||
or (name and os.path.basename(name) == b'GoToFile')
|
||||
)
|
||||
|
@ -1,45 +0,0 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
from powerline.renderer import Renderer
|
||||
from powerline.colorscheme import ATTR_UNDERLINE
|
||||
|
||||
|
||||
class BarRenderer(Renderer):
|
||||
'''bar (bar ain't recursive) renderer
|
||||
|
||||
|
||||
See documentation of `bar <https://github.com/LemonBoy/bar>`_ and :ref:`the usage instructions <bar-usage>`
|
||||
'''
|
||||
|
||||
character_translations = Renderer.character_translations.copy()
|
||||
character_translations[ord('%')] = '%%'
|
||||
|
||||
@staticmethod
|
||||
def hlstyle(*args, **kwargs):
|
||||
# We don’t need to explicitly reset attributes, so skip those calls
|
||||
return ''
|
||||
|
||||
def hl(self, contents, fg=None, bg=None, attrs=None):
|
||||
text = ''
|
||||
|
||||
if fg is not None:
|
||||
if fg is not False and fg[1] is not False:
|
||||
text += '%{{F#ff{0:06x}}}'.format(fg[1])
|
||||
if bg is not None:
|
||||
if bg is not False and bg[1] is not False:
|
||||
text += '%{{B#ff{0:06x}}}'.format(bg[1])
|
||||
|
||||
if attrs & ATTR_UNDERLINE:
|
||||
text += '%{+u}'
|
||||
|
||||
return text + contents + '%{F-B--u}'
|
||||
|
||||
def render(self, *args, **kwargs):
|
||||
return '%{{l}}{0}%{{r}}{1}'.format(
|
||||
super(BarRenderer, self).render(side='left', *args, **kwargs),
|
||||
super(BarRenderer, self).render(side='right', *args, **kwargs),
|
||||
)
|
||||
|
||||
|
||||
renderer = BarRenderer
|
61
powerline/renderers/lemonbar.py
Normal file
61
powerline/renderers/lemonbar.py
Normal file
@ -0,0 +1,61 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
from powerline.renderer import Renderer
|
||||
from powerline.theme import Theme
|
||||
from powerline.colorscheme import ATTR_UNDERLINE
|
||||
|
||||
|
||||
class LemonbarRenderer(Renderer):
|
||||
'''lemonbar (formerly bar/bar ain't recursive) renderer
|
||||
|
||||
|
||||
See documentation of `lemonbar <https://github.com/LemonBoy/bar>`_ and :ref:`the usage instructions <lemonbar-usage>`
|
||||
'''
|
||||
|
||||
character_translations = Renderer.character_translations.copy()
|
||||
character_translations[ord('%')] = '%%{}'
|
||||
|
||||
@staticmethod
|
||||
def hlstyle(*args, **kwargs):
|
||||
# We don’t need to explicitly reset attributes, so skip those calls
|
||||
return ''
|
||||
|
||||
def hl(self, contents, fg=None, bg=None, attrs=None):
|
||||
text = ''
|
||||
|
||||
if fg is not None:
|
||||
if fg is not False and fg[1] is not False:
|
||||
text += '%{{F#ff{0:06x}}}'.format(fg[1])
|
||||
if bg is not None:
|
||||
if bg is not False and bg[1] is not False:
|
||||
text += '%{{B#ff{0:06x}}}'.format(bg[1])
|
||||
|
||||
if attrs & ATTR_UNDERLINE:
|
||||
text += '%{+u}'
|
||||
|
||||
return text + contents + '%{F-B--u}'
|
||||
|
||||
def render(self, *args, **kwargs):
|
||||
return '%{{l}}{0}%{{r}}{1}'.format(
|
||||
super(LemonbarRenderer, self).render(side='left', segment_info={'output': kwargs.get('matcher_info')}, *args, **kwargs),
|
||||
super(LemonbarRenderer, self).render(side='right', segment_info={'output': kwargs.get('matcher_info')}, *args, **kwargs),
|
||||
)
|
||||
|
||||
def get_theme(self, matcher_info):
|
||||
if not matcher_info or matcher_info not in self.local_themes:
|
||||
return self.theme
|
||||
match = self.local_themes[matcher_info]
|
||||
|
||||
try:
|
||||
return match['theme']
|
||||
except KeyError:
|
||||
match['theme'] = Theme(
|
||||
theme_config=match['config'],
|
||||
main_theme_config=self.theme_config,
|
||||
**self.theme_kwargs
|
||||
)
|
||||
return match['theme']
|
||||
|
||||
|
||||
renderer = LemonbarRenderer
|
@ -30,6 +30,7 @@ def _fetch_battery_info(pl):
|
||||
else:
|
||||
devinterface = 'org.freedesktop.DBus.Properties'
|
||||
devtype_name = interface + '.Device'
|
||||
devices = []
|
||||
for devpath in up.EnumerateDevices(dbus_interface=interface):
|
||||
dev = bus.get_object(interface, devpath)
|
||||
devget = lambda what: dev.Get(
|
||||
@ -46,36 +47,62 @@ def _fetch_battery_info(pl):
|
||||
if not bool(devget('PowerSupply')):
|
||||
pl.debug('Not using DBUS+UPower with {0}: not a power supply', devpath)
|
||||
continue
|
||||
devices.append(devpath)
|
||||
pl.debug('Using DBUS+UPower with {0}', devpath)
|
||||
return lambda pl: (
|
||||
float(
|
||||
if devices:
|
||||
def _flatten_battery(pl):
|
||||
energy = 0.0
|
||||
energy_full = 0.0
|
||||
state = True
|
||||
for devpath in devices:
|
||||
dev = bus.get_object(interface, devpath)
|
||||
energy_full += float(
|
||||
dbus.Interface(dev, dbus_interface=devinterface).Get(
|
||||
devtype_name,
|
||||
'Percentage'
|
||||
),
|
||||
'EnergyFull'
|
||||
),
|
||||
)
|
||||
energy += float(
|
||||
dbus.Interface(dev, dbus_interface=devinterface).Get(
|
||||
devtype_name,
|
||||
'Energy'
|
||||
),
|
||||
)
|
||||
state &= dbus.Interface(dev, dbus_interface=devinterface).Get(
|
||||
devtype_name,
|
||||
'State'
|
||||
) == 1
|
||||
)
|
||||
) != 2
|
||||
return (energy * 100.0 / energy_full), state
|
||||
return _flatten_battery
|
||||
pl.debug('Not using DBUS+UPower as no batteries were found')
|
||||
|
||||
if os.path.isdir('/sys/class/power_supply'):
|
||||
linux_bat_fmt = '/sys/class/power_supply/{0}/capacity'
|
||||
linux_ac_fmt = '/sys/class/power_supply/{0}/online'
|
||||
for linux_bat in os.listdir('/sys/class/power_supply'):
|
||||
cap_path = linux_bat_fmt.format(linux_bat)
|
||||
online_path = linux_ac_fmt.format(linux_bat)
|
||||
if linux_bat.startswith('BAT') and os.path.exists(cap_path):
|
||||
pl.debug('Using /sys/class/power_supply with battery {0}', linux_bat)
|
||||
|
||||
linux_energy_full_fmt = '/sys/class/power_supply/{0}/energy_full'
|
||||
linux_energy_fmt = '/sys/class/power_supply/{0}/energy_now'
|
||||
linux_status_fmt = '/sys/class/power_supply/{0}/status'
|
||||
devices = []
|
||||
for linux_supplier in os.listdir('/sys/class/power_supply'):
|
||||
energy_path = linux_energy_fmt.format(linux_supplier)
|
||||
if not os.path.exists(energy_path):
|
||||
continue
|
||||
pl.debug('Using /sys/class/power_supply with battery {0}', linux_supplier)
|
||||
devices.append(linux_supplier)
|
||||
if devices:
|
||||
def _get_battery_status(pl):
|
||||
with open(cap_path, 'r') as f:
|
||||
_capacity = int(float(f.readline().split()[0]))
|
||||
with open(online_path, 'r') as f:
|
||||
_ac_powered = f.readline() == 1
|
||||
return _capacity, _ac_powered
|
||||
energy = 0.0
|
||||
energy_full = 0.0
|
||||
state = True
|
||||
for device in devices:
|
||||
with open(linux_energy_full_fmt.format(device), 'r') as f:
|
||||
energy_full += int(float(f.readline().split()[0]))
|
||||
with open(linux_energy_fmt.format(device), 'r') as f:
|
||||
energy += int(float(f.readline().split()[0]))
|
||||
try:
|
||||
with open(linux_status_fmt.format(device), 'r') as f:
|
||||
state &= (f.readline().strip() != 'Discharging')
|
||||
except IOError:
|
||||
state = None
|
||||
return (energy * 100.0 / energy_full), state
|
||||
return _get_battery_status
|
||||
pl.debug('Not using /sys/class/power_supply as no batteries were found')
|
||||
else:
|
||||
|
@ -74,6 +74,7 @@ else:
|
||||
_interface_starts = {
|
||||
'eth': 10, # Regular ethernet adapters : eth1
|
||||
'enp': 10, # Regular ethernet adapters, Gentoo : enp2s0
|
||||
'en': 10, # OS X : en0
|
||||
'ath': 9, # Atheros WiFi adapters : ath0
|
||||
'wlan': 9, # Other WiFi adapters : wlan1
|
||||
'wlp': 9, # Other WiFi adapters, Gentoo : wlp5s0
|
||||
|
@ -189,6 +189,10 @@ class MpdPlayerSegment(PlayerSegment):
|
||||
'total': now_playing[3],
|
||||
}
|
||||
else:
|
||||
try:
|
||||
client = mpd.MPDClient(use_unicode=True)
|
||||
except TypeError:
|
||||
# python-mpd 1.x does not support use_unicode
|
||||
client = mpd.MPDClient()
|
||||
client.connect(host, port)
|
||||
if password:
|
||||
@ -204,7 +208,7 @@ class MpdPlayerSegment(PlayerSegment):
|
||||
'album': now_playing.get('album'),
|
||||
'artist': now_playing.get('artist'),
|
||||
'title': now_playing.get('title'),
|
||||
'elapsed': _convert_seconds(now_playing.get('elapsed', 0)),
|
||||
'elapsed': _convert_seconds(status.get('elapsed', 0)),
|
||||
'total': _convert_seconds(now_playing.get('time', 0)),
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,8 @@ from powerline.segments import with_docstring
|
||||
cpu_count = None
|
||||
|
||||
|
||||
def system_load(pl, format='{avg:.1f}', threshold_good=1, threshold_bad=2, track_cpu_count=False):
|
||||
def system_load(pl, format='{avg:.1f}', threshold_good=1, threshold_bad=2,
|
||||
track_cpu_count=False, short=False):
|
||||
'''Return system load average.
|
||||
|
||||
Highlights using ``system_load_good``, ``system_load_bad`` and
|
||||
@ -35,6 +36,8 @@ def system_load(pl, format='{avg:.1f}', threshold_good=1, threshold_bad=2, track
|
||||
:param bool track_cpu_count:
|
||||
if True powerline will continuously poll the system to detect changes
|
||||
in the number of CPUs.
|
||||
:param bool short:
|
||||
if True only the sys load over last 1 minute will be displayed.
|
||||
|
||||
Divider highlight group used: ``background:divider``.
|
||||
|
||||
@ -61,6 +64,10 @@ def system_load(pl, format='{avg:.1f}', threshold_good=1, threshold_bad=2, track
|
||||
'divider_highlight_group': 'background:divider',
|
||||
'gradient_level': gradient_level,
|
||||
})
|
||||
|
||||
if short:
|
||||
return ret
|
||||
|
||||
ret[0]['contents'] += ' '
|
||||
ret[1]['contents'] += ' '
|
||||
return ret
|
||||
|
@ -1,13 +1,16 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
import re
|
||||
|
||||
from powerline.theme import requires_segment_info
|
||||
from powerline.bindings.wm import get_i3_connection
|
||||
|
||||
|
||||
conn = None
|
||||
WORKSPACE_REGEX = re.compile(r'^[0-9]+: ?')
|
||||
|
||||
|
||||
def calcgrp(w):
|
||||
def workspace_groups(w):
|
||||
group = []
|
||||
if w['focused']:
|
||||
group.append('w_focused')
|
||||
@ -19,7 +22,14 @@ def calcgrp(w):
|
||||
return group
|
||||
|
||||
|
||||
def workspaces(pl, only_show=None, output=None, strip=0):
|
||||
def format_name(name, strip=False):
|
||||
if strip:
|
||||
return WORKSPACE_REGEX.sub('', name, count=1)
|
||||
return name
|
||||
|
||||
|
||||
@requires_segment_info
|
||||
def workspaces(pl, segment_info, only_show=None, output=None, strip=0):
|
||||
'''Return list of used workspaces
|
||||
|
||||
:param list only_show:
|
||||
@ -28,7 +38,9 @@ def workspaces(pl, only_show=None, output=None, strip=0):
|
||||
are shown.
|
||||
|
||||
:param str output:
|
||||
If specified, only workspaces on this output are shown.
|
||||
May be set to the name of an X output. If specified, only workspaces
|
||||
on that output are shown. Overrides automatic output detection by
|
||||
the lemonbar renderer and bindings.
|
||||
|
||||
:param int strip:
|
||||
Specifies how many characters from the front of each workspace name
|
||||
@ -36,22 +48,57 @@ def workspaces(pl, only_show=None, output=None, strip=0):
|
||||
|
||||
Highlight groups used: ``workspace`` or ``w_visible``, ``workspace`` or ``w_focused``, ``workspace`` or ``w_urgent``.
|
||||
'''
|
||||
global conn
|
||||
if not conn:
|
||||
output = output or segment_info.get('output')
|
||||
|
||||
return [
|
||||
{
|
||||
'contents': w['name'][strip:],
|
||||
'highlight_groups': workspace_groups(w)
|
||||
}
|
||||
for w in get_i3_connection().get_workspaces()
|
||||
if ((not only_show or any(w[typ] for typ in only_show))
|
||||
and (not output or w['output'] == output))
|
||||
]
|
||||
|
||||
|
||||
@requires_segment_info
|
||||
def workspace(pl, segment_info, workspace=None, strip=False):
|
||||
'''Return the specified workspace name
|
||||
|
||||
:param str workspace:
|
||||
Specifies which workspace to show. If unspecified, may be set by the
|
||||
``list_workspaces`` lister if used, otherwise falls back to
|
||||
currently focused workspace.
|
||||
|
||||
:param bool strip:
|
||||
Specifies whether workspace numbers (in the ``1: name`` format) should
|
||||
be stripped from workspace names before being displayed. Defaults to false.
|
||||
|
||||
Highlight groups used: ``workspace`` or ``w_visible``, ``workspace`` or ``w_focused``, ``workspace`` or ``w_urgent``.
|
||||
'''
|
||||
if workspace:
|
||||
try:
|
||||
import i3ipc
|
||||
except ImportError:
|
||||
import i3 as conn
|
||||
w = next((
|
||||
w for w in get_i3_connection().get_workspaces()
|
||||
if w['name'] == workspace
|
||||
))
|
||||
except StopIteration:
|
||||
return None
|
||||
elif segment_info.get('workspace'):
|
||||
w = segment_info['workspace']
|
||||
else:
|
||||
conn = i3ipc.Connection()
|
||||
try:
|
||||
w = next((
|
||||
w for w in get_i3_connection().get_workspaces()
|
||||
if w['focused']
|
||||
))
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
return [{
|
||||
'contents': w['name'][min(len(w['name']), strip):],
|
||||
'highlight_groups': calcgrp(w)
|
||||
} for w in conn.get_workspaces()
|
||||
if (not only_show or any(w[typ] for typ in only_show))
|
||||
and (not output or w['output'] == output)
|
||||
]
|
||||
'contents': format_name(w['name'], strip=strip),
|
||||
'highlight_groups': workspace_groups(w)
|
||||
}]
|
||||
|
||||
|
||||
@requires_segment_info
|
||||
@ -68,3 +115,41 @@ def mode(pl, segment_info, names={'default': None}):
|
||||
if mode in names:
|
||||
return names[mode]
|
||||
return mode
|
||||
|
||||
|
||||
def scratchpad_groups(w):
|
||||
group = []
|
||||
if w.urgent:
|
||||
group.append('scratchpad:urgent')
|
||||
if w.nodes[0].focused:
|
||||
group.append('scratchpad:focused')
|
||||
if w.workspace().name != '__i3_scratch':
|
||||
group.append('scratchpad:visible')
|
||||
group.append('scratchpad')
|
||||
return group
|
||||
|
||||
|
||||
SCRATCHPAD_ICONS = {
|
||||
'fresh': 'O',
|
||||
'changed': 'X',
|
||||
}
|
||||
|
||||
|
||||
def scratchpad(pl, icons=SCRATCHPAD_ICONS):
|
||||
'''Returns the windows currently on the scratchpad
|
||||
|
||||
:param dict icons:
|
||||
Specifies the strings to show for the different scratchpad window states. Must
|
||||
contain the keys ``fresh`` and ``changed``.
|
||||
|
||||
Highlight groups used: ``scratchpad`` or ``scratchpad:visible``, ``scratchpad`` or ``scratchpad:focused``, ``scratchpad`` or ``scratchpad:urgent``.
|
||||
'''
|
||||
|
||||
return [
|
||||
{
|
||||
'contents': icons.get(w.scratchpad_state, icons['changed']),
|
||||
'highlight_groups': scratchpad_groups(w)
|
||||
}
|
||||
for w in get_i3_connection().get_tree().descendents()
|
||||
if w.scratchpad_state != 'none'
|
||||
]
|
||||
|
@ -11,7 +11,7 @@ from collections import defaultdict
|
||||
try:
|
||||
import vim
|
||||
except ImportError:
|
||||
vim = {}
|
||||
vim = object()
|
||||
|
||||
from powerline.bindings.vim import (vim_get_func, getbufvar, vim_getbufoption,
|
||||
buffer_name, vim_getwinvar,
|
||||
|
@ -7,10 +7,13 @@ import logging
|
||||
|
||||
from itertools import count
|
||||
|
||||
try:
|
||||
import vim
|
||||
except ImportError:
|
||||
vim = object()
|
||||
|
||||
from powerline.bindings.vim import vim_get_func, vim_getvar, get_vim_encoding, python_to_vim
|
||||
from powerline import Powerline, FailedUnicode
|
||||
from powerline import Powerline, FailedUnicode, finish_common_config
|
||||
from powerline.lib.dict import mergedicts
|
||||
from powerline.lib.unicode import u
|
||||
|
||||
@ -32,19 +35,21 @@ def _override_from(config, override_varname, key=None):
|
||||
class VimVarHandler(logging.Handler, object):
|
||||
'''Vim-specific handler which emits messages to Vim global variables
|
||||
|
||||
Used variable: ``g:powerline_log_messages``.
|
||||
:param str varname:
|
||||
Variable where
|
||||
'''
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(VimVarHandler, self).__init__(*args, **kwargs)
|
||||
vim.command('unlet! g:powerline_log_messages')
|
||||
vim.command('let g:powerline_log_messages = []')
|
||||
def __init__(self, varname):
|
||||
super(VimVarHandler, self).__init__()
|
||||
utf_varname = u(varname)
|
||||
self.vim_varname = utf_varname.encode('ascii')
|
||||
vim.command('unlet! g:' + utf_varname)
|
||||
vim.command('let g:' + utf_varname + ' = []')
|
||||
|
||||
@staticmethod
|
||||
def emit(record):
|
||||
def emit(self, record):
|
||||
message = u(record.message)
|
||||
if record.exc_text:
|
||||
message += '\n' + u(record.exc_text)
|
||||
vim.eval(b'add(g:powerline_log_messages, ' + python_to_vim(message) + b')')
|
||||
vim.eval(b'add(g:' + self.vim_varname + b', ' + python_to_vim(message) + b')')
|
||||
|
||||
|
||||
class VimPowerline(Powerline):
|
||||
@ -53,6 +58,12 @@ class VimPowerline(Powerline):
|
||||
self.last_window_id = 1
|
||||
self.pyeval = pyeval
|
||||
self.construct_window_statusline = self.create_window_statusline_constructor()
|
||||
if all((hasattr(vim.current.window, attr) for attr in ('options', 'vars', 'number'))):
|
||||
self.win_idx = self.new_win_idx
|
||||
else:
|
||||
self.win_idx = self.old_win_idx
|
||||
self._vim_getwinvar = vim_get_func('getwinvar', 'bytes')
|
||||
self._vim_setwinvar = vim_get_func('setwinvar')
|
||||
|
||||
if sys.version_info < (3,):
|
||||
def create_window_statusline_constructor(self):
|
||||
@ -80,18 +91,6 @@ class VimPowerline(Powerline):
|
||||
|
||||
default_log_stream = sys.stdout
|
||||
|
||||
def create_logger(self):
|
||||
logger = super(VimPowerline, self).create_logger()
|
||||
try:
|
||||
if int(vim_getvar('powerline_use_var_handler')):
|
||||
formatter = logging.Formatter(self.common_config['log_format'])
|
||||
handler = VimVarHandler(getattr(logging, self.common_config['log_level']))
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
except KeyError:
|
||||
pass
|
||||
return logger
|
||||
|
||||
def add_local_theme(self, key, config):
|
||||
'''Add local themes at runtime (during vim session).
|
||||
|
||||
@ -137,7 +136,16 @@ class VimPowerline(Powerline):
|
||||
get_encoding = staticmethod(get_vim_encoding)
|
||||
|
||||
def load_main_config(self):
|
||||
return _override_from(super(VimPowerline, self).load_main_config(), 'powerline_config_overrides')
|
||||
main_config = _override_from(super(VimPowerline, self).load_main_config(), 'powerline_config_overrides')
|
||||
try:
|
||||
use_var_handler = bool(int(vim_getvar('powerline_use_var_handler')))
|
||||
except KeyError:
|
||||
use_var_handler = False
|
||||
if use_var_handler:
|
||||
main_config.setdefault('common', {})
|
||||
main_config['common'] = finish_common_config(self.get_encoding(), main_config['common'])
|
||||
main_config['common']['log_file'].append(['powerline.vim.VimVarHandler', [['powerline_log_messages']]])
|
||||
return main_config
|
||||
|
||||
def load_theme_config(self, name):
|
||||
return _override_from(
|
||||
@ -252,8 +260,7 @@ class VimPowerline(Powerline):
|
||||
# do anything.
|
||||
pass
|
||||
|
||||
if all((hasattr(vim.current.window, attr) for attr in ('options', 'vars', 'number'))):
|
||||
def win_idx(self, window_id):
|
||||
def new_win_idx(self, window_id):
|
||||
r = None
|
||||
for window in vim.windows:
|
||||
try:
|
||||
@ -270,11 +277,8 @@ class VimPowerline(Powerline):
|
||||
if curwindow_id == window_id if window_id else window is vim.current.window:
|
||||
r = (window, curwindow_id, window.number)
|
||||
return r
|
||||
else:
|
||||
_vim_getwinvar = staticmethod(vim_get_func('getwinvar', 'bytes'))
|
||||
_vim_setwinvar = staticmethod(vim_get_func('setwinvar'))
|
||||
|
||||
def win_idx(self, window_id):
|
||||
def old_win_idx(self, window_id):
|
||||
r = None
|
||||
for winnr, window in zip(count(1), vim.windows):
|
||||
curwindow_id = self._vim_getwinvar(winnr, 'powerline_window_id')
|
||||
|
4
setup.py
4
setup.py
@ -59,7 +59,7 @@ else:
|
||||
|
||||
|
||||
def get_version():
|
||||
base_version = '2.3'
|
||||
base_version = '2.4'
|
||||
base_version += '.dev9999'
|
||||
try:
|
||||
return base_version + '+git.' + str(subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip())
|
||||
@ -70,7 +70,7 @@ def get_version():
|
||||
|
||||
setup(
|
||||
name='powerline-status',
|
||||
version='2.3',
|
||||
version='2.4',
|
||||
description='The ultimate statusline/prompt utility.',
|
||||
long_description=README,
|
||||
classifiers=[
|
||||
|
@ -18,7 +18,9 @@ exit_suite() {
|
||||
echo "${FAIL_SUMMARY}"
|
||||
fi
|
||||
export POWERLINE_CURRENT_SUITE="${POWERLINE_CURRENT_SUITE%/*}"
|
||||
if test "x$1" != "x--continue" ; then
|
||||
exit $FAILED
|
||||
fi
|
||||
}
|
||||
|
||||
fail() {
|
||||
|
@ -21,6 +21,11 @@ class Pl(object):
|
||||
' self.{0}s.append((kwargs.get("prefix") or self.prefix, msg, args, kwargs))\n'
|
||||
).format(meth))
|
||||
|
||||
def __nonzero__(self):
|
||||
return bool(self.exceptions or self.errors or self.warns)
|
||||
|
||||
__bool__ = __nonzero__
|
||||
|
||||
|
||||
class Args(object):
|
||||
theme_override = {}
|
||||
|
201
tests/run_bar_tests.sh
Executable file
201
tests/run_bar_tests.sh
Executable file
@ -0,0 +1,201 @@
|
||||
#!/bin/sh
|
||||
. tests/common.sh
|
||||
|
||||
enter_suite bar
|
||||
|
||||
TEST_ROOT="$ROOT/tests/bar"
|
||||
TEST_PATH="$TEST_ROOT/path"
|
||||
TEST_STATIC_ROOT="$ROOT/tests/test_bar"
|
||||
|
||||
test -d "$TEST_ROOT" && rm -r "$TEST_ROOT"
|
||||
mkdir "$TEST_ROOT"
|
||||
cp -r "$TEST_STATIC_ROOT/path" "$TEST_ROOT"
|
||||
cp -r "$TEST_STATIC_ROOT/powerline" "$TEST_ROOT"
|
||||
|
||||
export PYTHONPATH="$ROOT${PYTHONPATH:+:}$PYTHONPATH"
|
||||
|
||||
ln -s "$(which "${PYTHON}")" "$TEST_PATH"/python
|
||||
ln -s "$(which sed)" "$TEST_PATH"
|
||||
ln -s "$(which cat)" "$TEST_PATH"
|
||||
ln -s "$(which mkdir)" "$TEST_PATH"
|
||||
ln -s "$(which basename)" "$TEST_PATH"
|
||||
ln -s "$TEST_PATH/lemonbar" "$TEST_PATH/bar-aint-recursive"
|
||||
|
||||
DEPRECATED_SCRIPT="$ROOT/powerline/bindings/bar/powerline-bar.py"
|
||||
|
||||
run() {
|
||||
env -i \
|
||||
LANG=C \
|
||||
PATH="$TEST_PATH" \
|
||||
XDG_CONFIG_HOME="$TEST_ROOT" \
|
||||
XDG_CONFIG_DIRS="$TEST_ROOT/dummy" \
|
||||
PYTHONPATH="$PYTHONPATH" \
|
||||
TEST_ROOT="$TEST_ROOT" \
|
||||
LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
|
||||
"$@" || true
|
||||
}
|
||||
|
||||
display_log() {
|
||||
local log_file="$1"
|
||||
echo "$log_file:"
|
||||
echo '============================================================'
|
||||
cat -v "$log_file"
|
||||
echo
|
||||
echo '____________________________________________________________'
|
||||
}
|
||||
|
||||
check_log() {
|
||||
local log_file="$1"
|
||||
local text="$2"
|
||||
local warns="$3"
|
||||
if test "$warns" = "warns" ; then
|
||||
local warning="$(head -n1 "$log_file" | sed 's/.*://')"
|
||||
local expwarning="The 'bar' bindings are deprecated, please switch to 'lemonbar'"
|
||||
if test "x$warning" != "x$expwarning" ; then
|
||||
echo "Got: $warning"
|
||||
echo "Exp: $expwarning"
|
||||
fail "warn" F "Expected warning"
|
||||
fi
|
||||
sed -r -i -e '1d' "$log_file"
|
||||
fi
|
||||
local line="$(head -n1 "$log_file")"
|
||||
local linenum="$(cat "$log_file" | wc -l)"
|
||||
if test $linenum -lt 5 ; then
|
||||
fail "log:lt" F "Script was run not enough times"
|
||||
return 1
|
||||
elif test $linenum -gt 15 ; then
|
||||
fail "log:gt" E "Script was run too many times"
|
||||
return 1
|
||||
fi
|
||||
local expline="%{l}%{F#ffd0d0d0}%{B#ff303030} $text-left %{F-B--u}%{F#ff303030} %{F-B--u}%{r}%{F#ff303030} %{F-B--u}%{F#ffd0d0d0}%{B#ff303030} $text-right %{F-B--u}"
|
||||
if test "x$expline" != "x$line" ; then
|
||||
echo "Line: '$line'"
|
||||
echo "Expected: '$expline'"
|
||||
fail "log:line" F "Unexpected line"
|
||||
return 1
|
||||
fi
|
||||
local ret=0
|
||||
while test $linenum -gt 0 ; do
|
||||
echo "$line" >> "$TEST_ROOT/ok"
|
||||
linenum=$(( linenum - 1 ))
|
||||
done
|
||||
if ! diff "$TEST_ROOT/ok" "$log_file" ; then
|
||||
fail "log:diff" F "Unexpected output"
|
||||
ret=1
|
||||
fi
|
||||
rm "$TEST_ROOT/ok"
|
||||
return $ret
|
||||
}
|
||||
|
||||
killscript() {
|
||||
kill -KILL $1 || true
|
||||
}
|
||||
|
||||
if ! test -e "$DEPRECATED_SCRIPT" ; then
|
||||
# TODO: uncomment when skip is available
|
||||
# skip "deprecated" "Missing deprecated bar bindings script"
|
||||
:
|
||||
else
|
||||
enter_suite "deprecated"
|
||||
run python "$DEPRECATED_SCRIPT" $args > "$TEST_ROOT/deprecated.log" 2>&1 &
|
||||
SPID=$!
|
||||
sleep 5
|
||||
killscript $SPID
|
||||
if ! check_log "$TEST_ROOT/deprecated.log" "default" warns ; then
|
||||
display_log "$TEST_ROOT/deprecated.log"
|
||||
fail "log" F "Checking log failed"
|
||||
fi
|
||||
rm "$TEST_ROOT/deprecated.log"
|
||||
exit_suite --continue
|
||||
fi
|
||||
|
||||
LEMONBAR_SCRIPT="$ROOT/powerline/bindings/lemonbar/powerline-lemonbar.py"
|
||||
|
||||
if ! test -e "$LEMONBAR_SCRIPT" ; then
|
||||
# TODO: uncomment when skip is available
|
||||
# skip "lemonbar" "Missing lemonbar bindings script"
|
||||
:
|
||||
else
|
||||
enter_suite "lemonbar"
|
||||
for args in "" "-i0.5" "--interval=0.5" "-- test args" "--bar-command bar-aint-recursive" "--height=10"; do
|
||||
rm -rf "$TEST_ROOT/results"
|
||||
run python "$LEMONBAR_SCRIPT" $args > "$TEST_ROOT/lemonbar.log" 2>&1 &
|
||||
SPID=$!
|
||||
sleep 5
|
||||
killscript $SPID
|
||||
sleep 0.5
|
||||
enter_suite "args($args)"
|
||||
fnum=0
|
||||
for file in "$TEST_ROOT/results"/*.log ; do
|
||||
if ! test -e "$file" ; then
|
||||
fail "log" E "Log file is missing"
|
||||
break
|
||||
fi
|
||||
fnum=$(( fnum + 1 ))
|
||||
args_file="${file%.log}.args"
|
||||
if ! test -e "$args_file" ; then
|
||||
fail "args" E "$args_file is missing"
|
||||
else
|
||||
cat "$args_file" >> "$TEST_ROOT/args.log"
|
||||
fi
|
||||
text="dvi"
|
||||
if cat "$args_file" | grep -q +1 ; then
|
||||
text="default"
|
||||
fi
|
||||
if ! check_log "$file" "$text" ; then
|
||||
display_log "$file"
|
||||
fail "log" F "Checking log failed"
|
||||
fi
|
||||
rm "$file"
|
||||
done
|
||||
if test "$fnum" -ne 2 ; then
|
||||
fail "fnum" F "Expected two output files"
|
||||
fi
|
||||
if test "x${args#--height}" != "x$args" ; then
|
||||
height="${args#--height}"
|
||||
height="${height# }"
|
||||
height="${height#=}"
|
||||
height="${height%% *}"
|
||||
fi
|
||||
command="lemonbar"
|
||||
if test "x${args#--bar-command}" != "x$args" ; then
|
||||
command="${args#--bar-command}"
|
||||
command="${command# }"
|
||||
command="${command#=}"
|
||||
command="${command%% *}"
|
||||
fi
|
||||
received_args="$(cat "$TEST_ROOT/args.log" | sort)"
|
||||
rm "$TEST_ROOT/args.log"
|
||||
script_args="${args#*-- }"
|
||||
script_args="${script_args# }"
|
||||
if test "x${script_args}" '=' "x$args" ; then
|
||||
script_args=
|
||||
fi
|
||||
expected_args="$command -g 1920x$height+0${script_args:+ }$script_args${NL}$command -g 1920x$height+1${script_args:+ }$script_args"
|
||||
if test "x$expected_args" != "x$received_args" ; then
|
||||
echo "args:${NL}<$received_args>"
|
||||
echo "expected:${NL}<$expected_args>"
|
||||
fail "args" F "Expected different args"
|
||||
fi
|
||||
if ! test -z "$(cat "$TEST_ROOT/lemonbar.log")" ; then
|
||||
display_log "$TEST_ROOT/lemonbar.log"
|
||||
fail "stderr" E "Unexpected script output"
|
||||
fi
|
||||
rm "$TEST_ROOT/lemonbar.log"
|
||||
exit_suite --continue
|
||||
done
|
||||
exit_suite --continue
|
||||
fi
|
||||
|
||||
if ! powerline-lint \
|
||||
-p "$ROOT/powerline/config_files" \
|
||||
-p "$TEST_STATIC_ROOT/powerline"
|
||||
then
|
||||
fail "lint" F "Checking test config failed"
|
||||
fi
|
||||
|
||||
if test $FAILED -eq 0 ; then
|
||||
rm -r "$TEST_ROOT"
|
||||
fi
|
||||
|
||||
exit_suite
|
11
tests/test_bar/path/lemonbar
Executable file
11
tests/test_bar/path/lemonbar
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
RES_DIR="$TEST_ROOT/results"
|
||||
mkdir -p "$RES_DIR"
|
||||
RES_FILE="$RES_DIR/$$"
|
||||
while test -e "$RES_FILE.log" ; do
|
||||
RES_FILE="$RES_FILE.${RANDOM:-`date +%N | sed s/^0*//`}"
|
||||
done
|
||||
|
||||
echo $(basename $0) "$@" > "$RES_FILE.args"
|
||||
cat > "$RES_FILE.log"
|
31
tests/test_bar/path/xrandr
Executable file
31
tests/test_bar/path/xrandr
Executable file
@ -0,0 +1,31 @@
|
||||
#!/bin/sh
|
||||
|
||||
cat << EOF
|
||||
Screen 0: minimum 8 x 8, current 1920 x 1200, maximum 16384 x 16384
|
||||
DVI-I-0 disconnected (normal left inverted right x axis y axis)
|
||||
VGA-0 connected 1920x1200+1+0 (normal left inverted right x axis y axis) 520mm x 330mm
|
||||
1920x1200 59.95*+
|
||||
1920x1080 60.00
|
||||
1680x1050 59.95
|
||||
1600x1200 60.00
|
||||
1440x900 59.89
|
||||
1280x1024 75.02 60.02
|
||||
1280x800 59.81
|
||||
1152x864 75.00
|
||||
1024x768 75.03 60.00
|
||||
800x600 75.00 60.32
|
||||
640x480 75.00 59.94
|
||||
DVI-I-1 connected 1920x1200+0+0 (normal left inverted right x axis y axis) 520mm x 330mm
|
||||
1920x1200 59.95*+
|
||||
1920x1080 60.00
|
||||
1680x1050 59.95
|
||||
1600x1200 60.00
|
||||
1440x900 59.89
|
||||
1280x1024 75.02 60.02
|
||||
1280x800 59.81
|
||||
1152x864 75.00
|
||||
1024x768 75.03 60.00
|
||||
800x600 75.00 60.32
|
||||
640x480 75.00 59.94
|
||||
HDMI-0 disconnected (normal left inverted right x axis y axis)
|
||||
EOF
|
9
tests/test_bar/powerline/config.json
Normal file
9
tests/test_bar/powerline/config.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"ext": {
|
||||
"wm": {
|
||||
"local_themes": {
|
||||
"DVI-I-1": "dvi"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
tests/test_bar/powerline/themes/wm/default.json
Normal file
18
tests/test_bar/powerline/themes/wm/default.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"segments": {
|
||||
"left": [
|
||||
{
|
||||
"type": "string",
|
||||
"highlight_groups": ["time"],
|
||||
"contents": "default-left"
|
||||
}
|
||||
],
|
||||
"right": [
|
||||
{
|
||||
"type": "string",
|
||||
"highlight_groups": ["time"],
|
||||
"contents": "default-right"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
18
tests/test_bar/powerline/themes/wm/dvi.json
Normal file
18
tests/test_bar/powerline/themes/wm/dvi.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"segments": {
|
||||
"left": [
|
||||
{
|
||||
"type": "string",
|
||||
"highlight_groups": ["time"],
|
||||
"contents": "dvi-left"
|
||||
}
|
||||
],
|
||||
"right": [
|
||||
{
|
||||
"type": "string",
|
||||
"highlight_groups": ["time"],
|
||||
"contents": "dvi-right"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -825,28 +825,28 @@ class TestVim(TestCase):
|
||||
sys.path.pop(0)
|
||||
|
||||
|
||||
class TestBar(TestRender):
|
||||
def test_bar(self):
|
||||
class TestLemonbar(TestRender):
|
||||
def test_lemonbar(self):
|
||||
import powerline as powerline_module
|
||||
with swap_attributes(config, powerline_module):
|
||||
with get_powerline_raw(config, powerline_module.Powerline, replace_gcp=True, ext='wm', renderer_module='bar') as powerline:
|
||||
with get_powerline_raw(config, powerline_module.Powerline, replace_gcp=True, ext='wm', renderer_module='lemonbar') as powerline:
|
||||
self.assertRenderEqual(
|
||||
powerline,
|
||||
'%{l}%{F#ffc00000}%{B#ff008000}%{+u} A%{F-B--u}%{F#ff008000}%{B#ffc00000}>>%{F-B--u}%{F#ff008000}%{B#ffc00000}B%{F-B--u}%{F#ffc00000}>>%{F-B--u}%{r}%{F#ffc00000}<<%{F-B--u}%{F#ff804000}%{B#ffc00000}%{+u}C%{F-B--u}%{F#ff0000c0}%{B#ffc00000}<<%{F-B--u}%{F#ff008000}%{B#ff0000c0}D %{F-B--u}'
|
||||
)
|
||||
|
||||
@with_new_config
|
||||
def test_bar_escape(self, config):
|
||||
def test_lemonbar_escape(self, config):
|
||||
import powerline as powerline_module
|
||||
config['themes/wm/default']['segments']['left'] = (
|
||||
highlighted_string('%{asd}', 'hl1'),
|
||||
highlighted_string('10% %', 'hl2'),
|
||||
)
|
||||
with swap_attributes(config, powerline_module):
|
||||
with get_powerline_raw(config, powerline_module.Powerline, replace_gcp=True, ext='wm', renderer_module='bar') as powerline:
|
||||
with get_powerline_raw(config, powerline_module.Powerline, replace_gcp=True, ext='wm', renderer_module='lemonbar') as powerline:
|
||||
self.assertRenderEqual(
|
||||
powerline,
|
||||
'%{l}%{F#ffc00000}%{B#ff008000}%{+u} %%{asd}%{F-B--u}%{F#ff008000}%{B#ffc00000}>>%{F-B--u}%{F#ff008000}%{B#ffc00000}10%% %%%{F-B--u}%{F#ffc00000}>>%{F-B--u}%{r}%{F#ffc00000}<<%{F-B--u}%{F#ff804000}%{B#ffc00000}%{+u}C%{F-B--u}%{F#ff0000c0}%{B#ffc00000}<<%{F-B--u}%{F#ff008000}%{B#ff0000c0}D %{F-B--u}'
|
||||
'%{l}%{F#ffc00000}%{B#ff008000}%{+u} %%{}{asd}%{F-B--u}%{F#ff008000}%{B#ffc00000}>>%{F-B--u}%{F#ff008000}%{B#ffc00000}10%%{} %%{}%{F-B--u}%{F#ffc00000}>>%{F-B--u}%{r}%{F#ffc00000}<<%{F-B--u}%{F#ff804000}%{B#ffc00000}%{+u}C%{F-B--u}%{F#ff0000c0}%{B#ffc00000}<<%{F-B--u}%{F#ff008000}%{B#ff0000c0}D %{F-B--u}'
|
||||
)
|
||||
|
||||
|
||||
|
@ -17,6 +17,7 @@ from powerline.lib.vcs import guess, get_fallback_create_watcher
|
||||
from powerline.lib.threaded import ThreadedSegment, KwThreadedSegment
|
||||
from powerline.lib.monotonic import monotonic
|
||||
from powerline.lib.vcs.git import git_directory
|
||||
from powerline.lib.shell import run_cmd
|
||||
|
||||
import powerline.lib.unicode as plu
|
||||
|
||||
@ -48,6 +49,24 @@ def thread_number():
|
||||
return len(threading.enumerate())
|
||||
|
||||
|
||||
class TestShell(TestCase):
|
||||
def test_run_cmd(self):
|
||||
pl = Pl()
|
||||
self.assertEqual(run_cmd(pl, ['xxx_nonexistent_command_xxx']), None)
|
||||
self.assertEqual(len(pl.exceptions), 1)
|
||||
pl = Pl()
|
||||
self.assertEqual(run_cmd(pl, ['echo', ' test ']), 'test')
|
||||
self.assertFalse(pl)
|
||||
self.assertEqual(run_cmd(pl, ['echo', ' test '], strip=True), 'test')
|
||||
self.assertFalse(pl)
|
||||
self.assertEqual(run_cmd(pl, ['echo', ' test '], strip=False), ' test \n')
|
||||
self.assertFalse(pl)
|
||||
self.assertEqual(run_cmd(pl, ['cat'], stdin='test'), 'test')
|
||||
self.assertFalse(pl)
|
||||
self.assertEqual(run_cmd(pl, ['sh', '-c', 'cat >&2'], stdin='test'), '')
|
||||
self.assertFalse(pl)
|
||||
|
||||
|
||||
class TestThreaded(TestCase):
|
||||
def test_threaded_segment(self):
|
||||
log = []
|
||||
|
227
tests/test_listers.py
Normal file
227
tests/test_listers.py
Normal file
@ -0,0 +1,227 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
import powerline.listers.i3wm as i3wm
|
||||
|
||||
from tests.lib import Args, replace_attr, Pl
|
||||
from tests import TestCase
|
||||
|
||||
|
||||
class TestI3WM(TestCase):
|
||||
@staticmethod
|
||||
def get_workspaces():
|
||||
return iter([
|
||||
{'name': '1: w1', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': False},
|
||||
{'name': '2: w2', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': True},
|
||||
{'name': '3: w3', 'output': 'HDMI1', 'focused': False, 'urgent': True, 'visible': True},
|
||||
{'name': '4: w4', 'output': 'DVI01', 'focused': True, 'urgent': True, 'visible': True},
|
||||
])
|
||||
|
||||
@staticmethod
|
||||
def get_outputs(pl):
|
||||
return iter([
|
||||
{'name': 'LVDS1'},
|
||||
{'name': 'HDMI1'},
|
||||
{'name': 'DVI01'},
|
||||
])
|
||||
|
||||
def test_output_lister(self):
|
||||
pl = Pl()
|
||||
with replace_attr(i3wm, 'get_connected_xrandr_outputs', self.get_outputs):
|
||||
self.assertEqual(
|
||||
list(i3wm.output_lister(pl=pl, segment_info={'a': 1})),
|
||||
[
|
||||
({'a': 1, 'output': 'LVDS1'}, {'draw_inner_divider': None}),
|
||||
({'a': 1, 'output': 'HDMI1'}, {'draw_inner_divider': None}),
|
||||
({'a': 1, 'output': 'DVI01'}, {'draw_inner_divider': None}),
|
||||
]
|
||||
)
|
||||
|
||||
def test_workspace_lister(self):
|
||||
pl = Pl()
|
||||
with replace_attr(i3wm, 'get_i3_connection', lambda: Args(get_workspaces=self.get_workspaces)):
|
||||
self.assertEqual(
|
||||
list(i3wm.workspace_lister(pl=pl, segment_info={'a': 1})),
|
||||
[
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'LVDS1',
|
||||
'workspace': {
|
||||
'name': '1: w1',
|
||||
'focused': False,
|
||||
'urgent': False,
|
||||
'visible': False
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'LVDS1',
|
||||
'workspace': {
|
||||
'name': '2: w2',
|
||||
'focused': False,
|
||||
'urgent': False,
|
||||
'visible': True
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'HDMI1',
|
||||
'workspace': {
|
||||
'name': '3: w3',
|
||||
'focused': False,
|
||||
'urgent': True,
|
||||
'visible': True
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'DVI01',
|
||||
'workspace': {
|
||||
'name': '4: w4',
|
||||
'focused': True,
|
||||
'urgent': True,
|
||||
'visible': True
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
list(i3wm.workspace_lister(pl=pl, segment_info={'a': 1}, output='LVDS1')),
|
||||
[
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'LVDS1',
|
||||
'workspace': {
|
||||
'name': '1: w1',
|
||||
'focused': False,
|
||||
'urgent': False,
|
||||
'visible': False
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'LVDS1',
|
||||
'workspace': {
|
||||
'name': '2: w2',
|
||||
'focused': False,
|
||||
'urgent': False,
|
||||
'visible': True
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
list(i3wm.workspace_lister(
|
||||
pl=pl,
|
||||
segment_info={'a': 1, 'output': 'LVDS1'}
|
||||
)),
|
||||
[
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'LVDS1',
|
||||
'workspace': {
|
||||
'name': '1: w1',
|
||||
'focused': False,
|
||||
'urgent': False,
|
||||
'visible': False
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'LVDS1',
|
||||
'workspace': {
|
||||
'name': '2: w2',
|
||||
'focused': False,
|
||||
'urgent': False,
|
||||
'visible': True
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
list(i3wm.workspace_lister(
|
||||
pl=pl,
|
||||
segment_info={'a': 1, 'output': 'LVDS1'},
|
||||
output=False
|
||||
)),
|
||||
[
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'LVDS1',
|
||||
'workspace': {
|
||||
'name': '1: w1',
|
||||
'focused': False,
|
||||
'urgent': False,
|
||||
'visible': False
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'LVDS1',
|
||||
'workspace': {
|
||||
'name': '2: w2',
|
||||
'focused': False,
|
||||
'urgent': False,
|
||||
'visible': True
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'HDMI1',
|
||||
'workspace': {
|
||||
'name': '3: w3',
|
||||
'focused': False,
|
||||
'urgent': True,
|
||||
'visible': True
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'DVI01',
|
||||
'workspace': {
|
||||
'name': '4: w4',
|
||||
'focused': True,
|
||||
'urgent': True,
|
||||
'visible': True
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
list(i3wm.workspace_lister(
|
||||
pl=pl,
|
||||
segment_info={'a': 1},
|
||||
only_show=['focused', 'urgent']
|
||||
)),
|
||||
[
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'HDMI1',
|
||||
'workspace': {
|
||||
'name': '3: w3',
|
||||
'focused': False,
|
||||
'urgent': True,
|
||||
'visible': True
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
({
|
||||
'a': 1,
|
||||
'output': 'DVI01',
|
||||
'workspace': {
|
||||
'name': '4: w4',
|
||||
'focused': True,
|
||||
'urgent': True,
|
||||
'visible': True
|
||||
}
|
||||
}, {'draw_inner_divider': None}),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from tests import main
|
||||
main()
|
467
tests/test_logging.py
Normal file
467
tests/test_logging.py
Normal file
@ -0,0 +1,467 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
|
||||
'''Tests for various logging features'''
|
||||
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
import sys
|
||||
import re
|
||||
import codecs
|
||||
import os
|
||||
|
||||
from io import StringIO
|
||||
from shutil import rmtree
|
||||
|
||||
from powerline import finish_common_config, create_logger
|
||||
|
||||
from tests import TestCase
|
||||
from tests.lib import replace_attr
|
||||
|
||||
|
||||
TIMESTAMP_RE = r'\d{4}-\d\d-\d\d \d\d:\d\d:\d\d,\d{3}'
|
||||
|
||||
|
||||
class TestRE(TestCase):
|
||||
def assertMatches(self, text, regexp):
|
||||
self.assertTrue(
|
||||
re.match(regexp, text),
|
||||
'{0!r} did not match {1!r}'.format(text, regexp),
|
||||
)
|
||||
|
||||
|
||||
def close_handlers(logger):
|
||||
for handler in logger.handlers:
|
||||
handler.close()
|
||||
|
||||
|
||||
class TestHandlers(TestRE):
|
||||
def test_stderr_handler_is_default(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {})
|
||||
logger, pl, get_module_attr = create_logger(common_config)
|
||||
pl.error('Foo')
|
||||
close_handlers(logger)
|
||||
self.assertMatches(err.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_stream_override(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.error('Foo')
|
||||
close_handlers(logger)
|
||||
self.assertMatches(stream.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_explicit_none(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': [None]})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.error('Foo')
|
||||
close_handlers(logger)
|
||||
self.assertMatches(stream.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_explicit_stream_handler(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': [['logging.StreamHandler', [[]]]]})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.error('Foo')
|
||||
close_handlers(logger)
|
||||
self.assertEqual(stream.getvalue(), '')
|
||||
self.assertMatches(err.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_explicit_stream_handler_implicit_stream(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': [['logging.StreamHandler', []]]})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.error('Foo')
|
||||
close_handlers(logger)
|
||||
self.assertMatches(stream.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_file_handler(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
file_name = 'test_logging-test_file_handler'
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': file_name})
|
||||
try:
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.error('Foo')
|
||||
close_handlers(logger)
|
||||
with codecs.open(file_name, encoding='utf-8') as fp:
|
||||
self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$')
|
||||
finally:
|
||||
os.unlink(file_name)
|
||||
self.assertEqual(stream.getvalue(), '')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_file_handler_create_dir(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
file_name = 'test_logging-test_file_handler_create_dir/file'
|
||||
|
||||
self.assertFalse(os.path.isdir(os.path.dirname(file_name)))
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': file_name})
|
||||
try:
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.error('Foo')
|
||||
close_handlers(logger)
|
||||
self.assertTrue(os.path.isdir(os.path.dirname(file_name)))
|
||||
with codecs.open(file_name, encoding='utf-8') as fp:
|
||||
self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$')
|
||||
finally:
|
||||
rmtree(os.path.dirname(file_name))
|
||||
self.assertEqual(stream.getvalue(), '')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_multiple_files(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
file_name_1 = 'test_logging-test_multiple_files-1'
|
||||
file_name_2 = file_name_1[:-1] + '2'
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': [file_name_1, file_name_2]})
|
||||
try:
|
||||
try:
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.error('Foo')
|
||||
close_handlers(logger)
|
||||
for file_name in (file_name_1, file_name_2):
|
||||
with codecs.open(file_name, encoding='utf-8') as fp:
|
||||
self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$')
|
||||
finally:
|
||||
os.unlink(file_name_1)
|
||||
finally:
|
||||
os.unlink(file_name_2)
|
||||
self.assertEqual(stream.getvalue(), '')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_multiple_files_and_stream(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
file_name_1 = 'test_logging-test_multiple_files_and_stream-1'
|
||||
file_name_2 = file_name_1[:-1] + '2'
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': [file_name_1, file_name_2, None]})
|
||||
try:
|
||||
try:
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.error('Foo')
|
||||
close_handlers(logger)
|
||||
for file_name in (file_name_1, file_name_2):
|
||||
with codecs.open(file_name, encoding='utf-8') as fp:
|
||||
self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$')
|
||||
finally:
|
||||
os.unlink(file_name_1)
|
||||
finally:
|
||||
os.unlink(file_name_2)
|
||||
self.assertMatches(stream.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_handler_args(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
file_name = 'test_logging-test_handler_args'
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': [
|
||||
['RotatingFileHandler', [[file_name]]]
|
||||
]})
|
||||
try:
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.error('Foo')
|
||||
close_handlers(logger)
|
||||
with codecs.open(file_name, encoding='utf-8') as fp:
|
||||
self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$')
|
||||
finally:
|
||||
os.unlink(file_name)
|
||||
self.assertEqual(stream.getvalue(), '')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_handler_args_kwargs(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
file_name = 'test_logging-test_handler_args_kwargs'
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': [
|
||||
['RotatingFileHandler', [[file_name], {'maxBytes': 1, 'backupCount': 1}]]
|
||||
]})
|
||||
try:
|
||||
try:
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.error('Foo')
|
||||
pl.error('Bar')
|
||||
close_handlers(logger)
|
||||
with codecs.open(file_name, encoding='utf-8') as fp:
|
||||
self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$')
|
||||
with codecs.open(file_name + '.1', encoding='utf-8') as fp:
|
||||
self.assertMatches(fp.read(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Foo\n$')
|
||||
finally:
|
||||
os.unlink(file_name + '.1')
|
||||
finally:
|
||||
os.unlink(file_name)
|
||||
self.assertEqual(stream.getvalue(), '')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_logger_level(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
stream1 = StringIO()
|
||||
stream2 = StringIO()
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': [
|
||||
['logging.StreamHandler', [[stream1]], 'WARNING'],
|
||||
['logging.StreamHandler', [[stream2]], 'ERROR'],
|
||||
]})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.warn('Foo')
|
||||
pl.error('Bar')
|
||||
close_handlers(logger)
|
||||
self.assertMatches(stream1.getvalue(), (
|
||||
'^' + TIMESTAMP_RE + ':WARNING:__unknown__:Foo\n'
|
||||
+ TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$'
|
||||
))
|
||||
self.assertMatches(stream2.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$')
|
||||
self.assertEqual(stream.getvalue(), '')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_logger_level_not_overriding_default(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
stream1 = StringIO()
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': [
|
||||
['logging.StreamHandler', [[stream1]], 'DEBUG'],
|
||||
]})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.debug('Foo')
|
||||
pl.error('Bar')
|
||||
close_handlers(logger)
|
||||
self.assertMatches(stream1.getvalue(), '^' + TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$')
|
||||
self.assertEqual(stream.getvalue(), '')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_top_log_level(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
stream1 = StringIO()
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': [
|
||||
['logging.StreamHandler', [[stream1]], 'DEBUG'],
|
||||
], 'log_level': 'DEBUG'})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.debug('Foo')
|
||||
pl.error('Bar')
|
||||
close_handlers(logger)
|
||||
self.assertMatches(stream1.getvalue(), (
|
||||
'^' + TIMESTAMP_RE + ':DEBUG:__unknown__:Foo\n'
|
||||
+ TIMESTAMP_RE + ':ERROR:__unknown__:Bar\n$'
|
||||
))
|
||||
self.assertEqual(stream.getvalue(), '')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_logger_format(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
stream1 = StringIO()
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': [
|
||||
['logging.StreamHandler', [[stream1]], 'WARNING', 'FOO'],
|
||||
]})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.warn('Foo')
|
||||
pl.error('Bar')
|
||||
close_handlers(logger)
|
||||
self.assertEqual(stream1.getvalue(), 'FOO\nFOO\n')
|
||||
self.assertEqual(stream.getvalue(), '')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
def test_top_log_format(self):
|
||||
out = StringIO()
|
||||
err = StringIO()
|
||||
stream = StringIO()
|
||||
stream1 = StringIO()
|
||||
stream2 = StringIO()
|
||||
|
||||
with replace_attr(sys, 'stdout', out, 'stderr', err):
|
||||
common_config = finish_common_config('utf-8', {'log_file': [
|
||||
['logging.StreamHandler', [[stream1]], 'WARNING', 'FOO'],
|
||||
['logging.StreamHandler', [[stream2]], 'WARNING'],
|
||||
], 'log_format': 'BAR'})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.warn('Foo')
|
||||
pl.error('Bar')
|
||||
close_handlers(logger)
|
||||
self.assertEqual(stream2.getvalue(), 'BAR\nBAR\n')
|
||||
self.assertEqual(stream1.getvalue(), 'FOO\nFOO\n')
|
||||
self.assertEqual(stream.getvalue(), '')
|
||||
self.assertEqual(err.getvalue(), '')
|
||||
self.assertEqual(out.getvalue(), '')
|
||||
|
||||
|
||||
class TestPowerlineLogger(TestRE):
|
||||
def test_args_formatting(self):
|
||||
stream = StringIO()
|
||||
|
||||
common_config = finish_common_config('utf-8', {})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.warn('foo {0}', 'Test')
|
||||
pl.warn('bar {0!r}', 'Test')
|
||||
close_handlers(logger)
|
||||
self.assertMatches(stream.getvalue(), (
|
||||
'^' + TIMESTAMP_RE + ':WARNING:__unknown__:foo Test\n'
|
||||
+ TIMESTAMP_RE + ':WARNING:__unknown__:bar u?\'Test\'\n$'
|
||||
))
|
||||
|
||||
def test_prefix_formatting(self):
|
||||
stream = StringIO()
|
||||
|
||||
common_config = finish_common_config('utf-8', {})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.prefix = '1'
|
||||
pl.warn('foo')
|
||||
pl.prefix = '2'
|
||||
pl.warn('bar')
|
||||
close_handlers(logger)
|
||||
self.assertMatches(stream.getvalue(), (
|
||||
'^' + TIMESTAMP_RE + ':WARNING:__unknown__:1:foo\n'
|
||||
+ TIMESTAMP_RE + ':WARNING:__unknown__:2:bar\n$'
|
||||
))
|
||||
|
||||
def test_kwargs_formatting(self):
|
||||
stream = StringIO()
|
||||
|
||||
common_config = finish_common_config('utf-8', {})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.warn('foo {arg}', arg='Test')
|
||||
pl.warn('bar {arg!r}', arg='Test')
|
||||
close_handlers(logger)
|
||||
self.assertMatches(stream.getvalue(), (
|
||||
'^' + TIMESTAMP_RE + ':WARNING:__unknown__:foo Test\n'
|
||||
+ TIMESTAMP_RE + ':WARNING:__unknown__:bar u?\'Test\'\n$'
|
||||
))
|
||||
|
||||
def test_args_kwargs_formatting(self):
|
||||
stream = StringIO()
|
||||
|
||||
common_config = finish_common_config('utf-8', {})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.warn('foo {0!r} {arg}', 'Test0', arg='Test')
|
||||
pl.warn('bar {0} {arg!r}', 'Test0', arg='Test')
|
||||
close_handlers(logger)
|
||||
self.assertMatches(stream.getvalue(), (
|
||||
'^' + TIMESTAMP_RE + ':WARNING:__unknown__:foo u?\'Test0\' Test\n'
|
||||
+ TIMESTAMP_RE + ':WARNING:__unknown__:bar Test0 u?\'Test\'\n$'
|
||||
))
|
||||
|
||||
def test_exception_formatting(self):
|
||||
stream = StringIO()
|
||||
|
||||
common_config = finish_common_config('utf-8', {})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
try:
|
||||
raise ValueError('foo')
|
||||
except ValueError:
|
||||
pl.exception('Message')
|
||||
close_handlers(logger)
|
||||
self.assertMatches(stream.getvalue(), (
|
||||
'^' + TIMESTAMP_RE + ':ERROR:__unknown__:Message\n'
|
||||
+ 'Traceback \\(most recent call last\\):\n'
|
||||
+ '(?: File ".*?", line \\d+, in \\w+\n [^\n]*\n)+'
|
||||
+ 'ValueError: foo\n$'
|
||||
))
|
||||
|
||||
def test_levels(self):
|
||||
stream = StringIO()
|
||||
|
||||
common_config = finish_common_config('utf-8', {'log_level': 'DEBUG'})
|
||||
logger, pl, get_module_attr = create_logger(common_config, stream=stream)
|
||||
pl.debug('1')
|
||||
pl.info('2')
|
||||
pl.warn('3')
|
||||
pl.error('4')
|
||||
pl.critical('5')
|
||||
close_handlers(logger)
|
||||
self.assertMatches(stream.getvalue(), (
|
||||
'^' + TIMESTAMP_RE + ':DEBUG:__unknown__:1\n'
|
||||
+ TIMESTAMP_RE + ':INFO:__unknown__:2\n'
|
||||
+ TIMESTAMP_RE + ':WARNING:__unknown__:3\n'
|
||||
+ TIMESTAMP_RE + ':ERROR:__unknown__:4\n'
|
||||
+ TIMESTAMP_RE + ':CRITICAL:__unknown__:5\n$'
|
||||
))
|
||||
|
||||
|
||||
old_cwd = None
|
||||
|
||||
|
||||
def setUpModule():
|
||||
global old_cwd
|
||||
global __file__
|
||||
old_cwd = os.getcwd()
|
||||
__file__ = os.path.abspath(__file__)
|
||||
os.chdir(os.path.dirname(__file__))
|
||||
|
||||
|
||||
def tearDownModule():
|
||||
global old_cwd
|
||||
os.chdir(old_cwd)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from tests import main
|
||||
main()
|
@ -811,6 +811,12 @@ class TestSys(TestCommon):
|
||||
{'contents': '4 ', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 100},
|
||||
{'contents': '2', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 75.0}
|
||||
])
|
||||
self.assertEqual(self.module.system_load(pl=pl, short=True), [
|
||||
{'contents': '7.5', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 100},
|
||||
])
|
||||
self.assertEqual(self.module.system_load(pl=pl, format='{avg:.0f}', threshold_good=0, threshold_bad=1, short=True), [
|
||||
{'contents': '8', 'highlight_groups': ['system_load_gradient', 'system_load'], 'divider_highlight_group': 'background:divider', 'gradient_level': 100},
|
||||
])
|
||||
|
||||
def test_cpu_load_percent(self):
|
||||
try:
|
||||
@ -883,49 +889,85 @@ class TestWthr(TestCommon):
|
||||
|
||||
|
||||
class TestI3WM(TestCase):
|
||||
def test_workspaces(self):
|
||||
pl = Pl()
|
||||
with replace_attr(i3wm, 'conn', Args(get_workspaces=lambda: iter([
|
||||
@staticmethod
|
||||
def get_workspaces():
|
||||
return iter([
|
||||
{'name': '1: w1', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': False},
|
||||
{'name': '2: w2', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': True},
|
||||
{'name': '3: w3', 'output': 'HDMI1', 'focused': False, 'urgent': True, 'visible': True},
|
||||
{'name': '4: w4', 'output': 'DVI01', 'focused': True, 'urgent': True, 'visible': True},
|
||||
]))):
|
||||
self.assertEqual(i3wm.workspaces(pl=pl), [
|
||||
])
|
||||
|
||||
def test_workspaces(self):
|
||||
pl = Pl()
|
||||
with replace_attr(i3wm, 'get_i3_connection', lambda: Args(get_workspaces=self.get_workspaces)):
|
||||
segment_info = {}
|
||||
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info), [
|
||||
{'contents': '1: w1', 'highlight_groups': ['workspace']},
|
||||
{'contents': '2: w2', 'highlight_groups': ['w_visible', 'workspace']},
|
||||
{'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
|
||||
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
|
||||
])
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, only_show=None), [
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=None), [
|
||||
{'contents': '1: w1', 'highlight_groups': ['workspace']},
|
||||
{'contents': '2: w2', 'highlight_groups': ['w_visible', 'workspace']},
|
||||
{'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
|
||||
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
|
||||
])
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, only_show=['focused', 'urgent']), [
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['focused', 'urgent']), [
|
||||
{'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
|
||||
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
|
||||
])
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, only_show=['visible']), [
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible']), [
|
||||
{'contents': '2: w2', 'highlight_groups': ['w_visible', 'workspace']},
|
||||
{'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
|
||||
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
|
||||
])
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, only_show=['visible'], strip=3), [
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], strip=3), [
|
||||
{'contents': 'w2', 'highlight_groups': ['w_visible', 'workspace']},
|
||||
{'contents': 'w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
|
||||
{'contents': 'w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
|
||||
])
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, only_show=['focused', 'urgent'], output='DVI01'), [
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['focused', 'urgent'], output='DVI01'), [
|
||||
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
|
||||
])
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, only_show=['visible'], output='HDMI1'), [
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], output='HDMI1'), [
|
||||
{'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
|
||||
])
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, only_show=['visible'], strip=3, output='LVDS1'), [
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], strip=3, output='LVDS1'), [
|
||||
{'contents': 'w2', 'highlight_groups': ['w_visible', 'workspace']},
|
||||
])
|
||||
segment_info['output'] = 'LVDS1'
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], output='HDMI1'), [
|
||||
{'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
|
||||
])
|
||||
self.assertEqual(i3wm.workspaces(pl=pl, segment_info=segment_info, only_show=['visible'], strip=3), [
|
||||
{'contents': 'w2', 'highlight_groups': ['w_visible', 'workspace']},
|
||||
])
|
||||
|
||||
def test_workspace(self):
|
||||
pl = Pl()
|
||||
with replace_attr(i3wm, 'get_i3_connection', lambda: Args(get_workspaces=self.get_workspaces)):
|
||||
segment_info = {}
|
||||
|
||||
self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='1: w1'), [
|
||||
{'contents': '1: w1', 'highlight_groups': ['workspace']},
|
||||
])
|
||||
self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='3: w3', strip=True), [
|
||||
{'contents': 'w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
|
||||
])
|
||||
self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='9: w9'), None)
|
||||
self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info), [
|
||||
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
|
||||
])
|
||||
segment_info['workspace'] = next(self.get_workspaces())
|
||||
self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, workspace='4: w4'), [
|
||||
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
|
||||
])
|
||||
self.assertEqual(i3wm.workspace(pl=pl, segment_info=segment_info, strip=True), [
|
||||
{'contents': 'w1', 'highlight_groups': ['workspace']},
|
||||
])
|
||||
|
||||
def test_mode(self):
|
||||
pl = Pl()
|
||||
@ -934,6 +976,45 @@ class TestI3WM(TestCase):
|
||||
self.assertEqual(i3wm.mode(pl=pl, segment_info={'mode': 'default'}, names={'default': 'test'}), 'test')
|
||||
self.assertEqual(i3wm.mode(pl=pl, segment_info={'mode': 'test'}, names={'default': 'test', 'test': 't'}), 't')
|
||||
|
||||
def test_scratchpad(self):
|
||||
class Conn(object):
|
||||
def get_tree(self):
|
||||
return self
|
||||
|
||||
def descendents(self):
|
||||
nodes_unfocused = [Args(focused = False)]
|
||||
nodes_focused = [Args(focused = True)]
|
||||
|
||||
workspace_scratch = lambda: Args(name='__i3_scratch')
|
||||
workspace_noscratch = lambda: Args(name='2: www')
|
||||
return [
|
||||
Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused),
|
||||
Args(scratchpad_state='changed', urgent=True, workspace=workspace_noscratch, nodes=nodes_focused),
|
||||
Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_unfocused),
|
||||
Args(scratchpad_state=None, urgent=False, workspace=workspace_noscratch, nodes=nodes_unfocused),
|
||||
Args(scratchpad_state='fresh', urgent=False, workspace=workspace_scratch, nodes=nodes_focused),
|
||||
Args(scratchpad_state=None, urgent=True, workspace=workspace_noscratch, nodes=nodes_unfocused),
|
||||
]
|
||||
|
||||
pl = Pl()
|
||||
with replace_attr(i3wm, 'get_i3_connection', lambda: Conn()):
|
||||
self.assertEqual(i3wm.scratchpad(pl=pl), [
|
||||
{'contents': 'O', 'highlight_groups': ['scratchpad']},
|
||||
{'contents': 'X', 'highlight_groups': ['scratchpad:urgent', 'scratchpad:focused', 'scratchpad:visible', 'scratchpad']},
|
||||
{'contents': 'O', 'highlight_groups': ['scratchpad']},
|
||||
{'contents': 'X', 'highlight_groups': ['scratchpad:visible', 'scratchpad']},
|
||||
{'contents': 'O', 'highlight_groups': ['scratchpad:focused', 'scratchpad']},
|
||||
{'contents': 'X', 'highlight_groups': ['scratchpad:urgent', 'scratchpad:visible', 'scratchpad']},
|
||||
])
|
||||
self.assertEqual(i3wm.scratchpad(pl=pl, icons={'changed': '-', 'fresh': 'o'}), [
|
||||
{'contents': 'o', 'highlight_groups': ['scratchpad']},
|
||||
{'contents': '-', 'highlight_groups': ['scratchpad:urgent', 'scratchpad:focused', 'scratchpad:visible', 'scratchpad']},
|
||||
{'contents': 'o', 'highlight_groups': ['scratchpad']},
|
||||
{'contents': '-', 'highlight_groups': ['scratchpad:visible', 'scratchpad']},
|
||||
{'contents': 'o', 'highlight_groups': ['scratchpad:focused', 'scratchpad']},
|
||||
{'contents': '-', 'highlight_groups': ['scratchpad:urgent', 'scratchpad:visible', 'scratchpad']},
|
||||
])
|
||||
|
||||
|
||||
class TestMail(TestCommon):
|
||||
module_name = 'mail'
|
||||
|
@ -16,7 +16,7 @@ catch
|
||||
cquit
|
||||
endtry
|
||||
|
||||
if result isnot# '%1T%#Pl_247_10395294_236_3158064_NONE# 1 ./abc %2T2 ./def %#Pl_236_3158064_240_5789784_NONE# %3T%#Pl_250_12369084_240_5789784_NONE#3 ./%#Pl_231_16777215_240_5789784_bold#ghi %#Pl_240_5789784_236_3158064_NONE# %T%#Pl_231_16777215_236_3158064_NONE# %#Pl_252_13684944_236_3158064_NONE# %#Pl_235_2500134_252_13684944_bold# Tabs '
|
||||
if result isnot# '%1T%#Pl_247_10395294_236_3158064_NONE# 1 ./abc %#Pl_244_8421504_236_3158064_NONE# %2T%#Pl_247_10395294_236_3158064_NONE#2 ./def %#Pl_236_3158064_240_5789784_NONE# %3T%#Pl_250_12369084_240_5789784_NONE#3 ./%#Pl_231_16777215_240_5789784_bold#ghi %#Pl_240_5789784_236_3158064_NONE# %T%#Pl_231_16777215_236_3158064_NONE# %#Pl_252_13684944_236_3158064_NONE# %#Pl_235_2500134_252_13684944_bold# Tabs '
|
||||
call writefile(['Unexpected tabline', result], 'message.fail')
|
||||
cquit
|
||||
endif
|
||||
@ -30,7 +30,7 @@ catch
|
||||
cquit
|
||||
endtry
|
||||
|
||||
if result isnot# '%T%#Pl_247_10395294_236_3158064_NONE# 1 ./abc 2 ./def %#Pl_236_3158064_240_5789784_NONE# %#Pl_250_12369084_240_5789784_NONE#3 ./%#Pl_231_16777215_240_5789784_bold#ghi %#Pl_240_5789784_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE# %#Pl_252_13684944_236_3158064_NONE# %#Pl_235_2500134_252_13684944_bold# Bufs '
|
||||
if result isnot# '%T%#Pl_247_10395294_236_3158064_NONE# 1 ./abc %#Pl_244_8421504_236_3158064_NONE# %#Pl_247_10395294_236_3158064_NONE#2 ./def %#Pl_236_3158064_240_5789784_NONE# %#Pl_250_12369084_240_5789784_NONE#3 ./%#Pl_231_16777215_240_5789784_bold#ghi %#Pl_240_5789784_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE# %#Pl_252_13684944_236_3158064_NONE# %#Pl_235_2500134_252_13684944_bold# Bufs '
|
||||
call writefile(['Unexpected tabline (2)', result], 'message.fail')
|
||||
cquit
|
||||
endif
|
||||
@ -42,7 +42,7 @@ catch
|
||||
call writefile(['Exception while evaluating &tabline (3)', v:exception], 'message.fail')
|
||||
endtry
|
||||
|
||||
if result isnot# '%T%#Pl_247_10395294_236_3158064_NONE# 1 ./abc 2 ./def %#Pl_236_3158064_240_5789784_NONE# %#Pl_250_12369084_240_5789784_NONE#3 ./%#Pl_231_16777215_240_5789784_bold#ghi %#Pl_240_5789784_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE# %#Pl_252_13684944_236_3158064_NONE# %#Pl_235_2500134_252_13684944_bold# Bufs '
|
||||
if result isnot# '%T%#Pl_247_10395294_236_3158064_NONE# 1 ./abc %#Pl_244_8421504_236_3158064_NONE# %#Pl_247_10395294_236_3158064_NONE#2 ./def %#Pl_236_3158064_240_5789784_NONE# %#Pl_250_12369084_240_5789784_NONE#3 ./%#Pl_231_16777215_240_5789784_bold#ghi %#Pl_240_5789784_236_3158064_NONE# %#Pl_231_16777215_236_3158064_NONE# %#Pl_252_13684944_236_3158064_NONE# %#Pl_235_2500134_252_13684944_bold# Bufs '
|
||||
call writefile(['Unexpected tabline (3)', result], 'message.fail')
|
||||
cquit
|
||||
endif
|
||||
|
@ -265,6 +265,14 @@ def eval(expr):
|
||||
import os
|
||||
assert os.path.basename(current.buffer.name).startswith('NERD_tree_')
|
||||
return '/usr/include'
|
||||
elif expr.startswith('getbufvar('):
|
||||
import re
|
||||
match = re.match(r'^getbufvar\((\d+), ["\'](.+)["\']\)$', expr)
|
||||
if not match:
|
||||
raise NotImplementedError(expr)
|
||||
bufnr = int(match.group(1))
|
||||
varname = match.group(2)
|
||||
return _emul_getbufvar(bufnr, varname)
|
||||
elif expr == 'tabpagenr()':
|
||||
return current.tabpage.number
|
||||
elif expr == 'tabpagenr("$")':
|
||||
|
Loading…
x
Reference in New Issue
Block a user