VimからquickrunでPHPUnitを実行する

`*Test.php`のファイルを開いて、`<Leader>r`と打つと、PHPUnitをquickrunで実行して、結果をバッファに出力、エラーが出たらバッファは閉じて、quickfixに結果を出力するようにする。

# 下準備

composerでいれたphpunitを毎回

```
$ vendor/bin/phpunit
```

でと打つのは面倒なので、[composer で入れた phpunit で少し楽をする - Qiita](http://qiita.com/ngyuki/items/57ab6bb0e69590d5752d)を参考にして設定する。vimからも使いたいので関数ではなく、以下の様なシェルスクリプトにしてパスの通った場所に置く。

```bash:phpunit.sh
#!/usr/bin/env bash

function func_phpunit
{
    local cmd=$(which phpunit 2>/dev/null)
    local dir="${PWD}"

    while [ -n "${dir}" ]; do
        if [ -x "${dir}/vendor/bin/phpunit" ]; then
            cmd="${dir}/vendor/bin/phpunit"
            break
        fi
        dir="${dir%/*}"
    done

    if [ -z "$cmd" ]; then
        echo 'command not found: phpunit'
        return 1
    fi

    dir="${PWD}"
    while [ -n "${dir}" ]; do
        for testdir in "tests" "test" "" ; do
            for xml in "phpunit.xml" "phpunit.xml.dist"; do
                if [ -f "${dir}/${testdir}/${xml}" ]; then
                    cmd="${cmd} --configuration=${dir}/${testdir}/${xml}"
                    break 3
                fi
            done
        done
        dir="${dir%/*}"
    done

    $cmd $@ | cat
    return ${PIPESTATUS[0]}
}

func_phpunit $@
```

元のは`--colors`のオプションがあったが、quickrunの出力にカラーシーケンスが入らないようになくした。また、phpunit.xmlの探し方も変更した。
このシェルスクリプトを使うと、カレントディレクトリを遡って、`vendor/bin/phpunit`を探してあればそれを実行、なければPATHの通ったphpunitを実行するようになる。

また、

* tests/phpunit.xml.dist
* tests/phpunit.xml
* phpunit.xml.dist
* phpunit.xml

の順にディレクトリを見ていって、見つかったディレクトリを`--configuration`で指定するようになる。

お好みで、エイリアスを設定する。

```bash
alias phpunit='phpunit.sh --colors=auto'
```

zshを使っていて補完をしたいなら、`_gnu_generic`を使うと、`phpunit --help`の出力からそれなりにオプションを補完してくれるようになる。

```
compdef _gnu_generic phpunit
compdef _gnu_generic phpunit.sh
```

# quickrunの設定

[shabadou.vim を使って quickrun.vim をカスタマイズしよう - C++でゲームプログラミング](http://d.hatena.ne.jp/osyo-manga/20120919/1348054752)を参考に設定する。

[Shougo/neobundle.vim](https://github.com/Shougo/neobundle.vim)を使っているなら、以下のようにインストールする。

```vim
NeoBundle "thinca/vim-quickrun"
NeoBundle 'Shougo/vimproc.vim', {
\ 'build' : {
\     'windows' : 'tools\\update-dll-mingw',
\     'cygwin' : 'make -f make_cygwin.mak',
\     'mac' : 'make -f make_mac.mak',
\     'linux' : 'make',
\     'unix' : 'gmake',
\    },
\ }
NeoBundle "osyo-manga/shabadou.vim"
```

vim-quickrunがvim上からプログラムを実行するプラグイン
vimprocがプログラムを非同期実行するプラグイン
shabadou.vimが汎用的なquickrun-hookをまとめたプラグイン。

quickrunで動かすプログラム全体に関わる設定をする。
キーを`-`すると全体の設定になる。

```vim
if !exists("g:quickrun_config")
    let g:quickrun_config = {}
endif

let g:quickrun_config['_'] = {
\ 'runner'                                 : 'vimproc',
\ 'runner/vimproc/updatetime'              : 50,
\ 'outputter'                              : 'multi:buffer:quickfix',
\ 'outputter/buffer/split'                 : 'botright 8sp',
\ 'hook/close_quickfix/enable_hook_loaded' : 1,
\ 'hook/close_quickfix/enable_success'     : 1,
\ 'hook/close_buffer/enable_failure'       : 1,
\}
```

上から
vimprocを使う
50msごとに出力を更新する
出力先はbufferとquickfix
出力は横分割して、高さは8行
quickrun実行開始時にquickfixウィンドウを閉じる
実行結果が成功したらquickfixウィンドウを閉じる
失敗したらバッファを閉じる。

hookの部分がshabadou.vimが必要な部分。

次に`*Test.php`の実行に関する設定をする。quickrunの設定はfiletypeごとに設定するが、単にfiletypeがphpのファイルはphpunitではなくphpで実行したいので、`*Test.php`のファイルタイプを`php.phpunit`に変える設定をする。

```vim
augroup MyVimrc
    autocmd!
augroup END
autocmd MyVimrc BufNewFile,BufRead *Test.php setlocal ft=php.phpunit
```

filetypeをドットで区切ると、それぞれのfiletypeの設定を読むようになる。この場合phpの設定を読み込んで、phpunitの設定を読み込むようになる。

php.phpunitのquickrunの設定をする。

```vim
let g:quickrun_config['php.phpunit'] = {
\ 'hook/cd/directory'              : '%S:p:h',
\ 'command'                        : 'phpunit.sh',
\ 'cmdopt'                         : '',
\ 'exec'                           : '%c %o %s',
\ 'outputter/quickfix/errorformat' : '%f:%l,%m in %f on line %l',
\}
```

`hook/cd/directory`の部分はquickrun実行時にカレントディレクトリを開いているファイルがあるディレクトリに変更する設定
commandはphpunit.sh
オプションはデフォルトではなし
実行するコマンドで、`%c`がcommandで指定したもの、`%o`がcmdoptで指定したもの、`%s`がファイル名に置き換わる
errorformatでファイル名:エラー行の出力があったら、quickfix上で、その部分に飛べるようにしている。


最終的にvimrcは以下のようになる

```vim:.vimrc
" Note: Skip initialization for vim-tiny or vim-small.
if 0 | endif

if has('vim_starting')
  if &compatible
    set nocompatible               " Be iMproved
  endif

  " Required:
  set runtimepath+=~/.vim/bundle/neobundle.vim/
endif

" Required:
call neobundle#begin(expand('~/.vim/bundle/'))

" Let NeoBundle manage NeoBundle
" Required:
NeoBundleFetch 'Shougo/neobundle.vim'

" My Bundles here:
" Refer to |:NeoBundle-examples|.
" Note: You don't set neobundle setting in .gvimrc!
NeoBundle "thinca/vim-quickrun"
NeoBundle 'Shougo/vimproc.vim', {
\ 'build' : {
\     'windows' : 'tools\\update-dll-mingw',
\     'cygwin' : 'make -f make_cygwin.mak',
\     'mac' : 'make -f make_mac.mak',
\     'linux' : 'make',
\     'unix' : 'gmake',
\    },
\ }
NeoBundle "osyo-manga/shabadou.vim"

call neobundle#end()

" Required:
filetype plugin indent on

" If there are uninstalled bundles found on startup,
" this will conveniently prompt you to install them.
NeoBundleCheck


augroup MyVimrc
    autocmd!
augroup END
autocmd MyVimrc BufNewFile,BufRead *Test.php setlocal ft=php.phpunit

if !exists("g:quickrun_config")
    let g:quickrun_config = {}
endif

let g:quickrun_config['_'] = {
\ 'runner'                                 : 'vimproc',
\ 'runner/vimproc/updatetime'              : 50,
\ 'outputter'                              : 'multi:buffer:quickfix',
\ 'outputter/buffer/split'                 : 'botright 8sp',
\ 'hook/close_quickfix/enable_hook_loaded' : 1,
\ 'hook/close_quickfix/enable_success'     : 1,
\ 'hook/close_buffer/enable_failure'       : 1,
\}

let g:quickrun_config['php.phpunit'] = {
\ 'hook/cd/directory'              : '%S:p:h',
\ 'command'                        : 'phpunit.sh',
\ 'cmdopt'                         : '',
\ 'exec'                           : '%c %o %s',
\ 'outputter/quickfix/errorformat' : '%f:%l',
\}
```

この状態で、`*Test.php`を開いて`<Leader>r`（設定を変更していなければ<Learder>は\（バックスラッシュ））と打つとphpunitが実行される。