shabadou.vim を使って quickrun.vim をカスタマイズしよう

汎用的な quickrun-hook をまとめた shabadou.vim を使用して簡単に quickrun.vim をカスタマイズしましょう!
って、事で quickrun-hook を使用した quickrun.vim の設定を順を追って設定していきたいと思います。
shabadou.vim を使用すれば、コマンドが成功したら buffer に出力、コマンドが失敗した場合に unite-quickfix へ出力するなどといったことが比較的簡単に設定できます。
と、いう感じで段階を追って g:quickrun_config をいい感じにカスタマイズして行きましょう。




「さあ、ショータイムだ!」



0.必要なプラグイン

" neobundle.vim を使用しているなら
NeoBundle "thinca/vim-quickrun"
NeoBundle "Shougo/vimproc"
NeoBundle "Shougo/unite.vim"
NeoBundle "osyo-manga/unite-quickfix"
NeoBundle "osyo-manga/shabadou.vim"


事前に上記のプラグインを導入しておいて下さい。

1.vimrc に g:quickrun_config を定義する

何はともあれ、quickrun.vim のカスタマイズを行うのですが、quickrun.vim の挙動を設定するには大きく分けて2つの方法があります。


1つは :QuickRun コマンドに引数を渡す方法、もう1つは g:quickrun_config に記述する方法。
毎回 :QuickRun を定義するのは手間なので、quickrun の設定を行う際は vimrc に g:quickrun_config を設定します。
また、共通の挙動を設定したいので、g:quickrun_config._ に設定を行なっていきます。

let g:quickrun_config = {
\   "_" : {
\       以降ここに定義を書いていく
\   }
\}


以降は、これをベースとして書き込んでいきます。

2.非同期処理を行う

quickrun.vim の利点である非同期処理を設定します。
quickrun.vim では runner オプションを設定する事で、処理のバックエンドを指定することが出来ます。
非同期処理を行うために runner に vimproc を指定します。
これで quickrun.vim が実行中に Vim のフォーカスを奪われることなく作業することが出来ます。

" runner を vimproc に設定
" 更新時間も設定しておく
let g:quickrun_config = {
\   "_" : {
\       "runner" : "vimproc",
\       "runner/vimproc/updatetime" : 40,
\   }
\}


非同期処理の更新間隔は vimproc/updatetime で指定します。
updatetime の値が大きいと更新のタイミングが遅れる場合があるので、あまり大きい数値は設定しない方がよいです。
指定しない場合は Vim のオプションの updatetime を参照します。

3.バッファの開き方を変える

quickrun-hook とは関係ないですが、quickrun.vim の出力バッファの開き方を設定することが出来ます。
個人的に垂直分割はあまり好きではないので、水平分割で開くように設定します。

" バッファの開き方を設定
" 一番下に水平分割してウィンドウを開く
" ウィンドウの高さは 8行
let g:quickrun_config = {
\   "_" : {
\       "outputter/buffer/split" : ":botright 8",
\       "runner" : "vimproc",
\       "runner/vimproc/updatetime" : 40,
\   }
\}

4.quickrun.vim の実行中にアニメーションを出力する

さて、quickrun.vim で実行している間、ケースによっては quickrun.vim が動作しているのかわからない場合があります。
そこで quickrun.vim の実行中にアニメーションを出力することで quickrun.vim の実行が視覚的にわかるようにしてみたいと思います。
shabadou.vim にはいくつかアニメーションを行う quickrun-hook があるのですが、今回は『シャバドゥビタッチヘンシーン!!』を出力します。

" hook-shabadoubi_touch_henshin を有効にする
" shabadoubi_touch_henshin/wait でアニメーションの重みを設定できる
" 早いと思ったらこの値を大きくすれば遅くなる
let g:quickrun_config = {
\   "_" : {
\       "hook/shabadoubi_touch_henshin/enable" : 1,
\       "hook/shabadoubi_touch_henshin/wait" : 20,
\       "outputter/buffer/split" : ":botright 8",
\       "runner" : "vimproc",
\       "runner/vimproc/updatetime" : 40,
\   }
\}



他にも inu や neco があるので気になる人は試してみてください。

5.quickrun.vim の出力先を変更する

成功の有無で開き方を変えるために、まず quickrun.vim の出力先を変更します。
quickrun.vim のデフォルトの出力先は buffer になっていますが、outputter オプションを変更する事で出力先を変更することができます。

" quickfix へ出力する
:QuickRun -outputter quickfix


今回は成功の有無で buffer と quickfix(unite-quickfix)へと出力を行いたいので、まずは buffer と quickfix の両方へと出力を行います。
outputter/multi を使用することで複数の outputter へと出力を行うことが出来ます。

" outputter-multi を設定する
" 出力先は buffer と quickfix を設定
let g:quickrun_config = {
\   "_" : {
\       "outputter" : "multi:buffer:quickfix",
\       "hook/shabadoubi_touch_henshin/enable" : 1,
\       "hook/shabadoubi_touch_henshin/wait" : 20,
\       "outputter/buffer/split" : ":botright 8",
\       "runner" : "vimproc",
\       "runner/vimproc/updatetime" : 40,
\   }
\}


これで成功の有無にかかわらず buffer と quickfix の両方へと出力が行われるようになりました。


6.出力がなかったらバッファを閉じる

実は最近 quickrun.vim 側でも追加されたんですが、せっかくなので quickrun-hook でやってみます。
hook-close_buffer を使用することで出力データが無かった場合に quickrun.vim のバッファを閉じることが出来ます。

" hook-close_buffer で quickrun.vim のバッファを閉じることが出来る
" 今回は空のバッファだった場合に閉じたので enable_empty_data を有効にする
let g:quickrun_config = {
\   "_" : {
\       "hook/close_buffer/enable_empty_data" : 1,
\       "outputter" : "multi:buffer:quickfix",
\       "hook/shabadoubi_touch_henshin/enable" : 1,
\       "hook/shabadoubi_touch_henshin/wait" : 20,
\       "outputter/buffer/split" : ":botright 8",
\       "runner" : "vimproc",
\       "runner/vimproc/updatetime" : 40,
\   }
\}

7.失敗した場合に quickrun.vim のバッファを閉じる

余談ですが quickrun.vim のバッファの挙動は、:QuickRun された時点でバッファを開き、出力に応じで、非同期でバッファに出力を行なっていきます。
試しに下のようなコマンドを実行してみると挙動が分かりやすいかと思います。

:QuickRun ruby -outputter buffer -src "(1..50000).each{ |var| puts var }"


で、本題なんですが、6.で使用した hook-close_buffer を使用して失敗した場合にバッファを閉じるように設定します。

" hook/close_buffer を追加
" 今度は enable_failure を有効にする
let g:quickrun_config = {
\   "_" : {
\       "hook/close_buffer/enable_failure" : 1,
\       "hook/close_buffer/enable_empty_data" : 1,
\       "outputter" : "multi:buffer:quickfix",
\       "hook/shabadoubi_touch_henshin/enable" : 1,
\       "hook/shabadoubi_touch_henshin/wait" : 20,
\       "outputter/buffer/split" : ":botright 8",
\       "runner" : "vimproc",
\       "runner/vimproc/updatetime" : 40,
\   }
\}


これで失敗した場合にバッファが閉じるようになりました。
6.の設定と合わせると『出力がなかった場合』と『失敗した場合』にバッファが閉じられます。


8.成功した場合に quickfix を閉じる

先ほどの設定とは逆に今度は成功した場合に quickfix を閉じるように設定を追加します。
hook-close_buffer と同じような動作を行う hook-close_quickfix を使用します。

" hook-quickfix で任意のタイミングで quickfix を閉じる事が出来る
" 今回は成功した場合に quickfix を閉じる
let g:quickrun_config = {
\   "_" : {
\       "hook/close_quickfix/enable_success" : 1,
\       "hook/close_buffer/enable_failure" : 1,
\       "hook/close_buffer/enable_empty_data" : 1,
\       "outputter" : "multi:buffer:quickfix",
\       "hook/shabadoubi_touch_henshin/enable" : 1,
\       "hook/shabadoubi_touch_henshin/wait" : 20,
\       "outputter/buffer/split" : ":botright 8",
\       "runner" : "vimproc",
\       "runner/vimproc/updatetime" : 40,
\   }
\}


ただ、これだけでは quickfix ウィンドウを開いている時に quickrun.vim を実行するとちょっと見栄えが悪いので quickrun.vim の実行時に quickfix を閉じるように設定します。

" hook のロード後に quickfix を閉じる
let g:quickrun_config = {
\   "_" : {
\       "hook/close_quickfix/enable_hook_loaded" : 1,
\       "hook/close_quickfix/enable_success" : 1,
\       "hook/close_buffer/enable_failure" : 1,
\       "hook/close_buffer/enable_empty_data" : 1,
\       "outputter" : "multi:buffer:quickfix",
\       "hook/shabadoubi_touch_henshin/enable" : 1,
\       "hook/shabadoubi_touch_henshin/wait" : 20,
\       "outputter/buffer/split" : ":botright 8",
\       "runner" : "vimproc",
\       "runner/vimproc/updatetime" : 40,
\   }
\}



これで、成功した場合はバッファに出力し、失敗した場合は quickfix へと出力が行われるようになりました。
チョーイイネ!


が、利便性を追求するためにもうちっとだけ続くんじゃ。

9.quickfix ではなく unite.vim へ出力する

さて、エラー出力を quickfix へと行なっていましたが、quickfix ではなく unite.vim へと出力してみたいと思います。
unite.vim へ出力する利点は……まぁ言わなくても分かりますよねヾU・□・)ノシ
quickfix を参照して unite.vim へと出力を行う unite-quickfix があるのでそれを使用します。


まず、quickfix のデータがだけが必要で quickfix ウィンドウはもう必要がないので、quickrun.vim の終了時に quickfix を閉じます。

" 8.で追加した設定は削除
" enable_success から enable_exit に変更
" これで成功の有無にかかわらず必ず閉じるようになる。
let g:quickrun_config = {
\   "_" : {
\       "hook/close_quickfix/enable_exit" : 1,
\       "hook/close_buffer/enable_failure" : 1,
\       "hook/close_buffer/enable_empty_data" : 1,
\       "outputter" : "multi:buffer:quickfix",
\       "hook/shabadoubi_touch_henshin/enable" : 1,
\       "hook/shabadoubi_touch_henshin/wait" : 20,
\       "outputter/buffer/split" : ":botright 8",
\       "runner" : "vimproc",
\       "runner/vimproc/updatetime" : 40,
\   }
\}


次に unite-quickfix を開くために hook-unite_quickfix を設定します。

" unite-quickfix が開く hook を追加
" 失敗した場合に unite-quickfix を起動させる
let g:quickrun_config = {
\   "_" : {
\       "hook/unite_quickfix/enable_failure" : 1,
\       "hook/close_quickfix/enable_exit" : 1,
\       "hook/close_buffer/enable_failure" : 1,
\       "hook/close_buffer/enable_empty_data" : 1,
\       "outputter" : "multi:buffer:quickfix",
\       "hook/shabadoubi_touch_henshin/enable" : 1,
\       "hook/shabadoubi_touch_henshin/wait" : 20,
\       "outputter/buffer/split" : ":botright 8",
\       "runner" : "vimproc",
\       "runner/vimproc/updatetime" : 40,
\   }
\}


また、これも 8.で設定した quickfix 同様、quickrun.vim 実行時に閉じるように設定しましょう。

" hook-close_unite_quickfix で unite-quickfix を閉じることが出来る
" quickfix と同様に hook のロード後に untie-quickfix を閉じる
let g:quickrun_config = {
\   "_" : {
\       "hook/close_unite_quickfix/enable_hook_loaded" : 1,
\       "hook/unite_quickfix/enable_failure" : 1,
\       "hook/close_quickfix/enable_exit" : 1,
\       "hook/close_buffer/enable_failure" : 1,
\       "hook/close_buffer/enable_empty_data" : 1,
\       "outputter" : "multi:buffer:quickfix",
\       "hook/shabadoubi_touch_henshin/enable" : 1,
\       "hook/shabadoubi_touch_henshin/wait" : 20,
\       "outputter/buffer/split" : ":botright 8",
\       "runner" : "vimproc",
\       "runner/vimproc/updatetime" : 40,
\   }
\}



これでバッチリ
サイコー!

まとめ

長々と書きましたが、だいたいの流れはわかってもらえたかと思います。
quickrun.vim の挙動を理解するまでに時間がかかると思いますが、上記のような hook を使用することである程度、自分に合った quickrun.vim にカスタマイズする事が出来ると思います。
今回は shabadou.vim に付属されている hook-module のみを使用しましたが、ユーザ側でも簡単に hook-module を作成する事が出来ます。
いろんなタイミングで処理をフックする事が出来るので、ぜひ、自分なりの quickrun.vim にカスタマイズしてみましょう!

最終的な g:quickrun_config

let g:quickrun_config = {
\   "_" : {
\       "hook/close_unite_quickfix/enable_hook_loaded" : 1,
\       "hook/unite_quickfix/enable_failure" : 1,
\       "hook/close_quickfix/enable_exit" : 1,
\       "hook/close_buffer/enable_failure" : 1,
\       "hook/close_buffer/enable_empty_data" : 1,
\       "outputter" : "multi:buffer:quickfix",
\       "hook/shabadoubi_touch_henshin/enable" : 1,
\       "hook/shabadoubi_touch_henshin/wait" : 20,
\       "outputter/buffer/split" : ":botright 8",
\       "runner" : "vimproc",
\       "runner/vimproc/updatetime" : 40,
\   }
\}

わたしの使用している quickrun.vim