diff --git a/powerline/bindings/vim/__init__.py b/powerline/bindings/vim/__init__.py index 6705222d..ef8643ff 100644 --- a/powerline/bindings/vim/__init__.py +++ b/powerline/bindings/vim/__init__.py @@ -66,6 +66,18 @@ else: else: raise KeyError(varname) +if hasattr(vim, 'vars') and vim.vvars['version'] > 703: + def bufvar_exists(buffer, varname): + buffer = buffer or vim.current.buffer + return varname in buffer.vars +else: + def bufvar_exists(buffer, varname): # NOQA + if not buffer or buffer.number == vim.current.buffer.number: + return vim.eval('exists("b:{0}")'.format(varname)) + else: + return vim.eval('has_key(getbufvar({0}, ""), {1})' + .format(buffer.number, varname)) + if hasattr(vim, 'options'): def vim_getbufoption(info, option): return info['buffer'].options[option] diff --git a/powerline/bindings/zsh/powerline.zsh b/powerline/bindings/zsh/powerline.zsh index 494160e0..917f5a8b 100644 --- a/powerline/bindings/zsh/powerline.zsh +++ b/powerline/bindings/zsh/powerline.zsh @@ -24,13 +24,28 @@ _powerline_tmux_set_columns() { _powerline_tmux_setenv COLUMNS "$COLUMNS" } -_powerline_install_precmd() { +_powerline_precmd() { + # If you are wondering why I am not using the same code as I use for bash + # ($(jobs|wc -l)): consider the following test: + # echo abc | less + # + # . This way jobs will print + # [1] + done echo abc | + # suspended less -M + # ([ is in first column). You see: any line counting thingie will return + # wrong number of jobs. You need to filter the lines first. Or not use + # jobs built-in at all. + _POWERLINE_JOBNUM=${(%):-%j} +} + +_powerline_setup_prompt() { emulate -L zsh for f in "${precmd_functions[@]}"; do if [[ "$f" = "_powerline_precmd" ]]; then return fi done + precmd_functions+=( _powerline_precmd ) chpwd_functions+=( _powerline_tmux_set_pwd ) if zmodload zsh/zpython &>/dev/null ; then zpython 'from powerline.bindings.zsh import setup as powerline_setup' @@ -38,19 +53,7 @@ _powerline_install_precmd() { zpython 'del powerline_setup' else local add_args='--last_exit_code=$? --last_pipe_status="$pipestatus"' - # If you are wondering why I am not using the same code as I use for - # bash ($(jobs|wc -l)): consider the following test: - # echo abc | less - # - # . This way jobs will print - # [1] + done echo abc | - # suspended less -M - # ([ is in first column). You see: any line counting thingie will return - # wrong number of jobs. You need to filter the lines first. Or not use - # jobs built-in at all. - # - # This and above variants also do not use subshell. - add_args+=' --jobnum=${(%):-%j}' + add_args+=' --jobnum=$_POWERLINE_JOBNUM' PS1='$($POWERLINE_COMMAND shell left -r zsh_prompt '$add_args')' RPS1='$($POWERLINE_COMMAND shell right -r zsh_prompt '$add_args')' fi @@ -62,4 +65,4 @@ _powerline_tmux_set_pwd setopt promptpercent setopt promptsubst -_powerline_install_precmd +_powerline_setup_prompt diff --git a/powerline/config_files/themes/shell/default_leftonly.json b/powerline/config_files/themes/shell/default_leftonly.json index 16af9755..5060e1ea 100644 --- a/powerline/config_files/themes/shell/default_leftonly.json +++ b/powerline/config_files/themes/shell/default_leftonly.json @@ -34,6 +34,10 @@ "dir_limit_depth": 3 } }, + { + "module": "powerline.segments.shell", + "name": "jobnum" + }, { "name": "last_status", "module": "powerline.segments.shell" diff --git a/powerline/segments/plugin/ctrlp.py b/powerline/segments/plugin/ctrlp.py index e5893d7d..3c6af70d 100644 --- a/powerline/segments/plugin/ctrlp.py +++ b/powerline/segments/plugin/ctrlp.py @@ -6,8 +6,10 @@ except ImportError: vim = object() # NOQA from powerline.bindings.vim import getbufvar +from powerline.segments.vim import window_cached +@window_cached def ctrlp(pl, side): ''' diff --git a/powerline/segments/plugin/nerdtree.py b/powerline/segments/plugin/nerdtree.py index 39eb5aec..a8e6ad85 100644 --- a/powerline/segments/plugin/nerdtree.py +++ b/powerline/segments/plugin/nerdtree.py @@ -5,7 +5,7 @@ try: except ImportError: vim = object() # NOQA -from powerline.bindings.vim import getbufvar +from powerline.bindings.vim import bufvar_exists from powerline.segments.vim import window_cached @@ -15,9 +15,8 @@ def nerdtree(pl): Highlight groups used: ``nerdtree.path`` or ``file_name``. ''' - ntr = getbufvar('%', 'NERDTreeRoot') - if not ntr: - return + if not bufvar_exists(None, 'NERDTreeRoot'): + return None path_str = vim.eval('getbufvar("%", "NERDTreeRoot").path.str()') return [{ 'contents': path_str, diff --git a/powerline/shell.py b/powerline/shell.py index b887d323..aa04dc3d 100644 --- a/powerline/shell.py +++ b/powerline/shell.py @@ -62,6 +62,6 @@ def finish_args(args): if args.config: args.config = mergeargs((parsedotval(v) for v in args.config)) if args.theme_option: - args.theme_option = mergeargs((parsedotval(v) for v in args.config)) + args.theme_option = mergeargs((parsedotval(v) for v in args.theme_option)) else: args.theme_option = {} diff --git a/tests/install.sh b/tests/install.sh index 138da22a..24ad4a22 100755 --- a/tests/install.sh +++ b/tests/install.sh @@ -9,4 +9,5 @@ if python -c 'import sys; sys.exit(1 * (sys.version_info[0] != 2))' ; then pip install unittest2 argparse fi fi +sudo apt-get install -qq zsh screen true diff --git a/tests/test.sh b/tests/test.sh index e5b137ff..8d03f548 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -4,10 +4,12 @@ FAILED=0 export PYTHONPATH="${PYTHONPATH}:`realpath .`" for file in tests/test_*.py ; do if ! ${PYTHON} $file --verbose --catch ; then + echo "Failed test(s) from $file" FAILED=1 fi done if ! ${PYTHON} scripts/powerline-lint -p powerline/config_files ; then + echo "Failed powerline-lint" FAILED=1 fi for script in tests/*.vim ; do @@ -18,4 +20,8 @@ for script in tests/*.vim ; do FAILED=1 fi done +if ! sh tests/test_shells/test.sh ; then + echo "Failed shells" + FAILED=1 +fi exit $FAILED diff --git a/tests/test_configuration.py b/tests/test_configuration.py index 93857ec4..672c31b7 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -23,11 +23,15 @@ class TestConfig(TestCase): (('bufoptions',), {'buftype': 'help'}), (('bufname', '[Command Line]'), {}), (('bufoptions',), {'buftype': 'quickfix'}), + (('bufname', 'NERD_tree_1'), {}), + (('bufname', '__Gundo__'), {}), + (('bufname', '__Gundo_Preview__'), {}), + (('bufname', 'ControlP'), {}), ) with open(os.path.join(cfg_path, 'config.json'), 'r') as f: local_themes_raw = json.load(f)['ext']['vim']['local_themes'] # Don't run tests on external/plugin segments - local_themes = dict((k, v) for (k, v) in local_themes_raw.items() if not '.' in k) + local_themes = dict((k, v) for (k, v) in local_themes_raw.items()) self.assertEqual(len(buffers), len(local_themes)) outputs = {} i = 0 @@ -58,6 +62,10 @@ class TestConfig(TestCase): i += 1 if mode in exclude: continue + if mode == 'nc' and args == ('bufname', 'ControlP'): + # ControlP window is not supposed to not + # be in the focus + continue with vim_module._with(*args, **kwargs): check_output(mode, args, kwargs) finally: diff --git a/tests/test_shells/bash.ok b/tests/test_shells/bash.ok new file mode 100644 index 00000000..123b9fd6 --- /dev/null +++ b/tests/test_shells/bash.ok @@ -0,0 +1,12 @@ +  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd .git +  HOSTNAME  USER   BRANCH  ⋯  shell  3rd  .git  cd .. +  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +  HOSTNAME  USER  ⓔ  some-virtual-environment   BRANCH  ⋯  tests  shell  3rd  VIRTUAL_ENV= +  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  bash -c "echo \$\$>pid ; while true ; do sleep 0.1s ; done" & +[1] PID +  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  false +  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  1  kill `cat pid` ; sleep 1s +[1]+ Terminated bash -c "echo \$\$>pid ; while true ; do sleep 0.1s ; done" +  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  false +  HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  exit +exit diff --git a/tests/test_shells/input.bash b/tests/test_shells/input.bash new file mode 100644 index 00000000..9b97dac0 --- /dev/null +++ b/tests/test_shells/input.bash @@ -0,0 +1,14 @@ +POWERLINE_COMMAND="$PWD/scripts/powerline -p $PWD/powerline/config_files" +POWERLINE_COMMAND="$POWERLINE_COMMAND -t default_leftonly.segment_data.hostname.args.only_if_ssh=false" +POWERLINE_COMMAND="$POWERLINE_COMMAND -c ext.shell.theme=default_leftonly" +VIRTUAL_ENV= +source powerline/bindings/bash/powerline.sh ; cd tests/shell/3rd +cd .git +cd .. +VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +VIRTUAL_ENV= +bash -c "echo \$\$>pid ; while true ; do sleep 0.1s ; done" & +false +kill `cat pid` ; sleep 1s +false +exit diff --git a/tests/test_shells/input.zsh b/tests/test_shells/input.zsh new file mode 100644 index 00000000..a19bdff4 --- /dev/null +++ b/tests/test_shells/input.zsh @@ -0,0 +1,15 @@ +unsetopt promptsp transientrprompt +POWERLINE_COMMAND=( $PWD/scripts/powerline -p $PWD/powerline/config_files ) +POWERLINE_COMMAND=( $POWERLINE_COMMAND -t default_leftonly.segment_data.hostname.args.only_if_ssh=false ) +POWERLINE_COMMAND=( $POWERLINE_COMMAND -c ext.shell.theme=default_leftonly ) +VIRTUAL_ENV= +source powerline/bindings/zsh/powerline.zsh ; cd tests/shell/3rd +cd .git +cd .. +VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +VIRTUAL_ENV= +bash -c "echo \$\$>pid ; while true ; do sleep 0.1s ; done" & +false +kill `cat pid` ; sleep 1s +false +exit diff --git a/tests/test_shells/postproc.py b/tests/test_shells/postproc.py new file mode 100755 index 00000000..8cd037d0 --- /dev/null +++ b/tests/test_shells/postproc.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +from __future__ import unicode_literals + +import os +import socket +import sys +import codecs + + +fname = sys.argv[1] +new_fname = fname + '.new' +pid_fname = 'tests/shell/3rd/pid' + +with open(pid_fname, 'r') as P: + pid = P.read().strip() +hostname = socket.gethostname() +user = os.environ['USER'] + +with codecs.open(fname, 'r', encoding='utf-8') as R: + with codecs.open(new_fname, 'w', encoding='utf-8') as W: + found_cd = False + for line in R: + if not found_cd: + found_cd = ('cd tests/shell/3rd' in line) + continue + line = line.replace(pid, 'PID') + line = line.replace(hostname, 'HOSTNAME') + line = line.replace(user, 'USER') + W.write(line) + +os.rename(new_fname, fname) diff --git a/tests/test_shells/screenrc b/tests/test_shells/screenrc new file mode 100644 index 00000000..ad5a1466 --- /dev/null +++ b/tests/test_shells/screenrc @@ -0,0 +1,3 @@ +width 1024 +height 1 +logfile "tests/shell/screen.log" diff --git a/tests/test_shells/test.sh b/tests/test_shells/test.sh new file mode 100755 index 00000000..e5febb8f --- /dev/null +++ b/tests/test_shells/test.sh @@ -0,0 +1,53 @@ +#!/bin/sh +FAILED=0 + +if [ "$(echo '\e')" != '\e' ] ; then + safe_echo() { + echo -E "$@" + } +else + safe_echo() { + echo "$@" + } +fi + +run_test() { + SH="$1" + SESNAME="powerline-shell-test-$$" + screen -L -c tests/test_shells/screenrc -d -m -S "$SESNAME" \ + env LANG=en_US.UTF-8 BINDFILE="$BINDFILE" "$@" + screen -S "$SESNAME" -X readreg a tests/test_shells/input.$SH + sleep 0.3s + screen -S "$SESNAME" -p 0 -X width 300 1 + screen -S "$SESNAME" -p 0 -X logfile tests/shell/screen.log + screen -S "$SESNAME" -p 0 -X paste a + while screen -S "$SESNAME" -X blankerprg "" > /dev/null ; do + sleep 1s + done + ./tests/test_shells/postproc.py tests/shell/screen.log + if ! diff -u tests/test_shells/${SH}.ok tests/shell/screen.log | cat -v ; then + return 1 + fi + return 0 +} + +mkdir tests/shell +git init tests/shell/3rd +git --git-dir=tests/shell/3rd/.git checkout -b BRANCH + +if ! run_test bash --norc --noprofile -i ; then + echo "Failed bash" + FAILED=1 +fi +cp tests/shell/screen.log tests/bash.log +rm tests/shell/screen.log + +if ! run_test zsh -f -i ; then + echo "Failed zsh" + FAILED=1 +fi +cp tests/shell/screen.log tests/zsh.log +rm tests/shell/screen.log + +rm -r tests/shell +exit $FAILED diff --git a/tests/test_shells/zsh.ok b/tests/test_shells/zsh.ok new file mode 100644 index 00000000..2f7256b4 --- /dev/null +++ b/tests/test_shells/zsh.ok @@ -0,0 +1,12 @@ + +   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  cd .git +   HOSTNAME  USER   BRANCH  ⋯  shell  3rd  .git  cd .. +   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  VIRTUAL_ENV="$HOME/.virtenvs/some-virtual-environment" +   HOSTNAME  USER  ⓔ  some-virtual-environment   BRANCH  ⋯  tests  shell  3rd  VIRTUAL_ENV= +   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  bash -c "echo \$\$>pid ; while true ; do sleep 0.1s ; done" & +[1] PID +   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  false +   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  1  kill `cat pid` ; sleep 1s +[1] + terminated bash -c "echo \$\$>pid ; while true ; do sleep 0.1s ; done" +   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  false +   HOSTNAME  USER   BRANCH  ⋯  tests  shell  3rd  1  exit diff --git a/tests/vim.py b/tests/vim.py index 91a94886..bcc549b6 100644 --- a/tests/vim.py +++ b/tests/vim.py @@ -171,9 +171,13 @@ def eval(expr): return options[expr[1:]] elif expr.startswith('PowerlineRegisterCachePurgerEvent'): _buf_purge_events.add(expr[expr.find('"') + 1:expr.rfind('"') - 1]) - return "0" + return '0' elif expr.startswith('exists('): return '0' + elif expr == 'getbufvar("%", "NERDTreeRoot").path.str()': + import os + assert os.path.basename(buffers[_buffer()].name).startswith('NERD_tree_') + return '/usr/include' raise NotImplementedError @@ -205,6 +209,7 @@ def _emul_mode(*args): @_vim @_str_func def _emul_getbufvar(bufnr, varname): + import re if varname[0] == '&': if bufnr == '%': bufnr = buffers[_buffer()].number @@ -217,6 +222,12 @@ def _emul_getbufvar(bufnr, varname): return options[varname[1:]] except KeyError: return '' + elif re.match('^[a-zA-Z_]+$', varname): + if bufnr == '%': + bufnr = buffers[_buffer()].number + if bufnr not in buffers: + return '' + return buffers[bufnr].vars[varname] raise NotImplementedError @@ -625,10 +636,14 @@ class _WithBufName(object): self.new = new def __enter__(self): + import os buffer = buffers[_buffer()] self.buffer = buffer self.old = buffer.name buffer.name = self.new + if buffer.name and os.path.basename(buffer.name) == 'ControlP': + buffer.vars['powerline_ctrlp_type'] = 'main' + buffer.vars['powerline_ctrlp_args'] = ['focus', 'byfname', '0', 'prev', 'item', 'next', 'marked'] def __exit__(self, *args): self.buffer.name = self.old