Vim のコマンドラインで find & grep して :cn とか :cp できるようにしたよ

Vim には :grep コマンドがあります。 grep の結果を QuickFix リストに突っ込んで、 :cope コマンドでマッチ箇所を一覧したり :cn で次に飛んだり :cp で前に飛んだりできます。便利便利。 src ディレクトリの下を再帰的に grep するなら、こんな感じ。

:grep '\<parseInt\>' src -R

ただ -R オプションを使うと、 src の下に変な .xml とか .svn とかがあった場合、全部マッチしてしまうので困ることがあります。 .java だけ引っ掛けたかったりする。こんな時、シェルからであれば

find src -name '*.java' | xargs grep -Hn '\<parseInt\>'

するんだけど、 Vimコマンドラインからこれが打てない。

代替案として、 Vim 組み込みの grep である :vimgrep コマンドを使う手があります。こんな感じ。

:vim '\<parseInt\>' src/**/*.java

これのいいところは、どんな環境でも、 Windows でも、 Vim さえあれば使えるということ。それから、 Vim のバッファに一度ファイルを読み込んでから検索するので、文字コード自動検知を仕込んでおけば、日本語がバッチリ検索できることも嬉しい点です。難点は、 Vim のバッファに読み込むために、相当遅いことです。 *1

もうひとつの代替案として、 ack っていう Perl で書かれた grep 代替のツールを使う手があります。こいつは、引っ掛ける拡張子をコマンドラインオプションで指定できます。なので、 .vimrc で

" .vimrc
set grepprg=ack\ -a

とかやっとけば

:grep --java '\bparseInt\b' src

で行ける。行けるんだけど、見ての通り正規表現の文法が Perl なので、慣れてない僕には書きづらい。ちょっと遅いしね。それに、単に find & grep したいだけなのに新しいツールを入れるのは癪に障ります。とか言って長年ぶーたれてたんだけど、一念発起して vim から find & grep できるようにしました。こいつを .vimrc にぶっこみます。

あとは

:Grep find src -name '*.java' | xargs grep -Hn '\<parseInt\>'

で 行けます。 xargs を使いたくなければ

:Grep find src -name '*.java' -exec grep -Hn '\<parseInt\>' {} +

でも行けます。というか grep -n 形式で出力するコマンドなら find & grep に限らず OK です。たとえばこんな感じ。

:Grep <files.txt xargs grep -Hn '\<parseInt\>' 

また、標準の :grep コマンドはそのまんま使えます。便利便利。

*2

*1:id:kenichiice さんの指摘により追記しました。ありがとうございます。

*2:記事を通じて、 grep コマンドのオプションを -n としていましたが、これだとファイルが一つの時にうまくいかないので、 -Hn に修正しました。