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

[インデックス 18561] ファイルの概要

このコミットは、EmacsのGo言語メジャーモードであるgo-mode.elに、ff-find-other-file機能のサポートを追加するものです。go-mode.elは、EmacsでGo言語のコードを編集する際に、シンタックスハイライト、インデント、コード補完などの機能を提供するLispファイルです。この変更により、Goのソースファイル(.go)とそれに対応するテストファイル(_test.go)間を簡単に切り替えることができるようになります。

コミット

commit cce25c88ce96a8c6cc0af212bcd9f75bf9d3fb86
Author: Dominik Honnef <dominik.honnef@gmail.com>
Date:   Tue Feb 18 22:23:55 2014 -0500

    misc/emacs: add support for ff-find-other-file
    
    c-mode classically uses ff-find-other-file to toggle between headers
    and implementation. For Go it seemingly makes sense to jump between
    implementation and test.
    
    While there's no enforced mapping of file names for tests, the mapping
    in this CL seems to be very common at least throughout the standard
    library, and ff-find-other-file fails gracefully when the mapping
    doesn't apply.
    
    LGTM=adonovan
    R=adonovan
    CC=golang-codereviews
    https://golang.org/cl/65750044

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/cce25c88ce96a8c6cc0af212bcd9f75bf9d3fb86

元コミット内容

misc/emacs: add support for ff-find-other-file
    
c-mode classically uses ff-find-other-file to toggle between headers
and implementation. For Go it seemingly makes sense to jump between
implementation and test.

While there's no enforced mapping of file names for tests, the mapping
in this CL seems to be very common at least throughout the standard
library, and ff-find-other-file fails gracefully when the mapping
doesn't apply.

LGTM=adonovan
R=adonovan
CC=golang-codereviews
https://golang.org/cl/65750044

変更の背景

Emacsのユーザーは、関連するファイルを素早く切り替えるための効率的なワークフローを重視します。特に、C言語のプログラミングでは、ヘッダーファイル(.h)と実装ファイル(.c.cpp)の間をff-find-other-fileコマンドを使って頻繁に切り替えるのが一般的です。

Go言語においても、同様のニーズが存在します。Goのプロジェクトでは、通常、ソースコードファイル(例: foo.go)とそれに対応するテストファイル(例: foo_test.go)がペアで存在します。開発者は、実装とテストの間を行き来しながら作業することが多いため、この切り替えを効率化することが求められていました。

このコミットは、EmacsのGoモードにおいて、C言語モードと同様の「関連ファイル切り替え」の利便性を提供することを目的としています。Goのテストファイルの命名規則は厳密に強制されているわけではありませんが、標準ライブラリ全体で_test.goという命名パターンが非常に一般的であるため、このパターンをff-find-other-fileに適用することで、多くのGo開発者にとって有用な機能となると判断されました。また、このマッピングが適用されない場合でも、ff-find-other-fileは適切に失敗するため、既存のワークフローを妨げることはありません。

前提知識の解説

Emacs

Emacsは、高度にカスタマイズ可能なテキストエディタであり、統合開発環境(IDE)としても機能します。Lisp言語(Emacs Lisp)で記述されており、ユーザーはLispコードを記述することで、エディタの動作を拡張・変更できます。

ff-find-other-file

ff-find-other-fileは、Emacsのfind-fileライブラリが提供するコマンドの一つです。このコマンドは、現在開いているファイルに関連する別のファイルを推測し、そのファイルを開くことを試みます。例えば、foo.cを開いているときにこのコマンドを実行すると、foo.hを開こうとします。どのファイルが「関連する」と見なされるかは、ff-other-file-alistという変数で定義されます。

c-mode

c-modeは、EmacsにおけるC、C++、Objective-Cなどの言語のためのメジャーモードです。これらの言語のコードを編集する際に、シンタックスハイライト、インデント、コメントの自動挿入などの機能を提供します。c-modeでは、伝統的にff-find-other-fileがヘッダーファイルと実装ファイルの切り替えに利用されてきました。

Goテストファイル命名規則

Go言語のテストファイルは、慣習としてテスト対象のファイル名に_test.goというサフィックスを付けて命名されます。例えば、foo.goのテストはfoo_test.goというファイルに記述されます。これにより、Goのツールチェーンはテストファイルを自動的に認識し、テストを実行することができます。この命名規則はGoの標準ライブラリ全体で広く採用されており、事実上の標準となっています。

go-mode.el

go-mode.elは、EmacsでGo言語のコードを編集するためのメジャーモードです。Go言語のシンタックスハイライト、自動インデント、コード補完、定義へのジャンプなど、Go開発に特化した機能を提供します。

技術的詳細

このコミットの核心は、Emacsのff-find-other-fileコマンドがGo言語のソースファイルとテストファイルの間を切り替えられるように、go-mode.elを設定することです。

ff-find-other-fileは、ff-other-file-alistというEmacs Lisp変数に定義されたルールに基づいて、関連ファイルを特定します。ff-other-file-alistは、正規表現と、それに対応するファイル名の変換ルール(文字列のリストまたは関数)のペアのリストです。

このコミットでは、以下の2つの主要な変更が行われています。

  1. find-fileライブラリの読み込み: ff-find-other-fileが利用できるように、find-fileライブラリをgo-mode.elrequire(読み込み)しています。
  2. go-other-file-alistの定義と設定:
    • go-other-file-alistという新しいカスタム変数が定義されます。この変数は、Goファイルに特化したff-other-file-alistのルールを保持します。
    • このリストには2つのルールが含まれています。
      • ("_test\\.go\\'" (".go")): ファイル名が_test.goで終わる場合(テストファイルの場合)、対応する.goファイル(実装ファイル)に切り替えることを意味します。
      • ("\\.go\\'" ("_test.go")): ファイル名が.goで終わる場合(実装ファイルの場合)、対応する_test.goファイル(テストファイル)に切り替えることを意味します。
    • go-modeがアクティブになった際に、ff-other-file-alist変数をこの新しく定義されたgo-other-file-alistに設定します。これにより、ff-find-other-fileコマンドがGoファイルに対して適切に動作するようになります。

この設定により、ユーザーがfoo.goを開いているときにff-find-other-fileを実行するとfoo_test.goに、foo_test.goを開いているときに実行するとfoo.goに切り替えることが可能になります。この機能は、Goの標準ライブラリで広く採用されている命名規則に依存しており、この規則に従わないファイル名の場合でも、ff-find-other-fileはエラーを発生させずに動作します。

コアとなるコードの変更箇所

--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -7,6 +7,7 @@
 (require 'cl)
 (require 'etags)
 (require 'ffap)
+(require 'find-file)
 (require 'ring)
 (require 'url)
 
@@ -168,6 +169,13 @@ from https://github.com/bradfitz/goimports.\"\n   :type 'string\n   :group 'go)\n \n+(defcustom go-other-file-alist\n+  '(("_test\\.go\\'" (".go"))\n+    ("\\.go\\'" ("_test.go")))\n+  \"See the documentation of `ff-other-file-alist' for details.\"\n+  :type '(repeat (list regexp (choice (repeat string) function)))\n+  :group 'go)\n+\n (defface go-coverage-untracked\n   '((t (:foreground "#505050")))\n   \"Coverage color of untracked code.\"\n@@ -561,6 +569,8 @@ recommended that you look at goflymake\n   (set (make-local-variable 'go-dangling-cache) (make-hash-table :test 'eql))\n   (add-hook 'before-change-functions (lambda (x y) (setq go-dangling-cache (make-hash-table :test 'eql))) t t)\n \n+  ;; ff-find-other-file\n+  (setq ff-other-file-alist 'go-other-file-alist)\n \n   (setq imenu-generic-expression\n         '(("type" "^type *\\([^ \t\n\r\f]*\\)" 1)\n```

## コアとなるコードの解説

### `(require 'find-file)`

この行は、Emacsの`find-file`ライブラリを`go-mode.el`に読み込むことを宣言しています。`ff-find-other-file`コマンドは、この`find-file`ライブラリの一部として提供されているため、この行がないと関連機能が利用できません。

### `(defcustom go-other-file-alist ...)`

これは、`go-other-file-alist`という新しいカスタム変数を定義しています。

*   **`defcustom`**: Emacs Lispでユーザーがカスタマイズ可能な変数を定義するためのマクロです。これにより、ユーザーはEmacsのカスタマイズインターフェース(`M-x customize`)を通じてこの変数の値を変更できるようになります。
*   **`go-other-file-alist`**: 変数名です。Goモードに特化した関連ファイルリストであることを示しています。
*   **`'(("_test\\.go\\'" (".go")) ("\\.go\\'" ("_test.go")))`**: この変数のデフォルト値です。これは、`ff-other-file-alist`の形式に従った連想リストです。
    *   `("_test\\.go\\'" (".go"))`: 最初の要素は、現在のファイル名が正規表現`_test\.go\'`(`_test.go`で終わるファイル)にマッチする場合のルールです。この場合、ファイル名のサフィックスを`.go`に変換して関連ファイルを検索します。
    *   `("\\.go\\'" ("_test.go"))`: 2番目の要素は、現在のファイル名が正規表現`\.go\'`(`.go`で終わるファイル)にマッチする場合のルールです。この場合、ファイル名のサフィックスを`_test.go`に変換して関連ファイルを検索します。
*   **`"See the documentation of `ff-other-file-alist' for details."`**: この変数のドキュメンテーション文字列です。ユーザーがこの変数の目的を理解するのに役立ちます。
*   **`:type '(repeat (list regexp (choice (repeat string) function)))`**: この変数の型を定義しています。これは、正規表現と、文字列のリストまたは関数のペアのリストであることを示しています。
*   **`:group 'go`**: この変数がEmacsのカスタマイズインターフェースで「Go」グループに属することを示しています。

### `(setq ff-other-file-alist 'go-other-file-alist)`

この行は、`go-mode`がアクティブになった際に実行されるフック(`go-mode-hook`)内で設定されています。

*   **`setq`**: Emacs Lispで変数の値を設定するための特殊形式です。
*   **`ff-other-file-alist`**: Emacsの`find-file`ライブラリが関連ファイルを特定するために使用するグローバル変数です。
*   **`'go-other-file-alist`**: `ff-other-file-alist`に設定される値です。ここでは、先ほど定義した`go-other-file-alist`変数の値を引用符(`'`)で囲んで渡しています。これにより、`ff-other-file-alist`は`go-other-file-alist`で定義されたGoファイルに特化したルールセットを使用するようになります。

この変更により、Goモードが有効な間は、`ff-find-other-file`コマンドがGoのソースファイルとテストファイルの間を効率的に切り替えることができるようになります。

## 関連リンク

*   Go CL 65750044: [https://golang.org/cl/65750044](https://golang.org/cl/65750044)

## 参考にした情報源リンク

*   Emacs `ff-find-other-file` and `go-mode.el` context:
    *   [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEklQ1JyLeLvLOnZ9YCbkjnTLBXt6OT8IvkVlB9RipKqVCEuTSOsj7Co64hWt3YLTredldkkVk-r1_fkHXCaHe9KNjo99Fx9pTtJ_GRqs2J-vs4Rt7QRRds-HaY1raROmjyxD3M2K8TGOK3mBcZZlO5afaIdBqjtqI=](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEklQ1JyLeLvLOnZ9YCbkjnTLBXt6OT8IvkVlB9RipKqVCEuTSOsj7Co64hWt3YLTredldkkVk-r1_fkHXCaHe9KNjo99Fx9pTtJ_GRqs2J-vs4Rt7QRRds-HaY1raROmjyxD3M2K8TGOK3mBcZZlO5afaIdBqjtqI=)
    *   [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGxIm5lcIriwCCXMamCp2iYjxk2ywU6pNfBGd0yPkYdLx61DgoBTawtbL0er6i3ulgnvDQFpxToH-zvlyzaSm4xTf7_dH5q93pXy_AlklNjxpQeh2W5bsRusLoNkjgf0oOJOFOpEf6uHDWpO98XY6-4_6pHj_lNZXuO](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGxIm5lcIriwCCXMamCp2iYjxk2ywU6pNfBGd0yPkYdLx61DgoBTawtbL0er6i3ulgnvDQFpxToH-zvlyzaSm4xTf7_dH5q93pXy_AlklNjxpQeh2W5bsRusLoNkjgf0oOJOFOpEf6uHDWpO98XY6-4_6pHj_lNZXuO)
    *   [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEEpR__OAd6ARTfwmxs26BldOA4LJVhHZH-yy3oNIjwEbjGPfBAxPEpfE2rTZ-IqHx0rdTIEWNxKRHCZE8cGz7qYonFti-jXwdtke95VJxVOf4EOqTzWCRtB9psyz6CQIeK](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEEpR__OAd6ARTfwmxs26BldOA4LJVhHZH-yy3oNIjwEbjGPfBAxPEpfE2rTZ-IqHx0rdTIEWNxKRHCZE8cGz7qYonFti-jXwdtke95VJxVOf4EOqTzWCRtB9psyz6CQIeK)