Results tagged “Emacs”

(Emacs) Hi-lock modeを使う

前のエントリーからの続きである。

Hi-lock modeは、Font Lock modeのバッファ毎の追加ルールを手軽にインタラクティブに設定できるI/Fである。
Font Lock modeを有効にしていると、C-sで検索すると、マッチする部分がハイライト表示される。それが便利なので、ハイライト表示するためだけにいちいちC-sで検索することがあるのは筆者だけではないであろう。検索を抜けるとハイライトが解除されてしまい、またハイライトするために検索してしまう。そんな時はHi-lock modeである。

M-x highlight-regexp(既にHi-lock modeならC-x w h)を実行して、ハイライトするパターンを入力すると、マッチする箇所がハイライトされる。何かマッチすると、自動的にHi-lock modeが有効になる。もしFace Lock modeがOFFだと、自動的にFace Lock modeもONになる。

・実行前(Hi-lock modeでない)

・"x"をhighlight-regexpした状態(Hi-lock mode、mode-lineに"Hi"が追加されているのに注目)

検索パターンを単にxとするのでなく\<x\>とすると、単語の一部でなく単独で現れるxを対象にできる。
・"\<x\>"をhighlight-regexpした状態

続けてC-x w hして別のパターンをハイライトすることもできる。
・さらに"\<y\>"をhighlight-regexpした状態

C-x w l(highlight-lines-matching-regexp)を使うと、パターンを含む行全体をハイライトできる。
・さらに"draw"をhighlight-lines-matching-regexpした状態

1つのパターンのハイライトを解除するには、C-x w r(unhighlight-regexp)を実行する。全て解除するなら、M-x hi-lock-modeとしてHi-lock modeをOFFにすれば良い。

C-x w b(hi-lock-write-interactive-patterns)とすると、そのモードに定義されたコメント形式で、現在のハイライト設定が挿入される。
・上の状態から続けてhi-lock-write-interactive-patternsを実行した状態

c-modeなら、/*〜*/で括られたものが挿入される。これを残しておくと、次にこのファイルでHi-lock modeがONになった時に同じハイライトがなされる。

ハイライトを解除した後で、コメントに書かれたHi-lock設定を読み込むには、C-x w i(hi-lock-find-patterns)とする。

コメント形式のHi-lock設定はFont Lock modeのルールと同じなので、これを書き換えると、結構複雑な設定も書ける。
・"draw"のルールを書き換え中("draw_に続く単語を赤太字、"draw_"より後ろの"r"をピンクでハイライトするつもり)

・C-x w i(hi-lock-find-patterns)を実行した状態

前のエントリーからの続きである。

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)
(参考:font-lock-add-keywordsのhelpと、Emacs LispのinfoのFont Lock ModeのSearch-based Fontificationの項)
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に限らず、全モードで有効になる。

(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)
なお、上の3行目の部分をnilでなくmajor-modeと書いている例をよく見かけるが、そのようにすると、バッファが開く度にfont-lock-add-keywordsが実行され、font-lock-keywords-alistが肥大化してしまうので、nilの方がいいと思う。


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))
)))
実行前

実行後

Emacsのfaceとは、フォント名や太字/斜体/下線といったフォント属性や文字色といったフォント設定をまとめたものであり、バッファ内のテキストの一部分に適用する事ができる。Emacsでソースコードを開くと、予約語やコメント部分や文字列部分に色が付くが、これは、そういう色で文字を表示するというfaceがそれぞれ定義されており、それらの部分にそれぞれのfaceが適用されている状態である。

Emacsでフォントの設定をしていると、時々faceという単語が出てくる。意味がわからないままでもフォントの設定はできたが、特にX resourcesでフォントセットの定義をすると、何に使われるのかわからなくても、default, bold, italic, bold-italicの4つ分を定義させられる。これらのフォントも、テキストにそういうfaceが適用されると使用されるが、そういうfaceが適用されないと、使われる事がない。
筆者はC, Java, Perl, Pythonなどのプログラム言語のソースコードをEmacsで開くことがあるが、キーワードや特定パターンに色が付くのはよく見るが、太字や斜体になるのは滅多に見ない。目にするのは、helpやinfoを開いた時くらいである。最も多く編集するのはテキストファイルであるが、text-modeでは色も付かない。

せっかく設定したものがほとんど使われず、しかもどうやれば使えるのかがわからないのは、気になる。そこで、faceの使い方を少し調べることにした。


Emacsで開いているテキストの一部分のfaceを変える方法としては、主に
・facemenu-*関数を使う
・Font Lock modeを使う
・Hi-lock modeを使う
・Highlight Changes modeを使う
がある。他にも、Emacs23ならtext-scale-*関数があったり、色々あるようであるが、Emacs22のinfoですぐ見つかるのはこれくらいである。(10年くらい前にEmacsを使っていた時はhilit19.elというのにお世話になったが、今ではobsoleteのようである)


■facemenu.elを使う
範囲選択してfacemenu-set-*関数を実行すれば、その範囲にfaceを適用できる。

これは、Carbon Emacs 22.3で3文字ずつM-o o(facemenu-set-face)してみた例である。適用したfaceは順に、highlight, lazy-highlight, link, match, query-replace, custom-button, custom-button-pressed, custom-face-tagである。加えて、"abc"はM-o bでboldに、"def"はM-o iでitalicにしてある。


これは、後述のfacify-iroha-regionマクロで、1文字ずつ異なるfaceを適用してみたものである。

キャラクターベースのリモート端末でも、これくらいカラフルになる。

(EmacsはDebianのemacs21-nox、ターミナルソフトはPuTTY、設定はほぼvt100のdefault)

しかし、Font Lock modeがONになっていると使えない。昨今のPCの性能では、もはやFont Lock modeをOFFにして使用することは少ないと思うので、あまり使えなさそうである。
また、これによって設定されたfaceはバッファローカルであり、編集したテキストと共に保存される訳ではないので、あまりこれによるテキスト装飾を手作業でがんばる意味は無い。失われることを前提に一時的に装飾するのに使うものである。
ただ、上のようにマクロで好き勝手に装飾したい時は、使えそうである。


■font-lock-mode.elを使う
何らかのソースコードを開いて自動的に色が付くなら、まず間違いなく、Font Lock modeが有効になっている。予め設定されたルールに従って自動的にfaceが適用されるモードである。
大体、c-modeとかperl-modeとかの言語毎のモードに入ると、自動的にその言語特有のルールが追加される。
有効でない場合は、.emacs等に

(global-font-lock-mode t)
と書けば有効になる。

追加ルールの設定については、長くなったので、次のエントリーに書く。


■Hi-hock modeを使う
長くなったので、次の次のエントリーに書く。


■Highlight Changes modeを使う
変更部分に自動的にfaceが適用されるモードである。ファイルを開いてからM-x highlight-changes-modeとするか、.emacs等に

(global-highlight-changes 1)
と書くと有効になる。

次の画像は、テキストファイルの編集にHighlight Changes modeを使った画面の例である。

黒以外の部分が、M-x highlight-changes-modeを実行してから変更した部分である。色違いは、highlight-changes-rotate-facesで世代を切り替えたものである。
highlight-changes-previous-changeやhighlight-changes-next-change等の関数を使うと、前の変更部分や次の変更部分にジャンプできるようである。
facemenu.elを使った場合と同様、これによる色はファイルに保存される訳ではない。

保存されていない変更があるかどうかはmode lineの**でわかるし、変更履歴として保存される訳でもないので、使い所が難しい気がする。Font Lock modeを使っていると、編集中の部分に本来の着色がされなくなり、スペルミスの点検ができなくなったりするので、却って不便である。Font Lock modeの効果が少ないText modeで長文の一部を修正する時は便利かも知れない。

ちょっとドット絵を作りたくなったが、適当なツールが思い付かなかった。Windowsの「ペイント」しか思い付かなかったが、それだけのためにWindowsを起動するのは負けのような気がした。
手元で動いているのはMacBookである。「ペイント」に相当するくらいのアプリケーションはプレインストールされているような気がするが、筆者はMacに疎いのである。少なくとも「アプリケーション」の中を眺める限り、それだとわかるものは無い。GIMPはインストールしているのだが、マウスが無いのでしんどそうだし、それだけのために重いGIMPを起動するのも負けのような気がした。

目の前ではCarbon Emacsが動いていた。ふと、Emacs Lispで(if (looking-at ...))とかやれば、1キーで白黒反転するマクロが簡単に書けるのではないか…と思って、やってみたら、思ったより使い易かったので、もう少し進めてみた。

doteditor.el(漢字コードはEUC)

■起動方法
M-x load-fileまたは(load-file)で上のファイルを開き、M-x dot-editor-mode

■キーバインド
SPC: カーソル位置の□と■の反転
M-r: 選択領域の□と■の反転
M-c: 指定サイズの矩形領域を□で作成
M-e: 選択領域をビットマップとみなして16進数に変換したものを、選択領域の直後に挿入
M-d: 選択領域の16進数を□と■のビットマップに変換したものを、選択領域の直後に挿入
M-p: 選択領域の16進数をPBM形式の画像データにしたものを、tmp.pbmというバッファに作成 & image-modeが使用可能ならそれでプレビュー

■使用例1
1. M-cとし、width, heightに32, 24を入力
 → □が32x24個挿入される
2. 編集

□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
□□□□□□□□□□□□■■■■■■■■□□□□□□□□□□□□
□□□□□□□□□■■■■■■■■■■■■■■□□□□□□□□□
□□□□□□□□■■■■■■■■■■■■■■■■□□□□□□□□
□□□□□□□■■■■■□■■■■■■□■■■■■□□□□□□□
□□□□□□■■■■■■■■■■■■■■■■■■■■□□□□□□
□□□□□□■■■■■■■■■■■■■■■■■■■■□□□□□□
□□□□□■■■■■■■■■□□□□■■■■■■■■■□□□□□
□□□□■■■■■■■■■■■■■■■■■■■■■■■■□□□□
□□□□■■■■■■■■■■■■■■■■■■■■■■■■□□□□
□□□■■■■■■■■■□□□□□□□□■■■■■■■■■□□□
□□□■■■■■■■■□□□□□□□□□□■■■■■■■■□□□
□□■■■■■■■□□□□□□□□□□□□□□■■■■■■■□□
□■■■■■■■□□□□□□□□□□□□□□□□■■■■■■■□
□■■■■■■■□□□□□□□□□□□□□□□□■■■■■■■□
□■■■■■■□□□□□□□□□□□□□□□□□□■■■■■■□
■■■□■■■□□□□□□□□□□□□□□□□□□■■■□■■■
■■■□■■■□□□□□□□□□□□□□□□□□□■■■□■■■
■■■□■■■□□□□□□□□□□□□□□□□□□■■■□■■■
■■□□□■■■□□□□□□□□□□□□□□□□■■■□□□■■
■■□□□■■□■■■■■■□□□□■■■■■■□■■□□□■■
□□□□□□□■□□□□□□■■■■□□□□□□■□□□□□□□
□□□□□□□□■■■■■■□□□□■■■■■■□□□□□□□□

3. ビットマップ全体を選択し、M-e
00000000
00000000
000ff000
007ffe00
00ffff00
01f7ef80
03ffffc0
03ffffc0
07fc3fe0
0ffffff0
0ffffff0
1ff00ff8
1fe007f8
3f8001fc
7f0000fe
7f0000fe
7e00007e
ee000077
ee000077
ee000077
c70000e3
c6fc3f63
0103c080
00fc3f00

4. 16進データを選択し、M-pで表示確認

5. 16進データを保存

■使用例2
1. 16進テキストのビットマップデータを読み込む

00, 00, 00, 00,
00, 07, f8, 00,
00, 1f, fe, 00,
00, 3f, ff, 00,
00, 7f, ff, c0,
00, ff, e7, f0,
01, ff, ff, fc,
01, ff, ff, e0,
03, ff, ff, e0,
03, ff, ff, d0,
03, ff, ff, d0,
07, ff, ff, 10,
07, ef, be, 08,
07, ef, be, 08,
07, df, bc, 08,
07, df, 78, 08,
07, df, 78, 08,
0f, de, f8, 10,
0f, dd, f0, 10,
1f, dd, f0, 10,
1f, ed, f0, 20,
3d, f3, e0, 40,
38, f3, e1, e0,
60, 3f, ff, f0,

2. データ全体を選択し、M-d
(0-9, a-f, A-F以外の文字は無視されるのでカンマはそのままで良い、"0x"があるとその"0"が展開対象になるので注意)
□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
□□□□□□□□□□□□□■■■■■■■■□□□□□□□□□□□
□□□□□□□□□□□■■■■■■■■■■■■□□□□□□□□□
□□□□□□□□□□■■■■■■■■■■■■■■□□□□□□□□
□□□□□□□□□■■■■■■■■■■■■■■■■■□□□□□□
□□□□□□□□■■■■■■■■■■■□□■■■■■■■□□□□
□□□□□□□■■■■■■■■■■■■■■■■■■■■■■■□□
□□□□□□□■■■■■■■■■■■■■■■■■■■■□□□□□
□□□□□□■■■■■■■■■■■■■■■■■■■■■□□□□□
□□□□□□■■■■■■■■■■■■■■■■■■■■□■□□□□
□□□□□□■■■■■■■■■■■■■■■■■■■■□■□□□□
□□□□□■■■■■■■■■■■■■■■■■■■□□□■□□□□
□□□□□■■■■■■□■■■■■□■■■■■□□□□□■□□□
□□□□□■■■■■■□■■■■■□■■■■■□□□□□■□□□
□□□□□■■■■■□■■■■■■□■■■■□□□□□□■□□□
□□□□□■■■■■□■■■■■□■■■■□□□□□□□■□□□
□□□□□■■■■■□■■■■■□■■■■□□□□□□□■□□□
□□□□■■■■■■□■■■■□■■■■■□□□□□□■□□□□
□□□□■■■■■■□■■■□■■■■■□□□□□□□■□□□□
□□□■■■■■■■□■■■□■■■■■□□□□□□□■□□□□
□□□■■■■■■■■□■■□■■■■■□□□□□□■□□□□□
□□■■■■□■■■■■□□■■■■■□□□□□□■□□□□□□
□□■■■□□□■■■■□□■■■■■□□□□■■■■□□□□□
□■■□□□□□□□■■■■■■■■■■■■■■■■■■□□□□

3. 編集
以下略

とうとう、我が部屋は、日光が入らないようにカーテンを閉めてエアコンを付けっ放しにしても、35℃を下回らなくなった。
この部屋がアパートの最上階の西の端の部屋で、建物がコンクリート造りのため、部屋自体が熱を持ってしまっているらしい。床や壁を触ると、ぬくいのである。天井は触っていないが、おそらくヒーターと化しているであろう。
クーラーを動かしっ放しにしてやっと外と同じくらいの気温である。どちらかというと、殺す気かという感じである。
いや、元々殺さない気はないのであろう。一般論として、建物というものが人の生命を守るとは限らない。部屋も凶器になり得るはずである。

従って、頭が働かず、材料が揃わないので、ブログが更新できない。
でも何か書きたくなったので、軽めに、最近やったEmacsのカスタマイズについて書くことにする。

Emacs Lispを書くようになって、C-h fのdescribe-function(関数の説明を見るコマンド)やC-h vのdescribe-variable(変数の説明を見るコマンド)をよく使うようになった。カーソルをelispの関数名や変数名の上に置いてC-h fとすると、デフォルトのでその関数名や変数名が候補になるのが便利である。それに慣れると、カーソル位置にある単語をキルリング(Xで言うセレクション、Windowsで言うクリップボード)にコピーするキー操作が無いことに気付いた。
WindowsやMacだと大抵マウスのダブルクリックでそれができるので、結構無意識にやりたくなる操作である。

単語の先頭に移動するキーはあるので、
M-b (単語の先頭にジャンプ)
C-SPC (マークセット)
M-f (単語の末尾にジャンプ)
M-w (コピー)
とすると一応できるのだが、この8キーは結構打ちにくい。

筆者はこれをよく行うので、そういうことをする関数をキーに割り当てようとしたのだが、そういう関数が見つからなかった。そんな訳で、次のような設定を追加した。

(defun kill-ring-save-current-word ()
"Save current word to kill ring as if killed, but don't kill it."
(interactive)
(save-excursion
(forward-char)
(backward-sexp)
(let ((pos (point)))
(forward-sexp)
(kill-ring-save pos (point)))
))
(global-set-key "\C-xw" 'kill-ring-save-current-word)

これで、C-x wでその位置にある単語をコピーできるようになる。
カーソルが移動することもないので、例えば、これをコピーして別の所に貼り付けたいが、コピーした後に今のカーソル位置で少し編集したい、という時にも邪魔にならない。

Emacsで使える色々なX Windowのフォントを、実際にEmacsで表示したらどうなるかを一覧形式で見てみたくなって、自動的にフォントを切り替えながらウィンドウイメージを画像ファイルに保存するEmacs Lispのコードを作った。

コード(elisp)
結果の抜粋
 "tt-数字"の先はTrueType(要xft、Emacs23で表示したもの)
 "tt-noaa"とあるのはTrueTypeの中のアンチエイリアスされないフォント(xft不要、Emacs22で表示したもの)
 それ以外はビットマップフォント

上記コードを実行して、


本日は晴天で酷暑あるいは氷雪でブリザードなり。

のようなバッファを表示した状態でM-x captureなどとして実行すると、次々にフォントが切り替わって画像ファイルに保存されていく。ウィンドウイメージのキャプチャーにはImageMagickのimportコマンドを使用している。
キャプチャー画像からサンプル文字列だけを抜き出すのは、同じくImageMagickのconvertコマンドを使って、シェルスクリプトで一括変換した。
例:
foreach i (*.tif)
convert -crop 700x80+60+30 $i -trim `basename $i .tif`.png
end

Trim(autocrop)できる範囲を切り出せるように、文字列部分の上下左右にたっぷりと余白を取っておくのがコツである。

キャプチャー画像を.tifで保存しているのは、convertで-trimする時に画像圧縮によるノイズに邪魔されないようにするためである。もう少しがんばって、elispで文字列の表示位置を特定してそこだけキャプチャーするようにできればかなりいい感じなのだが、そこまでするためのelispの関数を調べ切れなかった。(というか、なんとなく不可能な気がする。文字列部分を特定して切り出すImageMagickのコマンドをelispに埋め込む方が有望かも)

次に、X resourcesでEmacsのフォントセットの定義を行ってみる。
今回は、Emacs22用の定義を~/.Xdefaultsに書いた。~/.Xresourcesでも良い。筆者の環境では.XdefaultsはEmacs起動の度に、.XresourcesはXセッション起動時のみ読み込まれ、両方ある場合は.Xdefaultsが無視される。全ユーザー共通の設定なら/usr/X11R6/lib/X11/app-defaults/以下のファイルに書いても良い。それらを以下、リソースファイルと呼ぶ。

説明の前に、リソースファイルでのEmacsのフォントセットの定義の例を示す。(ascii文字は東雲(しののめ)フォント、日本語は東風(こち)フォントにする例)

Emacs.Fontset-0: -shinonome-gothic-medium-r-normal--16-*-*-*-*-*-fontset-kochi16g,\
katakana-jisx0201:-kochi-gothic-medium-r-normal--16-*-*-*-*-*-jisx0201.*-*,\
japanese-jisx0208:-kochi-gothic-medium-r-normal--16-*-*-*-*-*-jisx0208.*-*
Emacs.Fontset-1: -shinonome-mincho-medium-r-normal--16-*-*-*-*-*-fontset-kochi16m,\
japanese-jisx0208:-kochi-mincho-medium-r-normal--16-*-*-*-*-*-jisx0208.*-*,\
katakana-jisx0201:-kochi-mincho-medium-r-normal--16-*-*-*-*-*-jisx0201.*-*

1つのフォントセットの定義は次のようなフォーマットで書く。
Emacs.Fontset-[n]: (asciiのフォント名)-fontset-(フォントセット名),\
 (文字セット名): (フォント名),\
 (文字セット名): (フォント名)...

まずフォント名であるが、筆者のFreeBSD 7.3のEmacs22はxftをサポートしていないので、フォント名は全て、ハイフンで区切られた14個のフィールドからなる、XLFD(X Logical Font Definition)表記である。XftをサポートしているEmacsではxftのフォント名を用いた別の書き方があるのかも知れないが、筆者は今の所知らない。Xftをサポートしている筆者のEmacs23でも、elispのx-list-fontsを実行するとEmacsで使用可能なフォントのリストがXLFD形式で得られるので、X Window上のEmacsのフォント設定において、XLFDと縁が切れることは当分無いと思う。
幸いにして、フォント指定時はXLFDのほとんどのフィールドにワイルドカードが使えるので、全てのフィールドを理解する必要は無い。大体、
-(フォント名)-(ファミリー)-(medium/bold)-(r/i)-normal-*-(サイズ)-*-*-*-*-*-(文字セット名)-(Encoding)
で十分と思う。mediumは通常、boldは太字、rは通常、iは斜体(Italic)である。文字セット名以降の部分は、iso8859-1ならそのまま(1がEncodingの部分)だが、jisx0208の場合はjisx0208.1983-0のようにjisx0208の後にピリオドとさらなる情報があり、さらにEncodingが0だったり1だったり2だったりするので、面倒ならjisx0208.*-*と指定するのが良い。

1行目の[n]の部分は、0から始まる連番でなければならない。Emacs.Fontset-1以上しか無ければ1つも有効にならないし、0,1,2と4以上しか無ければ0,1,2の分しか有効にならない。(過去には連番でなくてもいい方法があったような気がするが、Emacs22のInfoには見つけられなかった)

1行目のasciiのフォント名の部分は、"iso8859-1"の代わりに"fontset-(フォントセット名)"と書く。これにより、新たなフォントセットが定義される。実際のasciiのフォントは、"fontset-(フォントセット名)"の部分を"iso8859-1"に置換されたものが使われる。
iso8859-1に限らず、"fontset-(フォントセット名)"の部分を*-*にして該当する全ての(Emacsがサポートする)文字セットのフォントが、そのフォントセットのデフォルトとして使われるようである。例えば、

Emacs.Fontset-2: -shinonome-gothic-medium-r-normal--16-*-*-*-*-*-fontset-shinonome16

と書くと、iso-8859-1のみでなく、jisx0208やjisx0201についても東雲フォントが使われるようになる。
従って、1行目のasciiのフォント設定だけで足りることもある。その場合は、2行目以降と1行目のカンマ以降は不要である。

最初の例(東雲フォントと東風フォントの例)のように、特定の文字セットに対してasciiのフォントとは別のフォントを指定する時は、"(文字セット名): (フォント名)"という形式で、カンマで区切って書く。次の行に書く場合は(XLFDなら普通次の行に書くであろう)、行末に"\"(バックスラッシュ)を置いて次の行に書く。
Emacsがサポートする文字セット名は、M-x list-character-setsとすると調べられる(Emacs22以前ならM-x describe-fontsetの出力でもわかる)。
同じ行の\の後(改行コードの前)には何も書いてはいけない(直後の改行文字をエスケープするためのものであるため)。カンマの前にはスペースを入れてはいけないが、カンマの後ろなら良い。コロンも同様である。

リソースファイルへのフォントセットの定義が済んだら、それが読み込まれる状態で(自動的に読み込まれないならXを再起動するなりxrdb -mergeするなりして)Emacsを起動して確認する。最初からデフォルトのフォントを定義したフォントセットにするのは、フォントセットの定義に誤りがあるとEmacsが起動しないことがあるので、避けた方がいいと思う。
Emacsのウィンドウ上でShift+左クリックでポップアップメニューを開き、"Fontset"のメニューに定義したフォントセットが出てこなければ失敗である。
Fontsetメニューに出てきて選択可能でも、成功しているとは限らない。定義に問題があると、フォントが切り替わっても、フォントセットの定義がそのまま使われず、自動的にフォントセットが再構築されてしまうことがある。定義通りになっているかどうかは、そのフォントセットに切り替え、定義に関係する全文字セットの最低1文字ずつを含むファイルを開いた後、M-x describe-fontsetして確認する。もし、1行目に出てくるフォントセット名が、定義した名前でなく"fontset-default"や"fontset-auto??"となっていると、失敗している可能性が高い。そこはクリアしていても、一部の文字セットのフォントが正しく読まれていないかも知れないので、[]内のワイルドカードが展開されたフォント名をそれぞれ確認すると良いと思う。

1行目のmedium/bold、r/iの別は、フォントセット名と共に、フォントセットを区別する情報として用いられる。同じフォントセット名に対して、medium-r, bold-r, medium-i, bold-iのそれぞれのフォントセットを定義することが可能であり、そのようにすると、同じバッファにレギュラー体とイタリック体、細字と太字が混在する時も、それらの全てのフォントセットを設定することができる(1つのバッファに指定できるフォントセット名は1つであり、そのフォントセット名のmedium-rのフォントとかbold-rのフォントとかが使われる)。
残念ながら、medium/boldやr/iの部分を*にして、(medium/bold)-(r/i)の4通りのフォントセットを1つのEmacs.Fontset-[n]にまとめて定義することはできないようである。従って、同じフォントセット名で(medium/bold)-(r/i)の4通りを定義するには、Emacs.Fontset-[n]が4つ必要になる。
例:

Emacs.Fontset-20: -kappa-*-medium-r-normal--20-*-*-*-*-*-fontset-kappa
Emacs.Fontset-21: -kappa-*-medium-i-normal--20-*-*-*-*-*-fontset-kappa
Emacs.Fontset-22: -kappa-*-bold-r-normal--20-*-*-*-*-*-fontset-kappa
Emacs.Fontset-23: -kappa-*-bold-i-normal--20-*-*-*-*-*-fontset-kappa

今回、筆者がFreeBSD 7.3のpackagesで手当り次第に日本語のフォントをインストールして、Emacs22で使えそうなフォントを、リソースファイルにフォントセット定義として色々登録してみたものを、参考までに添付する。
リソースファイルへの記述例
Emacs.Fontset-0〜3は、intlfontsというパッケージに含まれるサンプルをそのまま使用したものである。それ以降は、筆者が主に16〜20ドットを使うので、その範囲のサイズを重点的に定義している。

参考:Emacs InfoのDefining fontsetsの章

次に、日本語とかASCIIとかの文字集合の単位で別々のフォントを設定してみる。
日本語と英語しか使わなくても、日本語文字の分しか無いフォントとか、ASCII文字の分しか無いフォントとかを使う場合、そういうことが必要になることがある。アラビア語とかハングルとか、日英以外の文字も表示したいのにフォントが自動的に読み込まれないような時も、必要になる。
Xftが有効なEmacs23を使う場合、fontconfigの設定が適切であれば、そのような事態はあまり起こらないような気がするし、起こってもEmacs側で対処するよりfontconfig側で直すべき話になるかも知れないが、筆者の環境ではEmacs22が現役であるので、そのような事態は基本的に発生するのである。

Emacsのフォントは文字セット(文字集合、charset)とフォント名の組で管理される。その文字セットとフォント名の組のリストをフォントセットと言う。文字セットは、JIS X 0208とかiso8859-1等の単位で指定するのが基本であるが、Emacs23では文字コードの範囲で指定することもできる。Emacsで定義されている文字セットは、M-x list-character-setsするとわかる。日本語文字とASCII文字に関係するのは以下のものである。
・ascii: 言うまでもなくASCII文字
・japanese-jisx0208: 日本語、大体第1〜2水準漢字を含む
・japanese-jisx0212: 大体第3〜4水準漢字
・japanese-jisx0213: JIS X0208 + JIS X0212
・katakana-jisx0201: 日本語のいわゆる半角カナ、Emacs23ではjisx0201
・unicode-bmp: Unicodeの基本面(0群0面、UCS-2で表現できる範囲)(Emacs23のみ)
半角カナを使わなければ、asciiとjapanese-jisx0208のフォントを設定すれば十分である。
フォントセットを意識せずにset-frame-fontとかで1つのフォントのみを指定してフォントを変更しても、裏では何らかのフォントセットが自動的に構成される。

現在使用されているフォントセットは、M-x describe-fontsetでcurrent frameを指定すると表示される。これの出力形式は、Emacs22と23とで全然異なる。Emacs22の方が単純でわかり易い。Emacs23の方がきめ細かな設定ができるので仕方ないのだろうが、非常にわかりづらい。困ったものである。Emacs22で実行すると、以下のような感じになる。

Fontset: -etl-*-medium-r-normal-*-16-*-*-*-*-*-fontset-16
CHARSET or CHAR RANGE FONT NAME
--------------------- ---------
ascii -etl-fixed-medium-r-normal--16-160-72-72-c-80-iso8859-1
[-ETL-fixed-bold-r-normal--16-160-72-72-C-80-ISO8859-1]
[-ETL-Fixed-Medium-R-Normal--16-160-72-72-C-80-ISO8859-1]
latin-iso8859-1 -etl-fixed-*-iso8859-1
latin-iso8859-2 -*-iso8859-2
latin-iso8859-3 -*-iso8859-3
(中略、以下抜粋)
katakana-jisx0201 -*-jisx0201-*
[-Shinonome-Gothic-Medium-R-Normal--16-150-75-75-C-80-JISX0201.1976-0]
japanese-jisx0208 -*-jisx0208.1990-*
japanese-jisx0212 -*-jisx0212-*
[-Misc-Fixed-Medium-R-Normal--16-150-75-75-C-160-JISX0212.1990-0]
japanese-jisx0213-1 -*-jisx0213.2000-1
[-Misc-Fixed-Medium-R-Normal--16-150-75-75-C-160-JISX0213.2000-1]
japanese-jisx0213-2 -*-jisx0213.2000-2
[-Misc-Fixed-Medium-R-Normal--16-150-75-75-C-160-JISX0213.2000-2]

文字セットの右側が指定したフォント名、[]内が実際にロードされたフォント名である。ちなみに、上の出力は、FreeBSD7.3でintlfontsというpackageをインストールして、intlfontsのdocに書かれている設定をそのまま使った状態である。

Emacs23だとこれを読み取るのは困難であるが、同じような意味の設定をすれば十分である。Emacs23だとiso10646とか"unicode-bmp"とかの名前もあって、これを使ってもまあ悪くない。

フォントセットの定義は、Xリソースでも.emacsでもできる。
今回は、Emacs23用に.emacsでやってみた。(筆者のXリソースはEmacs22に合わせている為)
まずは、フォントセットを定義せずに、自動的に作られたフォントセットのフォントを変更してみる。

(when (>= emacs-major-version 23)
(when window-system
;;(1)ASCIIフォント設定
(setq default-frame-alist
(append '(
(font . "Sazanami Mincho:style=Regular:size=22") ;ASCII文字のフォント
(width . 80) ;文字が大きいので、ついでにウィンドウサイズ変更
(height . 24)
)
default-frame-alist))

;;(2)最初のフレームのサイズ変更
(set-frame-size (selected-frame) 80 24)

;;(3)日本語フォント変更
(add-hook 'window-setup-hook
'(lambda ()
;;日本語→VLゴシック
(set-fontset-font (frame-parameter nil 'font)
'japanese-jisx0208
(font-spec :family "VL Gothic"))
;;全角カタカナのみ、さざなみ明朝に戻す
(set-fontset-font (frame-parameter nil 'font)
;;'(#x3041 . #x309f) ;ひらがな
'(#x30a0 . #x30ff) ;カタカナ
(font-spec :family "Sazanami Mincho"))
;;半角カナ→Kappaのイタリック体
(set-fontset-font (frame-parameter nil 'font)
'jisx0201
"-kappa-*-medium-i-*-*-20-*-*-*-*-*-jisx0201.1976-*")
))
))

結果

ASCIIフォントの設定はset-frame-font、現在のフォントセットの一部フォント変更は(set-fontset-font (frame-parameter nil 'font) ...)でできる((frame-parameter nil 'font)は現在のフレームのフォントセット名を返す)ので、それらを単に並べればできそうなものであるが、色々ややこしいことがあってそれではうまくいかなかったので、色々工夫してみた。
(1)のASCIIフォント設定は、default-frame-alistに登録するのでなくset-frame-fontを使うと、少なくとも筆者の環境では、.emacs実行後に(おそらくface設定の処理でdefault-frame-alist等のフォントに)また変えられてしまう。もし変えられなくても、C-x 5 2で開いたフレームにはフォント設定が引き継がれなくなってしまう。initial-frame-alistに登録するのでも同様の問題がある。
(2)のウィンドウサイズ変更は、せっかくdefault-frame-alistに書いても、筆者の環境では、最初のフレームについてはこの後default-frame-alistのwidthやheightが反映されない(fontは反映される)ので、仕方なく加えた。initial-frame-alistに登録してもだめだった。
(3)は、set-fontset-fontをすぐに実行すると、この時点ではまだdefault-frame-alistに登録したフォントに切り替わっていないため、無意味になってしまう(おそらくfontset-startupに対する設定になってしまう)ので、強引だがwindow-setup-hookに登録して後で実行させるようにした。

(face-set-after-frame-default)
(set-fontset-font ...)

とすれば、default-frame-alistのフォントに切り替わり、それに対するフォントセットも作られるようで、(3)と同じ結果が得られることを確認したが、どうせ後でdefault-frame-alistのフォントへの切替が発生するし、筆者がfaceの動作を理解していないので、今回は見送った。
なお、(1)でフォントサイズを22ドットとやたらでかくしているのは、さざなみフォントが20ドット以下だとアンチエイリアスされない(20ドット以下はビットマップフォントが内蔵されているため、TrueTypeでなくそちらが使われる)為である。同様に、東風フォントだと16ドット以下と20ドットがアンチエイリアスされない。
また、筆者の環境(FreeBSD 7.3のデフォルトのfontconfig)では、さざなみフォントの場合は(3)をしなくても日本語や半角カナが表示されない訳ではない。


さて、実際にフォントが切り替わってから現在のフレームのフォントセットに対して変更を加えるのは、set-fontset-fontだけで済むのである意味単純だが、あまり美しくない。上のように苦しくなってwindow-setup-hookのコールバックでフォントを切り替えるのでは敗北感すら漂う汚さである。そもそも、普通は先にフォントセットを定義してからフォントをそのフォントセットに切り替えるものである。Xのリソースでの設定ではそのようにしかできない。

そこで、次にフォントセットの定義をやってみる。フォントセットの定義は、create-fontset-from-ascii-fontしてからset-fontset-fontするのが定跡である。次のように書くと、上の例と同じ設定になる。

(when (>= emacs-major-version 23)
(when window-system
;;(4)フォントセット"fontset-test0"の定義
(create-fontset-from-ascii-font
"Sazanami Mincho:style=Regular:size=22" nil "test0")
;;日本語→VLゴシック
(set-fontset-font "fontset-test0"
'japanese-jisx0208
(font-spec :family "VL Gothic"))
;;全角カタカナのみ、さざなみ明朝に戻す
(set-fontset-font "fontset-test0"
'(#x30a0 . #x30ff) ;カタカナ
(font-spec :family "Sazanami Mincho"))
;;半角カナ→Kappaのイタリック体
(set-fontset-font "fontset-test0"
'jisx0201
"-kappa-*-medium-i-*-*-20-*-*-*-*-*-jisx0201.1976-*")

;;(5)フォント設定
(setq default-frame-alist
(append '(
(font . "fontset-test0")
(width . 80)
(height . 24)
)
default-frame-alist))

;;(2)最初のフレームのサイズ変更
(set-frame-size (selected-frame) 80 24)
))


(2)の部分は不満だが、かなりマシになった。

参考:Emacs InfoのDefining fontsetsの章

筆者は普段EmacsをX Windowで使わない。そもそもX Windowを使っていないからだ。使うのはFreeBSDやLinuxで動くEmacsだが、WindowsからTelnetやSSHでアクセスしているので、キャラクターベースである。マウスも使わ(え)ない。
昔はパソコンの性能に対してWindowsが重かったので、FreeBSD+X Windowを愛用していたが、その時はEmacsも重かったので、Emacsはktermやrxvtの中でしか使わなかった。
そのさらに昔、大学の研究室にはX Windowの端末があったので、X上のEmacsを使おうと思えば使えたのだが、Emacsを知ると同時にTelnetも知ってしまい、EmacsをXで使う利点よりも、コンピューターを遠隔操作することの魅力に取り憑かれてしまったので、やはりEmacsは文字ベースの端末で使っていた。
だから、X上のEmacsのカスタマイズというのはほとんどやったことがなかった。

時代は変わって、Windows上の仮想マシンでX Windowがスムーズに動くようになった。先月、訳あって、仮想マシンにFreeBSD 7.3をインストールした。XもEmacsもインストールした。ところで、筆者は昨年より再びEmacsを使い始め、今Emacsがマイブームなのである。そのため、XのEmacsのカスタマイズもやり始めている。大学の研究室でEmacsに出会ってからの1x年に渡る旧知の仲、しかも歳を重ねて英語もEmacs Lispもそれなりに読めるようになった今、もはや何もつまずくことはなかろうと高を括っていたら、フォントの設定にコテンパンにやられてしまった。何ゆえかくも複雑なのであろうか。

たかがフォントの設定に膨大な時間を費やしてしまったので、調べまくったことをここにメモしていくことにする。

●Emacs 22と23の違い
Xのフォントに関して、Emacsのバージョン22と23とでは大きな違いがある。バージョン23ではXftがサポートされ、アンチエイリアスされた滑らかなフォントが表示できるのである。また、フォント名として、あの長ったらしいXLFD名のみでなく、Xftの短い名前も使える。

・通常のビットマップフォントの例
(東雲ゴシック 16ドット)
-shinonome-gothic-medium-r-normal-*-16-150-75-75-c-160-jisx02081990-0
-shinonome-gothic-medium-r-normal-*-16-150-75-75-c-80-iso8859-1
(Ayuゴシック 20ドット)
-ayu-gothic-medium-r-normal-*-20-190-75-75-c-200-jisx02081990-0
ayu-gothic-medium-r-normal--20-190-75-75-c-100-iso8859-1

・アンチエイリアスされたTrueTypeフォントの例(M+2VM+IPAG circle 14pt)
M+2VM+IPAG circle
M+2VM+IPAG circle

しかしながら、その分ちょっと重い。

●Emacs23起動後のフォント変更方法
Shift+左クリックで開くポップアップメニューの"Change Buffer Font..."を選ぶと、フォント選択ダイアログが出てくる。
ダイアログの下半分のプレビューエリアには、Xのセレクションを使って、日本語をペーストすることもできる。(別プロセスのウィンドウの日本語文字列を左ボタンでドラッグして選択し、ここに中ボタンでペーストする等)

しかし、これで設定したフォントはバッファローカルであり、終了時に保存されないどころか、別のファイルを開くと引き継がれない。

●Emacs23のフォントの設定方法(X resourcesを使う場合)
Emacsのフォントの設定は.emacsの中にも書けるが、.emacsに書くには考慮することが色々あって結構難しい。それに対し、Xのリソースに登録する方法は、無難で手軽である。
例えば、~/.Xdefaultsに次のように記述する。

Emacs.font: M+2VM+IPAG circle

"M+2VM+IPAG circle"は、筆者のお気に入りのフォントの名前である。
M+2VM+IPAG circleにすると、ウィンドウサイズが横に広がりすぎるので、ウィンドウサイズも指定する。
Emacs.geometry: 40x32+30+0

ウィンドウサイズが40×32文字、表示位置が(30,0)という意味である。

フォントサイズを変更するには、フォントの高さをpt単位で指定する。
Emacs*attributeHeight: 140
設定する値は実際のpt数の10倍である。14ptなら140、10.5ptなら105とする。
"*"でごまかすのでなく、default faceのattributeHeightだけ指定すれば良いはずなのだが、書き方がわからなかった。("Emacs.default.attributeHeight: 140"では効かなかった)

万一、デフォルト起動でEmacsのXftが有効にならない場合は、

Emacs.FontBackend: xft

を含めておくと良いらしい。

余談だが、Xのリソース設定を~/.Xdefaultsに書いている場合は、アプリケーションの起動時に毎回自動的に読み込まれるので、ここに書いてEmacsを起動すると、設定したフォントで起動する。Xのセッション起動時に読み込まれる~/.Xresourcesに書いている場合は、追記した内容をすぐに反映させるには、次のコマンドを実行すると、Xのリソースに登録される。

xrdb -merge ~/.Xresources

●Emacs23のフォントの設定方法(.emacsに書く場合)
筆者の環境では、たまにEmacs23は重いと感じることがあるため、Emacs22をデフォルトにしている。そのため、XのリソースをEmacs23の設定にしたくない。そのような場合は、.emacsにてフォントを設定することもできる。

フレームのフォントの変更はset-frame-font、フレームのサイズの変更はset-frame-sizeでできる。また、ありがちな問題として、これらの設定はC-x 5 2で別のフレームを開いた時に引き継がれないということがあるので、こういうのはdefault-frame-alistに登録する必要がある。ついでにEmacsのバージョンもチェックするようにして、

(when (>= emacs-major-version 23)
(when window-system
(set-frame-font "M+2VM+IPAG circle") ;最初のフレームのフォント設定
(set-frame-size (selected-frame) 40 32) ;最初のフレームのサイズ
(setq default-frame-alist ;以後のフレームの設定
(append '(
(width . 40)
(height . 32)
(font . "M+2VM+IPAG circle")
) default-frame-alist))
))

でOKである。

筆者の環境では、ここでset-frame-fontをしなくても、この後の処理で最初のフレームのフォントがdefault-frame-alistに書いたフォントになることが確認できたので、set-frame-fontは外した。フレームのサイズについては、このように明示的にset-frame-sizeしないと変わらなかった。

フォントサイズの設定は、詳細を省くが

(set-face-attribute 'default nil :height 140)

のようにするとできる。これはフレームに対する設定ではなく、"default" faceに対する設定である。.emacsにこれを書いても、最初のフレームに関してはfaceの設定は済んだ後なので、最初のフレームについては、face設定の再読み込みが必要である。
(when (>= emacs-major-version 23)
(when window-system
;;(set-frame-font "M+2VM+IPAG circle") ;最初のフレームのフォント設定
(set-frame-size (selected-frame) 40 32) ;最初のフレームのサイズ
(setq default-frame-alist ;以後のフレームの設定
(append '(
(width . 40)
(height . 32)
(font . "M+2VM+IPAG circle")
) default-frame-alist))
(set-face-attribute 'default nil ;default faceの設定
:height 140 ;フォント高さ(/10pt)
)
(face-set-after-frame-default (selected-frame)) ;;最初のフレームのface再読み込み(NG)
))

…が、筆者の環境ではすぐにフォントサイズが戻ってしまった。Emacsの起動時には.emacsが実行された後も色々な処理が走るので、そのどこかで別の値に再設定されてしまうのだろう。その処理が特定できなかったので、今回はEmacs起動の最後の方で実行されるwindow-setup-hookに登録して乗り切ることにした。
(when (>= emacs-major-version 23)
(when window-system
;;(set-frame-font "M+2VM+IPAG circle") ;最初のフレームのフォント設定
(set-frame-size (selected-frame) 40 32) ;最初のフレームのサイズ
(setq default-frame-alist ;以後のフレームの設定
(append '(
(width . 40)
(height . 32)
(font . "M+2VM+IPAG circle")
) default-frame-alist))
(set-face-attribute 'default nil ;default faceの設定
:height 140 ;フォント高さ(/10pt)
)

;;最初のフレームのfaceの再読み込み(後処理)
(add-hook 'window-setup-hook
'(lambda ()
(face-set-after-frame-default (selected-frame)
))
))

以前にFreeBSDで(ローマ字でない)かなキー入力の設定をして、たまにjvim+cannaやEmacs+cannaでかな入力をしていたのだが、先月訳あってFreeBSD 7.3を新規にインストールすると、何と7.2まであったcanna-serverがpackagesから無くなっていた。portsを使えば時間はかかってもトラブル無くインストールできるのだろうが、今回はなるべくインストール作業に時間と手間を掛けたくなかったので、この機会にpackagesだけでインストールできるEmacs+anthy.elに完全に乗り換えることにした。

ところが、使ってみるとanthy.elのかな入力モード(anthy-kana-map-mode)のデフォルトの設定は使いづらいことがわかった。特に、全角数字や全角記号を入力する手段が無い(全角のアルファベットは入力できる)のが個人的に支障がある。漢字変換の辞書として登録しようにも、半角記号は漢字変換の対象にならないし、そして全角記号を片っ端からanthy-conf.elのキーマップに登録すると動かなくなってしまったのである。
丁度、GW開始と同時にえげつない風邪をひいて(咳と痰で窒息死するかと思った)未だ蟄居を余儀なくされており、パソコンに向かえるくらいには回復したものの、これより難しいことに取り組めるほど頭が回らないので、この機会に色々調べてanthy.elをカスタマイズしてみた。

(1) X Windowのキーの設定
以前のエントリーに書いたように、X Windowのデフォルトの設定では「ろ」「を」「ー」キー識別に問題があるので、keysymを変更する。
~/.Xmodmapに以下の2行を加える。

keycode 211 = underscore underscore
keycode 19 = 0 bar kana_WA kana_WO

(2) Emacsの設定
後述のキーマップの設定は文字コードがJISでないといけないので、anthy.el関連の設定は.emacs.elとは別のファイルに書くことにした。また、以前のエントリーではシステムのanthy-conf.elのキーマップの設定を書き換えていたが、ここではkeysymの設定をホームディレクトリに置いてるので、これもホームディレクトリに置くことにした。

~/.emacs.elの記述

(load (concat (getenv "HOME") "/.anthy-conf.el"))

~/.anthy-conf.el(文字コード:JIS)

;;anthy.elの設定
(load-library "anthy")
(setq defualt-input-method "japanese-anthy")
;(global-set-key "\C-o" 'anthy-mode)

(anthy-kana-map-mode) ;かなキー入力モード

;;xmodmapの変更に合わせたキーバインド
(anthy-change-hiragana-map "_" "ろ")
(anthy-change-hiragana-map "|" "を")
(anthy-change-hiragana-map "\\" "ー")
(anthy-change-katakana-map "_" "ロ")
(anthy-change-katakana-map "|" "ヲ")
(anthy-change-katakana-map "\\" "ー")

;;Anthyのひらがなモードとカタカナモードのキーマップを同時に設定する関数
(defun anthy-load-bothkana-map (map)
(mapcar (lambda (x)
(let ((key (car x)) (str (cdr x)))
(anthy-change-hiragana-map key str)
(anthy-change-katakana-map key str))) map))

;;日本語でよく使う記号(ワンプッシュにする)
(anthy-load-bothkana-map '(("{" . "「") ("}" . "」") ("?" . "・")))

;;その他全角記号("Q"+キーにする)
;;="@'+*は元々Shiftとの組み合わせで出るので省略
(anthy-load-bothkana-map
'(
("Q0" . "0") ("Q1" . "1") ("Q2" . "2") ("Q3" . "3") ("Q4" . "4") ("Q5" . "5") ("Q6" . "6") ("Q7" . "7") ("Q8" . "8") ("Q9" . "9")
("Q-" . "-") ("Q^" . "^") ("Q\"" . "\")
("Q!" . "!") ("Q#" . "#") ("Q$" . "$") ("Q%" . "%") ("Q&" . "&") ("Q'" . "'") ("Q(" . "(") ("Q)" . ")")
("Q~" . "~") ("Q|" . "|")
("Q[" . "[") ("Q]" . "]") ("Q{" . "{") ("Q}" . "}")
("Q;" . ";") ("Q:" . ":")
("Q," . ",") ("Q." . ".") ("Q<" . "<") ("Q>" . ">") ("Q/" . "/") ("Q?" . "?")))

;;カタカナは設定数が多いとダメのようなので、_はひらがなのみ
(anthy-change-hiragana-map "Q_" "_")
;;(anthy-change-katakana-map)をこれ以上実行すると固まる(\C-gで抜けられる)
;;(anthy-change-katakana-map "Q_" "_")

;;かな/カナ/全角アルファベットの切り替えのカスタマイズ
(setq anthy-rkmap-keybind
'(
;; \C-j --> ひらがな <=> カタカナ
(("hiragana" . 10) . "katakana")
(("katakana" . 10) . "hiragana")
(("walphabet" . 10) . "hiragana")
;; \C-p --> ひらがな <=> カタカナ
(("hiragana" . 16) . "katakana")
(("katakana" . 16) . "hiragana")
(("walphabet" . 16) . "hiragana")
;; \C-q --> ひらがな <=> ABC
(("hiragana" . 17) . "walphabet")
(("katakana" . 17) . "walphabet")
(("walphabet" . 17) . "hiragana")
;; H --> ひらがな
(("katakana" . 72) . "hiragana")
(("walphabet" . 72) . "hiragana")
;; K --> カタカナ
(("hiragana" . 75) . "katakana")
(("walphabet" . 75) . "katakana")
;; L --> ABC
(("hiragana" . 76) . "walphabet")
(("katakana" . 76) . "walphabet")
))

コメントにも少し書いているが、anthy-change-katakana-mapを使ってカタカナモードのキーマップにあまり多く登録すると、Anthyの応答が無くてEmacsが固まってしまう。その時にCtrl-Gを押すと、Emacs上にSegmentation faultと表示される。その後も日本語入力ができない訳ではない。謎である。

(5) anthy.elの修正
anthy-9100hのanthy.elは、Emacs23で使うと起動や変換候補一覧表示にやたら時間がかかる、よく知られたバグがある。これはanthy.elを書き換えて直すしかない。
ついでに、anthy.elをロードすると毎回

old-style backquotes detected!

と出て鬱陶しいので、それも修正する。

59c59
< (if (string-match "^22\." emacs-version)
---
> (if (>= emacs-major-version 22)
164,168c165,169
< (` (progn
< (defvar (, var) (, default-value)
< (, (format "%s\n\(buffer local\)" documentation)))
< (make-variable-buffer-local '(, var))
< )))
---
> `(progn
> (defvar ,var ,default-value
> ,(format "%s\n\(buffer local\)" documentation))
> (make-variable-buffer-local ',var)
> ))

これをファイルに保存して
cd /usr/local/share/emacs/site-lisp/anthy
patch anthy.el < (ファイル名)

とすると、修正が反映される。