Vim標準機能だけでプラグインがインストール済みかの確認方法

テキストエディターにVimを使っています。Vimの標準機能だけであるプラグインが現在インストールされているかの判定方法を記します。

はじめに

Vimで作業を快適にするためにいくつかプラグインをインストールしています。そして,プラグインの機能を有効化するために,その設定を.vimrcに記述しています。

しかし,プラグイン固有の設定を.vimrcに記述すると,そのプラグインがインストールされていなければ,変数や関数が未定義であるためエラーとなります。

これを回避するために,あるプラグインが現在インストールされているかを判定し,インストールされているときだけそのプラグイン固有の設定を記述する必要があります。

パッケージマネージャーやプラグインマネージャーとよばれるプラグインを管理するためのVimプラグインには,プラグインがインストールされているかを識別する関数が用意されています。

例えば,NeoBundleにはneobundle#is_installed()が存在し,以下のように記述することでNeoBundleでプラグインを管理できているかどうかを判定できます。

NeoBundleによるプラグインの有無の判定方法
if s:Neobundled('caw.vim')
    nmap \c <Plug>(caw:hatpos:toggle)
    vmap \c <Plug>(caw:hatpos:toggle)
    nmap \C <Plug>(caw:zeropos:uncomment)
    vmap \C <Plug>(caw:zeropos:uncomment)
endif

上記の例では,コメントのオン/オフの切り替えプラグインcaw.vimがインストールされているかどうかを判定し,インストールされていればその設定を行っています。

ただし,この方法には以下2点の問題があります。

パッケージマネージャーを利用したプラグインの有無の判定方法の問題
  1. そのパッケージマネージャーを使っていないと利用できない
  2. そのパッケージマネージャー自体がインストールされているかどうかを判定できない

そのため,できればより汎用的で特定のプラグインの機能に頼らずに,プラグインのインストールの判定を行う必要があります。

方法

この問題を解決するために,Vimの標準機能だけで指定したプラグインがインストールされているかどうかを判定する方法を考案しました。

以下の関数を用意して実現します。

プラグインがインストールされているかの判定方法
"" \brief Check if a plugin is installed.
"" \param[in] plugin Plugin name (direcotry name).
"" \return 1: installed, 0: not installed.
function! s:is_plugin_installed(plugin)
  return globpath(&runtimepath, 'pack/*/*/' . a:plugin, 1) != ''
endfunction   

処理の流れは以下となります。

s:is_plugin_installed()の処理の流れ
  1. 引数にプラグイン名を指定。
  2. runtimepathからglobpathによりpack/<directory>/<start or opt>/から指定した名前のプラグインを検索。
  3. プラグイン名のディレクトリーが存在すれば,trueを返却し,なければfalseを返却。

Vim 8から搭載されたパッケージ管理機能では,プラグインをpackpath配下のpack/ディレクトリー/startまたはpack/ディレクトリー/optに配置することになっています。globpath()によりpack/配下の3階層下のディレクトリーを確認することで,プラグインがインストールされているかを判定しています。

s:is_plugin_installed関数の利用例は以下となります。

s:is_plugin_istalled().vimrcでの利用例
if has('vim_starting')
  if match(&runtimepath, expand('~/.vim')) == -1
    set runtimepath& runtimepath+=~/.vim,~/.vim/after
    if exists('+packpath')
      set packpath& packpath+=~/.vim
    endif
  endif
endif

"" \brief Check if a plugin is installed.
"" \param[in] plugin Plugin name (direcotry name).
"" \return 1: installed, 0: not installed.
function! s:is_plugin_installed(plugin)
  return globpath(&runtimepath, 'pack/*/*/' . a:plugin, 1) != ''
endfunction

if s:is_plugin_installed('vim-mucomplete')
  set completeopt& completeopt+=menuone
  inoremap <expr> <c-e> mucomplete#popup_exit("\<c-e>")
  inoremap <expr> <c-y> mucomplete#popup_exit("\<c-y>")
  inoremap <expr>  <cr> mucomplete#popup_exit("\<cr>")
  set completeopt+=noselect
  set completeopt+=noinsert
  set shortmess+=c   " Shut off completion messages
  set belloff+=ctrlg " If Vim beeps during completion
  let g:mucomplete#enable_auto_at_startup = 1
endif

この例では,Windowsなどpackpath~/.vimがデフォルトで設定されていない場合に,packpath~/.vimを指定しています。その後,補完プラグインであるvim-mucompleteがインストールされているかを判定し,存在すればその設定を反映させるようにしています。

なお,当初は以下のようにfinddir()を使ってプラグインのディレクトリーを判定していました。

finddir()によるプラグインの有無の判定方法
"" \brief Check if a plugin is installed.                                       
"" \param[in] plugin Plugin name (direcotry name).                              
"" \return 1: installed, 0: not installed.                                      
function! s:is_plugin_installed(plugin)                                         
  for path in split(&runtimepath, ',')                                          
    if finddir(a:plugin, path . '/**') != ''                                    
      return 1                                                                  
    endif                                                                       
  endfor                                                                        
  return 0                                                                      
endfunction       

しかし,finddir()'/**'により再帰的に検索すると時間がかかりVimの起動が遅くなってしまいました。そこで,より速度の速いglobpath()を採用しました。

まとめ

Vimの標準機能だけでプラグインがインストールされているかの判定方法を解説しました。

Vim 8になってから標準でパッケージ管理機能が実装され,パッケージマネージャーを使わなくてもプラグインを管理できるようになりました。今回のプラグインの判定方法を活用することで,標準の機能だけでもある程度の管理ができます。

依存性を下げ,どこでも動作するような.vimrcの記述を心がけたいものです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です