Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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-modenext-error

Emacsのcompilation-modeは、コンパイラやリンカ、テストランナーなどの外部プログラムの出力を表示するための特殊なメジャーモードです。このモードの主な利点は、出力に含まれるエラーメッセージや警告を解析し、それらが参照するソースコードの該当箇所へ直接ジャンプできる機能を提供することです。

このジャンプ機能は主にnext-errorコマンドによって提供されます。next-errorは、compilation-modeのバッファ内で正規表現(compilation-error-regexp-alistに定義されている)にマッチするエラー行を見つけ、その行からファイル名と行番号を抽出し、対応するソースファイルを開いてカーソルをその行に移動させます。

compilation-error-regexp-alistcompilation-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-alistcompilation-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)))
  1. (when (and (boundp 'compilation-error-regexp-alist) (boundp 'compilation-error-regexp-alist-alist)))

    • この行は、compilation-error-regexp-alistcompilation-error-regexp-alist-alistという変数がEmacsの環境で定義されているかどうかを確認しています。これらの変数はEmacsのバージョンや設定によっては存在しない可能性があるため、安全のためにチェックを行っています。
  2. (add-to-list 'compilation-error-regexp-alist 'go-test t)

    • この行は、シンボルgo-testcompilation-error-regexp-alistリストの末尾に追加します。
    • tという最後の引数は、go-testがリストの末尾に追加されることを意味します(append)。前述の通り、Emacsはこれらのリストを逆順に走査するため、末尾に追加された要素が最初に評価されます。これにより、Goテストの正規表現が他の一般的な正規表現よりも優先されるようになります。
  3. (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コマンドを使ってエラー箇所に迅速に移動できるようになります。

関連リンク

参考にした情報源リンク