Effective NeoBundle -- autoload関数を理解しNeoBundleを使いこなすための8の方法 --

[1]: http://atnd.org/events/33746
[2]: http://twitter.com/tyru
[3]: http://d.hatena.ne.jp/tyru/20130509/vim_replaceable_keys
[4]: http://vim-jp.org/reading-vimrc/archive/044.html
[5]: http://d.hatena.ne.jp/osyo-manga/20130211/1360582966
[6]: http://www.slideshare.net/Shougo/neobundlevim
[7]: http://d.hatena.ne.jp/osyo-manga/searchdiary?word=NeoBundleFetch


この記事は[Vim Advent Calendar 2012 : ATND][1] 160日目の記事になります。
159日目は[@tyru][2]の[これであなたも節約上手！キーボード上のキーを最大限活用できる人のN個の習慣とは？][3]でした。

[第44回 vimrc読書会][4]で「neobundle#config() に関する記事を書くと有り難がられる。」
という話になったので、今回はNeoBundleのコアな設定(もしくは意外と知られていない設定)
について紹介したいと思います。

- - - - - - - - - - - - - - - - - - - - - - - -

# neobundle#rc()は引数を省略できる。

この関数`neobundle#rc([{base-path}])`は引数である{base-path}を省略することができます。
省略するとどうなるかというと、下記のコードは同じ意味を持つことになります。

> call neobundle#rc()
> call neobundle#rc(expand('~/.vim/bundle'))

NeoBundle使っている方は知っているかと思いますが念のためneobundle#rc()の説明をします。

neobundle#rc()はNeoBundleを初期化する関数です。
この関数を呼ぶ前に必ず以下のようにneobundle.vimのディレクトリを`has('vim_starting')`内でruntimepathに加えておかなければなりません。決して、`has('vim_starting')`内で`neobundle#rc()`を呼び出してはいけません。

```vim:
set nocompatible
if has("vim_starting")
  set runtimepath+=~/.vim/neobundle.vim
endif
call neobundle#rc(expand("~/.vim/bundle"))
...
filetype plugin indent on
```

ちなみに、なぜ`has('vim_starting')`内で`neobundle#rc()`を呼び出してはいけないかというとvimrcの再読み込みに備えるためにです。

`has('vim_starting')`はVimの起動時のみ真になります。なので、vimrcを`so $MYVIMRC`などで再読み込みした時にはもうすでに`has('vim_starting')`は偽になってしまいます。
ということは、`set runtimepath+=~/.vim/neobundle.vim`は再読み込みした時にもう一度設定する必要がないため`has('vim_starting')`内でよく、`call neobundle#rc(expand("~/.vim/bundle"))`はこの後設定する`NeoBundle '~'`のために一度設定をクリアにしとかなければなりません。


また、この関数は自動的に`:filetype off`を行います。
なのでわざわざ、vimrcに`:filetype off`を行うようなコードは必要ありません。

引数である{base-path}はNeoBundleで管理されたプラグインがデフォルトでインストール
されるディレクトリです。{base-path}は**省略可能**です。省略した場合、デフォルトで
インストールされるディレクトリは下記のような式で設定されます。

> expand(get( filter(split(globpath(&runtimepath, 'bundle', 1), '\n'), 'isdirectory(v:val)'), 0, '~/.vim/bundle'))

なので、`call neobundle#rc()`と`call neobundle#rc(expand('~/.vim/bundle'))`は全く
同じ意味になります。

# ":set rtp+=..."やNeoBundle系のコマンドの違いを理解する。

Vimプラグインを使用する場合NeoBundle系のコマンドを使用すると思いますが、
NeoBundle系のコマンドには何種類か存在します。
ここで、`:set rtp+=...`やNeoBundle系のコマンドの違いをまとめてみたいと思います。
とりあえず、簡単に表にまとめてみました。

|               |&rtpに追加される|NeoBundleで管理される|プラグインが読み込むタイミング|
|:--------------|----------------|---------------------|------------------------------|
|set rtp+=...   |        ○      |         ×          | filetype on が実行された直後 |
|NeoBundleLocal |        ○      |         ○          | filetype on が実行された直後 |
|NeoBundle      |        ○      |         ○          | filetype on が実行された直後 |
|NeoBundleFetch |        ×      |         ○          | 読み込まれない               |
|NeoBundleLazy  |        ○      |         ○          | hookかNeoBundleSourceを実行後|

1番目の`set rtp+=...`は問題ないですね。&runtimepathに新しいパスを追加するだけです。
NeoBundleで管理もされませんし、プラグインが読み込むタイミングを遅延させることも出来ません。

2番目の`NeoBundleLocal`は`set rtp+=...`の追加を楽にしたバージョンという感じです。

> NeoBundleLocal ~/.vim/mybundle

使いかたは上記のような感じでパスを指定し、このパスのサブディレクトリに当たるパスを
それぞれ&runtimepathに加えることができます。
<del>これもNeoBundleで管理もされませんし、</del>これはNeoBundleで管理もされます。
しかし、プラグインが読み込むタイミングを遅延させることは出来ません。

3番目の`NeoBundle`も問題ないですね。
&runtimepathに新しいパスを追加しNeoBundleで管理します。
基本的にはプラグインが読み込むタイミングを遅延させることも出来ませんが、
後述する`neobundle#config()`によって特性をいくらでも変更することは可能です。

4番目の`NeoBundleFetch`は使いどころが難しいコマンドです。
このコマンドはNeoBundleで管理するだけです。
&runtimepathに追加しないので、プラグインを読み込むこともしません。
主な使いどころは[neobundle.vim で github の C++ ライブラリを管理する][7]のような
Vimプラグインでないライブラリの管理くらいでしょうか。

5番目の`NeoBundleLazy`は簡単にいうと`NeoBundle`の遅延評価版です。
NeoBundleでは管理されますが、すぐに&runtimepathにパスが追加されることはありません。
NeoBundleSourceを実行して初めて&runtimepathに追加されます。
もしくは、コマンドなどにフックを設定しておくことで遅延して読み込ませることが可能になります。
`NeoBundleLazy`も後述する`neobundle#config()`によって特性をいくらでも変更することは可能です。

# NeoBundleで管理されているプラグインかどうかを知る。

NeoBundleで管理されているプラグインかどうかがわかると、NeoBundle系コマンドを
コメントアウトしただけでプラグインの設定をオフにすることが可能になります。
で、NeoBundleで管理されているプラグインかどうかを知るには下記のようなコードで実現できます。

```vim:
" NeoBundle 'Shougo/neocomplcache'
if ! empty(neobundle#get("neocomplcache"))
  " コメントアウトしているのでここにはきません。
endif
```

# NeoBundleを導入する場合、autoload関数を呼ぶコストを考える。

NeoBundleを導入すると、必ず下記のファイルを読み込まれることになります。

* neobundle.vim/autoload/neobundle/util.vim
* neobundle.vim/autoload/neobundle.vim
* neobundle.vim/autoload/neobundle/config.vim
* neobundle.vim/ftdetect/vimrecipe.vim
* neobundle.vim/plugin/neobundle.vim

ということは、`neobundle#rc()`や`neobundle#config#bundle()`は呼び出しても
差ほどコストにはなりませんが、`neobundle#autoload#get_unite_sources()`などを
vimrcから読みだすと'neobundle.vim/autoload/neobundle/autoload.vim'が
新しく読み込まれるので、Vimの起動時間を長くする原因になりえるかもしれません。
NeoBundleに限った話ではありませんがvimrcからautoload関数を呼ぶ際には
注意しておくとよいかもしれません。

# NeoBundle系コマンドのオプションとneobundle#config()との関係を理解する。

> :NeoBundle {repository} [[,{revision}] [,{options}]]
> :NeoBundle {repository} ,{revision}, {default} [,{options}]]

`:NeoBundle`コマンドは上記のような構文になっております。(`:NeoBundleLazy`コマンドも同じく)
たとえば、下記のコマンドは{repository}が`'vimproc'`、{options}が`{ 'build' : { ... }}`に当たります。

```vim:
NeoBundle "vimproc", {
    \ "build" : {
    \     "windows" : "mingw32-make -f make_mingw32.mak",
    \     "cygwin"  : "make -f make_cygwin.mak",
    \     "mac"     : "make -f make_mac.mak",
    \     "unix"    : "make -f make_unix.mak",
    \    },
    \ }
```

で、この{options}部は`neobundle#config()`を使って次のように分割することができます。

```vim:
NeoBundle "vimproc"
call neobundle#config("vimproc", {
    \ "build" : {
    \     "windows" : "mingw32-make -f make_mingw32.mak",
    \     "cygwin"  : "make -f make_cygwin.mak",
    \     "mac"     : "make -f make_mac.mak",
    \     "unix"    : "make -f make_unix.mak",
    \    },
    \ })
```

ちなみに、{revision}部も{options}に含めることが可能です。

> call neobundle#config('vimproc', { 'rev' : '43AF234' })

また、`neobundle#config()`は既存の{options}に追加されるようになっていますので、
次の2つのような書き方ができます。

```vim:
" 分割して設定
call neobundle#config("vimproc", { "A" : "..." })
call neobundle#config("vimproc", { "B" : "..." })

" まとめて設定
call neobundle#config("vimproc", { "A" : "...", "B" : "..." })
```

NeoBundle系コマンドの{options}部で設定するのと、neobundle#config()で設定するのとでの違いはほとんどありません。

# NeoBundleLazyの正体

プラグインの読み込みを遅延させてくれるコマンド`NeoBundleLazy`というものがあります。
実はこれは、`NeoBundle`に'lazy'オプションを有効にしただけのaliasにすぎません。
なので、下記の２つは同じ挙動になります。

> NeoBundleLazy 'vimproc'

> NeoBundle 'vimproc', { 'lazy': 1 }

ただし、`:call neobundle#config('vimproc', { 'lazy': 1 })`とする場合、
`:filetype on`される前に呼ばないと遅延されないので気を付けてください。

# プラグインの設定をon_sourceでできるだけ遅延させる。

on_sourceというhookを利用することで、プラグインの設定をできるだけ遅延させることができます。

```vim:
" `Unite`コマンドが実行されるときに初めてプラグインを読み込む
NeoBundleLazy "Shougo/unite.vim", {
\   'autoload' : {
\       'commands' : [ "Unite" ]
\   }
\}

let s:hooks = neobundle#get_hooks("unite.vim")
function! s:hooks.on_source(bundle)
  " 遅延させたいプラグインの設定を記述する
endfunction
```

詳細は[neobundle.vim の遅延処理で Vim の起動を高速化する][5]を参考に！

# NeoBundleのほとんどの設定はneobundle#config#get_neobundles()で把握できる。

これまで、`neobundle#config()`を中心にしてきましたが、実際にどういう風に設定されているかは、
`neobundle#config#get_neobundles()`か`neobundle#get({bundle-name})`ですべて把握できます。
(オプションの詳細については今回は説明しません。:help neobundle-options を参照してみて下さい。)

### neobundle#config#get_neobundles()

この関数はNeoBundleの現状のセッティングを辞書のリストで返します。

```vim:
" echo neobundle#config#get_neobundles()
[
  {
    "autoload": {},
    "base": "C:/Users/rbtnn/.vimplugins",
    "depends": [],
    "description": "",
    "directory": "vimdoc-ja",
    "disabled": 0,
    "dummy_commands": [],
    "dummy_mappings": [],
    "external_commands": {},
    "gui": 0,
    "hooks": {},
    "lazy": 1,
    "name": "vimdoc-ja",
    "orig_arg": '''vim-jp/vimdoc-ja''',
    "orig_name": "vim-jp/vimdoc-ja",
    "orig_opts": [],
    "overwrite": 1,
    "path": "C:/Users/rbtnn/.vimplugins/vimdoc-ja",
    "resettable": 1,
    "rev": "",
    "rtp": "C:/Users/rbtnn/.vimplugins/vimdoc-ja",
    "script_type": "",
    "sourced": 0,
    "stay_same": 0,
    "tail_path": 1,
    "terminal": 0,
    "type": "git",
    "uri": "git://github.com/vim-jp/vimdoc-ja.git"
  },
  {
    "autoload": {"commands": ["HexriptToBinaryFile", "VinariseHex2Script", "VinariseScript2Hex"], "function_prefix": "hexript"},
    "base": "C:/Users/rbtnn/.vimplugins",

...
```

実際に実行して見てもらえればわかると思いますが、`NeoBundleLazy '...'`や`NeoBundle '...',{ ... }`
や`neobundle#config('...',{...})`で行った設定はこの関数で確認することが出来ます。

この関数は出力が非常に多いので私は以下のようなコマンドをvimrcに作成しておいて、
`QuickRunPP neobundle#config#get_neobundles()`を実行して確認しています。

```vim:
" NeoBundle "thinca/vim-quickrun"
" NeoBundle "thinca/vim-prettyprint"

function! s:quickrun_pp(q_args)
  let dict = { "type" : "vim", "runner" : "vimscript", "outputter" : "buffer",
  \   "outputter/buffer/filetype" : "vim", "hook/eval/enable" : 1,
  \   "hook/eval/template" : "echo PP(%s)", "src" : a:q_args, }
  call quickrun#run(dict)
endfunction
command! -nargs=1 -complete=expression QuickRunPP :call <sid>quickrun_pp(<q-args>)
```


毎回、neobundle#config#get_neobundles()から取り出してくるのは億劫なので、以下のようなショートカットautoload関数が用意されています。

### neobundle#get({bundle-name})

この関数は`neobundle#config#get_neobundles()`のキー'name'が{bundle-name}の辞書を
返します。もし、存在しない場合には`{}`を返します。

### neobundle#get_hooks({bundle-name})

この関数は`neobundle#get({bundle-name})`のキー'hooks'の値を返します。
もし、存在しない場合には`{}`を返します。

### neobundle#is_sourced({bundle-name})

この関数は`neobundle#get({bundle-name})`のキー'sourced'の値を返します。
もし、存在しない場合には`0`を返します。

### neobundle#is_installed({bundle-name})

この関数は`neobundle#get({bundle-name})`のキー'path'の値を返します。
もし、存在しない場合には`''`を返します。


# 終わり

始めはNeoBundleについて15個くらいのネタを書こうかと用意していたのですが、
段々飽きてきて最終的に8個になってしまいましたw。

今回は、`neobundle#config()`と`QuickRunPP neobundle#config#get_neobundles()`が結構便利だなーっていうことが書きたかっただけでした。以上

誰か、Effective Vim script書かないかな？