[インデックス 16798] ファイルの概要
このコミットは、Go言語のEmacsメジャーモードであるgo-mode.el
に、godef-jump-other-window
という新しい機能を追加するものです。この機能は、Goの定義元へジャンプする際に、現在のウィンドウではなく別のウィンドウでファイルを開くように動作します。
コミット
commit 58ce655fd2efe2270ee852790eede952e179735e
Author: Dominik Honnef <dominik.honnef@gmail.com>
Date: Wed Jul 17 18:16:44 2013 -0400
misc/emacs: Add godef-jump-other-window
This will behave like similar "*-other-window" functions in Emacs.
Default key bind is C-x 4 C-c C-j – while awkward, it follows both
the convention for other-window functions and the convention for
not using user- or emacs-reserved keys.
R=golang-dev, adonovan
CC=golang-dev
https://golang.org/cl/10707045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/58ce655fd2efe2270ee852790eede952e179735e
元コミット内容
このコミットは、EmacsのGoモード(go-mode.el
)にgodef-jump-other-window
という新しいコマンドを追加します。このコマンドは、既存のgodef-jump
コマンドと同様にGoコード内のシンボルの定義元にジャンプしますが、その際に定義元ファイルが新しいウィンドウ(または既存の別のウィンドウ)で開かれるように動作します。これはEmacsにおける一般的な「-other-window
」系の関数(例: find-file-other-window
)の振る舞いに倣ったものです。
新しいコマンドには、デフォルトでC-x 4 C-c C-j
というキーバインドが割り当てられます。このキーバインドは一見すると複雑ですが、Emacsの「別のウィンドウで開く」系の機能の慣習(C-x 4
プレフィックス)と、ユーザー定義キーやEmacs内部予約キーを使用しないという慣習の両方に従っています。
変更の背景
Go言語の開発において、コードの定義元にジャンプする機能は非常に重要です。godef
ツールとそれを利用するEmacsのgo-mode
は、この機能を提供していました。しかし、既存のgodef-jump
コマンドは、常に現在のウィンドウで定義元ファイルを開くため、元のコードを編集中のウィンドウから移動してしまうという問題がありました。
開発者は、元のコンテキストを維持しつつ定義元を参照したいというニーズを抱えていました。Emacsには、ファイルを別のウィンドウで開くためのfind-file-other-window
のような慣習的な機能群が存在します。このコミットは、このEmacsの慣習をgodef-jump
機能にも適用することで、ユーザーエクスペリエンスを向上させることを目的としています。これにより、ユーザーは現在の作業を中断することなく、定義元を素早く確認できるようになります。
前提知識の解説
Emacs (イーマックス)
Emacsは、高度にカスタマイズ可能なテキストエディタであり、統合開発環境(IDE)としても機能します。Lisp方言であるEmacs Lispで拡張されており、ユーザーは独自の関数やキーバインドを定義して、エディタの動作を細かく制御できます。Emacsの大きな特徴の一つは、ウィンドウ管理機能です。Emacsの「ウィンドウ」は、通常、フレーム(GUIウィンドウ)内で分割された表示領域を指し、それぞれが異なるバッファ(ファイルの内容など)を表示できます。
Emacsのキーバインドと慣習
Emacsでは、特定のプレフィックスキーに続くキーシーケンスによってコマンドが実行されます。
C-x
(Control-x): ファイル操作、バッファ操作、ウィンドウ操作など、多くの基本的なコマンドのプレフィックスとして使われます。C-x 4
: これは「別のウィンドウで操作を行う」ことを示す慣習的なプレフィックスです。例えば、C-x 4 f
(find-file-other-window
) は、ファイルを別のウィンドウで開きます。C-c
: ユーザーが定義するコマンドのプレフィックスとして推奨されるキーです。
Go言語のgodef
ツール
godef
は、Go言語のソースコード解析ツールの一つです。Goのソースファイル内の識別子(変数、関数、型など)がどこで定義されているかを特定し、その定義元のファイルパス、行番号、列番号を出力します。これは、IDEやエディタが「定義へジャンプ」機能を実現するために利用されます。godef
は、Goの標準ライブラリのgo/parser
やgo/ast
パッケージなどを用いて、Goコードの抽象構文木(AST)を解析することで機能します。
Emacsのgo-mode
go-mode
は、EmacsでGo言語のコードを編集するためのメジャーモードです。Go言語のシンタックスハイライト、インデント、コメント、そしてgodef
のような外部ツールとの連携機能を提供します。このモードは、Go開発者がEmacsを快適に利用できるようにするための重要なコンポーネントです。
Emacs Lisp (Elisp)
Emacs Lispは、Emacsエディタの拡張言語です。Emacsのほとんどの機能はEmacs Lispで書かれており、ユーザーはEmacs Lispのコードを記述することで、エディタの動作をカスタマイズしたり、新しい機能を追加したりできます。
defun
: Emacs Lispで関数を定義するためのマクロです。interactive
: 関数が対話的に(キーバインドやM-x
コマンドから)呼び出されることを宣言します。引数の指定方法もここで定義できます。define-key
: キーマップにキーバインドを定義します。kbd
: キーシーケンスをEmacsの内部表現に変換します。with-current-buffer
: 指定されたバッファを一時的にカレントバッファにして、その中で式を評価します。funcall
: 関数を呼び出します。第一引数に関数名(シンボル)を取り、残りの引数をその関数に渡します。if
: 条件分岐を記述します。t
: Emacs Lispにおける真理値の真を表すシンボルです。
技術的詳細
このコミットの主要な変更点は、既存のgodef-jump
関数を拡張し、新しいgodef-jump-other-window
関数を追加することで、定義元へのジャンプ動作に「別のウィンドウで開く」オプションを導入したことです。
-
godef--find-file-line-column
関数の変更:- この関数は、
godef
ツールから返されたファイルパス、行番号、列番号に基づいて、Emacsで該当ファイルを開き、指定された位置にカーソルを移動させる役割を担っています。 - 変更前は、常に
find-file
関数を使用していました。 - 変更後、
other-window
という新しいブール型引数を受け取るようになりました。 - この引数の値に応じて、
funcall
とif
を組み合わせて、find-file-other-window
またはfind-file
のどちらの関数を呼び出すかを動的に決定します。other-window
がt
(真)の場合、find-file-other-window
が呼び出され、ファイルは別のウィンドウで開かれます。other-window
がnil
(偽)の場合、find-file
が呼び出され、ファイルは現在のウィンドウで開かれます。
- この関数は、
-
godef-jump
関数の変更:- この関数は、ユーザーがカーソルを置いているGoシンボルの定義元を
godef
ツールを使って特定し、その結果に基づいてgodef--find-file-line-column
を呼び出します。 - 変更前は、
point
引数のみを受け取っていました。 - 変更後、
&optional other-window
という新しいオプション引数を受け取るようになりました。これにより、この関数を呼び出す際に、定義元を別のウィンドウで開くかどうかを指定できるようになります。 - この
other-window
引数は、そのままgodef--find-file-line-column
関数に渡されます。
- この関数は、ユーザーがカーソルを置いているGoシンボルの定義元を
-
godef-jump-other-window
関数の新規追加:- この関数は、
godef-jump
関数をラップするシンプルなラッパー関数です。 interactive "d"
と宣言されており、対話的に呼び出された際に、現在のカーソル位置(point
)を引数として受け取ります。- 内部では、
godef-jump
関数を呼び出し、その際にother-window
引数にt
(真)を渡します。これにより、常に定義元が別のウィンドウで開かれるようになります。
- この関数は、
-
キーバインドの追加:
go-mode
のキーマップgo-mode-map
に、新しいキーバインド(kbd "C-x 4 C-c C-j")
が追加され、godef-jump-other-window
関数にマッピングされました。- このキーバインドは、Emacsの慣習に従い、
C-x 4
プレフィックスを使用することで、ユーザーに「別のウィンドウで操作を行う」ことを明確に示します。
これらの変更により、godef-jump
の既存の動作を維持しつつ、ユーザーは必要に応じて定義元を別のウィンドウで開くという柔軟な選択肢を得られるようになりました。
コアとなるコードの変更箇所
misc/emacs/go-mode.el
ファイルにおける変更は以下の通りです。
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -193,6 +193,7 @@
(define-key m "=" 'go-mode-insert-and-indent)
(define-key m (kbd "C-c C-a") 'go-import-add)
(define-key m (kbd "C-c C-j") 'godef-jump)
+ (define-key m (kbd "C-x 4 C-c C-j") 'godef-jump-other-window)
(define-key m (kbd "C-c C-d") 'godef-describe)
m)
"Keymap used by Go mode to implement electric keys.")
@@ -870,7 +871,7 @@ will be commented, otherwise they will be removed completely."
(message "Removed %d imports" (length lines)))
(if flymake-state (flymake-mode-on))))))
-(defun godef--find-file-line-column (specifier)
+(defun godef--find-file-line-column (specifier other-window)
"Given a file name in the format of `filename:line:column',
visit FILENAME and go to line LINE and column COLUMN."
(if (not (string-match "\\(.+\\):\\([0-9]+\\):\\([0-9]+\\)" specifier))
@@ -878,7 +879,7 @@ visit FILENAME and go to line LINE and column COLUMN."
(let ((filename (match-string 1 specifier))
(line (string-to-number (match-string 2 specifier)))
(column (string-to-number (match-string 3 specifier))))
- (with-current-buffer (find-file filename)
+ (with-current-buffer (funcall (if other-window 'find-file-other-window 'find-file) filename)
(goto-char (point-min))
(forward-line (1- line))
(beginning-of-line)
@@ -910,7 +911,7 @@ description at POINT."
(message "%s" description)))
(file-error (message "Could not run godef binary"))))
-(defun godef-jump (point)
+(defun godef-jump (point &optional other-window)
"Jump to the definition of the expression at POINT."
(interactive "d")
(condition-case nil
@@ -924,7 +925,11 @@ description at POINT."
(message "%s" file))
(t
(push-mark)
- (godef--find-file-line-column file))))
+ (godef--find-file-line-column file other-window))))
(file-error (message "Could not run godef binary"))))
+(defun godef-jump-other-window (point)
+ (interactive "d")
+ (godef-jump point t))
+
(provide 'go-mode)
コアとなるコードの解説
1. キーバインドの追加
(define-key m (kbd "C-x 4 C-c C-j") 'godef-jump-other-window)
go-mode-map
(m
として参照) に新しいキーバインドが追加されています。C-x 4 C-c C-j
というキーシーケンスが、新しく定義される関数godef-jump-other-window
に割り当てられます。C-x 4
はEmacsで「別のウィンドウで操作する」ことを示す標準的なプレフィックスであり、このキーバインドがその慣習に従っていることを示しています。
2. godef--find-file-line-column
関数の変更
-(defun godef--find-file-line-column (specifier)
+(defun godef--find-file-line-column (specifier other-window)
;; ...
- (with-current-buffer (find-file filename)
+ (with-current-buffer (funcall (if other-window 'find-file-other-window 'find-file) filename)
;; ...
この関数は、godef
ツールが返すファイル名:行番号:列番号
の形式の文字列(specifier
)を解析し、該当するファイルを開いて指定された位置にジャンプする内部ヘルパー関数です。
- 関数の定義が変更され、
other-window
という新しい引数を受け取るようになりました。この引数は、定義元を別のウィンドウで開くべきかどうかを示すブール値(t
またはnil
)です。 - ファイルを開く部分のロジックが変更されました。以前は常に
find-file
を使用していましたが、funcall (if other-window 'find-file-other-window 'find-file) filename
という式に置き換えられました。if other-window 'find-file-other-window 'find-file)
:other-window
がt
(真)であればシンボル'find-file-other-window
を返し、そうでなければシンボル'find-file
を返します。funcall
:if
式の結果として得られたシンボル(関数名)を、filename
を引数として呼び出します。 この変更により、godef--find-file-line-column
は、呼び出し元が指定したother-window
の値に応じて、現在のウィンドウまたは別のウィンドウでファイルを開くことができるようになりました。
3. godef-jump
関数の変更
-(defun godef-jump (point)
+(defun godef-jump (point &optional other-window)
;; ...
(t
(push-mark)
- (godef--find-file-line-column file))))
+ (godef--find-file-line-column file other-window))))
;; ...
この関数は、ユーザーがカーソルを置いているGoシンボルの定義元にジャンプする主要なコマンドです。
- 関数の定義が変更され、
&optional other-window
というオプション引数を受け取るようになりました。これにより、この関数はother-window
の値を省略可能となり、省略された場合はnil
として扱われます。 godef--find-file-line-column
を呼び出す際に、新しく追加されたother-window
引数をそのまま渡すようになりました。これにより、godef-jump
は、呼び出し元から受け取ったother-window
の指示を、実際にファイルを開くヘルパー関数に伝えることができます。
4. godef-jump-other-window
関数の新規追加
+(defun godef-jump-other-window (point)
+ (interactive "d")
+ (godef-jump point t))
これは、新しいキーバインドC-x 4 C-c C-j
に割り当てられる関数です。
interactive "d"
: この関数が対話的に呼び出されることを宣言し、現在のカーソル位置(point
)を引数として受け取るように指定します。(godef-jump point t)
: 既存のgodef-jump
関数を呼び出します。この際、point
(現在のカーソル位置)と、other-window
引数にt
(真)を明示的に渡しています。これにより、この関数が呼び出されると、常に定義元が別のウィンドウで開かれるようになります。
これらの変更により、godef-jump
の既存の動作(現在のウィンドウで開く)を維持しつつ、godef-jump-other-window
という新しいコマンドを通じて、ユーザーは定義元を別のウィンドウで開くという選択肢を得られるようになりました。これはEmacsの慣習に沿った、より柔軟なナビゲーション機能を提供します。
関連リンク
- Go言語公式サイト: https://go.dev/
- Emacs公式サイト: https://www.gnu.org/software/emacs/
godef
ツールのGitHubリポジトリ (非公式): https://github.com/rogpeppe/godef (Goのツールは通常Goリポジトリの一部として開発されますが、godef
は独立したプロジェクトとして始まった経緯があります)- GoのGerritコードレビューシステム: https://go.googlesource.com/go/+/refs/heads/master/CONTRIBUTING.md#Code-Review
参考にした情報源リンク
- Emacs Lisp Reference Manual: https://www.gnu.org/software/emacs/manual/html_node/elisp/
- Emacs Manual (Windows): https://www.gnu.org/software/emacs/manual/html_node/emacs/Windows.html
- Goのツールに関するドキュメント (例:
go doc
): https://go.dev/doc/cmd/go - Gerrit Code Review: https://www.gerritcodereview.com/
- Goのコードレビュープロセス: https://go.dev/doc/contribute#code_review
- Emacsのウィンドウとフレームに関するドキュメント: https://www.gnu.org/software/emacs/manual/html_node/emacs/Windows.html
- Emacsのキーバインドに関するドキュメント: https://www.gnu.org/software/emacs/manual/html_node/emacs/Key-Bindings.html
- Emacs Lispの
funcall
に関するドキュメント: https://www.gnu.org/software/emacs/manual/html_node/elisp/Calling-Functions.html - Emacs Lispの
if
に関するドキュメント: https://www.gnu.org/software/emacs/manual/html_node/elisp/Conditionals.html - Emacs Lispの
&optional
に関するドキュメント: https://www.gnu.org/software/emacs/manual/html_node/elisp/Lambda-Expressions.html - Emacs Lispの
interactive
に関するドキュメント: https://www.gnu.org/software/emacs/manual/html_node/elisp/Interactive-Call.html - Emacs Lispの
define-key
に関するドキュメント: https://www.gnu.org/software/emacs/manual/html_node/elisp/Keymaps.html - Emacs Lispの
kbd
に関するドキュメント: https://www.gnu.org/software/emacs/manual/html_node/elisp/Key-Sequences.html - Emacs Lispの
with-current-buffer
に関するドキュメント: https://www.gnu.org/software/emacs/manual/html_node/elisp/Buffers.html - Emacs Lispの
find-file
とfind-file-other-window
に関するドキュメント: https://www.gnu.org/software/emacs/manual/html_node/emacs/Visiting-Files.html - Goのソースコード解析に関するパッケージ(
go/parser
,go/ast
など): https://go.dev/pkg/go/ - GoのGerrit Change-ID
10707045
(これはGoのGerritシステムでの変更セットIDであり、直接アクセスは難しい場合がありますが、コミットメッセージに記載されているため関連情報として含めます): https://golang.org/cl/10707045 (このリンクはGerritの変更セットへの直接リンクですが、古いGerrit IDはリダイレクトされない場合があります。しかし、コミットメッセージに記載されているため、関連情報として含めます。)