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

[インデックス 14831] ファイルの概要

このコミットは、EmacsエディタのGo言語モード(go-mode.el)におけるシンタックステーブルとコメント処理の改善を目的としています。具体的には、*(アスタリスク)と/(スラッシュ)のシンタックス定義を修正し、改行文字のコメント終了文字としての扱いを変更し、さらにコメントの開始スキップパターンをより正確に定義することで、Goコードの編集体験を向上させています。

コミット

  • コミットハッシュ: f14f458640c2444c77a68a79744338880cc80e3c
  • 作者: Sameer Ajmani sameer@golang.org
  • コミット日時: 2013年1月9日(水)10:26:34 -0500

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/f14f458640c2444c77a68a79744338880cc80e3c

元コミット内容

misc/emacs: update go-mode syntax table and comment handling as
suggested by pkleiweg.

Fixes #3471.

R=adonovan, pkleiweg, rsc
CC=golang-dev
https://golang.org/cl/7060056

変更の背景

この変更は、Go言語のEmacsモード(go-mode)における既存のシンタックスハイライトとコメント処理の不正確さを修正するために行われました。コミットメッセージにある Fixes #3471 は、GoプロジェクトのIssueトラッカーにおける特定のバグ報告に対応していることを示唆しています。

Go言語では、/* ... */ のようなブロックコメントと // のような行コメントが使用されます。Emacsのシンタックス解析は、これらのコメント構造を正しく認識し、ハイライトやインデント、コメントアウト機能などを適切に動作させる必要があります。

元のgo-mode.elでは、*/ がコメントの一部として誤って扱われたり、改行がコメントの終了を意味すると定義されていたり、コメントの開始位置をスキップするロジックが不十分であったりした可能性があります。これにより、ユーザーがGoコードを編集する際に、シンタックスハイライトが崩れたり、コメントアウトが意図通りに動作しないなどの問題が発生していたと考えられます。

pkleiweg氏からの提案に基づき、これらの問題を解決し、より正確で使いやすいgo-modeを提供することが変更の背景にあります。

前提知識の解説

EmacsとEmacs Lisp

Emacsは、高度にカスタマイズ可能なテキストエディタであり、その機能のほとんどはEmacs Lisp(Elisp)というプログラミング言語で記述されています。ユーザーはElispを使ってEmacsの動作を拡張したり、新しい機能を追加したりできます。

Emacsのシンタックステーブル

Emacsは、各バッファ(開いているファイル)に対して「シンタックステーブル」と呼ばれるデータ構造を持っています。このテーブルは、各文字がどのようなシンタックス特性を持つかを定義します。例えば、文字が単語の一部なのか、空白なのか、コメントの開始文字なのか、文字列の区切り文字なのか、といった情報です。

  • modify-syntax-entry: このElisp関数は、シンタックステーブル内の特定の文字のシンタックス特性を変更するために使用されます。
    • 第一引数: 変更する文字(例: ?* はアスタリスク文字)。
    • 第二引数: 新しいシンタックス特性を表す文字列。例えば、. は「句読点」、23 は「コメントの開始文字(/** のように、コメントの2番目の文字)」、1456 は「コメントの開始文字(/ のように、コメントの1番目の文字)」、b は「コメントの終了文字」などを意味します。
    • 第三引数: 変更を適用するシンタックステーブル(通常は現在のバッファのシンタックステーブル)。

Emacsのコメント処理

Emacsは、プログラミング言語のコメントを扱うための様々な変数と関数を提供しています。

  • comment-start: コメントの開始文字列を定義する変数(例: // /*)。
  • comment-end: コメントの終了文字列を定義する変数(例: */)。
  • comment-use-syntax: この変数がnilに設定されている場合、Emacsはコメントの開始と終了を判断する際に、シンタックステーブルの情報を直接使用するのではなく、comment-startcomment-endの値に依存します。
  • comment-start-skip: コメントの開始文字列の前にスキップすべき文字(空白など)を定義する正規表現。これは、comment-dwim(Do What I Mean for comments)のようなコメント関連のコマンドが、行頭の空白を無視してコメントを挿入したり削除したりする際に使用されます。

Go言語のコメント

Go言語では、以下の2種類のコメントが使われます。

  • 行コメント: // から行末まで。
  • ブロックコメント: /* から */ まで。

技術的詳細

このコミットは、go-mode.elファイル内の以下の主要な領域に焦点を当てています。

  1. シンタックステーブルの修正:

    • go-mode-syntax-table関数内で、*/ のシンタックス定義が変更されています。
    • 変更前は、* がコメントの2番目または3番目の文字(. 23)として、/ がコメントの1番目、2番目、4番目、6番目の文字(. 1456 または . 124b)として定義されていました。これは、/**/ のようなブロックコメントの開始・終了文字としての役割を考慮したものでしたが、Go言語の文脈では過剰または不正確だった可能性があります。
    • 変更後は、両方とも単なる句読点(.)として定義されています。これにより、Emacsがこれらの文字をコメントの特殊な一部としてではなく、通常の演算子や区切り文字として扱うようになります。コメントの認識は、より高レベルのコメント処理ロジックに委ねられることになります。
    • \n(改行)がコメントの終了文字(> b)として定義されていた行が削除されました。Goの行コメントは改行で終わりますが、Emacsの一般的なコメント処理では、行コメントの終了は通常、シンタックステーブルではなく、comment-startcomment-endの設定や、行末の概念によって処理されます。この変更は、Emacsのコメント処理の内部的な整合性を高めるものです。
  2. go-mode-whitespace-p 関数の修正:

    • この関数は、特定の文字がGoモードにおける空白文字であるかどうかを判定します。
    • 変更前は、改行文字(?\n)も空白として扱われていました。
    • 変更後は、シンタックステーブルで空白として定義されている文字((= (char-syntax char) ?\ ))のみを空白として扱います。これにより、改行文字の扱いがより厳密になり、シンタックステーブルの定義と一致するようになります。
  3. コメント処理変数の設定:

    • go-mode-hook関数内で、コメント関連の変数が追加設定されています。
    • (set (make-local-variable 'comment-use-syntax) nil): これは非常に重要な変更です。comment-use-syntaxnilに設定することで、Emacsはコメントの開始と終了を判断する際に、シンタックステーブルの情報を直接使用するのではなく、comment-startcomment-endの値に依存するようになります。これにより、Goのコメント形式(///* ... */)がより正確に認識されるようになります。
    • (set (make-local-variable 'comment-start-skip) "\\([ \\t]*\\)// "): comment-start-skipは、コメントの開始文字列の前にスキップすべき文字を定義する正規表現です。この正規表現 \\([ \\t]*\\)// は、「0個以上のスペースまたはタブの後に // が続くパターン」を意味します。これにより、comment-dwimなどのコマンドが、行頭のインデントを考慮して//コメントを正しく挿入・削除できるようになります。

これらの変更は、EmacsがGoコードのシンタックスをより正確に解析し、コメント関連の機能をより適切に提供するための基盤を強化します。

コアとなるコードの変更箇所

--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -33,8 +33,8 @@
      ;; Operators (punctuation)
      (modify-syntax-entry ?+  "." st)
      (modify-syntax-entry ?-  "." st)
-    (modify-syntax-entry ?*  ". 23" st)                                    ; also part of comments
-    (modify-syntax-entry ?/ (if (featurep 'xemacs) ". 1456" ". 124b") st)  ; ditto
+    (modify-syntax-entry ?*  "." st)
+    (modify-syntax-entry ?/  "." st)
      (modify-syntax-entry ?%  "." st)
      (modify-syntax-entry ?&  "." st)
      (modify-syntax-entry ?|  "." st)
@@ -50,9 +50,6 @@
      (modify-syntax-entry ?`  "." st)
      (modify-syntax-entry ?\\ "." st)

-    ;; Newline is a comment-ender.
-    (modify-syntax-entry ?\\n "> b" st)
-
      st)
    "Syntax table for Go mode.")

@@ -552,9 +549,8 @@ token on the line."
           (not (looking-at go-mode-non-terminating-keywords-regexp)))))))


  (defun go-mode-whitespace-p (char)
-  "Is newline, or char whitespace in the syntax table for go."
-  (or (eq char ?\\n)\n-      (= (char-syntax char) ?\\ )))\n+  "Is char whitespace in the syntax table for go."
+  (eq 32 (char-syntax char)))

  (defun go-mode-backward-skip-comments ()
    "Skip backward over comments and whitespace."
@@ -573,7 +569,7 @@ token on the line."
     		((go-mode-in-comment)
     		 ;; move point to char preceeding current comment
     		 (goto-char (1- (car (go-mode-in-comment)))))\n-\t\t\n+\n     		;; not in a comment or whitespace? we must be done.
     		(t (setq loop-guard nil)
     		   (forward-char 1)))))))\n@@ -727,6 +723,8 @@ functions, and some types.  It also provides indentation that is
    ;; Comments
    (set (make-local-variable 'comment-start) "// ")
    (set (make-local-variable 'comment-end)   "")
    +  (set (make-local-variable 'comment-use-syntax) nil)\n+  (set (make-local-variable 'comment-start-skip) "\\([ \\t]*\\)// ")

コアとなるコードの解説

  1. modify-syntax-entry の変更:

    • - (modify-syntax-entry ?* ". 23" st)
    • - (modify-syntax-entry ?/ (if (featurep 'xemacs) ". 1456" ". 124b") st)
    • + (modify-syntax-entry ?* "." st)
    • + (modify-syntax-entry ?/ "." st)
      • */ のシンタックス定義から、コメント関連のフラグ(23, 1456, 124b)が削除され、単なる句読点(.)として扱われるようになりました。これにより、Emacsがこれらの文字をコメントの開始・終了の一部として自動的に解釈するのではなく、より明示的なコメント処理ロジックに依存するようになります。これは、Go言語のコメント構造をより正確に反映するための変更です。
  2. 改行文字のシンタックス定義の削除:

    • - (modify-syntax-entry ?\\n "> b" st)
      • 改行文字(\n)がコメントの終了文字(> b)として定義されていた行が削除されました。Goの行コメントは改行で終わりますが、Emacsのコメント処理の内部的な整合性を高めるために、この明示的な定義が不要と判断された可能性があります。
  3. go-mode-whitespace-p 関数の修正:

    • - (or (eq char ?\\n)\n- (= (char-syntax char) ?\\ )))\n+ (eq 32 (char-syntax char)))
      • go-mode-whitespace-p関数から、改行文字(?\n)を明示的に空白として扱うロジックが削除されました。代わりに、シンタックステーブルで空白として定義されている文字((= (char-syntax char) ?\ ))のみを空白として扱います。これは、改行の扱いをより厳密にし、シンタックステーブルの定義と一致させるための変更です。
  4. コメント処理変数の追加設定:

    • + (set (make-local-variable 'comment-use-syntax) nil)
      • comment-use-syntax変数をnilに設定することで、Emacsはコメントの開始と終了を判断する際に、シンタックステーブルの情報を直接使用するのではなく、comment-startcomment-endの値に依存するようになります。これにより、Goのコメント形式(///* ... */)がより正確に認識されるようになります。
    • + (set (make-local-variable 'comment-start-skip) "\\([ \\t]*\\)// ")
      • comment-start-skip変数を正規表現 \\([ \\t]*\\)// に設定しました。この正規表現は、「0個以上のスペースまたはタブの後に // が続くパターン」にマッチします。これにより、comment-dwimなどのコメント関連コマンドが、行頭のインデントを考慮して//コメントを正しく挿入・削除できるようになります。

これらの変更は、EmacsのGoモードがGo言語のシンタックスとコメント規則をより正確に理解し、それに基づいてより適切な編集支援を提供するための重要な改善です。

関連リンク

  • Go CL (Code Review): https://golang.org/cl/7060056
  • Go Issue #3471: このコミットが修正したIssueの詳細は、GoプロジェクトのIssueトラッカーで #3471 を検索することで確認できます。

参考にした情報源リンク