diff --git a/.travis.yml b/.travis.yml index 920141cf..01429651 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,11 +8,11 @@ addons: packages: - libssl1.0.0 - zsh - # - tcsh - # - mksh - # - busybox + - tcsh + - mksh + - busybox # - rc - # - socat + - socat - bc language: python install: tests/install.sh diff --git a/README.rst b/README.rst index c30679e1..4a9f3140 100644 --- a/README.rst +++ b/README.rst @@ -7,7 +7,7 @@ Powerline **Powerline is a statusline plugin for vim, and provides statuslines and prompts for several other applications, including zsh, bash, tmux, IPython, -Awesome and Qtile.** +Awesome, i3 and Qtile.** * `Support forum`_ (powerline-support@googlegroups.com) * `Development discussion`_ (powerline-dev@googlegroups.com) diff --git a/docs/source/configuration/segments/i3wm.rst b/docs/source/configuration/segments/i3wm.rst new file mode 100644 index 00000000..d1033742 --- /dev/null +++ b/docs/source/configuration/segments/i3wm.rst @@ -0,0 +1,6 @@ +************* +i3wm segments +************* + +.. automodule:: powerline.segments.i3wm + :members: diff --git a/docs/source/develop/segments.rst b/docs/source/develop/segments.rst index 8d752229..d96bb1cb 100644 --- a/docs/source/develop/segments.rst +++ b/docs/source/develop/segments.rst @@ -467,7 +467,8 @@ Shell ``client_id`` 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 + `. 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 @@ -481,6 +482,14 @@ Shell Local theme that will be used by shell. One should not rely on the 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. Ipython diff --git a/docs/source/installation.rst b/docs/source/installation.rst index b4682d45..be786480 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -113,8 +113,7 @@ install a patched font. Patched fonts ------------- -This method is the fallback method and works for every terminal, with the -exception of :ref:`rxvt-unicode `. +This method is the fallback method and works for every terminal. Download the font from `powerline-fonts`_. If preferred font can’t be found in the `powerline-fonts`_ repo, then patching the preferred font is needed instead. diff --git a/docs/source/installation/osx.rst b/docs/source/installation/osx.rst index 99e19494..5a85e692 100644 --- a/docs/source/installation/osx.rst +++ b/docs/source/installation/osx.rst @@ -22,7 +22,7 @@ Python package to be installed. ``coreutils`` may be installed using ``brew install coreutils``. -2. Install Powerline using one of the following commans: +2. Install Powerline using one of the following commands: .. code-block:: sh diff --git a/docs/source/overview.rst b/docs/source/overview.rst index 73804ea5..e943b044 100644 --- a/docs/source/overview.rst +++ b/docs/source/overview.rst @@ -4,7 +4,7 @@ Overview **Powerline is a statusline plugin for vim, and provides statuslines and prompts for several other applications, including zsh, bash, tmux, IPython, -Awesome and Qtile.** +Awesome, i3 and Qtile.** Features -------- diff --git a/docs/source/powerline_automan.py b/docs/source/powerline_automan.py index b4e1a14f..1f79001a 100644 --- a/docs/source/powerline_automan.py +++ b/docs/source/powerline_automan.py @@ -7,6 +7,8 @@ import codecs from collections import namedtuple +from functools import reduce + from docutils.parsers.rst import Directive from docutils.parsers.rst.directives import unchanged_required from docutils import nodes diff --git a/docs/source/troubleshooting.rst b/docs/source/troubleshooting.rst index 007d9367..542ee9b0 100644 --- a/docs/source/troubleshooting.rst +++ b/docs/source/troubleshooting.rst @@ -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 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 ========== @@ -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 source vimrc with ``BufWritePost`` (or any other) event, but without ``nested`` this event is not launched. See also `autocmd-nested -`_ -Vim documentation. +`_ Vim +documentation. Powerline loses color after saving any file ------------------------------------------- diff --git a/powerline/bindings/tmux/powerline-base.conf b/powerline/bindings/tmux/powerline-base.conf index 5900f9b4..a17f0c41 100644 --- a/powerline/bindings/tmux/powerline-base.conf +++ b/powerline/bindings/tmux/powerline-base.conf @@ -2,11 +2,11 @@ set -g status on set -g status-utf8 on set -g status-interval 2 set -g status-left-length 20 -set -g status-right '#(env "$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS tmux right -R pane_id=`tmux display -p "#D"`)' +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 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-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-format "#[$_POWERLINE_WINDOW_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER_SPACES#I#F #[$_POWERLINE_WINDOW_DIVIDER_COLOR]$_POWERLINE_LEFT_SOFT_DIVIDER#[default]#W $_POWERLINE_LEFT_HARD_DIVIDER_SPACES" +set -g window-status-current-format "#[$_POWERLINE_WINDOW_CURRENT_HARD_DIVIDER_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER#[$_POWERLINE_WINDOW_CURRENT_COLOR]#I#F $_POWERLINE_LEFT_SOFT_DIVIDER#[$_POWERLINE_WINDOW_NAME_COLOR]#W #[$_POWERLINE_WINDOW_CURRENT_HARD_DIVIDER_NEXT_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER" # 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 diff --git a/powerline/bindings/tmux/powerline_tmux_1.7_plus.conf b/powerline/bindings/tmux/powerline_tmux_1.7_plus.conf index 6562b6a7..8c60294f 100644 --- a/powerline/bindings/tmux/powerline_tmux_1.7_plus.conf +++ b/powerline/bindings/tmux/powerline_tmux_1.7_plus.conf @@ -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-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-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'`\")" # vim: ft=tmux diff --git a/powerline/bindings/tmux/powerline_tmux_1.8_plus.conf b/powerline/bindings/tmux/powerline_tmux_1.8_plus.conf index f8f8a517..95d85ff4 100644 --- a/powerline/bindings/tmux/powerline_tmux_1.8_plus.conf +++ b/powerline/bindings/tmux/powerline_tmux_1.8_plus.conf @@ -1,5 +1,5 @@ # powerline_tmux_1.8_plus.conf # tmux Version 1.8 introduces the 'client_prefix' format variable, applicable # 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 diff --git a/powerline/commands/main.py b/powerline/commands/main.py index da228edf..a5b27ef7 100644 --- a/powerline/commands/main.py +++ b/powerline/commands/main.py @@ -10,7 +10,7 @@ from itertools import chain from powerline.lib.overrides import parsedotval, parse_override_var from powerline.lib.dict import mergeargs 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,): @@ -49,6 +49,14 @@ def finish_args(environ, args): )) if args.renderer_arg: 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 = ( [path for path in environ.get('POWERLINE_CONFIG_PATHS', '').split(':') if path] + (args.config_path or []) diff --git a/powerline/config_files/themes/ascii.json b/powerline/config_files/themes/ascii.json index 9ba09c31..9e876734 100644 --- a/powerline/config_files/themes/ascii.json +++ b/powerline/config_files/themes/ascii.json @@ -51,7 +51,9 @@ "powerline.segments.common.bat.battery": { "args": { "full_heart": "O", - "empty_heart": "O" + "empty_heart": "O", + "online": "C", + "offline": " " } }, "powerline.segments.common.sys.uptime": { diff --git a/powerline/config_files/themes/powerline.json b/powerline/config_files/themes/powerline.json index 2bbe7bfd..c33b5c1f 100644 --- a/powerline/config_files/themes/powerline.json +++ b/powerline/config_files/themes/powerline.json @@ -50,7 +50,9 @@ "powerline.segments.common.bat.battery": { "args": { "full_heart": "♥", - "empty_heart": "♥" + "empty_heart": "♥", + "online": "⚡︎", + "offline": " " } }, "powerline.segments.common.sys.uptime": { diff --git a/powerline/config_files/themes/powerline_unicode7.json b/powerline/config_files/themes/powerline_unicode7.json index 2b0b0184..bfa86fe0 100644 --- a/powerline/config_files/themes/powerline_unicode7.json +++ b/powerline/config_files/themes/powerline_unicode7.json @@ -50,7 +50,9 @@ "powerline.segments.common.bat.battery": { "args": { "full_heart": "💙", - "empty_heart": "💛" + "empty_heart": "💛", + "online": "⚡️", + "offline": " " } }, "powerline.segments.common.sys.uptime": { diff --git a/powerline/config_files/themes/unicode.json b/powerline/config_files/themes/unicode.json index f6d6f5e5..eadfc870 100644 --- a/powerline/config_files/themes/unicode.json +++ b/powerline/config_files/themes/unicode.json @@ -50,7 +50,9 @@ "powerline.segments.common.bat.battery": { "args": { "full_heart": "♥", - "empty_heart": "♥" + "empty_heart": "♥", + "online": "⚡︎", + "offline": " " } }, "powerline.segments.common.sys.uptime": { diff --git a/powerline/config_files/themes/unicode_terminus.json b/powerline/config_files/themes/unicode_terminus.json index 5b0a165b..8c1e045a 100644 --- a/powerline/config_files/themes/unicode_terminus.json +++ b/powerline/config_files/themes/unicode_terminus.json @@ -50,7 +50,9 @@ "powerline.segments.common.bat.battery": { "args": { "full_heart": "♥", - "empty_heart": "♥" + "empty_heart": "♥", + "online": "⚡︎", + "offline": " " } }, "powerline.segments.common.sys.uptime": { diff --git a/powerline/config_files/themes/unicode_terminus_condensed.json b/powerline/config_files/themes/unicode_terminus_condensed.json index a725a470..1c567dc7 100644 --- a/powerline/config_files/themes/unicode_terminus_condensed.json +++ b/powerline/config_files/themes/unicode_terminus_condensed.json @@ -51,7 +51,9 @@ "powerline.segments.common.bat.battery": { "args": { "full_heart": "♥", - "empty_heart": "♥" + "empty_heart": "♥", + "online": "⚡︎", + "offline": " " } }, "powerline.segments.common.sys.uptime": { diff --git a/powerline/dist/systemd/powerline-daemon.service b/powerline/dist/systemd/powerline-daemon.service new file mode 100644 index 00000000..96b685dd --- /dev/null +++ b/powerline/dist/systemd/powerline-daemon.service @@ -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 diff --git a/powerline/lib/inotify.py b/powerline/lib/inotify.py index 174d88f8..8b74a7f1 100644 --- a/powerline/lib/inotify.py +++ b/powerline/lib/inotify.py @@ -134,7 +134,7 @@ class INotify(object): eno = ctypes.get_errno() extra = '' 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)) def __del__(self): diff --git a/powerline/renderers/tmux.py b/powerline/renderers/tmux.py index 9034999a..840bbdda 100644 --- a/powerline/renderers/tmux.py +++ b/powerline/renderers/tmux.py @@ -63,7 +63,7 @@ class TmuxRenderer(Renderer): if segment_info: r.update(segment_info) if 'pane_id' in r: - varname = 'TMUX_PWD_' + r['pane_id'].lstrip('%') + varname = 'TMUX_PWD_' + str(r['pane_id']) if varname in r['environ']: r['getcwd'] = lambda: r['environ'][varname] r['mode'] = mode diff --git a/powerline/segments/common/bat.py b/powerline/segments/common/bat.py index 732d8e11..26e8b0dc 100644 --- a/powerline/segments/common/bat.py +++ b/powerline/segments/common/bat.py @@ -8,11 +8,7 @@ import re from powerline.lib.shell import run_cmd -# XXX Warning: module name must not be equal to the segment name as long as this -# segment is imported into powerline.segments.common module. - - -def _get_battery(pl): +def _fetch_battery_info(pl): try: import dbus except ImportError: @@ -51,27 +47,37 @@ def _get_battery(pl): pl.debug('Not using DBUS+UPower with {0}: not a power supply', devpath) continue 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( devtype_name, - 'Percentage' - ) + 'State' + ) == 1 ) pl.debug('Not using DBUS+UPower as no batteries were found') if os.path.isdir('/sys/class/power_supply'): linux_bat_fmt = '/sys/class/power_supply/{0}/capacity' + linux_ac_fmt = '/sys/class/power_supply/{0}/online' for linux_bat in os.listdir('/sys/class/power_supply'): cap_path = linux_bat_fmt.format(linux_bat) + online_path = linux_ac_fmt.format(linux_bat) if linux_bat.startswith('BAT') and os.path.exists(cap_path): pl.debug('Using /sys/class/power_supply with battery {0}', linux_bat) - def _get_capacity(pl): + def _get_battery_status(pl): with open(cap_path, 'r') as f: - return int(float(f.readline().split()[0])) - - return _get_capacity - pl.debug('Not using /sys/class/power_supply as no batteries were found') + _capacity = int(float(f.readline().split()[0])) + with open(online_path, 'r') as f: + _ac_powered = f.readline() == 1 + return _capacity, _ac_powered + return _get_battery_status + pl.debug('Not using /sys/class/power_supply as no batteries were found') else: 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+)%') - def _get_capacity(pl): + def _get_battery_status(pl): battery_summary = run_cmd(pl, ['pmset', '-g', 'batt']) battery_percent = BATTERY_PERCENT_RE.search(battery_summary).group(1) - return int(battery_percent) - - return _get_capacity + ac_charging = 'AC' in battery_summary + return int(battery_percent), ac_charging + return _get_battery_status else: pl.debug('Not using pmset: executable not found') @@ -110,11 +116,11 @@ def _get_battery(pl): for battery in wmi.InstancesOf('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 - 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') from ctypes import Structure, c_byte, c_ulong, byref if sys.platform == 'cygwin': @@ -136,52 +142,57 @@ def _get_battery(pl): ('BatteryFullLifeTime', c_ulong) ] - def _get_capacity(pl): + def _get_battery_status(pl): powerclass = PowerClass() result = library_loader.kernel32.GetSystemPowerStatus(byref(powerclass)) # http://msdn.microsoft.com/en-us/library/windows/desktop/aa372693(v=vs.85).aspx if result: 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') else: pl.debug('Using GetSystemPowerStatus') - return _get_capacity + return _get_battery_status raise NotImplementedError -def _get_capacity(pl): - global _get_capacity +def _get_battery_status(pl): + global _get_battery_status - def _failing_get_capacity(pl): + def _failing_get_status(pl): raise NotImplementedError try: - _get_capacity = _get_battery(pl) + _get_battery_status = _fetch_battery_info(pl) except NotImplementedError: - _get_capacity = _failing_get_capacity + _get_battery_status = _failing_get_status except Exception as e: - pl.exception('Exception while obtaining battery capacity getter: {0}', str(e)) - _get_capacity = _failing_get_capacity - return _get_capacity(pl) + pl.exception('Exception while obtaining battery status: {0}', str(e)) + _get_battery_status = _failing_get_status + 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. :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: Number of discrete steps to show between 0% and 100% capacity if gamify is True. :param bool gamify: Measure in hearts (♥) instead of percentages. For full hearts ``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: Heart displayed for “full” part of battery. :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 the same as full_heart as long as necessary highlighting groups are 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 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: - capacity = _get_capacity(pl) + capacity, ac_powered = _get_battery_status(pl) except NotImplementedError: - pl.info('Unable to get battery capacity.') + pl.info('Unable to get battery status.') return None + ret = [] if gamify: denom = int(steps) 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({ 'contents': full_heart * numer, 'draw_inner_divider': False, @@ -220,7 +242,7 @@ def battery(pl, format='{capacity:3.0%}', steps=5, gamify=False, full_heart='O', }) else: 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'], # Gradients are “least alert – most alert” by default, capacity has # the opposite semantics. diff --git a/powerline/segments/common/env.py b/powerline/segments/common/env.py index 0ba7be5f..ec28be7f 100644 --- a/powerline/segments/common/env.py +++ b/powerline/segments/common/env.py @@ -19,9 +19,20 @@ def environment(pl, segment_info, variable=None): @requires_segment_info -def virtualenv(pl, segment_info): - '''Return the name of the current Python virtualenv.''' - return os.path.basename(segment_info['environ'].get('VIRTUAL_ENV', '')) or None +def virtualenv(pl, segment_info, ignore_venv=False, ignore_conda=False): + '''Return the name of the current Python or conda virtualenv. + + :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 @@ -148,11 +159,13 @@ username = False _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. :param str hide_user: 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. @@ -166,6 +179,11 @@ def user(pl, hide_user=None): return None if username == hide_user: return None + if hide_domain: + try: + username = username[:username.index('@')] + except ValueError: + pass euid = _geteuid() return [{ 'contents': username, diff --git a/powerline/segments/common/net.py b/powerline/segments/common/net.py index 46243c66..eb5b4bcf 100644 --- a/powerline/segments/common/net.py +++ b/powerline/segments/common/net.py @@ -101,16 +101,24 @@ else: return 0 def internal_ip(pl, interface='auto', ipv=4): + family = netifaces.AF_INET6 if ipv == 6 else netifaces.AF_INET if interface == 'auto': try: interface = next(iter(sorted(netifaces.interfaces(), key=_interface_key, reverse=True))) except StopIteration: pl.info('No network interfaces found') 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) try: - return addrs[netifaces.AF_INET6 if ipv == 6 else netifaces.AF_INET][0]['addr'] + return addrs[family][0]['addr'] except (KeyError, IndexError): + pl.info("No IPv{0} address found for interface {1}", ipv, interface) return None @@ -130,6 +138,11 @@ Requires ``netifaces`` module to work properly. #. ``teredo`` followed by number or the end of string. #. Any other interface that is not ``lo*``. #. ``lo`` followed by number or the end of string. + + Use ``default_gateway`` to detect the interface based on the machine's + `default gateway `_ (i.e., + the router to which it is connected). + :param int ipv: 4 or 6 for ipv4 and ipv6 respectively, depending on which IP address you need exactly. @@ -150,7 +163,10 @@ try: return if_io.bytes_recv, if_io.bytes_sent 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(): if data: yield interface, data.bytes_recv, data.bytes_sent diff --git a/powerline/segments/common/players.py b/powerline/segments/common/players.py index 1e03af93..8ae6cb1a 100644 --- a/powerline/segments/common/players.py +++ b/powerline/segments/common/players.py @@ -167,14 +167,16 @@ Requires cmus-remote command be acessible from $PATH. 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: import mpd except ImportError: + if password: + host = password + '@' + host now_playing = run_cmd(pl, [ 'mpc', 'current', '-f', '%album%\n%artist%\n%title%\n%time%', - '-h', str(host), + '-h', host, '-p', str(port) ], strip=False) if not now_playing: @@ -189,6 +191,8 @@ class MpdPlayerSegment(PlayerSegment): else: client = mpd.MPDClient() client.connect(host, port) + if password: + client.password(password) now_playing = client.currentsong() if not now_playing: return @@ -220,6 +224,8 @@ package) or alternatively the ``mpc`` command to be acessible from $PATH. {0} :param str host: Host on which mpd runs. +:param str password: + Password used for connecting to daemon. :param int port: Port which should be connected to. ''').format(_common_args.format('mpd'))) diff --git a/powerline/segments/common/time.py b/powerline/segments/common/time.py index 84518c77..1e2207b3 100644 --- a/powerline/segments/common/time.py +++ b/powerline/segments/common/time.py @@ -16,8 +16,13 @@ def date(pl, format='%Y-%m-%d', istime=False): 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 [{ - 'contents': datetime.now().strftime(format), + 'contents': contents, 'highlight_groups': (['time'] if istime else []) + ['date'], 'divider_highlight_group': 'time:divider' if istime else None, }] diff --git a/powerline/segments/i3wm.py b/powerline/segments/i3wm.py index f0c16427..a5a82774 100644 --- a/powerline/segments/i3wm.py +++ b/powerline/segments/i3wm.py @@ -19,7 +19,7 @@ def calcgrp(w): 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 :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 are shown. + :param str output: + If specified, only workspaces on this output are shown. + :param int strip: Specifies how many characters from the front of each workspace name 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 [{ 'contents': w['name'][min(len(w['name']), strip):], 'highlight_groups': calcgrp(w) - } for w in conn.get_workspaces() if not only_show or any((w[typ] for typ in only_show))] + } 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 diff --git a/scripts/powerline-release.py b/scripts/powerline-release.py index 65d46b63..42381bde 100755 --- a/scripts/powerline-release.py +++ b/scripts/powerline-release.py @@ -147,38 +147,42 @@ def create_ebuilds(version_string, overlay, user, **kwargs): live_ebuild = None for ebuild in os.listdir(pdir): if ebuild.endswith('.ebuild') and '9999' in ebuild: + live_ebuild_base = ebuild live_ebuild = os.path.join(pdir, ebuild) break assert(live_ebuild) vcur = os.path.join(pdir, '{0}-{1}.ebuild'.format(pn, version_string)) - with open(live_ebuild) as LEF: - with open(vcur, 'w') as F: - dropnext = False - for line in LEF: - if line.startswith('EGIT'): - # Drop all EGIT_… and the next empty line - dropnext = True - next_re = re.compile('^$') - continue - if dropnext: - assert(next_re.match(line)) - dropnext = False - continue - if line.startswith('# Note the lack of an assignment to ${S}'): - next_re = re.compile('^#') - dropnext = True - line = 'S="${WORKDIR}/${MY_P}"\n' - if line.startswith('inherit'): - line = line.replace(' git-r3', '') - line += '\n' - line += 'MY_PN="powerline-status"\n' - line += 'MY_P="${MY_PN}-${PV}"' - line += '\n' - elif line.startswith('HOMEPAGE'): - line += 'SRC_URI="mirror://pypi/p/${MY_PN}/${MY_P}.tar.gz"\n' - elif line.startswith('KEYWORDS'): - line = 'KEYWORDS="~amd64 ~ppc ~x86 ~x86-fbsd"\n' - F.write(line) + if pn == 'powerline-vim': + with open(live_ebuild) as LEF: + with open(vcur, 'w') as F: + dropnext = False + for line in LEF: + if line.startswith('EGIT'): + # Drop all EGIT_… and the next empty line + dropnext = True + next_re = re.compile('^$') + continue + if dropnext: + assert(next_re.match(line)) + dropnext = False + continue + if line.startswith('# Note the lack of an assignment to ${S}'): + next_re = re.compile('^#') + dropnext = True + line = 'S="${WORKDIR}/${MY_P}"\n' + if line.startswith('inherit'): + line = line.replace(' git-r3', '') + line += '\n' + line += 'MY_PN="powerline-status"\n' + line += 'MY_P="${MY_PN}-${PV}"' + line += '\n' + elif line.startswith('HOMEPAGE'): + line += 'SRC_URI="mirror://pypi/p/${MY_PN}/${MY_P}.tar.gz"\n' + elif line.startswith('KEYWORDS'): + line = 'KEYWORDS="~amd64 ~ppc ~x86 ~x86-fbsd"\n' + F.write(line) + else: + os.symlink(live_ebuild_base, vcur) new_files.append(vcur) check_call(['ebuild', vcur, 'manifest']) new_files.append(os.path.join(pdir, 'Manifest')) diff --git a/setup.py b/setup.py index 4759ff9e..ea6a1f3d 100644 --- a/setup.py +++ b/setup.py @@ -59,7 +59,7 @@ else: def get_version(): - base_version = '2.2' + base_version = '2.3' base_version += '.dev9999' try: return base_version + '+git.' + str(subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip()) @@ -70,7 +70,7 @@ def get_version(): setup( name='powerline-status', - version='2.2', + version='2.3', description='The ultimate statusline/prompt utility.', long_description=README, classifiers=[ diff --git a/tests/common.sh b/tests/common.sh new file mode 100644 index 00000000..0b555162 --- /dev/null +++ b/tests/common.sh @@ -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 +} diff --git a/tests/install.sh b/tests/install.sh index 6c1bbbd0..d9fb48af 100755 --- a/tests/install.sh +++ b/tests/install.sh @@ -29,7 +29,11 @@ checkout_cached_dir git://github.com/powerline/deps tests/bot-ci/deps mkdir -p "$HOME/opt" 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 . virtualenvwrapper.sh set -e diff --git a/tests/run_daemon_tests.sh b/tests/run_daemon_tests.sh index e42a3bc8..af68eacf 100755 --- a/tests/run_daemon_tests.sh +++ b/tests/run_daemon_tests.sh @@ -1,5 +1,8 @@ #!/bin/sh -FAILED=0 +. tests/common.sh + +enter_suite daemon + export ADDRESS="powerline-ipc-test-$$" echo "Powerline address: $ADDRESS" 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 | \ grep 'file not found' ) ; then - echo "-p/dev/null argument ignored or not treated properly" - FAILED=1 + fail "devnull" F "-p/dev/null argument ignored or not treated properly" fi if ( \ $PYTHON client/powerline.py --socket $ADDRESS \ -p$PWD/powerline/config_files shell left | \ grep 'file not found' ) ; then - echo "-p/dev/null argument remembered while it should not" - FAILED=1 + fail "nodevnull" F "-p/dev/null argument remembered while it should not" fi if ! ( \ cd tests && \ @@ -25,17 +26,15 @@ if $PYTHON scripts/powerline-daemon -s$ADDRESS ; then -p$PWD/../powerline/config_files shell left | \ grep 'tests' ) ; then - echo "Output lacks string “tests”" - FAILED=1 + fail "segment" F "Output lacks string “tests”" fi else - echo "Daemon exited with status $?" - FAILED=1 + fail "exitcode" E "Daemon exited with status $?" fi if $PYTHON scripts/powerline-daemon -s$ADDRESS -k ; then : else - echo "powerline-daemon -k failed with exit code $?" - FAILED=1 + fail "-k" F "powerline-daemon -k failed with exit code $?" fi -exit $FAILED + +exit_suite diff --git a/tests/run_lint_tests.sh b/tests/run_lint_tests.sh index 09157910..585e7a03 100755 --- a/tests/run_lint_tests.sh +++ b/tests/run_lint_tests.sh @@ -1,7 +1,10 @@ #!/bin/sh -FAILED=0 +. tests/common.sh + +enter_suite lint + if ! ${PYTHON} scripts/powerline-lint -p powerline/config_files ; then - echo "Failed powerline-lint" - FAILED=1 + fail "test" F "Running powerline-lint failed" fi -exit $FAILED + +exit_suite diff --git a/tests/run_python_tests.sh b/tests/run_python_tests.sh index 62eac30a..f5524142 100755 --- a/tests/run_python_tests.sh +++ b/tests/run_python_tests.sh @@ -1,9 +1,13 @@ #!/bin/sh -FAILED=0 +. tests/common.sh + +enter_suite python + for file in tests/test_*.py ; do + test_name="${file##*/test_}" if ! ${PYTHON} $file --verbose --catch ; then - echo "Failed test(s) from $file" - FAILED=1 + fail "${test_name%.py}" F "Failed test(s) from $file" fi done -exit $FAILED + +exit_suite diff --git a/tests/run_vim_tests.sh b/tests/run_vim_tests.sh index 33705b26..c32831db 100755 --- a/tests/run_vim_tests.sh +++ b/tests/run_vim_tests.sh @@ -1,11 +1,12 @@ #!/bin/sh -. tests/bot-ci/scripts/common/main.sh -FAILED=0 +. tests/common.sh + +enter_suite vim if test -z "$VIM" ; then if test -n "$USE_UCS2_PYTHON" ; then - NEW_VIM="$ROOT/tests/bot-ci/deps/vim/tip-$UCS2_PYTHON_VARIANT-ucs2-double/vim" - OLD_VIM="$ROOT/tests/bot-ci/deps/vim/v7-0-112-$UCS2_PYTHON_VARIANT-ucs2/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" opt_dir="$HOME/opt/cpython-ucs2-$UCS2_PYTHON_VARIANT" main_path="$opt_dir/lib/python$UCS2_PYTHON_VARIANT" site_path="$main_path/site-packages" @@ -18,8 +19,8 @@ if test -z "$VIM" ; then exit 0 fi if test -d "$ROOT/tests/bot-ci/deps" ; then - NEW_VIM="$ROOT/tests/bot-ci/deps/vim/tip-$PYTHON_MM/vim" - OLD_VIM="$ROOT/tests/bot-ci/deps/vim/v7-0-112-$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" else NEW_VIM="vim" fi @@ -42,28 +43,29 @@ export POWERLINE_THEME_OVERRIDES='default.segments.left=[]' test_script() { local vim="$1" local script="$2" + local test_name_prefix="$3" echo "Running script $script with $vim" if ! test -e "$vim" ; then return 0 fi if ! "$vim" -u NONE -S $script || test -f message.fail ; then - 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 rm message.fail - FAILED=1 fi } for script in tests/test_*.vim ; do if test "${script%.old.vim}" = "${script}" ; then - test_script "$NEW_VIM" "$script" + test_script "$NEW_VIM" "$script" new fi done if test -e "$OLD_VIM" ; then for script in tests/test_*.old.vim ; do - test_script "$OLD_VIM" "$script" + test_script "$OLD_VIM" "$script" old done fi -exit $FAILED +exit_suite diff --git a/tests/run_vterm_tests.sh b/tests/run_vterm_tests.sh index 312b817d..c918ba32 100755 --- a/tests/run_vterm_tests.sh +++ b/tests/run_vterm_tests.sh @@ -1,8 +1,13 @@ #!/bin/sh -set -e -FAILED=0 -if ! sh tests/test_in_vterm/test.sh ; then - echo "Failed vterm" - FAILED=1 -fi -exit $FAILED +. tests/common.sh + +enter_suite vterm + +for t in tests/test_in_vterm/test_*.sh ; do + test_name="${t##*/test_}" + if ! sh "$t" ; then + fail "${test_name%.sh}" F "Failed running $t" + fi +done + +exit_suite diff --git a/tests/test.sh b/tests/test.sh index 6fe9ade7..68bd9310 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -1,20 +1,16 @@ #!/bin/bash -. tests/bot-ci/scripts/common/main.sh +. tests/common.sh + +enter_suite root : ${USER:=`id -un`} : ${HOME:=`getent passwd $USER | cut -d: -f6`} export USER HOME -FAILED=0 - if test "$TRAVIS" = true ; then export PATH="$HOME/opt/fish/bin:${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 export PATH="$HOME/opt/zsh-${PYTHON_MM}${USE_UCS2_PYTHON:+-ucs2}/bin:${PATH}" @@ -38,9 +34,16 @@ fi export PYTHON="${PYTHON:=python}" export PYTHONPATH="${PYTHONPATH}${PYTHONPATH:+:}`realpath .`" for script in tests/run_*_tests.sh ; do + test_name="${script##*/run_}" if ! sh $script ; then - echo "Failed $script" - FAILED=1 + fail "${test_name%_tests.sh}" F "Failed $script" fi done -exit $FAILED + +if test -e tests/failures ; then + echo "Some tests failed. Summary:" + cat tests/failures + rm tests/failures +fi + +exit_suite diff --git a/tests/test_in_vterm/test.sh b/tests/test_in_vterm/test.sh deleted file mode 100755 index f87201fe..00000000 --- a/tests/test_in_vterm/test.sh +++ /dev/null @@ -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 diff --git a/tests/test_in_vterm/test_tmux.py b/tests/test_in_vterm/test_tmux.py index 6454d69c..950f9171 100755 --- a/tests/test_in_vterm/test_tmux.py +++ b/tests/test_in_vterm/test_tmux.py @@ -18,7 +18,7 @@ from powerline import get_fallback_logger 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): @@ -193,57 +193,57 @@ def main(attempts=3): (((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), (((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' S2 string here '), - (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '), + (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '), (((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), - (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1 '), + (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1- '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '), (((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '), - (((102, 204, 255), (0, 102, 153), 0, 0, 0), '2 | '), + (((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '), (((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '), - (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 127), + (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 124), (((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '), (((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here '), ), expected_result_new=( (((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), (((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' S2 string here '), - (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '), + (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '), (((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), - (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1 '), + (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1- '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), 'bash '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '), - (((102, 204, 255), (0, 102, 153), 0, 0, 0), '2 | '), + (((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '), (((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '), - (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 127), + (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 124), (((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '), (((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here '), ), expected_result_2_0=( (((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), (((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' S2 string here '), - (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '), + (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 0 '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '), (((188, 188, 188), (11, 11, 11), 0, 0, 0), 'bash '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), - (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1 '), + (((133, 133, 133), (11, 11, 11), 0, 0, 0), ' 1- '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), '| '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), 'bash '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' '), (((11, 11, 11), (0, 102, 153), 0, 0, 0), ' '), - (((102, 204, 255), (0, 102, 153), 0, 0, 0), '2 | '), + (((102, 204, 255), (0, 102, 153), 0, 0, 0), '2* | '), (((255, 255, 255), (0, 102, 153), 1, 0, 0), 'bash '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '), - (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 128), + (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' ' * 125), (((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '), (((199, 199, 199), (88, 88, 88), 0, 0, 0), ' S1 string here '), )) @@ -265,10 +265,10 @@ def main(attempts=3): (((0, 0, 0), (243, 243, 243), 1, 0, 0), ' 0 '), (((243, 243, 243), (11, 11, 11), 0, 0, 0), ' '), (((255, 255, 255), (11, 11, 11), 0, 0, 0), ' <'), - (((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), ' '), (((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 '), (((0, 102, 153), (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 '), (((243, 243, 243), (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), ' '), (((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 '), (((0, 102, 153), (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 '), (((243, 243, 243), (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), ' '), (((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 '), (((0, 102, 153), (11, 11, 11), 0, 0, 0), ' '), (((88, 88, 88), (11, 11, 11), 0, 0, 0), ' '), diff --git a/tests/test_in_vterm/test_tmux.sh b/tests/test_in_vterm/test_tmux.sh new file mode 100755 index 00000000..c62ce530 --- /dev/null +++ b/tests/test_in_vterm/test_tmux.sh @@ -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 diff --git a/tests/test_segments.py b/tests/test_segments.py index ab56810b..a1c70c98 100644 --- a/tests/test_segments.py +++ b/tests/test_segments.py @@ -7,6 +7,7 @@ import os from functools import partial from collections import namedtuple from time import sleep +from platform import python_implementation from powerline.segments import shell, tmux, pdb, i3wm from powerline.lib.vcs import get_fallback_create_watcher @@ -397,6 +398,29 @@ class TestNet(TestCommon): interfaces[:] = () 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 gb(interface): return None @@ -472,15 +496,15 @@ class TestEnv(TestCommon): pass def username(self): - return 'def' + return 'def@DOMAIN.COM' if hasattr(self.module, 'psutil') and not callable(self.module.psutil.Process.username): username = property(username) struct_passwd = namedtuple('struct_passwd', ('pw_name',)) new_psutil = new_module('psutil', Process=Process) - new_pwd = new_module('pwd', getpwuid=lambda uid: struct_passwd(pw_name='def')) - new_getpass = new_module('getpass', getuser=lambda: 'def') + new_pwd = new_module('pwd', getpwuid=lambda uid: struct_passwd(pw_name='def@DOMAIN.COM')) + new_getpass = new_module('getpass', getuser=lambda: 'def@DOMAIN.COM') pl = Pl() with replace_attr(self.module, 'pwd', new_pwd): 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, '_geteuid', lambda: 5): 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'), [ + {'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']} ]) - self.assertEqual(self.module.user(pl=pl, hide_user='def'), None) with replace_attr(self.module, '_geteuid', lambda: 0): self.assertEqual(self.module.user(pl=pl), [ {'contents': 'def', 'highlight_groups': ['superuser', 'user']} @@ -602,8 +632,39 @@ class TestEnv(TestCommon): pl = Pl() 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, 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') 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): pl = Pl() @@ -686,6 +747,12 @@ class TestTime(TestCommon): 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, 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): time = Args(hour=0, minute=45) @@ -819,10 +886,10 @@ class TestI3WM(TestCase): def test_workspaces(self): pl = Pl() with replace_attr(i3wm, 'conn', Args(get_workspaces=lambda: iter([ - {'name': '1: w1', 'focused': False, 'urgent': False, 'visible': False}, - {'name': '2: w2', 'focused': False, 'urgent': False, 'visible': True}, - {'name': '3: w3', 'focused': False, 'urgent': True, 'visible': True}, - {'name': '4: w4', 'focused': True, 'urgent': True, 'visible': True}, + {'name': '1: w1', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': False}, + {'name': '2: w2', 'output': 'LVDS1', 'focused': False, 'urgent': False, 'visible': True}, + {'name': '3: w3', 'output': 'HDMI1', 'focused': False, 'urgent': True, 'visible': True}, + {'name': '4: w4', 'output': 'DVI01', 'focused': True, 'urgent': True, 'visible': True}, ]))): self.assertEqual(i3wm.workspaces(pl=pl), [ {'contents': '1: w1', 'highlight_groups': ['workspace']}, @@ -850,6 +917,15 @@ class TestI3WM(TestCase): {'contents': 'w3', 'highlight_groups': ['w_urgent', 'w_visible', 'workspace']}, {'contents': 'w4', 'highlight_groups': ['w_focused', 'w_urgent', 'w_visible', 'workspace']}, ]) + self.assertEqual(i3wm.workspaces(pl=pl, only_show=['focused', 'urgent'], output='DVI01'), [ + {'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): pl = Pl() @@ -881,12 +957,12 @@ class TestBat(TestCommon): def test_battery(self): pl = Pl() - def _get_capacity(pl): - return 86 + def _get_battery_status(pl): + 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), [{ - 'contents': '86%', + 'contents': ' 86%', 'highlight_groups': ['battery_gradient', 'battery'], 'gradient_level': 14, }]) @@ -896,11 +972,17 @@ class TestBat(TestCommon): 'gradient_level': 14, }]) self.assertEqual(self.module.battery(pl=pl, steps=7), [{ - 'contents': '86%', + 'contents': ' 86%', 'highlight_groups': ['battery_gradient', 'battery'], 'gradient_level': 14, }]) 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', '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'), [ + { + 'contents': ' ', + 'draw_inner_divider': False, + 'highlight_groups': ['battery_offline', 'battery_ac_state', 'battery_gradient', 'battery'], + 'gradient_level': 0 + }, { 'contents': '++++++++', '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): def test_mode(self): diff --git a/tests/test_shells/postproc.py b/tests/test_shells/postproc.py index 0e7f0923..9b2a19a3 100755 --- a/tests/test_shells/postproc.py +++ b/tests/test_shells/postproc.py @@ -30,6 +30,7 @@ user = os.environ['USER'] REFS_RE = re.compile(r'^\[\d+ refs\]\n') 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' if shell == 'pdb': @@ -55,7 +56,10 @@ with codecs.open(fname, 'r', encoding='utf-8') as R: line = line.replace(user, 'USER') if pid is not None: 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 = '' try: while line.index('\033[0;'): diff --git a/tests/test_shells/test.sh b/tests/test_shells/test.sh index 0663a6fa..8abc8532 100755 --- a/tests/test_shells/test.sh +++ b/tests/test_shells/test.sh @@ -1,10 +1,8 @@ #!/bin/sh -. tests/bot-ci/scripts/common/main.sh -set +x +. tests/common.sh + +enter_suite shells -: ${PYTHON:=python} -FAIL_SUMMARY="" -FAILED=0 if test "x$1" = "x--fast" ; then FAST=1 shift @@ -285,9 +283,7 @@ check_test_client() { esac expected_mime_type="${expected_mime_type%/*}" if test "$expected_mime_type" != "$actual_mime_type" ; then - echo "Expected $executable to have MIME type $expected_mime_type, but got $actual_mime_type" - FAILED=1 - FAIL_SUMMARY="${FAIL_SUMMARY}${NL}M ${executable}" + fail "MIME-$executable" "M" "Expected $executable to have MIME type $expected_mime_type, but got $actual_mime_type" fi } @@ -382,8 +378,7 @@ if test -z "${ONLY_SHELL}" || test "x${ONLY_SHELL%sh}" != "x${ONLY_SHELL}" || te fi echo ">>> $(readlink "tests/shell/path/$SH")" if ! run_test $TEST_TYPE $TEST_CLIENT $TEST_COMMAND ; then - FAILED=1 - FAIL_SUMMARY="${FAIL_SUMMARY}${NL}T ${TEST_TYPE} ${TEST_CLIENT} ${TEST_COMMAND}" + fail "$SH-$TEST_TYPE-$TEST_CLIENT:test" F "Failed checking $TEST_COMMAND" fi done done @@ -395,8 +390,7 @@ if test -z "${ONLY_SHELL}" || test "x${ONLY_SHELL%sh}" != "x${ONLY_SHELL}" || te echo "Daemon log:" echo '============================================================' cat tests/shell/daemon_log - FAILED=1 - FAIL_SUMMARY="${FAIL_SUMMARY}${NL}L ${TEST_TYPE} ${TEST_CLIENT} ${TEST_COMMAND}" + fail "$SH-$TEST_TYPE-$TEST_CLIENT:log" E "Non-empty daemon log for ${TEST_COMMAND}" fi fi done @@ -406,9 +400,7 @@ if $PYTHON scripts/powerline-daemon -s$ADDRESS > tests/shell/daemon_log_2 2>&1 ; sleep 1 $PYTHON scripts/powerline-daemon -s$ADDRESS -k else - echo "Daemon exited with status $?" - FAILED=1 - FAIL_SUMMARY="${FAIL_SUMMARY}${NL}D" + fail "daemon:run" F "Daemon exited with status $?" fi 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 '============================================================' cat tests/shell/daemon_log_2 - FAILED=1 - FAIL_SUMMARY="${FAIL_SUMMARY}${NL}L" + fail "daemon:log" E "Daemon run with non-empty log" fi 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 echo "> zpython" if ! run_test zpython zpython zsh -f -i ; then - FAILED=1 - FAIL_SUMMARY="${FAIL_SUMMARY}${NL}T zpython zsh -f -i" + fail "zsh-zpython:test" F "Failed checking zsh -f -i" 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 echo "> pdb subclass" if ! run_test subclass python $PDB_PYTHON "$PWD/tests/test_shells/pdb-main.py" ; then - FAILED=1 - FAIL_SUMMARY="${FAIL_SUMMARY}${NL}T pdb $PDB_PYTHON $PWD/tests/test_shells/pdb-main.py" + fail "pdb-subclass:test" F "Failed checking $PDB_PYTHON $PWD/tests/test_shells/pdb-main.py" fi fi 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__" fi if ! run_test module python $PDB_PYTHON -m$MODULE "$PWD/tests/test_shells/pdb-script.py" ; then - FAILED=1 - FAIL_SUMMARY="${FAIL_SUMMARY}${NL}T pdb $PDB_PYTHON -m$MODULE $PWD/tests/test_shells/pdb-script" + fail "pdb-module:test" F "Failed checking $PDB_PYTHON -m$MODULE $PWD/tests/test_shells/pdb-script" 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=[]' echo "> ipython" if ! run_test ipython ipython ${IPYTHON_PYTHON} -mIPython ; then - FAILED=1 - FAIL_SUMMARY="${FAIL_SUMMARY}${NL}T ipython" + fail "ipython:test" F "Failed checking ${IPYTHON_PYTHON} -mIPython" fi unset POWERLINE_THEME_OVERRIDES unset POWERLINE_CONFIG_OVERRIDES @@ -470,7 +457,6 @@ fi if test $FAILED -eq 0 ; then rm -r tests/shell -else - echo "${FAIL_SUMMARY}" fi -exit $FAILED + +exit_suite diff --git a/tests/test_shells/zsh.daemon.ok b/tests/test_shells/zsh.daemon.ok index daf415dc..ae8682e4 100644 --- a/tests/test_shells/zsh.daemon.ok +++ b/tests/test_shells/zsh.daemon.ok @@ -1,52 +1,52 @@ -  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd .git -  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  .git  cd .. -  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   BRANCH  ⋯  tests  shell  3rd  bgscript.sh & waitpid.sh +  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd .git +  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  .git  cd .. +  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   BRANCH  ⋯  tests  shell  3rd  bgscript.sh & waitpid.sh [1] PID -  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  false +  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  1  kill `cat pid` ; sleep 1s [1] + terminated bgscript.sh -  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd "$DIR1" -  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^[[32m  cd ../"$DIR2" -  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^H  cd ../'\[\]' -  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  \[\]  cd ../'%%' -  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  %%  cd ../'#[bold]' -  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 ../'«Unicode!»' -  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  «Unicode!»  cd .. -  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   - INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  echo abc +  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd "$DIR1" +  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^[[32m  cd ../"$DIR2" +  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^H  cd ../'\[\]' +  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  \[\]  cd ../'%%' +  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  %%  cd ../'#[bold]' +  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 ../'«Unicode!»' +  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  «Unicode!»  cd .. +  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   + INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  echo abc abc - INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  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  ⋯  tests  shell  3rd  select abc in def ghi jkl - select                            do - select                             echo $abc - select                             break - select                            done + INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  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  ⋯  tests  shell  3rd  select abc in def ghi jkl + select                            do + select                             echo $abc + select                             break + select                            done 1) def 2) ghi 3) jkl -                   Select variant  1 +                   Select variant  1 def - 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  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  cd . + INSERT  ⋯  tests  shell  3rd  cd . + INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above "$ABOVE_LEFT"  INSERT  ⋯  tests  shell  3rd  export DISPLAYED_ENV_VAR=foo -                                                                                                                                                                                                                                                                                                      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 +                                                                                                                                                                                                                                                                                                      foo  + INSERT  ⋯  tests  shell  3rd  unset DISPLAYED_ENV_VAR +                                                                                                                                                                                                                                                                                                             INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above - INSERT  ⋯  tests  shell  3rd  hash -d foo=$PWD:h ; cd . - INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC - INSERT $ABC~foo  3rd $ABCtrue + INSERT  ⋯  tests  shell  3rd  hash -d foo=$PWD:h ; cd . + INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC + INSERT $ABC~foo  3rd $ABCtrue diff --git a/tests/test_shells/zsh.nodaemon.ok b/tests/test_shells/zsh.nodaemon.ok index 6a813f93..ce35d952 100644 --- a/tests/test_shells/zsh.nodaemon.ok +++ b/tests/test_shells/zsh.nodaemon.ok @@ -1,52 +1,52 @@ -  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd .git -  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  .git  cd .. -  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   BRANCH  ⋯  tests  shell  3rd  bgscript.sh & waitpid.sh +  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd .git +  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  .git  cd .. +  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   BRANCH  ⋯  tests  shell  3rd  bgscript.sh & waitpid.sh [1] PID -  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  false +  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  1  kill `cat pid` ; sleep 1s [1] + terminated bgscript.sh -  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd "$DIR1" -  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^[[32m  cd ../"$DIR2" -  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^H  cd ../'\[\]' -  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  \[\]  cd ../'%%' -  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  %%  cd ../'#[bold]' -  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 ../'«Unicode!»' -  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  «Unicode!»  cd .. -  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   - INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  echo abc +  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd "$DIR1" +  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^[[32m  cd ../"$DIR2" +  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  ^H  cd ../'\[\]' +  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  \[\]  cd ../'%%' +  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  %%  cd ../'#[bold]' +  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 ../'«Unicode!»' +  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  «Unicode!»  cd .. +  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   + INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  echo abc abc - INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  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  ⋯  tests  shell  3rd  select abc in def ghi jkl - select  do - select   echo $abc - select   break - select  done + INSERT   HOSTNAME  USER  ⋯  tests  shell  3rd  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  ⋯  tests  shell  3rd  select abc in def ghi jkl + select  do + select   echo $abc + select   break + select  done 1) def 2) ghi 3) jkl - Select variant  1 + Select variant  1 def - 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  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  cd . + INSERT  ⋯  tests  shell  3rd  cd . + INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above "$ABOVE_LEFT"  INSERT  ⋯  tests  shell  3rd  export DISPLAYED_ENV_VAR=foo -                                                                                                                                                                                                                                                                                                      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 +                                                                                                                                                                                                                                                                                                      foo  + INSERT  ⋯  tests  shell  3rd  unset DISPLAYED_ENV_VAR +                                                                                                                                                                                                                                                                                                             INSERT  ⋯  tests  shell  3rd  set_theme_option default.segments.above - INSERT  ⋯  tests  shell  3rd  hash -d foo=$PWD:h ; cd . - INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC - INSERT $ABC~foo  3rd $ABCtrue + INSERT  ⋯  tests  shell  3rd  hash -d foo=$PWD:h ; cd . + INSERT  ~foo  3rd  set_theme_option default.dividers.left.hard \$ABC + INSERT $ABC~foo  3rd $ABCtrue