[インデックス 17776] ファイルの概要
このコミットは、EmacsエディタのGo言語モード (go-mode.el
) における、関数呼び出しの構文ハイライトに関するバグ修正です。具体的には、misc/emacs/go-mode.el
ファイルが変更されています。このファイルは、EmacsでGo言語のコードを編集する際に、シンタックスハイライトやインデントなどの機能を提供するEmacs Lispスクリプトです。
コミット
このコミットは、EmacsのGoモードにおいて、(foo)(bar)
のような形式が、直前に単語文字がある場合に誤って関数呼び出しとしてハイライトされる問題を修正します。これにより、Go言語のコードがEmacsでより正確に表示されるようになります。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/47bb44fd5bee504cd53e1e9e1d1c36e28a15e94f
元コミット内容
misc/emacs: don't treat (foo)(bar) as a function call when preceded by a word character.
Fixes #6531.
R=adonovan
CC=golang-dev
https://golang.org/cl/14523043
変更の背景
Emacsのgo-mode
は、Go言語のコードを解析し、関数名やキーワードなどを適切にハイライトする機能を提供しています。このハイライトは、Emacs Lispの正規表現を用いて行われます。
このコミットが行われる前は、go-mode
の関数呼び出しを検出する正規表現に問題がありました。具体的には、(foo)(bar)
のような形式が、その直前に単語文字(アルファベット、数字、アンダースコアなど)がある場合に、誤って関数呼び出しとして認識され、ハイライトされてしまうというバグが存在しました。これは、Go言語の構文ではこのような形式が関数呼び出しではないため、ユーザーにとっては誤解を招く表示となっていました。
この問題は、Go言語のIssueトラッカーで #6531 として報告されており、このコミットはその問題を修正するために作成されました。
前提知識の解説
Emacs Lisp (Elisp)
Emacs Lispは、Emacsエディタの拡張言語です。Emacsのほとんどの機能はEmacs Lispで書かれており、ユーザーはEmacs Lispを使ってEmacsをカスタマイズしたり、新しい機能を追加したりすることができます。go-mode.el
もEmacs Lispで書かれたファイルであり、Go言語の編集モードを定義しています。
font-lock-mode
font-lock-mode
は、Emacsの主要なシンタックスハイライトシステムです。このモードが有効になっていると、Emacsは開いているファイルのコンテンツを解析し、定義された正規表現パターンに基づいて異なるフォントや色でテキストをハイライトします。プログラミング言語のモード(例: go-mode
)は、通常、font-lock-mode
を利用してコードのシンタックスハイライトを実現します。
Emacs Lispにおける正規表現
Emacs Lispでは、正規表現は文字列として表現されます。一般的な正規表現の構文に加え、Emacs Lisp独自の拡張も存在します。
\
:エスケープ文字。例えば\(
はリテラルの(
を意味します。[:word:]
:単語文字クラス。アルファベット、数字、アンダースコアにマッチします。[:multibyte:]
:マルチバイト文字クラス。日本語などのマルチバイト文字にマッチします。[^...]
:否定文字クラス。...
内の文字以外の文字にマッチします。*
:直前の要素が0回以上繰り返されることにマッチします。+
:直前の要素が1回以上繰り返されることにマッチします。[[:space:]]
:空白文字にマッチします。
font-lock-function-name-face
font-lock-function-name-face
は、Emacsのfont-lock-mode
で使用されるフェイス(表示属性のセット)の一つです。このフェイスが適用されたテキストは、通常、関数名として認識され、特定のフォントや色でハイライトされます。
技術的詳細
このコミットの核心は、go-mode.el
内の正規表現の変更です。変更された行は、括弧で囲まれた関数呼び出し(例: (func)(args)
)を検出するための正規表現を定義しています。
元の正規表現は以下のようでした。
(,(concat "(\\\\(" go-identifier-regexp "\\\\))[[:space:]]*(" ") 1 font-lock-function-name-face)) ;; bracketed function call
この正規表現は、(
で始まり、その後に (
と go-identifier-regexp
(Goの識別子にマッチする正規表現)、そして )
が続き、さらに )
と [[:space:]]*
(0個以上の空白文字)、そして (
が続くパターンにマッチしようとしていました。
問題は、この正規表現が (foo)(bar)
のようなパターンを、その直前に何らかの文字がある場合でも関数呼び出しとして誤認識してしまう点にありました。例えば、x(foo)(bar)
のようなコードがあった場合、x
の後に続く (foo)(bar)
が関数呼び出しとしてハイライトされてしまう可能性がありました。
修正後の正規表現は以下のようになりました。
(,(concat "[^[:word:][:multibyte:]](\\\\(" go-identifier-regexp "\\\\))[[:space:]]*(" ") 1 font-lock-function-name-face)) ;; bracketed function call
この変更のポイントは、正規表現の先頭に [^[:word:][:multibyte:]]
が追加されたことです。
[^...]
は否定文字クラスを意味します。[:word:]
は単語文字(アルファベット、数字、アンダースコア)にマッチします。[:multibyte:]
はマルチバイト文字(日本語など)にマッチします。
したがって、[^[:word:][:multibyte:]]
は「単語文字でもマルチバイト文字でもない文字」にマッチします。これにより、この正規表現は、括弧で囲まれた関数呼び出しのパターンが、単語文字やマルチバイト文字の直後に続かない場合のみにマッチするようになります。
これにより、x(foo)(bar)
のようなケースでは、x
が単語文字であるため、この正規表現はマッチせず、誤ったハイライトが回避されます。一方で、行頭や空白文字の後に (foo)(bar)
のようなパターンが続く場合は、適切にマッチし、ハイライトされるようになります。
go-identifier-regexp
は、Go言語の識別子(変数名、関数名など)にマッチする正規表現であり、font-lock-function-name-face
は、マッチした部分を関数名としてハイライトするための表示属性です。
コアとなるコードの変更箇所
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -249,7 +249,7 @@ For mode=set, all covered lines will have this weight.\"\n
(if go-fontify-function-calls
`((,(concat \"\\\\(\" go-identifier-regexp \"\\\\)[[:space:]]*(\") 1 font-lock-function-name-face) ;; function call/method name
- (,(concat \"(\\\\(\" go-identifier-regexp \"\\\\))[[:space:]]*(\") 1 font-lock-function-name-face)) ;; bracketed function call
+ (,(concat \"[^[:word:][:multibyte:]](\\\\(\" go-identifier-regexp \"\\\\))[[:space:]]*(\") 1 font-lock-function-name-face)) ;; bracketed function call
`((,go-func-meth-regexp 1 font-lock-function-name-face))) ;; method name
`(\
コアとなるコードの解説
変更は misc/emacs/go-mode.el
ファイルの249行目付近にあります。
元のコード:
(,(concat "(\\\\(" go-identifier-regexp "\\\\))[[:space:]]*(" ") 1 font-lock-function-name-face)) ;; bracketed function call
この行は、bracketed function call
(括弧で囲まれた関数呼び出し)を検出するための正規表現を定義していました。concat
関数は複数の文字列を結合して一つの正規表現文字列を作成します。この正規表現は、(
で始まり、その後に (
と go-identifier-regexp
、そして )
が続き、さらに )
と空白文字、そして (
が続くパターンにマッチします。
変更後のコード:
(,(concat "[^[:word:][:multibyte:]](\\\\(" go-identifier-regexp "\\\\))[[:space:]]*(" ") 1 font-lock-function-name-face)) ;; bracketed function call
この変更では、正規表現の先頭に [^[:word:][:multibyte:]]
が追加されました。これは「単語文字でもマルチバイト文字でもない文字」にマッチする否定文字クラスです。
この修正により、正規表現は、括弧で囲まれた関数呼び出しのパターンが、単語文字やマルチバイト文字の直後に続かない場合にのみマッチするようになります。これにより、x(foo)(bar)
のような、Go言語の構文では関数呼び出しではないパターンが誤ってハイライトされるのを防ぎます。
この変更は、EmacsのGoモードにおけるシンタックスハイライトの正確性を向上させ、ユーザーがGoコードをより快適に編集できるようにすることを目的としています。
関連リンク
- Go言語の変更リスト: https://golang.org/cl/14523043
- Go言語のIssue #6531 (このコミットで修正された問題): 検索結果からは直接的なリンクが見つかりませんでしたが、コミットメッセージに記載されています。
参考にした情報源リンク
- この解説は、提供されたコミット情報 (
./commit_data/17776.txt
) と、一般的なEmacs Lispおよび正規表現の知識に基づいて作成されました。追加の外部情報源は使用していません。