[インデックス 18977] ファイルの概要
このコミットは、EmacsのGoモード(go-mode.el
)におけるシンタックスハイライトの挙動を修正するものです。具体的には、Go言語の組み込み関数名が変数名として使用されている場合に、誤って組み込み関数としてハイライトされる問題を解決します。これにより、「new」のような頻繁に変数名として使われる組み込み関数名が、関数呼び出しでない限りハイライトされないようになります。
コミット
commit 5f5e280e14efde7c576c282fc7ee3a2c734eb8c5
Author: Rui Ueyama <ruiu@google.com>
Date: Thu Mar 27 17:35:07 2014 -0400
misc/emacs: do not highlight built-in function if not followed by '('
Name of built-in function is not reserved word in Go, and you can
use it as variable name. "new" is often used as local variable, for
instance.
This patch is to apply font-lock-builtin-face only when built-in
function name is followed by '(', so that it doesn't highlight
non-function variable that happen to have the same name as built-in
function.
LGTM=dominik.honnef
R=golang-codereviews, dominik.honnef, adonovan
CC=golang-codereviews
https://golang.org/cl/79260043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5f5e280e14efde7c576c282fc7ee3a2c734eb8c5
元コミット内容
Go言語の組み込み関数名が、その後に括弧 (
が続かない場合にはハイライトしないように、EmacsのGoモード(go-mode.el
)の挙動を変更します。Goでは組み込み関数名が予約語ではないため、変数名として使用されることがあり、特に「new」のような名前はローカル変数として頻繁に利用されます。この変更は、組み込み関数名と同じ名前を持つ非関数変数が誤ってハイライトされるのを防ぐことを目的としています。
変更の背景
Go言語の設計上の特徴として、new
やmake
といった組み込み関数(built-in functions)の名前が、言語の予約語(reserved words)ではないという点があります。これは、開発者がこれらの名前を通常の変数名や関数名として自由に利用できることを意味します。例えば、new
という名前の変数を宣言することはGo言語の文法上全く問題ありません。
しかし、EmacsのGoモード(go-mode.el
)は、以前のバージョンでは組み込み関数名を一律にハイライトする設定になっていました。このため、コード内で組み込み関数名と同じ名前の変数が使われている場合でも、それが関数呼び出しではないにもかかわらず、組み込み関数としてハイライトされてしまうという問題がありました。これは、特にnew
のように頻繁に変数名として使われる名前において、コードの可読性を損ねる原因となっていました。
このコミットは、このような誤ったハイライトを是正し、EmacsのGoモードがより正確にGoコードのセマンティクスを反映するようにするために行われました。具体的には、組み込み関数名が実際に「関数呼び出し」として使われている(つまり、その直後に(
が続く)場合にのみハイライトを行うように変更することで、この問題を解決しています。
前提知識の解説
Go言語の予約語と組み込み関数
Go言語には、特定の意味を持つキーワード(var
, func
, if
, for
など)が予約語として存在し、これらは変数名や関数名として使用できません。しかし、len
, cap
, new
, make
, panic
, recover
, print
, println
, complex
, real
, imag
, close
, delete
, append
, copy
といった組み込み関数は、予約語ではありません。これは、これらの名前を開発者が変数名や型名として再定義できることを意味します。例えば、var new int
のような宣言はGoでは有効です。この柔軟性が、Emacsのハイライトにおける問題の根源となっていました。
Emacsのfont-lock-mode
とシンタックスハイライト
Emacsのfont-lock-mode
は、ソースコードのシンタックスハイライト(構文強調表示)を提供する主要な機能です。これは、テキストバッファ内の特定のパターン(通常は正規表現)を検出し、それらに対応する「フェイス」(色、フォント、スタイルなどの視覚的属性のセット)を適用することで機能します。
font-lock-mode
は、各メジャーモード(例: go-mode
、python-mode
など)が定義するfont-lock-keywords
という変数に依存します。この変数には、ハイライトのルールを記述したリストが格納されており、各ルールは通常、正規表現とそれに適用するフェイスのペアで構成されます。
font-lock-keyword-face
:if
,for
,func
などの言語のキーワードに適用されるフェイス。font-lock-builtin-face
:new
,make
などの組み込み関数や組み込み型に適用されるフェイス。font-lock-function-name-face
: ユーザー定義の関数名に適用されるフェイス。
Emacs Lispの正規表現関連関数
Emacs Lispでは、正規表現を操作するためのいくつかの便利な関数が提供されています。
regexp-opt
: 複数の文字列のリストを受け取り、それらのいずれかにマッチする最適化された単一の正規表現を生成します。例えば、(regexp-opt '("foo" "bar"))
は\\(?:foo\\|bar\\)
のような正規表現を返します。これは、多数のキーワードを効率的にマッチさせる際に非常に有用です。go--regexp-enclose-in-symbol
:go-mode.el
内で定義されているヘルパー関数で、与えられた正規表現をシンボル(単語の境界)で囲むためのものです。これにより、例えば「new」が「renewal」の一部としてマッチするのを防ぎ、「new」という単語全体としてのみマッチするようにします。内部的には\\b
(単語境界)を使用していると考えられます。concat
: 複数の文字列を結合して新しい文字列を生成します。正規表現の構築において、動的にパターンを組み合わせる際に使用されます。
font-lock-keywords
のルールは、(REGEXP . FACE)
または(REGEXP CAPTURE-GROUP FACE)
のような形式を取ります。CAPTURE-GROUP
が指定されている場合、正規表現全体ではなく、指定されたキャプチャグループにマッチした部分にのみフェイスが適用されます。
技術的詳細
このコミットの核心は、go-mode.el
内のgo-font-lock-keywords
リストにおける、組み込み関数をハイライトするための正規表現の変更にあります。
変更前は、組み込み関数をハイライトするルールは以下のようになっていました。
(,(go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) . font-lock-builtin-face)
このルールは、go-builtins
(Goの組み込み関数名のリスト)から生成された正規表現(例: \b(?:new|make|len)\b
)にマッチするすべてのテキストにfont-lock-builtin-face
を適用していました。このため、var new int
のようなコードでも「new」がハイライトされてしまっていました。
変更後のルールは以下のようになります。
(,(concat "\\(" (go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) "\\)[[:space:]]*(") 1 font-lock-builtin-face)
この新しい正規表現は、以下の要素を結合して構築されています。
"\\("
: これは正規表現のキャプチャグループの開始を示すリテラルな(
です。(go--regexp-enclose-in-symbol (regexp-opt go-builtins t))
: これは変更前と同じく、new
やmake
などの組み込み関数名に単語境界でマッチする正規表現を生成します。この部分が最初のキャプチャグループの内容となります。"\\)[[:space:]]*("
: これは正規表現のキャプチャグループの終了を示すリテラルな)
、その後に0個以上の空白文字([[:space:]]*
)、そしてリテラルな開き括弧(
が続くパターンです。
この正規表現全体がマッチした場合、ルールは1 font-lock-builtin-face
と指定されています。これは、「正規表現全体がマッチした部分のうち、1番目のキャプチャグループにマッチした部分にのみfont-lock-builtin-face
を適用する」という意味です。
結果として、この新しいルールは「単語境界で囲まれた組み込み関数名」の直後に「0個以上の空白」と「開き括弧 (
」が続く場合にのみマッチし、そのマッチした組み込み関数名(1番目のキャプチャグループ)にハイライトを適用します。これにより、new(Type)
のような関数呼び出しはハイライトされますが、var new int
のような変数宣言はハイライトされなくなります。
コアとなるコードの変更箇所
misc/emacs/go-mode.el
ファイルの変更点です。
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -262,7 +262,7 @@ For mode=set, all covered lines will have this weight.\"
;; doesn\'t understand that
(append
`(,(go--regexp-enclose-in-symbol (regexp-opt go-mode-keywords t)) . font-lock-keyword-face)
- (,(go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) . font-lock-builtin-face)
+ (,(concat "\\(" (go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) "\\)[[:space:]]*(") 1 font-lock-builtin-face)
(,(go--regexp-enclose-in-symbol (regexp-opt go-constants t)) . font-lock-constant-face)
(,go-func-regexp 1 font-lock-function-name-face)) ;; function (not method) name
コアとなるコードの解説
変更は、go-mode.el
内のgo-font-lock-keywords
リストの一部である、組み込み関数(go-builtins
)のハイライトルールにあります。
元の行:
(,(go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) . font-lock-builtin-face)
この行は、go-builtins
リスト内のすべての組み込み関数名(例: new
, make
)を単語として認識し、それらすべてにfont-lock-builtin-face
を適用していました。
変更後の行:
(,(concat "\\(" (go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) "\\)[[:space:]]*(") 1 font-lock-builtin-face)
この行は、以下の点で大きく異なります。
concat
の使用: 複数の文字列を結合して新しい正規表現文字列を動的に構築しています。"\\("
と"\\)"
: これらは正規表現のリテラルな括弧(
と)
を表します。\
はエスケープ文字です。これにより、組み込み関数名自体がキャプチャグループ((
と)
で囲まれた部分)になります。"[[:space:]]*("
: これは、キャプチャグループの直後に「0個以上の空白文字」と「リテラルな開き括弧(
」が続くことを要求する正規表現パターンです。1 font-lock-builtin-face
: これが最も重要な変更点です。font-lock-mode
のルールにおいて、正規表現の後に数字が続く場合、その数字は「キャプチャグループのインデックス」を示します。ここでは1
が指定されているため、正規表現全体がマッチした場合でも、1番目のキャプチャグループ(つまり、組み込み関数名自体)にのみfont-lock-builtin-face
が適用されます。
この変更により、new
という単語がコード中に現れても、その直後に(
が続かない限り(つまり、関数呼び出しでない限り)、font-lock-builtin-face
によるハイライトは適用されなくなりました。これにより、Go言語のセマンティクスに合致した、より正確なシンタックスハイライトが実現されています。
関連リンク
- Go言語の組み込み関数に関する公式ドキュメント: https://go.dev/ref/spec#Predeclared_identifiers
- このコミットのGoレビューシステム上のリンク: https://golang.org/cl/79260043
参考にした情報源リンク
- GNU Emacs Manual - Font Lock Mode: https://www.gnu.org/software/emacs/manual/html_node/elisp/Font-Lock-Mode.html
- GNU Emacs Manual - Regexp functions: https://www.gnu.org/software/emacs/manual/html_node/elisp/Regexp-functions.html
- Emacs Lisp
regexp-opt
function documentation (Web search results provided by Gemini): https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHEIl6Ppm9nm6XDuZ9bko2Y1aYN-g-hR8RQVlXfWXaqH5jES8LcWwKfDQ4QNOQW4rAvedUq1c_oNC5nxoTv-5-noiGtY_XmJfFCyqJ8GRmOvFSowlqiDGWkELjRUP_znHRCXwXZgjfOcfv2QSJOXA8aNAz-BRhFjACjUONKO0_9z-m0 go-mode.el
source code (for context ongo--regexp-enclose-in-symbol
andgo-builtins
): https://github.com/golang/go/blob/master/misc/emacs/go-mode.el```markdown
[インデックス 18977] ファイルの概要
このコミットは、EmacsのGoモード(go-mode.el
)におけるシンタックスハイライトの挙動を修正するものです。具体的には、Go言語の組み込み関数名が変数名として使用されている場合に、誤って組み込み関数としてハイライトされる問題を解決します。これにより、「new」のような頻繁に変数名として使われる組み込み関数名が、関数呼び出しでない限りハイライトされないようになります。
コミット
commit 5f5e280e14efde7c576c282fc7ee3a2c734eb8c5
Author: Rui Ueyama <ruiu@google.com>
Date: Thu Mar 27 17:35:07 2014 -0400
misc/emacs: do not highlight built-in function if not followed by '('
Name of built-in function is not reserved word in Go, and you can
use it as variable name. "new" is often used as local variable, for
instance.
This patch is to apply font-lock-builtin-face only when built-in
function name is followed by '(', so that it doesn't highlight
non-function variable that happen to have the same name as built-in
function.
LGTM=dominik.honnef
R=golang-codereviews, dominik.honnef, adonovan
CC=golang-codereviews
https://golang.org/cl/79260043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5f5e280e14efde7c576c282fc7ee3a2c734eb8c5
元コミット内容
Go言語の組み込み関数名が、その後に括弧 (
が続かない場合にはハイライトしないように、EmacsのGoモード(go-mode.el
)の挙動を変更します。Goでは組み込み関数名が予約語ではないため、変数名として使用されることがあり、特に「new」のような名前はローカル変数として頻繁に利用されます。この変更は、組み込み関数名と同じ名前を持つ非関数変数が誤ってハイライトされるのを防ぐことを目的としています。
変更の背景
Go言語の設計上の特徴として、new
やmake
といった組み込み関数(built-in functions)の名前が、言語の予約語(reserved words)ではないという点があります。これは、開発者がこれらの名前を通常の変数名や関数名として自由に利用できることを意味します。例えば、new
という名前の変数を宣言することはGo言語の文法上全く問題ありません。
しかし、EmacsのGoモード(go-mode.el
)は、以前のバージョンでは組み込み関数名を一律にハイライトする設定になっていました。このため、コード内で組み込み関数名と同じ名前の変数が使われている場合でも、それが関数呼び出しではないにもかかわらず、組み込み関数としてハイライトされてしまうという問題がありました。これは、特にnew
のように頻繁に変数名として使われる名前において、コードの可読性を損ねる原因となっていました。
このコミットは、このような誤ったハイライトを是正し、EmacsのGoモードがより正確にGoコードのセマンティクスを反映するようにするために行われました。具体的には、組み込み関数名が実際に「関数呼び出し」として使われている(つまり、その直後に(
が続く)場合にのみハイライトを行うように変更することで、この問題を解決しています。
前提知識の解説
Go言語の予約語と組み込み関数
Go言語には、特定の意味を持つキーワード(var
, func
, if
, for
など)が予約語として存在し、これらは変数名や関数名として使用できません。しかし、len
, cap
, new
, make
, panic
, recover
, print
, println
, complex
, real
, imag
, close
, delete
, append
, copy
といった組み込み関数は、予約語ではありません。これは、これらの名前を開発者が変数名や型名として再定義できることを意味します。例えば、var new int
のような宣言はGoでは有効です。この柔軟性が、Emacsのハイライトにおける問題の根源となっていました。
Emacsのfont-lock-mode
とシンタックスハイライト
Emacsのfont-lock-mode
は、ソースコードのシンタックスハイライト(構文強調表示)を提供する主要な機能です。これは、テキストバッファ内の特定のパターン(通常は正規表現)を検出し、それらに対応する「フェイス」(色、フォント、スタイルなどの視覚的属性のセット)を適用することで機能します。
font-lock-mode
は、各メジャーモード(例: go-mode
、python-mode
など)が定義するfont-lock-keywords
という変数に依存します。この変数には、ハイライトのルールを記述したリストが格納されており、各ルールは通常、正規表現とそれに適用するフェイスのペアで構成されます。
font-lock-keyword-face
:if
,for
,func
などの言語のキーワードに適用されるフェイス。font-lock-builtin-face
:new
,make
などの組み込み関数や組み込み型に適用されるフェイス。font-lock-function-name-face
: ユーザー定義の関数名に適用されるフェイス。
Emacs Lispの正規表現関連関数
Emacs Lispでは、正規表現を操作するためのいくつかの便利な関数が提供されています。
regexp-opt
: 複数の文字列のリストを受け取り、それらのいずれかにマッチする最適化された単一の正規表現を生成します。例えば、(regexp-opt '("foo" "bar"))
は\\(?:foo\\|bar\\)
のような正規表現を返します。これは、多数のキーワードを効率的にマッチさせる際に非常に有用です。go--regexp-enclose-in-symbol
:go-mode.el
内で定義されているヘルパー関数で、与えられた正規表現をシンボル(単語の境界)で囲むためのものです。これにより、例えば「new」が「renewal」の一部としてマッチするのを防ぎ、「new」という単語全体としてのみマッチするようにします。内部的には\\b
(単語境界)を使用していると考えられます。concat
: 複数の文字列を結合して新しい文字列を生成します。正規表現の構築において、動的にパターンを組み合わせる際に使用されます。
font-lock-keywords
のルールは、(REGEXP . FACE)
または(REGEXP CAPTURE-GROUP FACE)
のような形式を取ります。CAPTURE-GROUP
が指定されている場合、正規表現全体ではなく、指定されたキャプチャグループにマッチした部分にのみフェイスが適用されます。
技術的詳細
このコミットの核心は、go-mode.el
内のgo-font-lock-keywords
リストにおける、組み込み関数をハイライトするための正規表現の変更にあります。
変更前は、組み込み関数をハイライトするルールは以下のようになっていました。
(,(go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) . font-lock-builtin-face)
このルールは、go-builtins
(Goの組み込み関数名のリスト)から生成された正規表現(例: \b(?:new|make|len)\b
)にマッチするすべてのテキストにfont-lock-builtin-face
を適用していました。このため、var new int
のようなコードでも「new」がハイライトされてしまっていました。
変更後のルールは以下のようになります。
(,(concat "\\(" (go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) "\\)[[:space:]]*(") 1 font-lock-builtin-face)
この新しい正規表現は、以下の要素を結合して構築されています。
"\\("
: これは正規表現のキャプチャグループの開始を示すリテラルな(
です。(go--regexp-enclose-in-symbol (regexp-opt go-builtins t))
: これは変更前と同じく、new
やmake
などの組み込み関数名に単語境界でマッチする正規表現を生成します。この部分が最初のキャプチャグループの内容となります。"\\)[[:space:]]*("
: これは正規表現のキャプチャグループの終了を示すリテラルな)
、その後に0個以上の空白文字([[:space:]]*
)、そしてリテラルな開き括弧(
が続くパターンです。
この正規表現全体がマッチした場合、ルールは1 font-lock-builtin-face
と指定されています。これは、「正規表現全体がマッチした部分のうち、1番目のキャプチャグループにマッチした部分にのみfont-lock-builtin-face
を適用する」という意味です。
結果として、この新しいルールは「単語境界で囲まれた組み込み関数名」の直後に「0個以上の空白」と「開き括弧 (
」が続く場合にのみマッチし、そのマッチした組み込み関数名(1番目のキャプチャグループ)にハイライトを適用します。これにより、new(Type)
のような関数呼び出しはハイライトされますが、var new int
のような変数宣言はハイライトされなくなります。
コアとなるコードの変更箇所
misc/emacs/go-mode.el
ファイルの変更点です。
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -262,7 +262,7 @@ For mode=set, all covered lines will have this weight.\"
;; doesn\'t understand that
(append
`(,(go--regexp-enclose-in-symbol (regexp-opt go-mode-keywords t)) . font-lock-keyword-face)
- (,(go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) . font-lock-builtin-face)
+ (,(concat "\\(" (go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) "\\)[[:space:]]*(") 1 font-lock-builtin-face)
(,(go--regexp-enclose-in-symbol (regexp-opt go-constants t)) . font-lock-constant-face)
(,go-func-regexp 1 font-lock-function-name-face)) ;; function (not method) name
コアとなるコードの解説
変更は、go-mode.el
内のgo-font-lock-keywords
リストの一部である、組み込み関数(go-builtins
)のハイライトルールにあります。
元の行:
(,(go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) . font-lock-builtin-face)
この行は、go-builtins
リスト内のすべての組み込み関数名(例: new
, make
)を単語として認識し、それらすべてにfont-lock-builtin-face
を適用していました。
変更後の行:
(,(concat "\\(" (go--regexp-enclose-in-symbol (regexp-opt go-builtins t)) "\\)[[:space:]]*(") 1 font-lock-builtin-face)
この行は、以下の点で大きく異なります。
concat
の使用: 複数の文字列を結合して新しい正規表現文字列を動的に構築しています。"\\("
と"\\)"
: これらは正規表現のリテラルな括弧(
と)
を表します。\
はエスケープ文字です。これにより、組み込み関数名自体がキャプチャグループ((
と)
で囲まれた部分)になります。"[[:space:]]*("
: これは、キャプチャグループの直後に「0個以上の空白文字」と「リテラルな開き括弧(
」が続くことを要求する正規表現パターンです。1 font-lock-builtin-face
: これが最も重要な変更点です。font-lock-mode
のルールにおいて、正規表現の後に数字が続く場合、その数字は「キャプチャグループのインデックス」を示します。ここでは1
が指定されているため、正規表現全体がマッチした場合でも、1番目のキャプチャグループ(つまり、組み込み関数名自体)にのみfont-lock-builtin-face
が適用されます。
この変更により、new
という単語がコード中に現れても、その直後に(
が続かない限り(つまり、関数呼び出しでない限り)、font-lock-builtin-face
によるハイライトは適用されなくなりました。これにより、Go言語のセマンティクスに合致した、より正確なシンタックスハイライトが実現されています。
関連リンク
- Go言語の組み込み関数に関する公式ドキュメント: https://go.dev/ref/spec#Predeclared_identifiers
- このコミットのGoレビューシステム上のリンク: https://golang.org/cl/79260043
参考にした情報源リンク
- GNU Emacs Manual - Font Lock Mode: https://www.gnu.org/software/emacs/manual/html_node/elisp/Font-Lock-Mode.html
- GNU Emacs Manual - Regexp functions: https://www.gnu.org/software/emacs/manual/html_node/elisp/Regexp-functions.html
- Emacs Lisp
regexp-opt
function documentation (Web search results provided by Gemini): https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHEIl6Ppm9nm6XDuZ9bko2Y1aYN-g-hR8RQVlXfWXaqH5jES8LcWwKfDQ4QNOQW4rAvedUq1c_oNC5nxoTv-5-noiGtY_XmJfFCyqJ8GRmOvFSowlqiDGWkELjRUP_znHRCXwXZgjfOcfv2QSJOXA8aNAz-BRhFjACjUONKO0_9z-m0 go-mode.el
source code (for context ongo--regexp-enclose-in-symbol
andgo-builtins
): https://github.com/golang/go/blob/master/misc/emacs/go-mode.el