Vim のすゝめ

第7回 QuickFix

2013.04.24

「男は黙って Vim をフルスクリーン」、Vim 使いの「ブイ」(仮名)です。一部の方には人気(?)があるこの連載もついに 7 回目です。応援してくれている皆さんには感謝しています。今回のテーマは「QuickFix」です。Vim には QuickFix という機能がありますが、この機能こそ Vim が開発者のためのエディタである、ということを表しているのではないかと思います。

1 QuickFix

QuickFix とは、エラー結果や grep の結果が表示される専用のウインドウ領域のことです [1]。Visual Studio や Eclipse といった IDE に存在する、ビルド結果が表示されるウインドウによく似ています。ただし QuickFix はビルド結果専用というわけではなく、grep の結果の表示などにも使用されます。

QuickFix のメリットは、毎回 Vim を終了したりプログラムを切り替えなくてもビルドエラーの確認や grep の結果確認が可能ということです。普通、ソースコードの編集とビルド、grep による検索というのは開発中に何度も繰り返し行われるものです。ビルドするときや grep を行うときに Vim を終了する (または切り替える)コストというのは、かなり大きなものになります。さらに、もしコンパイルエラーがあったとして、コンパイラのエラー行からエラーのあったファイルと行番号を目視で参照するのは至難の技です。しかし、Vim を使用すれば Vim がエラーのある行や grep の結果を解析してくれるのでその手間を省くことができます。

2 :make と QuickFix

まずは :make におけるQuickFix の利用です。:make とは、Vim におけるビルドコマンドのことです。このコマンドを実行すると開いているソースファイルに対し、ファイルタイプに応じたビルド用コマンドが呼び出され [2]、結果が QuickFix に表示されます。

今回の題材としては、Vim のソースコードを使用します。

$ hg clone https://vim.googlecode.com/hg/ vim
$ cd vim; ./configure
$ vim src/eval.c

ソースコードにエラーがない場合で試してみましょう。”src/eval.c” を開いている状態で :make を実行します [3]。この make にはかなり時間がかかります。

エラーが出てこないと思いますが、さらに :copen を実行しましょう。メッセージが大量に表示されていますが、コンパイルエラーは表示されないはずです。

次にエラーがある場合で試します。”src/eval.c” の先頭付近にある #include 文を次のようにコメントアウトします。

/*#include "vim.h"*/

今度は大量のエラーが出力されるはずです。さらに、:copen を実行します。エラーを起こしたファイル名と行番号、エラーメッセージが一覧表示されます。ここで <Enter> キーを押します。エラーを起こした行に飛んだはずです。ちなみに、QuickFix ウインドウは :cclose で閉じることができます。

3 grep と QuickFix

Vim は Vim の中で grep を呼び出し、結果を QuickFix に表示する機能を備えています。grep というのはプログラム開発のなかで頻繁に利用するコマンドです。この機能を利用すれば、わざわざ grep の結果を参照するためだけに Vim を終了したり、シェルに切り替えるといった作業をしなくて済みます。

Vim の grep には、内部 grep と外部 grep の二種類があります。内部 grep は Vim 7.0 以降で追加された Vim 自身が行う grep です。日本語の文字コードも正しく認識することができます。ただし、対象ファイルを全て Vim のバッファに読み込むので、対象ファイルが多い場合にはとても遅いです。文字コードが混在していて、外部grep ではうまく認識されない場合や grep が標準ではインストールされていない環境(Windows) では内部 grep を使用するのがよいでしょう。外部 grepは、外部コマンドの grep を用いる grep です。シェルで実行するときのgrep とほぼ同等の結果を得ることができます。ただし、当然外部コマンドのgrep が必要です。マルチバイトを検索するためには、使用する grep がマルチバイトに対応している必要があります。

まず、内部 grep について解説します。内部 grep には、:vimgrep というコマンドを用います。下記のコマンドを実行してみましょう。

:vimgrep /vim *.vim

:vimgrep のコマンドは、:vimgrep /{pattern}/{flag} {file} ... という構文になっています。{pattern} とは、検索するパターンのことで、上記の例では “vim” です。{flag} は検索時の動作を制御します。今回は {flag} は省略されているのでありません。{file} の部分には、検索対象のファイルを複数指定できます。今回の例のように、ワイルドカードも使用することができます。:vimgrep の実行後は、:copen コマンドを実行すると、検索結果の一覧を見ることができます。

:vimgrep コマンドでは、{flag} を省略した場合に最初の検索結果にジャンプしてしまいます。:make のときならともかく、:vimgrep の場合はこの仕様は邪魔になる場合が多いと思います。このジャンプを無効にする場合は、次のようにコマンドを実行します。

:vimgrep /vim/j *.vim

今回は “j” フラグを指定しており、最初にマッチした位置にジャンプ しな い という意味になります。いちいち “j” フラグを付けるのが面倒な場合、:vimgrep をラップした新たなコマンドを定義すると良いでしょう。

次に、外部 grep について解説します。外部 grep には、:grep というコマンドを用います。下記のコマンドを実行してみましょう。

:silent grep! vim *.vim

:grep のコマンドは、:grep {pattern} {file}... という構文になっています。引数は、シェルから呼び出す grep と同じです。:grep の代わりに :grep! を使用することで [4]、最初に見つかった行に自動的に移動しないようになります。:grep の実行後は、:copen コマンドを実行すると、検索結果の一覧を見ることができます。

:grep で使用する grep コマンドは、”grepprg” オプションで変更することができます。grep の引数の空白をエスケープすることに注意してください。

set grepprg=grep\ -nH

次のように、”grepprg” オプションの値を “internal” とすると、:grep:vimgrep と同じになります。

set grepprg=internal

次回は「テキストオブジェクト」について解説する予定です。

[1]Vim には QuickFixの他にロケーションリストというものもあり、QuickFix はグローバル(ひとつの Vim でひとつのみ)ですが、ロケーションリストはウインドウ毎に用意されています。
[2]今回の例では C 言語なので、”Makefile” がディレクトリ内に存在すれば動作します。しかし、ファイルタイプによっては、手動でビルド用のコマンドを指定しなければなりません。ビルド用のコマンドを指定するには、:compiler {コンパイラ名} というコマンドを使用します。詳しくは、:help compiler を参照してください。
[3]コマンドの出力が邪魔な場合、:make の代わりに :silent make を使用すると良いでしょう。
[4]grep コマンドに限らず、Vim の場合はコマンド名の最後に ! (bang) を付加すると、元々の挙動を微妙に変えるようになっています。バッファをファイルに保存しなくても Vim を終了させる、:quit! コマンドが代表的です。
This article is made by Vim.

著者プロフィール

v

ブイ。社内では数少ない Vim 使い。ブログ記事の執筆により、社内でのVim の知名度を上げ、Vim を使用する人を増やそうと計画しているらしい。

記事一覧Index