Unbundle.vim が有効にならないパターン

Unbundle.vim は filetype を見て、filetype に一致したプラグインを読み込んでくれる。
詳しくは [twitter:@mattn_jp] さんのブログ参照。
Big Sky :: pathogen やめた。


しばらく使っていて、次のような現象が発生した。
MacVim Kaoriya の GUI を使っていて、起動直後に :set filetype=python としても unbundle.vim が読み込んでくれるはずの ~/.vim/ftbundle/python/* が読み込まれない。
# たとえば :e sample.py とかだと動作する


色々調査してみた。
まず再現したのが MacVim Kaoriya, Windows 版 Kaoriya で発生した。
MacVim, Ubuntuaptitude からインストールした Vim, Ubuntu でソースからビルドした Vim では発生しなかった。


まず Kaoriya 版が使っているプラグインを疑った(結果的には濡れ衣だった orz)。
Kaoriya 版 Vim は plugins/kaoriya/plugin/* を自動的に読み込んでいる
Vim は起動時に $VIM/vimrc を読み込む。
この中には Vim が提供する example_vimrc.vim というファイルを読み込む。
この中には filetype plugin indent on という定義がある。


filetype plugin indent on が実行すると、Vim はデフォルトの ftplugin/* の filetype プラグインを読み込む。
例えば jedi.vim は omnifunc を jedi.vim 内で設定しているが、先にデフォルトの ftplugin/python.vim の omnifunc が設定される。
この時最初に filetype plugin indent on した際の設定がキャッシュされるそう。


example_vimrc.vim 読み込み完了後に自分の .vimrc が読まれて、その中で unbundle.vim が読み込まれる。
unbundle.vim は filetype を検知して、vim の runtimepath に ftbundle 内の該当するプラグインを追加する。
ここで、プラグイン追加後にバッファの再読み込みを行う。

function! Unftbundle(type)
  let l:bundles = Unbundle('ftbundle/' . a:type . '/*')
  if !empty(l:bundles)
    " load ftbundles that were newly added to the runtimepath
    for l:plugin in filter(split(globpath(l:bundles, 'plugin/**/*.vim'), "\n"), '!isdirectory(v:val)')
      execute 'source' fnameescape(l:plugin)
    endfor

    " apply newly loaded ftbundles to currently open buffers
    doautoall BufRead
  endif
endfunction

# doautoall BufRead の部分
ただし、

との事なので、doautoall の後に let &l:filetype = &l:filetype すれば再度 filetype が実行され、autocmd FileType とかが動作する。
# 送付しているパッチは doautoall BufRead,FileType としていた
# どっちが良いのだろうか…


これで一応問題は解決するが、このパッチが正しいのかが凄く微妙な気がしている。
まず example_vimrc.vim を unbundle.vim を読み込んでるのが Kaoriya 版 Vim 以外にあるのか。
# もっとも unbundle.vim を読み込む前に filetype plugin indent on とかしてたら一緒だけど…


filetype plugin indent on を unbundle.vim 読み込む前にしていない場合に Unftbundle() 内で &l:filetype = &l:filetype や doautoall BufRead,FileType を定義した場合、同じ autocmd FileType が二回動作する。
この二回動作するというのが個人的にもの凄くモヤっとする所。


Pull Request したパッチを以下のようしようかと思ってる所。
# まだ出してないくて、unbundle.vim の作者さんにはちょっと調査するからと言って待って貰ってる

--- unbundle.vim.orig	2013-01-12 03:01:33.000000000 +0900
+++ unbundle.vim	2013-01-12 03:46:21.000000000 +0900
@@ -31,11 +31,26 @@
       execute 'source' fnameescape(l:plugin)
     endfor
 
+    if s:file_type_set == 1
+      let &l:filetype = &l:filetype
+    endif
     " apply newly loaded ftbundles to currently open buffers
-    doautoall BufRead,FileType
+    doautoall BufRead
   endif
 endfunction
 
+" If filetype `plugin indent on` already have been set before unbundle.vim,
+" unbundle.vim should execute autocmd filetype.
+"
+redir => filetype_out
+  silent filetype
+redir END
+let s:file_type_set = 0
+if filetype_out =~# 'plugin:(on)' || filetype_out =~# 'plugin:ON'
+  let s:file_type_set = 1
+endif
+
 " commands for manual invocation
 command! Unbundle call Unbundle('bundle/*')
 command! -nargs=1 -complete=filetype Unftbundle call Unftbundle(<f-args>)

# 自分の環境じゃ :filetype で MacVim で plugin:(on) って入ってた。
# あとで調査する。
# あと Windows でもどうなるか調査する必要あり。

謝辞

[twitter:@mattn_jp] さん、[twitter:@kaoriya] さん、[twitter:@h_east] さん、[twitter:@splhack] さん、[twitter:@ShougoMatsu] さんに Twitter 上で色々アドバイスを頂いた。
ありがとうございます。感謝します!