[インデックス 18560] ファイルの概要
このコミットは、Go言語のEmacsメジャーモードであるgo-mode.el
ファイルに対する変更です。go-mode.el
は、Emacsエディタ内でGo言語のコードを記述する際に、シンタックスハイライト、インデント、コード補完、定義ジャンプなどの機能を提供するLispスクリプトです。
コミット
misc/emacs: actually use point argument that is passed to godef--call
LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/62600043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/0d9b9aafd575099fcbd05e0c8f05f087d8d2b922
元コミット内容
misc/emacs: actually use point argument that is passed to godef--call
このコミットメッセージは、godef--call
関数に渡されるpoint
引数が、実際にその関数内で使用されるように修正されたことを示しています。
変更の背景
この変更の背景には、go-mode.el
におけるgodef
ツールの利用方法に関するバグがありました。godef
はGo言語の識別子の定義元を検索するためのコマンドラインツールです。Emacsのgo-mode.el
は、このgodef
ツールを呼び出して、ユーザーがカーソルを置いた場所(または指定した場所)のシンボルの定義元を特定する機能を提供しています。
問題は、godef--call
というEmacs Lisp関数が、定義元を検索する位置を示すpoint
引数を受け取るにもかかわらず、その引数を適切に利用していなかった点にありました。具体的には、godef
ツールに渡す位置情報を生成する際に、引数として渡されたpoint
ではなく、常に現在のバッファのカーソル位置(Emacs Lispの(point)
関数が返す値)を使用していました。
このため、godef--call
が特定のpoint
(例えば、現在のカーソル位置とは異なる場所のシンボル定義を調べたい場合)を指定して呼び出されたとしても、期待通りの動作をせず、常に現在のカーソル位置のシンボル定義を返してしまうという不具合が発生していました。このコミットは、この論理的な誤りを修正し、godef--call
が受け取ったpoint
引数を正しく利用するようにすることで、より正確な定義ジャンプ機能を提供することを目的としています。
前提知識の解説
Emacs Lisp (Elisp)
Emacs Lispは、Emacsエディタの拡張機能やカスタマイズを記述するために使用されるプログラミング言語です。Emacsのほぼ全ての機能はEmacs Lispで実装されており、ユーザーはEmacs Lispコードを記述することで、エディタの動作を細かく制御したり、新しい機能を追加したりできます。go-mode.el
もEmacs Lispで書かれたファイルです。
Emacsにおけるpoint
Emacsにおいて「ポイント (point)」とは、現在のカーソル位置を指す概念です。バッファ内の文字と文字の間に位置し、通常は1から始まる整数値で表現されます。Emacs Lispでは、(point)
関数を呼び出すことで、現在のバッファのポイント値を取得できます。また、特定のポイント値を指定して、その位置で何らかの操作を行うことも頻繁に行われます。
godef
ツール
godef
は、Go言語のソースコード内で特定の識別子(変数、関数、型など)がどこで定義されているかを特定するためのコマンドラインツールです。Goのソースファイルを解析し、指定されたファイルパスとバイトオフセットに基づいて、その位置にある識別子の定義元(ファイルパス、行番号、列番号)を出力します。Emacsのgo-mode.el
のようなIDE連携ツールは、このgodef
をバックエンドとして利用し、ユーザーがコード上で定義ジャンプ(Go to Definition)を行う機能を実現しています。
go-mode.el
とgodef
の連携
go-mode.el
は、Emacs Lispのコードを通じてgodef
コマンドを外部プロセスとして実行します。この際、godef
には、定義を調べたいGoファイルのパスと、そのファイル内でのバイトオフセット(文字位置)を引数として渡します。godef
はこれらの情報に基づいて定義元を特定し、その結果を標準出力に返します。go-mode.el
はその出力を解析し、Emacsバッファ内で定義元にジャンプしたり、情報を表示したりします。
go--position-bytes
関数
go--position-bytes
は、Emacsのポイント(文字位置)を、godef
が期待するバイトオフセットに変換するためのgo-mode.el
内のヘルパー関数です。Emacsは内部的に文字コードを考慮してポイントを扱いますが、godef
のような外部ツールは通常、ファイルの先頭からのバイトオフセットを期待するため、この変換が必要になります。
技術的詳細
このコミットが修正しているのは、go-mode.el
内のgodef--call
関数がgodef
ツールを呼び出す際の引数渡しに関する問題です。
godef--call
関数は、以下のような構造でgodef
コマンドを構築し、実行していました(簡略化)。
(defun godef--call (point)
;; ...
(let ((command-args
(list "-f"
(file-truename (buffer-file-name (go--coverage-origin-buffer)))
"-o"
(number-to-string (go--position-bytes (point)))))) ; ここが問題
;; ... godefコマンドを実行
))
ここで注目すべきは、godef
に渡す-o
オプションの値、すなわちバイトオフセットを生成している部分です。
(number-to-string (go--position-bytes (point)))
このコードでは、godef--call
関数が引数としてpoint
を受け取っているにもかかわらず、go--position-bytes
関数に渡しているのは、引数のpoint
ではなく、Emacs Lispの組み込み関数である(point)
の呼び出し結果です。組み込みの(point)
関数は、常に「現在のバッファのカーソル位置」を返します。
したがって、godef--call
が例えば(godef--call 100)
のように、特定のポイント値(例: 100)を指定して呼び出されたとしても、godef
ツールには常に現在のカーソル位置のバイトオフセットが渡されていました。これにより、ユーザーが意図した場所ではなく、カーソルがある場所のシンボル定義が検索されてしまうという、機能的な不整合が生じていました。
このコミットは、この部分を修正し、godef--call
に渡された引数のpoint
を正しくgo--position-bytes
に渡すように変更しています。
コアとなるコードの変更箇所
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -995,7 +995,7 @@ description at POINT."
"-f"
(file-truename (buffer-file-name (go--coverage-origin-buffer)))
"-o"
- (number-to-string (go--position-bytes (point))))
+ (number-to-string (go--position-bytes point))))
(with-current-buffer outbuf
(split-string (buffer-substring-no-properties (point-min) (point-max)) "\\n"))))
変更はmisc/emacs/go-mode.el
ファイルの1箇所のみです。
コアとなるコードの解説
変更された行は以下の通りです。
- 変更前:
(number-to-string (go--position-bytes (point)))
- 変更後:
(number-to-string (go--position-bytes point))
この変更は非常にシンプルですが、その影響は重要です。
-
変更前:
(point)
というEmacs Lispの組み込み関数が呼び出されています。この関数は、そのコードが実行された時点での「現在のバッファのカーソル位置」を返します。したがって、godef--call
関数が引数としてpoint
を受け取っていたとしても、この内部の呼び出しではその引数が無視され、常に現在のカーソル位置が使用されていました。 -
変更後:
point
というシンボルが直接go--position-bytes
関数に渡されています。このpoint
は、godef--call
関数の引数として受け取った値です。これにより、godef--call
が呼び出し元から指定された特定のポイント値に基づいてgodef
ツールに位置情報を渡すことができるようになります。
この修正により、godef--call
関数は、そのインターフェース(引数としてpoint
を受け取る)と実際の動作が一致するようになり、より柔軟かつ正確な定義ジャンプ機能を提供できるようになりました。例えば、プログラム的に特定のコード位置の定義を調べたい場合など、現在のカーソル位置に依存しないgodef
の呼び出しが可能になります。
関連リンク
- Go Code Review 62600043: https://golang.org/cl/62600043
参考にした情報源リンク
- Emacs Lisp Manual: https://www.gnu.org/software/emacs/manual/html_node/elisp/index.html (特に
point
関数に関する記述) godef
ツール (Go言語の定義ジャンプツール): https://pkg.go.dev/golang.org/x/tools/cmd/godef- Go Emacs Mode (
go-mode.el
) のソースコード (GitHub): https://github.com/golang/go/blob/master/misc/emacs/go-mode.el (コミット時点のバージョンとは異なる可能性があります) - Emacs Lispの
point
に関する一般的な情報: https://www.gnu.org/software/emacs/manual/html_node/elisp/Point.html - Emacs Lispの関数呼び出しと引数に関する一般的な情報: https://www.gnu.org/software/emacs/manual/html_node/elisp/Calling-Functions.html
- Go言語のツールに関する情報: https://go.dev/doc/tools