Blank File

LinuxとかPythonとかVimとか、趣味でいじる感じで

Vimのパッケージ機能を試してみました

最近dein.vimがバズったりVim本体にパッケージ機能が追加されたり、Vim界隈は第二次プラグインマネージャ戦争の気配に包まれています [要出典]。 dein.vimはすでにいくつか紹介記事がありますが、本体の方はあまり情報を見かけかなかったので先日試した結果を含めて紹介します。

この機能は入ったばかりなので、今後仕様の変更があるかもしれませんし、バグもあるかもしれませんし、(たぶん)機能追加もあると思います。 記事の内容が古くなっているかもしれないので、日付とVimのバージョンをよく確認してください。

試す人は本体のデバッグに自分のVimを捧げる気持ちでいきましょう。 バックアップ重要です。

[2016/03/07: :loadpluginが削除され:packaddが追加されたので修正]

[2016/03/19: 思いついたので追記] プラグインのインストール、アップデート、ヘルプの作成やpluginディレクトリにダミーファイル置いたりするスクリプトを書きましたので、気になる方はこちらもご参照下さい。

h-miyako.hatenablog.com

メリット

  • プラグインマネージャが裏で色々頑張ってくれていることが理解できる

必要なもの

  • 最新のVim
  • インストールするプラグイン
  • たくさんエラーが出てもいいVim環境
  • エラーやバグに負けない強い心

私は Kubuntu 15.10 で試しました。 Vimのバージョンは7.4.1225くらいでした。

情報源

  • :help packages
  • :help :packadd
  • :help 'packpath'

困ったらソースコード

とりあえずプラグインを入れてみる

プラグインを入れるディレクトリは大別して二種類です。

  • ~/.vim/pack/{好きな名前}/ever
  • ~/.vim/pack/{好きな名前}/opt

基本的にはever以下に自動的に読み込んでほしいプラグインを置いて、opt以下に必要な時に読み込む(遅延読込する)プラグインを置く形です。 すでにNeoBundleなどのプラグインマネージャを使っている場合はプラグインが一つのディレクトリにまとまっていると思いますので、その中身をまるっとever以下にコピーしてneobundle#begin()neobundle#end()あたりをif 0endifで囲めばすぐ試せます(微妙な仕様の違いがあるので、そのままだと大量のエラーを経験することになりますが)。

例えばplugin1とplugin2をever以下に置く場合は次のようなディレクトリ構成になります。

~/.vim
├── pack
│   ├── mypack
│   │   ├── ever
│   │   │   ├── plugin1
│   │   │   │   ├── autoload
│   │   │   │   ├── plugin
│   │   │   │   └── README.md
│   │   │   ├── plugin2
│   │   │   │   ├── autoload
│   │   │   │   ├── plugin
│   │   │   │   └── readme.md

この状態でVimを起動すると、.vimrcなどを読み込んだ後に自動的にplugin1とplugin2がruntimepathに追加されます。

太字部分重要です。 つまりvimrcの中ではプラグインが定義するコマンドや関数は使えません。 例えばNoeBundle ~とかやっていた部分は全滅します。 autoload関数も使えないので、設定でcall plugin#setup(...)などとしている部分も全滅です。 また、プラグインもロードされていないので、例えばif neobundle#is_installed('プラグイン名')などのかわりに単純にif get(g:, 'loaded_プラグイン名')などと置き換える事もできません。 値の設定(let g:superplugin_default_option = 1など)は大丈夫です。

私はこれを回避するために、プラグインを使っている部分を別ファイルに分離してオートコマンドでVimEnter時に読み込むようにしました。 ~/.vim/after/plugin以下も試してみましたが、ここもパッケージのロードより先に読み込まれていました。 最終的にはプラグインを使う設定を~/.vim/config/plugins.vimに書いて、次のような設定をvimrcに追加しました。

if filereadable(expand('~/.vim/config/plugins.vim'))
  autocmd myvimrc VimEnter * source ~/.vim/config/plugins.vim
endif

これでplugins.vimの中ではプラグインが使えます。 インストールの確認もif get(g:, 'loaded_~')if exists(':PluginCommand')などでできます。 g:loaded_~を設定しないプラグインは、とりあえずif match(&runtimepath, 'プラグイン名')で確認しています。

注意する点は、オプション値の設定(let g:~~~ = ...と設定するタイプ)はvimrc内に書いたほうが安全ということです。 読み込み時に設定値のチェックをしてそのまま使っているプラグインが結構あるようで、それらがロードされる前に値の設定を済ませる必要があるからです。

読み込まれないプラグイン対策

現在はpluginディレクトリがないプラグインは読み込まれない(runtimepathに追加されない)ようです。 これはautoload関数だけを提供しているプラグインtextobj-userなど)やカラースキーム(solalizedなど)、スニペット集(neosnippet-snippets)などが該当し、読み込まれません。 これが仕様として確定するのかわかりませんが、私はとりあえずの回避策としてmkdir plugin && touch plugin/_.vimと適当にファイルを作って置きました。

また、plugin直下に*.vimファイルがなく、さらにディレクトリがあるようなプラグインも読み込まれませんでした。 仕様なのか微妙ですが、runtimepathには追加されているのでバグのような気がします。 ありがたいことに動作確認とIssue報告までしていただいたので、7.5のリリースまでに修正されるのではないかと。。。 これも上記と同様に適当なファイル(*.vim)をpluginディレクトリに置くことで読み込み可能です。

遅延読み込み

opt以下のプラグインはそのままでは読み込まれません。 :packadd {プラグインのディレクトリ名}を実行して初めて有効になります。

私はとりあえずインサートモードで使うプラグインoptに置き、以下のような設定を行いました。

function! s:lazy_load_insert() abort
  loadplugin delimitMate
  loadplugin vim-smartchr
  loadplugin ...
  ...
  " マッピングなどの設定があればする
  call s:init_delimitMate()

  " 二回目以降実行されないようにautocmdを削除
  autocmd! lazy_load_i
endfunction

augroup lazy_load_i
  autocmd! InsertEnter * call s:lazy_load_insert()
augroup END

NeoBundleはコマンド実行や関数呼び出しやマッピングをトリガにして遅延読み込みできますが、大変そうだったのでそこまでやっていません。 起動時間に露骨に影響するようなプラグインはそもそも入れてないというのもありますが。 (NERDTreeやsyntasticは読み込みに結構時間かかるので使っていません)

起動時間

みなさん気になると思います。 ざっくり雑に測っただけですが、とりあえず遅延読み込みしないで全部読み込むような条件ではdein.vimと同じか少し速いくらい、NeoBundleより30~40%速い感じでした。 ただ、上に書いたように読み込まれないプラグインがけっこうあって、気づいたものは対策しましたがまだ読み込まれていないものもありそうなので、実際にはdein.vimと同じくらいじゃないかと思います。

余談ですが、Vimの起動時間が気になる人は(もしやっていないなら)ファイルタイプの設定を自前で用意してデフォルトのfiletype.vimを読まないようにするといいと思います。 デフォルトの設定だと人生で一度も使わないであろうファイルタイプの設定が大量にあるので。 デフォルトのfiletype.vimshare/vim/vim74/filetype.vimにあります。 ここから必要そうな設定を拝借してvimrcで設定するなりして、let g:did_load_filetypes=1しておけばデフォルトのファイルタイプ設定は読まれなくなります。

まとめ

NeoBundleがメンテナンスモードに入ると聞いてdein.vimへの移行を考えている方、どうせプラグイン周りの設定をいじるならついでに本体のパッケージ機能も試してみませんか? いっしょに人柱してバグを探しましょう。