Vimとボクと、ときどき、PHP

Vim好きなエンジニア(主にPHP開発)が不定期に技術情報やネタを書いていくブログです

Home » dein.vimで未使用プラグインを削除するコマンドを定義する

dein.vimで未使用プラグインを削除するコマンドを定義する

久々にVimの話題です。

Vimのプラグイン管理に、以前はNeoBundleを使っていましたが、作者のShougo氏により、次のバージョンであるdeinがリリースされましたので、乗り換えました。そのコンセプト通り、非常に高速で快適です。
乗り換え手順などは様々な方が紹介されているので割愛し、今回は「deinでインストールしたプラグインで使わなくなったものをアンインストールする」という機能を実装してみようと思います。

最初にお断りしておりますが、「deinにプラグインアンインストール機能を追加実装してPRを投げる」というわけではありません

経緯など

ずいぶん前のことになりますが、NeoBundleにはもともとNeoBundleCleanというコマンドが実装されておりました。使ってないプラグインを削除する機能です。
しかしいつの頃からか、このコマンドが姿を消しました。Shougo氏曰く、「危険だから消しました」(意訳)だそうです。記憶を頼りにもう少し詳しく書くなら、「依存関係が壊れたりする可能性があるので危険」だったような・・・。
しかし、個人的にこのコマンドを結構使っておりましたので、残念に思っていました。

あるとき、何となくdeinのヘルプを見ておりましたら、QAで

Q: How to remove the disabled plugins?

A: You can get them by |dein#check_clean()|.
So you can remove them like below.
>
        call map(dein#check_clean(), “delete(v:val, ‘rf’)”)
<

このように書かれておりまして。これは「危険な処理だから機能として実装はしないけど、こうすれば自分でやれるからどうぞ」という意味ですよね。

というわけで、NeoBundleCleanのdein版、DeinCleanコマンドを実装してみようじゃないかと。deinのコンセプトに従うならコマンドではなく関数で実装すべきなのですが、個人使用ですし良しとしましょう。

前提条件

既にdeinでプラグインを管理していることを前提とします。deinとは何かとか、導入方法、設定方法などは書きません。
また、作者のShougo氏が「自分でやってね」と言っている以上、dein自体にDeinCleanコマンドを追加実装するという選択はありえません。vimrc上に個人使用向けで実装します。ですので、自己責任でお願いします。

方針

まず、削除対象のプラグインのディレクトリを取得する必要があるわけですが、それはヘルプにあるように、dein#check_clean()で取得できます。取得できたら、それを全部削除しちゃうだけですね。
しかしそれだけでは少々使い勝手が悪いことがあります。例えば、

  1. VimとNeovimを共存させていて、設定を共有している
  2. 何かの理由で一時的に無効化しているプラグインがあるが、消したくはない

というような場合です。1の場合に何が問題になるかというと、「Neovimでは動かないプラグインがあるのでVimのときだけ有効になるよう設定している」という場合に、NeovimでDeinCleanをやって消えてしまうと、Vimを使うときに毎回再インストールすることになってしまいます。逆も然り。
いい例はneocompletedeopleteですね。両方とも入力補完のプラグインで、前者はVim用、後者はNeovim用です。共存している場合は常にどちらか一方を無効にするわけですが、どちらか一方でDeinCleanを実行するともう一方のプラグインが消えるようでは、ちょっと都合が悪い。

そこで、下記のような仕様で実装したいと思います。

  • 削除対象のプラグイン1つ1つについて、削除していいか確認する。yが入力されたら削除する。aが入力されたら、以降は確認せずに全部消す。<ESC>や<C-c>だったら処理を中断する。それ以外の入力(何も入力せずEnterなど)の場合は削除しない。(もしかしたらNeoBundleCleanもこんな仕様になってたかも)
  • 問答無用で全削除したい時もあると思うので、DeinClean!も許可することにして、!が付いていたら確認無しで全削除とする。
  • 実装は1つのファイルに切り出して、vimrcでsourceしてやる。(私はvimrcを複数ファイルに分けて管理しているのでこうしましたが、vimrcにそのまま記述しても全く問題ないです)

実装

まず、DeinCleanコマンドの実装から。~/.vim/rc/plugins/dein.rc.vimというファイルを作って、そこに記述することにします。

やってることは方針で書いたそのままです。
ただ、「削除していいか確認」するという部分で、Vim標準のinput関数を使うと<ESC>と<CR>(Enter)が区別できないため、このページを参考(というか丸パクり)にしてラッパー関数を定義しています。入力がyかaかの判定は、大文字小文字の違いを無視して、「y/ye/yes なら y」「a/al/all なら a」と判定されるようにしています。

プラグインディレクトリの削除は、Linuxの場合はsystem('rm -fr /path/to/dir')、Windowsの場合はsystem('rmdir /S /Q /path/to/dir')になるわけですが、プラットフォーム判定など細かくやろうとすると地味に面倒です。
さてどうしようかと考えているとき、ふと思い付いたのが「dein#reinstall()とかいう関数があったなぁ」でした。プラグインを再インストールするということは、いったんそのディレクトリを削除してから、再度git cloneし直しているのではないか。ディレクトリを削除する必要があるのだから、Shougo氏ならそういうユーティリティ関数を定義しているのではないか。そんな期待をしつつdein#reinstall()の実装を見てみたところ、案の定でした。というか、Vimのバージョンが新しければdelete('/path/to/dir', 'rf')でいけるんですね・・・だからヘルプの例もそうなってたのか・・・。
まぁしかし、常に新しいVimを使えるとは限りませんので、ディレクトリの削除にはdein#install#_rm()を使わせていただくことにしました。deinが有効なの前提で作ってますので、関数が存在するかの判定はしてません。

あとはこのファイルをvimrcからsourceしてやればいいです。
私はdeinにプラグインを追加するのにTOMLファイルを使っておりますので、以下のようにしてみました。

dein#add()を使っている方は・・・こんな感じでいいのかな?(間違ってたら教えてください)

もしくは、vimrcの適当な場所で

source ~/.vim/rc/plugins/dein.rc.vim

だけ書いてもいいです。

まとめ

とりあえずこれで、DeinCleanを実装することはできました。ただ、個人的にはまだ不満です。
正直、「TOMLファイル内に記述されていれば(たとえ無効と設定されていても)残す」という仕様にすればいいのではないかと思い始めました。そうすれば、いちいち「削除していいですか?」と聞かなくてもよくなるはずです。そのうち、このように改良すると思います。

Name of author

Name: よーすけ

Short Bio:

主にPHP開発をやってる社内PGです。

コメントを残す

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