Emacsで異体字とか色付き絵文字とかを表示できるようにしてみた

いまだに Emacs を使ってるんだけど、最近フォント周りを調べてみたのでメモ。

異体字セレクタ

Emacs は異体字セレクタに対応してないとずっと思っていたんだけど、実は単にフォントの問題で、ちゃんと異体字セレクタに対応したフォントを使えば異体字を表示することができた。

普段使ってる Migu 1M フォントだと Emacs 上で異体字はこんな感じに表示される。

異体字セレクタに対応している花園明朝Aフォントを使うとちゃんと表示できる。

でも明朝体ではなくゴシック体を使いたい。IPAexゴシックフォントは一部しか異体字セレクタに対応していない。「禰󠄀豆子」は表示できるけど「令󠄂和」は表示できない。

全体的に Migu 1M フォントを使いつつ、「令」(U+4EE4)は花園明朝A、「禰」(U+79B0)はIPAexゴシックを使うということもできる。

(set-fontset-font nil #x4EE4 (font-spec :family "HanaminA"))
(set-fontset-font nil #x79B0 (font-spec :family "IPAexGothic"))

不格好。どこかに異体字セレクタにちゃんと対応しているフリーのゴシック体フォントは無いものか。

色付き絵文字

Emacs は色付き絵文字には対応してないとずっと思ってたんだけど(以下略

Noto Color Emoji フォントを指定すればちゃんと表示することができた。

Noto Color Emoji はユニコードのある範囲の文字群じゃなくて飛び飛びに配置されてるので、fc-query NotoColorEmoji.ttf の結果から対応している文字コードを抽出して、それだけを指定するようにした。

コード一覧だけ変数に設定してループで set-fontset-font を呼ぶようにすればいいような気はするんだけど、Lisp はまったくわからないのでとりあえずこんな感じで…。

(setq fontset-noto-color-emoji (font-spec :family "noto color emoji" :size 11))
(set-fontset-font nil #x200D fontset-noto-color-emoji)
(set-fontset-font nil #x203C fontset-noto-color-emoji)
(set-fontset-font nil #x2049 fontset-noto-color-emoji)
(set-fontset-font nil #x20E3 fontset-noto-color-emoji)
(set-fontset-font nil #x2122 fontset-noto-color-emoji)
(set-fontset-font nil #x2139 fontset-noto-color-emoji)
(set-fontset-font nil '(#x2194 . #x2199) fontset-noto-color-emoji)
(set-fontset-font nil '(#x21A9 . #x21AA) fontset-noto-color-emoji)
...

Migu 1M と文字幅を合わせるために :size 11 を指定しているんだけど、これだと拡大縮小時に追従してくれいない。何かいい方法ないかな…。

まあ、これでだいたいの絵文字は表示できるようになったんだけど、Noto Color Emoji で対応しているはずの絵文字なのに表示できないものも一部ある。

どうもデフォルトフォントが対応している文字は set-fontset-font で指定しても効かないらしい。デフォルトフォントとして Migu 1M を使っていたので、Migu 1M が含んでいる文字については Noto Color Emoji が使われないのだった。 異体字はちゃんと効くのになぁ…。


[追記]

Zennの方のコメント欄で教えてもらったんだけど、これは次のようにすることで解決した。

(setq use-default-font-for-symbols nil)

なので以下は不要。


ということで、ASCII+α くらいの最小文字しか含んでなくて良さそうなフォントの Inconsolata をデフォルトフォントにすることにした。

Emacs 起動時にデスクトップ環境の Monospace フォントとして設定されているものが自動的にデフォルトフォントになるらしい。設定でデフォルトフォントを変更する方法はいくつかあるみたいだけど、set-fontset-font'ascii を指定しても効くようなのでそうした。

(set-fontset-font nil 'ascii (font-spec :family "Inconsolata"))

ちゃんと Noto Color Emoji で表示されるようになった。

Migu 1M は日本語っぽい charset を指定して設定している。'han は漢字全般らしい。

(setq fontset-migu1m (font-spec :family "Migu 1M"))
(set-fontset-font nil 'japanese-jisx0208 fontset-migu1m)
(set-fontset-font nil 'japanese-jisx0208-1978 fontset-migu1m)
(set-fontset-font nil 'japanese-jisx0212 fontset-migu1m)
(set-fontset-font nil 'japanese-jisx0213-1 fontset-migu1m)
(set-fontset-font nil 'japanese-jisx0213-2 fontset-migu1m)
(set-fontset-font nil 'japanese-jisx0213.2004-1 fontset-migu1m)
(set-fontset-font nil 'han fontset-migu1m)

めでたしめでたし。


おまけ

TrueType フォントがサポートしているコードポイントを一覧するスクリプト。要 fc-query。

fontfile, = ARGV
IO.popen("fc-query #{fontfile}") do |r|
  r.each do |l|
    break if l =~ /\A\tcharset:/
  end
  r.each do |l|
    break unless l =~ /:/
    seg, *data = l.strip.split(/[:\s]+/)
    seg = seg.to_i(16)
    data.each_with_index do |d, i|
      d = d.to_i(16)
      bits = d.to_s(2)
      bits.size.times do |j|
        puts "%04X"%(seg*0x100+i*32+j) if d[j] == 1
      end
    end
  end
end

実行例:

% ruby font-codepoint.rb NotoColorEmoji.ttf
0020
0023
002A
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
00A9
00AE
200D
203C
2049
20E3
2122
2139
2194
2195
...