[インデックス 13268] ファイルの概要
このコミットは、Emacsのcompilation-mode
がGo言語のテスト失敗出力を正しく解釈し、next-error
機能で該当するエラー箇所へジャンプできるようにするための改善です。具体的には、go-mode.el
ファイルにEmacsのcompilation-error-regexp-alist
およびcompilation-error-regexp-alist-alist
にGoテストの失敗パターンを認識させるための正規表現を追加しています。
コミット
commit 062b6094139edb8345c2f6ba82f8fe129ccaaf62
Author: Ryan Barrett <ryanb@google.com>
Date: Mon Jun 4 10:36:24 2012 -0400
misc/emacs: make compilation-mode's next-error understand test failure output.
specifically, adds a go-test element to compilation-error-regexp-alist[-alist].
Fixes #3629.
R=golang-dev, rsc, sameer
CC=golang-dev, jba
https://golang.org/cl/6197091
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/062b6094139edb8345c2f6ba82f8fe129ccaaf62
元コミット内容
misc/emacs: make compilation-mode's next-error understand test failure output.
specifically, adds a go-test element to compilation-error-regexp-alist[-alist].
Fixes #3629.
変更の背景
この変更は、Go言語のテスト実行結果がEmacsのcompilation-mode
で適切に扱われないという問題(Issue 3629)を解決するために行われました。Goのテストフレームワークは、テストが失敗した場合に特定の形式でファイル名と行番号を含むエラーメッセージを出力します。しかし、Emacsの標準的なcompilation-mode
は、このGo特有の出力形式を認識できませんでした。
その結果、開発者はEmacs内でgo test
を実行し、テストが失敗した場合にnext-error
コマンド(通常は`C-x ``にバインドされている)を使用しても、エラーが発生したソースコードの正確な位置にジャンプすることができませんでした。これは、テスト駆動開発(TDD)やデバッグのワークフローにおいて、大きな生産性の低下を招きます。
このコミットは、Emacsのgo-mode.el
にGoテストの失敗出力を解析するための正規表現ルールを追加することで、この問題を解決し、開発者がEmacs内でよりスムーズにGoのテスト結果を扱えるようにすることを目的としています。
前提知識の解説
Emacsのcompilation-mode
とnext-error
Emacsのcompilation-mode
は、コンパイラやリンカ、テストランナーなどの外部プログラムの出力を表示するための特殊なメジャーモードです。このモードの主な利点は、出力に含まれるエラーメッセージや警告を解析し、それらが参照するソースコードの該当箇所へ直接ジャンプできる機能を提供することです。
このジャンプ機能は主にnext-error
コマンドによって提供されます。next-error
は、compilation-mode
のバッファ内で正規表現(compilation-error-regexp-alist
に定義されている)にマッチするエラー行を見つけ、その行からファイル名と行番号を抽出し、対応するソースファイルを開いてカーソルをその行に移動させます。
compilation-error-regexp-alist
とcompilation-error-regexp-alist-alist
Emacsがエラーメッセージを解析するために使用する正規表現は、compilation-error-regexp-alist
という変数にリストとして格納されています。このリストの各要素は、エラーメッセージのパターンと、そのパターンからファイル名、行番号、列番号などを抽出するためのグループ指定(サブマッチ)を定義します。
さらに、compilation-error-regexp-alist-alist
という変数も存在します。これは、compilation-error-regexp-alist
の各要素が参照する、より詳細な正規表現定義のリストです。compilation-error-regexp-alist
の各要素はシンボル(例: go-test
)を参照し、そのシンボルに対応する実際の正規表現とグループ指定がcompilation-error-regexp-alist-alist
に定義されます。
Emacsは、compilation-mode
のバッファを解析する際に、これらのリストを逆順に(つまり、リストの最後に追加されたものから)走査し、最初に見つかったマッチングパターンを使用してエラー情報を抽出します。この走査順序は、特定の言語やツールに特化した正規表現が、より一般的な正規表現よりも優先されるようにするために重要です。
Go言語のテスト出力形式
Go言語の標準的なテストフレームワーク(go test
コマンド)は、テストが失敗した場合に以下のような形式でエラーメッセージを出力します。
--- FAIL: TestSomething (0.00s)
path/to/file.go:123: Error message here
FAIL
重要なのは、path/to/file.go:123:
の部分で、これがファイル名と行番号を示しています。compilation-mode
がこの形式を認識できるように、適切な正規表現を定義する必要があります。
技術的詳細
このコミットの技術的な核心は、Go言語のテスト失敗出力形式に特化した正規表現をEmacsのcompilation-mode
に登録することです。
Goのテスト失敗出力は、通常タブでインデントされた行にファイル名と行番号が含まれます。例えば:
/path/to/your_test.go:42: Error message
このパターンを認識するために、以下の正規表現が定義されています。
"^\\t+\\\\([^()\\t\\n]+\\\\):\\\\([0-9]+\\\\):? .*$"
この正規表現を分解すると以下のようになります。
^
: 行の先頭にマッチ。\\t+
: 1つ以上のタブ文字にマッチ。Goのテスト出力では、失敗したテストのファイル/行情報は通常タブでインデントされます。\\\\([^()\\t\\n]+\\\\)
: 最初のキャプチャグループ。\\(
と\\)
: キャプチャグループの開始と終了。Emacs Lispの文字列リテラル内で正規表現の括弧をエスケープするためにバックスラッシュが二重になっています。[^()\\t\\n]+
: 括弧、タブ、改行以外の任意の文字が1回以上繰り返される部分にマッチ。これはファイルパス(例:/home/user/project/test.go
)をキャプチャします。
:
: ファイルパスと行番号の間のコロンにマッチ。\\\\([0-9]+\\\\)
: 2番目のキャプチャグループ。[0-9]+
: 1つ以上の数字にマッチ。これは行番号(例:42
)をキャプチャします。
:?
: オプションのコロンにマッチ。行番号の後にコロンが続く場合と続かない場合の両方に対応します。.*
: 残りの任意の文字(エラーメッセージなど)にマッチ。$
: 行の末尾にマッチ。
この正規表現は、Goテストの出力からファイルパスを1番目のグループ(\1
)として、行番号を2番目のグループ(\2
)として抽出するように設計されています。
この正規表現は、go-mode.el
の初期化時にcompilation-error-regexp-alist
とcompilation-error-regexp-alist-alist
に追加されます。add-to-list
関数が使用され、最後の引数にt
が指定されているため、これらの要素はリストの末尾に追加されます。Emacsはこれらのリストを逆順に走査するため、go-test
の正規表現が他の一般的な正規表現よりも優先的に評価されることになります。これにより、Goテストの出力が正しく解析されることが保証されます。
コアとなるコードの変更箇所
misc/emacs/go-mode.el
ファイルの以下の部分が変更されました。
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -729,7 +729,20 @@ functions, and some types. It also provides indentation that is
(set (make-local-variable 'comment-end) ""))
;; Go style
- (setq indent-tabs-mode t))\n
+ (setq indent-tabs-mode t)\n
+
+ ;; Handle unit test failure output in compilation-mode
+ ;;\n
+ ;; Note the final t argument to add-to-list for append, ie put these at the
+ ;; *ends* of compilation-error-regexp-alist[-alist]. We want go-test to be
+ ;; handled first, otherwise other elements will match that don't work, and
+ ;; those alists are traversed in *reverse* order:\n
+ ;; http://lists.gnu.org/archive/html/bug-gnu-emacs/2001-12/msg00674.html\n
+ (when (and (boundp 'compilation-error-regexp-alist)\n
+ (boundp 'compilation-error-regexp-alist-alist))\n
+ (add-to-list 'compilation-error-regexp-alist 'go-test t)\n
+ (add-to-list 'compilation-error-regexp-alist-alist\n
+ '(go-test . ("^\\t+\\\\([^()\\t\\n]+\\\\):\\\\([0-9]+\\\\):? .*$" 1 2)) t)))\n
\n ;;;###autoload
(add-to-list 'auto-mode-alist (cons "\\\\.go$" #'go-mode))\n
コアとなるコードの解説
追加されたコードブロックは、go-mode
が有効になった際に実行されます。
;; Handle unit test failure output in compilation-mode
;;
;; Note the final t argument to add-to-list for append, ie put these at the
;; *ends* of compilation-error-regexp-alist[-alist]. We want go-test to be
;; handled first, otherwise other elements will match that don't work, and
;; those alists are traversed in *reverse* order:
;; http://lists.gnu.org/archive/html/bug-gnu-emacs/2001-12/msg00674.html
(when (and (boundp 'compilation-error-regexp-alist)
(boundp 'compilation-error-regexp-alist-alist))
(add-to-list 'compilation-error-regexp-alist 'go-test t)
(add-to-list 'compilation-error-regexp-alist-alist
'(go-test . ("^\\t+\\\\([^()\\t\\n]+\\\\):\\\\([0-9]+\\\\):? .*$" 1 2)) t)))
-
(when (and (boundp 'compilation-error-regexp-alist) (boundp 'compilation-error-regexp-alist-alist)))
- この行は、
compilation-error-regexp-alist
とcompilation-error-regexp-alist-alist
という変数がEmacsの環境で定義されているかどうかを確認しています。これらの変数はEmacsのバージョンや設定によっては存在しない可能性があるため、安全のためにチェックを行っています。
- この行は、
-
(add-to-list 'compilation-error-regexp-alist 'go-test t)
- この行は、シンボル
go-test
をcompilation-error-regexp-alist
リストの末尾に追加します。 t
という最後の引数は、go-test
がリストの末尾に追加されることを意味します(append
)。前述の通り、Emacsはこれらのリストを逆順に走査するため、末尾に追加された要素が最初に評価されます。これにより、Goテストの正規表現が他の一般的な正規表現よりも優先されるようになります。
- この行は、シンボル
-
(add-to-list 'compilation-error-regexp-alist-alist '(go-test . ("^\\t+\\\\([^()\\t\\n]+\\\\):\\\\([0-9]+\\\\):? .*$" 1 2)) t)
- この行は、
go-test
シンボルに対応する実際の正規表現定義をcompilation-error-regexp-alist-alist
リストの末尾に追加します。 '(go-test . ("^\\t+\\\\([^()\\t\\n]+\\\\):\\\\([0-9]+\\\\):? .*$" 1 2))
は、アソシエーションリスト(alist)の要素です。go-test
: キーとなるシンボル。"^\\t+\\\\([^()\\t\\n]+\\\\):\\\\([0-9]+\\\\):? .*$"
: Goテストの失敗出力にマッチするための正規表現文字列。1
: 正規表現の1番目のキャプチャグループ(\1
)がファイル名に対応することを示します。2
: 正規表現の2番目のキャプチャグループ(\2
)が行番号に対応することを示します。
- ここでも
t
が最後の引数として指定されており、この定義がリストの末尾に追加され、優先的に評価されるようにしています。
- この行は、
この変更により、Emacsのcompilation-mode
はGoのテスト失敗出力を正確に解析し、開発者がnext-error
コマンドを使ってエラー箇所に迅速に移動できるようになります。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/062b6094139edb8345c2f6ba82f8fe129ccaaf62
- Go CL (Code Review): https://golang.org/cl/6197091
- Go Issue 3629: https://github.com/golang/go/issues/3629
参考にした情報源リンク
- GNU Emacs Manual: Compilation Mode: https://www.gnu.org/software/emacs/manual/html_node/emacs/Compilation-Mode.html
- GNU Emacs Manual: Regular Expressions: https://www.gnu.org/software/emacs/manual/html_node/elisp/Regexp-Syntax.html
- Emacs Lisp Reference Manual:
add-to-list
: https://www.gnu.org/software/emacs/manual/html_node/elisp/List-Functions.html#index-add-to-list - Emacs Lisp Reference Manual:
boundp
: https://www.gnu.org/software/emacs/manual/html_node/elisp/Variable-Access.html#index-boundp - bug-gnu-emacsメーリングリストアーカイブ (2001-12):
compilation-error-regexp-alist
の走査順序に関する議論: http://lists.gnu.org/archive/html/bug-gnu-emacs/2001-12/msg00674.html