Vimのプラグイン管理に疲弊した人に送る処方箋


はじめに

初投稿です。お手柔らかにお願いします。
タイトルは、テキトーなのでざっくりとVimのプラグイン管理の話なんだろうと思って貰えれば良いです。
たいした内容では無いのでVim初心者の方向けです。
おそらくN番煎じの内容だろうと思います。

背景

私が、Vimと出会ったのは学生の頃、Linuxのサーバー構築の授業でした。
最初は、操作に慣れず「使いずらいな」と思っていたのですが、操作に慣れると「作業がスーパー早くなった
そう思うようなってからはVimをよく利用していました。
でも結局、コーディングはEclipseなどのIDEを使うことが多くLinux関係以外でVimを使うことはなかった...

それから数年後社会人になって、業務でUbuntuを使って開発をする案件に携わるようになり「久々にVimってみるかな。​」と言うことでVimに復帰。
ところが、IDEというぬるま湯に使っていたせいか、Vimを使いこなせていないせいか(これは今もか)作業がしずらい。

ファイルツリー、コード補完、ビルド、Lint...

IDEのベタなこの辺りの機能がVimでできたらな。ということで、私のVimのプラグイン漁りの日々が始まりました。
ネットの記事を参考に「neobundle.vim」を入れて日夜、プラグインを入れたり消したり。
そんな日々が続いて、プラグイン漁りも落ち着いてきた頃、Vim 8がリリースされ、
細かい話は良く分からないけどなんか凄そう、そんな思いでVim 8をビルドして使うようになりました。

プラグインも充実して「No Vim No Life」な状態となっていたそんな時、
2017年のVim Advent Calendarに「Vim 8 時代のがんばらないプラグイン管理のすすめ」が投稿されていました。
ざっくりと「~/.vim/pack/plugin/start/*にプラグインを置けば起動時に読み込んでくれる機能がVimにあるよ」という内容の記事で、
私にとっては晴天の霹靂でした。「Vimにプラグイン管理機能があったとは…Vimは深い。」

詳細は記事を読んで頂ければと思いますが、早速私はneobundle.vimにさよならして
git submoduleでvimのプラグインを管理するようになりました。

あれから1年とちょっと経ちますが、プラグインの追加、削除の度にgit submodule … 。
定期的にプラグインの整理をしているとgit sumoduleでの管理すら面倒になってきました。。。
人間(私)は面倒くさがり屋なのです。
(と言うか、自宅、職場で計5環境ぐらいあることが問題なのか?)

そこで、.vimrcのみでプラグインの管理は出来ないものかと思い手を動かしてみました。

要件

前置きが長くなりましたが、以下が要件です。

  • ファイル(.vimrc)にプラグインの情報を書くだけで追加、削除できたら嬉しい
  • 高機能なプラグイン管理は要らない(プラグインのバージョン管理、遅延ロードなど)
  • プラグインのアップデートは気にしてない
  • gitで公開されているプラグインしか使わない

要は「.vimrcを編集すればプラグインの追加、削除が行われるようにしたい」ただそれだけ。

出来上がったもの

if has('win32')
    let PLUGIN_PATH = expand('~/vimfiles/pack/plugin/start/')
else
    let PLUGIN_PATH = expand('~/.vim/pack/plugin/start/')
endif

if !isdirectory(PLUGIN_PATH)
    call mkdir(PLUGIN_PATH, 'p')
endif

let PLUGIN_LIST = {
    \'ack.vim' : 'https://github.com/mileszs/ack.vim.git',
    \'lightline.vim' : 'https://github.com/itchyny/lightline.vim.git',
    \'molokai' : 'https://github.com/tomasr/molokai.git',
    \'vaffle.vim' : 'https://github.com/cocopon/vaffle.vim.git',
    \'vim-gitgutter' : 'https://github.com/airblade/vim-gitgutter.git',
    ".....
    \}

if executable('git')
    let pluginNames = keys(PLUGIN_LIST)
    let dirList = split(expand(PLUGIN_PATH . '*'), '\n')
    for d in dirList
        if match(pluginNames, fnamemodify(d, ':t')) == -1
            call delete(expand(d), 'rf')
            echo 'Delete ' . fnamemodify(d, ':t')
        endif
    endfor

    for i in pluginNames
        let clonePath = PLUGIN_PATH . i
        if isdirectory(clonePath)
            continue
        endif
        call system('git ' . 'clone ' . PLUGIN_LIST[i] . ' ' . clonePath)
        if v:shell_error == 0
            echo i . ' OK'
        else
            echo i . ' Error...'
        endif
    endfor
else
    echo 'Cannot find [git]...'
endif

解説

プラグインのパス設定

if has('win32')
    let PLUGIN_PATH = expand('~/vimfiles/pack/plugin/start/')
else
    let PLUGIN_PATH = expand('~/.vim/pack/plugin/start/')
endif

if !isdirectory(PLUGIN_PATH)
    call mkdir(PLUGIN_PATH, 'p')
endif

プラグインをダウンロードするディレクトリを設定します。
この場合デフォルトでプラグインとしてVimがロードするディレクトリを設定しています。
WindowsとLinuxではデフォルトのruntimepathが異なるので分岐。
そして、設定したディレクトリを作成(なければ)

プラグインのリストを設定

let PLUGIN_LIST = {
    \'ack.vim' : 'https://github.com/mileszs/ack.vim.git',
    \'lightline.vim' : 'https://github.com/itchyny/lightline.vim.git',
    \'molokai' : 'https://github.com/tomasr/molokai.git',
    \'vaffle.vim' : 'https://github.com/cocopon/vaffle.vim.git',
    \'vim-gitgutter' : 'https://github.com/airblade/vim-gitgutter.git',
    ".....
    \}

シンプルに、キー:プラグイン名、値:プラグインのGitURLの辞書ですね。

Gitの確認

if executable('git')
" ....
else
    echo 'Cannot find [git]...'
endif

Gitが必要なので確認。

リストにないプラグインの削除

    let pluginNames = keys(PLUGIN_LIST)
    let dirList = split(expand(PLUGIN_PATH . '*'), '\n')
    for d in dirList
        if match(pluginNames, fnamemodify(d, ':t')) == -1
            call delete(expand(d), 'rf')
            echo 'Delete ' . fnamemodify(d, ':t')
        endif
    endfor

ディレクトリの一覧とプラグインのリストを照らし合わせてリストに存在しないものは削除

プラグインの取得

    for i in pluginNames
        let clonePath = PLUGIN_PATH . i
        if isdirectory(clonePath)
            continue
        endif
        call system('git ' . 'clone ' . PLUGIN_LIST[i] . ' ' . clonePath)
        if v:shell_error == 0
            echo i . ' OK'
        else
            echo i . ' Error...'
        endif
    endfor

まだ、プラグインリストに存在していてクローンしていないものはクローンしてきます。
クローンの成功判定はGitコマンドのStatus codeを使用しています。

最後に

非常にシンプルな作りで痒い所に手が届く感じはあまりしませんが、私にとってはこれで十分なのです。。
vimscriptについてはまだまだ初心者なので、こんな書き方もできるよとか、ここおかしいよとか、こんなプラグイン管理の方が楽だよなどコメント貰えたら嬉しいです。