Release 2.7

- Added ALE support.
- Added mocp support.
- Added awesome 4+ support.
- Added support for `$pipestatus` in bash.
- Recognize terminal-job mode.
- Fixed i3 bindings when both i3-py and i3ipc are installed.
- Fixed i3 bar bindings.
- Fixed checking for battery in WSL.
- Fixed spotify segment on Mac OS.
- Fixed compiling C client with GCC-7.
This commit is contained in:
Foo 2018-08-12 22:41:44 +03:00
commit 3b85be6836
63 changed files with 1108 additions and 236 deletions

5
.gitignore vendored
View File

@ -10,4 +10,7 @@ build
message.fail message.fail
client/powerline /client/powerline
/tests/tmp
/tests/status

View File

@ -1,4 +1,5 @@
sudo: false sudo: false
dist: trusty
cache: cache:
directories: directories:
- $HOME/.cache/pip - $HOME/.cache/pip
@ -17,19 +18,25 @@ addons:
language: python language: python
install: tests/install.sh install: tests/install.sh
script: tests/test.sh script: tests/test.sh
matrix: jobs:
include: include:
- python: "2.6" - stage: UCS2 python
- python: "2.7" python: "2.7"
- python: "3.2"
- python: "3.3"
- python: "3.4"
- python: "3.5"
- python: "pypy"
- python: "pypy3"
- python: "2.7"
env: >- env: >-
USE_UCS2_PYTHON=1 USE_UCS2_PYTHON=1
UCS2_PYTHON_VARIANT="2.7" UCS2_PYTHON_VARIANT="2.7"
- stage: Old Python
python: "2.6"
- python: "3.2"
- stage: PyPy
python: "pypy"
- python: "pypy3"
- stage: Latest Python
python: "2.7"
- python: "3.6"
- stage: Intermediate versions
python: "3.3"
- python: "3.4"
- python: "3.5"
# vim: et # vim: et

View File

@ -6,8 +6,8 @@ Powerline
:Version: beta :Version: beta
**Powerline is a statusline plugin for vim, and provides statuslines and **Powerline is a statusline plugin for vim, and provides statuslines and
prompts for several other applications, including zsh, bash, tmux, IPython, prompts for several other applications, including zsh, bash, fish, tmux,
Awesome, i3 and Qtile.** IPython, Awesome, i3 and Qtile.**
* `Support forum`_ (powerline-support@googlegroups.com) * `Support forum`_ (powerline-support@googlegroups.com)
* `Development discussion`_ (powerline-dev@googlegroups.com) * `Development discussion`_ (powerline-dev@googlegroups.com)

View File

@ -42,7 +42,7 @@ void do_write(int sd, const char *raw, size_t len) {
} }
} }
inline size_t true_sun_len(const struct sockaddr_un *ptr) { static inline size_t true_sun_len(const struct sockaddr_un *ptr) {
#ifdef __linux__ #ifdef __linux__
/* Because SUN_LEN uses strlen and abstract namespace paths begin /* Because SUN_LEN uses strlen and abstract namespace paths begin
* with a null byte, SUN_LEN is broken for these. Passing the full * with a null byte, SUN_LEN is broken for these. Passing the full
@ -71,7 +71,7 @@ inline size_t true_sun_len(const struct sockaddr_un *ptr) {
#endif #endif
#define ADDRESS_SIZE sizeof(ADDRESS_TEMPLATE) + (sizeof(uid_t) * 4) #define ADDRESS_SIZE sizeof(ADDRESS_TEMPLATE) + (sizeof(uid_t) * 4)
#define NUM_ARGS_SIZE (sizeof(int) * 2) #define NUM_ARGS_SIZE (sizeof(int) * 2 + 1)
#define BUF_SIZE 4096 #define BUF_SIZE 4096
#define NEW_ARGV_SIZE 200 #define NEW_ARGV_SIZE 200
@ -88,6 +88,7 @@ int main(int argc, char *argv[]) {
char *wd = NULL; char *wd = NULL;
char **envp; char **envp;
const char *address; const char *address;
int len;
if (argc < 2) { if (argc < 2) {
printf("Must provide at least one argument.\n"); printf("Must provide at least one argument.\n");
@ -122,8 +123,8 @@ int main(int argc, char *argv[]) {
execvp("powerline-render", newargv); execvp("powerline-render", newargv);
} }
snprintf(num_args, NUM_ARGS_SIZE, "%x", argc - 1); len = snprintf(num_args, NUM_ARGS_SIZE, "%x", argc - 1);
do_write(sd, num_args, strlen(num_args)); do_write(sd, num_args, len);
do_write(sd, eof, 1); do_write(sd, eof, 1);
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {

View File

@ -9,6 +9,12 @@ Vim segments
Plugin-specific segments Plugin-specific segments
======================== ========================
Asynchronous Linter Engine (ALE) segments
-----------------------------------------
.. automodule:: powerline.segments.vim.plugin.ale
:members:
Syntastic segments Syntastic segments
------------------ ------------------

View File

@ -41,7 +41,7 @@ Generic requirements
.. _repository-root: .. _repository-root:
.. note:: .. note::
When using ``pip`` ``{repository_root}`` directory referenced in When using ``pip``, the ``{repository_root}`` directory referenced in
documentation may be found using ``pip show powerline-status``. In the output documentation may be found using ``pip show powerline-status``. In the output
of ``pip show`` there is a line like ``Location: {path}``, that ``{path}`` is of ``pip show`` there is a line like ``Location: {path}``, that ``{path}`` is
``{repository_root}``. Unless it is ``--editable`` installation this is only ``{repository_root}``. Unless it is ``--editable`` installation this is only

View File

@ -60,12 +60,12 @@ with any coding font.
#. Move the symbol font to a valid X font path. Valid font paths can be #. Move the symbol font to a valid X font path. Valid font paths can be
listed with ``xset q``:: listed with ``xset q``::
mv PowerlineSymbols.otf ~/.fonts/ mv PowerlineSymbols.otf ~/.local/share/fonts/
#. Update font cache for the path the font was moved to (root priveleges may be #. Update font cache for the path the font was moved to (root priveleges may be
needed to update cache for the system-wide paths):: needed to update cache for the system-wide paths)::
fc-cache -vf ~/.fonts/ fc-cache -vf ~/.local/share/fonts/
#. Install the fontconfig file. For newer versions of fontconfig the config #. Install the fontconfig file. For newer versions of fontconfig the config
path is ``~/.config/fontconfig/conf.d/``, for older versions its path is ``~/.config/fontconfig/conf.d/``, for older versions its
@ -92,12 +92,12 @@ After downloading font the following should be done:
#. Move the patched font to a valid X font path. Valid font paths can be #. Move the patched font to a valid X font path. Valid font paths can be
listed with ``xset q``:: listed with ``xset q``::
mv 'SomeFont for Powerline.otf' ~/.fonts/ mv 'SomeFont for Powerline.otf' ~/.local/share/fonts/
#. Update font cache for the path the font was moved to (root priveleges may be #. Update font cache for the path the font was moved to (root privileges may be
needed for updating font cache for some paths):: needed for updating font cache for some paths)::
fc-cache -vf ~/.fonts/ fc-cache -vf ~/.local/share/fonts/
After installing patched font terminal emulator, GVim or whatever application After installing patched font terminal emulator, GVim or whatever application
powerline should work with must be configured to use the patched font. The powerline should work with must be configured to use the patched font. The

View File

@ -143,6 +143,40 @@ started from.*
Shell issues Shell issues
============ ============
Pipe status segment displays only last value in bash
----------------------------------------------------
Make sure that powerline command that sets prompt appears the very first in
``$PROMPT_COMMAND``. To do this ``powerline.sh`` needs to be sourced the very
last, after all other users of ``$PROMPT_COMMAND``.
Bash prompt stopped updating
----------------------------
Make sure that powerline commands appear in ``$PROMPT_COMMAND``: some users of
``$PROMPT_COMMAND`` have a habit of overwriting the value instead of
prepending/appending to it. All powerline commands start with ``_powerline`` or
``powerline``, e.g. ``_powerline_set_prompt``.
Bash prompt does not show last exit code
----------------------------------------
There are two possibilities here:
* You are using ``default`` theme in place of ``default_leftonly``. Unlike
``default_leftonly`` ``default`` theme was designed for shells with right
prompt support (e.g. zsh, tcsh, fish) and status in question is supposed to be
shown on the right side which bash cannot display.
* There is some other user of ``$PROMPT_COMMAND`` which prepended to this
variable, but did not bother keeping the exit code. For the best experience
powerline must appear first in ``$PROMPT_COMMAND`` which may be achieved by
sourcing powerline bindings the last.
.. note::
Resourcing bash bindings will not resolve the problem unless you clear
powerline commands from ``$PROMPT_COMMAND`` first.
When sourcing shell bindings it complains about missing command or file When sourcing shell bindings it complains about missing command or file
----------------------------------------------------------------------- -----------------------------------------------------------------------

View File

@ -27,7 +27,7 @@ The colors look weird in iTerm2!
* The arrows may have the wrong colors if you have changed the “minimum * The arrows may have the wrong colors if you have changed the “minimum
contrast” slider in the color tab of your OS X settings. contrast” slider in the color tab of your OS X settings.
* Please disable background transparency to resolve this issue. * If you're using transparency, check “Keep background colors opaque”.
Statusline is getting wrapped to the next line in iTerm2 Statusline is getting wrapped to the next line in iTerm2
-------------------------------------------------------- --------------------------------------------------------

View File

@ -8,7 +8,7 @@ Application-specific requirements
Vim plugin requirements Vim plugin requirements
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
The vim plugin requires a vim version with Python support compiled in. Presense The vim plugin requires a vim version with Python support compiled in. Presence
of Python support in Vim can be checked by running ``vim --version | grep of Python support in Vim can be checked by running ``vim --version | grep
+python``. +python``.

View File

@ -5,7 +5,7 @@ Window manager widgets
Awesome widget Awesome widget
============== ==============
.. note:: Powerline currently only supports awesome 3.5. .. note:: Powerline currently only supports awesome 3.5 and 4+.
.. note:: The Powerline widget will spawn a shell script that runs in the .. note:: The Powerline widget will spawn a shell script that runs in the
background and updates the statusline with ``awesome-client``. background and updates the statusline with ``awesome-client``.
@ -23,8 +23,18 @@ Then add the ``powerline_widget`` to ``wibox``:
.. code-block:: lua .. code-block:: lua
-- awesome3.5
right_layout:add(powerline_widget) right_layout:add(powerline_widget)
-- awesome4+
s.mywibox:setup {
...
{ -- Right widgets
...
powerline_widget,
},
}
Qtile widget Qtile widget
============ ============
@ -82,20 +92,11 @@ All ``powerline-lemonbar.py`` arguments:
I3 bar I3 bar
====== ======
.. note:: Add the following to :file:`~/.config/i3/config`::
As the patch to include background-colors in i3bar is likely not to be
merged, it is recommended to instead run ``bar`` (see above). The source for
i3bgbar is however still available `here
<https://github.com/S0lll0s/i3bgbar>`_.
Add the following to :file:`~/.i3/config`::
bar { bar {
i3bar_command i3bgbar
status_command python /path/to/powerline/bindings/i3/powerline-i3.py status_command python /path/to/powerline/bindings/i3/powerline-i3.py
font pango:PowerlineFont 12 font pango:PowerlineFont 12
} }
where ``i3bgbar`` may be replaced with the path to the custom i3bar binary and where ``PowerlineFont`` is any system font with powerline support.
``PowerlineFont`` is any system font with powerline support.

View File

@ -6,5 +6,10 @@ powerline_widget:set_align('right')
function powerline(mode, widget) end function powerline(mode, widget) end
awful.util.spawn_with_shell('powerline-daemon -q') if string.find(awesome.version, 'v4') then
awful.util.spawn_with_shell('powerline wm.awesome') awful.spawn.with_shell('powerline-daemon -q')
awful.spawn.with_shell('powerline wm.awesome')
else
awful.util.spawn_with_shell('powerline-daemon -q')
awful.util.spawn_with_shell('powerline wm.awesome')
end

View File

@ -27,6 +27,43 @@ _powerline_tmux_set_pwd() {
fi fi
} }
_powerline_return() {
return $1
}
_POWERLINE_HAS_PIPESTATUS="$(
_powerline_return 0 | _powerline_return 43
test "${PIPESTATUS[*]}" = "0 43"
echo "$?"
)"
_powerline_has_pipestatus() {
return $_POWERLINE_HAS_PIPESTATUS
}
_powerline_status_wrapper() {
local last_exit_code=$? last_pipe_status=( "${PIPESTATUS[@]}" )
if ! _powerline_has_pipestatus \
|| test "${#last_pipe_status[@]}" -eq "0" \
|| test "$last_exit_code" != "${last_pipe_status[$(( ${#last_pipe_status[@]} - 1 ))]}" ; then
last_pipe_status=()
fi
"$@" $last_exit_code "${last_pipe_status[*]}"
return $last_exit_code
}
_powerline_add_status_wrapped_command() {
local action="$1" ; shift
local cmd="$1" ; shift
full_cmd="_powerline_status_wrapper $cmd"
if test "$action" = "append" ; then
PROMPT_COMMAND="$PROMPT_COMMAND"$'\n'"$full_cmd"
else
PROMPT_COMMAND="$full_cmd"$'\n'"$PROMPT_COMMAND"
fi
}
_powerline_tmux_set_columns() { _powerline_tmux_set_columns() {
_powerline_tmux_setenv COLUMNS "${COLUMNS:-`_powerline_columns_fallback`}" _powerline_tmux_setenv COLUMNS "${COLUMNS:-`_powerline_columns_fallback`}"
} }
@ -40,41 +77,53 @@ _powerline_init_tmux_support() {
_powerline_tmux_set_columns _powerline_tmux_set_columns
test "$PROMPT_COMMAND" != "${PROMPT_COMMAND/_powerline_tmux_set_pwd}" \ test "$PROMPT_COMMAND" != "${PROMPT_COMMAND/_powerline_tmux_set_pwd}" \
|| PROMPT_COMMAND="${PROMPT_COMMAND}"$'\n_powerline_tmux_set_pwd' || _powerline_add_status_wrapped_command append _powerline_tmux_set_pwd
fi fi
} }
_powerline_local_prompt() { _powerline_local_prompt() {
# Arguments: side, renderer_module arg, last_exit_code, jobnum, local theme # Arguments:
# 1: side
# 2: renderer_module arg
# 3: last_exit_code
# 4: last_pipe_status
# 5: jobnum
# 6: local theme
"$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS shell $1 \ "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS shell $1 \
$2 \ $2 \
--last-exit-code=$3 \ --last-exit-code=$3 \
--jobnum=$4 \ --last-pipe-status="$4" \
--jobnum=$5 \
--renderer-arg="client_id=$$" \ --renderer-arg="client_id=$$" \
--renderer-arg="local_theme=$5" --renderer-arg="local_theme=$6"
} }
_powerline_prompt() { _powerline_prompt() {
# Arguments: side, last_exit_code, jobnum # Arguments:
# 1: side
# 2: last_exit_code
# 3: last_pipe_status
# 4: jobnum
"$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS shell $1 \ "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS shell $1 \
--width="${COLUMNS:-$(_powerline_columns_fallback)}" \ --width="${COLUMNS:-$(_powerline_columns_fallback)}" \
-r.bash \ -r.bash \
--last-exit-code=$2 \ --last-exit-code=$2 \
--jobnum=$3 \ --last-pipe-status="$3" \
--jobnum=$4 \
--renderer-arg="client_id=$$" --renderer-arg="client_id=$$"
} }
_powerline_set_prompt() { _powerline_set_prompt() {
local last_exit_code=$? local last_exit_code=$1 ; shift
local last_pipe_status=$1 ; shift
local jobnum="$(jobs -p|wc -l)" local jobnum="$(jobs -p|wc -l)"
PS1="$(_powerline_prompt aboveleft $last_exit_code $jobnum)" PS1="$(_powerline_prompt aboveleft $last_exit_code "$last_pipe_status" $jobnum)"
if test -n "$POWERLINE_SHELL_CONTINUATION$POWERLINE_BASH_CONTINUATION" ; then if test -n "$POWERLINE_SHELL_CONTINUATION$POWERLINE_BASH_CONTINUATION" ; then
PS2="$(_powerline_local_prompt left -r.bash $last_exit_code $jobnum continuation)" PS2="$(_powerline_local_prompt left -r.bash $last_exit_code "$last_pipe_status" $jobnum continuation)"
fi fi
if test -n "$POWERLINE_SHELL_SELECT$POWERLINE_BASH_SELECT" ; then if test -n "$POWERLINE_SHELL_SELECT$POWERLINE_BASH_SELECT" ; then
PS3="$(_powerline_local_prompt left '' $last_exit_code $jobnum select)" PS3="$(_powerline_local_prompt left '' $last_exit_code "$last_pipe_status" $jobnum select)"
fi fi
return $last_exit_code
} }
_powerline_setup_prompt() { _powerline_setup_prompt() {
@ -83,9 +132,9 @@ _powerline_setup_prompt() {
POWERLINE_COMMAND="$("$POWERLINE_CONFIG_COMMAND" shell command)" POWERLINE_COMMAND="$("$POWERLINE_CONFIG_COMMAND" shell command)"
fi fi
test "$PROMPT_COMMAND" != "${PROMPT_COMMAND%_powerline_set_prompt*}" \ test "$PROMPT_COMMAND" != "${PROMPT_COMMAND%_powerline_set_prompt*}" \
|| PROMPT_COMMAND=$'_powerline_set_prompt\n'"${PROMPT_COMMAND}" || _powerline_add_status_wrapped_command prepend _powerline_set_prompt
PS2="$(_powerline_local_prompt left -r.bash 0 0 continuation)" PS2="$(_powerline_local_prompt left -r.bash 0 0 0 continuation)"
PS3="$(_powerline_local_prompt left '' 0 0 select)" PS3="$(_powerline_local_prompt left '' 0 0 0 select)"
} }
if test -z "${POWERLINE_CONFIG_COMMAND}" ; then if test -z "${POWERLINE_CONFIG_COMMAND}" ; then

View File

@ -164,7 +164,10 @@ def init_tmux_environment(pl, args, set_tmux_environment=set_tmux_environment):
# But it does not support empty attributes as well. # But it does not support empty attributes as well.
or 'none')) or 'none'))
else: else:
set_tmux_environment(varname, 'colour' + str(get_highlighting(group)[attr][0])) if powerline.common_config['term_truecolor']:
set_tmux_environment(varname, '#{0:06x}'.format(get_highlighting(group)[attr][1]))
else:
set_tmux_environment(varname, 'colour' + str(get_highlighting(group)[attr][0]))
left_dividers = powerline.renderer.theme.dividers['left'] left_dividers = powerline.renderer.theme.dividers['left']
set_tmux_environment('_POWERLINE_LEFT_HARD_DIVIDER', left_dividers['hard']) set_tmux_environment('_POWERLINE_LEFT_HARD_DIVIDER', left_dividers['hard'])

View File

@ -7,37 +7,44 @@ import time
from threading import Lock from threading import Lock
import i3 from powerline.bindings.wm import get_i3_connection, i3_subscribe
from powerline import Powerline from powerline import Powerline
from powerline.lib.monotonic import monotonic from powerline.lib.monotonic import monotonic
class I3Powerline(Powerline):
'''Powerline child for i3bar
Currently only changes the default log target.
'''
default_log_stream = sys.stderr
if __name__ == '__main__': if __name__ == '__main__':
name = 'wm' name = 'wm'
if len(sys.argv) > 1: if len(sys.argv) > 1:
name = sys.argv[1] name = sys.argv[1]
powerline = Powerline(name, renderer_module='i3bar') powerline = I3Powerline(name, renderer_module='i3bar')
powerline.update_renderer() powerline.update_renderer()
interval = 0.5 interval = 0.5
print ('{"version": 1, "custom_workspace": true}') print ('{"version": 1}')
print ('[') print ('[')
print ('\t[[],[]]') print ('[]')
lock = Lock() lock = Lock()
def render(event=None, data=None, sub=None): def render(event=None, data=None, sub=None):
global lock global lock
with lock: with lock:
s = '[\n' + powerline.render(side='right')[:-2] + '\n]\n' print (',[' + powerline.render()[:-1] + ']')
s += ',[\n' + powerline.render(side='left')[:-2] + '\n]'
print (',[\n' + s + '\n]')
sys.stdout.flush() sys.stdout.flush()
sub = i3.Subscription(render, 'workspace') i3 = get_i3_connection()
i3_subscribe(i3, 'workspace', render)
while True: while True:
start_time = monotonic() start_time = monotonic()

View File

@ -14,6 +14,44 @@ DEFAULT_UPDATE_INTERVAL = 0.5
conn = None conn = None
def i3_subscribe(conn, event, callback):
'''Subscribe to i3 workspace event
:param conn:
Connection returned by :py:func:`get_i3_connection`.
:param str event:
Event to subscribe to, e.g. ``'workspace'``.
:param func callback:
Function to run on event.
'''
try:
import i3ipc
except ImportError:
import i3
conn.Subscription(callback, event)
return
else:
pass
conn.on(event, callback)
from threading import Thread
class I3Thread(Thread):
daemon = True
def __init__(self, conn):
super(I3Thread, self).__init__()
self.__conn = conn
def run(self):
self.__conn.main()
thread = I3Thread(conn=conn)
thread.start()
def get_i3_connection(): def get_i3_connection():
'''Return a valid, cached i3 Connection instance '''Return a valid, cached i3 Connection instance
''' '''

View File

@ -117,7 +117,8 @@
"r": "PROMPT", "r": "PROMPT",
"rm": "-MORE-", "rm": "-MORE-",
"r?": "CNFIRM", "r?": "CNFIRM",
"!": "!SHELL" "!": "!SHELL",
"t": "TERM "
} }
} }
}, },

View File

@ -115,7 +115,8 @@
"r": "PROMPT", "r": "PROMPT",
"rm": "-MORE-", "rm": "-MORE-",
"r?": "CNFIRM", "r?": "CNFIRM",
"!": "!SHELL" "!": "!SHELL",
"t": "TERM "
} }
} }
}, },

View File

@ -115,7 +115,8 @@
"r": "PROMPT", "r": "PROMPT",
"rm": "-MORE-", "rm": "-MORE-",
"r?": "CNFIRM", "r?": "CNFIRM",
"!": "!SHELL" "!": "!SHELL",
"t": "TERM "
} }
} }
}, },

View File

@ -129,7 +129,8 @@
"r": "PROMPT", "r": "PROMPT",
"rm": "-MORE-", "rm": "-MORE-",
"r?": "CNFIRM", "r?": "CNFIRM",
"!": "!SHELL" "!": "!SHELL",
"t": "TERM "
} }
} }
}, },

View File

@ -26,7 +26,7 @@
"priority": 20 "priority": 20
}, },
{ {
"function": "powerline.segments.shell.last_status", "function": "powerline.segments.shell.last_pipe_status",
"priority": 10 "priority": 10
} }
] ]

View File

@ -115,7 +115,8 @@
"r": "PROMPT", "r": "PROMPT",
"rm": "-MORE-", "rm": "-MORE-",
"r?": "CNFIRM", "r?": "CNFIRM",
"!": "!SHELL" "!": "!SHELL",
"t": "TERM "
} }
} }
}, },

View File

@ -115,7 +115,8 @@
"r": "PROMPT", "r": "PROMPT",
"rm": "-MORE-", "rm": "-MORE-",
"r?": "CNFIRM", "r?": "CNFIRM",
"!": "!SHELL" "!": "!SHELL",
"t": "TERM "
} }
} }
}, },

View File

@ -29,9 +29,8 @@ class I3barRenderer(Renderer):
segment['color'] = '#{0:06x}'.format(fg[1]) segment['color'] = '#{0:06x}'.format(fg[1])
if bg is not None: if bg is not None:
if bg is not False and bg[1] is not False: if bg is not False and bg[1] is not False:
segment['background_color'] = '#{0:06x}'.format(bg[1]) segment['background'] = '#{0:06x}'.format(bg[1])
# i3bar “pseudo json” requires one line at a time return json.dumps(segment) + ','
return json.dumps(segment) + ',\n'
renderer = I3barRenderer renderer = I3barRenderer

View File

@ -48,12 +48,18 @@ class TmuxRenderer(Renderer):
if fg is False or fg[0] is False: if fg is False or fg[0] is False:
tmux_attrs += ['fg=default'] tmux_attrs += ['fg=default']
else: else:
tmux_attrs += ['fg=colour' + str(fg[0])] if self.term_truecolor and fg[1]:
tmux_attrs += ['fg=#{0:06x}'.format(int(fg[1]))]
else:
tmux_attrs += ['fg=colour' + str(fg[0])]
if bg is not None: if bg is not None:
if bg is False or bg[0] is False: if bg is False or bg[0] is False:
tmux_attrs += ['bg=default'] tmux_attrs += ['bg=default']
else: else:
tmux_attrs += ['bg=colour' + str(bg[0])] if self.term_truecolor and bg[1]:
tmux_attrs += ['bg=#{0:06x}'.format(int(bg[1]))]
else:
tmux_attrs += ['bg=colour' + str(bg[0])]
if attrs is not None: if attrs is not None:
tmux_attrs += attrs_to_tmux_attrs(attrs) tmux_attrs += attrs_to_tmux_attrs(attrs)
return '#[' + ','.join(tmux_attrs) + ']' return '#[' + ','.join(tmux_attrs) + ']'

View File

@ -114,6 +114,21 @@ def _fetch_battery_info(pl):
return (energy * 100.0 / energy_full), state return (energy * 100.0 / energy_full), state
return _get_battery_status return _get_battery_status
pl.debug('Not using /sys/class/power_supply as no batteries were found') pl.debug('Not using /sys/class/power_supply as no batteries were found')
else:
pl.debug("Checking for first capacity battery percentage")
for batt in os.listdir('/sys/class/power_supply'):
if os.path.exists('/sys/class/power_supply/{0}/capacity'.format(batt)):
def _get_battery_perc(pl):
state = True
with open('/sys/class/power_supply/{0}/capacity'.format(batt), 'r') as f:
perc = int(f.readline().split()[0])
try:
with open(linux_status_fmt.format(batt), 'r') as f:
state &= (f.readline().strip() != 'Discharging')
except IOError:
state = None
return perc, state
return _get_battery_perc
else: else:
pl.debug('Not using /sys/class/power_supply: no directory') pl.debug('Not using /sys/class/power_supply: no directory')

View File

@ -159,7 +159,8 @@ username = False
_geteuid = getattr(os, 'geteuid', lambda: 1) _geteuid = getattr(os, 'geteuid', lambda: 1)
def user(pl, hide_user=None, hide_domain=False): @requires_segment_info
def user(pl, segment_info, hide_user=None, hide_domain=False):
'''Return the current user. '''Return the current user.
:param str hide_user: :param str hide_user:
@ -172,6 +173,11 @@ def user(pl, hide_user=None, hide_domain=False):
Highlight groups used: ``superuser`` or ``user``. It is recommended to define all highlight groups. Highlight groups used: ``superuser`` or ``user``. It is recommended to define all highlight groups.
''' '''
global username global username
if (
segment_info['environ'].get('_POWERLINE_RUNNING_SHELL_TESTS')
== 'ee5bcdc6-b749-11e7-9456-50465d597777'
):
return 'user'
if username is False: if username is False:
username = _get_user() username = _get_user()
if username is None: if username is None:

View File

@ -22,6 +22,11 @@ def hostname(pl, segment_info, only_if_ssh=False, exclude_domain=False):
:param bool exclude_domain: :param bool exclude_domain:
return the hostname without domain if there is one return the hostname without domain if there is one
''' '''
if (
segment_info['environ'].get('_POWERLINE_RUNNING_SHELL_TESTS')
== 'ee5bcdc6-b749-11e7-9456-50465d597777'
):
return 'hostname'
if only_if_ssh and not segment_info['environ'].get('SSH_CLIENT'): if only_if_ssh and not segment_info['environ'].get('SSH_CLIENT'):
return None return None
if exclude_domain: if exclude_domain:

View File

@ -254,6 +254,14 @@ else:
return return
if not info: if not info:
return return
try:
elapsed = iface.Get(iface_player, 'Position')
except dbus.exceptions.DBusException:
pl.warning('Missing player elapsed time')
elapsed = None
else:
elapsed = _convert_seconds(elapsed / 1e6)
album = info.get('xesam:album') album = info.get('xesam:album')
title = info.get('xesam:title') title = info.get('xesam:title')
artist = info.get('xesam:artist') artist = info.get('xesam:artist')
@ -269,6 +277,7 @@ else:
'album': album, 'album': album,
'artist': artist, 'artist': artist,
'title': title, 'title': title,
'elapsed': elapsed,
'total': _convert_seconds(info.get('mpris:length') / 1e6), 'total': _convert_seconds(info.get('mpris:length') / 1e6),
} }
@ -299,6 +308,17 @@ Requires ``dbus`` python module. Only for players that support specific protocol
class SpotifyDbusPlayerSegment(PlayerSegment): class SpotifyDbusPlayerSegment(PlayerSegment):
def get_player_status(self, pl): def get_player_status(self, pl):
player_status = _get_dbus_player_status(
pl=pl,
player_name='Spotify',
bus_name='org.mpris.MediaPlayer2.spotify',
player_path='/org/mpris/MediaPlayer2',
iface_prop='org.freedesktop.DBus.Properties',
iface_player='org.mpris.MediaPlayer2.Player',
)
if player_status is not None:
return player_status
# Fallback for legacy spotify client with different DBus protocol
return _get_dbus_player_status( return _get_dbus_player_status(
pl=pl, pl=pl,
player_name='Spotify', player_name='Spotify',
@ -333,7 +353,7 @@ class SpotifyAppleScriptPlayerSegment(PlayerSegment):
set artist_name to artist of current track set artist_name to artist of current track
set album_name to album of current track set album_name to album of current track
set track_length to duration of current track set track_length to duration of current track
set now_playing to "" & player state & "{0}" & album_name & "{0}" & artist_name & "{0}" & track_name & "{0}" & track_length set now_playing to "" & player state & "{0}" & album_name & "{0}" & artist_name & "{0}" & track_name & "{0}" & track_length & "{0}" & player position
return now_playing return now_playing
else else
return player state return player state
@ -358,7 +378,8 @@ class SpotifyAppleScriptPlayerSegment(PlayerSegment):
'album': spotify_status[1], 'album': spotify_status[1],
'artist': spotify_status[2], 'artist': spotify_status[2],
'title': spotify_status[3], 'title': spotify_status[3],
'total': _convert_seconds(int(spotify_status[4])) 'total': _convert_seconds(int(spotify_status[4])/1000),
'elapsed': _convert_seconds(spotify_status[5]),
} }
@ -371,7 +392,7 @@ Requires ``osascript`` available in $PATH.
''').format(_common_args.format('spotify_apple_script'))) ''').format(_common_args.format('spotify_apple_script')))
if 'dbus' in globals() or not sys.platform.startswith('darwin'): if not sys.platform.startswith('darwin'):
spotify = spotify_dbus spotify = spotify_dbus
_old_name = 'spotify_dbus' _old_name = 'spotify_dbus'
else: else:
@ -528,3 +549,59 @@ Requires ``osascript``.
{0} {0}
''').format(_common_args.format('itunes'))) ''').format(_common_args.format('itunes')))
class MocPlayerSegment(PlayerSegment):
def get_player_status(self, pl):
'''Return Music On Console (mocp) player information.
``mocp -i`` returns current information i.e.
.. code-block::
File: filename.format
Title: full title
Artist: artist name
SongTitle: song title
Album: album name
TotalTime: 00:00
TimeLeft: 00:00
TotalSec: 000
CurrentTime: 00:00
CurrentSec: 000
Bitrate: 000kbps
AvgBitrate: 000kbps
Rate: 00kHz
For the information we are looking for we dont really care if we have
extra-timing information or bit rate level. The dictionary comprehension
in this method takes anything in ignore_info and brings the key inside
that to the right info of the dictionary.
'''
now_playing_str = run_cmd(pl, ['mocp', '-i'])
if not now_playing_str:
return
now_playing = dict((
line.split(': ', 1)
for line in now_playing_str.split('\n')[:-1]
))
state = _convert_state(now_playing.get('State', 'stop'))
return {
'state': state,
'album': now_playing.get('Album', ''),
'artist': now_playing.get('Artist', ''),
'title': now_playing.get('SongTitle', ''),
'elapsed': _convert_seconds(now_playing.get('CurrentSec', 0)),
'total': _convert_seconds(now_playing.get('TotalSec', 0)),
}
mocp = with_docstring(MocPlayerSegment(),
('''Return MOC (Music On Console) player information
Requires version >= 2.3.0 and ``mocp`` executable in ``$PATH``.
{0}
''').format(_common_args.format('mocp')))

View File

@ -46,7 +46,7 @@ branch = with_docstring(BranchSegment(),
:param bool status_colors: :param bool status_colors:
Determines whether repository status will be used to determine highlighting. Determines whether repository status will be used to determine highlighting.
Default: False. Default: False.
:param bool ignore_statuses: :param list ignore_statuses:
List of statuses which will not result in repo being marked as dirty. Most List of statuses which will not result in repo being marked as dirty. Most
useful is setting this option to ``["U"]``: this will ignore repository useful is setting this option to ``["U"]``: this will ignore repository
which has just untracked files (i.e. repository with modified, deleted or which has just untracked files (i.e. repository with modified, deleted or

View File

@ -39,7 +39,10 @@ def last_pipe_status(pl, segment_info):
Highlight groups used: ``exit_fail``, ``exit_success`` Highlight groups used: ``exit_fail``, ``exit_success``
''' '''
last_pipe_status = segment_info['args'].last_pipe_status last_pipe_status = (
segment_info['args'].last_pipe_status
or (segment_info['args'].last_exit_code,)
)
if any(last_pipe_status): if any(last_pipe_status):
return [ return [
{ {

View File

@ -63,6 +63,7 @@ vim_modes = {
'rm': '-MORE-', 'rm': '-MORE-',
'r?': 'CNFIRM', 'r?': 'CNFIRM',
'!': '!SHELL', '!': '!SHELL',
't': 'TERM ',
} }

View File

@ -0,0 +1,52 @@
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
try:
import vim
except ImportError:
vim = object()
from powerline.bindings.vim import vim_global_exists
from powerline.theme import requires_segment_info
@requires_segment_info
def ale(segment_info, pl, err_format='ERR: ln {first_line} ({num}) ', warn_format='WARN: ln {first_line} ({num}) '):
'''Show whether ALE has found any errors or warnings
:param str err_format:
Format string for errors.
:param str warn_format:
Format string for warnings.
Highlight groups used: ``ale:warning`` or ``warning``, ``ale:error`` or ``error``.
'''
if not (vim_global_exists('ale_enabled') and int(vim.eval('g:ale_enabled'))):
return None
has_errors = int(vim.eval('ale#statusline#Count(' + str(segment_info['bufnr']) + ').total'))
if not has_errors:
return
error = None
warning = None
errors_count = 0
warnings_count = 0
for issue in vim.eval('ale#engine#GetLoclist(' + str(segment_info['bufnr']) + ')'):
if issue['type'] == 'E':
error = error or issue
errors_count += 1
elif issue['type'] == 'W':
warning = warning or issue
warnings_count += 1
segments = []
if error:
segments.append({
'contents': err_format.format(first_line=error['lnum'], num=errors_count),
'highlight_groups': ['ale:error', 'error'],
})
if warning:
segments.append({
'contents': warn_format.format(first_line=warning['lnum'], num=warnings_count),
'highlight_groups': ['ale:warning', 'warning'],
})
return segments

View File

@ -59,7 +59,7 @@ else:
def get_version(): def get_version():
base_version = '2.6' base_version = '2.7'
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.6', version='2.7',
description='The ultimate statusline/prompt utility.', description='The ultimate statusline/prompt utility.',
long_description=README, long_description=README,
classifiers=[ classifiers=[
@ -124,7 +124,7 @@ setup(
packages=find_packages(exclude=('tests', 'tests.*')), packages=find_packages(exclude=('tests', 'tests.*')),
include_package_data=True, include_package_data=True,
zip_safe=False, zip_safe=False,
install_requires=[], install_requires=['argparse'] if OLD_PYTHON else [],
extras_require={ extras_require={
'docs': [ 'docs': [
'Sphinx', 'Sphinx',

View File

@ -46,13 +46,13 @@ if test -n "$USE_UCS2_PYTHON" ; then
mkvirtualenv -p "$PYTHON" cpython-ucs2-$UCS2_PYTHON_VARIANT mkvirtualenv -p "$PYTHON" cpython-ucs2-$UCS2_PYTHON_VARIANT
set -e set -e
. tests/bot-ci/scripts/common/main.sh . tests/bot-ci/scripts/common/main.sh
pip install . pip install --verbose --verbose --verbose .
if test "$UCS2_PYTHON_VARIANT" = "2.6" ; then if test "$UCS2_PYTHON_VARIANT" = "2.6" ; then
rm tests/bot-ci/deps/wheels/ucs2-CPython-${UCS2_PYTHON_VARIANT}*/pyuv*.whl rm tests/bot-ci/deps/wheels/ucs2-CPython-${UCS2_PYTHON_VARIANT}*/pyuv*.whl
fi fi
pip install --no-deps tests/bot-ci/deps/wheels/ucs2-CPython-${UCS2_PYTHON_VARIANT}*/*.whl pip install --no-deps tests/bot-ci/deps/wheels/ucs2-CPython-${UCS2_PYTHON_VARIANT}*/*.whl
else else
pip install . pip install --verbose --verbose --verbose .
# FIXME Uv watcher sometimes misses events and INotify is not available in # FIXME Uv watcher sometimes misses events and INotify is not available in
# Python-2.6, thus pyuv should be removed in order for VCS tests to # Python-2.6, thus pyuv should be removed in order for VCS tests to
# pass. # pass.

View File

@ -2,10 +2,93 @@
from __future__ import (unicode_literals, division, absolute_import, print_function) from __future__ import (unicode_literals, division, absolute_import, print_function)
import sys import sys
import os
if sys.version_info < (2, 7): if sys.version_info < (2, 7):
from unittest2 import TestCase, main # NOQA from unittest2 import TestCase as _TestCase # NOQA
from unittest2 import main as _main # NOQA
from unittest2.case import SkipTest # NOQA from unittest2.case import SkipTest # NOQA
else: else:
from unittest import TestCase, main # NOQA from unittest import TestCase as _TestCase # NOQA
from unittest import main as _main # NOQA
from unittest.case import SkipTest # NOQA from unittest.case import SkipTest # NOQA
from tests.modules.lib import PowerlineSingleTest
class PowerlineDummyTest(object):
def __enter__(self):
return self
def __exit__(self, *args):
pass
def fail(self, *args, **kwargs):
pass
def exception(self, *args, **kwargs):
pass
class PowerlineTestSuite(object):
def __init__(self, name):
self.name = name
def __enter__(self):
self.saved_current_suite = os.environ['POWERLINE_CURRENT_SUITE']
os.environ['POWERLINE_CURRENT_SUITE'] = (
self.saved_current_suite + '/' + self.name)
self.suite = self.saved_current_suite + '/' + self.name
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type is not None:
self.exception(
'suite_noexcept',
'Exception while running test suite: {0!r}'.format(exc_value),
)
os.environ['POWERLINE_CURRENT_SUITE'] = self.saved_current_suite
def record_test_failure(self, fail_char, test_name, message, allow_failure=False):
if allow_failure:
fail_char = 'A' + fail_char
full_msg = '{fail_char} {suite}|{test_name} :: {message}'.format(
fail_char=fail_char,
suite=self.suite,
test_name=test_name,
message=message,
)
with open(os.environ['FAILURES_FILE'], 'a') as ffd:
ffd.write(full_msg + '\n')
return False
def exception(self, test_name, message, allow_failure=False):
return self.record_test_failure('E', test_name, message, allow_failure)
def fail(self, test_name, message, allow_failure=False):
return self.record_test_failure('F', test_name, message, allow_failure)
def test(self, name, attempts_left=0):
if not attempts_left:
return PowerlineSingleTest(self, name)
else:
return PowerlineDummyTest()
def subsuite(self, name):
return PowerlineTestSuite(name)
suite = None
def main(*args, **kwargs):
global suite
suite = PowerlineTestSuite(sys.argv[0])
_main(*args, **kwargs)
class TestCase(_TestCase):
def fail(self, msg=None):
suite.fail(self.__class__.__name__,
msg or 'Test failed without message')
super(TestCase, self).fail(*args, **kwargs)

View File

@ -161,3 +161,23 @@ def replace_env(key, new, environ=None, **kwargs):
r = kwargs.copy() r = kwargs.copy()
r['environ'] = environ or {} r['environ'] = environ or {}
return ItemReplace(r['environ'], key, new, r) return ItemReplace(r['environ'], key, new, r)
class PowerlineSingleTest(object):
def __init__(self, suite, name):
self.suite = suite
self.name = name
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type is not None:
self.exception('Exception while running test: {0!r}'.format(
exc_value))
def fail(self, message, allow_failure=False):
return self.suite.fail(self.name, message, allow_failure)
def exception(self, message, allow_failure=False):
return self.suite.exception(self.name, message, allow_failure)

View File

@ -61,13 +61,17 @@ class ExpectProcess(threading.Thread):
self.buffer = [] self.buffer = []
self.child_lock = threading.Lock() self.child_lock = threading.Lock()
self.shutdown_event = threading.Event() self.shutdown_event = threading.Event()
self.started_event = threading.Event()
def run(self): def run(self):
child = pexpect.spawn(self.cmd, self.args, cwd=self.cwd, env=self.env) with self.child_lock:
sleep(0.5) child = pexpect.spawn(self.cmd, self.args, cwd=self.cwd,
child.setwinsize(self.dim.rows, self.dim.cols) env=self.env)
sleep(0.5) sleep(0.5)
self.child = child child.setwinsize(self.dim.rows, self.dim.cols)
sleep(0.5)
self.child = child
self.started_event.set()
status = None status = None
while status is None and not self.shutdown_event.is_set(): while status is None and not self.shutdown_event.is_set():
try: try:
@ -109,21 +113,33 @@ class ExpectProcess(threading.Thread):
with self.child_lock: with self.child_lock:
self.child.send(data) self.child.send(data)
def get_highlighted_text(self, text, attrs, default_props=()): def get_highlighted_text(self, text, attrs, default_props=(),
use_escapes=False):
ret = [] ret = []
new_attrs = attrs.copy() new_attrs = attrs.copy()
for cell_properties, segment_text in text: for cell_properties, segment_text in text:
segment_text = segment_text.translate({'{': '{{', '}': '}}'}) if use_escapes:
if cell_properties not in new_attrs: escapes = ('\033[38;2;{0};{1};{2};48;2;{3};{4};{5}'.format(
new_attrs[cell_properties] = len(new_attrs) + 1 *(cell_properties[0] + cell_properties[1]))) + (
props_name = new_attrs[cell_properties] ';1' if cell_properties[2] else ''
if props_name in default_props: ) + (
ret.append(segment_text) ';3' if cell_properties[3] else ''
) + (
';4' if cell_properties[4] else ''
) + 'm'
ret.append(escapes + segment_text + '\033[0m')
else: else:
ret.append('{' + str(props_name) + ':' + segment_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 return ''.join(ret), new_attrs
def get_row(self, row, attrs, default_props=()): def get_row(self, row, attrs, default_props=(), use_escapes=False):
with self.lock: with self.lock:
return self.get_highlighted_text(( return self.get_highlighted_text((
(key, ''.join((cell.text for cell in subline))) (key, ''.join((cell.text for cell in subline)))
@ -131,35 +147,48 @@ class ExpectProcess(threading.Thread):
self.vterm.vtscreen[row, col] self.vterm.vtscreen[row, col]
for col in range(self.dim.cols) for col in range(self.dim.cols)
), lambda cell: cell.cell_properties_key) ), lambda cell: cell.cell_properties_key)
), attrs, default_props) ), attrs, default_props, use_escapes)
def get_screen(self, attrs, default_props=()): def get_screen(self, attrs, default_props=(), use_escapes=False):
lines = [] lines = []
for row in range(self.dim.rows): for row in range(self.dim.rows):
line, attrs = self.get_row(row, attrs, default_props) line, attrs = self.get_row(row, attrs, default_props, use_escapes)
lines.append(line) lines.append(line)
return '\n'.join(lines), attrs return '\n'.join(lines), attrs
def test_expected_result(p, test, last_attempt, last_attempt_cb=None): def test_expected_result(p, test, last_attempt, last_attempt_cb, attempts):
debugging_tests = not not os.environ.get('_POWERLINE_DEBUGGING_TESTS')
expected_text, attrs = test['expected_result'] expected_text, attrs = test['expected_result']
attempts = 3
result = None result = None
while attempts: while attempts:
actual_text, all_attrs = p.get_row(test['row'], attrs) if 'row' in test:
row = test['row']
else:
row = p.dim.rows - 1
while row >= 0 and not p[row, 0].text:
row -= 1
if row < 0:
row = 0
actual_text, all_attrs = p.get_row(row, attrs)
if actual_text == expected_text: if actual_text == expected_text:
return True return True
attempts -= 1 attempts -= 1
print('Actual result does not match expected. Attempts left: {0}.'.format(attempts)) print('Actual result does not match expected for row {0}. Attempts left: {1}.'.format(
row, attempts))
sleep(2) sleep(2)
print('Result:') print('Result (row {0}):'.format(row))
print(actual_text) print(actual_text)
print('Expected:') print('Expected:')
print(expected_text) print(expected_text)
print('Attributes:') print('Attributes:')
print(all_attrs) for v, k in sorted(
((v, k) for k, v in all_attrs.items()),
key=(lambda t: '%02u'.format(t[0]) if isinstance(t[0], int) else t[0]),
):
print('{k!r}: {v!r},'.format(v=v, k=k))
print('Screen:') print('Screen:')
screen, screen_attrs = p.get_screen(attrs) screen, screen_attrs = p.get_screen(attrs, use_escapes=debugging_tests)
print(screen) print(screen)
print(screen_attrs) print(screen_attrs)
print('_' * 80) print('_' * 80)
@ -219,8 +248,12 @@ def get_env(vterm_path, test_dir, *args, **kwargs):
return env return env
def do_terminal_tests(tests, cmd, dim, args, env, cwd=None, fin_cb=None, def do_terminal_tests(tests, cmd, dim, args, env, suite, cwd=None, fin_cb=None,
last_attempt_cb=None, attempts=3): last_attempt_cb=None, attempts=None):
debugging_tests = not not os.environ.get('_POWERLINE_DEBUGGING_TESTS')
default_attempts = 2 if debugging_tests else 3
if attempts is None:
attempts = default_attempts
lib = os.environ.get('POWERLINE_LIBVTERM') lib = os.environ.get('POWERLINE_LIBVTERM')
if not lib: if not lib:
if os.path.exists('tests/bot-ci/deps/libvterm/libvterm.so'): if os.path.exists('tests/bot-ci/deps/libvterm/libvterm.so'):
@ -239,21 +272,26 @@ def do_terminal_tests(tests, cmd, dim, args, env, cwd=None, fin_cb=None,
env=env, env=env,
) )
p.start() p.start()
p.started_event.wait()
ret = True ret = True
for test in tests: for i, test in enumerate(tests):
try: with suite.test(test.get('name', 'test_{0}'.format(i)),
test_prep = test['prep_cb'] attempts - 1) as ptest:
except KeyError: try:
pass test_prep = test['prep_cb']
else: except KeyError:
test_prep(p) pass
ret = ( else:
ret test_prep(p)
and test_expected_result(p, test, attempts == 0, test_result = test_expected_result(
last_attempt_cb) p, test, attempts == 0, last_attempt_cb,
) test.get('attempts', default_attempts)
)
if not test_result:
ptest.fail('Result does not match expected')
ret = ret and test_result
if ret: if ret:
return ret return ret

View File

@ -116,6 +116,7 @@ def get_functions(lib):
('cell', ctypes.POINTER(VTermScreenCell_s)) ('cell', ctypes.POINTER(VTermScreenCell_s))
)), )),
vterm_free=(None, (('vt', VTerm_p),)), vterm_free=(None, (('vt', VTerm_p),)),
vterm_set_utf8=(None, (('vt', VTerm_p), ('is_utf8', ctypes.c_int))),
) )
@ -173,6 +174,7 @@ class VTerm(object):
def __init__(self, lib, dim): def __init__(self, lib, dim):
self.functions = get_functions(lib) self.functions = get_functions(lib)
self.vt = self.functions.vterm_new(dim.rows, dim.cols) self.vt = self.functions.vterm_new(dim.rows, dim.cols)
self.functions.vterm_set_utf8(self.vt, 1)
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)

View File

@ -1,10 +1,29 @@
. tests/bot-ci/scripts/common/main.sh
set +x
: ${PYTHON:=python}
: ${USER:=`id -un`} : ${USER:=`id -un`}
: ${HOME:=`getent passwd $USER | cut -d: -f6`} : ${HOME:=`getent passwd $USER | cut -d: -f6`}
if test -z "${PYTHON}" ; then
if test -n "$USE_UCS2_PYTHON" ; then
LD_LIBRARY_PATH="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT/lib${LD_LIBRARY_PATH:+:}${LD_LIBRARY_PATH}"
fi
fi
export LD_LIBRARY_PATH
export USER
export HOME
if test -n "$USE_UCS2_PYTHON" ; then
POWERLINE_VIRTUALENV="cpython-ucs2-$UCS2_PYTHON_VARIANT"
PYTHON="$HOME/.virtualenvs/$POWERLINE_VIRTUALENV/bin/python"
if test -n "$BASH_VERSION" ; then
set +e
. virtualenvwrapper.sh
workon "$POWERLINE_VIRTUALENV"
set -e
fi
fi
. tests/bot-ci/scripts/common/main.sh silent
export USER HOME export USER HOME
if test -z "$FAILED" ; then if test -z "$FAILED" ; then
@ -13,7 +32,7 @@ if test -z "$FAILED" ; then
FAIL_SUMMARY="" FAIL_SUMMARY=""
TMP_ROOT="$ROOT/tests/tmp" TMP_ROOT="$ROOT/tests/tmp"
FAILURES_FILE="$ROOT/tests/failures" export FAILURES_FILE="$ROOT/tests/status"
fi fi
ANSI_CLEAR="\033[0K" ANSI_CLEAR="\033[0K"
@ -26,10 +45,29 @@ travis_fold() {
echo -en "travis_fold:${action}:${name}\r${ANSI_CLEAR}" echo -en "travis_fold:${action}:${name}\r${ANSI_CLEAR}"
} }
print_environ() {
echo "Using $PYTHON_IMPLEMENTATION version $PYTHON_VERSION."
echo "Path to Python executable: $PYTHON."
echo "Root: $ROOT."
echo "Branch: $BRANCH_NAME."
echo "sys.path:"
"$PYTHON" -c "for path in __import__('sys').path: print(' %r' % path)"
}
enter_suite() { enter_suite() {
set +x
local suite_name="$1" ; shift local suite_name="$1" ; shift
local final="$1"
export POWERLINE_CURRENT_SUITE="${POWERLINE_CURRENT_SUITE}/$suite_name" export POWERLINE_CURRENT_SUITE="${POWERLINE_CURRENT_SUITE}/$suite_name"
travis_fold start "$POWERLINE_CURRENT_SUITE" travis_fold start "$POWERLINE_CURRENT_SUITE"
print_environ
if test "$final" = final ; then
if test -n "$POWERLINE_SUITE_FINAL" ; then
fail __suite__/enter/final E "Final suites do not allow nesting"
fi
export POWERLINE_SUITE_FINAL=1
# set -x
fi
} }
exit_suite() { exit_suite() {
@ -40,14 +78,17 @@ exit_suite() {
echo "Suite ${POWERLINE_CURRENT_SUITE} failed, summary:" echo "Suite ${POWERLINE_CURRENT_SUITE} failed, summary:"
echo "${FAIL_SUMMARY}" echo "${FAIL_SUMMARY}"
fi fi
set +x
travis_fold end "$POWERLINE_CURRENT_SUITE" travis_fold end "$POWERLINE_CURRENT_SUITE"
export POWERLINE_CURRENT_SUITE="${POWERLINE_CURRENT_SUITE%/*}" export POWERLINE_CURRENT_SUITE="${POWERLINE_CURRENT_SUITE%/*}"
if test "$1" != "--continue" ; then if test "$1" != "--continue" ; then
exit $FAILED exit $FAILED
else
unset POWERLINE_SUITE_FINAL
fi fi
} }
fail() { _fail() {
local allow_failure= local allow_failure=
if test "$1" = "--allow-failure" ; then if test "$1" = "--allow-failure" ; then
shift shift
@ -56,15 +97,26 @@ fail() {
local test_name="$1" ; shift local test_name="$1" ; shift
local fail_char="$allow_failure$1" ; shift local fail_char="$allow_failure$1" ; shift
local message="$1" ; shift local message="$1" ; shift
local verb="$1" ; shift
local full_msg="$fail_char $POWERLINE_CURRENT_SUITE|$test_name :: $message" local full_msg="$fail_char $POWERLINE_CURRENT_SUITE|$test_name :: $message"
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}${full_msg}" FAIL_SUMMARY="${FAIL_SUMMARY}${NL}${full_msg}"
echo "Failed: $full_msg" echo "$verb: $full_msg"
echo "$full_msg" >> "$FAILURES_FILE" echo "$full_msg" >> "$FAILURES_FILE"
if test -z "$allow_failure" ; then if test -z "$allow_failure" ; then
FAILED=1 FAILED=1
fi fi
} }
fail() {
_fail "$@" "Failed"
}
skip() {
local test_name="$1" ; shift
local message="$1" ; shift
_fail --allow-failure "$test_name" S "$message" "Skipped"
}
make_test_root() { make_test_root() {
local suffix="${POWERLINE_CURRENT_SUITE##*/}" local suffix="${POWERLINE_CURRENT_SUITE##*/}"

View File

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

View File

@ -33,10 +33,10 @@ for script in "$ROOT"/tests/test_*/test.sh ; do
fi fi
done done
if test -e tests/failures ; then if test -e "$FAILURES_FILE" ; then
echo "Some tests failed. Summary:" echo "Fails and skips summary:"
cat tests/failures cat "$FAILURES_FILE"
rm tests/failures rm "$FAILURES_FILE"
fi fi
exit_suite exit_suite

View File

@ -102,7 +102,7 @@ if ! test -e "$DEPRECATED_SCRIPT" ; then
# skip "deprecated" "Missing deprecated bar bindings script" # skip "deprecated" "Missing deprecated bar bindings script"
: :
else else
enter_suite "deprecated" enter_suite "deprecated" final
for args in "" "0.5"; do for args in "" "0.5"; do
rm -rf "$TEST_ROOT/results" rm -rf "$TEST_ROOT/results"
mkdir "$TEST_ROOT/results" mkdir "$TEST_ROOT/results"
@ -132,7 +132,7 @@ else
exit_suite --continue exit_suite --continue
fi fi
enter_suite "awesome" enter_suite "awesome" final
ADDRESS="powerline-ipc-test-$$" ADDRESS="powerline-ipc-test-$$"
echo "Powerline address: $ADDRESS" echo "Powerline address: $ADDRESS"
rm -rf "$TEST_ROOT/results" rm -rf "$TEST_ROOT/results"

View File

@ -94,7 +94,7 @@ if ! test -e "$DEPRECATED_SCRIPT" ; then
# skip "deprecated" "Missing deprecated bar bindings script" # skip "deprecated" "Missing deprecated bar bindings script"
: :
else else
enter_suite "deprecated" enter_suite "deprecated" final
run python "$DEPRECATED_SCRIPT" $args > "$TEST_ROOT/deprecated.log" 2>&1 & run python "$DEPRECATED_SCRIPT" $args > "$TEST_ROOT/deprecated.log" 2>&1 &
SPID=$! SPID=$!
sleep 5 sleep 5
@ -122,7 +122,7 @@ else
sleep 5 sleep 5
killscript $SPID killscript $SPID
sleep 0.5 sleep 0.5
enter_suite "args($args)" enter_suite "args($args)" final
fnum=0 fnum=0
for file in "$TEST_ROOT/results"/*.log ; do for file in "$TEST_ROOT/results"/*.log ; do
if ! test -e "$file" ; then if ! test -e "$file" ; then

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
. tests/shlib/common.sh . tests/shlib/common.sh
enter_suite daemon enter_suite daemon final
export ADDRESS="powerline-ipc-test-$$" export ADDRESS="powerline-ipc-test-$$"
echo "Powerline address: $ADDRESS" echo "Powerline address: $ADDRESS"

View File

@ -0,0 +1,16 @@
# vim: ft=sh
set_theme_option() {
export POWERLINE_THEME_OVERRIDES="${POWERLINE_THEME_OVERRIDES};$1=$2"
}
set_theme() {
export POWERLINE_CONFIG_OVERRIDES="ext.shell.theme=$1"
}
set_virtual_env() {
export VIRTUAL_ENV="$HOME/.virtenvs/$1"
}
set_theme_option default_leftonly.segment_data.hostname.args.only_if_ssh false
set_theme default_leftonly
. "$ROOT/powerline/bindings/shell/powerline.sh"
export VIRTUAL_ENV=
cd "$TEST_ROOT/3rd"

View File

@ -0,0 +1,162 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import os
import sys
from time import sleep
from subprocess import check_call
from glob import glob1
from traceback import print_exc
from argparse import ArgumentParser
from powerline.lib.dict import updated
from tests.modules.lib.terminal import (ExpectProcess, MutableDimensions,
do_terminal_tests, get_env)
from tests.modules import PowerlineTestSuite
TEST_ROOT = os.path.abspath(os.environ['TEST_ROOT'])
def get_parser():
parser = ArgumentParser()
parser.add_argument('--type', action='store')
parser.add_argument('--client', action='store')
parser.add_argument('--binding', action='store')
parser.add_argument('args', action='append')
return parser
BINDING_OPTIONS = {
'dash': {
'cmd': 'dash',
'args': ['-i'],
'init': [
'. "$ROOT/tests/test_in_vterm/shell/inits/dash"',
],
},
}
def main(argv):
script_args = get_parser().parse_args(argv)
vterm_path = os.path.join(TEST_ROOT, 'path')
env = get_env(vterm_path, TEST_ROOT)
env['ROOT'] = os.path.abspath('.')
env['TEST_ROOT'] = TEST_ROOT
env['TEST_TYPE'] = script_args.type
env['TEST_CLIENT'] = script_args.client
env['LANG'] = 'en_US.UTF_8'
env['_POWERLINE_RUNNING_SHELL_TESTS'] = (
'ee5bcdc6-b749-11e7-9456-50465d597777')
dim = MutableDimensions(rows=50, cols=200)
binding_opts = BINDING_OPTIONS[script_args.binding]
cmd = os.path.join(vterm_path, binding_opts['cmd'])
args = binding_opts['args']
def gen_init(binding):
def init(p):
for line in binding_opts['init']:
p.send(line + '\n')
sleep(1)
return init
def gen_feed(line):
def feed(p):
p.send(line + '\n')
sleep(0.1)
return feed
base_attrs = {
((255, 204,0), (204, 51, 0), 0, 0, 0): 'H',
((204, 51, 0), (0, 102, 153), 0, 0, 0): 'sHU',
((255, 255, 255), (0, 102, 153), 1, 0, 0): 'U',
((0, 102, 153), (44, 44, 44), 0, 0, 0): 'sUB',
((199, 199, 199), (44, 44, 44), 0, 0, 0): 'B',
((44, 44, 44), (88, 88, 88), 0, 0, 0): 'sBD',
((199, 199, 199), (88, 88, 88), 0, 0, 0): 'D',
((144, 144, 144), (88, 88, 88), 0, 0, 0): 'sD',
((221, 221, 221), (88, 88, 88), 1, 0, 0): 'C',
((88, 88, 88), (0, 0, 0), 0, 0, 0): 'sDN',
((240, 240, 240), (0, 0, 0), 0, 0, 0): 'N',
((0, 102, 153), (51, 153, 204), 0, 0, 0): 'sUE',
((255, 255, 255), (51, 153, 204), 0, 0, 0): 'E',
((51, 153, 204), (44, 44, 44), 0, 0, 0): 'sEB',
}
tests = (
{
'expected_result': (
'{H:  hostname }{sHU: }'
'{U:user }{sUB: }'
'{B: BRANCH }{sBD: }'
'{D:… }{sD: }{D:tmp }{sD: }{D:vshells }{sD: }{C:3rd }{sDN: }'
'{N:}',
base_attrs,
),
'prep_cb': gen_init(script_args.binding),
},
{
'expected_result': (
'{H:  hostname }{sHU: }'
'{U:user }{sUB: }'
'{B: BRANCH }{sBD: }'
'{D:… }{sD: }{D:vshells }{sD: }{D:3rd }{sD: }{C:.git }{sDN: }'
'{N:}',
base_attrs
),
'prep_cb': gen_feed('cd .git'),
},
{
'expected_result': (
'{H:  hostname }{sHU: }'
'{U:user }{sUB: }'
'{B: BRANCH }{sBD: }'
'{D:… }{sD: }{D:tmp }{sD: }{D:vshells }{sD: }{C:3rd }{sDN: }'
'{N:}',
base_attrs,
),
'prep_cb': gen_feed('cd ..'),
},
{
'expected_result': (
'{H:  hostname }{sHU: }'
'{U:user }{sUE: }'
'{E:(e) some-venv }{sEB: }'
'{B: BRANCH }{sBD: }'
'{D:… }{sD: }{D:tmp }{sD: }{D:vshells }{sD: }{C:3rd }{sDN: }'
'{N:}',
base_attrs,
),
'prep_cb': gen_feed('set_virtual_env some-venv'),
},
)
with PowerlineTestSuite('shell') as suite:
return do_terminal_tests(
tests=tests,
cmd=cmd,
dim=dim,
args=args,
env=env,
cwd=TEST_ROOT,
suite=suite,
)
if __name__ == '__main__':
if main(sys.argv[1:]):
raise SystemExit(0)
else:
raise SystemExit(1)

View File

@ -0,0 +1,119 @@
#!/bin/bash
. tests/shlib/common.sh
. tests/shlib/vterm.sh
enter_suite vshells
vterm_setup
HAS_SOCAT=
HAS_C_CLIENT=
git init "$TEST_ROOT/3rd"
git --git-dir="$TEST_ROOT/3rd/.git" checkout -b BRANCH
export DIR1=""
export DIR2=""
mkdir "$TEST_ROOT/3rd/$DIR1"
mkdir "$TEST_ROOT/3rd/$DIR2"
mkdir "$TEST_ROOT"/3rd/'\[\]'
mkdir "$TEST_ROOT"/3rd/'%%'
mkdir "$TEST_ROOT"/3rd/'#[bold]'
mkdir "$TEST_ROOT"/3rd/'(echo)'
mkdir "$TEST_ROOT"/3rd/'$(echo)'
mkdir "$TEST_ROOT"/3rd/'`echo`'
mkdir "$TEST_ROOT"/3rd/'«Unicode!»'
mkdir "$TEST_ROOT/fish_home"
mkdir "$TEST_ROOT/fish_home/fish"
mkdir "$TEST_ROOT/fish_home/fish/generated_completions"
cp -r "$ROOT/tests/test_shells/ipython_home" "$TEST_ROOT"
ln -s "$(which env)" "$TEST_ROOT/path"
ln -s "$(which git)" "$TEST_ROOT/path"
ln -s "$(which sleep)" "$TEST_ROOT/path"
ln -s "$(which cat)" "$TEST_ROOT/path"
ln -s "$(which false)" "$TEST_ROOT/path"
ln -s "$(which true)" "$TEST_ROOT/path"
ln -s "$(which kill)" "$TEST_ROOT/path"
ln -s "$(which echo)" "$TEST_ROOT/path"
ln -s "$(which which)" "$TEST_ROOT/path"
ln -s "$(which dirname)" "$TEST_ROOT/path"
ln -s "$(which wc)" "$TEST_ROOT/path"
ln -s "$(which stty)" "$TEST_ROOT/path"
ln -s "$(which cut)" "$TEST_ROOT/path"
ln -s "$(which bc)" "$TEST_ROOT/path"
ln -s "$(which expr)" "$TEST_ROOT/path"
ln -s "$(which mktemp)" "$TEST_ROOT/path"
ln -s "$(which grep)" "$TEST_ROOT/path"
ln -s "$(which sed)" "$TEST_ROOT/path"
ln -s "$(which rm)" "$TEST_ROOT/path"
ln -s "$(which tr)" "$TEST_ROOT/path"
ln -s "$(which uname)" "$TEST_ROOT/path"
ln -s "$(which test)" "$TEST_ROOT/path"
ln -s "$(which pwd)" "$TEST_ROOT/path"
ln -s "$(which hostname)" "$TEST_ROOT/path"
ln -s "$ROOT/tests/test_shells/bgscript.sh" "$TEST_ROOT/path"
ln -s "$ROOT/tests/test_shells/waitpid.sh" "$TEST_ROOT/path"
ln -s "$ROOT/scripts/powerline-config" "$TEST_ROOT/path"
ln -s "$ROOT/scripts/powerline-render" "$TEST_ROOT/path"
ln -s "$ROOT/client/powerline.py" "$TEST_ROOT/path"
if test -e "$ROOT/scripts/powerline" ; then
ln -s "$ROOT/scripts/powerline" "$TEST_ROOT/path"
elif test -e client/powerline ; then
ln -s "$ROOT/client/powerline" "$TEST_ROOT/path"
elif which powerline ; then
ln -s "$(which powerline)" "$TEST_ROOT/path"
else
echo "Executable powerline was not found"
exit 1
fi
if test "$(
file --mime-type --brief --dereference "$TEST_ROOT/path/powerline" \
| cut -d/ -f1)" = "application" ; then
HAS_C_CLIENT=1
fi
if which socat ; then
HAS_SOCAT=1
ln -s "$(which socat)" "$TEST_ROOT/path"
ln -s "$ROOT/client/powerline.sh" "$TEST_ROOT/path"
fi
# Test type: daemon, renderer, …
# Test client: python, shell, c, none
# Test binding: *sh, ipython, pdb, …
test_shell() {
local test_type="$1" ; shift
local test_client="$1" ; shift
local test_binding="$1" ; shift
if test "$test_client" = shell && test -z "$HAS_SOCAT" ; then
echo "Skipping test, socat not available"
return
fi
if test "$test_client" = c && test -z "$HAS_C_CLIENT" ; then
echo "Skipping test, C client not available"
return
fi
if which "$test_binding" ; then
ln -s "$(which "$test_binding")" "$TEST_ROOT/path"
fi
if ! "${PYTHON}" "$ROOT/tests/test_in_vterm/test_shells.py" \
--type=$test_type \
--client=$test_client \
--binding=$test_binding \
-- "$@"
then
local test_name="$test_type-$test_client-$test_binding"
fail "$test_name" F "Failed vterm shell test"
fi
}
test_shell renderer python dash -i || true
vterm_shutdown
exit_suite

View File

@ -17,9 +17,10 @@ from powerline import get_fallback_logger
from tests.modules.lib.terminal import (ExpectProcess, MutableDimensions, from tests.modules.lib.terminal import (ExpectProcess, MutableDimensions,
do_terminal_tests, get_env) do_terminal_tests, get_env)
from tests.modules import PowerlineTestSuite
VTERM_TEST_DIR = os.path.abspath('tests/vterm_tmux') TEST_ROOT = os.path.abspath(os.environ['TEST_ROOT'])
def tmux_logs_iter(test_dir): def tmux_logs_iter(test_dir):
@ -28,7 +29,7 @@ def tmux_logs_iter(test_dir):
def print_tmux_logs(): def print_tmux_logs():
for f in tmux_logs_iter(VTERM_TEST_DIR): for f in tmux_logs_iter(TEST_ROOT):
print('_' * 80) print('_' * 80)
print(os.path.basename(f) + ':') print(os.path.basename(f) + ':')
print('=' * 80) print('=' * 80)
@ -57,15 +58,15 @@ def tmux_fin_cb(p, cmd, env):
try: try:
check_call([ check_call([
cmd, '-S', env['POWERLINE_TMUX_SOCKET_PATH'], 'kill-server' cmd, '-S', env['POWERLINE_TMUX_SOCKET_PATH'], 'kill-server'
], env=env, cwd=VTERM_TEST_DIR) ], env=env, cwd=TEST_ROOT)
except Exception: except Exception:
print_exc() print_exc()
for f in tmux_logs_iter(VTERM_TEST_DIR): for f in tmux_logs_iter(TEST_ROOT):
os.unlink(f) 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(TEST_ROOT, 'path')
tmux_exe = os.path.join(vterm_path, 'tmux') tmux_exe = os.path.join(vterm_path, 'tmux')
@ -73,7 +74,7 @@ def main(attempts=3):
if os.path.exists(socket_path): if os.path.exists(socket_path):
os.unlink(socket_path) os.unlink(socket_path)
env = get_env(vterm_path, VTERM_TEST_DIR, { env = get_env(vterm_path, TEST_ROOT, {
'POWERLINE_THEME_OVERRIDES': ';'.join(( 'POWERLINE_THEME_OVERRIDES': ';'.join((
key + '=' + json.dumps(val) key + '=' + json.dumps(val)
for key, val in ( for key, val in (
@ -99,7 +100,7 @@ def main(attempts=3):
conf_path = os.path.abspath('powerline/bindings/tmux/powerline.conf') conf_path = os.path.abspath('powerline/bindings/tmux/powerline.conf')
conf_line = 'source "' + ( conf_line = 'source "' + (
conf_path.replace('\\', '\\\\').replace('"', '\\"')) + '"\n' conf_path.replace('\\', '\\\\').replace('"', '\\"')) + '"\n'
conf_file = os.path.realpath(os.path.join(VTERM_TEST_DIR, 'tmux.conf')) conf_file = os.path.realpath(os.path.join(TEST_ROOT, 'tmux.conf'))
with open(conf_file, 'w') as cf_fd: with open(conf_file, 'w') as cf_fd:
cf_fd.write(conf_line) cf_fd.write(conf_line)
@ -229,16 +230,18 @@ def main(attempts=3):
'new-window', 'bash --norc --noprofile -i', ';', 'new-window', 'bash --norc --noprofile -i', ';',
] ]
return do_terminal_tests( with PowerlineTestSuite('tmux') as suite:
tests=tests, return do_terminal_tests(
cmd=tmux_exe, tests=tests,
dim=dim, cmd=tmux_exe,
args=args, dim=dim,
env=env, args=args,
cwd=VTERM_TEST_DIR, env=env,
fin_cb=tmux_fin_cb, cwd=TEST_ROOT,
last_attempt_cb=print_tmux_logs, fin_cb=tmux_fin_cb,
) last_attempt_cb=print_tmux_logs,
suite=suite,
)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -1,17 +1,15 @@
#!/bin/sh #!/bin/bash
. tests/shlib/common.sh . tests/shlib/common.sh
. tests/shlib/vterm.sh . tests/shlib/vterm.sh
enter_suite tmux enter_suite tmux final
VTERM_TEST_DIR="$ROOT/tests/vterm_tmux" vterm_setup
vterm_setup "$VTERM_TEST_DIR" ln -s "$(which env)" "$TEST_ROOT/path"
ln -s "$(which cut)" "$TEST_ROOT/path"
ln -s "$(which env)" "$VTERM_TEST_DIR/path" ln -s "$ROOT/scripts/powerline-render" "$TEST_ROOT/path"
ln -s "$(which cut)" "$VTERM_TEST_DIR/path" ln -s "$ROOT/scripts/powerline-config" "$TEST_ROOT/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
@ -22,7 +20,7 @@ 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}")" "$VTERM_TEST_DIR/path/tmux" ln -sf "$(which "${POWERLINE_TMUX_EXE}")" "$TEST_ROOT/path/tmux"
f="$ROOT/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)"
@ -41,6 +39,6 @@ else
test_tmux || true test_tmux || true
fi fi
vterm_shutdown "$VTERM_TEST_DIR" vterm_shutdown
exit_suite exit_suite

View File

@ -4,42 +4,66 @@ 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 glob import glob1 from glob import glob1
from traceback import print_exc from traceback import print_exc
from powerline.lib.dict import updated
from tests.modules.lib.terminal import (ExpectProcess, MutableDimensions, from tests.modules.lib.terminal import (ExpectProcess, MutableDimensions,
do_terminal_tests, get_env) do_terminal_tests, get_env)
from tests.modules import PowerlineTestSuite
VTERM_TEST_DIR = os.path.abspath('tests/vterm_vim') TEST_ROOT = os.path.abspath(os.environ['TEST_ROOT'])
def main(attempts=3): def main(attempts=3):
vterm_path = os.path.join(VTERM_TEST_DIR, 'path') vterm_path = os.path.join(TEST_ROOT, 'path')
vim_exe = os.path.join(vterm_path, 'vim') vim_exe = os.path.join(vterm_path, 'vim')
env = get_env(vterm_path, VTERM_TEST_DIR) env = get_env(vterm_path, TEST_ROOT)
env['ROOT'] = os.path.abspath('.')
dim = MutableDimensions(rows=50, cols=200) dim = MutableDimensions(rows=50, cols=200)
vimrc = os.path.join(TEST_ROOT, 'init.vim')
vimrc_contents = '''
set laststatus=2
set runtimepath=$ROOT/powerline/bindings/vim
'''
with open(vimrc, 'w') as vd:
vd.write(vimrc_contents)
base_attrs = {
(( 64, 64, 255), (0, 0, 0), 0, 0, 0): 'NT', # NonText
((240, 240, 240), (0, 0, 0), 0, 0, 0): 'N', # Normal
}
args = [
'-u', vimrc,
'-i', 'NONE',
]
def feed(p):
p.send(':echo strtrans(eval(&statusline[2:]))\n')
tests = ( tests = (
) )
args = [] with PowerlineTestSuite('vim') as suite:
return do_terminal_tests(
return do_terminal_tests( tests=tests,
tests=tests, cmd=vim_exe,
cmd=vim_exe, dim=dim,
dim=dim, args=args,
args=args, env=env,
env=env, cwd=TEST_ROOT,
cwd=VTERM_TEST_DIR, suite=suite,
) )
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -3,11 +3,9 @@
. tests/shlib/vterm.sh . tests/shlib/vterm.sh
. tests/shlib/vim.sh . tests/shlib/vim.sh
enter_suite vim enter_suite vvim final
VTERM_TEST_DIR="$ROOT/tests/vterm_vim" vterm_setup
vterm_setup "$VTERM_TEST_DIR"
test_vim() { test_vim() {
if test "$PYTHON_IMPLEMENTATION" != CPython ; then if test "$PYTHON_IMPLEMENTATION" != CPython ; then
@ -17,10 +15,10 @@ test_vim() {
if ! which "$POWERLINE_VIM_EXE" ; then if ! which "$POWERLINE_VIM_EXE" ; then
return 0 return 0
fi fi
ln -sf "$(which "${POWERLINE_VIM_EXE}")" "$VTERM_TEST_DIR/path/vim" ln -sf "$(which "${POWERLINE_VIM_EXE}")" "$TEST_ROOT/path/vim"
f="$ROOT/tests/test_in_vterm/test_vim.py" f="$ROOT/tests/test_in_vterm/test_vim.py"
if ! "${PYTHON}" "$f" ; then if ! "${PYTHON}" "$f" ; then
local test_name="$(LANG=C "$POWERLINE_VIM_EXE" --cmd 'echo version' --cmd qa 2>&1)" local test_name="$(LANG=C "$POWERLINE_VIM_EXE" --cmd 'echo version' --cmd qa 2>&1 | tail -n2)"
fail "$test_name" F "Failed vterm test $f" fail "$test_name" F "Failed vterm test $f"
fi fi
} }
@ -36,6 +34,6 @@ else
test_vim || true test_vim || true
fi fi
vterm_shutdown "$VTERM_TEST_DIR" vterm_shutdown
exit_suite exit_suite

View File

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

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
. tests/shlib/common.sh . tests/shlib/common.sh
enter_suite python enter_suite python final
for file in "$ROOT"/tests/test_python/test_*.py ; do for file in "$ROOT"/tests/test_python/test_*.py ; do
test_name="${file##*/test_}" test_name="${file##*/test_}"

View File

@ -125,6 +125,11 @@ class TestParser(TestCase):
'side': 'left', 'side': 'left',
'config_override': {'common': {}}, 'config_override': {'common': {}},
}), }),
(['shell', 'left', '--last-pipe-status='], {
'ext': ['shell'],
'side': 'left',
'last_pipe_status': [],
}),
]: ]:
args = parser.parse_args(argv) args = parser.parse_args(argv)
finish_args(parser, {}, args) finish_args(parser, {}, args)

View File

@ -6,6 +6,7 @@ import os
import sys import sys
import re import re
import shutil import shutil
import unicodedata
from time import sleep from time import sleep
from subprocess import call, PIPE from subprocess import call, PIPE
@ -497,22 +498,14 @@ class TestUnicode(TestCase):
if sys.maxunicode < 0x10FFFF: if sys.maxunicode < 0x10FFFF:
raise SkipTest('Can only test strwidth_ucs_4 in UCS-4 Pythons') raise SkipTest('Can only test strwidth_ucs_4 in UCS-4 Pythons')
def east_asian_width(ch): self.assertEqual(1, plu.strwidth_ucs_4(width_data, '\U0001F063'))
assert (len(ch) == 1)
assert ord(ch) == 0x1F48E
return 'F'
with replace_attr(plu, 'east_asian_width', east_asian_width):
# Warning: travis unicodedata.east_asian_width for some reason
# thinks this character is 5 symbols wide.
self.assertEqual(2, plu.strwidth_ucs_4(width_data, '\U0001F48E'))
def test_strwidth_ucs_2(self): def test_strwidth_ucs_2(self):
self.assertEqual(4, plu.strwidth_ucs_2(width_data, 'abcd')) self.assertEqual(4, plu.strwidth_ucs_2(width_data, 'abcd'))
self.assertEqual(4, plu.strwidth_ucs_2(width_data, '')) self.assertEqual(4, plu.strwidth_ucs_2(width_data, ''))
if not sys.maxunicode < 0x10FFFF: if not sys.maxunicode < 0x10FFFF:
raise SkipTest('Can only test strwidth_ucs_2 in UCS-2 Pythons') raise SkipTest('Can only test strwidth_ucs_2 in UCS-2 Pythons')
self.assertEqual(2, plu.strwidth_ucs_2(width_data, '\ud83d\udc8e')) self.assertEqual(1, plu.strwidth_ucs_2(width_data, '\ud83c\udc30'))
class TestVCS(TestCase): class TestVCS(TestCase):

View File

@ -138,7 +138,7 @@ class TestConfig(TestCase):
def test_bash(self): def test_bash(self):
from powerline.shell import ShellPowerline from powerline.shell import ShellPowerline
args = Args(last_exit_code=1, jobnum=0, ext=['shell'], renderer_module='.bash', config_override={'ext': {'shell': {'theme': 'default_leftonly'}}}) args = Args(last_exit_code=1, last_pipe_status=[], jobnum=0, ext=['shell'], renderer_module='.bash', config_override={'ext': {'shell': {'theme': 'default_leftonly'}}})
with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline:
powerline.render(segment_info={'args': args}) powerline.render(segment_info={'args': args})
with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline: with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline:

View File

@ -52,15 +52,35 @@ class TestShell(TestCase):
def test_last_pipe_status(self): def test_last_pipe_status(self):
pl = Pl() pl = Pl()
segment_info = {'args': Args(last_pipe_status=[])} segment_info = {'args': Args(last_pipe_status=[], last_exit_code=0)}
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None) self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None)
segment_info['args'].last_pipe_status = [0, 0, 0] segment_info['args'].last_pipe_status = [0, 0, 0]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None) self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None)
segment_info['args'].last_pipe_status = [0, 0]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None)
segment_info['args'].last_pipe_status = [0]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None)
segment_info['args'].last_pipe_status = [0, 2, 0] segment_info['args'].last_pipe_status = [0, 2, 0]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}, {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True},
{'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, {'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True},
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True} {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True},
])
segment_info['args'].last_pipe_status = [2, 0, 0]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [
{'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True},
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True},
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True},
])
segment_info['args'].last_pipe_status = [0, 0, 2]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True},
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True},
{'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True},
])
segment_info['args'].last_pipe_status = [2]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [
{'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True},
]) ])
segment_info['args'].last_pipe_status = [0, 'sigsegv', 'sigsegv+core'] segment_info['args'].last_pipe_status = [0, 'sigsegv', 'sigsegv+core']
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [ self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [
@ -80,6 +100,11 @@ class TestShell(TestCase):
{'contents': 'sigsegv+core', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True}, {'contents': 'sigsegv+core', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True},
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True} {'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}
]) ])
segment_info['args'].last_pipe_status = []
segment_info['args'].last_exit_code = 5
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [
{'contents': '5', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True},
])
def test_jobnum(self): def test_jobnum(self):
pl = Pl() pl = Pl()
@ -502,6 +527,11 @@ class TestEnv(TestCommon):
if hasattr(self.module, 'psutil') and not callable(self.module.psutil.Process.username): if hasattr(self.module, 'psutil') and not callable(self.module.psutil.Process.username):
username = property(username) username = property(username)
segment_info = {'environ': {}}
def user(*args, **kwargs):
return self.module.user(pl=pl, segment_info=segment_info, *args, **kwargs)
struct_passwd = namedtuple('struct_passwd', ('pw_name',)) struct_passwd = namedtuple('struct_passwd', ('pw_name',))
new_psutil = new_module('psutil', Process=Process) new_psutil = new_module('psutil', Process=Process)
new_pwd = new_module('pwd', getpwuid=lambda uid: struct_passwd(pw_name='def@DOMAIN.COM')) new_pwd = new_module('pwd', getpwuid=lambda uid: struct_passwd(pw_name='def@DOMAIN.COM'))
@ -512,21 +542,21 @@ class TestEnv(TestCommon):
with replace_attr(self.module, 'os', new_os): with replace_attr(self.module, 'os', new_os):
with replace_attr(self.module, 'psutil', new_psutil): with replace_attr(self.module, 'psutil', new_psutil):
with replace_attr(self.module, '_geteuid', lambda: 5): with replace_attr(self.module, '_geteuid', lambda: 5):
self.assertEqual(self.module.user(pl=pl), [ self.assertEqual(user(), [
{'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']} {'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']}
]) ])
self.assertEqual(self.module.user(pl=pl, hide_user='abc'), [ self.assertEqual(user(hide_user='abc'), [
{'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']} {'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']}
]) ])
self.assertEqual(self.module.user(pl=pl, hide_domain=False), [ self.assertEqual(user(hide_domain=False), [
{'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']} {'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']}
]) ])
self.assertEqual(self.module.user(pl=pl, hide_user='def@DOMAIN.COM'), None) self.assertEqual(user(hide_user='def@DOMAIN.COM'), None)
self.assertEqual(self.module.user(pl=pl, hide_domain=True), [ self.assertEqual(user(hide_domain=True), [
{'contents': 'def', 'highlight_groups': ['user']} {'contents': 'def', 'highlight_groups': ['user']}
]) ])
with replace_attr(self.module, '_geteuid', lambda: 0): with replace_attr(self.module, '_geteuid', lambda: 0):
self.assertEqual(self.module.user(pl=pl), [ self.assertEqual(user(), [
{'contents': 'def', 'highlight_groups': ['superuser', 'user']} {'contents': 'def', 'highlight_groups': ['superuser', 'user']}
]) ])

View File

@ -55,6 +55,7 @@ cd ../'(echo)'
cd ../'$(echo)' cd ../'$(echo)'
cd ../'`echo`' cd ../'`echo`'
cd ../'«Unicode!»' cd ../'«Unicode!»'
(exit 42)|(exit 43)
set_theme_option default_leftonly.segments.above "$ABOVE_LEFT" set_theme_option default_leftonly.segments.above "$ABOVE_LEFT"
export DISPLAYED_ENV_VAR=foo export DISPLAYED_ENV_VAR=foo
unset DISPLAYED_ENV_VAR unset DISPLAYED_ENV_VAR

View File

@ -26,7 +26,8 @@ def
  BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.segments.above "$ABOVE_LEFT"   BRANCH  …  shell  3rd  «Unicode!»  (exit 42)|(exit 43)
  BRANCH  …  shell  3rd  «Unicode!»  42  43  set_theme_option default_leftonly.segments.above "$ABOVE_LEFT"
  BRANCH  …  shell  3rd  «Unicode!»  export DISPLAYED_ENV_VAR=foo   BRANCH  …  shell  3rd  «Unicode!»  export DISPLAYED_ENV_VAR=foo
 foo    foo  
  BRANCH  …  shell  3rd  «Unicode!»  unset DISPLAYED_ENV_VAR   BRANCH  …  shell  3rd  «Unicode!»  unset DISPLAYED_ENV_VAR

View File

@ -26,7 +26,8 @@ def
  BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'   BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'   BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'   BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.segments.above "$ABOVE_LEFT"   BRANCH  …  shell  3rd  «Unicode!»  (exit 42)|(exit 43)
  BRANCH  …  shell  3rd  «Unicode!»  42  43  set_theme_option default_leftonly.segments.above "$ABOVE_LEFT"
  BRANCH  …  shell  3rd  «Unicode!»  export DISPLAYED_ENV_VAR=foo   BRANCH  …  shell  3rd  «Unicode!»  export DISPLAYED_ENV_VAR=foo
 foo    foo  
  BRANCH  …  shell  3rd  «Unicode!»  unset DISPLAYED_ENV_VAR   BRANCH  …  shell  3rd  «Unicode!»  unset DISPLAYED_ENV_VAR

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
. tests/shlib/common.sh . tests/shlib/common.sh
enter_suite shell enter_suite shell final
if test $# -eq 0 ; then if test $# -eq 0 ; then
FAST=1 FAST=1
@ -453,7 +453,7 @@ if test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "pdb" ; then
if ! run_test subclass python $PDB_PYTHON \ if ! run_test subclass python $PDB_PYTHON \
"$ROOT/tests/test_shells/pdb-main.py" "$ROOT/tests/test_shells/pdb-main.py"
then then
fail "pdb-subclass:test" F \ fail --allow-failure "pdb-subclass:test" F \
"Failed checking $PDB_PYTHON $ROOT/tests/test_shells/pdb-main.py" "Failed checking $PDB_PYTHON $ROOT/tests/test_shells/pdb-main.py"
fi fi
fi fi
@ -466,7 +466,7 @@ if test -z "${ONLY_SHELL}" || test "${ONLY_SHELL}" = "pdb" ; then
if ! run_test module python "$PDB_PYTHON" -m"$MODULE" \ if ! run_test module python "$PDB_PYTHON" -m"$MODULE" \
"$ROOT/tests/test_shells/pdb-script.py" "$ROOT/tests/test_shells/pdb-script.py"
then then
fail "pdb-module:test" F \ fail --allow-failure "pdb-module:test" F \
"Failed checking $PDB_PYTHON -m$MODULE $ROOT/tests/test_shells/pdb-script" "Failed checking $PDB_PYTHON -m$MODULE $ROOT/tests/test_shells/pdb-script"
fi fi
fi fi

View File

@ -1,10 +1,11 @@
#!/bin/sh #!/bin/sh
. tests/shlib/common.sh . tests/shlib/common.sh
. tests/shlib/vterm.sh
. tests/shlib/vim.sh . tests/shlib/vim.sh
enter_suite vim enter_suite vim final
make_test_root vterm_setup vim
# Define some overrides. These ones must be ignored and do not affect Vim # Define some overrides. These ones must be ignored and do not affect Vim
# status/tab lines. # status/tab lines.
@ -14,6 +15,7 @@ export POWERLINE_THEME_OVERRIDES='default.segments.left=[]'
test_script() { test_script() {
local vim="$1" ; shift local vim="$1" ; shift
local script="$1" ; shift local script="$1" ; shift
local allow_failure_arg="$1" ; shift
echo "Running script $script with $vim" echo "Running script $script with $vim"
if ! test -e "$vim" ; then if ! test -e "$vim" ; then
return 0 return 0
@ -22,7 +24,8 @@ test_script() {
|| test -f message.fail || test -f message.fail
then then
local test_name="${script##*/}" local test_name="${script##*/}"
fail "${test_name%.vim}" F "Failed script $script run with $vim" fail $allow_failure_arg "${test_name%.vim}" \
F "Failed script $script run with $vim"
if test -e message.fail ; then if test -e message.fail ; then
cat message.fail >&2 cat message.fail >&2
rm message.fail rm message.fail
@ -36,14 +39,22 @@ cd "$TEST_ROOT"
for script in "$TEST_SCRIPT_ROOT"/*.vim ; do for script in "$TEST_SCRIPT_ROOT"/*.vim ; do
if test "${script%.old.vim}" = "${script}" ; then if test "${script%.old.vim}" = "${script}" ; then
test_script "$NEW_VIM" "$script" test_script "$NEW_VIM" "$script" ""
fi fi
done done
if test "$PYTHON_VERSION_MAJOR.$PYTHON_VERSION_MINOR" = "2.7" ; then
ALLOW_FAILURE_ARG=--allow-failure
else
ALLOW_FAILURE_ARG=
fi
if test -e "$OLD_VIM" ; then if test -e "$OLD_VIM" ; then
for script in "$TEST_SCRIPT_ROOT"/*.old.vim ; do for script in "$TEST_SCRIPT_ROOT"/*.old.vim ; do
test_script "$OLD_VIM" "$script" test_script "$OLD_VIM" "$script" "$ALLOW_FAILURE_ARG"
done done
fi fi
vterm_shutdown
exit_suite exit_suite