dein.vim
でプラグインが読み込まれた時に実行させたい処理は autocmd
でユーザーイベントをフックして使うようになったようだ。NeoBundle
では独自のon_source
オプションがあったが、dein.vim
では標準の機能を上手く使ってシンプル&高速化していこうっていうことだと思う。
で、そのsourceフックの書き方について、何か上手い書き方は無いかなーと色々模索してみた記録です。
結論を先に書いておくと、最終的にはTOML管理が一番良さそうという結論に落ち着きました。
普通の書き方
dein.vim
ではプラグイン毎の設定や読み込み時の追加処理はこんな感じに書けば良いようだ。
" どこか最初の方に書いておく
augroup MyAutoCmd
autocmd!
augroup END
if dein#tap('deoplete-go')
" プラグインの設定
let g:deoplete#sources#go#align_class = 1
" on_source処理
function! deoplete_go_on_source() abort
" gocodeが無ければインストール
if executable('go') && !executable('gocode')
echo "install gocode ..."
call system("go get -u github.com/nsf/gocode")
endif
endfunction
execute "autocmd MyAutoCmd User dein#source#deoplete-go call s:deoplete_go_on_source()"
endif
ところで、autocmd
を使う場合ワンライナーな設定ならまだしも、まとまった処理を書こうとするとやはり一度関数を作って実行することになるよね。
で、その時に使うユニークな関数名を考えるのが毎度毎度凄く面倒くさいんだよな…。しかもこの関数名って関数定義時とautocmdの登録時で2回も同じ名前を書かなきゃいけないのも面倒だし、さらに言えばこの関数名をautocmdの登録以外で使うことも無いので関数名の存在価値の無さも半端ない…。
つまりもっと楽がしたい!
関数名を考えたくない
で、何とか楽ができないかと調べてたら、どうやら dein#tap()
すると g:dein#name
に今tapしたプラグイン名が入ってくれるようだ。これを使ってフック関数名を作っちゃえばいいんじゃね?…出来た!
if dein#tap('deoplete-go')
" プラグインの設定
let g:deoplete#sources#go#align_class = 1
" on_source処理
let s:on_source = substitute(g:dein#name, '\W', '_', 'g') . '_on_source'
function! s:{s:on_source}() abort
if executable('go') && !executable('gocode')
echo "install gocode ..."
call system("go get -u github.com/nsf/gocode")
endif
endfunction
execute "autocmd MyAutoCmd User dein#source#".g:dein#name." call s:".s:on_source."()"
endif
うむ、autocmd
用の関数名を考えなくて良いって楽だね!
関数名を考えたくない&コピペ量も減らしたい
関数名考えなくて良くなって多少楽になったけど、全体的になんかちょっとゴツいし、一時変数 s:on_source
を作ったり autocmd
の登録部分はプラグイン毎に全く同じコードを実行してるだけし、もっと簡素な書き方で省力化出来ないかなー。
うーん、もうちょっとゴニョってみよう…、出来た!
" dein#tap()の代わりに使うとブロック内で s:{s:on_source}() という関数定義をするだけでフック登録出来る便利関数
function! s:dein_tap(name) abort
if dein#tap(a:name)
let s:on_source = substitute(a:name, '\W', '_', 'g') . '_on_source'
execute 'autocmd MyAutoCmd User'
\ 'dein#source#' . a:name
\ 'if exists("*s:' . s:on_source . '") | call s:' . s:on_source . '() | endif'
return 1
endif
return 0
endfunction
" 各プラグインのtapブロック内では後処理の関数定義をするだけでOK
if s:dein_tap('deoplete-go')
" プラグインの設定
let g:deoplete#sources#go#align_class = 1
" on_source処理
function! s:{s:on_source}() abort
if executable('go') && !executable('gocode')
echo "install gocode..."
call system("go get -u github.com/nsf/gocode")
endif
endfunction
endif
" 各プラグインのtapブロック内では後処理の関数定義をするだけでOK
if s:dein_tap('totemo-sugoi-nanika')
function! s:{s:on_source}() abort
echo "とても凄い何かが読み込まれたぞ!"
endfunction
endif
処理の流れ的には以下の様な感じだ。
-
s:dein_tap()
て関数を作ってこれをdein#tap()
の代わりに使うようにする。 - ブロック内では
function! s:{s:on_source}()
というコピペOKなお決まりの関数定義を書いて中にやりたい処理を書くだけでよい。 -
autocmd
の登録もs:dein_tap()
がやってくれているので毎回自分で書いてやる必要はない。 - もちろん
s:dein_tap()
を使ったけどコールバック関数の定義しなかったって場合でもエラーになったりはしない。
個人の趣味によるかもだけど、なかなかよい感じではないかな?
hook_* オプションが追加されたのでこっち使うほうが良さそう! (追記2016-03-20
コミットログによると 2016-03-19 に hook_source
の他、hook_*
な複数の(dein#add
時の)オプションが追加されたので今後はこれを使うのが良さそうです。
hook_系オプションには文字列で実行させたいコマンドを書く感じですが、改行で区切れば複数行もオーケーな模様。そして改行区切りがイケるということはどちらかというと vimrc 内で書くというよりは toml 向けの新機能と言えるでしょう。
vimスクリプト内に文字列でvimコマンドを列強するのはクオートの記述が煩雑になるので余り嬉しい機能に思えませんが、逆に toml では '''
で囲むことで複数行が簡単に記述できるので hook_* の導入によって toml でプラグインを管理するインセンティブが格段に上がりました。
僕は一つのプラグインの設定を追加と後処理で複数箇所に生き別れ状態で書かなきゃいけないのが嫌だったので toml 機能の導入は躊躇してたんですが、hookをtoml側で簡潔に書けるようになったことで、逆にtomlの方がaddと後処理を全て一箇所にまとめて書けるようになって俄然tomlで管理したくなりました。
ということで記述例をここに書くのは後にしてとりあえず自分の設定をこの後tomlに書き換えていってみたいと思います。
追記:TOML管理に移行したので改めてまとめました> dein.vimのプラグイン設定のマイベストプラクティス - Qiita