[インデックス 18168] ファイルの概要
このコミットは、Go言語のEmacsメジャーモードであるgo-mode.el
における、type
キーワードのシンタックスハイライト(fontification)の挙動を修正するものです。具体的には、type
キーワードの後に少なくとも1つのスペースが続く場合にのみ型としてハイライトされるように正規表現が調整され、また型スイッチの閉じ括弧が誤って型としてハイライトされる問題が修正されています。これにより、Emacs上でのGoコードの可読性が向上します。
コミット
commit 79653e412132c02b455ea010733c3adfe40c7313
Author: Dominik Honnef <dominik.honnef@gmail.com>
Date: Mon Jan 6 11:11:03 2014 -0500
misc/emacs: fontify type switch correctly
Require at least one space after "type" and do not fontify closing
parenthesis of type switch as a type.
R=adonovan
CC=golang-codereviews
https://golang.org/cl/37720050
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/79653e412132c02b455ea010733c3adfe40c7313
元コミット内容
misc/emacs: fontify type switch correctly
Require at least one space after "type" and do not fontify closing
parenthesis of type switch as a type.
R=adonovan
CC=golang-codereviews
https://golang.org/cl/37720050
変更の背景
このコミットの背景には、EmacsのGoモード(go-mode.el
)におけるシンタックスハイライトの不正確さがありました。特に、Go言語の「型スイッチ(type switch)」構文において、type
キーワードの後のスペースの有無や、型スイッチの閉じ括弧が誤って型として認識され、不適切な色付けがされるという問題が存在していました。
Go言語の型スイッチは、インターフェース変数の動的な型を判定し、それに基づいて異なる処理を行うための強力な機能です。その構文は以下のようになります。
switch v := i.(type) {
case int:
fmt.Printf("Integer: %d\n", v)
case string:
fmt.Printf("String: %s\n", v)
default:
fmt.Printf("Unknown type\n")
}
このi.(type)
の部分が型スイッチの構文であり、type
はキーワードとして特別な意味を持ちます。しかし、既存のgo-mode.el
の正規表現では、このtype
キーワードの後に続くパターンを正確に識別できていなかったため、以下のような問題が発生していました。
type
キーワードの後のスペースの扱い:type
キーワードの直後にスペースがない場合でも、正規表現がマッチしてしまい、意図しない部分が型としてハイライトされる可能性がありました。これは、type
がキーワードとして使われる文脈と、例えば変数名の一部として使われる場合などを区別するために重要です。- 型スイッチの閉じ括弧の誤認識:
i.(type)
の閉じ括弧)
が、正規表現によって誤って型の一部として認識され、不適切にハイライトされることがありました。これは、シンタックスハイライトの目的であるコードの構造と意味の明確化を妨げるものでした。
これらの問題を解決し、Emacs上でのGoコードのシンタックスハイライトをより正確にすることで、開発者のコードリーディング体験を向上させることが、このコミットの主な目的です。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
- Emacs Lisp (Elisp): Emacsエディタの拡張言語であり、Emacsの動作をカスタマイズしたり、新しい機能を追加したりするために使用されます。
go-mode.el
はElispで書かれたファイルであり、Go言語の編集モードを定義しています。 - シンタックスハイライト (Fontification): プログラミング言語のキーワード、変数、文字列、コメントなどを異なる色やスタイルで表示することで、コードの可読性を高める機能です。Emacsでは「fontification」と呼ばれ、
font-lock-mode
によって制御されます。シンタックスハイライトのルールは、通常、正規表現(Regular Expression)を用いて定義されます。 - 正規表現 (Regular Expression): 文字列のパターンを記述するための強力なツールです。このコミットでは、Emacs Lispの正規表現が使用されており、特に以下の要素が重要です。
concat
: 複数の文字列を結合するElisp関数。go--regexp-enclose-in-symbol
:go-mode.el
内で定義されているヘルパー関数で、特定のキーワードをシンボルとして認識するための正規表現を生成します。これにより、例えばtype
という単語が、mytype
のような別の単語の一部としてではなく、独立したキーワードとして扱われるようになります。[[:space:]]*
: 0個以上の空白文字(スペース、タブなど)にマッチします。[[:space:]]+
: 1個以上の空白文字にマッチします。この変更がこのコミットの核心部分です。\\(
と\\)
: キャプチャグループを定義します。マッチした部分文字列を後で参照するために使用されます。[^[:space:]]+
: 1個以上の空白文字以外の文字にマッチします。go-identifier-regexp
: Go言語の識別子(変数名、関数名など)にマッチする正規表現。go-type-name-regexp
: Go言語の型名にマッチする正規表現。
- Go言語の型スイッチ (Type Switch): Go言語の特定の構文で、インターフェース変数の動的な型を判定し、その型に基づいて異なるコードブロックを実行するために使用されます。構文は
switch v := i.(type) { ... }
の形式を取ります。
これらの知識を組み合わせることで、go-mode.el
がどのようにGoコードを解析し、シンタックスハイライトを適用しているか、そしてこのコミットがそのプロセスをどのように改善しているかを理解することができます。
技術的詳細
このコミットは、misc/emacs/go-mode.el
ファイル内の正規表現の定義を修正することで、Go言語のtype
キーワードのシンタックスハイライトの精度を向上させています。具体的には、font-lock-type-face
(型をハイライトするためのスタイル)が適用される正規表現パターンが変更されています。
変更された行は以下の2行です。
変更前:
(,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]*\\([^[:space:]]+\\)") 1 font-lock-type-face) ;; types
(,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]*" go-identifier-regexp "[[:space:]]*" go-type-name-regexp) 1 font-lock-type-face) ;; types
変更後:
(,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]+\\([^[:space:]]+\\)") 1 font-lock-type-face) ;; types
(,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]+" go-identifier-regexp "[[:space:]]*" go-type-name-regexp) 1 font-lock-type-face) ;; types
この変更の核心は、正規表現内の[[:space:]]*
が[[:space:]]+
に置き換えられた点です。
[[:space:]]*
: これは「0個以上の空白文字」にマッチします。つまり、type
キーワードの直後に空白がなくてもマッチしてしまいます。[[:space:]]+
: これは「1個以上の空白文字」にマッチします。これにより、type
キーワードの直後に少なくとも1つの空白文字が続く場合にのみ、この正規表現がマッチするようになります。
この変更がもたらす具体的な影響は以下の通りです。
type
キーワードの厳密なマッチング: Go言語においてtype
キーワードが型定義や型スイッチで使用される場合、通常その後にスペースが続きます。この変更により、type
の直後にスペースがないような、意図しない文脈でのtype
のハイライトが防がれます。例えば、mytype
のような変数名の一部としてのtype
が誤ってハイライトされることがなくなります。- 型スイッチの閉じ括弧の誤認識の修正: コミットメッセージには「do not fontify closing parenthesis of type switch as a type」とありますが、これは直接的な正規表現の変更ではなく、
[[:space:]]+
への変更によって間接的に解決される問題であると考えられます。type
キーワードの後のパターンマッチがより厳密になることで、i.(type)
のような型スイッチ構文において、type
の後の)
が誤って型の一部として認識されることがなくなります。以前の[[:space:]]*
では、type)
のようなパターンもマッチしてしまう可能性がありましたが、[[:space:]]+
にすることで、type
と)
の間にスペースがないため、このパターンはマッチしなくなります。これにより、閉じ括弧が型としてハイライトされることがなくなります。
これらの変更は、Emacsのfont-lock-mode
がGoコードを解析し、適切なシンタックスハイライトを適用する際の精度を大幅に向上させ、開発者にとってより正確で視覚的に分かりやすいコード表示を提供します。
コアとなるコードの変更箇所
変更はmisc/emacs/go-mode.el
ファイル内の2箇所です。
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -264,8 +264,8 @@ For mode=set, all covered lines will have this weight.\"\
`((,go-func-meth-regexp 1 font-lock-function-name-face))) ;; method name
`(\
- (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]*\\([^[:space:]]+\\)") 1 font-lock-type-face) ;; types
- (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]*" go-identifier-regexp "[[:space:]]*" go-type-name-regexp) 1 font-lock-type-face) ;; types
+ (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]+\\([^[:space:]]+\\)") 1 font-lock-type-face) ;; types
+ (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]+" go-identifier-regexp "[[:space:]]*" go-type-name-regexp) 1 font-lock-type-face) ;; types
(,(concat "[^[:word:][:multibyte:]]\\[\\([[:digit:]]+\\|\\.\\.\\.\\)?\\]" go-type-name-regexp) 2 font-lock-type-face) ;; Arrays/slices
(,(concat "\\(" go-identifier-regexp "\\)" "{") 1 font-lock-type-face)
(,(concat (go--regexp-enclose-in-symbol "map") "\\[[^]]+\\]" go-type-name-regexp) 1 font-lock-type-face) ;; map value type
コアとなるコードの解説
このコミットで変更されたのは、go-mode.el
内のfont-lock-keywords
リストの一部です。このリストは、EmacsがGoコードをシンタックスハイライトする際に使用する正規表現と、それに対応するハイライトスタイル(face)のペアを定義しています。
変更された2つの正規表現パターンは、Go言語の「型(types)」を識別するためのものです。
-
最初のパターン:
- 変更前:
(,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]*\\([^[:space:]]+\\)") 1 font-lock-type-face)
- 変更後:
(,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]+\\([^[:space:]]+\\)") 1 font-lock-type-face)
このパターンは、
type
キーワードの後に続く型名をハイライトすることを目的としています。(go--regexp-enclose-in-symbol "type")
:type
という単語が独立したキーワードとして扱われるように正規表現を生成します。[[:space:]]*
から[[:space:]]+
への変更: ここが最も重要な変更点です。これにより、type
キーワードの直後に「少なくとも1つの空白文字」が続く場合にのみマッチするようになります。これにより、type
がキーワードとして使われる文脈(例:type MyStruct struct {}
やswitch v := i.(type)
)でのみ正しくハイライトされるようになります。\\([^[:space:]]+\\)
: 1つ以上の空白文字以外の文字(つまり型名)をキャプチャします。1 font-lock-type-face
: キャプチャグループ1(型名)にfont-lock-type-face
というハイライトスタイルを適用することを示します。
- 変更前:
-
二番目のパターン:
- 変更前:
(,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]*" go-identifier-regexp "[[:space:]]*" go-type-name-regexp) 1 font-lock-type-face)
- 変更後:
(,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]+" go-identifier-regexp "[[:space:]]*" go-type-name-regexp) 1 font-lock-type-face)
このパターンは、より複雑な型定義、特に構造体やインターフェースのフィールドにおける型をハイライトすることを目的としている可能性があります。
- 同様に、
[[:space:]]*
から[[:space:]]+
への変更が適用されています。 go-identifier-regexp
: Goの識別子(フィールド名など)にマッチします。go-type-name-regexp
: Goの型名にマッチします。
- 変更前:
これらの変更により、go-mode.el
はtype
キーワードの後の文脈をより正確に解釈し、シンタックスハイライトの誤りを減らすことができます。特に、型スイッチ構文におけるi.(type)
のようなケースで、type
キーワードが正しく認識され、その後の閉じ括弧が誤ってハイライトされることがなくなります。これは、正規表現のマッチングがより厳密になった結果として得られる副作用です。
関連リンク
- Go言語の型スイッチに関する公式ドキュメント: https://go.dev/tour/methods/16 (Go Tourの型スイッチのセクション)
- Emacs Lispの正規表現に関する情報: https://www.gnu.org/software/emacs/manual/html_node/elisp/Regexp-Syntax.html
- EmacsのFont Lockモードに関する情報: https://www.gnu.org/software/emacs/manual/html_node/elisp/Font-Lock-Mode.html
参考にした情報源リンク
- GitHubのコミットページ: https://github.com/golang/go/commit/79653e412132c02b455ea010733c3adfe40c7313
- Gerrit Code Review (golang.org/cl/37720050): https://golang.org/cl/37720050 (コミットメッセージに記載されている変更リストへのリンク)
- Emacs Lispのドキュメント (正規表現、concat関数など): https://www.gnu.org/software/emacs/manual/html_node/elisp/
- Go言語の仕様 (型スイッチ): https://go.dev/ref/spec#Type_switches