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

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