Release 2.3

- Added ability to hide domain part of the user name to common.env.user segment.
- Added ability to show conda environment to virtualenv segment.
- Added systemd service file.
- Added ability to detect internal_ip interface using default gateway.
- Added support for password-protected connections in mpd player bindings.
- Added `output` option to i3wm.workspaces segment to filter workspaces based on
  their output.
- Added “charging” indicator to battery segment.
- Made tmux bindings show zoom indicator in window status.
- Fixed tmux bindings so that they support tmux-2.1.
- Fixed support for unicode characters in common.time.date segment.
This commit is contained in:
Foo 2015-10-20 12:54:26 +03:00
commit 7ed55bb25c
46 changed files with 658 additions and 360 deletions

View File

@ -8,11 +8,11 @@ addons:
packages: packages:
- libssl1.0.0 - libssl1.0.0
- zsh - zsh
# - tcsh - tcsh
# - mksh - mksh
# - busybox - busybox
# - rc # - rc
# - socat - socat
- bc - bc
language: python language: python
install: tests/install.sh install: tests/install.sh

View File

@ -7,7 +7,7 @@ Powerline
**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, tmux, IPython,
Awesome and Qtile.** 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

@ -0,0 +1,6 @@
*************
i3wm segments
*************
.. automodule:: powerline.segments.i3wm
:members:

View File

@ -467,7 +467,8 @@ Shell
``client_id`` ``client_id``
Identifier unique to one shell instance. Is used to record instance Identifier unique to one shell instance. Is used to record instance
state by powerline daemon. state by powerline daemon. In tmux this is the same as :ref:`pane_id
<dev-seginfo-shell-renarg-pane_id>`.
It is not guaranteed that existing client ID will not be retaken It is not guaranteed that existing client ID will not be retaken
when old shell with this ID quit: usually process PID is used as when old shell with this ID quit: usually process PID is used as
@ -481,6 +482,14 @@ Shell
Local theme that will be used by shell. One should not rely on the Local theme that will be used by shell. One should not rely on the
existence of this key. existence of this key.
.. _dev-seginfo-shell-renarg-pane_id:
``pane_id``
Identifier unique to each tmux pane. Is always an integer, optional.
Obtained by using ``tmux display -p '#D'``, then all leading spaces
and per cent signs are stripped and the result is converted into an
integer.
Other keys, if any, are specific to segments. Other keys, if any, are specific to segments.
Ipython Ipython

View File

@ -113,8 +113,7 @@ install a patched font.
Patched fonts Patched fonts
------------- -------------
This method is the fallback method and works for every terminal, with the This method is the fallback method and works for every terminal.
exception of :ref:`rxvt-unicode <tips-and-tricks-urxvt>`.
Download the font from `powerline-fonts`_. If preferred font cant be found in Download the font from `powerline-fonts`_. If preferred font cant be found in
the `powerline-fonts`_ repo, then patching the preferred font is needed instead. the `powerline-fonts`_ repo, then patching the preferred font is needed instead.

View File

@ -22,7 +22,7 @@ Python package
to be installed. ``coreutils`` may be installed using ``brew install to be installed. ``coreutils`` may be installed using ``brew install
coreutils``. coreutils``.
2. Install Powerline using one of the following commans: 2. Install Powerline using one of the following commands:
.. code-block:: sh .. code-block:: sh

View File

@ -4,7 +4,7 @@ Overview
**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, tmux, IPython,
Awesome and Qtile.** Awesome, i3 and Qtile.**
Features Features
-------- --------

View File

@ -7,6 +7,8 @@ import codecs
from collections import namedtuple from collections import namedtuple
from functools import reduce
from docutils.parsers.rst import Directive from docutils.parsers.rst import Directive
from docutils.parsers.rst.directives import unchanged_required from docutils.parsers.rst.directives import unchanged_required
from docutils import nodes from docutils import nodes

View File

@ -189,6 +189,25 @@ If your locale encoding is not unicode (any encoding that starts with “utf”
should set up your system to use unicode locale or forget about powerline fancy should set up your system to use unicode locale or forget about powerline fancy
characters. characters.
Urxvt unicode3 and frills
-------------------------
Make sure that, whatever urxvt package you're installing, both the `unicode3`
and `frills` features are enabled at compile time. Run
``urxvt --help 2>&1 | grep options:`` to get a list of enabled options.
This should contain at least `frills`, `unicode3` and optionally `iso14755`
if you want to input Unicode characters as well.
Compiler flags example:
--enable-frills \
--enable-unicode3
As long as your terminal emulator is compiled without unicode rendering,
no amount of configuration will make it display unicode characters.
They're being considered 'unnecessary features', but they add negligible
overhead to the size of the installed package (~100KB).
Vim issues Vim issues
========== ==========
@ -244,8 +263,8 @@ highlighting groups are usually cleared, including those defined by powerline.
To workaround this issue powerline hooks ``Colorscheme`` event, but when you To workaround this issue powerline hooks ``Colorscheme`` event, but when you
source vimrc with ``BufWritePost`` (or any other) event, but without ``nested`` source vimrc with ``BufWritePost`` (or any other) event, but without ``nested``
this event is not launched. See also `autocmd-nested this event is not launched. See also `autocmd-nested
<http://vimpluginloader.sourceforge.net/doc/autocmd.txt.html#autocmd-nested>`_ <http://vimcommunity.bitbucket.org/doc/autocmd.txt.html#autocmd-nested>`_ Vim
Vim documentation. documentation.
Powerline loses color after saving any file Powerline loses color after saving any file
------------------------------------------- -------------------------------------------

View File

@ -2,11 +2,11 @@ set -g status on
set -g status-utf8 on set -g status-utf8 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 #[$_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 $_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

@ -10,7 +10,7 @@ from itertools import chain
from powerline.lib.overrides import parsedotval, parse_override_var 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 from powerline.lib.unicode import u, unicode
if sys.version_info < (3,): if sys.version_info < (3,):
@ -49,6 +49,14 @@ def finish_args(environ, args):
)) ))
if args.renderer_arg: if args.renderer_arg:
args.renderer_arg = mergeargs((parsedotval(v) for v in args.renderer_arg), remove=True) args.renderer_arg = mergeargs((parsedotval(v) for v in args.renderer_arg), remove=True)
if 'pane_id' in args.renderer_arg:
if isinstance(args.renderer_arg['pane_id'], (bytes, unicode)):
try:
args.renderer_arg['pane_id'] = int(args.renderer_arg['pane_id'].lstrip(' %'))
except ValueError:
pass
if 'client_id' not in args.renderer_arg:
args.renderer_arg['client_id'] = args.renderer_arg['pane_id']
args.config_path = ( args.config_path = (
[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 [])

View File

@ -51,7 +51,9 @@
"powerline.segments.common.bat.battery": { "powerline.segments.common.bat.battery": {
"args": { "args": {
"full_heart": "O", "full_heart": "O",
"empty_heart": "O" "empty_heart": "O",
"online": "C",
"offline": " "
} }
}, },
"powerline.segments.common.sys.uptime": { "powerline.segments.common.sys.uptime": {

View File

@ -50,7 +50,9 @@
"powerline.segments.common.bat.battery": { "powerline.segments.common.bat.battery": {
"args": { "args": {
"full_heart": "♥", "full_heart": "♥",
"empty_heart": "♥" "empty_heart": "♥",
"online": "⚡︎",
"offline": " "
} }
}, },
"powerline.segments.common.sys.uptime": { "powerline.segments.common.sys.uptime": {

View File

@ -50,7 +50,9 @@
"powerline.segments.common.bat.battery": { "powerline.segments.common.bat.battery": {
"args": { "args": {
"full_heart": "💙", "full_heart": "💙",
"empty_heart": "💛" "empty_heart": "💛",
"online": "⚡️",
"offline": " "
} }
}, },
"powerline.segments.common.sys.uptime": { "powerline.segments.common.sys.uptime": {

View File

@ -50,7 +50,9 @@
"powerline.segments.common.bat.battery": { "powerline.segments.common.bat.battery": {
"args": { "args": {
"full_heart": "♥", "full_heart": "♥",
"empty_heart": "♥" "empty_heart": "♥",
"online": "⚡︎",
"offline": " "
} }
}, },
"powerline.segments.common.sys.uptime": { "powerline.segments.common.sys.uptime": {

View File

@ -50,7 +50,9 @@
"powerline.segments.common.bat.battery": { "powerline.segments.common.bat.battery": {
"args": { "args": {
"full_heart": "♥", "full_heart": "♥",
"empty_heart": "♥" "empty_heart": "♥",
"online": "⚡︎",
"offline": " "
} }
}, },
"powerline.segments.common.sys.uptime": { "powerline.segments.common.sys.uptime": {

View File

@ -51,7 +51,9 @@
"powerline.segments.common.bat.battery": { "powerline.segments.common.bat.battery": {
"args": { "args": {
"full_heart": "♥", "full_heart": "♥",
"empty_heart": "♥" "empty_heart": "♥",
"online": "⚡︎",
"offline": " "
} }
}, },
"powerline.segments.common.sys.uptime": { "powerline.segments.common.sys.uptime": {

View File

@ -0,0 +1,10 @@
[Unit]
Description=powerline-daemon - Daemon that improves powerline performance
Documentation=man:powerline-daemon(1)
Documentation=https://powerline.readthedocs.org/en/latest/
[Service]
ExecStart=/usr/bin/powerline-daemon --foreground
[Install]
WantedBy=default.target

View File

@ -134,7 +134,7 @@ class INotify(object):
eno = ctypes.get_errno() eno = ctypes.get_errno()
extra = '' extra = ''
if eno == errno.ENOSPC: if eno == errno.ENOSPC:
extra = 'You may need to increase the inotify limits on your system, via /proc/sys/inotify/max_user_*' extra = 'You may need to increase the inotify limits on your system, via /proc/sys/fs/inotify/max_user_*'
raise OSError(eno, self.os.strerror(eno) + str(extra)) raise OSError(eno, self.os.strerror(eno) + str(extra))
def __del__(self): def __del__(self):

View File

@ -63,7 +63,7 @@ class TmuxRenderer(Renderer):
if segment_info: if segment_info:
r.update(segment_info) r.update(segment_info)
if 'pane_id' in r: if 'pane_id' in r:
varname = 'TMUX_PWD_' + r['pane_id'].lstrip('%') varname = 'TMUX_PWD_' + str(r['pane_id'])
if varname in r['environ']: if varname in r['environ']:
r['getcwd'] = lambda: r['environ'][varname] r['getcwd'] = lambda: r['environ'][varname]
r['mode'] = mode r['mode'] = mode

View File

@ -8,11 +8,7 @@ import re
from powerline.lib.shell import run_cmd from powerline.lib.shell import run_cmd
# XXX Warning: module name must not be equal to the segment name as long as this def _fetch_battery_info(pl):
# segment is imported into powerline.segments.common module.
def _get_battery(pl):
try: try:
import dbus import dbus
except ImportError: except ImportError:
@ -51,27 +47,37 @@ def _get_battery(pl):
pl.debug('Not using DBUS+UPower with {0}: not a power supply', devpath) pl.debug('Not using DBUS+UPower with {0}: not a power supply', devpath)
continue continue
pl.debug('Using DBUS+UPower with {0}', devpath) pl.debug('Using DBUS+UPower with {0}', devpath)
return lambda pl: float( return lambda pl: (
float(
dbus.Interface(dev, dbus_interface=devinterface).Get(
devtype_name,
'Percentage'
),
),
dbus.Interface(dev, dbus_interface=devinterface).Get( dbus.Interface(dev, dbus_interface=devinterface).Get(
devtype_name, devtype_name,
'Percentage' 'State'
) ) == 1
) )
pl.debug('Not using DBUS+UPower as no batteries were found') pl.debug('Not using DBUS+UPower as no batteries were found')
if os.path.isdir('/sys/class/power_supply'): if os.path.isdir('/sys/class/power_supply'):
linux_bat_fmt = '/sys/class/power_supply/{0}/capacity' linux_bat_fmt = '/sys/class/power_supply/{0}/capacity'
linux_ac_fmt = '/sys/class/power_supply/{0}/online'
for linux_bat in os.listdir('/sys/class/power_supply'): for linux_bat in os.listdir('/sys/class/power_supply'):
cap_path = linux_bat_fmt.format(linux_bat) cap_path = linux_bat_fmt.format(linux_bat)
online_path = linux_ac_fmt.format(linux_bat)
if linux_bat.startswith('BAT') and os.path.exists(cap_path): if linux_bat.startswith('BAT') and os.path.exists(cap_path):
pl.debug('Using /sys/class/power_supply with battery {0}', linux_bat) pl.debug('Using /sys/class/power_supply with battery {0}', linux_bat)
def _get_capacity(pl): def _get_battery_status(pl):
with open(cap_path, 'r') as f: with open(cap_path, 'r') as f:
return int(float(f.readline().split()[0])) _capacity = int(float(f.readline().split()[0]))
with open(online_path, 'r') as f:
return _get_capacity _ac_powered = f.readline() == 1
pl.debug('Not using /sys/class/power_supply as no batteries were found') return _capacity, _ac_powered
return _get_battery_status
pl.debug('Not using /sys/class/power_supply as no batteries were found')
else: else:
pl.debug('Not using /sys/class/power_supply: no directory') pl.debug('Not using /sys/class/power_supply: no directory')
@ -86,12 +92,12 @@ def _get_battery(pl):
BATTERY_PERCENT_RE = re.compile(r'(\d+)%') BATTERY_PERCENT_RE = re.compile(r'(\d+)%')
def _get_capacity(pl): def _get_battery_status(pl):
battery_summary = run_cmd(pl, ['pmset', '-g', 'batt']) battery_summary = run_cmd(pl, ['pmset', '-g', 'batt'])
battery_percent = BATTERY_PERCENT_RE.search(battery_summary).group(1) battery_percent = BATTERY_PERCENT_RE.search(battery_summary).group(1)
return int(battery_percent) ac_charging = 'AC' in battery_summary
return int(battery_percent), ac_charging
return _get_capacity return _get_battery_status
else: else:
pl.debug('Not using pmset: executable not found') pl.debug('Not using pmset: executable not found')
@ -110,11 +116,11 @@ def _get_battery(pl):
for battery in wmi.InstancesOf('Win32_Battery'): for battery in wmi.InstancesOf('Win32_Battery'):
pl.debug('Using win32com.client with Win32_Battery') pl.debug('Using win32com.client with Win32_Battery')
def _get_capacity(pl): def _get_battery_status(pl):
# http://msdn.microsoft.com/en-us/library/aa394074(v=vs.85).aspx # http://msdn.microsoft.com/en-us/library/aa394074(v=vs.85).aspx
return battery.EstimatedChargeRemaining return battery.EstimatedChargeRemaining, battery.BatteryStatus == 6
return _get_capacity return _get_battery_status
pl.debug('Not using win32com.client as no batteries were found') pl.debug('Not using win32com.client as no batteries were found')
from ctypes import Structure, c_byte, c_ulong, byref from ctypes import Structure, c_byte, c_ulong, byref
if sys.platform == 'cygwin': if sys.platform == 'cygwin':
@ -136,52 +142,57 @@ def _get_battery(pl):
('BatteryFullLifeTime', c_ulong) ('BatteryFullLifeTime', c_ulong)
] ]
def _get_capacity(pl): def _get_battery_status(pl):
powerclass = PowerClass() powerclass = PowerClass()
result = library_loader.kernel32.GetSystemPowerStatus(byref(powerclass)) result = library_loader.kernel32.GetSystemPowerStatus(byref(powerclass))
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa372693(v=vs.85).aspx # http://msdn.microsoft.com/en-us/library/windows/desktop/aa372693(v=vs.85).aspx
if result: if result:
return None return None
return powerclass.BatteryLifePercent return powerclass.BatteryLifePercent, powerclass.ACLineStatus == 1
if _get_capacity() is None: if _get_battery_status() is None:
pl.debug('Not using GetSystemPowerStatus because it failed') pl.debug('Not using GetSystemPowerStatus because it failed')
else: else:
pl.debug('Using GetSystemPowerStatus') pl.debug('Using GetSystemPowerStatus')
return _get_capacity return _get_battery_status
raise NotImplementedError raise NotImplementedError
def _get_capacity(pl): def _get_battery_status(pl):
global _get_capacity global _get_battery_status
def _failing_get_capacity(pl): def _failing_get_status(pl):
raise NotImplementedError raise NotImplementedError
try: try:
_get_capacity = _get_battery(pl) _get_battery_status = _fetch_battery_info(pl)
except NotImplementedError: except NotImplementedError:
_get_capacity = _failing_get_capacity _get_battery_status = _failing_get_status
except Exception as e: except Exception as e:
pl.exception('Exception while obtaining battery capacity getter: {0}', str(e)) pl.exception('Exception while obtaining battery status: {0}', str(e))
_get_capacity = _failing_get_capacity _get_battery_status = _failing_get_status
return _get_capacity(pl) return _get_battery_status(pl)
def battery(pl, format='{capacity:3.0%}', steps=5, gamify=False, full_heart='O', empty_heart='O'): def battery(pl, format='{ac_state} {capacity:3.0%}', steps=5, gamify=False, full_heart='O', empty_heart='O', online='C', offline=' '):
'''Return battery charge status. '''Return battery charge status.
:param str format: :param str format:
Percent format in case gamify is False. Percent format in case gamify is False. Format arguments: ``ac_state``
which is equal to either ``online`` or ``offline`` string arguments and
``capacity`` which is equal to current battery capacity in interval [0,
100].
:param int steps: :param int steps:
Number of discrete steps to show between 0% and 100% capacity if gamify Number of discrete steps to show between 0% and 100% capacity if gamify
is True. is True.
:param bool gamify: :param bool gamify:
Measure in hearts () instead of percentages. For full hearts Measure in hearts () instead of percentages. For full hearts
``battery_full`` highlighting group is preferred, for empty hearts there ``battery_full`` highlighting group is preferred, for empty hearts there
is ``battery_empty``. is ``battery_empty``. ``battery_online`` or ``battery_offline`` group
will be used for leading segment containing ``online`` or ``offline``
argument contents.
:param str full_heart: :param str full_heart:
Heart displayed for full part of battery. Heart displayed for full part of battery.
:param str empty_heart: :param str empty_heart:
@ -189,21 +200,32 @@ def battery(pl, format='{capacity:3.0%}', steps=5, gamify=False, full_heart='O',
another gradient level and highlighting group, so it is OK for it to be another gradient level and highlighting group, so it is OK for it to be
the same as full_heart as long as necessary highlighting groups are the same as full_heart as long as necessary highlighting groups are
defined. defined.
:param str online:
Symbol used if computer is connected to a power supply.
:param str offline:
Symbol used if computer is not connected to a power supply.
``battery_gradient`` and ``battery`` groups are used in any case, first is ``battery_gradient`` and ``battery`` groups are used in any case, first is
preferred. preferred.
Highlight groups used: ``battery_full`` or ``battery_gradient`` (gradient) or ``battery``, ``battery_empty`` or ``battery_gradient`` (gradient) or ``battery``. Highlight groups used: ``battery_full`` or ``battery_gradient`` (gradient) or ``battery``, ``battery_empty`` or ``battery_gradient`` (gradient) or ``battery``, ``battery_online`` or ``battery_ac_state`` or ``battery_gradient`` (gradient) or ``battery``, ``battery_offline`` or ``battery_ac_state`` or ``battery_gradient`` (gradient) or ``battery``.
''' '''
try: try:
capacity = _get_capacity(pl) capacity, ac_powered = _get_battery_status(pl)
except NotImplementedError: except NotImplementedError:
pl.info('Unable to get battery capacity.') pl.info('Unable to get battery status.')
return None return None
ret = [] ret = []
if gamify: if gamify:
denom = int(steps) denom = int(steps)
numer = int(denom * capacity / 100) numer = int(denom * capacity / 100)
ret.append({
'contents': online if ac_powered else offline,
'draw_inner_divider': False,
'highlight_groups': ['battery_online' if ac_powered else 'battery_offline', 'battery_ac_state', 'battery_gradient', 'battery'],
'gradient_level': 0,
})
ret.append({ ret.append({
'contents': full_heart * numer, 'contents': full_heart * numer,
'draw_inner_divider': False, 'draw_inner_divider': False,
@ -220,7 +242,7 @@ def battery(pl, format='{capacity:3.0%}', steps=5, gamify=False, full_heart='O',
}) })
else: else:
ret.append({ ret.append({
'contents': format.format(capacity=(capacity / 100.0)), 'contents': format.format(ac_state=(online if ac_powered else offline), capacity=(capacity / 100.0)),
'highlight_groups': ['battery_gradient', 'battery'], 'highlight_groups': ['battery_gradient', 'battery'],
# Gradients are “least alert most alert” by default, capacity has # Gradients are “least alert most alert” by default, capacity has
# the opposite semantics. # the opposite semantics.

View File

@ -19,9 +19,20 @@ def environment(pl, segment_info, variable=None):
@requires_segment_info @requires_segment_info
def virtualenv(pl, segment_info): def virtualenv(pl, segment_info, ignore_venv=False, ignore_conda=False):
'''Return the name of the current Python virtualenv.''' '''Return the name of the current Python or conda virtualenv.
return os.path.basename(segment_info['environ'].get('VIRTUAL_ENV', '')) or None
:param bool ignore_venv:
Whether to ignore virtual environments. Default is False.
:param bool ignore_conda:
Whether to ignore conda environments. Default is False.
'''
return (
(not ignore_venv and
os.path.basename(segment_info['environ'].get('VIRTUAL_ENV', ''))) or
(not ignore_conda and
segment_info['environ'].get('CONDA_DEFAULT_ENV', '')) or
None)
@requires_segment_info @requires_segment_info
@ -148,11 +159,13 @@ username = False
_geteuid = getattr(os, 'geteuid', lambda: 1) _geteuid = getattr(os, 'geteuid', lambda: 1)
def user(pl, hide_user=None): def user(pl, hide_user=None, hide_domain=False):
'''Return the current user. '''Return the current user.
:param str hide_user: :param str hide_user:
Omit showing segment for users with names equal to this string. Omit showing segment for users with names equal to this string.
:param bool hide_domain:
Drop domain component if it exists in a username (delimited by '@').
Highlights the user with the ``superuser`` if the effective user ID is 0. Highlights the user with the ``superuser`` if the effective user ID is 0.
@ -166,6 +179,11 @@ def user(pl, hide_user=None):
return None return None
if username == hide_user: if username == hide_user:
return None return None
if hide_domain:
try:
username = username[:username.index('@')]
except ValueError:
pass
euid = _geteuid() euid = _geteuid()
return [{ return [{
'contents': username, 'contents': username,

View File

@ -101,16 +101,24 @@ else:
return 0 return 0
def internal_ip(pl, interface='auto', ipv=4): def internal_ip(pl, interface='auto', ipv=4):
family = netifaces.AF_INET6 if ipv == 6 else netifaces.AF_INET
if interface == 'auto': if interface == 'auto':
try: try:
interface = next(iter(sorted(netifaces.interfaces(), key=_interface_key, reverse=True))) interface = next(iter(sorted(netifaces.interfaces(), key=_interface_key, reverse=True)))
except StopIteration: except StopIteration:
pl.info('No network interfaces found') pl.info('No network interfaces found')
return None return None
elif interface == 'default_gateway':
try:
interface = netifaces.gateways()['default'][family][1]
except KeyError:
pl.info('No default gateway found for IPv{0}', ipv)
return None
addrs = netifaces.ifaddresses(interface) addrs = netifaces.ifaddresses(interface)
try: try:
return addrs[netifaces.AF_INET6 if ipv == 6 else netifaces.AF_INET][0]['addr'] return addrs[family][0]['addr']
except (KeyError, IndexError): except (KeyError, IndexError):
pl.info("No IPv{0} address found for interface {1}", ipv, interface)
return None return None
@ -130,6 +138,11 @@ Requires ``netifaces`` module to work properly.
#. ``teredo`` followed by number or the end of string. #. ``teredo`` followed by number or the end of string.
#. Any other interface that is not ``lo*``. #. Any other interface that is not ``lo*``.
#. ``lo`` followed by number or the end of string. #. ``lo`` followed by number or the end of string.
Use ``default_gateway`` to detect the interface based on the machine's
`default gateway <https://en.wikipedia.org/wiki/Default_gateway>`_ (i.e.,
the router to which it is connected).
:param int ipv: :param int ipv:
4 or 6 for ipv4 and ipv6 respectively, depending on which IP address you 4 or 6 for ipv4 and ipv6 respectively, depending on which IP address you
need exactly. need exactly.
@ -150,7 +163,10 @@ try:
return if_io.bytes_recv, if_io.bytes_sent return if_io.bytes_recv, if_io.bytes_sent
def _get_interfaces(): def _get_interfaces():
io_counters = psutil.network_io_counters(pernic=True) try:
io_counters = psutil.net_io_counters(pernic=True)
except AttributeError:
io_counters = psutil.network_io_counters(pernic=True)
for interface, data in io_counters.items(): for interface, data in io_counters.items():
if data: if data:
yield interface, data.bytes_recv, data.bytes_sent yield interface, data.bytes_recv, data.bytes_sent

View File

@ -167,14 +167,16 @@ Requires cmus-remote command be acessible from $PATH.
class MpdPlayerSegment(PlayerSegment): class MpdPlayerSegment(PlayerSegment):
def get_player_status(self, pl, host='localhost', port=6600): def get_player_status(self, pl, host='localhost', password=None, port=6600):
try: try:
import mpd import mpd
except ImportError: except ImportError:
if password:
host = password + '@' + host
now_playing = run_cmd(pl, [ now_playing = run_cmd(pl, [
'mpc', 'current', 'mpc', 'current',
'-f', '%album%\n%artist%\n%title%\n%time%', '-f', '%album%\n%artist%\n%title%\n%time%',
'-h', str(host), '-h', host,
'-p', str(port) '-p', str(port)
], strip=False) ], strip=False)
if not now_playing: if not now_playing:
@ -189,6 +191,8 @@ class MpdPlayerSegment(PlayerSegment):
else: else:
client = mpd.MPDClient() client = mpd.MPDClient()
client.connect(host, port) client.connect(host, port)
if password:
client.password(password)
now_playing = client.currentsong() now_playing = client.currentsong()
if not now_playing: if not now_playing:
return return
@ -220,6 +224,8 @@ package) or alternatively the ``mpc`` command to be acessible from $PATH.
{0} {0}
:param str host: :param str host:
Host on which mpd runs. Host on which mpd runs.
:param str password:
Password used for connecting to daemon.
:param int port: :param int port:
Port which should be connected to. Port which should be connected to.
''').format(_common_args.format('mpd'))) ''').format(_common_args.format('mpd')))

View File

@ -16,8 +16,13 @@ def date(pl, format='%Y-%m-%d', istime=False):
Highlight groups used: ``time`` or ``date``. Highlight groups used: ``time`` or ``date``.
''' '''
try:
contents = datetime.now().strftime(format)
except UnicodeEncodeError:
contents = datetime.now().strftime(format.encode('utf-8')).decode('utf-8')
return [{ return [{
'contents': datetime.now().strftime(format), 'contents': contents,
'highlight_groups': (['time'] if istime else []) + ['date'], 'highlight_groups': (['time'] if istime else []) + ['date'],
'divider_highlight_group': 'time:divider' if istime else None, 'divider_highlight_group': 'time:divider' if istime else None,
}] }]

View File

@ -19,7 +19,7 @@ def calcgrp(w):
return group return group
def workspaces(pl, only_show=None, strip=0): def workspaces(pl, only_show=None, output=None, strip=0):
'''Return list of used workspaces '''Return list of used workspaces
:param list only_show: :param list only_show:
@ -27,6 +27,9 @@ def workspaces(pl, only_show=None, strip=0):
``"urgent"`` and ``"focused"``. If omitted or ``null`` all workspaces ``"urgent"`` and ``"focused"``. If omitted or ``null`` all workspaces
are shown. are shown.
:param str output:
If specified, only workspaces on this output are shown.
:param int strip: :param int strip:
Specifies how many characters from the front of each workspace name Specifies how many characters from the front of each workspace name
should be stripped (e.g. to remove workspace numbers). Defaults to zero. should be stripped (e.g. to remove workspace numbers). Defaults to zero.
@ -45,7 +48,10 @@ def workspaces(pl, only_show=None, strip=0):
return [{ return [{
'contents': w['name'][min(len(w['name']), strip):], 'contents': w['name'][min(len(w['name']), strip):],
'highlight_groups': calcgrp(w) 'highlight_groups': calcgrp(w)
} for w in conn.get_workspaces() if not only_show or any((w[typ] for typ in only_show))] } for w in conn.get_workspaces()
if (not only_show or any(w[typ] for typ in only_show))
and (not output or w['output'] == output)
]
@requires_segment_info @requires_segment_info

View File

@ -147,38 +147,42 @@ def create_ebuilds(version_string, overlay, user, **kwargs):
live_ebuild = None live_ebuild = None
for ebuild in os.listdir(pdir): for ebuild in os.listdir(pdir):
if ebuild.endswith('.ebuild') and '9999' in ebuild: if ebuild.endswith('.ebuild') and '9999' in ebuild:
live_ebuild_base = ebuild
live_ebuild = os.path.join(pdir, ebuild) live_ebuild = os.path.join(pdir, ebuild)
break break
assert(live_ebuild) assert(live_ebuild)
vcur = os.path.join(pdir, '{0}-{1}.ebuild'.format(pn, version_string)) vcur = os.path.join(pdir, '{0}-{1}.ebuild'.format(pn, version_string))
with open(live_ebuild) as LEF: if pn == 'powerline-vim':
with open(vcur, 'w') as F: with open(live_ebuild) as LEF:
dropnext = False with open(vcur, 'w') as F:
for line in LEF: dropnext = False
if line.startswith('EGIT'): for line in LEF:
# Drop all EGIT_… and the next empty line if line.startswith('EGIT'):
dropnext = True # Drop all EGIT_… and the next empty line
next_re = re.compile('^$') dropnext = True
continue next_re = re.compile('^$')
if dropnext: continue
assert(next_re.match(line)) if dropnext:
dropnext = False assert(next_re.match(line))
continue dropnext = False
if line.startswith('# Note the lack of an assignment to ${S}'): continue
next_re = re.compile('^#') if line.startswith('# Note the lack of an assignment to ${S}'):
dropnext = True next_re = re.compile('^#')
line = 'S="${WORKDIR}/${MY_P}"\n' dropnext = True
if line.startswith('inherit'): line = 'S="${WORKDIR}/${MY_P}"\n'
line = line.replace(' git-r3', '') if line.startswith('inherit'):
line += '\n' line = line.replace(' git-r3', '')
line += 'MY_PN="powerline-status"\n' line += '\n'
line += 'MY_P="${MY_PN}-${PV}"' line += 'MY_PN="powerline-status"\n'
line += '\n' line += 'MY_P="${MY_PN}-${PV}"'
elif line.startswith('HOMEPAGE'): line += '\n'
line += 'SRC_URI="mirror://pypi/p/${MY_PN}/${MY_P}.tar.gz"\n' elif line.startswith('HOMEPAGE'):
elif line.startswith('KEYWORDS'): line += 'SRC_URI="mirror://pypi/p/${MY_PN}/${MY_P}.tar.gz"\n'
line = 'KEYWORDS="~amd64 ~ppc ~x86 ~x86-fbsd"\n' elif line.startswith('KEYWORDS'):
F.write(line) line = 'KEYWORDS="~amd64 ~ppc ~x86 ~x86-fbsd"\n'
F.write(line)
else:
os.symlink(live_ebuild_base, vcur)
new_files.append(vcur) new_files.append(vcur)
check_call(['ebuild', vcur, 'manifest']) check_call(['ebuild', vcur, 'manifest'])
new_files.append(os.path.join(pdir, 'Manifest')) new_files.append(os.path.join(pdir, 'Manifest'))

View File

@ -59,7 +59,7 @@ else:
def get_version(): def get_version():
base_version = '2.2' base_version = '2.3'
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.2', version='2.3',
description='The ultimate statusline/prompt utility.', description='The ultimate statusline/prompt utility.',
long_description=README, long_description=README,
classifiers=[ classifiers=[

33
tests/common.sh Normal file
View File

@ -0,0 +1,33 @@
. 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%/*}"
exit $FAILED
}
fail() {
local test_name="$1"
local fail_char="$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
FAILED=1
}

View File

@ -29,7 +29,11 @@ checkout_cached_dir git://github.com/powerline/deps tests/bot-ci/deps
mkdir -p "$HOME/opt" mkdir -p "$HOME/opt"
if test -n "$USE_UCS2_PYTHON" ; then if test -n "$USE_UCS2_PYTHON" ; then
pip install virtualenvwrapper if test "$UCS2_PYTHON_VARIANT" = "2.6" ; then
pip install 'virtualenvwrapper==4.6.0'
else
pip install virtualenvwrapper
fi
set +e set +e
. virtualenvwrapper.sh . virtualenvwrapper.sh
set -e set -e

View File

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

View File

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

View File

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

View File

@ -1,11 +1,12 @@
#!/bin/sh #!/bin/sh
. tests/bot-ci/scripts/common/main.sh . tests/common.sh
FAILED=0
enter_suite vim
if test -z "$VIM" ; then if test -z "$VIM" ; then
if test -n "$USE_UCS2_PYTHON" ; then if test -n "$USE_UCS2_PYTHON" ; then
NEW_VIM="$ROOT/tests/bot-ci/deps/vim/tip-$UCS2_PYTHON_VARIANT-ucs2-double/vim" 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" 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" opt_dir="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT"
main_path="$opt_dir/lib/python$UCS2_PYTHON_VARIANT" main_path="$opt_dir/lib/python$UCS2_PYTHON_VARIANT"
site_path="$main_path/site-packages" site_path="$main_path/site-packages"
@ -18,8 +19,8 @@ if test -z "$VIM" ; then
exit 0 exit 0
fi fi
if test -d "$ROOT/tests/bot-ci/deps" ; then if test -d "$ROOT/tests/bot-ci/deps" ; then
NEW_VIM="$ROOT/tests/bot-ci/deps/vim/tip-$PYTHON_MM/vim" 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" OLD_VIM="$ROOT/tests/bot-ci/deps/vim/v7.0.112-$PYTHON_MM/vim"
else else
NEW_VIM="vim" NEW_VIM="vim"
fi fi
@ -42,28 +43,29 @@ export POWERLINE_THEME_OVERRIDES='default.segments.left=[]'
test_script() { test_script() {
local vim="$1" local vim="$1"
local script="$2" local script="$2"
local test_name_prefix="$3"
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
fi fi
if ! "$vim" -u NONE -S $script || test -f message.fail ; then if ! "$vim" -u NONE -S $script || test -f message.fail ; then
echo "Failed script $script run with $VIM" >&2 local test_name="$test_name_prefix-${script##*/}"
fail "${test_name%.vim}" F "Failed script $script run with $VIM"
cat message.fail >&2 cat message.fail >&2
rm message.fail rm message.fail
FAILED=1
fi fi
} }
for script in tests/test_*.vim ; do for script in tests/test_*.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" new
fi fi
done done
if test -e "$OLD_VIM" ; then if test -e "$OLD_VIM" ; then
for script in tests/test_*.old.vim ; do for script in tests/test_*.old.vim ; do
test_script "$OLD_VIM" "$script" test_script "$OLD_VIM" "$script" old
done done
fi fi
exit $FAILED exit_suite

View File

@ -1,8 +1,13 @@
#!/bin/sh #!/bin/sh
set -e . tests/common.sh
FAILED=0
if ! sh tests/test_in_vterm/test.sh ; then enter_suite vterm
echo "Failed vterm"
FAILED=1 for t in tests/test_in_vterm/test_*.sh ; do
fi test_name="${t##*/test_}"
exit $FAILED if ! sh "$t" ; then
fail "${test_name%.sh}" F "Failed running $t"
fi
done
exit_suite

View File

@ -1,20 +1,16 @@
#!/bin/bash #!/bin/bash
. tests/bot-ci/scripts/common/main.sh . tests/common.sh
enter_suite root
: ${USER:=`id -un`} : ${USER:=`id -un`}
: ${HOME:=`getent passwd $USER | cut -d: -f6`} : ${HOME:=`getent passwd $USER | cut -d: -f6`}
export USER HOME export USER HOME
FAILED=0
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"
export PATH="$PWD/tests/bot-ci/deps/mksh:$PATH"
export PATH="$PWD/tests/bot-ci/deps/busybox:$PATH"
export PATH="$PWD/tests/bot-ci/deps/tcsh:$PATH"
export PATH="$PWD/tests/bot-ci/deps/socat:$PATH"
if test "$PYTHON_IMPLEMENTATION" = "CPython" ; then if test "$PYTHON_IMPLEMENTATION" = "CPython" ; then
export PATH="$HOME/opt/zsh-${PYTHON_MM}${USE_UCS2_PYTHON:+-ucs2}/bin:${PATH}" export PATH="$HOME/opt/zsh-${PYTHON_MM}${USE_UCS2_PYTHON:+-ucs2}/bin:${PATH}"
@ -38,9 +34,16 @@ 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 tests/run_*_tests.sh ; do
test_name="${script##*/run_}"
if ! sh $script ; then if ! sh $script ; then
echo "Failed $script" fail "${test_name%_tests.sh}" F "Failed $script"
FAILED=1
fi fi
done done
exit $FAILED
if test -e tests/failures ; then
echo "Some tests failed. Summary:"
cat tests/failures
rm tests/failures
fi
exit_suite

View File

@ -1,55 +0,0 @@
#!/bin/sh
. tests/bot-ci/scripts/common/main.sh
set +x
FAILED=0
rm -rf tests/vterm
mkdir tests/vterm
mkdir tests/vterm/path
ln -s "$(which "${PYTHON}")" tests/vterm/path/python
ln -s "$(which bash)" tests/vterm/path
ln -s "$(which env)" tests/vterm/path
ln -s "$(which cut)" tests/vterm/path
ln -s "$PWD/scripts/powerline-render" tests/vterm/path
ln -s "$PWD/scripts/powerline-config" tests/vterm/path
cp -r tests/terminfo tests/vterm
FAIL_SUMMARY=""
test_tmux() {
if test "$PYTHON_IMPLEMENTATION" = PyPy; then
# FIXME PyPy3 segfaults for some reason, PyPy does it as well, but
# occasionally.
return 0
fi
if ! which "${POWERLINE_TMUX_EXE}" ; then
return 0
fi
ln -sf "$(which "${POWERLINE_TMUX_EXE}")" tests/vterm/path
f=tests/test_in_vterm/test_tmux.py
if ! "${PYTHON}" $f ; then
echo "Failed vterm test $f"
FAILED=1
FAIL_SUMMARY="$FAIL_SUMMARY${NL}F $POWERLINE_TMUX_EXE $f"
fi
}
if test -z "$POWERLINE_TMUX_EXE" && test -d tests/bot-ci/deps/tmux ; then
for tmux in tests/bot-ci/deps/tmux/tmux-*/tmux ; do
export POWERLINE_TMUX_EXE="$PWD/$tmux"
test_tmux || true
done
else
export POWERLINE_TMUX_EXE="${POWERLINE_TMUX_EXE:-tmux}"
test_tmux || true
fi
if test $FAILED -eq 0 ; then
echo "$FAIL_SUMMARY"
rm -rf tests/vterm
fi
exit $FAILED

View File

@ -18,7 +18,7 @@ from powerline import get_fallback_logger
from tests.lib.terminal import ExpectProcess from tests.lib.terminal import ExpectProcess
VTERM_TEST_DIR = os.path.abspath('tests/vterm') VTERM_TEST_DIR = os.path.abspath('tests/vterm_tmux')
def cell_properties_key_to_shell_escape(cell_properties_key): def cell_properties_key_to_shell_escape(cell_properties_key):
@ -193,57 +193,57 @@ def main(attempts=3):
(((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), (((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '),
(((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), (((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' S2 string here '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' S2 string here '),
(((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '), (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '),
(((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '), (((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1 '), (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1- '),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '),
(((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '), (((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '), (((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '),
(((102, 204, 255), (0, 102, 153), 0, 0, 0), '2 | '), (((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '),
(((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '), (((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 127), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 124),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '),
(((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here '), (((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here '),
), expected_result_new=( ), expected_result_new=(
(((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), (((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '),
(((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), (((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' S2 string here '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' S2 string here '),
(((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '), (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '),
(((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '), (((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1 '), (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1- '),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), 'bash '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), 'bash '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '), (((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '),
(((102, 204, 255), (0, 102, 153), 0, 0, 0), '2 | '), (((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '),
(((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '), (((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 127), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 124),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '),
(((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here '), (((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here '),
), expected_result_2_0=( ), expected_result_2_0=(
(((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), (((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '),
(((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), (((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' S2 string here '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' S2 string here '),
(((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '), (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '),
(((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '), (((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1 '), (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1- '),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), 'bash '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), 'bash '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '), (((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '),
(((102, 204, 255), (0, 102, 153), 0, 0, 0), '2 | '), (((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '),
(((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '), (((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 128), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 125),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '),
(((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here '), (((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here '),
)) ))
@ -265,10 +265,10 @@ def main(attempts=3):
(((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), (((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '),
(((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), (((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' <'), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' <'),
(((188, 188, 188), (11, 11, 11), 0, 0, 0), 'sh '), (((188, 188, 188), (11, 11, 11), 0, 0, 0), 'h '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '), (((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '),
(((102, 204, 255), (0, 102, 153), 0, 0, 0), '2 | '), (((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '),
(((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '), (((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
@ -278,10 +278,10 @@ def main(attempts=3):
(((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), (((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '),
(((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), (((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' <'), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' <'),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), 'sh '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), 'h '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '), (((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '),
(((102, 204, 255), (0, 102, 153), 0, 0, 0), '2 | '), (((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '),
(((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '), (((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
@ -291,10 +291,10 @@ def main(attempts=3):
(((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), (((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '),
(((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), (((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), '<'), (((255, 255, 255), (11, 11, 11), 0, 0, 0), '<'),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), 'bash '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), 'ash '),
(((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '),
(((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '), (((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '),
(((102, 204, 255), (0, 102, 153), 0, 0, 0), '2 | '), (((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '),
(((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '), (((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '),
(((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '),
(((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '),

View File

@ -0,0 +1,52 @@
#!/bin/sh
. tests/common.sh
enter_suite tmux
rm -rf tests/vterm_tmux
mkdir tests/vterm_tmux
mkdir tests/vterm_tmux/path
ln -s "$(which "${PYTHON}")" tests/vterm_tmux/path/python
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
test_tmux() {
if test "$PYTHON_IMPLEMENTATION" = PyPy; then
# FIXME PyPy3 segfaults for some reason, PyPy does it as well, but
# occasionally.
return 0
fi
if ! which "${POWERLINE_TMUX_EXE}" ; then
return 0
fi
ln -sf "$(which "${POWERLINE_TMUX_EXE}")" tests/vterm_tmux/path
f=tests/test_in_vterm/test_tmux.py
if ! "${PYTHON}" $f ; then
local test_name="$("$POWERLINE_TMUX_EXE" -V 2>&1 | cut -d' ' -f2)"
fail "$test_name" F "Failed vterm test $f"
fi
}
if test -z "$POWERLINE_TMUX_EXE" && test -d tests/bot-ci/deps/tmux ; then
for tmux in tests/bot-ci/deps/tmux/tmux-*/tmux ; do
export POWERLINE_TMUX_EXE="$PWD/$tmux"
test_tmux || true
done
else
export POWERLINE_TMUX_EXE="${POWERLINE_TMUX_EXE:-tmux}"
test_tmux || true
fi
if test $FAILED -eq 0 ; then
rm -rf tests/vterm_tmux
else
echo "$FAIL_SUMMARY"
fi
exit_suite

View File

@ -7,6 +7,7 @@ import os
from functools import partial from functools import partial
from collections import namedtuple from collections import namedtuple
from time import sleep from time import sleep
from platform import python_implementation
from powerline.segments import shell, tmux, pdb, i3wm 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
@ -397,6 +398,29 @@ class TestNet(TestCommon):
interfaces[:] = () interfaces[:] = ()
self.assertEqual(self.module.internal_ip(pl=pl, ipv=6), None) self.assertEqual(self.module.internal_ip(pl=pl, ipv=6), None)
gateways = {
'default': {
netifaces.AF_INET: ('192.168.100.1', 'enp2s0'),
netifaces.AF_INET6: ('feff::5446:5eff:fe5a:0001', 'enp2s0')
}
}
with replace_module_module(
self.module, 'netifaces',
interfaces=(lambda: interfaces),
ifaddresses=(lambda interface: addr[interface]),
gateways=(lambda: gateways),
AF_INET=netifaces.AF_INET,
AF_INET6=netifaces.AF_INET6,
):
# default gateway has specified address family
self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=4), '192.168.100.200')
self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=6), 'feff::5446:5eff:fe5a:7777%enp2s0')
# default gateway doesn't have specified address family
gateways['default'] = {}
self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=4), None)
self.assertEqual(self.module.internal_ip(pl=pl, interface='default_gateway', ipv=6), None)
def test_network_load(self): def test_network_load(self):
def gb(interface): def gb(interface):
return None return None
@ -472,15 +496,15 @@ class TestEnv(TestCommon):
pass pass
def username(self): def username(self):
return 'def' return 'def@DOMAIN.COM'
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)
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')) new_pwd = new_module('pwd', getpwuid=lambda uid: struct_passwd(pw_name='def@DOMAIN.COM'))
new_getpass = new_module('getpass', getuser=lambda: 'def') new_getpass = new_module('getpass', getuser=lambda: 'def@DOMAIN.COM')
pl = Pl() pl = Pl()
with replace_attr(self.module, 'pwd', new_pwd): with replace_attr(self.module, 'pwd', new_pwd):
with replace_attr(self.module, 'getpass', new_getpass): with replace_attr(self.module, 'getpass', new_getpass):
@ -488,12 +512,18 @@ class TestEnv(TestCommon):
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(self.module.user(pl=pl), [
{'contents': 'def', 'highlight_groups': ['user']} {'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']}
]) ])
self.assertEqual(self.module.user(pl=pl, hide_user='abc'), [ self.assertEqual(self.module.user(pl=pl, hide_user='abc'), [
{'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']}
])
self.assertEqual(self.module.user(pl=pl, hide_domain=False), [
{'contents': 'def@DOMAIN.COM', 'highlight_groups': ['user']}
])
self.assertEqual(self.module.user(pl=pl, hide_user='def@DOMAIN.COM'), None)
self.assertEqual(self.module.user(pl=pl, hide_domain=True), [
{'contents': 'def', 'highlight_groups': ['user']} {'contents': 'def', 'highlight_groups': ['user']}
]) ])
self.assertEqual(self.module.user(pl=pl, hide_user='def'), None)
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(self.module.user(pl=pl), [
{'contents': 'def', 'highlight_groups': ['superuser', 'user']} {'contents': 'def', 'highlight_groups': ['superuser', 'user']}
@ -602,8 +632,39 @@ class TestEnv(TestCommon):
pl = Pl() pl = Pl()
with replace_env('VIRTUAL_ENV', '/abc/def/ghi') as segment_info: with replace_env('VIRTUAL_ENV', '/abc/def/ghi') as segment_info:
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'ghi') self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'ghi')
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), 'ghi')
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), None)
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None)
segment_info['environ'].pop('VIRTUAL_ENV') segment_info['environ'].pop('VIRTUAL_ENV')
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), None) self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), None)
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), None)
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), None)
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None)
with replace_env('CONDA_DEFAULT_ENV', 'foo') as segment_info:
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'foo')
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), None)
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), 'foo')
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None)
segment_info['environ'].pop('CONDA_DEFAULT_ENV')
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), None)
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), None)
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), None)
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None)
with replace_env('CONDA_DEFAULT_ENV', 'foo', environ={'VIRTUAL_ENV': '/sbc/def/ghi'}) as segment_info:
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'ghi')
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), 'ghi')
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), 'foo')
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None)
segment_info['environ'].pop('CONDA_DEFAULT_ENV')
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info), 'ghi')
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_conda=True), 'ghi')
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True), None)
self.assertEqual(self.module.virtualenv(pl=pl, segment_info=segment_info, ignore_venv=True, ignore_conda=True), None)
def test_environment(self): def test_environment(self):
pl = Pl() pl = Pl()
@ -686,6 +747,12 @@ class TestTime(TestCommon):
with replace_attr(self.module, 'datetime', Args(now=lambda: Args(strftime=lambda fmt: fmt))): with replace_attr(self.module, 'datetime', Args(now=lambda: Args(strftime=lambda fmt: fmt))):
self.assertEqual(self.module.date(pl=pl), [{'contents': '%Y-%m-%d', 'highlight_groups': ['date'], 'divider_highlight_group': None}]) self.assertEqual(self.module.date(pl=pl), [{'contents': '%Y-%m-%d', 'highlight_groups': ['date'], 'divider_highlight_group': None}])
self.assertEqual(self.module.date(pl=pl, format='%H:%M', istime=True), [{'contents': '%H:%M', 'highlight_groups': ['time', 'date'], 'divider_highlight_group': 'time:divider'}]) self.assertEqual(self.module.date(pl=pl, format='%H:%M', istime=True), [{'contents': '%H:%M', 'highlight_groups': ['time', 'date'], 'divider_highlight_group': 'time:divider'}])
unicode_date = self.module.date(pl=pl, format='\u231a', istime=True)
expected_unicode_date = [{'contents': '\u231a', 'highlight_groups': ['time', 'date'], 'divider_highlight_group': 'time:divider'}]
if python_implementation() == 'PyPy' and sys.version_info >= (3,):
if unicode_date != expected_unicode_date:
raise SkipTest('Dates do not match, see https://bitbucket.org/pypy/pypy/issues/2161/pypy3-strftime-does-not-accept-unicode')
self.assertEqual(unicode_date, expected_unicode_date)
def test_fuzzy_time(self): def test_fuzzy_time(self):
time = Args(hour=0, minute=45) time = Args(hour=0, minute=45)
@ -819,10 +886,10 @@ class TestI3WM(TestCase):
def test_workspaces(self): def test_workspaces(self):
pl = Pl() pl = Pl()
with replace_attr(i3wm, 'conn', Args(get_workspaces=lambda: iter([ with replace_attr(i3wm, 'conn', Args(get_workspaces=lambda: iter([
{'name': '1: w1', 'focused': False, 'urgent': False, 'visible': False}, {'name': '1: w1', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': False},
{'name': '2: w2', 'focused': False, 'urgent': False, 'visible': True}, {'name': '2: w2', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': True},
{'name': '3: w3', 'focused': False, 'urgent': True, 'visible': True}, {'name': '3: w3', 'output': 'HDMI1', 'focused': False, 'urgent': True, 'visible': True},
{'name': '4: w4', 'focused': True, 'urgent': True, 'visible': True}, {'name': '4: w4', 'output': 'DVI01', 'focused': True, 'urgent': True, 'visible': True},
]))): ]))):
self.assertEqual(i3wm.workspaces(pl=pl), [ self.assertEqual(i3wm.workspaces(pl=pl), [
{'contents': '1: w1', 'highlight_groups': ['workspace']}, {'contents': '1: w1', 'highlight_groups': ['workspace']},
@ -850,6 +917,15 @@ class TestI3WM(TestCase):
{'contents': 'w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']}, {'contents': 'w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
{'contents': 'w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']}, {'contents': 'w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
]) ])
self.assertEqual(i3wm.workspaces(pl=pl, only_show=['focused', 'urgent'], output='DVI01'), [
{'contents': '4: w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']},
])
self.assertEqual(i3wm.workspaces(pl=pl, only_show=['visible'], output='HDMI1'), [
{'contents': '3: w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']},
])
self.assertEqual(i3wm.workspaces(pl=pl, only_show=['visible'], strip=3, output='LVDS1'), [
{'contents': 'w2', 'highlight_groups': ['w_visible', 'workspace']},
])
def test_mode(self): def test_mode(self):
pl = Pl() pl = Pl()
@ -881,12 +957,12 @@ class TestBat(TestCommon):
def test_battery(self): def test_battery(self):
pl = Pl() pl = Pl()
def _get_capacity(pl): def _get_battery_status(pl):
return 86 return 86, False
with replace_attr(self.module, '_get_capacity', _get_capacity): with replace_attr(self.module, '_get_battery_status', _get_battery_status):
self.assertEqual(self.module.battery(pl=pl), [{ self.assertEqual(self.module.battery(pl=pl), [{
'contents': '86%', 'contents': ' 86%',
'highlight_groups': ['battery_gradient', 'battery'], 'highlight_groups': ['battery_gradient', 'battery'],
'gradient_level': 14, 'gradient_level': 14,
}]) }])
@ -896,11 +972,17 @@ class TestBat(TestCommon):
'gradient_level': 14, 'gradient_level': 14,
}]) }])
self.assertEqual(self.module.battery(pl=pl, steps=7), [{ self.assertEqual(self.module.battery(pl=pl, steps=7), [{
'contents': '86%', 'contents': ' 86%',
'highlight_groups': ['battery_gradient', 'battery'], 'highlight_groups': ['battery_gradient', 'battery'],
'gradient_level': 14, 'gradient_level': 14,
}]) }])
self.assertEqual(self.module.battery(pl=pl, gamify=True), [ self.assertEqual(self.module.battery(pl=pl, gamify=True), [
{
'contents': ' ',
'draw_inner_divider': False,
'highlight_groups': ['battery_offline', 'battery_ac_state', 'battery_gradient', 'battery'],
'gradient_level': 0
},
{ {
'contents': 'OOOO', 'contents': 'OOOO',
'draw_inner_divider': False, 'draw_inner_divider': False,
@ -915,6 +997,12 @@ class TestBat(TestCommon):
} }
]) ])
self.assertEqual(self.module.battery(pl=pl, gamify=True, full_heart='+', empty_heart='-', steps='10'), [ self.assertEqual(self.module.battery(pl=pl, gamify=True, full_heart='+', empty_heart='-', steps='10'), [
{
'contents': ' ',
'draw_inner_divider': False,
'highlight_groups': ['battery_offline', 'battery_ac_state', 'battery_gradient', 'battery'],
'gradient_level': 0
},
{ {
'contents': '++++++++', 'contents': '++++++++',
'draw_inner_divider': False, 'draw_inner_divider': False,
@ -929,6 +1017,34 @@ class TestBat(TestCommon):
} }
]) ])
def test_battery_with_ac_online(self):
pl = Pl()
def _get_battery_status(pl):
return 86, True
with replace_attr(self.module, '_get_battery_status', _get_battery_status):
self.assertEqual(self.module.battery(pl=pl, online='C', offline=' '), [
{
'contents': 'C 86%',
'highlight_groups': ['battery_gradient', 'battery'],
'gradient_level': 14,
}])
def test_battery_with_ac_offline(self):
pl = Pl()
def _get_battery_status(pl):
return 86, False
with replace_attr(self.module, '_get_battery_status', _get_battery_status):
self.assertEqual(self.module.battery(pl=pl, online='C', offline=' '), [
{
'contents': ' 86%',
'highlight_groups': ['battery_gradient', 'battery'],
'gradient_level': 14,
}])
class TestVim(TestCase): class TestVim(TestCase):
def test_mode(self): def test_mode(self):

View File

@ -30,6 +30,7 @@ user = os.environ['USER']
REFS_RE = re.compile(r'^\[\d+ refs\]\n') REFS_RE = re.compile(r'^\[\d+ refs\]\n')
IPYPY_DEANSI_RE = re.compile(r'\033(?:\[(?:\?\d+[lh]|[^a-zA-Z]+[a-ln-zA-Z])|[=>])') IPYPY_DEANSI_RE = re.compile(r'\033(?:\[(?:\?\d+[lh]|[^a-zA-Z]+[a-ln-zA-Z])|[=>])')
ZSH_HL_RE = re.compile(r'\033\[\?\d+[hl]')
start_str = 'cd tests/shell/3rd' start_str = 'cd tests/shell/3rd'
if shell == 'pdb': if shell == 'pdb':
@ -55,7 +56,10 @@ with codecs.open(fname, 'r', encoding='utf-8') as R:
line = line.replace(user, 'USER') line = line.replace(user, 'USER')
if pid is not None: if pid is not None:
line = line.replace(pid, 'PID') line = line.replace(pid, 'PID')
if shell == 'fish': if shell == 'zsh':
line = line.replace('\033[0m\033[23m\033[24m\033[J', '')
line = ZSH_HL_RE.subn('', line)[0]
elif shell == 'fish':
res = '' res = ''
try: try:
while line.index('\033[0;'): while line.index('\033[0;'):

View File

@ -1,10 +1,8 @@
#!/bin/sh #!/bin/sh
. tests/bot-ci/scripts/common/main.sh . tests/common.sh
set +x
enter_suite shells
: ${PYTHON:=python}
FAIL_SUMMARY=""
FAILED=0
if test "x$1" = "x--fast" ; then if test "x$1" = "x--fast" ; then
FAST=1 FAST=1
shift shift
@ -285,9 +283,7 @@ check_test_client() {
esac esac
expected_mime_type="${expected_mime_type%/*}" expected_mime_type="${expected_mime_type%/*}"
if test "$expected_mime_type" != "$actual_mime_type" ; then if test "$expected_mime_type" != "$actual_mime_type" ; then
echo "Expected $executable to have MIME type $expected_mime_type, but got $actual_mime_type" fail "MIME-$executable" "M" "Expected $executable to have MIME type $expected_mime_type, but got $actual_mime_type"
FAILED=1
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}M ${executable}"
fi fi
} }
@ -382,8 +378,7 @@ if test -z "${ONLY_SHELL}" || test "x${ONLY_SHELL%sh}" != "x${ONLY_SHELL}" || te
fi fi
echo ">>> $(readlink "tests/shell/path/$SH")" echo ">>> $(readlink "tests/shell/path/$SH")"
if ! run_test $TEST_TYPE $TEST_CLIENT $TEST_COMMAND ; then if ! run_test $TEST_TYPE $TEST_CLIENT $TEST_COMMAND ; then
FAILED=1 fail "$SH-$TEST_TYPE-$TEST_CLIENT:test" F "Failed checking $TEST_COMMAND"
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}T ${TEST_TYPE} ${TEST_CLIENT} ${TEST_COMMAND}"
fi fi
done done
done done
@ -395,8 +390,7 @@ if test -z "${ONLY_SHELL}" || test "x${ONLY_SHELL%sh}" != "x${ONLY_SHELL}" || te
echo "Daemon log:" echo "Daemon log:"
echo '============================================================' echo '============================================================'
cat tests/shell/daemon_log cat tests/shell/daemon_log
FAILED=1 fail "$SH-$TEST_TYPE-$TEST_CLIENT:log" E "Non-empty daemon log for ${TEST_COMMAND}"
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}L ${TEST_TYPE} ${TEST_CLIENT} ${TEST_COMMAND}"
fi fi
fi fi
done done
@ -406,9 +400,7 @@ if $PYTHON scripts/powerline-daemon -s$ADDRESS > tests/shell/daemon_log_2 2>&1 ;
sleep 1 sleep 1
$PYTHON scripts/powerline-daemon -s$ADDRESS -k $PYTHON scripts/powerline-daemon -s$ADDRESS -k
else else
echo "Daemon exited with status $?" fail "daemon:run" F "Daemon exited with status $?"
FAILED=1
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}D"
fi fi
if ! test -z "$(cat tests/shell/daemon_log_2)" ; then if ! test -z "$(cat tests/shell/daemon_log_2)" ; then
@ -416,8 +408,7 @@ if ! test -z "$(cat tests/shell/daemon_log_2)" ; then
echo "Daemon log (2nd):" echo "Daemon log (2nd):"
echo '============================================================' echo '============================================================'
cat tests/shell/daemon_log_2 cat tests/shell/daemon_log_2
FAILED=1 fail "daemon:log" E "Daemon run with non-empty log"
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}L"
fi fi
if ( test "x${ONLY_SHELL}" = "x" || test "x${ONLY_SHELL}" = "xzsh" ) \ if ( test "x${ONLY_SHELL}" = "x" || test "x${ONLY_SHELL}" = "xzsh" ) \
@ -425,8 +416,7 @@ if ( test "x${ONLY_SHELL}" = "x" || test "x${ONLY_SHELL}" = "xzsh" ) \
&& zsh tests/test_shells/zsh_test_script.zsh 2>/dev/null; then && zsh tests/test_shells/zsh_test_script.zsh 2>/dev/null; then
echo "> zpython" echo "> zpython"
if ! run_test zpython zpython zsh -f -i ; then if ! run_test zpython zpython zsh -f -i ; then
FAILED=1 fail "zsh-zpython:test" F "Failed checking zsh -f -i"
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}T zpython zsh -f -i"
fi fi
fi fi
@ -435,8 +425,7 @@ if test "x${ONLY_SHELL}" = "x" || test "x${ONLY_SHELL}" = "xpdb" ; then
if test "x${ONLY_TEST_TYPE}" = "x" || test "x${ONLY_TEST_TYPE}" = "xsubclass" ; then if test "x${ONLY_TEST_TYPE}" = "x" || test "x${ONLY_TEST_TYPE}" = "xsubclass" ; then
echo "> pdb subclass" echo "> pdb subclass"
if ! run_test subclass python $PDB_PYTHON "$PWD/tests/test_shells/pdb-main.py" ; then if ! run_test subclass python $PDB_PYTHON "$PWD/tests/test_shells/pdb-main.py" ; then
FAILED=1 fail "pdb-subclass:test" F "Failed checking $PDB_PYTHON $PWD/tests/test_shells/pdb-main.py"
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}T pdb $PDB_PYTHON $PWD/tests/test_shells/pdb-main.py"
fi fi
fi fi
if test "x${ONLY_TEST_TYPE}" = "x" || test "x${ONLY_TEST_TYPE}" = "xmodule" ; then if test "x${ONLY_TEST_TYPE}" = "x" || test "x${ONLY_TEST_TYPE}" = "xmodule" ; then
@ -446,8 +435,7 @@ if test "x${ONLY_SHELL}" = "x" || test "x${ONLY_SHELL}" = "xpdb" ; then
MODULE="powerline.bindings.pdb.__main__" MODULE="powerline.bindings.pdb.__main__"
fi fi
if ! run_test module python $PDB_PYTHON -m$MODULE "$PWD/tests/test_shells/pdb-script.py" ; then if ! run_test module python $PDB_PYTHON -m$MODULE "$PWD/tests/test_shells/pdb-script.py" ; then
FAILED=1 fail "pdb-module:test" F "Failed checking $PDB_PYTHON -m$MODULE $PWD/tests/test_shells/pdb-script"
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}T pdb $PDB_PYTHON -m$MODULE $PWD/tests/test_shells/pdb-script"
fi fi
fi fi
fi fi
@ -460,8 +448,7 @@ if test "x${ONLY_SHELL}" = "x" || test "x${ONLY_SHELL}" = "xipython" ; then
export POWERLINE_THEME_OVERRIDES='in.segments.left=[]' export POWERLINE_THEME_OVERRIDES='in.segments.left=[]'
echo "> ipython" echo "> ipython"
if ! run_test ipython ipython ${IPYTHON_PYTHON} -mIPython ; then if ! run_test ipython ipython ${IPYTHON_PYTHON} -mIPython ; then
FAILED=1 fail "ipython:test" F "Failed checking ${IPYTHON_PYTHON} -mIPython"
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}T ipython"
fi fi
unset POWERLINE_THEME_OVERRIDES unset POWERLINE_THEME_OVERRIDES
unset POWERLINE_CONFIG_OVERRIDES unset POWERLINE_CONFIG_OVERRIDES
@ -470,7 +457,6 @@ fi
if test $FAILED -eq 0 ; then if test $FAILED -eq 0 ; then
rm -r tests/shell rm -r tests/shell
else
echo "${FAIL_SUMMARY}"
fi fi
exit $FAILED
exit_suite

View File

@ -1,52 +1,52 @@
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd .git
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  .git  cd ..
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  VIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment"   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  VIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment"
  HOSTNAME  USER  ⓔ  some-virtual-environment   BRANCH  ⋯  tests  shell  3rd  VIRTUAL_ENV=   HOSTNAME  USER  ⓔ  some-virtual-environment   BRANCH  ⋯  tests  shell  3rd  VIRTUAL_ENV=
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  bgscript.sh & waitpid.sh   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  bgscript.sh & waitpid.sh
[1] PID [1] PID
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  false   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  false
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  1  kill `cat pid` ; sleep 1s   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  1  kill `cat pid` ; sleep 1s
[1] + terminated bgscript.sh [1] + terminated bgscript.sh
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd "$DIR1"   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd "$DIR1"
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^[[32m  cd ../"$DIR2"   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^[[32m  cd ../"$DIR2"
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^H  cd ../'\[\]'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^H  cd ../'\[\]'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  \[\]  cd ../'%%'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  \[\]  cd ../'%%'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  %%  cd ../'#[bold]'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  %%  cd ../'#[bold]'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  #[bold]  cd ../'(echo)'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  #[bold]  cd ../'(echo)'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  (echo)  cd ../'$(echo)'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  (echo)  cd ../'$(echo)'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  $(echo)  cd ../'`echo`'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  $(echo)  cd ../'`echo`'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  `echo`  cd ../'«Unicode!»'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  `echo`  cd ../'«Unicode!»'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  «Unicode!»  cd ..   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  «Unicode!»  cd ..
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  bindkey -v ; set_theme default   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  bindkey -v ; set_theme default
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd   COMMND   HOSTNAME  USER  ⋯  tests  shell  3rd    INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd   COMMND   HOSTNAME  USER  ⋯  tests  shell  3rd  
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd    INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  echo abc  INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  echo abc
abc abc
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  false  INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  false
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  set_theme_option default.segment_data.hostname.display false  INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  set_theme_option default.segment_data.hostname.display false
 INSERT  USER  ⋯  tests  shell  3rd  set_theme_option default.segment_data.user.display false  INSERT  USER  ⋯  tests  shell  3rd  set_theme_option default.segment_data.user.display false
 INSERT  ⋯  tests  shell  3rd  select abc in def ghi jkl  INSERT  ⋯  tests  shell  3rd  select abc in def ghi jkl
 select                            do  select                            do
 select                             echo $abc  select                             echo $abc
 select                             break  select                             break
 select                            done  select                            done
1) def 2) ghi 3) jkl 1) def 2) ghi 3) jkl
                   Select variant  1                    Select variant  1
def def
 INSERT  ⋯  tests  shell  3rd  cd .  INSERT  ⋯  tests  shell  3rd  cd .
 INSERT  ⋯  tests  shell  3rd  cd .  INSERT  ⋯  tests  shell  3rd  cd .
 INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above "$ABOVE_LEFT"  INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above "$ABOVE_LEFT"
 INSERT  ⋯  tests  shell  3rd  export DISPLAYED_ENV_VAR=foo
 foo  
 INSERT  ⋯  tests  shell  3rd  unset DISPLAYED_ENV_VAR
 INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above "$ABOVE_FULL"
                                                                                                                                                                                                                                                                                                           
 INSERT  ⋯  tests  shell  3rd  export DISPLAYED_ENV_VAR=foo  INSERT  ⋯  tests  shell  3rd  export DISPLAYED_ENV_VAR=foo
                                                                                                                                                                                                                                                                                                      foo   foo  
 INSERT  ⋯  tests  shell  3rd  unset DISPLAYED_ENV_VAR  INSERT  ⋯  tests  shell  3rd  unset DISPLAYED_ENV_VAR
                                                                                                                                                                                                                                                                                                             INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above "$ABOVE_FULL"
                                                                                                                                                                                                                                                                                                           
 INSERT  ⋯  tests  shell  3rd  export DISPLAYED_ENV_VAR=foo
                                                                                                                                                                                                                                                                                                      foo 
 INSERT  ⋯  tests  shell  3rd  unset DISPLAYED_ENV_VAR
                                                                                                                                                                                                                                                                                                           
 INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above  INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above
 INSERT  ⋯  tests  shell  3rd  hash -d foo=$PWD:h ; cd .  INSERT  ⋯  tests  shell  3rd  hash -d foo=$PWD:h ; cd .
 INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC  INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC
 INSERT $ABC~foo  3rd $ABCtrue  INSERT $ABC~foo  3rd $ABCtrue

View File

@ -1,52 +1,52 @@
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd .git   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd .git
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  .git  cd ..   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  .git  cd ..
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  VIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment"   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  VIRTUAL_ENV="/home/USER/.virtenvs/some-virtual-environment"
  HOSTNAME  USER  ⓔ  some-virtual-environment   BRANCH  ⋯  tests  shell  3rd  VIRTUAL_ENV=   HOSTNAME  USER  ⓔ  some-virtual-environment   BRANCH  ⋯  tests  shell  3rd  VIRTUAL_ENV=
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  bgscript.sh & waitpid.sh   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  bgscript.sh & waitpid.sh
[1] PID [1] PID
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  false   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  false
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  1  kill `cat pid` ; sleep 1s   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  1  kill `cat pid` ; sleep 1s
[1] + terminated bgscript.sh [1] + terminated bgscript.sh
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd "$DIR1"   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd "$DIR1"
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^[[32m  cd ../"$DIR2"   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^[[32m  cd ../"$DIR2"
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^H  cd ../'\[\]'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^H  cd ../'\[\]'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  \[\]  cd ../'%%'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  \[\]  cd ../'%%'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  %%  cd ../'#[bold]'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  %%  cd ../'#[bold]'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  #[bold]  cd ../'(echo)'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  #[bold]  cd ../'(echo)'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  (echo)  cd ../'$(echo)'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  (echo)  cd ../'$(echo)'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  $(echo)  cd ../'`echo`'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  $(echo)  cd ../'`echo`'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  `echo`  cd ../'«Unicode!»'   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  `echo`  cd ../'«Unicode!»'
  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  «Unicode!»  cd ..   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  «Unicode!»  cd ..
  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  bindkey -v ; set_theme default   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  bindkey -v ; set_theme default
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd   COMMND   HOSTNAME  USER  ⋯  tests  shell  3rd    INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd   COMMND   HOSTNAME  USER  ⋯  tests  shell  3rd  
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd    INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  echo abc  INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  echo abc
abc abc
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  false  INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  false
 INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  set_theme_option default.segment_data.hostname.display false  INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  set_theme_option default.segment_data.hostname.display false
 INSERT  USER  ⋯  tests  shell  3rd  set_theme_option default.segment_data.user.display false  INSERT  USER  ⋯  tests  shell  3rd  set_theme_option default.segment_data.user.display false
 INSERT  ⋯  tests  shell  3rd  select abc in def ghi jkl  INSERT  ⋯  tests  shell  3rd  select abc in def ghi jkl
 select  do  select  do
 select   echo $abc  select   echo $abc
 select   break  select   break
 select  done  select  done
1) def 2) ghi 3) jkl 1) def 2) ghi 3) jkl
 Select variant  1  Select variant  1
def def
 INSERT  ⋯  tests  shell  3rd  cd .  INSERT  ⋯  tests  shell  3rd  cd .
 INSERT  ⋯  tests  shell  3rd  cd .  INSERT  ⋯  tests  shell  3rd  cd .
 INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above "$ABOVE_LEFT"  INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above "$ABOVE_LEFT"
 INSERT  ⋯  tests  shell  3rd  export DISPLAYED_ENV_VAR=foo
 foo  
 INSERT  ⋯  tests  shell  3rd  unset DISPLAYED_ENV_VAR
 INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above "$ABOVE_FULL"
                                                                                                                                                                                                                                                                                                           
 INSERT  ⋯  tests  shell  3rd  export DISPLAYED_ENV_VAR=foo  INSERT  ⋯  tests  shell  3rd  export DISPLAYED_ENV_VAR=foo
                                                                                                                                                                                                                                                                                                      foo   foo  
 INSERT  ⋯  tests  shell  3rd  unset DISPLAYED_ENV_VAR  INSERT  ⋯  tests  shell  3rd  unset DISPLAYED_ENV_VAR
                                                                                                                                                                                                                                                                                                             INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above "$ABOVE_FULL"
                                                                                                                                                                                                                                                                                                           
 INSERT  ⋯  tests  shell  3rd  export DISPLAYED_ENV_VAR=foo
                                                                                                                                                                                                                                                                                                      foo 
 INSERT  ⋯  tests  shell  3rd  unset DISPLAYED_ENV_VAR
                                                                                                                                                                                                                                                                                                           
 INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above  INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above
 INSERT  ⋯  tests  shell  3rd  hash -d foo=$PWD:h ; cd .  INSERT  ⋯  tests  shell  3rd  hash -d foo=$PWD:h ; cd .
 INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC  INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC
 INSERT $ABC~foo  3rd $ABCtrue  INSERT $ABC~foo  3rd $ABCtrue