本文を読み飛ばす

ackをvimの外部grepで使う

一度に複数のソースファイルから特定のテキストパターンを検索するには ack を使うと便利。自分にとっての "find | xargs grep" イディオムに対する ack の最大のメリットは、特別なオプションを指定しなくともプログラミングに無関係なファイルを検索対象から除外してくれる点。これを vim の外部 grep 機能から呼び出して使う方法について備忘録。

(補足:vim 上での(内部|外部) grep は、vim を終了させることなく複数ファイルに対してパターン検索を行って、ヒット箇所を次々に開くことができる機能。詳しくは vim にて :h grep で確認のこと。)

vim で複数ファイルの一括検索を行う方法には大きく分けて内部 grep と外部 grep の 2 種類があり、外部 grep 機能の裏で実行されるコマンドラインは vim のオプション grepprg で変更できる。そして ack のコマンドラインオプションや出力フォーマットは grep とかなり共通化されている。なので、基本的には grep コマンドの代わりに ack を使うよう grepprg を設定すれば良い。たとえば .vimrc に次のような行を追加する:

set grepprg=ack\ -k

こう設定した状態で、たとえば vim で次を実行すると:

:grep getaddrinfo ./src

:grep の部分を grepprg の設定値に置き換えたコマンドライン、つまり次のコマンドラインが実行されるようになる:

ack -k getaddrinfo ./src

後はカスタマイズ前と同じように :cn(または :cp)で次(または前)の検索ヒット位置にジャンプしたり、:cw で一覧表示したりすれば良い。ちなみにヒット箇所一覧 (QuickFix ウィンドウ) はマウスでスクロールしたり、ダブルクリックでジャンプしたりすることもできる。キーボードでの操作に慣れていなかったり、忘れてしまった場合はマウス操作に逃げる(?)のも良いだろう。

ところで、上の例では ack のオプション -k を付けることで「ack に知られている (known) ファイル形式(拡張子)のテキストファイル」だけに検索対象を絞り込んでいる。そして -k を打ち消すオプションは ack に無いもよう。すると、まれに READMEHISTORY.md といった名前のテキストファイルも含めて検索したい場合もあるかもしれないとか、ターミナルで -k を付けずに ack を使うので検索対象が変わるのは気持ち悪い、などと心配してしまう人は(← 自分のことだ)、最初から grepprg には ack とだけ指定しておくが吉。そうした上で、外部 grep 実行時にフィルタリング系オプションを適宜指定する。たとえば次のようにして C/C++ のソース・ヘッダーファイルに限定してやる、など:

:grep --cc --cpp 'infinity'

検索対象のフィルタリングオプションについては -k だけでなく、上の例で使ったようなプログラミング言語を使った指定もできる(その言語でよく使われるソースファイルの拡張子のセットを対象に入れてくれる)。対応言語の一覧は ack --help-files で確認できる。