Vim Advent Calendar 2013: :NeoBundleLazy したプラグインをフォーカスが外れている時に自動的に読み込む

この記事は Vim Advent Calendar 2013 74日目の記事になります。
元ネタ:

http://lingr.com/room/vim/archives/2014/02/11#message-18320930

LingrVim 部屋で上記のようなやりとりがあったのですが、簡単に実装してみました。
ちなみに NeoBundleLazy というのは neobundle.vim で実装されているプラグインを遅延読込する機能です。
簡単に説明すると以下の様な感じです。

" これが通常の使い方
" Vim の起動時にプラグインが読み込まれる
" NeoBundle "Shougo/unite.vim"

" NeoBundleLazy を使用する
" Vim の起動時にはまだプラグインは読み込まれない
NeoBundleLazy "Shougo/unite.vim"


" 必要になった場合に後からプラグインを読み込む
NeoBundleSource unite.vim


今回は上記のコードで書かれている :NeoBundleSource の処理をVim のフォーカスが外れた場合に自動的に行うようなスクリプトを書いてみました。
また neobundle.vim の NeoBundleLazy を利用したプラグインの遅延読み込みについては以下の記事が参考になります。

ちなみに今回とは方向性が違いますが○○○のタイミングで自動的にプラグインを読み込むという機能は既に neobundle.vim に実装されています。
例えば、任意のコマンドが呼ばれた場合に自動的にそのコマンドのプラグインを読み込むことが可能です。

[ソース]

" Lazy しているプラグイン名をリストアップ
function! s:get_lazy_plugins()
    " 先に source したいプラグインをリストの先頭に追加する
    return [
\       "unite.vim",
\       "vimfiler.vim",
\       "vim-quickrun",
\   ] + map(filter(neobundle#config#get_neobundles(), "v:val.lazy"), "v:val.name")
endfunction


function! s:is_not_sourced(source)
    return neobundle#config#is_installed(a:source) && !neobundle#config#is_sourced(a:source)
endfunction


function! s:source()
    let sources =  map(filter(s:get_lazy_plugins(), "s:is_not_sourced(v:val)"), "v:val")
    if empty(sources)
        augroup auto-source
            autocmd!
        augroup END
        return
    endif
    echom "source:" . sources[0]
    call neobundle#source(sources[0])
    echom "sourced:" . sources[0]
endfunction


let s:active_auto_source = 0

augroup auto-source
    autocmd!
    autocmd CursorHold * if s:active_auto_source | call s:source() | endif
    autocmd FocusLost * let s:active_auto_source = 1
    autocmd FocusGained * let s:active_auto_source = 0
augroup END


上記のコードでは autocmd FocusLost をトリガーとし、Vim からフォーカスが外れている場合に autocmd CursorHold で自動的に次々とプラグインを読み込むようにしています。
フォーカスが Vim に戻ったら読み込みを中断します。
また、CursorHold は 'updatetime' の値に依存するので注意して下さい。
この値が大きいと次のプラグインを読み込むまでに時間がかかります。
必要であれば FocusLost 時に 'updatetime' を変更しておくとよいでしょう。


最初は微妙かと思っていたんですが、わたしは Vim からフォーカスを移動して別の作業をしている事が多いので結構いい感じですね。
ただ、読み込み時にコストがかかるプラグインには有効なんですが、autoload 関数などを活用してプラグインの読み込みを短くしているプラグインだと恩恵は少ないですね。
これを回避する場合は『プラグインを読み込んだ時に意図的に autoload 関数を呼び出したり初期化する』などと言った工夫が必要になってくると思います。
プラグイン側でそういう機能が用意されていればいいのですが、全部のプラグインで対応するのはちょっと大変そうですねぇ…。


あとは FocusLost/FocusGained + CursorHold の組み合わせが結構面白かったです。
これは何かに利用してみたい。