dein.vimでon_source処理を簡単に書けるようにした

`dein.vim` でプラグインが読み込まれた時に実行させたい処理は `autocmd` でユーザーイベントをフックして使うようになったようだ。`NeoBundle`では独自の`on_source`オプションがあったが、`dein.vim`では標準の機能を上手く使ってシンプル＆高速化していこうっていうことだと思う。

で、そのsourceフックの書き方について、何か上手い書き方は無いかなーと色々模索してみた記録です。

結論を先に書いておくと、最終的には[TOML管理が一番良さそう](http://qiita.com/kawaz/items/ee725f6214f91337b42b)という結論に落ち着きました。


# 普通の書き方
`dein.vim` ではプラグイン毎の設定や読み込み時の追加処理はこんな感じに書けば良いようだ。

```vim:~/.config/nvim/init.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したプラグイン名が入ってくれるようだ。これを使ってフック関数名を作っちゃえばいいんじゃね？…出来た！

```vim:~/.config/nvim/init.vim
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` の登録部分はプラグイン毎に全く同じコードを実行してるだけし、もっと簡素な書き方で省力化出来ないかなー。
うーん、もうちょっとゴニョってみよう…、出来た！

```vim:~/.config/nvim/init.vim
" 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-１９ に `hook_source` の他、`hook_*` な複数の(`dein#add`時の)オプションが追加されたので今後はこれを使うのが良さそうです。

hook_系オプションには文字列で実行させたいコマンドを書く感じですが、改行で区切れば複数行もオーケーな模様。そして改行区切りがイケるということはどちらかというと vimrc 内で書くというよりは toml 向けの新機能と言えるでしょう。
vimスクリプト内に文字列でvimコマンドを列強するのはクオートの記述が煩雑になるので余り嬉しい機能に思えませんが、逆に toml では `'''` で囲むことで複数行が簡単に記述できるので hook_* の導入によって toml でプラグインを管理するインセンティブが格段に上がりました。

僕は一つのプラグインの設定を追加と後処理で複数箇所に生き別れ状態で書かなきゃいけないのが嫌だったので toml 機能の導入は躊躇してたんですが、hookをtoml側で簡潔に書けるようになったことで、逆にtomlの方がaddと後処理を全て一箇所にまとめて書けるようになって俄然tomlで管理したくなりました。

ということで記述例をここに書くのは後にしてとりあえず自分の設定をこの後tomlに書き換えていってみたいと思います。

追記：TOML管理に移行したので改めてまとめました＞ [dein.vimのプラグイン設定のマイベストプラクティス - Qiita](http://qiita.com/kawaz/items/ee725f6214f91337b42b)