Release 2.6

- Added support for new Vim modes.
- Added ability to control output padding.
- Added iTunes player segment.
- Added support for tmux development builds.
- Added a workaround for a fish bug sometimes occurring when using eval from
  config.fish (upstream status unknown).
- Added a workaround for tmux 2.4 bug: excessive CPU usage when having multiple
  panes (also fixed upstream).
- Fixed clean file status support in mercurial.
- Fixed error when battery capacity is zero and using DBus.
- Fixed mercurial command servers leakage.
- Refactored awesome bindings to use powerline daemon.
This commit is contained in:
Foo 2017-05-08 19:47:40 +03:00
commit c3261d4e57
136 changed files with 2159 additions and 1215 deletions

View File

@ -215,6 +215,13 @@ Common configuration is a subdictionary that is a value of ``ext`` key in
All components are enabled by default. All components are enabled by default.
.. _config-ext-update_interval:
``update_interval``
Determines how often WM status bars need to be updated, in seconds. Only
valid for WM extensions which use ``powerline-daemon``. Defaults to
2 seconds.
.. _config-colors: .. _config-colors:
Color definitions Color definitions
@ -361,6 +368,10 @@ ascii Theme without any unicode characters at all
is set in the local themes it will be ignored. This option may also be is set in the local themes it will be ignored. This option may also be
ignored in some bindings. ignored in some bindings.
``outer_padding``
Defines number of spaces at the end of output (on the right side) or at
the start of output (on the left side). Defaults to ``1``.
``dividers`` ``dividers``
Defines the dividers used in all Powerline extensions. Defines the dividers used in all Powerline extensions.
@ -391,7 +402,7 @@ ascii Theme without any unicode characters at all
:ref:`display <config-themes-seg-display>`. :ref:`display <config-themes-seg-display>`.
Key :ref:`args <config-themes-seg-args>` (only for function and Key :ref:`args <config-themes-seg-args>` (only for function and
segments_list segments) is handled specially: unlike other values it is segment_list segments) is handled specially: unlike other values it is
merged with all other values, except that a single ``{module}.{function}`` merged with all other values, except that a single ``{module}.{function}``
key if found prevents merging all ``{function}`` values. key if found prevents merging all ``{function}`` values.
@ -428,7 +439,7 @@ ascii Theme without any unicode characters at all
``type`` ``type``
The segment type. Can be one of ``function`` (default), ``string`` or The segment type. Can be one of ``function`` (default), ``string`` or
``segments_list``: ``segment_list``:
``function`` ``function``
The segment contents is the return value of the function defined in The segment contents is the return value of the function defined in
@ -443,7 +454,7 @@ ascii Theme without any unicode characters at all
highlighting group is defined in the :ref:`highlight_groups option highlighting group is defined in the :ref:`highlight_groups option
<config-themes-seg-highlight_groups>`. <config-themes-seg-highlight_groups>`.
``segments_list`` ``segment_list``
Sub-list of segments. This list only allows :ref:`function Sub-list of segments. This list only allows :ref:`function
<config-themes-seg-function>`, :ref:`segments <config-themes-seg-function>`, :ref:`segments
<config-themes-seg-segments>` and :ref:`args <config-themes-seg-segments>` and :ref:`args
@ -458,7 +469,7 @@ ascii Theme without any unicode characters at all
Segment name. If present allows referring to this segment in Segment name. If present allows referring to this segment in
:ref:`segment_data <config-themes-segment_data>` dictionary by this :ref:`segment_data <config-themes-segment_data>` dictionary by this
name. If not ``string`` segments may not be referred there at all and name. If not ``string`` segments may not be referred there at all and
``function`` and ``segments_list`` segments may be referred there using ``function`` and ``segment_list`` segments may be referred there using
either ``{module}.{function_name}`` or ``{function_name}``, whichever either ``{module}.{function_name}`` or ``{function_name}``, whichever
will be found first. Function name is taken from :ref:`function key will be found first. Function name is taken from :ref:`function key
<config-themes-seg-function>`. <config-themes-seg-function>`.

View File

@ -30,7 +30,7 @@ Generic requirements
with bazaar repositories. with bazaar repositories.
* ``pyuv`` python package. Required for :ref:`libuv-based watcher * ``pyuv`` python package. Required for :ref:`libuv-based watcher
<config-common-watcher>` to work. <config-common-watcher>` to work.
* ``i3-ipc`` python package. Required for i3wm bindings and segments. * ``i3ipc`` python package. Required for i3wm bindings and segments.
* ``xrandr`` program. Required for the multi-monitor lemonbar binding and the * ``xrandr`` program. Required for the multi-monitor lemonbar binding and the
:py:func:`powerline.listers.i3wm.output_lister`. :py:func:`powerline.listers.i3wm.output_lister`.

View File

@ -111,7 +111,7 @@ following in ``~/.profile``:
.. code-block:: bash .. code-block:: bash
if test "x$0" != "x${0#dash}" ; then if test "$0" != "${0#dash}" ; then
export ENV={repository_root}/powerline/bindings/shell/powerline.sh export ENV={repository_root}/powerline/bindings/shell/powerline.sh
fi fi

View File

@ -419,6 +419,11 @@ def _get_log_keys(common_config):
)) ))
DEFAULT_UPDATE_INTERVAL = 2
'''Default value for :ref:`update_interval <config-ext-update_interval>`
'''
class Powerline(object): class Powerline(object):
'''Main powerline class, entrance point for all powerline uses. Sets '''Main powerline class, entrance point for all powerline uses. Sets
powerline up and loads the configuration. powerline up and loads the configuration.
@ -514,6 +519,7 @@ class Powerline(object):
self.setup_args = () self.setup_args = ()
self.setup_kwargs = {} self.setup_kwargs = {}
self.imported_modules = set() self.imported_modules = set()
self.update_interval = DEFAULT_UPDATE_INTERVAL
get_encoding = staticmethod(get_preferred_output_encoding) get_encoding = staticmethod(get_preferred_output_encoding)
'''Get encoding used by the current application '''Get encoding used by the current application
@ -638,6 +644,7 @@ class Powerline(object):
or self.ext_config.get('local_themes') != self.prev_ext_config.get('local_themes') or self.ext_config.get('local_themes') != self.prev_ext_config.get('local_themes')
): ):
self.renderer_options['local_themes'] = self.get_local_themes(self.ext_config.get('local_themes')) self.renderer_options['local_themes'] = self.get_local_themes(self.ext_config.get('local_themes'))
self.update_interval = self.ext_config.get('update_interval', 2)
load_colorscheme = ( load_colorscheme = (
load_colorscheme load_colorscheme
or not self.prev_ext_config or not self.prev_ext_config

View File

@ -4,38 +4,17 @@ from __future__ import (unicode_literals, division, absolute_import, print_funct
import sys import sys
from time import sleep from powerline.bindings.wm import DEFAULT_UPDATE_INTERVAL
from subprocess import Popen, PIPE from powerline.bindings.wm.awesome import run
from powerline import Powerline
from powerline.lib.monotonic import monotonic
powerline = Powerline('wm', renderer_module='pango_markup')
powerline.update_renderer()
try:
interval = float(sys.argv[1])
except IndexError:
interval = 2
def read_to_log(pl, client): def main():
for line in client.stdout: try:
if line: interval = float(sys.argv[1])
pl.info(line, prefix='awesome-client') except IndexError:
for line in client.stderr: interval = DEFAULT_UPDATE_INTERVAL
if line: run(interval=interval)
pl.error(line, prefix='awesome-client')
if client.wait():
pl.error('Client exited with {0}', client.returncode, prefix='awesome')
while True: if __name__ == '__main__':
start_time = monotonic() main()
s = powerline.render(side='right')
request = 'powerline_widget:set_markup(\'' + s.replace('\\', '\\\\').replace('\'', '\\\'') + '\')\n'
client = Popen(['awesome-client'], shell=False, stdout=PIPE, stderr=PIPE, stdin=PIPE)
client.stdin.write(request.encode('utf-8'))
client.stdin.close()
read_to_log(powerline.pl, client)
sleep(max(interval - (monotonic() - start_time), 0.1))

View File

@ -6,6 +6,5 @@ powerline_widget:set_align('right')
function powerline(mode, widget) end function powerline(mode, widget) end
bindings_path = string.gsub(debug.getinfo(1).source:match('@(.*)$'), '/[^/]+$', '') awful.util.spawn_with_shell('powerline-daemon -q')
powerline_cmd = bindings_path .. '/powerline-awesome.py' awful.util.spawn_with_shell('powerline wm.awesome')
awful.util.spawn_with_shell('ps -C powerline-awesome.py || ' .. powerline_cmd)

View File

@ -11,6 +11,7 @@ from argparse import ArgumentParser
from powerline.lemonbar import LemonbarPowerline from powerline.lemonbar import LemonbarPowerline
from powerline.lib.encoding import get_unicode_writer from powerline.lib.encoding import get_unicode_writer
from powerline.bindings.wm import DEFAULT_UPDATE_INTERVAL
if __name__ == '__main__': if __name__ == '__main__':
@ -29,7 +30,7 @@ if __name__ == '__main__':
def render(reschedule=False): def render(reschedule=False):
if reschedule: if reschedule:
Timer(0.5, render, kwargs={'reschedule': True}).start() Timer(DEFAULT_UPDATE_INTERVAL, render, kwargs={'reschedule': True}).start()
global lock global lock
with lock: with lock:

View File

@ -21,7 +21,7 @@ _powerline_tmux_setenv() {
} }
_powerline_tmux_set_pwd() { _powerline_tmux_set_pwd() {
if test "x$_POWERLINE_SAVED_PWD" != "x$PWD" ; then if test "$_POWERLINE_SAVED_PWD" != "$PWD" ; then
_POWERLINE_SAVED_PWD="$PWD" _POWERLINE_SAVED_PWD="$PWD"
_powerline_tmux_setenv PWD "$PWD" _powerline_tmux_setenv PWD "$PWD"
fi fi
@ -39,8 +39,8 @@ _powerline_init_tmux_support() {
trap '_powerline_tmux_set_columns' WINCH trap '_powerline_tmux_set_columns' WINCH
_powerline_tmux_set_columns _powerline_tmux_set_columns
test "x$PROMPT_COMMAND" != "x${PROMPT_COMMAND/_powerline_tmux_set_pwd}" || test "$PROMPT_COMMAND" != "${PROMPT_COMMAND/_powerline_tmux_set_pwd}" \
PROMPT_COMMAND="${PROMPT_COMMAND}"$'\n_powerline_tmux_set_pwd' || PROMPT_COMMAND="${PROMPT_COMMAND}"$'\n_powerline_tmux_set_pwd'
fi fi
} }
@ -82,8 +82,8 @@ _powerline_setup_prompt() {
if test -z "${POWERLINE_COMMAND}" ; then if test -z "${POWERLINE_COMMAND}" ; then
POWERLINE_COMMAND="$("$POWERLINE_CONFIG_COMMAND" shell command)" POWERLINE_COMMAND="$("$POWERLINE_CONFIG_COMMAND" shell command)"
fi fi
test "x$PROMPT_COMMAND" != "x${PROMPT_COMMAND%_powerline_set_prompt*}" || test "$PROMPT_COMMAND" != "${PROMPT_COMMAND%_powerline_set_prompt*}" \
PROMPT_COMMAND=$'_powerline_set_prompt\n'"${PROMPT_COMMAND}" || PROMPT_COMMAND=$'_powerline_set_prompt\n'"${PROMPT_COMMAND}"
PS2="$(_powerline_local_prompt left -r.bash 0 0 continuation)" PS2="$(_powerline_local_prompt left -r.bash 0 0 continuation)"
PS3="$(_powerline_local_prompt left '' 0 0 select)" PS3="$(_powerline_local_prompt left '' 0 0 select)"
} }

View File

@ -99,7 +99,7 @@ class EmptyArgs(object):
def init_tmux_environment(pl, args, set_tmux_environment=set_tmux_environment): def init_tmux_environment(pl, args, set_tmux_environment=set_tmux_environment):
'''Initialize tmux environment from tmux configuration '''Initialize tmux environment from tmux configuration
''' '''
powerline = ShellPowerline(finish_args(os.environ, EmptyArgs('tmux', args.config_path))) powerline = ShellPowerline(finish_args(None, os.environ, EmptyArgs('tmux', args.config_path)))
# TODO Move configuration files loading out of Powerline object and use it # TODO Move configuration files loading out of Powerline object and use it
# directly # directly
powerline.update_renderer() powerline.update_renderer()

View File

@ -34,7 +34,7 @@ function powerline-setup
set -g POWERLINE_COMMAND (env $POWERLINE_CONFIG_COMMAND shell command) set -g POWERLINE_COMMAND (env $POWERLINE_CONFIG_COMMAND shell command)
end end
function _powerline_set_default_mode --on-variable fish_key_bindings function _powerline_set_default_mode --on-variable fish_key_bindings
if test x$fish_key_bindings != xfish_vi_key_bindings if test $fish_key_bindings != fish_vi_key_bindings
set -g _POWERLINE_DEFAULT_MODE default set -g _POWERLINE_DEFAULT_MODE default
else else
set -g -e _POWERLINE_DEFAULT_MODE set -g -e _POWERLINE_DEFAULT_MODE
@ -62,7 +62,7 @@ function powerline-setup
set rpromptpast set rpromptpast
set columnsexpr '(_powerline_columns)' set columnsexpr '(_powerline_columns)'
end end
eval " echo "
function fish_prompt function fish_prompt
env \$POWERLINE_COMMAND $POWERLINE_COMMAND_ARGS shell $promptside $addargs env \$POWERLINE_COMMAND $POWERLINE_COMMAND_ARGS shell $promptside $addargs
end end
@ -73,7 +73,7 @@ function powerline-setup
function _powerline_set_columns --on-signal WINCH function _powerline_set_columns --on-signal WINCH
set -g _POWERLINE_COLUMNS $columnsexpr set -g _POWERLINE_COLUMNS $columnsexpr
end end
" " | source
_powerline_set_columns _powerline_set_columns
end end
_powerline_set_default_mode _powerline_set_default_mode

View File

@ -37,7 +37,7 @@ fn _powerline_common_setup {
} }
fn _powerline_tmux_pane { fn _powerline_tmux_pane {
if (test x$TMUX_PANE '!=' x) { if (test -n $TMUX_PANE) {
echo $TMUX_PANE | tr -d ' %' echo $TMUX_PANE | tr -d ' %'
} else { } else {
TMUX=$_POWERLINE_TMUX tmux display -p '#D' | tr -d ' %' TMUX=$_POWERLINE_TMUX tmux display -p '#D' | tr -d ' %'
@ -54,9 +54,9 @@ if (test -z $POWERLINE_CONFIG_COMMAND) {
echo powerline-config executable not found, unable to proceed >[2=1] echo powerline-config executable not found, unable to proceed >[2=1]
} }
} }
if (test x$POWERLINE_CONFIG_COMMAND '!=' x) { if (test -n $POWERLINE_CONFIG_COMMAND) {
if ($POWERLINE_CONFIG_COMMAND shell --shell rcsh uses prompt) { if ($POWERLINE_CONFIG_COMMAND shell --shell rcsh uses prompt) {
if (test x$POWERLINE_COMMAND_ARGS '!=' x) { if (test -n $POWERLINE_COMMAND_ARGS) {
# Perform splitting # Perform splitting
POWERLINE_COMMAND_ARGS=( `{echo $POWERLINE_COMMAND_ARGS} ) POWERLINE_COMMAND_ARGS=( `{echo $POWERLINE_COMMAND_ARGS} )
} }
@ -75,11 +75,11 @@ if (test x$POWERLINE_CONFIG_COMMAND '!=' x) {
} }
_powerline_common_setup _powerline_common_setup
} }
if (test x$TMUX '!=' x) { if (test -n $TMUX) {
if ($POWERLINE_CONFIG_COMMAND shell --shell rcsh uses tmux) { if ($POWERLINE_CONFIG_COMMAND shell --shell rcsh uses tmux) {
_POWERLINE_TMUX=$TMUX _POWERLINE_TMUX=$TMUX
fn _powerline_tmux_setenv { fn _powerline_tmux_setenv {
if (test x$2 '!=' x) { if (test -n $2) {
TMUX=$_POWERLINE_TMUX tmux setenv -g TMUX_$1^_`{ TMUX=$_POWERLINE_TMUX tmux setenv -g TMUX_$1^_`{
_powerline_tmux_pane _powerline_tmux_pane
} $2 } $2

View File

@ -115,7 +115,7 @@ _powerline_tmux_setenv() {
} }
_powerline_tmux_set_pwd() { _powerline_tmux_set_pwd() {
if test "x$_POWERLINE_SAVED_PWD" != "x$PWD" ; then if test "$_POWERLINE_SAVED_PWD" != "$PWD" ; then
_POWERLINE_SAVED_PWD="$PWD" _POWERLINE_SAVED_PWD="$PWD"
_powerline_tmux_setenv PWD "$PWD" _powerline_tmux_setenv PWD "$PWD"
fi fi

View File

@ -76,6 +76,8 @@ def get_tmux_version(pl):
version_string = get_tmux_output(pl, '-V') version_string = get_tmux_output(pl, '-V')
_, version_string = version_string.split(' ') _, version_string = version_string.split(' ')
version_string = version_string.strip() version_string = version_string.strip()
if version_string == 'master':
return TmuxVersionInfo(float('inf'), 0, version_string)
major, minor = version_string.split('.') major, minor = version_string.split('.')
suffix = DIGITS.subn('', minor)[0] or None suffix = DIGITS.subn('', minor)[0] or None
minor = NON_DIGITS.subn('', minor)[0] minor = NON_DIGITS.subn('', minor)[0]

View File

@ -1,11 +1,11 @@
set -g status on set -g status on
set -g status-interval 2 set -g status-interval 2
set -g status-left-length 20 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"`\")' set -g status-right '#(env "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS tmux right -R pane_id=\"`tmux display -p "#""D"`\")'
set -g status-right-length 150 set -g status-right-length 150
set -g window-status-format "#[$_POWERLINE_WINDOW_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER_SPACES#I#F #[$_POWERLINE_WINDOW_DIVIDER_COLOR]$_POWERLINE_LEFT_SOFT_DIVIDER#[default]#W $_POWERLINE_LEFT_HARD_DIVIDER_SPACES" set -g window-status-format "#[$_POWERLINE_WINDOW_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER_SPACES#I#F #[$_POWERLINE_WINDOW_DIVIDER_COLOR]$_POWERLINE_LEFT_SOFT_DIVIDER#[default]#W $_POWERLINE_LEFT_HARD_DIVIDER_SPACES"
set -g window-status-current-format "#[$_POWERLINE_WINDOW_CURRENT_HARD_DIVIDER_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER#[$_POWERLINE_WINDOW_CURRENT_COLOR]#I#F $_POWERLINE_LEFT_SOFT_DIVIDER#[$_POWERLINE_WINDOW_NAME_COLOR]#W #[$_POWERLINE_WINDOW_CURRENT_HARD_DIVIDER_NEXT_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER" set -g window-status-current-format "#[$_POWERLINE_WINDOW_CURRENT_HARD_DIVIDER_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER#[$_POWERLINE_WINDOW_CURRENT_COLOR]#I#F $_POWERLINE_LEFT_SOFT_DIVIDER#[$_POWERLINE_WINDOW_NAME_COLOR]#W #[$_POWERLINE_WINDOW_CURRENT_HARD_DIVIDER_NEXT_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER"
# Legacy status-left definition to be overwritten for tmux Versions 1.8+ # Legacy status-left definition to be overwritten for tmux Versions 1.8+
set -g status-left "#[$_POWERLINE_SESSION_COLOR] #S #[$_POWERLINE_SESSION_HARD_DIVIDER_NEXT_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER#(env \"\$POWERLINE_COMMAND\" tmux left -R pane_id=\"`tmux display -p '#D'`\")" set -g status-left "#[$_POWERLINE_SESSION_COLOR] #S #[$_POWERLINE_SESSION_HARD_DIVIDER_NEXT_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER#(env \"\$POWERLINE_COMMAND\" tmux left -R pane_id=\"`tmux display -p '#''D'`\")"
# vim: ft=tmux # vim: ft=tmux

View File

@ -1,3 +1,3 @@
set -g status-right '#(env "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS tmux right -R pane_id="`tmux display -p "#D"`" --width=`tmux display -p "#{client_width}"` -R width_adjust=`tmux show-options -g status-left-length | cut -d" " -f 2`)' set -g status-right '#(env "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS tmux right -R pane_id="`tmux display -p "#""D"`" --width=`tmux display -p "#""{client_width}"` -R width_adjust=`tmux show-options -g status-left-length | cut -d" " -f 2`)'
set -g status-left "#[$_POWERLINE_SESSION_COLOR] #S #[$_POWERLINE_SESSION_HARD_DIVIDER_NEXT_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER#(env \"\$POWERLINE_COMMAND\" tmux left --width=`tmux display -p '#{client_width}'` -R width_adjust=`tmux show-options -g status-right-length | cut -d' ' -f2` -R pane_id=\"`tmux display -p '#D'`\")" set -g status-left "#[$_POWERLINE_SESSION_COLOR] #S #[$_POWERLINE_SESSION_HARD_DIVIDER_NEXT_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER#(env \"\$POWERLINE_COMMAND\" tmux left --width=`tmux display -p '#''{client_width}'` -R width_adjust=`tmux show-options -g status-right-length | cut -d' ' -f2` -R pane_id=\"`tmux display -p '#''D'`\")"
# vim: ft=tmux # vim: ft=tmux

View File

@ -1,5 +1,5 @@
# powerline_tmux_1.8_plus.conf # powerline_tmux_1.8_plus.conf
# tmux Version 1.8 introduces the 'client_prefix' format variable, applicable # tmux Version 1.8 introduces the 'client_prefix' format variable, applicable
# for versions 1.8+ # for versions 1.8+
set -qg status-left "#{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_FG]#[bg=$_POWERLINE_SESSION_PREFIX_BG]#[$_POWERLINE_SESSION_PREFIX_ATTR],#[fg=$_POWERLINE_SESSION_FG]#[bg=$_POWERLINE_SESSION_BG]#[$_POWERLINE_SESSION_ATTR]} #S #{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_BG],#[fg=$_POWERLINE_SESSION_BG]}#[bg=$_POWERLINE_BACKGROUND_BG]#[nobold]$_POWERLINE_LEFT_HARD_DIVIDER#(env \$POWERLINE_COMMAND \$POWERLINE_COMMAND_ARGS tmux left --width=`tmux display -p '#{client_width}'` -R width_adjust=`tmux show-options -g status-right-length | cut -d' ' -f2` -R pane_id=\"`tmux display -p '#D'`\")" set -qg status-left "#{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_FG]#[bg=$_POWERLINE_SESSION_PREFIX_BG]#[$_POWERLINE_SESSION_PREFIX_ATTR],#[fg=$_POWERLINE_SESSION_FG]#[bg=$_POWERLINE_SESSION_BG]#[$_POWERLINE_SESSION_ATTR]} #S #{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_BG],#[fg=$_POWERLINE_SESSION_BG]}#[bg=$_POWERLINE_BACKGROUND_BG]#[nobold]$_POWERLINE_LEFT_HARD_DIVIDER#(env \$POWERLINE_COMMAND \$POWERLINE_COMMAND_ARGS tmux left --width=`tmux display -p '#''{client_width}'` -R width_adjust=`tmux show-options -g status-right-length | cut -d' ' -f2` -R pane_id=\"`tmux display -p '#''D'`\")"
# vim: ft=tmux # vim: ft=tmux

View File

@ -1,2 +1,3 @@
# Starting from tmux-2.1 escaping of dollar signs inside #() is harmful # Starting from tmux-2.1 escaping of dollar signs inside #() is harmful
set -qg status-left "#{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_FG]#[bg=$_POWERLINE_SESSION_PREFIX_BG]#[$_POWERLINE_SESSION_PREFIX_ATTR],#[fg=$_POWERLINE_SESSION_FG]#[bg=$_POWERLINE_SESSION_BG]#[$_POWERLINE_SESSION_ATTR]} #S #{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_BG],#[fg=$_POWERLINE_SESSION_BG]}#[bg=$_POWERLINE_BACKGROUND_BG]#[nobold]$_POWERLINE_LEFT_HARD_DIVIDER#(env $POWERLINE_COMMAND $POWERLINE_COMMAND_ARGS tmux left --width=`tmux display -p '#{client_width}'` -R width_adjust=`tmux show-options -g status-right-length | cut -d' ' -f2` -R pane_id=\"`tmux display -p '#D'`\")" set -qg status-left "#{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_FG]#[bg=$_POWERLINE_SESSION_PREFIX_BG]#[$_POWERLINE_SESSION_PREFIX_ATTR],#[fg=$_POWERLINE_SESSION_FG]#[bg=$_POWERLINE_SESSION_BG]#[$_POWERLINE_SESSION_ATTR]} #S #{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_BG],#[fg=$_POWERLINE_SESSION_BG]}#[bg=$_POWERLINE_BACKGROUND_BG]#[nobold]$_POWERLINE_LEFT_HARD_DIVIDER#(env $POWERLINE_COMMAND $POWERLINE_COMMAND_ARGS tmux left --width=`tmux display -p '#''{client_width}'` -R width_adjust=`tmux show-options -g status-right-length | cut -d' ' -f2` -R pane_id=\"`tmux display -p '#''D'`\")"
set -g window-status-format "#[$_POWERLINE_WINDOW_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER_SPACES#I#{?window_flags,#F, } #[$_POWERLINE_WINDOW_DIVIDER_COLOR]$_POWERLINE_LEFT_SOFT_DIVIDER#[default]#W $_POWERLINE_LEFT_HARD_DIVIDER_SPACES"

View File

@ -5,6 +5,10 @@ import re
from powerline.theme import requires_segment_info from powerline.theme import requires_segment_info
from powerline.lib.shell import run_cmd from powerline.lib.shell import run_cmd
from powerline.bindings.wm.awesome import AwesomeThread
DEFAULT_UPDATE_INTERVAL = 0.5
conn = None conn = None
@ -36,3 +40,8 @@ def get_connected_xrandr_outputs(pl):
return (match.groupdict() for match in XRANDR_OUTPUT_RE.finditer( return (match.groupdict() for match in XRANDR_OUTPUT_RE.finditer(
run_cmd(pl, ['xrandr', '-q']) run_cmd(pl, ['xrandr', '-q'])
)) ))
wm_threads = {
'awesome': AwesomeThread,
}

View File

@ -0,0 +1,59 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import sys
from threading import Thread, Event
from time import sleep
from subprocess import Popen, PIPE
from powerline import Powerline
from powerline.lib.monotonic import monotonic
def read_to_log(pl, client):
for line in client.stdout:
if line:
pl.info(line, prefix='awesome-client')
for line in client.stderr:
if line:
pl.error(line, prefix='awesome-client')
if client.wait():
pl.error('Client exited with {0}', client.returncode, prefix='awesome')
def run(thread_shutdown_event=None, pl_shutdown_event=None, pl_config_loader=None,
interval=None):
powerline = Powerline(
'wm',
renderer_module='pango_markup',
shutdown_event=pl_shutdown_event,
config_loader=pl_config_loader,
)
powerline.update_renderer()
if not thread_shutdown_event:
thread_shutdown_event = powerline.shutdown_event
while not thread_shutdown_event.is_set():
# powerline.update_interval may change over time
used_interval = interval or powerline.update_interval
start_time = monotonic()
s = powerline.render(side='right')
request = 'powerline_widget:set_markup(\'' + s.translate({'\'': '\\\'', '\\': '\\\\'}) + '\')\n'
client = Popen(['awesome-client'], shell=False, stdout=PIPE, stderr=PIPE, stdin=PIPE)
client.stdin.write(request.encode('utf-8'))
client.stdin.close()
read_to_log(powerline.pl, client)
thread_shutdown_event.wait(max(used_interval - (monotonic() - start_time), 0.1))
class AwesomeThread(Thread):
__slots__ = ('powerline_shutdown_event',)
def __init__(self, **kwargs):
super(AwesomeThread, self).__init__()
self.powerline_run_kwargs = kwargs
def run(self):
run(**self.powerline_run_kwargs)

View File

@ -111,7 +111,7 @@ if hasattr(zsh, 'expand') and zsh.expand('${:-}') == '':
zsh_expand = zsh.expand zsh_expand = zsh.expand
else: else:
def zsh_expand(s): def zsh_expand(s):
zsh.eval('_POWERLINE_REPLY="' + s + '"') zsh.eval('local _POWERLINE_REPLY="' + s + '"')
ret = zsh.getvalue('_POWERLINE_REPLY') ret = zsh.getvalue('_POWERLINE_REPLY')
zsh.setvalue('_POWERLINE_REPLY', None) zsh.setvalue('_POWERLINE_REPLY', None)
return ret return ret

View File

@ -25,6 +25,11 @@ _powerline_tmux_pane() {
echo "${TMUX_PANE:-`tmux display -p "#D"`}" | tr -d ' %' echo "${TMUX_PANE:-`tmux display -p "#D"`}" | tr -d ' %'
} }
_powerline_tmux_pane() {
local -x TMUX="$_POWERLINE_TMUX"
echo "${TMUX_PANE:-`tmux display -p "#D"`}" | tr -d ' %'
}
_powerline_init_tmux_support() { _powerline_init_tmux_support() {
emulate -L zsh emulate -L zsh
if test -n "$TMUX" && tmux refresh -S &>/dev/null ; then if test -n "$TMUX" && tmux refresh -S &>/dev/null ; then

View File

@ -11,6 +11,7 @@ from powerline.lib.overrides import parsedotval, parse_override_var
from powerline.lib.dict import mergeargs from powerline.lib.dict import mergeargs
from powerline.lib.encoding import get_preferred_arguments_encoding from powerline.lib.encoding import get_preferred_arguments_encoding
from powerline.lib.unicode import u, unicode from powerline.lib.unicode import u, unicode
from powerline.bindings.wm import wm_threads
if sys.version_info < (3,): if sys.version_info < (3,):
@ -23,7 +24,7 @@ else:
return s return s
def finish_args(environ, args): def finish_args(parser, environ, args, is_daemon=False):
'''Do some final transformations '''Do some final transformations
Transforms ``*_override`` arguments into dictionaries, adding overrides from Transforms ``*_override`` arguments into dictionaries, adding overrides from
@ -61,7 +62,13 @@ def finish_args(environ, args):
[path for path in environ.get('POWERLINE_CONFIG_PATHS', '').split(':') if path] [path for path in environ.get('POWERLINE_CONFIG_PATHS', '').split(':') if path]
+ (args.config_path or []) + (args.config_path or [])
) )
args.side = args.side[0] if args.ext[0].startswith('wm.'):
if not is_daemon:
parser.error('WM bindings must be used with daemon only')
elif args.ext[0][3:] not in wm_threads:
parser.error('WM binding not found')
elif not args.side:
parser.error('expected one argument')
return args return args
@ -77,15 +84,16 @@ def get_argparser(ArgumentParser=argparse.ArgumentParser):
parser.add_argument( parser.add_argument(
'ext', nargs=1, 'ext', nargs=1,
help='Extension: application for which powerline command is launched ' help='Extension: application for which powerline command is launched '
'(usually `shell\' or `tmux\').' '(usually `shell\' or `tmux\'). Also supports `wm.\' extensions: '
+ ', '.join(('`wm.' + key + '\'' for key in wm_threads.keys())) + '.'
) )
parser.add_argument( parser.add_argument(
'side', nargs=1, choices=('left', 'right', 'above', 'aboveleft'), 'side', nargs='?', choices=('left', 'right', 'above', 'aboveleft'),
help='Side: `left\' and `right\' represent left and right side ' help='Side: `left\' and `right\' represent left and right side '
'respectively, `above\' emits lines that are supposed to be printed ' 'respectively, `above\' emits lines that are supposed to be printed '
'just above the prompt and `aboveleft\' is like concatenating ' 'just above the prompt and `aboveleft\' is like concatenating '
'`above\' with `left\' with the exception that only one Python ' '`above\' with `left\' with the exception that only one Python '
'instance is used in this case.' 'instance is used in this case. May be omitted for `wm.*\' extensions.'
) )
parser.add_argument( parser.add_argument(
'-r', '--renderer-module', metavar='MODULE', type=str, '-r', '--renderer-module', metavar='MODULE', type=str,

View File

@ -76,6 +76,50 @@
"branch:divider": { "fg": "darkcyan", "bg": "darkblue", "attrs": [] } "branch:divider": { "fg": "darkcyan", "bg": "darkblue", "attrs": [] }
} }
}, },
"ic": {
"colors": {
"gray0": "darkestblue",
"gray1": "darkestblue",
"gray2": "darkestblue",
"gray3": "darkblue",
"gray4": "darkblue",
"gray5": "darkestcyan",
"gray6": "darkestcyan",
"gray7": "darkestcyan",
"gray8": "mediumcyan",
"gray9": "mediumcyan",
"gray10": "mediumcyan",
"green_yellow_red": "gray5",
"dark_green_gray": "light_green_gray"
},
"groups": {
"mode": { "fg": "darkestcyan", "bg": "white", "attrs": ["bold"] },
"background:divider": { "fg": "darkcyan", "bg": "darkestblue", "attrs": [] },
"branch:divider": { "fg": "darkcyan", "bg": "darkblue", "attrs": [] }
}
},
"ix": {
"colors": {
"gray0": "darkestblue",
"gray1": "darkestblue",
"gray2": "darkestblue",
"gray3": "darkblue",
"gray4": "darkblue",
"gray5": "darkestcyan",
"gray6": "darkestcyan",
"gray7": "darkestcyan",
"gray8": "mediumcyan",
"gray9": "mediumcyan",
"gray10": "mediumcyan",
"green_yellow_red": "gray5",
"dark_green_gray": "light_green_gray"
},
"groups": {
"mode": { "fg": "darkestcyan", "bg": "white", "attrs": ["bold"] },
"background:divider": { "fg": "darkcyan", "bg": "darkestblue", "attrs": [] },
"branch:divider": { "fg": "darkcyan", "bg": "darkblue", "attrs": [] }
}
},
"v": { "v": {
"groups": { "groups": {
"mode": { "fg": "darkorange", "bg": "brightestorange", "attrs": ["bold"] } "mode": { "fg": "darkorange", "bg": "brightestorange", "attrs": ["bold"] }
@ -95,6 +139,16 @@
"groups": { "groups": {
"mode": { "fg": "white", "bg": "brightred", "attrs": ["bold"] } "mode": { "fg": "white", "bg": "brightred", "attrs": ["bold"] }
} }
},
"Rc": {
"groups": {
"mode": { "fg": "white", "bg": "brightred", "attrs": ["bold"] }
}
},
"Rx": {
"groups": {
"mode": { "fg": "white", "bg": "brightred", "attrs": ["bold"] }
}
} }
} }
} }

View File

@ -73,6 +73,20 @@
"col_current": { "fg": "solarized:base0", "bg": "solarized:base3", "attrs": [] } "col_current": { "fg": "solarized:base0", "bg": "solarized:base3", "attrs": [] }
} }
}, },
"ic": {
"groups": {
"background": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": [] },
"background:divider": { "fg": "solarized:base2", "bg": "solarized:base01", "attrs": [] },
"mode": { "fg": "solarized:base3", "bg": "solarized:blue", "attrs": ["bold"] }
}
},
"ix": {
"groups": {
"background": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": [] },
"background:divider": { "fg": "solarized:base2", "bg": "solarized:base01", "attrs": [] },
"mode": { "fg": "solarized:base3", "bg": "solarized:blue", "attrs": ["bold"] }
}
},
"v": { "v": {
"groups": { "groups": {
"mode": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] } "mode": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] }
@ -92,6 +106,16 @@
"groups": { "groups": {
"mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] } "mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] }
} }
},
"Rc": {
"groups": {
"mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] }
}
},
"Rx": {
"groups": {
"mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] }
}
} }
} }
} }

View File

@ -74,6 +74,20 @@
"col_current": { "fg": "solarized:base00", "bg": "solarized:base03", "attrs": [] } "col_current": { "fg": "solarized:base00", "bg": "solarized:base03", "attrs": [] }
} }
}, },
"ic": {
"groups": {
"background": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] },
"background:divider": { "fg": "solarized:base02", "bg": "solarized:base2", "attrs": [] },
"mode": { "fg": "solarized:base3", "bg": "solarized:blue", "attrs": ["bold"] }
}
},
"ix": {
"groups": {
"background": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] },
"background:divider": { "fg": "solarized:base02", "bg": "solarized:base2", "attrs": [] },
"mode": { "fg": "solarized:base3", "bg": "solarized:blue", "attrs": ["bold"] }
}
},
"v": { "v": {
"groups": { "groups": {
"mode": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] } "mode": { "fg": "solarized:base3", "bg": "solarized:orange", "attrs": ["bold"] }
@ -93,6 +107,16 @@
"groups": { "groups": {
"mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] } "mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] }
} }
},
"Rc": {
"groups": {
"mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] }
}
},
"Rx": {
"groups": {
"mode": { "fg": "solarized:base3", "bg": "solarized:red", "attrs": ["bold"] }
}
} }
} }
} }

View File

@ -46,7 +46,8 @@
}, },
"wm": { "wm": {
"colorscheme": "default", "colorscheme": "default",
"theme": "default" "theme": "default",
"update_interval": 2
} }
} }
} }

View File

@ -105,8 +105,12 @@
"S": "S-LINE", "S": "S-LINE",
"^S": "S-BLCK", "^S": "S-BLCK",
"i": "INSERT", "i": "INSERT",
"ic": "I-COMP",
"ix": "I-C_X ",
"R": "RPLACE", "R": "RPLACE",
"Rv": "V-RPLC", "Rv": "V-RPLC",
"Rc": "R-COMP",
"Rx": "R-C_X ",
"c": "COMMND", "c": "COMMND",
"cv": "VIM-EX", "cv": "VIM-EX",
"ce": "NRM-EX", "ce": "NRM-EX",

View File

@ -103,8 +103,12 @@
"S": "S·LINE", "S": "S·LINE",
"^S": "S·BLCK", "^S": "S·BLCK",
"i": "INSERT", "i": "INSERT",
"ic": "I·COMP",
"ix": "I·C-X ",
"R": "RPLACE", "R": "RPLACE",
"Rv": "V·RPLC", "Rv": "V·RPLC",
"Rc": "R·COMP",
"Rx": "R·C-X ",
"c": "COMMND", "c": "COMMND",
"cv": "VIM·EX", "cv": "VIM·EX",
"ce": "NRM·EX", "ce": "NRM·EX",

View File

@ -103,8 +103,12 @@
"S": "S·LINE", "S": "S·LINE",
"^S": "S·BLCK", "^S": "S·BLCK",
"i": "INSERT", "i": "INSERT",
"ic": "I·COMP",
"ix": "I·C-X ",
"R": "RPLACE", "R": "RPLACE",
"Rv": "V·RPLC", "Rv": "V·RPLC",
"Rc": "R·COMP",
"Rx": "R·C-X ",
"c": "COMMND", "c": "COMMND",
"cv": "VIM·EX", "cv": "VIM·EX",
"ce": "NRM·EX", "ce": "NRM·EX",

View File

@ -117,8 +117,12 @@
"S": "S·LINE", "S": "S·LINE",
"^S": "S·BLCK", "^S": "S·BLCK",
"i": "INSERT", "i": "INSERT",
"ic": "I·COMP",
"ix": "I·C-X ",
"R": "RPLACE", "R": "RPLACE",
"Rv": "V·RPLC", "Rv": "V·RPLC",
"Rc": "R·COMP",
"Rx": "R·C-X ",
"c": "COMMND", "c": "COMMND",
"cv": "VIM·EX", "cv": "VIM·EX",
"ce": "NRM·EX", "ce": "NRM·EX",

View File

@ -103,8 +103,12 @@
"S": "S·LINE", "S": "S·LINE",
"^S": "S·BLCK", "^S": "S·BLCK",
"i": "INSERT", "i": "INSERT",
"ic": "I·COMP",
"ix": "I·C-X ",
"R": "RPLACE", "R": "RPLACE",
"Rv": "V·RPLC", "Rv": "V·RPLC",
"Rc": "R·COMP",
"Rx": "R·C-X ",
"c": "COMMND", "c": "COMMND",
"cv": "VIM·EX", "cv": "VIM·EX",
"ce": "NRM·EX", "ce": "NRM·EX",

View File

@ -103,8 +103,12 @@
"S": "S·LINE", "S": "S·LINE",
"^S": "S·BLCK", "^S": "S·BLCK",
"i": "INSERT", "i": "INSERT",
"ic": "I·COMP",
"ix": "I·C-X ",
"R": "RPLACE", "R": "RPLACE",
"Rv": "V·RPLC", "Rv": "V·RPLC",
"Rc": "R·COMP",
"Rx": "R·C-X ",
"c": "COMMND", "c": "COMMND",
"cv": "VIM·EX", "cv": "VIM·EX",
"ce": "NRM·EX", "ce": "NRM·EX",

View File

@ -104,8 +104,12 @@
"S": "SLN", "S": "SLN",
"^S": "SBL", "^S": "SBL",
"i": "INS", "i": "INS",
"ic": "I-C",
"ix": "I^X",
"R": "REP", "R": "REP",
"Rv": "VRP", "Rv": "VRP",
"Rc": "R-C",
"Rx": "R^X",
"c": "CMD", "c": "CMD",
"cv": "VEX", "cv": "VEX",
"ce": " EX", "ce": " EX",

View File

@ -24,8 +24,8 @@ class Repository(object):
# hg status -> (powerline file status, repo status flag) # hg status -> (powerline file status, repo status flag)
statuses = { statuses = {
b'M': ('M', 1), b'A': ('A', 1), b'R': ('R', 1), b'!': ('D', 1), b'M': ('M', 1), b'A': ('A', 1), b'R': ('R', 1), b'!': ('D', 1),
b'?': ('U', 2), b'I': ('I', 0) b'?': ('U', 2), b'I': ('I', 0), b'C': ('', 0),
} }
repo_statuses_str = (None, 'D ', ' U', 'DU') repo_statuses_str = (None, 'D ', ' U', 'DU')
@ -63,20 +63,20 @@ class Repository(object):
return self.do_status(self.directory, path) return self.do_status(self.directory, path)
def do_status(self, directory, path): def do_status(self, directory, path):
repo = self._repo(directory) with self._repo(directory) as repo:
if path: if path:
path = os.path.join(directory, path) path = os.path.join(directory, path)
statuses = repo.status(include=path, all=True) statuses = repo.status(include=path, all=True)
for status, paths in statuses: for status, paths in statuses:
if paths: if paths:
return self.statuses[status][0] return self.statuses[status][0]
return None return None
else: else:
resulting_status = 0 resulting_status = 0
for status, paths in repo.status(all=True): for status, paths in repo.status(all=True):
if paths: if paths:
resulting_status |= self.statuses[status][1] resulting_status |= self.statuses[status][1]
return self.repo_statuses_str[resulting_status] return self.repo_statuses_str[resulting_status]
def branch(self): def branch(self):
config_file = join(self.directory, '.hg', 'branch') config_file = join(self.directory, '.hg', 'branch')

View File

@ -130,7 +130,8 @@ main_spec = (Spec(
local_themes=Spec().unknown_spec( local_themes=Spec().unknown_spec(
Spec().re('^[0-9A-Za-z-]+$'), Spec().re('^[0-9A-Za-z-]+$'),
ext_theme_spec() ext_theme_spec()
).optional() ).optional(),
update_interval=Spec().cmp('gt', 0.0).optional(),
).optional(), ).optional(),
).unknown_spec( ).unknown_spec(
check_ext, check_ext,

View File

@ -458,7 +458,7 @@ class Renderer(object):
segment is first_segment segment is first_segment
if side == 'left' else if side == 'left' else
segment is last_segment segment is last_segment
)) )) * theme.outer_padding
draw_divider = segment['draw_' + divider_type + '_divider'] draw_divider = segment['draw_' + divider_type + '_divider']
segment_len += outer_padding segment_len += outer_padding
@ -519,7 +519,7 @@ class Renderer(object):
segment is first_segment segment is first_segment
if side == 'left' else if side == 'left' else
segment is last_segment segment is last_segment
)) * ' ' )) * theme.outer_padding * ' '
divider_type = 'soft' if compare_segment['highlight']['bg'] == segment['highlight']['bg'] else 'hard' divider_type = 'soft' if compare_segment['highlight']['bg'] == segment['highlight']['bg'] else 'hard'
divider_highlighted = '' divider_highlighted = ''

View File

@ -72,7 +72,10 @@ def _fetch_battery_info(pl):
devtype_name, devtype_name,
'State' 'State'
) != 2 ) != 2
return (energy * 100.0 / energy_full), state if energy_full > 0:
return (energy * 100.0 / energy_full), state
else:
return 0.0, state
return _flatten_battery return _flatten_battery
pl.debug('Not using DBUS+UPower as no batteries were found') pl.debug('Not using DBUS+UPower as no batteries were found')

View File

@ -477,3 +477,54 @@ Requires ``osascript`` available in $PATH.
{0} {0}
''').format(_common_args.format('rdio'))) ''').format(_common_args.format('rdio')))
class ITunesPlayerSegment(PlayerSegment):
def get_player_status(self, pl):
status_delimiter = '-~`/='
ascript = '''
tell application "System Events"
set process_list to (name of every process)
end tell
if process_list contains "iTunes" then
tell application "iTunes"
if player state is playing then
set t_title to name of current track
set t_artist to artist of current track
set t_album to album of current track
set t_duration to duration of current track
set t_elapsed to player position
set t_state to player state
return t_title & "{0}" & t_artist & "{0}" & t_album & "{0}" & t_elapsed & "{0}" & t_duration & "{0}" & t_state
end if
end tell
end if
'''.format(status_delimiter)
now_playing = asrun(pl, ascript)
if not now_playing:
return
now_playing = now_playing.split(status_delimiter)
if len(now_playing) != 6:
return
title, artist, album = now_playing[0], now_playing[1], now_playing[2]
state = _convert_state(now_playing[5])
total = _convert_seconds(now_playing[4])
elapsed = _convert_seconds(now_playing[3])
return {
'title': title,
'artist': artist,
'album': album,
'total': total,
'elapsed': elapsed,
'state': state
}
itunes = with_docstring(ITunesPlayerSegment(),
('''Return iTunes now playing information
Requires ``osascript``.
{0}
''').format(_common_args.format('itunes')))

View File

@ -50,15 +50,19 @@ vim_modes = {
'S': 'S-LINE', 'S': 'S-LINE',
'^S': 'S-BLCK', '^S': 'S-BLCK',
'i': 'INSERT', 'i': 'INSERT',
'R': 'REPLACE', 'ic': 'I-COMP',
'Rv': 'V-RPLCE', 'ix': 'I-C_X ',
'R': 'RPLACE',
'Rv': 'V-RPLC',
'Rc': 'R-COMP',
'Rx': 'R-C_X ',
'c': 'COMMND', 'c': 'COMMND',
'cv': 'VIM EX', 'cv': 'VIM-EX',
'ce': 'EX', 'ce': 'NRM-EX',
'r': 'PROMPT', 'r': 'PROMPT',
'rm': 'MORE', 'rm': '-MORE-',
'r?': 'CONFIRM', 'r?': 'CNFIRM',
'!': 'SHELL', '!': '!SHELL',
} }
@ -87,18 +91,27 @@ def window_cached(func):
def mode(pl, segment_info, override=None): def mode(pl, segment_info, override=None):
'''Return the current vim mode. '''Return the current vim mode.
If mode (returned by ``mode()`` VimL function, see ``:h mode()`` in Vim)
consists of multiple characters and necessary mode is not known to powerline
then it will fall back to mode with last character(s) ignored.
:param dict override: :param dict override:
dict for overriding default mode strings, e.g. ``{ 'n': 'NORM' }`` dict for overriding default mode strings, e.g. ``{ 'n': 'NORM' }``
''' '''
mode = segment_info['mode'] mode = segment_info['mode']
if mode == 'nc': if mode == 'nc':
return None return None
if not override: while mode:
return vim_modes[mode] try:
try: if not override:
return override[mode] return vim_modes[mode]
except KeyError: try:
return vim_modes[mode] return override[mode]
except KeyError:
return vim_modes[mode]
except KeyError:
mode = mode[:-1]
return 'BUG'
@window_cached @window_cached

View File

@ -69,6 +69,7 @@ class Theme(object):
self.cursor_space_multiplier = None self.cursor_space_multiplier = None
self.cursor_columns = theme_config.get('cursor_columns') self.cursor_columns = theme_config.get('cursor_columns')
self.spaces = theme_config['spaces'] self.spaces = theme_config['spaces']
self.outer_padding = int(theme_config.get('outer_padding', 1))
self.segments = [] self.segments = []
self.EMPTY_SEGMENT = { self.EMPTY_SEGMENT = {
'contents': None, 'contents': None,

View File

@ -6,6 +6,9 @@ import socket
import os import os
import errno import errno
import sys import sys
import fcntl
import atexit
import stat
from argparse import ArgumentParser from argparse import ArgumentParser
from select import select from select import select
@ -13,21 +16,21 @@ from signal import signal, SIGTERM
from time import sleep from time import sleep
from functools import partial from functools import partial
from io import BytesIO from io import BytesIO
from threading import Event
from itertools import chain
from logging import StreamHandler
from powerline.shell import ShellPowerline from powerline.shell import ShellPowerline
from powerline.commands.main import finish_args, write_output from powerline.commands.main import finish_args, write_output
from powerline.lib.monotonic import monotonic from powerline.lib.monotonic import monotonic
from powerline.lib.encoding import get_preferred_output_encoding, get_preferred_arguments_encoding, get_unicode_writer from powerline.lib.encoding import get_preferred_output_encoding, get_preferred_arguments_encoding, get_unicode_writer
from powerline.bindings.wm import wm_threads
from powerline.commands.main import get_argparser as get_main_argparser from powerline.commands.main import get_argparser as get_main_argparser
from powerline.commands.daemon import get_argparser as get_daemon_argparser from powerline.commands.daemon import get_argparser as get_daemon_argparser
is_daemon = False USE_FILESYSTEM = not sys.platform.lower().startswith('linux')
use_filesystem = not sys.platform.lower().startswith('linux')
address = None
pidfile = None
class NonInteractiveArgParser(ArgumentParser): class NonInteractiveArgParser(ArgumentParser):
@ -44,31 +47,48 @@ class NonInteractiveArgParser(ArgumentParser):
raise Exception(self.format_usage()) raise Exception(self.format_usage())
parser = get_main_argparser(NonInteractiveArgParser)
EOF = b'EOF\0\0' EOF = b'EOF\0\0'
powerlines = {}
logger = None class State(object):
config_loader = None __slots__ = ('powerlines', 'logger', 'config_loader', 'started_wm_threads',
home = os.path.expanduser('~') 'ts_shutdown_event')
def __init__(self, **kwargs):
self.logger = None
self.config_loader = None
self.started_wm_threads = {}
self.powerlines = {}
self.ts_shutdown_event = Event()
class PowerlineDaemon(ShellPowerline): HOME = os.path.expanduser('~')
class NonDaemonShellPowerline(ShellPowerline):
def get_log_handler(self): def get_log_handler(self):
if not is_daemon: return StreamHandler()
import logging
return logging.StreamHandler()
return super(PowerlineDaemon, self).get_log_handler()
def render(args, environ, cwd): def start_wm(args, environ, cwd, is_daemon, state):
global logger wm_name = args.ext[0][3:]
global config_loader if wm_name in state.started_wm_threads:
cwd = cwd or environ.get('PWD', '/') return b''
thread_shutdown_event = Event()
thread = wm_threads[wm_name](
thread_shutdown_event=thread_shutdown_event,
pl_shutdown_event=state.ts_shutdown_event,
pl_config_loader=state.config_loader,
)
thread.start()
state.started_wm_threads[wm_name] = (thread, thread_shutdown_event)
return b''
def render(args, environ, cwd, is_daemon, state):
segment_info = { segment_info = {
'getcwd': lambda: cwd, 'getcwd': lambda: cwd,
'home': environ.get('HOME', home), 'home': environ.get('HOME', HOME),
'environ': environ, 'environ': environ,
'args': args, 'args': args,
} }
@ -82,22 +102,24 @@ def render(args, environ, cwd):
environ.get('POWERLINE_CONFIG_OVERRIDES', ''), environ.get('POWERLINE_CONFIG_OVERRIDES', ''),
environ.get('POWERLINE_CONFIG_PATHS', ''), environ.get('POWERLINE_CONFIG_PATHS', ''),
) )
finish_args(environ, args)
PowerlineClass = ShellPowerline if is_daemon else NonDaemonShellPowerline
powerline = None powerline = None
try: try:
powerline = powerlines[key] powerline = state.powerlines[key]
except KeyError: except KeyError:
try: try:
powerline = powerlines[key] = PowerlineDaemon( powerline = state.powerlines[key] = PowerlineClass(
args, args,
logger=logger, logger=state.logger,
config_loader=config_loader, config_loader=state.config_loader,
run_once=False, run_once=False,
shutdown_event=state.ts_shutdown_event,
) )
if logger is None: if state.logger is None:
logger = powerline.logger state.logger = powerline.logger
if config_loader is None: if state.config_loader is None:
config_loader = powerline.config_loader state.config_loader = powerline.config_loader
except SystemExit: except SystemExit:
# Somebody thought raising system exit was a good idea, # Somebody thought raising system exit was a good idea,
return '' return ''
@ -168,23 +190,30 @@ def safe_bytes(o, encoding=get_preferred_output_encoding()):
return safe_bytes(str(e), encoding) return safe_bytes(str(e), encoding)
def parse_args(req, encoding=get_preferred_arguments_encoding()): def parse_args(req, parser, encoding=get_preferred_arguments_encoding()):
args = [x.decode(encoding) for x in req.split(b'\0') if x] args = [x.decode(encoding) for x in req.split(b'\0') if x]
numargs = int(args[0], 16) numargs = int(args[0], 16)
shell_args = parser.parse_args(args[1:numargs + 1]) shell_args = parser.parse_args(args[1:numargs + 1])
cwd = args[numargs + 1] cwd = args[numargs + 1]
environ = dict(((k, v) for k, v in (x.partition('=')[0::2] for x in args[numargs + 2:]))) environ = dict(((k, v) for k, v in (x.partition('=')[0::2] for x in args[numargs + 2:])))
cwd = cwd or environ.get('PWD', '/')
return shell_args, environ, cwd return shell_args, environ, cwd
def do_render(req): def get_answer(req, is_daemon, argparser, state):
try: try:
return safe_bytes(render(*parse_args(req))) args, environ, cwd = parse_args(req, argparser)
finish_args(argparser, environ, args, is_daemon=True)
if args.ext[0].startswith('wm.'):
return safe_bytes(start_wm(args, environ, cwd, is_daemon, state))
else:
return safe_bytes(render(args, environ, cwd, is_daemon, state))
except Exception as e: except Exception as e:
return safe_bytes(str(e)) return safe_bytes(str(e))
def do_one(sock, read_sockets, write_sockets, result_map): def do_one(sock, read_sockets, write_sockets, result_map, is_daemon, argparser,
state):
r, w, e = select( r, w, e = select(
tuple(read_sockets) + (sock,), tuple(read_sockets) + (sock,),
tuple(write_sockets), tuple(write_sockets),
@ -214,7 +243,7 @@ def do_one(sock, read_sockets, write_sockets, result_map):
if req == EOF: if req == EOF:
raise SystemExit(0) raise SystemExit(0)
elif req: elif req:
ans = do_render(req) ans = get_answer(req, is_daemon, argparser, state)
result_map[s] = ans result_map[s] = ans
write_sockets.add(s) write_sockets.add(s)
else: else:
@ -230,17 +259,61 @@ def do_one(sock, read_sockets, write_sockets, result_map):
s.close() s.close()
def main_loop(sock): def shutdown(sock, read_sockets, write_sockets, state):
'''Perform operations necessary for nicely shutting down daemon
Specifically it
#. Closes all sockets.
#. Notifies segments based on
:py:class:`powerline.lib.threaded.ThreadedSegment` and WM-specific
threads that daemon is shutting down.
#. Waits for threads to finish, but no more then 2 seconds total.
#. Waits so that total execution time of this function is 2 seconds in order
to allow ThreadedSegments to finish.
'''
total_wait_time = 2
shutdown_start_time = monotonic()
for s in chain((sock,), read_sockets, write_sockets):
s.close()
# Notify ThreadedSegments
state.ts_shutdown_event.set()
for thread, shutdown_event in state.started_wm_threads.values():
shutdown_event.set()
for thread, shutdown_event in state.started_wm_threads.values():
wait_time = total_wait_time - (monotonic() - shutdown_start_time)
if wait_time > 0:
thread.join(wait_time)
wait_time = total_wait_time - (monotonic() - shutdown_start_time)
sleep(wait_time)
def main_loop(sock, is_daemon):
sock.listen(128) sock.listen(128)
sock.setblocking(0) sock.setblocking(0)
read_sockets, write_sockets = set(), set() read_sockets, write_sockets = set(), set()
result_map = {} result_map = {}
parser = get_main_argparser(NonInteractiveArgParser)
state = State()
try: try:
while True: try:
do_one(sock, read_sockets, write_sockets, result_map) while True:
except KeyboardInterrupt: do_one(
raise SystemExit(0) sock, read_sockets, write_sockets, result_map,
is_daemon=is_daemon,
argparser=parser,
state=state,
)
except KeyboardInterrupt:
raise SystemExit(0)
except SystemExit as e:
shutdown(sock, read_sockets, write_sockets, state)
raise e
return 0 return 0
@ -249,10 +322,10 @@ def daemonize(stdin=os.devnull, stdout=os.devnull, stderr=os.devnull):
pid = os.fork() pid = os.fork()
if pid > 0: if pid > 0:
# exit first parent # exit first parent
sys.exit(0) raise SystemExit(0)
except OSError as e: except OSError as e:
sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1) raise SystemExit(1)
# decouple from parent environment # decouple from parent environment
os.chdir("/") os.chdir("/")
@ -264,10 +337,10 @@ def daemonize(stdin=os.devnull, stdout=os.devnull, stderr=os.devnull):
pid = os.fork() pid = os.fork()
if pid > 0: if pid > 0:
# exit from second parent # exit from second parent
sys.exit(0) raise SystemExit(0)
except OSError as e: except OSError as e:
sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1) raise SystemExit(1)
# Redirect standard file descriptors. # Redirect standard file descriptors.
si = open(stdin, 'rb') si = open(stdin, 'rb')
@ -276,12 +349,11 @@ def daemonize(stdin=os.devnull, stdout=os.devnull, stderr=os.devnull):
os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno()) os.dup2(se.fileno(), sys.stderr.fileno())
global is_daemon return True
is_daemon = True
def check_existing(): def check_existing(address):
if use_filesystem: if USE_FILESYSTEM:
# We cannot bind if the socket file already exists so remove it, we # We cannot bind if the socket file already exists so remove it, we
# already have a lock on pidfile, so this should be safe. # already have a lock on pidfile, so this should be safe.
try: try:
@ -299,7 +371,7 @@ def check_existing():
return sock return sock
def kill_daemon(): def kill_daemon(address):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try: try:
try: try:
@ -313,7 +385,7 @@ def kill_daemon():
return True return True
def cleanup_lockfile(fd, *args): def cleanup_lockfile(pidfile, fd, *args):
try: try:
# Remove the directory entry for the lock file # Remove the directory entry for the lock file
os.unlink(pidfile) os.unlink(pidfile)
@ -326,10 +398,7 @@ def cleanup_lockfile(fd, *args):
raise SystemExit(1) raise SystemExit(1)
def lockpidfile(): def lockpidfile(pidfile):
import fcntl
import atexit
import stat
fd = os.open( fd = os.open(
pidfile, pidfile,
os.O_WRONLY | os.O_CREAT, os.O_WRONLY | os.O_CREAT,
@ -344,24 +413,25 @@ def lockpidfile():
os.ftruncate(fd, 0) os.ftruncate(fd, 0)
os.write(fd, ('%d' % os.getpid()).encode('ascii')) os.write(fd, ('%d' % os.getpid()).encode('ascii'))
os.fsync(fd) os.fsync(fd)
cleanup = partial(cleanup_lockfile, fd) cleanup = partial(cleanup_lockfile, pidfile, fd)
signal(SIGTERM, cleanup) signal(SIGTERM, cleanup)
atexit.register(cleanup) atexit.register(cleanup)
return fd return fd
def main(): def main():
global address
global pidfile
parser = get_daemon_argparser() parser = get_daemon_argparser()
args = parser.parse_args() args = parser.parse_args()
is_daemon = False
address = None
pidfile = None
if args.socket: if args.socket:
address = args.socket address = args.socket
if not use_filesystem: if not USE_FILESYSTEM:
address = '\0' + address address = '\0' + address
else: else:
if use_filesystem: if USE_FILESYSTEM:
address = '/tmp/powerline-ipc-%d' address = '/tmp/powerline-ipc-%d'
else: else:
# Use the abstract namespace for sockets rather than the filesystem # Use the abstract namespace for sockets rather than the filesystem
@ -370,13 +440,13 @@ def main():
address = address % os.getuid() address = address % os.getuid()
if use_filesystem: if USE_FILESYSTEM:
pidfile = address + '.pid' pidfile = address + '.pid'
if args.kill: if args.kill:
if args.foreground or args.replace: if args.foreground or args.replace:
parser.error('--kill and --foreground/--replace cannot be used together') parser.error('--kill and --foreground/--replace cannot be used together')
if kill_daemon(): if kill_daemon(address):
if not args.quiet: if not args.quiet:
print ('Kill command sent to daemon, if it does not die in a couple of seconds use kill to kill it') print ('Kill command sent to daemon, if it does not die in a couple of seconds use kill to kill it')
raise SystemExit(0) raise SystemExit(0)
@ -386,19 +456,19 @@ def main():
raise SystemExit(1) raise SystemExit(1)
if args.replace: if args.replace:
while kill_daemon(): while kill_daemon(address):
if not args.quiet: if not args.quiet:
print ('Kill command sent to daemon, waiting for daemon to exit, press Ctrl-C to terminate wait and exit') print ('Kill command sent to daemon, waiting for daemon to exit, press Ctrl-C to terminate wait and exit')
sleep(2) sleep(2)
if use_filesystem and not args.foreground: if USE_FILESYSTEM and not args.foreground:
# We must daemonize before creating the locked pidfile, unfortunately, # We must daemonize before creating the locked pidfile, unfortunately,
# this means further print statements are discarded # this means further print statements are discarded
daemonize() is_daemon = daemonize()
if use_filesystem: if USE_FILESYSTEM:
# Create a locked pid file containing the daemons PID # Create a locked pid file containing the daemons PID
if lockpidfile() is None: if lockpidfile(pidfile) is None:
if not args.quiet: if not args.quiet:
sys.stderr.write( sys.stderr.write(
'The daemon is already running. Use %s -k to kill it.\n' % ( 'The daemon is already running. Use %s -k to kill it.\n' % (
@ -406,7 +476,7 @@ def main():
raise SystemExit(1) raise SystemExit(1)
# Bind to address or bail if we cannot bind # Bind to address or bail if we cannot bind
sock = check_existing() sock = check_existing(address)
if sock is None: if sock is None:
if not args.quiet: if not args.quiet:
sys.stderr.write( sys.stderr.write(
@ -414,14 +484,11 @@ def main():
os.path.basename(sys.argv[0]))) os.path.basename(sys.argv[0])))
raise SystemExit(1) raise SystemExit(1)
if args.foreground: if not USE_FILESYSTEM and not args.foreground:
return main_loop(sock)
if not use_filesystem:
# We daemonize on linux # We daemonize on linux
daemonize() is_daemon = daemonize()
main_loop(sock) return main_loop(sock, is_daemon)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -23,8 +23,9 @@ else:
if __name__ == '__main__': if __name__ == '__main__':
args = get_argparser().parse_args() parser = get_argparser()
finish_args(os.environ, args) args = parser.parse_args()
finish_args(parser, os.environ, args)
powerline = ShellPowerline(args, run_once=True) powerline = ShellPowerline(args, run_once=True)
segment_info = {'args': args, 'environ': os.environ} segment_info = {'args': args, 'environ': os.environ}
write_output(args, powerline, segment_info, get_unicode_writer()) write_output(args, powerline, segment_info, get_unicode_writer())

View File

@ -59,7 +59,7 @@ else:
def get_version(): def get_version():
base_version = '2.5.2' base_version = '2.6'
base_version += '.dev9999' base_version += '.dev9999'
try: try:
return base_version + '+git.' + str(subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip()) return base_version + '+git.' + str(subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip())
@ -70,7 +70,7 @@ def get_version():
setup( setup(
name='powerline-status', name='powerline-status',
version='2.5.2', version='2.6',
description='The ultimate statusline/prompt utility.', description='The ultimate statusline/prompt utility.',
long_description=README, long_description=README,
classifiers=[ classifiers=[

View File

@ -1,11 +0,0 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import sys
if sys.version_info < (2, 7):
from unittest2 import TestCase, main # NOQA
from unittest2.case import SkipTest # NOQA
else:
from unittest import TestCase, main # NOQA
from unittest.case import SkipTest # NOQA

View File

@ -1,42 +0,0 @@
. tests/bot-ci/scripts/common/main.sh
set +x
: ${PYTHON:=python}
FAILED=0
FAIL_SUMMARY=""
enter_suite() {
local suite_name="$1"
export POWERLINE_CURRENT_SUITE="${POWERLINE_CURRENT_SUITE}/$suite_name"
}
exit_suite() {
if test $FAILED -ne 0 ; then
echo "Suite ${POWERLINE_CURRENT_SUITE} failed, summary:"
echo "${FAIL_SUMMARY}"
fi
export POWERLINE_CURRENT_SUITE="${POWERLINE_CURRENT_SUITE%/*}"
if test "x$1" != "x--continue" ; then
exit $FAILED
fi
}
fail() {
local allow_failure=
if test "x$1" = "x--allow-failure" ; then
shift
allow_failure=A
fi
local test_name="$1"
local fail_char="$allow_failure$2"
local message="$3"
local full_msg="$fail_char $POWERLINE_CURRENT_SUITE|$test_name :: $message"
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}${full_msg}"
echo "Failed: $full_msg"
echo "$full_msg" >> tests/failures
if test "x$allow_failure" = "x" ; then
FAILED=1
fi
}

View File

@ -1,6 +1,7 @@
#!/bin/bash #!/bin/bash
set -e set -e
set -x
remote_master_hex() { remote_master_hex() {
local url="$1" local url="$1"
@ -16,7 +17,7 @@ checkout_cached_dir() {
fi fi
if ! test -d "$target" ; then if ! test -d "$target" ; then
git clone --depth=1 "$url" "$target" git clone --depth=1 "$url" "$target"
mv "$target"/.git/refs/heads/master .version git rev-parse HEAD > "$target/.version"
rm -rf "$target"/.git rm -rf "$target"/.git
fi fi
} }

View File

@ -1,67 +0,0 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import threading
from time import sleep
import pexpect
from tests.lib.vterm import VTerm
class ExpectProcess(threading.Thread):
def __init__(self, lib, rows, cols, cmd, args, cwd=None, env=None):
super(ExpectProcess, self).__init__()
self.vterm = VTerm(lib, rows, cols)
self.lock = threading.Lock()
self.rows = rows
self.cols = cols
self.cmd = cmd
self.args = args
self.cwd = cwd
self.env = env
self.buffer = []
self.child_lock = threading.Lock()
def run(self):
child = pexpect.spawn(self.cmd, self.args, cwd=self.cwd, env=self.env)
sleep(0.5)
child.setwinsize(self.rows, self.cols)
sleep(0.5)
self.child = child
status = None
while status is None:
try:
with self.child_lock:
s = child.read_nonblocking(size=1024, timeout=0)
status = child.status
except pexpect.TIMEOUT:
pass
except pexpect.EOF:
break
else:
with self.lock:
self.vterm.push(s)
self.buffer.append(s)
def resize(self, rows, cols):
with self.child_lock:
self.rows = rows
self.cols = cols
self.child.setwinsize(rows, cols)
self.vterm.resize(rows, cols)
def __getitem__(self, position):
with self.lock:
return self.vterm.vtscreen[position]
def read(self):
with self.lock:
ret = b''.join(self.buffer)
del self.buffer[:]
return ret
def send(self, data):
with self.child_lock:
self.child.send(data)

11
tests/modules/__init__.py Normal file
View File

@ -0,0 +1,11 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import sys
if sys.version_info < (2, 7):
from unittest2 import TestCase, main # NOQA
from unittest2.case import SkipTest # NOQA
else:
from unittest import TestCase, main # NOQA
from unittest.case import SkipTest # NOQA

View File

@ -12,7 +12,7 @@ from powerline.renderer import Renderer
from powerline.lib.config import ConfigLoader from powerline.lib.config import ConfigLoader
from powerline import Powerline, get_default_theme from powerline import Powerline, get_default_theme
from tests.lib import Args, replace_attr from tests.modules.lib import Args, replace_attr
UT = get_default_theme(is_unicode=True) UT = get_default_theme(is_unicode=True)
@ -175,7 +175,7 @@ def get_powerline(config, **kwargs):
TestPowerline, TestPowerline,
_helpers=helpers, _helpers=helpers,
ext='test', ext='test',
renderer_module='tests.lib.config_mock', renderer_module='tests.modules.lib.config_mock',
logger=Logger(), logger=Logger(),
**kwargs **kwargs
) )

View File

@ -59,7 +59,7 @@ class FSTree(object):
self.p = TestPowerline( self.p = TestPowerline(
_paths=self.get_config_paths(self.root), _paths=self.get_config_paths(self.root),
ext='test', ext='test',
renderer_module='tests.lib.config_mock', renderer_module='tests.modules.lib.config_mock',
**self.p_kwargs **self.p_kwargs
) )
if os.environ.get('POWERLINE_RUN_LINT_DURING_TESTS'): if os.environ.get('POWERLINE_RUN_LINT_DURING_TESTS'):

View File

@ -0,0 +1,269 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import threading
import os
from time import sleep
from itertools import groupby
from signal import SIGKILL
from difflib import ndiff
import pexpect
from powerline.lib.unicode import u
from tests.modules.lib.vterm import VTerm, Dimensions
class MutableDimensions(object):
def __init__(self, rows, cols):
super(MutableDimensions, self).__init__()
self._list = [rows, cols]
def __getitem__(self, idx):
return self._list[idx]
def __setitem__(self, idx, val):
self._list[idx] = val
def __iter__(self):
return iter(self._list)
def __len__(self):
return 2
def __nonzero__(self):
return True
__bool__ = __nonzero__
rows = property(
fget = lambda self: self._list[0],
fset = lambda self, val: self._list.__setitem__(0, val),
)
cols = property(
fget = lambda self: self._list[1],
fset = lambda self, val: self._list.__setitem__(1, val),
)
class ExpectProcess(threading.Thread):
def __init__(self, lib, dim, cmd, args, cwd=None, env=None):
super(ExpectProcess, self).__init__()
self.vterm = VTerm(lib, dim)
self.lock = threading.Lock()
self.dim = Dimensions(*dim)
self.cmd = cmd
self.args = args
self.cwd = cwd
self.env = env
self.buffer = []
self.child_lock = threading.Lock()
self.shutdown_event = threading.Event()
def run(self):
child = pexpect.spawn(self.cmd, self.args, cwd=self.cwd, env=self.env)
sleep(0.5)
child.setwinsize(self.dim.rows, self.dim.cols)
sleep(0.5)
self.child = child
status = None
while status is None and not self.shutdown_event.is_set():
try:
with self.child_lock:
s = child.read_nonblocking(size=1024, timeout=0)
status = child.status
except pexpect.TIMEOUT:
pass
except pexpect.EOF:
break
else:
with self.lock:
self.vterm.push(s)
self.buffer.append(s)
if status is None:
child.kill(SIGKILL)
def kill(self):
self.shutdown_event.set()
def resize(self, dim):
with self.child_lock:
self.dim = Dimensions(*dim)
self.child.setwinsize(self.dim.rows, self.dim.cols)
self.vterm.resize(self.dim)
def __getitem__(self, position):
with self.lock:
return self.vterm.vtscreen[position]
def read(self):
with self.lock:
ret = b''.join(self.buffer)
del self.buffer[:]
return ret
def send(self, data):
with self.child_lock:
self.child.send(data)
def get_highlighted_text(self, text, attrs, default_props=()):
ret = []
new_attrs = attrs.copy()
for cell_properties, segment_text in text:
segment_text = segment_text.translate({'{': '{{', '}': '}}'})
if cell_properties not in new_attrs:
new_attrs[cell_properties] = len(new_attrs) + 1
props_name = new_attrs[cell_properties]
if props_name in default_props:
ret.append(segment_text)
else:
ret.append('{' + str(props_name) + ':' + segment_text + '}')
return ''.join(ret), new_attrs
def get_row(self, row, attrs, default_props=()):
with self.lock:
return self.get_highlighted_text((
(key, ''.join((cell.text for cell in subline)))
for key, subline in groupby((
self.vterm.vtscreen[row, col]
for col in range(self.dim.cols)
), lambda cell: cell.cell_properties_key)
), attrs, default_props)
def get_screen(self, attrs, default_props=()):
lines = []
for row in range(self.dim.rows):
line, attrs = self.get_row(row, attrs, default_props)
lines.append(line)
return '\n'.join(lines), attrs
def test_expected_result(p, test, last_attempt, last_attempt_cb=None):
expected_text, attrs = test['expected_result']
attempts = 3
result = None
while attempts:
actual_text, all_attrs = p.get_row(test['row'], attrs)
if actual_text == expected_text:
return True
attempts -= 1
print('Actual result does not match expected. Attempts left: {0}.'.format(attempts))
sleep(2)
print('Result:')
print(actual_text)
print('Expected:')
print(expected_text)
print('Attributes:')
print(all_attrs)
print('Screen:')
screen, screen_attrs = p.get_screen(attrs)
print(screen)
print(screen_attrs)
print('_' * 80)
print('Diff:')
print('=' * 80)
print(''.join((
u(line) for line in ndiff([actual_text + '\n'], [expected_text + '\n']))
))
if last_attempt and last_attempt_cb:
last_attempt_cb()
return False
ENV_BASE = {
# Reasoning:
# 1. vt* TERMs (used to be vt100 here) make tmux-1.9 use different and
# identical colors for inactive windows. This is not like tmux-1.6:
# foreground color is different from separator color and equal to (0,
# 102, 153) for some reason (separator has correct color). tmux-1.8 is
# fine, so are older versions (though tmux-1.6 and tmux-1.7 do not have
# highlighting for previously active window) and my system tmux-1.9a.
# 2. screen, xterm and some other non-256color terminals both have the same
# issue and make libvterm emit complains like `Unhandled CSI SGR 3231`.
# 3. screen-256color, xterm-256color and other -256color terminals make
# libvterm emit complains about unhandled escapes to stderr.
# 4. `st-256color` does not have any of the above problems, but it may be
# not present on the target system because it is installed with
# x11-terms/st and not with sys-libs/ncurses.
#
# For the given reasons decision was made: to fix tmux-1.9 tests and not
# make libvterm emit any data to stderr st-256color $TERM should be used, up
# until libvterm has its own terminfo database entry (if it ever will). To
# make sure that relevant terminfo entry is present on the target system it
# should be distributed with powerline test package. To make distribution
# not require modifying anything outside of powerline test directory
# TERMINFO variable is set.
#
# This fix propagates to non-tmux vterm tests just in case.
'TERM': 'st-256color',
# Also $TERMINFO definition in get_env
'POWERLINE_CONFIG_PATHS': os.path.abspath('powerline/config_files'),
'POWERLINE_COMMAND': 'powerline-render',
'LD_LIBRARY_PATH': os.environ.get('LD_LIBRARY_PATH', ''),
'PYTHONPATH': os.environ.get('PYTHONPATH', ''),
}
def get_env(vterm_path, test_dir, *args, **kwargs):
env = ENV_BASE.copy()
env.update({
'TERMINFO': os.path.join(test_dir, 'terminfo'),
'PATH': vterm_path,
'SHELL': os.path.join(vterm_path, 'bash'),
})
env.update(*args, **kwargs)
return env
def do_terminal_tests(tests, cmd, dim, args, env, cwd=None, fin_cb=None,
last_attempt_cb=None, attempts=3):
lib = os.environ.get('POWERLINE_LIBVTERM')
if not lib:
if os.path.exists('tests/bot-ci/deps/libvterm/libvterm.so'):
lib = 'tests/bot-ci/deps/libvterm/libvterm.so'
else:
lib = 'libvterm.so'
while attempts:
try:
p = ExpectProcess(
lib=lib,
dim=dim,
cmd=cmd,
args=args,
cwd=cwd,
env=env,
)
p.start()
ret = True
for test in tests:
try:
test_prep = test['prep_cb']
except KeyError:
pass
else:
test_prep(p)
ret = (
ret
and test_expected_result(p, test, attempts == 0,
last_attempt_cb)
)
if ret:
return ret
finally:
if fin_cb:
fin_cb(p=p, cmd=cmd, env=env)
p.kill()
p.join(10)
assert(not p.isAlive())
attempts -= 1
return False

View File

@ -3,9 +3,14 @@ from __future__ import (unicode_literals, division, absolute_import, print_funct
import ctypes import ctypes
from collections import namedtuple
from powerline.lib.unicode import unicode, unichr, tointiter from powerline.lib.unicode import unicode, unichr, tointiter
Dimensions = namedtuple('Dimensions', ('rows', 'cols'))
class CTypesFunction(object): class CTypesFunction(object):
def __init__(self, library, name, rettype, args): def __init__(self, library, name, rettype, args):
self.name = name self.name = name
@ -165,9 +170,9 @@ class VTermScreen(object):
class VTerm(object): class VTerm(object):
def __init__(self, lib, rows, cols): def __init__(self, lib, dim):
self.functions = get_functions(lib) self.functions = get_functions(lib)
self.vt = self.functions.vterm_new(rows, cols) self.vt = self.functions.vterm_new(dim.rows, dim.cols)
self.vtscreen = VTermScreen(self.functions, self.functions.vterm_obtain_screen(self.vt)) self.vtscreen = VTermScreen(self.functions, self.functions.vterm_obtain_screen(self.vt))
self.vtscreen.reset(True) self.vtscreen.reset(True)
@ -176,8 +181,8 @@ class VTerm(object):
data = data.encode('utf-8') data = data.encode('utf-8')
return self.functions.vterm_input_write(self.vt, data, len(data)) return self.functions.vterm_input_write(self.vt, data, len(data))
def resize(self, rows, cols): def resize(self, dim):
self.functions.vterm_set_size(self.vt, rows, cols) self.functions.vterm_set_size(self.vt, dim.rows, dim.cols)
def __del__(self): def __del__(self):
try: try:

View File

@ -1,40 +0,0 @@
#!/bin/sh
. tests/common.sh
enter_suite daemon
export ADDRESS="powerline-ipc-test-$$"
echo "Powerline address: $ADDRESS"
if $PYTHON scripts/powerline-daemon -s$ADDRESS ; then
sleep 1
if ! ( \
$PYTHON client/powerline.py --socket $ADDRESS -p/dev/null shell left | \
grep 'file not found'
) ; then
fail "devnull" F "-p/dev/null argument ignored or not treated properly"
fi
if ( \
$PYTHON client/powerline.py --socket $ADDRESS \
-p$PWD/powerline/config_files shell left | \
grep 'file not found'
) ; then
fail "nodevnull" F "-p/dev/null argument remembered while it should not"
fi
if ! ( \
cd tests && \
$PYTHON ../client/powerline.py --socket $ADDRESS \
-p$PWD/../powerline/config_files shell left | \
grep 'tests'
) ; then
fail "segment" F "Output lacks string “tests”"
fi
else
fail "exitcode" E "Daemon exited with status $?"
fi
if $PYTHON scripts/powerline-daemon -s$ADDRESS -k ; then
:
else
fail "-k" F "powerline-daemon -k failed with exit code $?"
fi
exit_suite

View File

@ -1,10 +0,0 @@
#!/bin/sh
. tests/common.sh
enter_suite lint
if ! ${PYTHON} scripts/powerline-lint -p powerline/config_files ; then
fail "test" F "Running powerline-lint failed"
fi
exit_suite

View File

@ -1,7 +0,0 @@
#!/bin/sh
FAILED=0
if ! sh tests/test_shells/test.sh --fast ; then
echo "Failed shells"
FAILED=1
fi
exit $FAILED

View File

@ -1,71 +0,0 @@
#!/bin/sh
. tests/common.sh
enter_suite vim
if test -z "$VIM" ; then
if test -n "$USE_UCS2_PYTHON" ; then
NEW_VIM="$ROOT/tests/bot-ci/deps/vim/master-$UCS2_PYTHON_VARIANT-ucs2-double/vim"
OLD_VIM="$ROOT/tests/bot-ci/deps/vim/v7.0.112-$UCS2_PYTHON_VARIANT-ucs2/vim"
opt_dir="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT"
main_path="$opt_dir/lib/python$UCS2_PYTHON_VARIANT"
site_path="$main_path/site-packages"
venv_main_path="$VIRTUAL_ENV/lib/python$UCS2_PYTHON_VARIANT"
venv_site_path="$venv_main_path/site-packages"
new_paths="${main_path}:${site_path}:${venv_main_path}:${venv_site_path}"
export PYTHONPATH="$new_paths${PYTHONPATH:+:}$PYTHONPATH"
else
if test "$PYTHON_IMPLEMENTATION" != "CPython" ; then
exit 0
fi
if test -d "$ROOT/tests/bot-ci/deps" ; then
NEW_VIM="$ROOT/tests/bot-ci/deps/vim/master-$PYTHON_MM/vim"
OLD_VIM="$ROOT/tests/bot-ci/deps/vim/v7.0.112-$PYTHON_MM/vim"
else
NEW_VIM="vim"
fi
if test -e "$OLD_VIM" ; then
VIMS="NEW_VIM OLD_VIM"
else
VIMS="NEW_VIM"
fi
fi
else
NEW_VIM="$VIM"
OLD_VIM="$VIM"
fi
# Define some overrides. These ones must be ignored and do not affect Vim
# status/tab lines.
export POWERLINE_CONFIG_OVERRIDES='common.default_top_theme=ascii'
export POWERLINE_THEME_OVERRIDES='default.segments.left=[]'
test_script() {
local vim="$1"
local script="$2"
local test_name_prefix="$3"
echo "Running script $script with $vim"
if ! test -e "$vim" ; then
return 0
fi
if ! "$vim" -u NONE -S $script || test -f message.fail ; then
local test_name="$test_name_prefix-${script##*/}"
fail "${test_name%.vim}" F "Failed script $script run with $VIM"
cat message.fail >&2
rm message.fail
fi
}
for script in tests/test_*.vim ; do
if test "${script%.old.vim}" = "${script}" ; then
test_script "$NEW_VIM" "$script" new
fi
done
if test -e "$OLD_VIM" ; then
for script in tests/test_*.old.vim ; do
test_script "$OLD_VIM" "$script" old
done
fi
exit_suite

98
tests/shlib/common.sh Normal file
View File

@ -0,0 +1,98 @@
. tests/bot-ci/scripts/common/main.sh
set +x
: ${PYTHON:=python}
: ${USER:=`id -un`}
: ${HOME:=`getent passwd $USER | cut -d: -f6`}
export USER HOME
if test -z "$FAILED" ; then
FAILED=0
FAIL_SUMMARY=""
TMP_ROOT="$ROOT/tests/tmp"
FAILURES_FILE="$ROOT/tests/failures"
fi
ANSI_CLEAR="\033[0K"
travis_fold() {
local action="$1"
local name="$2"
name="$(echo -n "$name" | tr '\n\0' '--' | sed -r 's/[^A-Za-z0-9]+/-/g')"
name="$(echo -n "$name" | sed -r 's/-$//')"
echo -en "travis_fold:${action}:${name}\r${ANSI_CLEAR}"
}
enter_suite() {
local suite_name="$1" ; shift
export POWERLINE_CURRENT_SUITE="${POWERLINE_CURRENT_SUITE}/$suite_name"
travis_fold start "$POWERLINE_CURRENT_SUITE"
}
exit_suite() {
if test "$POWERLINE_CURRENT_SUITE" = "$POWERLINE_TMP_DIR_SUITE" ; then
rm_test_root
fi
if test $FAILED -ne 0 ; then
echo "Suite ${POWERLINE_CURRENT_SUITE} failed, summary:"
echo "${FAIL_SUMMARY}"
fi
travis_fold end "$POWERLINE_CURRENT_SUITE"
export POWERLINE_CURRENT_SUITE="${POWERLINE_CURRENT_SUITE%/*}"
if test "$1" != "--continue" ; then
exit $FAILED
fi
}
fail() {
local allow_failure=
if test "$1" = "--allow-failure" ; then
shift
allow_failure=A
fi
local test_name="$1" ; shift
local fail_char="$allow_failure$1" ; shift
local message="$1" ; shift
local full_msg="$fail_char $POWERLINE_CURRENT_SUITE|$test_name :: $message"
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}${full_msg}"
echo "Failed: $full_msg"
echo "$full_msg" >> "$FAILURES_FILE"
if test -z "$allow_failure" ; then
FAILED=1
fi
}
make_test_root() {
local suffix="${POWERLINE_CURRENT_SUITE##*/}"
local tmpdir="$TMP_ROOT/$suffix/"
export POWERLINE_TMP_DIR_SUITE="$POWERLINE_CURRENT_SUITE"
if test -d "$tmpdir" ; then
rm -r "$tmpdir"
fi
mkdir -p "$tmpdir"
export TEST_ROOT="$tmpdir"
}
rm_test_root() {
if test -e "$FAILURES_FILE" ; then
return 0
fi
local suffix="${POWERLINE_CURRENT_SUITE##*/}"
if test -d "$TMP_ROOT/$suffix" ; then
rm -r "$TMP_ROOT/$suffix"
rmdir "$TMP_ROOT" &>/dev/null || true
fi
}
if ! which realpath ; then
realpath() {
$PYTHON -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$1"
}
fi

33
tests/shlib/vim.sh Normal file
View File

@ -0,0 +1,33 @@
. tests/bot-ci/scripts/common/main.sh
if test -z "$POWERLINE_VIM_EXE" ; then
if test -n "$USE_UCS2_PYTHON" ; then
NEW_VIM="$ROOT/tests/bot-ci/deps/vim/master-$UCS2_PYTHON_VARIANT-ucs2-double/vim"
OLD_VIM="$ROOT/tests/bot-ci/deps/vim/v7.0.112-$UCS2_PYTHON_VARIANT-ucs2/vim"
opt_dir="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT"
main_path="$opt_dir/lib/python$UCS2_PYTHON_VARIANT"
site_path="$main_path/site-packages"
venv_main_path="$VIRTUAL_ENV/lib/python$UCS2_PYTHON_VARIANT"
venv_site_path="$venv_main_path/site-packages"
new_paths="${main_path}:${site_path}:${venv_main_path}:${venv_site_path}"
export PYTHONPATH="$new_paths${PYTHONPATH:+:}$PYTHONPATH"
else
if test "$PYTHON_IMPLEMENTATION" != "CPython" ; then
exit 0
fi
if test -d "$ROOT/tests/bot-ci/deps" ; then
NEW_VIM="$ROOT/tests/bot-ci/deps/vim/master-$PYTHON_MM/vim"
OLD_VIM="$ROOT/tests/bot-ci/deps/vim/v7.0.112-$PYTHON_MM/vim"
else
NEW_VIM="vim"
fi
if test -e "$OLD_VIM" ; then
VIMS="NEW_VIM OLD_VIM"
else
VIMS="NEW_VIM"
fi
fi
else
NEW_VIM="$POWERLINE_VIM_EXE"
OLD_VIM="$POWERLINE_VIM_EXE"
fi

26
tests/shlib/vterm.sh Normal file
View File

@ -0,0 +1,26 @@
. tests/shlib/common.sh
. tests/bot-ci/scripts/common/main.sh
set +x
vterm_setup() {
local test_dir="$1" ; shift
rm -rf "$test_dir"
mkdir "$test_dir"
mkdir "$test_dir/path"
ln -s "$(which "${PYTHON}")" "$test_dir/path/python"
ln -s "$(which bash)" "$test_dir/path"
cp -r "$ROOT/tests/terminfo" "$test_dir"
}
vterm_shutdown() {
local test_dir="$1" ; shift
if test $FAILED -eq 0 ; then
rm -rf "$test_dir"
else
echo "$FAIL_SUMMARY"
fi
}

View File

@ -1,13 +1,8 @@
#!/bin/bash #!/bin/bash
. tests/common.sh . tests/shlib/common.sh
enter_suite root enter_suite root
: ${USER:=`id -un`}
: ${HOME:=`getent passwd $USER | cut -d: -f6`}
export USER HOME
if test "$TRAVIS" = true ; then if test "$TRAVIS" = true ; then
export PATH="$HOME/opt/fish/bin:${PATH}" export PATH="$HOME/opt/fish/bin:${PATH}"
export PATH="$PWD/tests/bot-ci/deps/rc:$PATH" export PATH="$PWD/tests/bot-ci/deps/rc:$PATH"
@ -22,18 +17,16 @@ if test "$TRAVIS" = true ; then
. virtualenvwrapper.sh . virtualenvwrapper.sh
workon cpython-ucs2-$UCS2_PYTHON_VARIANT workon cpython-ucs2-$UCS2_PYTHON_VARIANT
set -e set -e
else
LIBRARY_PATH="$(ldd "$(which python)" | grep libpython | sed 's/^.* => //;s/ .*$//')"
LIBRARY_DIR="$(dirname "${LIBRARY_PATH}")"
export LD_LIBRARY_PATH="$LIBRARY_DIR${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH"
fi fi
fi fi
if ! which realpath ; then
realpath() {
$PYTHON -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$1"
}
fi
export PYTHON="${PYTHON:=python}" export PYTHON="${PYTHON:=python}"
export PYTHONPATH="${PYTHONPATH}${PYTHONPATH:+:}`realpath .`" export PYTHONPATH="${PYTHONPATH}${PYTHONPATH:+:}`realpath .`"
for script in tests/run_*_tests.sh ; do for script in "$ROOT"/tests/test_*/test.sh ; do
test_name="${script##*/run_}" test_name="${script##*/run_}"
if ! sh $script ; then if ! sh $script ; then
fail "${test_name%_tests.sh}" F "Failed $script" fail "${test_name%_tests.sh}" F "Failed $script"

View File

@ -0,0 +1,3 @@
#!/bin/sh
echo "$@" >> "$TEST_ROOT/results/args"
cat >> "$TEST_ROOT/results/requests"

View File

@ -0,0 +1,7 @@
{
"ext": {
"wm": {
"update_interval": 0.5
}
}
}

View File

@ -0,0 +1,18 @@
{
"segments": {
"left": [
{
"type": "string",
"highlight_groups": ["time"],
"contents": "default-left"
}
],
"right": [
{
"type": "string",
"highlight_groups": ["time"],
"contents": "default-right"
}
]
}
}

View File

@ -0,0 +1,18 @@
{
"segments": {
"left": [
{
"type": "string",
"highlight_groups": ["time"],
"contents": "dvi-left"
}
],
"right": [
{
"type": "string",
"highlight_groups": ["time"],
"contents": "dvi-right"
}
]
}
}

188
tests/test_awesome/test.sh Executable file
View File

@ -0,0 +1,188 @@
#!/bin/sh
. tests/shlib/common.sh
enter_suite awesome
make_test_root
TEST_PATH="$TEST_ROOT/path"
TEST_STATIC_ROOT="$ROOT/tests/test_awesome"
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 cat)" "$TEST_PATH"
ln -s "$(which sh)" "$TEST_PATH"
ln -s "$(which env)" "$TEST_PATH"
if which socat ; then
ln -s "$(which socat)" "$TEST_PATH"
fi
for pexe in powerline powerline.sh powerline.py ; do
if test -e scripts/$pexe ; then
ln -s "$PWD/scripts/$pexe" $TEST_ROOT/path
elif test -e client/$pexe ; then
ln -s "$PWD/client/$pexe" $TEST_ROOT/path
elif which $pexe ; then
ln -s "$(which $pexe)" $TEST_ROOT/path
else
continue
fi
if test "$pexe" != 'powerline.sh' || test -e "$TEST_PATH/socat" ; then
POWERLINE_COMMAND="$pexe"
break
fi
done
DEPRECATED_SCRIPT="$ROOT/powerline/bindings/awesome/powerline-awesome.py"
POWERLINE_DAEMON="scripts/powerline-daemon"
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 args_file="$TEST_ROOT/results/args"
local log_file="$TEST_ROOT/results/requests"
local line="$(head -n1 "$log_file")"
local linenum="$(cat "$log_file" | wc -l)"
echo "Number of runs: $linenum (expected approx 5 / 0.5 = 10 runs)"
if test $linenum -lt 5 ; then
fail "log:lt" F "Script was run not enough times: $linenum < 5"
return 1
elif test $linenum -gt 15 ; then
fail "log:gt" E "Script was run too many times: $linenum > 15"
return 1
fi
local expline="powerline_widget:set_markup('<span foreground=\"#303030\"> </span><span foreground=\"#d0d0d0\" background=\"#303030\" font_weight=\"bold\"> default-right </span>')"
if test "$expline" != "$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"
for args in "" "0.5"; do
rm -rf "$TEST_ROOT/results"
mkdir "$TEST_ROOT/results"
DEPRECATED_LOG="$TEST_ROOT/deprecated.log"
run env \
DEPRECATED_SCRIPT="$DEPRECATED_SCRIPT" \
args="$args" \
DEPRECATED_LOG="$DEPRECATED_LOG" \
TEST_ROOT="$TEST_ROOT" \
sh -c '
echo $$ > "$TEST_ROOT/$args-pid"
exec "$DEPRECATED_SCRIPT" $args > "$DEPRECATED_LOG" 2>&1
' &
sleep 5
killscript "$(cat "$TEST_ROOT/$args-pid")"
rm "$TEST_ROOT/$args-pid"
if test -n "$(cat "$DEPRECATED_LOG")" ; then
display_log "$DEPRECATED_LOG"
fail "output" E "Nonempty $DEPRECATED_SCRIPT output"
fi
rm "$DEPRECATED_LOG"
if ! check_log ; then
display_log "$TEST_ROOT/results/args"
fail "log" F "Checking log failed"
fi
done
exit_suite --continue
fi
enter_suite "awesome"
ADDRESS="powerline-ipc-test-$$"
echo "Powerline address: $ADDRESS"
rm -rf "$TEST_ROOT/results"
mkdir "$TEST_ROOT/results"
run env \
POWERLINE_DAEMON="$POWERLINE_DAEMON" \
TEST_ROOT="$TEST_ROOT" \
ADDRESS="$ADDRESS" \
sh -c '
echo $$ > "$TEST_ROOT/dpid"
exec python "$POWERLINE_DAEMON" --socket $ADDRESS --foreground > "$TEST_ROOT/daemon.log" 2>&1
' &
DPID=$!
sleep 2
run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.1" 2>&1
run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.2" 2>&1
run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.3" 2>&1
run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.4" 2>&1
run "$POWERLINE_COMMAND" --socket $ADDRESS wm.awesome > "$TEST_ROOT/output.log.5" 2>&1
for log_file in "$TEST_ROOT"/output.log.* ; do
if test -n "$(cat "$log_file")" ; then
display_log "$log_file"
fail "output" E "Nonempty $POWERLINE_COMMAND output at run ${log_file#*.}"
fi
rm "$log_file"
done
sleep 5
run python "$POWERLINE_DAEMON" --socket $ADDRESS --quiet --kill > "$TEST_ROOT/kill.log" 2>&1
if test -n "$(cat "$TEST_ROOT/kill.log")" ; then
display_log "$TEST_ROOT/kill.log"
fail "daemonlog" E "Nonempty kill log"
fi
rm "$TEST_ROOT/kill.log"
wait $DPID
if test -n "$(cat "$TEST_ROOT/daemon.log")" ; then
display_log "$TEST_ROOT/daemon.log"
fail "daemonlog" E "Nonempty daemon log"
fi
rm "$TEST_ROOT/daemon.log"
if ! check_log ; then
display_log "$TEST_ROOT/results/args"
fail "log" F "Checking log failed"
fi
exit_suite --continue
if ! powerline-lint \
-p "$ROOT/powerline/config_files" \
-p "$TEST_STATIC_ROOT/powerline"
then
fail "lint" F "Checking test config failed"
fi
exit_suite

View File

@ -1,14 +1,12 @@
#!/bin/sh #!/bin/sh
. tests/common.sh . tests/shlib/common.sh
enter_suite bar enter_suite bar
TEST_ROOT="$ROOT/tests/bar" make_test_root
TEST_PATH="$TEST_ROOT/path" TEST_PATH="$TEST_ROOT/path"
TEST_STATIC_ROOT="$ROOT/tests/test_bar" 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/path" "$TEST_ROOT"
cp -r "$TEST_STATIC_ROOT/powerline" "$TEST_ROOT" cp -r "$TEST_STATIC_ROOT/powerline" "$TEST_ROOT"
@ -51,7 +49,7 @@ check_log() {
if test "$warns" = "warns" ; then if test "$warns" = "warns" ; then
local warning="$(head -n1 "$log_file" | sed 's/.*://')" local warning="$(head -n1 "$log_file" | sed 's/.*://')"
local expwarning="The 'bar' bindings are deprecated, please switch to 'lemonbar'" local expwarning="The 'bar' bindings are deprecated, please switch to 'lemonbar'"
if test "x$warning" != "x$expwarning" ; then if test "$warning" != "$expwarning" ; then
echo "Got: $warning" echo "Got: $warning"
echo "Exp: $expwarning" echo "Exp: $expwarning"
fail "warn" F "Expected warning" fail "warn" F "Expected warning"
@ -68,7 +66,7 @@ check_log() {
return 1 return 1
fi 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}" 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 if test "$expline" != "$line" ; then
echo "Line: '$line'" echo "Line: '$line'"
echo "Expected: '$expline'" echo "Expected: '$expline'"
fail "log:line" F "Unexpected line" fail "log:line" F "Unexpected line"
@ -151,14 +149,14 @@ else
if test "$fnum" -ne 2 ; then if test "$fnum" -ne 2 ; then
fail "fnum" F "Expected two output files" fail "fnum" F "Expected two output files"
fi fi
if test "x${args#--height}" != "x$args" ; then if test "${args#--height}" != "$args" ; then
height="${args#--height}" height="${args#--height}"
height="${height# }" height="${height# }"
height="${height#=}" height="${height#=}"
height="${height%% *}" height="${height%% *}"
fi fi
command="lemonbar" command="lemonbar"
if test "x${args#--bar-command}" != "x$args" ; then if test "${args#--bar-command}" != "$args" ; then
command="${args#--bar-command}" command="${args#--bar-command}"
command="${command# }" command="${command# }"
command="${command#=}" command="${command#=}"
@ -168,11 +166,11 @@ else
rm "$TEST_ROOT/args.log" rm "$TEST_ROOT/args.log"
script_args="${args#*-- }" script_args="${args#*-- }"
script_args="${script_args# }" script_args="${script_args# }"
if test "x${script_args}" '=' "x$args" ; then if test "${script_args}" = "$args" ; then
script_args= script_args=
fi fi
expected_args="$command -g 1920x$height+0${script_args:+ }$script_args${NL}$command -g 1920x$height+1${script_args:+ }$script_args" 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 if test "$expected_args" != "$received_args" ; then
echo "args:${NL}<$received_args>" echo "args:${NL}<$received_args>"
echo "expected:${NL}<$expected_args>" echo "expected:${NL}<$expected_args>"
fail "args" F "Expected different args" fail "args" F "Expected different args"
@ -194,8 +192,4 @@ then
fail "lint" F "Checking test config failed" fail "lint" F "Checking test config failed"
fi fi
if test $FAILED -eq 0 ; then
rm -r "$TEST_ROOT"
fi
exit_suite exit_suite

41
tests/test_daemon/test.sh Executable file
View File

@ -0,0 +1,41 @@
#!/bin/sh
. tests/shlib/common.sh
enter_suite daemon
export ADDRESS="powerline-ipc-test-$$"
echo "Powerline address: $ADDRESS"
if "$PYTHON" "$ROOT/scripts/powerline-daemon" -s"$ADDRESS" ; then
sleep 1
if ! ( \
"$PYTHON" "$ROOT/client/powerline.py" \
--socket "$ADDRESS" -p/dev/null shell left \
| grep "file not found"
) ; then
fail "devnull" F "-p/dev/null argument ignored or not treated properly"
fi
if ( \
"$PYTHON" "$ROOT/client/powerline.py" --socket "$ADDRESS" \
-p"$ROOT/powerline/config_files" shell left \
| grep "file not found"
) ; then
fail "nodevnull" F "-p/dev/null argument remembered while it should not"
fi
if ! ( \
cd "$ROOT/tests/test_daemon" \
&& "$PYTHON" "$ROOT/client/powerline.py" --socket "$ADDRESS" \
-p"$ROOT/powerline/config_files" shell left \
| grep "test_daemon"
) ; then
fail "segment" F "Output lacks string “tests”"
fi
else
fail "exitcode" E "Daemon exited with status $?"
fi
if "$PYTHON" "$ROOT/scripts/powerline-daemon" -s"$ADDRESS" -k ; then
:
else
fail "-k" F "powerline-daemon -k failed with exit code $?"
fi
exit_suite

View File

@ -1,11 +1,11 @@
#!/bin/sh #!/bin/sh
. tests/common.sh . tests/shlib/common.sh
enter_suite vterm enter_suite vterm
for t in tests/test_in_vterm/test_*.sh ; do for t in "$ROOT"/tests/test_in_vterm/test_*.sh ; do
test_name="${t##*/test_}" test_name="${t##*/test_}"
if ! sh "$t" ; then if ! "$t" ; then
fail "${test_name%.sh}" F "Failed running $t" fail "${test_name%.sh}" F "Failed running $t"
fi fi
done done

View File

@ -4,317 +4,241 @@ from __future__ import (unicode_literals, division, absolute_import, print_funct
import os import os
import sys import sys
import json
from time import sleep from time import sleep
from subprocess import check_call from subprocess import check_call
from itertools import groupby
from difflib import ndiff
from glob import glob1 from glob import glob1
from traceback import print_exc
from powerline.lib.unicode import u from powerline.lib.dict import updated
from powerline.bindings.tmux import get_tmux_version from powerline.bindings.tmux import get_tmux_version
from powerline import get_fallback_logger from powerline import get_fallback_logger
from tests.lib.terminal import ExpectProcess from tests.modules.lib.terminal import (ExpectProcess, MutableDimensions,
do_terminal_tests, get_env)
VTERM_TEST_DIR = os.path.abspath('tests/vterm_tmux') VTERM_TEST_DIR = os.path.abspath('tests/vterm_tmux')
def cell_properties_key_to_shell_escape(cell_properties_key): def tmux_logs_iter(test_dir):
fg, bg, bold, underline, italic = cell_properties_key for tail in glob1(test_dir, '*.log'):
return('\x1b[38;2;{0};48;2;{1}{bold}{underline}{italic}m'.format( yield os.path.join(test_dir, tail)
';'.join((str(i) for i in fg)),
';'.join((str(i) for i in bg)),
bold=(';1' if bold else ''),
underline=(';4' if underline else ''),
italic=(';3' if italic else ''),
))
def test_expected_result(p, expected_result, cols, rows, print_logs): def print_tmux_logs():
last_line = [] for f in tmux_logs_iter(VTERM_TEST_DIR):
for col in range(cols): print('_' * 80)
last_line.append(p[rows - 1, col]) print(os.path.basename(f) + ':')
attempts = 3 print('=' * 80)
result = None with open(f, 'r') as fp:
while attempts: for line in fp:
result = tuple(( sys.stdout.write(line)
(key, ''.join((i.text for i in subline))) os.unlink(f)
for key, subline in groupby(last_line, lambda i: i.cell_properties_key)
))
if result == expected_result:
return True
attempts -= 1
print('Actual result does not match expected. Attempts left: {0}.'.format(attempts))
sleep(2)
print('Result:')
shesc_result = ''.join((
'{0}{1}\x1b[m'.format(cell_properties_key_to_shell_escape(key), text)
for key, text in result
))
print(shesc_result)
print(result)
print('Expected:')
shesc_expected_result = ''.join((
'{0}{1}\x1b[m'.format(cell_properties_key_to_shell_escape(key), text)
for key, text in expected_result
))
print(shesc_expected_result)
p.send(b'powerline-config tmux setup\n')
sleep(5)
print('Screen:')
screen = []
for i in range(rows):
screen.append([])
for j in range(cols):
screen[-1].append(p[i, j])
print('\n'.join(
''.join((
'{0}{1}\x1b[m'.format(
cell_properties_key_to_shell_escape(i.cell_properties_key),
i.text
) for i in line
))
for line in screen
))
a = shesc_result.replace('\x1b', '\\e') + '\n'
b = shesc_expected_result.replace('\x1b', '\\e') + '\n'
print('_' * 80)
print('Diff:')
print('=' * 80)
print(''.join((u(line) for line in ndiff([a], [b]))))
if print_logs:
for f in glob1(VTERM_TEST_DIR, '*.log'):
print('_' * 80)
print(os.path.basename(f) + ':')
print('=' * 80)
with open(f, 'r') as F:
for line in F:
sys.stdout.write(line)
os.unlink(f)
return False
def get_expected_result(tmux_version, expected_result_old, expected_result_1_7=None, expected_result_new=None, expected_result_2_0=None): def get_expected_result(tmux_version,
expected_result_old,
expected_result_1_7=None,
expected_result_1_8=None,
expected_result_2_0=None):
if tmux_version >= (2, 0) and expected_result_2_0: if tmux_version >= (2, 0) and expected_result_2_0:
return expected_result_2_0 return expected_result_2_0
elif tmux_version >= (1, 8) and expected_result_new: elif tmux_version >= (1, 8) and expected_result_1_8:
return expected_result_new return expected_result_1_8
elif tmux_version >= (1, 7) and expected_result_1_7: elif tmux_version >= (1, 7) and expected_result_1_7:
return expected_result_1_7 return expected_result_1_7
else: else:
return expected_result_old return expected_result_old
def tmux_fin_cb(p, cmd, env):
try:
check_call([
cmd, '-S', env['POWERLINE_TMUX_SOCKET_PATH'], 'kill-server'
], env=env, cwd=VTERM_TEST_DIR)
except Exception:
print_exc()
for f in tmux_logs_iter(VTERM_TEST_DIR):
os.unlink(f)
def main(attempts=3): def main(attempts=3):
vterm_path = os.path.join(VTERM_TEST_DIR, 'path') vterm_path = os.path.join(VTERM_TEST_DIR, 'path')
socket_path = 'tmux-socket'
rows = 50
cols = 200
tmux_exe = os.path.join(vterm_path, 'tmux') tmux_exe = os.path.join(vterm_path, 'tmux')
if os.path.exists('tests/bot-ci/deps/libvterm/libvterm.so'): socket_path = os.path.abspath('tmux-socket-{0}'.format(attempts))
lib = 'tests/bot-ci/deps/libvterm/libvterm.so' if os.path.exists(socket_path):
else: os.unlink(socket_path)
lib = os.environ.get('POWERLINE_LIBVTERM', 'libvterm.so')
try: env = get_env(vterm_path, VTERM_TEST_DIR, {
p = ExpectProcess( 'POWERLINE_THEME_OVERRIDES': ';'.join((
lib=lib, key + '=' + json.dumps(val)
rows=rows, for key, val in (
cols=cols, ('default.segments.right', [{
cmd=tmux_exe, 'type': 'string',
args=[ 'name': 's1',
# Specify full path to tmux socket (testing tmux instance must 'highlight_groups': ['cwd'],
# not interfere with user one) 'priority':50,
'-S', socket_path, }]),
# Force 256-color mode ('default.segments.left', [{
'-2', 'type': 'string',
# Request verbose logging just in case 'name': 's2',
'-v', 'highlight_groups': ['background'],
# Specify configuration file 'priority':20,
'-f', os.path.abspath('powerline/bindings/tmux/powerline.conf'), }]),
# Run bash three times ('default.segment_data.s1.contents', 'S1 string here'),
'new-session', 'bash --norc --noprofile -i', ';', ('default.segment_data.s2.contents', 'S2 string here'),
'new-window', 'bash --norc --noprofile -i', ';', )
'new-window', 'bash --norc --noprofile -i', ';', )),
], 'POWERLINE_TMUX_SOCKET_PATH': socket_path,
cwd=VTERM_TEST_DIR, })
env={
# Reasoning: conf_path = os.path.abspath('powerline/bindings/tmux/powerline.conf')
# 1. vt* TERMs (used to be vt100 here) make tmux-1.9 use conf_line = 'source "' + (
# different and identical colors for inactive windows. This conf_path.replace('\\', '\\\\').replace('"', '\\"')) + '"\n'
# is not like tmux-1.6: foreground color is different from conf_file = os.path.realpath(os.path.join(VTERM_TEST_DIR, 'tmux.conf'))
# separator color and equal to (0, 102, 153) for some reason with open(conf_file, 'w') as cf_fd:
# (separator has correct color). tmux-1.8 is fine, so are cf_fd.write(conf_line)
# older versions (though tmux-1.6 and tmux-1.7 do not have
# highlighting for previously active window) and my system tmux_version = get_tmux_version(get_fallback_logger())
# tmux-1.9a.
# 2. screen, xterm and some other non-256color terminals both dim = MutableDimensions(rows=50, cols=200)
# have the same issue and make libvterm emit complains like
# `Unhandled CSI SGR 3231`. def prepare_test_1(p):
# 3. screen-256color, xterm-256color and other -256color
# terminals make libvterm emit complains about unhandled
# escapes to stderr.
# 4. `st-256color` does not have any of the above problems, but
# it may be not present on the target system because it is
# installed with x11-terms/st and not with sys-libs/ncurses.
#
# For the given reasons decision was made: to fix tmux-1.9 tests
# and not make libvterm emit any data to stderr st-256color
# $TERM should be used, up until libvterm has its own terminfo
# database entry (if it ever will). To make sure that relevant
# terminfo entry is present on the target system it should be
# distributed with powerline test package. To make distribution
# not require modifying anything outside of powerline test
# directory TERMINFO variable is set.
'TERMINFO': os.path.join(VTERM_TEST_DIR, 'terminfo'),
'TERM': 'st-256color',
'PATH': vterm_path,
'SHELL': os.path.join(VTERM_TEST_DIR, 'path', 'bash'),
'POWERLINE_CONFIG_PATHS': os.path.abspath('powerline/config_files'),
'POWERLINE_COMMAND': 'powerline-render',
'POWERLINE_THEME_OVERRIDES': (
'default.segments.right=[{"type":"string","name":"s1","highlight_groups":["cwd"],"priority":50}];'
'default.segments.left=[{"type":"string","name":"s2","highlight_groups":["background"],"priority":20}];'
'default.segment_data.s1.contents=S1 string here;'
'default.segment_data.s2.contents=S2 string here;'
),
'LD_LIBRARY_PATH': os.environ.get('LD_LIBRARY_PATH', ''),
'PYTHONPATH': os.environ.get('PYTHONPATH', ''),
},
)
p.start()
sleep(5) sleep(5)
tmux_version = get_tmux_version(get_fallback_logger())
expected_result = get_expected_result(tmux_version, expected_result_old=( def prepare_test_2(p):
(((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), dim.cols = 40
(((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), p.resize(dim)
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' S2 string here '),
(((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '),
(((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1- '),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '),
(((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '),
(((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '),
(((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 124),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '),
(((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here '),
), expected_result_new=(
(((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '),
(((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' S2 string here '),
(((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '),
(((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1- '),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), 'bash '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '),
(((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '),
(((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 124),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '),
(((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here '),
), expected_result_2_0=(
(((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '),
(((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' S2 string here '),
(((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '),
(((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1- '),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), 'bash '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '),
(((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '),
(((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 125),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '),
(((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here '),
))
ret = None
if not test_expected_result(p, expected_result, cols, rows, not attempts):
if attempts:
pass
# Will rerun main later.
else:
ret = False
elif ret is not False:
ret = True
cols = 40
p.resize(rows, cols)
sleep(5) sleep(5)
expected_result = get_expected_result(tmux_version, (
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * cols), base_attrs = {
), expected_result_1_7=( ((0, 0, 0), (243, 243, 243), 1, 0, 0): 'lead',
(((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), ((243, 243, 243), (11, 11, 11), 0, 0, 0): 'leadsep',
(((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), ((255, 255, 255), (11, 11, 11), 0, 0, 0): 'bg',
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' <'), ((199, 199, 199), (88, 88, 88), 0, 0, 0): 'cwd',
(((188, 188, 188), (11, 11, 11), 0, 0, 0), 'h '), ((88, 88, 88), (11, 11, 11), 0, 0, 0): 'cwdhsep',
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), ((0, 0, 0), (0, 224, 0), 0, 0, 0): 'defstl',
(((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '), }
(((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '), tests = (
(((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '), {
(((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '), 'expected_result': get_expected_result(
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), tmux_version,
(((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '), expected_result_old=(
(((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here ') '{lead: 0 }{leadsep: }{bg: S2 string here }'
), expected_result_new=( '{4: 0 }{cwdhsep:| }{6:bash }'
(((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), '{bg: }{4: 1- }{cwdhsep:| }{6:bash }'
(((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), '{bg: }{7: }{8:2* | }{9:bash }{10: }'
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' <'), '{bg:' + (' ' * 124) + '}'
(((0, 102, 153), (11, 11, 11), 0, 0, 0), 'h '), '{cwdhsep: }{cwd: S1 string here }', updated(base_attrs, {
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), ((133, 133, 133), (11, 11, 11), 0, 0, 0): 4,
(((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '), ((188, 188, 188), (11, 11, 11), 0, 0, 0): 6,
(((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '), ((11, 11, 11), (0, 102, 153), 0, 0, 0): 7,
(((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '), ((102, 204, 255), (0, 102, 153), 0, 0, 0): 8,
(((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '), ((255, 255, 255), (0, 102, 153), 1, 0, 0): 9,
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), ((0, 102, 153), (11, 11, 11), 0, 0, 0): 10,
(((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '), })),
(((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here ') expected_result_1_8=(
), expected_result_2_0=( '{lead: 0 }{leadsep: }{bg: S2 string here }'
(((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), '{4: 0 }{cwdhsep:| }{6:bash }'
(((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), '{bg: }{4: 1- }{cwdhsep:| }{7:bash }'
(((255, 255, 255), (11, 11, 11), 0, 0, 0), '<'), '{bg: }{8: }{9:2* | }{10:bash }{7: }'
(((0, 102, 153), (11, 11, 11), 0, 0, 0), 'ash '), '{bg:' + (' ' * 124) + '}'
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), '{cwdhsep: }{cwd: S1 string here }', updated(base_attrs, {
(((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '), ((133, 133, 133), (11, 11, 11), 0, 0, 0): 4,
(((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '), ((188, 188, 188), (11, 11, 11), 0, 0, 0): 6,
(((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '), ((0, 102, 153), (11, 11, 11), 0, 0, 0): 7,
(((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '), ((11, 11, 11), (0, 102, 153), 0, 0, 0): 8,
(((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '), ((102, 204, 255), (0, 102, 153), 0, 0, 0): 9,
(((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here ') ((255, 255, 255), (0, 102, 153), 1, 0, 0): 10,
)) })),
if not test_expected_result(p, expected_result, cols, rows, not attempts): expected_result_2_0=(
if attempts: '{lead: 0 }{leadsep: }{bg: S2 string here }'
pass '{4: 0 }{cwdhsep:| }{6:bash }'
else: '{bg: }{4: 1- }{cwdhsep:| }{7:bash }'
ret = False '{bg: }{8: }{9:2* | }{10:bash }{7: }'
elif ret is not False: '{bg:' + (' ' * 125) + '}'
ret = True '{cwdhsep: }{cwd: S1 string here }', updated(base_attrs, {
if ret is not None: ((133, 133, 133), (11, 11, 11), 0, 0, 0): 4,
return ret ((188, 188, 188), (11, 11, 11), 0, 0, 0): 6,
finally: ((0, 102, 153), (11, 11, 11), 0, 0, 0): 7,
check_call([tmux_exe, '-S', socket_path, 'kill-server'], env={ ((11, 11, 11), (0, 102, 153), 0, 0, 0): 8,
'PATH': vterm_path, ((102, 204, 255), (0, 102, 153), 0, 0, 0): 9,
'LD_LIBRARY_PATH': os.environ.get('LD_LIBRARY_PATH', ''), ((255, 255, 255), (0, 102, 153), 1, 0, 0): 10,
}, cwd=VTERM_TEST_DIR) })),
return main(attempts=(attempts - 1)) ),
'prep_cb': prepare_test_1,
'row': dim.rows - 1,
}, {
'expected_result': get_expected_result(
tmux_version,
expected_result_old=('{bg:' + (' ' * 40) + '}', base_attrs),
expected_result_1_7=(
'{lead: 0 }'
'{leadsep: }{bg: <}{4:h }{bg: }{5: }'
'{6:2* | }{7:bash }{8: }{bg: }{cwdhsep: }'
'{cwd: S1 string here }', updated(base_attrs, {
((188, 188, 188), (11, 11, 11), 0, 0, 0): 4,
((11, 11, 11), (0, 102, 153), 0, 0, 0): 5,
((102, 204, 255), (0, 102, 153), 0, 0, 0): 6,
((255, 255, 255), (0, 102, 153), 1, 0, 0): 7,
((0, 102, 153), (11, 11, 11), 0, 0, 0): 8,
})),
expected_result_1_8=(
'{lead: 0 }'
'{leadsep: }{bg: <}{4:h }{bg: }{5: }'
'{6:2* | }{7:bash }{4: }{bg: }{cwdhsep: }'
'{cwd: S1 string here }', updated(base_attrs, {
((0, 102, 153), (11, 11, 11), 0, 0, 0): 4,
((11, 11, 11), (0, 102, 153), 0, 0, 0): 5,
((102, 204, 255), (0, 102, 153), 0, 0, 0): 6,
((255, 255, 255), (0, 102, 153), 1, 0, 0): 7,
})),
expected_result_2_0=(
'{lead: 0 }'
'{leadsep: }{bg:<}{4:ash }{bg: }{5: }'
'{6:2* | }{7:bash }{4: }{cwdhsep: }'
'{cwd: S1 string here }', updated(base_attrs, {
((0, 102, 153), (11, 11, 11), 0, 0, 0): 4,
((11, 11, 11), (0, 102, 153), 0, 0, 0): 5,
((102, 204, 255), (0, 102, 153), 0, 0, 0): 6,
((255, 255, 255), (0, 102, 153), 1, 0, 0): 7,
})),
),
'prep_cb': prepare_test_2,
'row': dim.rows - 1,
}
)
args = [
# Specify full path to tmux socket (testing tmux instance must not
# interfere with user one)
'-S', socket_path,
# Force 256-color mode
'-2',
# Request verbose logging just in case
'-v',
# Specify configuration file
'-f', conf_file,
# Run bash three times
'new-session', 'bash --norc --noprofile -i', ';',
'new-window', 'bash --norc --noprofile -i', ';',
'new-window', 'bash --norc --noprofile -i', ';',
]
return do_terminal_tests(
tests=tests,
cmd=tmux_exe,
dim=dim,
args=args,
env=env,
cwd=VTERM_TEST_DIR,
fin_cb=tmux_fin_cb,
last_attempt_cb=print_tmux_logs,
)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -1,20 +1,17 @@
#!/bin/sh #!/bin/sh
. tests/common.sh . tests/shlib/common.sh
. tests/shlib/vterm.sh
enter_suite tmux enter_suite tmux
rm -rf tests/vterm_tmux VTERM_TEST_DIR="$ROOT/tests/vterm_tmux"
mkdir tests/vterm_tmux
mkdir tests/vterm_tmux/path
ln -s "$(which "${PYTHON}")" tests/vterm_tmux/path/python vterm_setup "$VTERM_TEST_DIR"
ln -s "$(which bash)" tests/vterm_tmux/path
ln -s "$(which env)" tests/vterm_tmux/path
ln -s "$(which cut)" tests/vterm_tmux/path
ln -s "$PWD/scripts/powerline-render" tests/vterm_tmux/path
ln -s "$PWD/scripts/powerline-config" tests/vterm_tmux/path
cp -r tests/terminfo tests/vterm_tmux ln -s "$(which env)" "$VTERM_TEST_DIR/path"
ln -s "$(which cut)" "$VTERM_TEST_DIR/path"
ln -s "$ROOT/scripts/powerline-render" "$VTERM_TEST_DIR/path"
ln -s "$ROOT/scripts/powerline-config" "$VTERM_TEST_DIR/path"
test_tmux() { test_tmux() {
if test "$PYTHON_IMPLEMENTATION" = PyPy; then if test "$PYTHON_IMPLEMENTATION" = PyPy; then
@ -25,17 +22,18 @@ test_tmux() {
if ! which "${POWERLINE_TMUX_EXE}" ; then if ! which "${POWERLINE_TMUX_EXE}" ; then
return 0 return 0
fi fi
ln -sf "$(which "${POWERLINE_TMUX_EXE}")" tests/vterm_tmux/path ln -sf "$(which "${POWERLINE_TMUX_EXE}")" "$VTERM_TEST_DIR/path/tmux"
f=tests/test_in_vterm/test_tmux.py f="$ROOT/tests/test_in_vterm/test_tmux.py"
if ! "${PYTHON}" $f ; then if ! "${PYTHON}" "$f" ; then
local test_name="$("$POWERLINE_TMUX_EXE" -V 2>&1 | cut -d' ' -f2)" local test_name="$("$POWERLINE_TMUX_EXE" -V 2>&1 | cut -d' ' -f2)"
fail "$test_name" F "Failed vterm test $f" fail "$test_name" F "Failed vterm test $f"
fi fi
} }
if test -z "$POWERLINE_TMUX_EXE" && test -d tests/bot-ci/deps/tmux ; then if test -z "$POWERLINE_TMUX_EXE" && test -d "$ROOT/tests/bot-ci/deps/tmux"
for tmux in tests/bot-ci/deps/tmux/tmux-*/tmux ; do then
export POWERLINE_TMUX_EXE="$PWD/$tmux" for tmux in "$ROOT"/tests/bot-ci/deps/tmux/tmux-*/tmux ; do
export POWERLINE_TMUX_EXE="$tmux"
test_tmux || true test_tmux || true
done done
else else
@ -43,10 +41,6 @@ else
test_tmux || true test_tmux || true
fi fi
if test $FAILED -eq 0 ; then vterm_shutdown "$VTERM_TEST_DIR"
rm -rf tests/vterm_tmux
else
echo "$FAIL_SUMMARY"
fi
exit_suite exit_suite

49
tests/test_in_vterm/test_vim.py Executable file
View File

@ -0,0 +1,49 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import os
import sys
import json
from time import sleep
from subprocess import check_call
from glob import glob1
from traceback import print_exc
from tests.modules.lib.terminal import (ExpectProcess, MutableDimensions,
do_terminal_tests, get_env)
VTERM_TEST_DIR = os.path.abspath('tests/vterm_vim')
def main(attempts=3):
vterm_path = os.path.join(VTERM_TEST_DIR, 'path')
vim_exe = os.path.join(vterm_path, 'vim')
env = get_env(vterm_path, VTERM_TEST_DIR)
dim = MutableDimensions(rows=50, cols=200)
tests = (
)
args = []
return do_terminal_tests(
tests=tests,
cmd=vim_exe,
dim=dim,
args=args,
env=env,
cwd=VTERM_TEST_DIR,
)
if __name__ == '__main__':
if main():
raise SystemExit(0)
else:
raise SystemExit(1)

41
tests/test_in_vterm/test_vim.sh Executable file
View File

@ -0,0 +1,41 @@
#!/bin/sh
. tests/shlib/common.sh
. tests/shlib/vterm.sh
. tests/shlib/vim.sh
enter_suite vim
VTERM_TEST_DIR="$ROOT/tests/vterm_vim"
vterm_setup "$VTERM_TEST_DIR"
test_vim() {
if test "$PYTHON_IMPLEMENTATION" != CPython ; then
# Can only link with cpython
return 0
fi
if ! which "$POWERLINE_VIM_EXE" ; then
return 0
fi
ln -sf "$(which "${POWERLINE_VIM_EXE}")" "$VTERM_TEST_DIR/path/vim"
f="$ROOT/tests/test_in_vterm/test_vim.py"
if ! "${PYTHON}" "$f" ; then
local test_name="$(LANG=C "$POWERLINE_VIM_EXE" --cmd 'echo version' --cmd qa 2>&1)"
fail "$test_name" F "Failed vterm test $f"
fi
}
if test -z "$POWERLINE_VIM_EXE" && test -d "$ROOT/tests/bot-ci/deps/vim"
then
for vim in "$OLD_VIM" "$NEW_VIM" ; do
export POWERLINE_VIM_EXE="$vim"
test_vim || true
done
else
export POWERLINE_VIM_EXE="${POWERLINE_VIM_EXE:-vim}"
test_vim || true
fi
vterm_shutdown "$VTERM_TEST_DIR"
exit_suite

10
tests/test_lint/test.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
. tests/shlib/common.sh
enter_suite lint
if ! "$PYTHON" "$ROOT/scripts/powerline-lint" -p "$ROOT/powerline/config_files" ; then
fail "test" F "Running powerline-lint failed"
fi
exit_suite

View File

@ -1,11 +1,11 @@
#!/bin/sh #!/bin/sh
. tests/common.sh . tests/shlib/common.sh
enter_suite python enter_suite python
for file in tests/test_*.py ; do for file in "$ROOT"/tests/test_python/test_*.py ; do
test_name="${file##*/test_}" test_name="${file##*/test_}"
if ! ${PYTHON} $file --verbose --catch ; then if ! "$PYTHON" "$file" --verbose --catch ; then
fail "${test_name%.py}" F "Failed test(s) from $file" fail "${test_name%.py}" F "Failed test(s) from $file"
fi fi
done done

View File

@ -13,8 +13,8 @@ else:
from powerline.commands.main import get_argparser, finish_args from powerline.commands.main import get_argparser, finish_args
from tests import TestCase from tests.modules import TestCase
from tests.lib import replace_attr from tests.modules.lib import replace_attr
class TestParser(TestCase): class TestParser(TestCase):
@ -127,7 +127,7 @@ class TestParser(TestCase):
}), }),
]: ]:
args = parser.parse_args(argv) args = parser.parse_args(argv)
finish_args({}, args) finish_args(parser, {}, args)
for key, val in expargs.items(): for key, val in expargs.items():
self.assertEqual(getattr(args, key), val) self.assertEqual(getattr(args, key), val)
for key, val in args.__dict__.items(): for key, val in args.__dict__.items():
@ -140,5 +140,5 @@ class TestParser(TestCase):
if __name__ == '__main__': if __name__ == '__main__':
from tests import main from tests.modules import main
main() main()

View File

@ -11,8 +11,8 @@ from shutil import rmtree
from powerline.lib.dict import mergedicts_copy as mdc from powerline.lib.dict import mergedicts_copy as mdc
from powerline import Powerline from powerline import Powerline
from tests import TestCase from tests.modules import TestCase
from tests.lib.config_mock import select_renderer, UT from tests.modules.lib.config_mock import select_renderer, UT
CONFIG_DIR = 'tests/config' CONFIG_DIR = 'tests/config'
@ -139,7 +139,7 @@ class WithConfigTree(object):
select_renderer(simpler_renderer=True) select_renderer(simpler_renderer=True)
self.p = TestPowerline( self.p = TestPowerline(
ext='test', ext='test',
renderer_module='tests.lib.config_mock', renderer_module='tests.modules.lib.config_mock',
**self.p_kwargs **self.p_kwargs
) )
if os.environ.get('POWERLINE_RUN_LINT_DURING_TESTS'): if os.environ.get('POWERLINE_RUN_LINT_DURING_TESTS'):
@ -266,5 +266,5 @@ class TestMerging(TestCase):
if __name__ == '__main__': if __name__ == '__main__':
from tests import main from tests.modules import main
main() main()

View File

@ -5,8 +5,8 @@ from time import sleep
from copy import deepcopy from copy import deepcopy
from functools import wraps from functools import wraps
from tests import TestCase from tests.modules import TestCase
from tests.lib.config_mock import get_powerline, add_watcher_events, UT from tests.modules.lib.config_mock import get_powerline, add_watcher_events, UT
config = { config = {
@ -315,5 +315,5 @@ class TestConfigReload(TestCase):
if __name__ == '__main__': if __name__ == '__main__':
from tests import main from tests.modules import main
main() main()

View File

@ -7,11 +7,12 @@ import os
from functools import wraps from functools import wraps
from copy import deepcopy from copy import deepcopy
import tests.vim as vim_module import tests.modules.vim as vim_module
from tests import TestCase from tests.modules import TestCase
from tests.lib.config_mock import get_powerline, get_powerline_raw, swap_attributes, UT from tests.modules.lib.config_mock import (get_powerline, get_powerline_raw,
from tests.lib import Args, replace_item swap_attributes, UT)
from tests.modules.lib import Args, replace_item
def highlighted_string(s, group, **kwargs): def highlighted_string(s, group, **kwargs):
@ -550,6 +551,28 @@ class TestDisplayCondition(TestRender):
self.assertRenderEqual(p, '{56} s1{6-}>>{--}', mode='m1') self.assertRenderEqual(p, '{56} s1{6-}>>{--}', mode='m1')
class TestOuterPadding(TestRender):
@add_args
def test_outer_padding_left(self, p, config):
config['themes/' + UT]['outer_padding'] = 5
self.assertRenderEqual(p, '{121} s{24}>>{344}g{4-}>>{--}', side='left')
@add_args
def test_outer_padding_right(self, p, config):
config['themes/' + UT]['outer_padding'] = 5
self.assertRenderEqual(p, '{4-}<<{344}f {--}', side='right')
@add_args
def test_outer_padding_ten(self, p, config):
config['themes/' + UT]['outer_padding'] = 10
self.assertRenderEqual(p, '{121} s {24}>>{344}g{34}>{34}|{344} f {--}', width=30)
@add_args
def test_outer_padding_zero(self, p, config):
config['themes/' + UT]['outer_padding'] = 0
self.assertRenderEqual(p, '{121}s {24}>>{344}g{34}>{34}|{344} f{--}', width=30)
class TestSegmentAttributes(TestRender): class TestSegmentAttributes(TestRender):
@add_args @add_args
def test_no_attributes(self, p, config): def test_no_attributes(self, p, config):
@ -775,7 +798,6 @@ class TestVim(TestCase):
def test_environ_update(self): def test_environ_update(self):
# Regression test: test that segment obtains environment from vim, not # Regression test: test that segment obtains environment from vim, not
# from os.environ. # from os.environ.
import tests.vim as vim_module
with vim_module._with('globals', powerline_config_paths=['/']): with vim_module._with('globals', powerline_config_paths=['/']):
from powerline.vim import VimPowerline from powerline.vim import VimPowerline
import powerline as powerline_module import powerline as powerline_module
@ -795,7 +817,7 @@ class TestVim(TestCase):
import powerline as powerline_module import powerline as powerline_module
with swap_attributes(config, powerline_module): with swap_attributes(config, powerline_module):
with get_powerline_raw(config, VimPowerline, replace_gcp=True) as powerline: with get_powerline_raw(config, VimPowerline, replace_gcp=True) as powerline:
powerline.add_local_theme('tests.matchers.always_true', { powerline.add_local_theme('tests.modules.matchers.always_true', {
'segment_data': { 'segment_data': {
'foo': { 'foo': {
'contents': '“bar”' 'contents': '“bar”'
@ -818,7 +840,7 @@ class TestVim(TestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'path'))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'vim_sys_path')))
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
@ -851,5 +873,5 @@ class TestLemonbar(TestRender):
if __name__ == '__main__': if __name__ == '__main__':
from tests import main from tests.modules import main
main() main()

View File

@ -21,8 +21,8 @@ from powerline.lib.shell import run_cmd
import powerline.lib.unicode as plu import powerline.lib.unicode as plu
from tests.lib import Pl, replace_attr from tests.modules.lib import Pl, replace_attr
from tests import TestCase, SkipTest from tests.modules import TestCase, SkipTest
try: try:
@ -704,7 +704,7 @@ class TestVCS(TestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
cls.powerline_old_cwd = os.getcwd() cls.powerline_old_cwd = os.getcwd()
os.chdir(os.path.dirname(__file__)) os.chdir(os.path.dirname(os.path.dirname(__file__)))
call(['git', 'init', '--quiet', GIT_REPO]) call(['git', 'init', '--quiet', GIT_REPO])
assert os.path.isdir(GIT_REPO) assert os.path.isdir(GIT_REPO)
call(['git', 'config', '--local', 'user.name', 'Foo'], cwd=GIT_REPO) call(['git', 'config', '--local', 'user.name', 'Foo'], cwd=GIT_REPO)
@ -736,5 +736,5 @@ class TestVCS(TestCase):
if __name__ == '__main__': if __name__ == '__main__':
from tests import main from tests.modules import main
main() main()

View File

@ -5,11 +5,11 @@ import os
from powerline.lib.config import ConfigLoader from powerline.lib.config import ConfigLoader
from tests import TestCase from tests.modules import TestCase
from tests.lib.fsconfig import FSTree from tests.modules.lib.fsconfig import FSTree
FILE_ROOT = os.path.join(os.path.dirname(__file__), 'cfglib') FILE_ROOT = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'cfglib')
class LoadedList(list): class LoadedList(list):
@ -48,5 +48,5 @@ class TestLoaderCondition(TestCase):
if __name__ == '__main__': if __name__ == '__main__':
from tests import main from tests.modules import main
main() main()

View File

@ -3,8 +3,8 @@ from __future__ import (unicode_literals, division, absolute_import, print_funct
import powerline.listers.i3wm as i3wm import powerline.listers.i3wm as i3wm
from tests.lib import Args, replace_attr, Pl from tests.modules.lib import Args, replace_attr, Pl
from tests import TestCase from tests.modules import TestCase
class TestI3WM(TestCase): class TestI3WM(TestCase):
@ -223,5 +223,5 @@ class TestI3WM(TestCase):
if __name__ == '__main__': if __name__ == '__main__':
from tests import main from tests.modules import main
main() main()

View File

@ -14,8 +14,8 @@ from shutil import rmtree
from powerline import finish_common_config, create_logger from powerline import finish_common_config, create_logger
from tests import TestCase from tests.modules import TestCase
from tests.lib import replace_attr from tests.modules.lib import replace_attr
TIMESTAMP_RE = r'\d{4}-\d\d-\d\d \d\d:\d\d:\d\d,\d{3}' TIMESTAMP_RE = r'\d{4}-\d\d-\d\d \d\d:\d\d:\d\d,\d{3}'
@ -454,7 +454,7 @@ def setUpModule():
global __file__ global __file__
old_cwd = os.getcwd() old_cwd = os.getcwd()
__file__ = os.path.abspath(__file__) __file__ = os.path.abspath(__file__)
os.chdir(os.path.dirname(__file__)) os.chdir(os.path.dirname(os.path.dirname(__file__)))
def tearDownModule(): def tearDownModule():
@ -463,5 +463,5 @@ def tearDownModule():
if __name__ == '__main__': if __name__ == '__main__':
from tests import main from tests.modules import main
main() main()

View File

@ -9,10 +9,10 @@ import os
import json import json
import logging import logging
import tests.vim as vim_module import tests.modules.vim as vim_module
from tests.lib import Args, urllib_read, replace_attr from tests.modules.lib import Args, urllib_read, replace_attr
from tests import TestCase from tests.modules import TestCase
from powerline import NotInterceptedError from powerline import NotInterceptedError
from powerline.segments.common import wthr from powerline.segments.common import wthr
@ -46,7 +46,7 @@ def get_logger(stream=None):
class TestVimConfig(TestCase): class TestVimConfig(TestCase):
def test_vim(self): def test_vim(self):
from powerline.vim import VimPowerline from powerline.vim import VimPowerline
cfg_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'powerline', 'config_files') cfg_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'powerline', 'config_files')
buffers = ( buffers = (
(('bufoptions',), {'buftype': 'help'}), (('bufoptions',), {'buftype': 'help'}),
(('bufname', '[Command Line]'), {}), (('bufname', '[Command Line]'), {}),
@ -101,7 +101,7 @@ class TestVimConfig(TestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'path'))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'vim_sys_path')))
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
@ -182,7 +182,7 @@ def setUpModule():
global saved_get_config_paths global saved_get_config_paths
import powerline import powerline
saved_get_config_paths = powerline.get_config_paths saved_get_config_paths = powerline.get_config_paths
path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'powerline', 'config_files') path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'powerline', 'config_files')
powerline.get_config_paths = lambda: [path] powerline.get_config_paths = lambda: [path]
old_cwd = os.getcwd() old_cwd = os.getcwd()
@ -197,5 +197,5 @@ def tearDownModule():
if __name__ == '__main__': if __name__ == '__main__':
from tests import main from tests.modules import main
main() main()

View File

@ -13,10 +13,11 @@ from powerline.segments import shell, tmux, pdb, i3wm
from powerline.lib.vcs import get_fallback_create_watcher from powerline.lib.vcs import get_fallback_create_watcher
from powerline.lib.unicode import out_u from powerline.lib.unicode import out_u
import tests.vim as vim_module import tests.modules.vim as vim_module
from tests.lib import Args, urllib_read, replace_attr, new_module, replace_module_module, replace_env, Pl from tests.modules.lib import (Args, urllib_read, replace_attr, new_module,
from tests import TestCase, SkipTest replace_module_module, replace_env, Pl)
from tests.modules import TestCase, SkipTest
def get_dummy_guess(**kwargs): def get_dummy_guess(**kwargs):
@ -1159,6 +1160,8 @@ class TestVim(TestCase):
self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info, override={'n': 'NORM'}), 'NORM') self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info, override={'n': 'NORM'}), 'NORM')
with vim_module._with('mode', 'i') as segment_info: with vim_module._with('mode', 'i') as segment_info:
self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info), 'INSERT') self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info), 'INSERT')
with vim_module._with('mode', 'i\0') as segment_info:
self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info), 'INSERT')
with vim_module._with('mode', chr(ord('V') - 0x40)) as segment_info: with vim_module._with('mode', chr(ord('V') - 0x40)) as segment_info:
self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info), 'V-BLCK') self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info), 'V-BLCK')
self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info, override={'^V': 'VBLK'}), 'VBLK') self.assertEqual(self.vim.mode(pl=pl, segment_info=segment_info, override={'^V': 'VBLK'}), 'VBLK')
@ -1288,7 +1291,11 @@ class TestVim(TestCase):
pl = Pl() pl = Pl()
segment_info = vim_module._get_segment_info() segment_info = vim_module._get_segment_info()
self.assertEqual(self.vim.file_size(pl=pl, segment_info=segment_info), '0 B') self.assertEqual(self.vim.file_size(pl=pl, segment_info=segment_info), '0 B')
with vim_module._with('buffer', os.path.join(os.path.dirname(__file__), 'empty')) as segment_info: with vim_module._with(
'buffer',
os.path.join(
os.path.dirname(os.path.dirname(__file__)), 'empty')
) as segment_info:
self.assertEqual(self.vim.file_size(pl=pl, segment_info=segment_info), '0 B') self.assertEqual(self.vim.file_size(pl=pl, segment_info=segment_info), '0 B')
def test_file_opts(self): def test_file_opts(self):
@ -1596,7 +1603,7 @@ class TestVim(TestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'path'))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'vim_sys_path')))
from powerline.segments import vim from powerline.segments import vim
cls.vim = vim cls.vim = vim
from powerline.segments.common import vcs from powerline.segments.common import vcs
@ -1661,7 +1668,7 @@ def setUpModule():
global __file__ global __file__
old_cwd = os.getcwd() old_cwd = os.getcwd()
__file__ = os.path.abspath(__file__) __file__ = os.path.abspath(__file__)
os.chdir(os.path.dirname(__file__)) os.chdir(os.path.dirname(os.path.dirname(__file__)))
def tearDownModule(): def tearDownModule():
@ -1670,5 +1677,5 @@ def tearDownModule():
if __name__ == '__main__': if __name__ == '__main__':
from tests import main from tests.modules import main
main() main()

View File

@ -6,10 +6,10 @@ import sys
from functools import partial from functools import partial
import tests.vim as vim_module import tests.modules.vim as vim_module
from tests.lib import Pl from tests.modules.lib import Pl
from tests import TestCase from tests.modules import TestCase
class TestVim(TestCase): class TestVim(TestCase):
@ -22,7 +22,7 @@ class TestVim(TestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'path'))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'vim_sys_path')))
from powerline.selectors import vim from powerline.selectors import vim
cls.vim = vim cls.vim = vim
@ -32,5 +32,5 @@ class TestVim(TestCase):
if __name__ == '__main__': if __name__ == '__main__':
from tests import main from tests.modules import main
main() main()

View File

@ -13,7 +13,7 @@ from powerline.lib.watcher.uv import UvNotFound
from powerline import get_fallback_logger from powerline import get_fallback_logger
from powerline.lib.monotonic import monotonic from powerline.lib.monotonic import monotonic
from tests import TestCase, SkipTest from tests.modules import TestCase, SkipTest
INOTIFY_DIR = 'inotify' + os.path.basename(os.environ.get('PYTHON', '')) INOTIFY_DIR = 'inotify' + os.path.basename(os.environ.get('PYTHON', ''))
@ -231,7 +231,7 @@ old_cwd = None
def setUpModule(): def setUpModule():
global old_cwd global old_cwd
old_cwd = os.getcwd() old_cwd = os.getcwd()
os.chdir(os.path.dirname(__file__)) os.chdir(os.path.dirname(os.path.dirname(__file__)))
os.mkdir(INOTIFY_DIR) os.mkdir(INOTIFY_DIR)
@ -241,5 +241,5 @@ def tearDownModule():
if __name__ == '__main__': if __name__ == '__main__':
from tests import main from tests.modules import main
main() main()

View File

@ -1,7 +0,0 @@
print ('cd ' + 'tests/shell/3rd') # Start of the test marker
bool 42
bool 44
class Test(object):
pass
exit

View File

@ -32,7 +32,7 @@ ABOVE_FULL='[{
set_theme default_leftonly set_theme default_leftonly
export VIRTUAL_ENV= export VIRTUAL_ENV=
source powerline/bindings/bash/powerline.sh source powerline/bindings/bash/powerline.sh
cd tests/shell/3rd cd "$TEST_ROOT"/3rd
cd .git cd .git
cd .. cd ..
VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"

View File

@ -8,7 +8,7 @@ set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false
set_theme default_leftonly set_theme default_leftonly
. powerline/bindings/shell/powerline.sh . powerline/bindings/shell/powerline.sh
export VIRTUAL_ENV= export VIRTUAL_ENV=
cd tests/shell/3rd cd "$TEST_ROOT"/3rd
cd .git cd .git
cd .. cd ..
VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"

View File

@ -8,7 +8,7 @@ set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false
set_theme default_leftonly set_theme default_leftonly
. powerline/bindings/shell/powerline.sh . powerline/bindings/shell/powerline.sh
export VIRTUAL_ENV= export VIRTUAL_ENV=
cd tests/shell/3rd cd "$TEST_ROOT"/3rd
cd .git cd .git
cd .. cd ..
VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"

View File

@ -37,7 +37,7 @@ while jobs | grep fish_update_completions
end end
powerline-setup powerline-setup
setenv VIRTUAL_ENV setenv VIRTUAL_ENV
cd tests/shell/3rd cd "$TEST_ROOT"/3rd
cd .git cd .git
cd .. cd ..
setenv VIRTUAL_ENV "$HOME/.virtenvs/some-virtual-environment" setenv VIRTUAL_ENV "$HOME/.virtenvs/some-virtual-environment"

View File

@ -0,0 +1,7 @@
print ('cd ' + '"$TEST_ROOT"/3rd') # Start of the test marker
bool 42
bool 44
class Test(object):
pass
exit

View File

@ -8,7 +8,7 @@ set_theme default_leftonly
set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false
. powerline/bindings/shell/powerline.sh . powerline/bindings/shell/powerline.sh
export VIRTUAL_ENV= export VIRTUAL_ENV=
cd tests/shell/3rd cd "$TEST_ROOT"/3rd
cd .git cd .git
cd .. cd ..
VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment"

View File

@ -5,7 +5,8 @@ set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false
POWERLINE_CONFIG_OVERRIDES = 'ext.shell.theme=default_leftonly' POWERLINE_CONFIG_OVERRIDES = 'ext.shell.theme=default_leftonly'
. powerline/bindings/rc/powerline.rc . powerline/bindings/rc/powerline.rc
VIRTUAL_ENV = () VIRTUAL_ENV = ()
cd tests/shell/3rd cd $TEST_ROOT/3rd
true cd "$TEST_ROOT"/3rd # Test start marker
cd .git cd .git
cd .. cd ..
VIRTUAL_ENV = '/home/foo/.virtenvs/some-virtual-environment' VIRTUAL_ENV = '/home/foo/.virtenvs/some-virtual-environment'

View File

@ -2,7 +2,7 @@ setenv POWERLINE_THEME_OVERRIDES "default_leftonly.segment_data.hostname.args.on
setenv POWERLINE_CONFIG_OVERRIDES "ext.shell.theme=default_leftonly" setenv POWERLINE_CONFIG_OVERRIDES "ext.shell.theme=default_leftonly"
source powerline/bindings/tcsh/powerline.tcsh source powerline/bindings/tcsh/powerline.tcsh
unsetenv VIRTUAL_ENV unsetenv VIRTUAL_ENV
cd tests/shell/3rd cd "$TEST_ROOT"/3rd
cd .git cd .git
cd .. cd ..
setenv VIRTUAL_ENV "/home/foo/.virtenvs/some-virtual-environment" setenv VIRTUAL_ENV "/home/foo/.virtenvs/some-virtual-environment"

Some files were not shown because too many files have changed in this diff Show More