[インデックス 17872] ファイルの概要
このコミットは、EmacsのGoモード(go-mode.el
)において、Go言語のコードフォーマットツールであるgofmt
の実行コマンドをユーザーがカスタマイズできるようにする変更を導入しています。特に、gofmt
の代わりにgoimports
ツールを使用できるようにすることが主な目的です。
コミット
commit 19dda5cd74401cefaadf2ea46da32890e5737542
Author: Sameer Ajmani <sameer@golang.org>
Date: Fri Nov 8 11:31:44 2013 -0500
emacs: allow users to customize the gofmt command, in particular, to use goimports instead.
R=adonovan
CC=golang-dev
https://golang.org/cl/23680043
---
misc/emacs/go-mode.el | 8 +++++++-\n 1 file changed, 7 insertions(+), 1 deletion(-)\n
diff --git a/misc/emacs/go-mode.el b/misc/emacs/go-mode.el
index b74bc45e8d..3dfa8e3353 100644
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -157,6 +157,12 @@ customize this variable to point to the wrapper script.\"\n :type 'string\n :group 'go)\n
+(defcustom gofmt-command \"gofmt\"\n+ \"The 'gofmt' command. Some users may replace this with 'goimports'\n+from https://github.com/bradfitz/goimports.\"\n+ :type 'string\n+ :group 'go)\n+\n (defface go-coverage-untracked\n '((t (:foreground \"#505050\")))\n \"Coverage color of untracked code.\"\n@@ -638,7 +644,7 @@ buffer.\"\n ;; We're using errbuf for the mixed stdout and stderr output. This\n ;; is not an issue because gofmt -w does not produce any stdout\n ;; output in case of success.\n- (if (zerop (call-process \"gofmt\" nil errbuf nil \"-w\" tmpfile))\n+ (if (zerop (call-process gofmt-command nil errbuf nil \"-w\" tmpfile))\n (if (zerop (call-process-region (point-min) (point-max) \"diff\" nil patchbuf nil \"-n\" \"-\" tmpfile))\n (progn\n (kill-buffer errbuf)\n```
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/19dda5cd74401cefaadf2ea46da32890e5737542](https://github.com/golang/go/commit/19dda5cd74401cefaadf2ea46da32890e5737542)
## 元コミット内容
このコミットの目的は、EmacsのGoモードにおいて、`gofmt`コマンドをユーザーがカスタマイズできるようにすることです。特に、`goimports`ツールを代わりに利用できるようにすることが明記されています。
## 変更の背景
Go言語の開発において、コードのフォーマットは非常に重要視されており、公式ツールである`gofmt`がその役割を担っています。`gofmt`は、Goコードの標準的なスタイルを強制し、一貫性を保つために使用されます。しかし、Goコミュニティでは、`gofmt`の機能に加えて、インポート文の自動整理(追加、削除、ソート)を行う`goimports`というツールが広く利用されるようになりました。
`goimports`は`gofmt`の機能をすべて含みつつ、さらにインポートの管理を自動で行うため、多くのGo開発者にとって非常に便利なツールです。EmacsのGoモードは、デフォルトで`gofmt`を使用するように設定されていましたが、ユーザーが`goimports`を使いたい場合、その設定を直接変更する簡単な方法がありませんでした。
このコミットは、このような背景から、EmacsのGoモードのユーザーが、自身の好みに合わせてフォーマットコマンドを`gofmt`から`goimports`、あるいはその他の互換性のあるツールに簡単に切り替えられるようにするために導入されました。これにより、Emacsユーザーはより柔軟な開発環境を構築できるようになります。
## 前提知識の解説
* **`gofmt`**: Go言語の公式なコードフォーマッタです。Goのソースコードを標準的なスタイルに自動的に整形します。Goツールチェインに同梱されており、Go開発におけるコードの一貫性を保つ上で不可欠なツールです。
* **`goimports`**: `gofmt`の機能をすべて含み、さらにGoソースコードのインポート文を自動的に追加、削除、ソートするツールです。これにより、開発者は手動でインポートを管理する手間を省くことができます。`goimports`は、`gofmt`よりも高機能であるため、多くのGo開発者に好んで使用されています。
* **Emacs `go-mode`**: EmacsエディタでGo言語のコードを編集するためのメジャーモードです。シンタックスハイライト、インデント、コードフォーマットなどの機能を提供し、Go開発をEmacs上で行う際の利便性を高めます。
* **`defcustom` (Emacs Lisp)**: Emacs Lispにおける特殊フォームの一つで、ユーザーがカスタマイズ可能な変数を定義するために使用されます。`defcustom`で定義された変数は、Emacsのカスタマイズインターフェース(`M-x customize`など)を通じて簡単に設定を変更できます。
* **`call-process` (Emacs Lisp)**: Emacs Lispの関数で、外部のプログラムを実行するために使用されます。この関数は、指定されたコマンドを新しいプロセスとして起動し、その標準入力、標準出力、標準エラー出力をEmacsバッファにリダイレクトしたり、ファイルに保存したりすることができます。
## 技術的詳細
このコミットの技術的な核心は、EmacsのGoモード(`misc/emacs/go-mode.el`)が、Goコードのフォーマットを実行する際に、ハードコードされた`gofmt`コマンドではなく、ユーザーが設定可能な変数を使用するように変更された点にあります。
具体的には、以下の変更が行われました。
1. **`gofmt-command`変数の導入**: `defcustom`を使用して、`gofmt-command`という新しいカスタマイズ可能な変数が定義されました。この変数のデフォルト値は`"gofmt"`ですが、ユーザーはこれを`"goimports"`などの別のコマンドに変更できます。これにより、Emacsのカスタマイズ機能を通じて、フォーマットに使用するツールを簡単に切り替えることが可能になります。
2. **`call-process`の引数変更**: `go-mode.el`内で`gofmt`を実行していた`call-process`の呼び出しが変更されました。以前は`"gofmt"`という文字列リテラルが直接渡されていましたが、変更後は新しく定義された`gofmt-command`変数の値が渡されるようになりました。これにより、`call-process`は`gofmt-command`に設定されたコマンドを実行するようになります。
この変更により、EmacsのGoモードは、より柔軟な外部ツール連携を実現し、ユーザーの多様な開発ワークフローに対応できるようになりました。特に、`goimports`のような、`gofmt`のスーパーセットであるツールをシームレスに統合できるようになったことは、開発者の生産性向上に大きく貢献します。
## コアとなるコードの変更箇所
```diff
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -157,6 +157,12 @@ customize this variable to point to the wrapper script.\"\n :type 'string\n :group 'go)\n
+(defcustom gofmt-command \"gofmt\"\n+ \"The 'gofmt' command. Some users may replace this with 'goimports'\n+from https://github.com/bradfitz/goimports.\"\n+ :type 'string\n+ :group 'go)\n+\n (defface go-coverage-untracked\n '((t (:foreground \"#505050\")))\n \"Coverage color of untracked code.\"\n@@ -638,7 +644,7 @@ buffer.\"\n ;; We're using errbuf for the mixed stdout and stderr output. This\n ;; is not an issue because gofmt -w does not produce any stdout\n ;; output in case of success.\n- (if (zerop (call-process \"gofmt\" nil errbuf nil \"-w\" tmpfile))\n+ (if (zerop (call-process gofmt-command nil errbuf nil \"-w\" tmpfile))\n (if (zerop (call-process-region (point-min) (point-max) \"diff\" nil patchbuf nil \"-n\" \"-\" tmpfile))\n (progn\n (kill-buffer errbuf)\n```
## コアとなるコードの解説
このコミットにおける主要なコード変更は、`misc/emacs/go-mode.el`ファイル内の2つのセクションに集中しています。
1. **`gofmt-command`変数の定義(追加部分)**:
```emacs-lisp
(defcustom gofmt-command "gofmt"
"The 'gofmt' command. Some users may replace this with 'goimports'
from https://github.com/bradfitz/goimports."
:type 'string
:group 'go)
```
このコードブロックは、`gofmt-command`という新しいEmacs Lisp変数を定義しています。
* `defcustom`: この変数がユーザーによってカスタマイズ可能であることを示します。
* `"gofmt"`: `gofmt-command`の初期値(デフォルト値)が`"gofmt"`であることを意味します。これは、変更前と同じくデフォルトでは`gofmt`が使用されることを保証します。
* ドキュメント文字列: 変数の目的と、`goimports`への置き換えの可能性について説明しています。
* `:type 'string`: 変数の型が文字列であることを指定します。
* `:group 'go`: この変数がEmacsのカスタマイズインターフェースにおいて「Go」グループに属することを示し、関連する設定と一緒に表示されるようにします。
2. **`call-process`の引数変更(修正部分)**:
```diff
- (if (zerop (call-process "gofmt" nil errbuf nil "-w" tmpfile))\
+ (if (zerop (call-process gofmt-command nil errbuf nil "-w" tmpfile))\
```
この行は、実際に外部コマンドを実行している部分です。
* 変更前: `(call-process "gofmt" ...)` となっており、`gofmt`という文字列リテラルが直接コマンド名として渡されていました。これは、常に`gofmt`が実行されることを意味します。
* 変更後: `(call-process gofmt-command ...)` となっています。ここでは、ハードコードされた文字列の代わりに、先ほど定義された`gofmt-command`変数の値がコマンド名として使用されます。これにより、ユーザーが`gofmt-command`の値を`"goimports"`などに変更した場合、`call-process`は`goimports`を実行するようになります。
これらの変更により、EmacsのGoモードは、Goコードのフォーマットに使用する外部ツールを、ユーザーの選択に応じて動的に切り替えることができるようになりました。
## 関連リンク
* GitHubコミットページ: [https://github.com/golang/go/commit/19dda5cd74401cefaadf2ea46da32890e5737542](https://github.com/golang/go/commit/19dda5cd74401cefaadf2ea46da32890e5737542)
* Gerrit Change-Id: [https://golang.org/cl/23680043](https://golang.org/cl/23680043)
* `goimports` GitHubリポジトリ: [https://github.com/bradfitz/goimports](https://github.com/bradfitz/goimports)
## 参考にした情報源リンク
* `gofmt` vs `goimports`:
* [https://medium.com/@vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQF08Ac-ljFrbGkJHzxLrOkV4M1Wb9Gxt-ZcjBdyl_xC3fB8p72-QPH_sCbXAe7dMkUjbA1sJaZjfIUmSls_8PpeQIKW91cXk_qYB_kf6Vv4TEkxC-_PxAZssVv5wIlEYQn75bAXCc9gGEo3i4I2-xyAo97JOm0vgBwF2AlTPPgCkqBq--IFuH1otyUMSKPYI3g7I5qKbDzl8fy7T90=](https://medium.com/@vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQF08Ac-ljFrbGkJHzxLrOkV4M1Wb9Gxt-ZcjBdyl_xC3fB8p72-QPH_sCbXAe7dMkUjbA1sJaZjfIUmSls_8PpeQIKW91cXk_qYB_kf6Vv4TEkxC-_PxAZssVv5wIlEYQn75bAXCc9gGEo3i4I2-xyAo97JOm0vgBwF2AlTPPgCkqBq--IFuH1otyUMSKPYI3g7I5qKbDzl8fy7T90=)
* [https://codewithyury.com/gofmt-vs-goimports/](https://codewithyury.com/gofmt-vs-goimports/)
* [https://hyr.mn/posts/gofmt-vs-goimports/](https://hyr.mn/posts/gofmt-vs-goimports/)
* Emacs `go-mode`と`goimports`の設定:
* [https://yousefourabi.com/posts/go-mode-emacs/](https://yousefourabi.com/posts/go-mode-emacs/)
* [https://github.com/dominikh/go-mode.el/blob/master/go-mode.el](https://github.com/dominikh/go-mode.el/blob/master/go-mode.el)
* [https://emacs.stackexchange.com/questions/10000/how-to-use-goimports-with-go-mode](https://emacs.stackexchange.com/questions/10000/how-to-use-goimports-with-go-mode)
* [https://go-mode.github.io/go-mode/](https://go-mode.github.io/go-mode/)
* Gerrit Change-Id (golang.org/cl):
* [https://go.googlesource.com/go/+/23680043](https://go.googlesource.com/go/+/23680043)