前のエントリーからの続きである。
Font Lock modeの追加ルールを設定するには、font-lock-add-keywordsという関数を使う。ルールは、正規表現のパターンとそれにマッチする部分に適用するface、の組み合わせとして定義する。モード毎の設定が基本だが、現在のバッファのみの設定もできる。
font-lock-add-keywords関数の書式は、
(font-lock-add-keywords モード名 ルールのリスト)である。モード名をnilにすると、現在のバッファに対する設定になる。
ルールの書式はいくつかの種類がある。
- a. MATCHER
- b. (MATCHER . SUBEXP)
- c. (MATCHER . FACENAME)
- d. (MATCHER . HIGHLIGHTER)
- e. (MATCHER HIGHLIGHTER1 HIGHLIGHTER2 ...)
- f. (eval . FORM)
a.とb.はfaceを指定しない場合(font-lock-keyword-faceが使われる)、c.はfaceのみを指定する場合(MATCHERにマッチする部分全体に適用される)、f.は正規表現の代わりにfaceの変更対象を検索する関数を別途定義する場合に使用するもので、a.〜c.はd.で代用でき、d.はe.で代用でき、f.は特殊なので、1つ覚えるならe.の形式が良いと思う。
HIGHLIGHTERの書式は、主に(SUBEXP FACENAME [OVERRIDE])である。SUBEXPは正規表現に()を使う場合の何番目の()の部分かの意味で、全体なら0とする。OVERRIDEは別のルールが適用済でも適用するかどうかである。
例えば、次のようにすると、java-modeの時に、TABの部分がunderline、2バイトスペースや行末の空白部分がtrailing-whitespaceというface(これらはfaces.elに定義されている)になる。
実行前(font-lock-add-keywords 'java-mode '( ("\t" . 'underline) (" " . 'trailing-whitespace) ("[ \t]+$" . 'trailing-whitespace) ))
実行後
次のようにすると、java-modeに限らず、全モードで有効になる。
なお、上の3行目の部分をnilでなくmajor-modeと書いている例をよく見かけるが、そのようにすると、バッファが開く度にfont-lock-add-keywordsが実行され、font-lock-keywords-alistが肥大化してしまうので、nilの方がいいと思う。(defadvice font-lock-mode (before my-font-lock-mode ()) (font-lock-add-keywords nil ;現在のバッファのみ '(("\t" 0 'underline append) (" " . 'trailing-whitespace) ("[ \t]+$" . 'trailing-whitespace) ))) (ad-enable-advice 'font-lock-mode 'before 'my-font-lock-mode) (ad-activate 'font-lock-mode)
HIGHLIGHTERの書式には、他に、MATCHERがマッチした後の行末までの部分を対象に、別のパターンの検索を行う、anchoredな形式がある。
ANCHORED-MATCHERを使う場合は、HIGHLIGHTERの書式が(ANCHORED-MATCHER PRE-FORM POST-FORM SUBEXP-HIGHLIGHTERS...)となる。PRE-FORMは、このANCHORED-MATCHERの検索が始まる前に実行され、POST-FORMは、行末までこのANCHORED-MATCHERが探された後に実行される。これを使うと、以下のようなことができる。
■コメント部分の特定キーワードの表示を変える
筆者は試行錯誤中のコードをコメントアウトして残す癖があり、作成中のコードには使用中のコードの3〜4倍のコードがコメントに存在することが普通にあるが、デフォルトのルールでは大体それらがコメント色1色になってしまうので、たまに痛い時がある。
実行前(font-lock-add-keywords nil '( (";" ("face\\|frame" nil ;PRE-FORM (goto-char (match-end 0)) ;POST-FORM: pointを";"の直後に戻す (0 font-lock-type-face t)) ("default" nil ;PRE-FORM nil ;POST-FORM (0 font-lock-builtin-face t)) )))
実行後(コメント中の"face", "frame", "default"に色が付いている)
■CやJavaの"if"の後の"="を警告表示にする
実行前(add-hook 'c-mode-common-hook '(lambda () (font-lock-add-keywords major-mode '( ("\\<if\\>" ("[^<>=]\\(=\\)[^=]" nil nil (1 font-lock-warning-face)) ))) ))
実行後
過去にそんなミス滅多に無いだろ、みたいなことを書いたが、筆者はExcel VBAを書いた直後だとやってしまうことに気付いた。
■"\x1b\x24\x42"〜"\x1b\x28\x42"とその間の16進数に着色する
実行前(font-lock-add-keywords nil '( ("\\\\x\\(1b\\)\\\\x\\(24\\)\\\\x\\(42\\).*?\\\\x\\(1b\\)\\\\x\\(28\\)\\\\x\\(42\\)" (1 font-lock-function-name-face t) ;"1b"の部分 (2 font-lock-function-name-face t) ;"24"の部分 (3 font-lock-function-name-face t) ;"42"の部分 (4 font-lock-constant-face t) ;"1b"の部分 (5 font-lock-constant-face t) ;"28"の部分 (6 font-lock-constant-face t) ;"42"の部分 ("[0-9a-f]" ;ANCHORED (progn ;PRE-FORM (goto-char (match-end 3)) ;3つ目の後に移動 (match-beginning 4)) ;4つ目の先頭までに限る nil ;POST-FORM (0 font-lock-type-face t)) )))
実行後
ANCHORED-MATCHERは、プログラマー魂を刺激するのである。
kano
(defadvice font-lock-mode (before my-font-lock-mode ())
(font-lock-add-keywords
nil ;現在のバッファのみ
'(("\t" 0 'underline append)
(" " . 'trailing-whitespace)
("[ \t]+$" . 'trailing-whitespace)
)))
(ad-enable-advice 'font-lock-mode 'before 'my-font-lock-mode)
(ad-activate 'font-lock-mode)
↑指定通りのものを書くと、下記のエラーが出ますね。
Lisp nesting exceeds `max-lisp-eval-depth'