neobundle.vim の遅延処理で Vim の起動を高速化する

この記事は Vim Advent Calendar 2012 73日目の記事になります。


今回は最近実装された neobundle.vim の遅延読み込み処理をわたしが把握している範囲で簡単にまとめてみたいと思います。
neobundle.vimプラグインの遅延読み込み行うことで Vim の起動の高速化が期待出来ます。

[その前に]

neobundle.vim 自体に関しては下記の資料を読んでみるといいと思います。


また、neobundle.vim の遅延読み込みに関して下記の記事と一部被っている記述があります。
全体的な Vim の起動の高速化に関してはこちらの方が参考になるかと思います。

[プラグインを読み込む]

neobundle.vimプラグインを読み込む場合、基本的には次のような設定になると思います。

" プラグインを読み込む
NeoBundle "Shougo/unite.vim"
NeoBundle "Shougo/vimfiler", { 'depends' : ["Shougo/unite.vim"] }
NeoBundle "ryutorion/vim-itunes"
NeoBundle "tyru/open-browser.vim"
NeoBundle "vim-jp/cpp-vim"


" プラグインの初期設定
let g:unite_source_file_mru_limit = 300
let g:unite_kind_jump_list_after_jump_scroll=0
call unite#custom_default_action('directory' , 'tabvimfiler')
call unite#custom_default_action("directory_mru", "vimfiler")

let g:vimfiler_safe_mode_by_default=0
let g:unite_kind_file_use_trashbox = 1
let g:vimfiler_as_default_explorer = 1
let g:vimfiler_split_rule="botright"


" プラグインを呼び出すキーマッピング
nnoremap <Space>ufm :Unite file_mru2<CR>
nnoremap <Space>udm :Unite directory_mru<CR>

nnoremap <Space>vf  :VimFilerTab<CR>

noremap <expr> <Space>i<Space> itunes#pause()
nnoremap <expr> <Space>ip itunes#play()
nnoremap <expr> <Space>is itunes#stop()
nnoremap <expr> <Space>ih itunes#prev()
nnoremap <expr> <Space>il itunes#next()

nmap <Space>op  <Plug>(openbrowser-smart-search)


上記のような場合、プラグインを使用するまでの流れとしては、

という形になると思います。
今回は上記の設定を基礎として書き進めて行きたいと思います。

[プラグインの初期化処理を on_source に記述する]

遅延読み込みを行う前にまずプラグインの初期化処理を切り分けたいと思います。
neobundle.vim の hook 機能を使用すれば『プラグインが読み込まれた時』に処理を hook 事が出来ます。

" プラグインを読み込む
NeoBundle "Shougo/unite.vim"
NeoBundle "Shougo/vimfiler", { 'depends' : ["Shougo/unite.vim"] }
NeoBundle "ryutorion/vim-itunes"
NeoBundle "tyru/open-browser.vim"
NeoBundle "vim-jp/cpp-vim"


" プラグインの初期設定
" 各プラグインが読み込まれている場合に処理される
" :NeoBundle している場合は neobundle.vim 側で自動的に呼び出される
let s:bundle = neobundle#get("unite.vim")
function! s:bundle.hooks.on_source(bundle)
    let g:unite_source_file_mru_limit = 300
    let g:unite_kind_jump_list_after_jump_scroll=0
    call unite#custom_default_action('directory' , 'tabvimfiler')
    call unite#custom_default_action("directory_mru", "vimfiler")
endfunction
unlet s:bundle

let s:bundle = neobundle#get("vimfiler")
function! s:bundle.hooks.on_source(bundle)
    let g:vimfiler_safe_mode_by_default=0
    let g:unite_kind_file_use_trashbox = 1
    let g:vimfiler_as_default_explorer = 1
    let g:vimfiler_split_rule="botright"
endfunction
unlet s:bundle


" プラグインを呼び出すキーマッピング
nnoremap <Space>ufm :Unite file_mru2<CR>
nnoremap <Space>udm :Unite directory_mru<CR>

nnoremap <Space>vf  :VimFilerTab<CR>

noremap <expr> <Space>i<Space> itunes#pause()
nnoremap <expr> <Space>ip itunes#play()
nnoremap <expr> <Space>is itunes#stop()
nnoremap <expr> <Space>ih itunes#prev()
nnoremap <expr> <Space>il itunes#next()

nmap <Space>op  <Plug>(openbrowser-smart-search)


上記のような設定をしておけば『後からプラグインを無効にした場合』でも初期化処理が呼ばれることがないので無駄な処理を省く事が出来ます。
また unite.vim の初期化処理として unite#custom_default_action を使用していますが、これは unite.vim が読み込まれていなければエラーになってしまいます。
初期化処理処理を切り分けておけばこれを回避する事も出来ます。


あと『実際にプラグインが読み込まれるまでプラグインの初期化処理を行わない』という設定にも利用できます。
ちなみにマッピングを初期化処理に設定していないのは後から設定する自動読み込みのキーとして使用する為です。

[プラグインの遅延読み込み]

さて、本題の遅延読み込みを行う設定を記述したいと思います。
コマンドは :NeoBundle ではなくて :NeoBundleLazy を使用します。
:NeoBundleLazy を使用するとコマンドの呼び出し時にプラグインが読み込まれるのではなくて :NeoBundleSource した時にプラグインが読み込まれるような流れに変わります。
基本的な記述方法は :NeoBundle と変わりありません。

" プラグインの遅延読み込み
" NeoBundleLazy を使用する
NeoBundleLazy "Shougo/unite.vim"
NeoBundleLazy "Shougo/vimfiler", { 'depends' : ["Shougo/unite.vim"] }
NeoBundleLazy "ryutorion/vim-itunes"
NeoBundleLazy "tyru/open-browser.vim"
NeoBundleLazy "vim-jp/cpp-vim"


" プラグインの初期設定
" 各プラグインが読み込まれている場合に処理される
let s:bundle = neobundle#get("vimfiler")
function! s:bundle.hooks.on_source(bundle)
    let g:vimfiler_safe_mode_by_default=0
    let g:unite_kind_file_use_trashbox = 1
    let g:vimfiler_as_default_explorer = 1
    let g:vimfiler_split_rule="botright"
endfunction
unlet s:bundle


let s:bundle = neobundle#get("unite.vim")
function! s:bundle.hooks.on_source(bundle)
    let g:unite_source_file_mru_limit = 300
    let g:unite_kind_jump_list_after_jump_scroll=0
    call unite#custom_default_action('directory' , 'tabvimfiler')
    call unite#custom_default_action("directory_mru", "vimfiler")
endfunction
unlet s:bundle


" プラグインを呼び出すキーマッピング
nnoremap <Space>vf  :VimFilerTab<CR>

nnoremap <Space>ufm :Unite file_mru2<CR>
nnoremap <Space>udm :Unite directory_mru<CR>

nnoremap <expr> <Space>i<Space> itunes#pause()
nnoremap <expr> <Space>ip itunes#play()
nnoremap <expr> <Space>is itunes#stop()
nnoremap <expr> <Space>ih itunes#prev()
nnoremap <expr> <Space>il itunes#next()

nmap <Space>op  <Plug>(openbrowser-smart-search)


上記の設定が vimrc に記述されている場合、Vim の起動時にプラグインの読み込みは行われません。
ですので、その分だけ Vim の起動時間が短縮されて高速化が期待出来ます。
実際にプラグインを読み込みたい場合は Vim の起動後に :NeoBundleSource を呼び出す必要があります。
例えば、unite.vim を使用するのであれば

" :NeoBundleSource を呼び出した以降であれば :Unite 等が使用出来る
:NeoBundleSource unite.vim

" :NeoBundleSource が呼ばれた時に
" hooks.on_source
" に設定した処理が呼ばれる

というような呼び出しが必要です。

[プラグインの自動読み込みを行う]

:NeoBundleLazy を使用することでプラグインの遅延読み込みを行うことが出来ました。
が、プラグインを使用する時に明示的に :NeoBundleSource を呼び出すのはめんどくさいですね。
素晴らしいことに neobundle.vim では任意のタイミングで自動的に :NeoBundleSource してくれるような設定を行うことが出来ます。
この設定は下記のように :NeoBundleLazy のオプションに追加します。

" プラグインの遅延読み込み

" 'commands' に設定したコマンドが呼ばれた時に読み込まれる
NeoBundleLazy "Shougo/unite.vim", {
\   'autoload' : {
\       'commands' : [ "Unite" ]
\   }
\}


NeoBundleLazy 'Shougo/vimfiler', {
\   'depends' : ["Shougo/unite.vim"],
\   'autoload' : {
\       'commands' : [ "VimFilerTab", "VimFiler", "VimFilerExplorer" ]
\   }
\}

" itunes#〜 autoload 関数が呼ばれた時に読み込まれる
" 今回は説明の為に明示的に設定してあるが、
" 通常はautoload関数名から自動推測されるので設定されてなくても問題ない
NeoBundleLazy "ryutorion/vim-itunes", {
\   'autoload' : {
\       'function_prefix' : "itunes"
\   },
\}

" OpenBrowser 関数
" :OpenBrowser, :OpenBrowserSearch コマンド
" <Plug>(openbrowser-smart-search) キーマッピング
" のいずれかが呼ばれた場合に読み込まれる
NeoBundleLazy "tyru/open-browser.vim", {
\   'autoload' : {
\       'functions' : "OpenBrowser",
\       'commands'  : ["OpenBrowser", "OpenBrowserSearch"],
\       'mappings'  : "<Plug>(openbrowser-smart-search)"
\   },
\}

" set filetype=cpp
" された時に読み込まれる
NeoBundleLazy "vim-jp/cpp-vim", {
\   "autoload" : { "filetypes" : ["cpp"] }
\}


" プラグインの初期設定
" 各プラグインが読み込まれている場合に処理される
let s:bundle = neobundle#get("unite.vim")
function! s:bundle.hooks.on_source(bundle)
    let g:unite_source_file_mru_limit = 300
    let g:unite_kind_jump_list_after_jump_scroll=0
    call unite#custom_default_action('directory' , 'tabvimfiler')
    call unite#custom_default_action("directory_mru", "vimfiler")
endfunction
unlet s:bundle

let s:bundle = neobundle#get("vimfiler")
function! s:bundle.hooks.on_source(bundle)
    let g:vimfiler_safe_mode_by_default=0
    let g:unite_kind_file_use_trashbox = 1
    let g:vimfiler_as_default_explorer = 1
    let g:vimfiler_split_rule="botright"
endfunction
unlet s:bundle


" プラグインを呼び出すキーマッピング
nnoremap <Space>ufm :Unite file_mru<CR>
nnoremap <Space>udm :Unite directory_mru<CR>

nnoremap <Space>vf  :VimFilerTab<CR>

nnoremap <expr> <Space>i<Space> itunes#pause()
nnoremap <expr> <Space>ip itunes#play()
nnoremap <expr> <Space>is itunes#stop()
nnoremap <expr> <Space>ih itunes#prev()
nnoremap <expr> <Space>il itunes#next()

nmap <Space>op  <Plug>(openbrowser-smart-search)


このように任意のタイミングで自動読み込みを設定する事が出来ます。
これでいちいち :NeoBundleSource を呼び出す必要がなくなりました。
現在、プラグインの自動読み込みを設定できるタイミングは、

  • filetypes
    • filetype が設定された時
  • commands
    • command が呼ばれた時
  • function
    • 関数が呼ばれた時
  • function_prefix
    • {function_prefix}# のような関数が呼ばれた時
  • mappings
  • insert
    • insert に入った時

になります。


詳細は

:help neobundle-options-autoload

を参照して下さい。

[まとめ]

こんな感じで neobundle.vim をしよ空いたプラグインの遅延読み込みを設定することが出来ました。
プラグインを読み込むまでの大まかな処理の流れとしては、

  • 1.:NeoBundleLazy を設定する
  • 2.:NeoBundleLazy に設定したコマンドや関数が呼ばれる
  • 3.:NeoBundleSource が処理されプラグインが読み込まれる
  • 4.:NeoBundleSource から on_source が呼ばれてプラグインの初期化処理を行う
  • 5.最初に読んだコマンドや関数が処理される


になります。
設定を既述する時のコツなんですがわたしは『プラグインの初期化処理』と『プラグインを呼び出す処理』を分けることを意識しています。


ちなみにわたしの環境では neobundle.vim の遅延読み込みを行うことで起動時間が

3937.000 → 2156.000

まで短縮することが出来ました。
早い/(^o^)\


と、いう感じで使用しているプラグインによって効果はまちまちだと思いますが、設定はそんなに難しくないので起動時間を短縮してみたい方はやってみるといいと思います。

[明日は]

明日は Mi Sawa さんになります。
Vim Advent Calendar はまだまだ募集中ですよ!!