errorformatについて(入門編)


この記事は[Vim Advent Calendar 2012][1] : ATND 348日目の記事になります。

昨日は@manga_osyoさんの[quickrun.vim でリアルタイムに出力を行う場合の注意][2]でした。
今回は`&errorformat`について説明したいと思います。
この記事では`&errorformat`をどういうふうに設定すればよいのかを説明するつもりです。
`&errorformat`がどんな時に使われるか全く検討のつかない方はQuickfixや:makeについて
調べてから読むことをおすすめします。
また、ここで説明することは`:help error-file-format`にすべて載っています。


# 前準備

`&errorformat`をいろいろと試してみるにあたり、まずは`&errorformat`のテスト環境をまず作りましょう。

```vim:
function! TestErrFmt(errfmt,lines)
  let temp_errorfomat = &errorformat
  try
    let &errorformat = a:errfmt
    cexpr join(a:lines,"\n")
    copen
  catch
    echo v:exception
    echo v:throwpoint
  finally
    let &errorformat = temp_errorfomat
  endtry
endfunction
```

これは以下のような感じで使います。

> :call TestErrFmt('(%l\,%c):%m',['(1,2): abc','(13,27): xyz','hoge'])

__Quickfixの出力結果__

```
|1 col 2| abc
|13 col 27| xyz
|| hoge
```

簡単にこのTestErrFmt関数を説明すると、これは引数に「&errorformat文字列」と「解析する文字列」を指定し、
その結果をQuickfixに出力する関数です。

行っていることは以下のような感じです。`:cexpr`便利ですね！

1. `temp_errorfomat`に現在の`&errorformat`を退避しておく。
2. `&errorformat`を設定する。
3. `:cexpr`でTestErrFmt関数に渡された引数をもとにQuickfixを作成する。
4. `:copen`でQuickfixを開く。
5. `&errorformat`を元に戻す。


# &errorformatの書式

## カンマ(`,`)

`&errorformat`とは複数のパターンというものをカンマ(`,`)で区切ってある文字列のことです。

> let &errorformat = 'File %f,(%l\,%c):%m'
> set errorformat=File\ %f,(%l\\\\,%c):%m

カンマ(`,`)がパターンに含まれている場合には`\`でエスケープしなければなりません。
個人的にletのほうがエスケープがめんどくないので好みです。


## 基本要素

`&errorformat`のパターンは`%X`のように%でエスケープされた特殊文字と単なる文字(例えば`A`とか)で
構成させています。


### 1.主な特殊文字

* `%f`: ファイルパスにマッチする文字列。各文字は`&isfname`に含まれていなければなりません。
* `%l`: 行番号。単なる数字にマッチします。
* `%c`: 桁番号。単なる数字にマッチします。
* `%m`: エラーメッセージ。正規表現でいうところの/.*/です。

上記の特殊文字はそれぞれ`%f|%l col %c| %m`の形式でQuickfixの表示される部分に当たります。


### 2.正規表現のように扱われる特殊文字

* `%\`: 単体の '\' という文字。
* `%.`: 単体の '.' という文字。
* `%#`: 単体の '*' という文字。
* `%[`: 単体の '[' という文字。文字の範囲[]のために使われる。
* `%~`: 単体の '~' という文字。

上記の特殊文字は正規表現のアトムと全く同じ扱われ方をします。


### 3.便利な特殊文字

* `%-G`: このメッセージを無視する。これを付けるとそのパターンはQuickfixに表示されなくなります。
* `%A`: 複数行メッセージの開始。
* `%C`: 複数行メッセージの継続。
* `%Z`: 複数行メッセージの終了。

上記の特殊文字は基本的にパターンの先頭に置きます。
それぞれ、単体では何もマッチしませんので他のものと一緒に使用します。


## パターンマッチ

パターンマッチは行単位で行われ、`&errorformat`の先頭から順にそれぞれのパターンと
パターンマッチが行われます。
どれにもマッチしなかった場合には、単なるメッセージとしてQuickfixに表示されます。


# &errorformatの使用例

まぁ簡単にまとめてみましたが、日本語で説明するのは難しいので、
先ほどのTestErrFmt関数を使っていくつか例をあげて終わりにしたいと思います。

----------------------------------------------------------------------------------

### 1. `TestErrFmt('$%m,%-G%.%#',['$hoge','$foo','piyo'])`

__Quickfixの出力結果__

```
|| hoge
|| foo
```

どれにもマッチしなかった場合には、単なるメッセージとしてQuickfixに表示されるので、
最後に'%-G%.%#'のパターンをつけておくと、'%.%#'によって0文字以上の任意の文字にマッチし、
'%-G'によってQuickfixに表示されなくなるので余計な出力を消せてすごく便利です。
また、'%m'にマッチした部分しか表示されないので'$'の部分は表示されません。

----------------------------------------------------------------------------------

### 2. `TestErrFmt('(%l\,%c):%m',['(1,2): abc','(13,27): xyz','hoge'])`

__Quickfixの出力結果__

```
|1 col 2| abc
|13 col 27| xyz
|| hoge
```

最後の'hoge'はどれにもマッチしなかったので単なるメッセージとしてQuickfixに表示されています。

----------------------------------------------------------------------------------

### 3. `TestErrFmt('%A[%f],%C%l\,%c,%Z%m',['[~/.vimrc]','12,5','hoge'])`

__Quickfixの出力結果__

```
.vimrc|12 col 5|  hoge
```

'%A'と'%C'と'%Z'を一緒に使うことで複数行を１つの出力として扱うことができます。


----------------------------------------------------------------------------------

### 4. `TestErrFmt('%.%m',['hoge','foo','piyo'])`

__Quickfixの出力結果__

```
|| oge
|| oo
|| iyo
```

'%.'は正規表現でいう/./に当たるので出力はそれに１文字消費されてしまいます。

----------------------------------------------------------------------------------

### 5. `TestErrFmt('%[a-i]%m',['hoge','foo','piyo'])`

__Quickfixの出力結果__

```
|| oge
|| oo
|| piyo
```

'%[a-i]'は正規表現でいう/[a-i]/に当たるので、hogeのhとfooのfは消費されてしまいます。


# 終わり

以上、「errorformatについて(入門編)」でした。
これがすべてではないので、詳しくは`:help error-file-format`を参照してください。
Vim Advent Calendar 2012もあと16日ですね。明日は@unmoremasterさんっぽいです。

[1]: http://atnd.org/events/33746
[2]: http://d.hatena.ne.jp/osyo-manga/20131112/1384255703