2017-09-26

Emacs 25.2以降でASCIIと日本語のフォントを別々に設定する(一部の記号のフォントが変更できない場合)

最近Emacs 25.3へ変えたら一部の記号(○や※等)が正しく表示されなくなったのですが、結論から言うと use-default-font-for-symbols を使えということでした。

以前次のような設定で解決したと思ったのですが、最近Emacs 25.3へ変えたら一部の記号だけASCII用のフォントで表示されてしまいました。

(progn
  (set-face-attribute 'default nil :family "Inconsolata" :height 120)
  (set-fontset-font nil 'cp932 (font-spec :family "MS Gothic")))

emacs-25ブランチへの最近の変更を見てみましたがそれらしい変更点は見つけられず。元々以前の時も何が原因なのか分からずじまいだったので、たまたまうまく行っていただけだったのかもしれません。

不思議なのは一部の記号(○や※)がASCIIのみに対するフォント設定に影響されてしまうことです。上の設定をした後で各文字でどのフォントが選ばれるか試してみました。

(face-font 'default nil ?○);;=>"-outline-Inconsolata-normal-normal-normal-mono-16-*-*-*-p-*-iso8859-1"
(face-font 'default nil ?×);;=>"-outline-MS ゴシック-normal-normal-normal-mono-16-*-*-*-c-*-iso8859-1"
(face-font 'default nil ?あ);;=>"-outline-MS ゴシック-normal-normal-normal-mono-16-*-*-*-c-*-iso8859-1"

「○△□☆…∵→」あたりの記号でASCII用のフォントが使われてしまいます。describe-charで各文字を確認してみましたが、おかしくなるものに共通するのは「script: Symbol」であることくらいでしょうか。

「○」のフォントを次のようにして強制的に設定してみました。

(set-fontset-font "fontset-default" ?○ (font-spec :family "MS Gothic") nil 'prepend)

describe-fontsetで確認するとちゃんと#x25cbのフォントはMS Gothicになっています。でもなぜかMS Gothicが選ばれません。

仕方ないのでソースコードを追うことに。

  1. face-font 関数はxfaces.cにある。 FACE_FOR_CHAR がcharacterに応じてfaceを割り出している部分っぽい。
  2. FACE_FOR_CHAR はdispextern.hにあって HAVE_WINDOW_SYSTEM ならそのまま face_for_char 関数を呼び出す。
  3. face_for_char 関数はfontset.cにある。んん? 冒頭に use_default_font_for_symbols なんてものがある。同ファイルの上の方で use-default-font-for-symbols という変数を定義している。

use-default-font-for-symbols の説明を読む。

use-default-font-for-symbols is a variable defined in ‘C source code’.

Its value is t

Documentation:

If non-nil, use the default face’s font for symbols and punctuation.

By default, Emacs will try to use the default face’s font for displaying symbol and punctuation characters, disregarding the fontsets, if the default font can display the character. Set this to nil to make Emacs honor the fontsets instead.

「non-nilのとき記号や区切り文字にfaceのデフォルトフォントを使用します」……だって!?

試しに (setq use-default-font-for-symbols nil) にしたら全てが解決しました。なんてこった……。

というわけで最終的に次のようにしたらうまくいきました。

;; デフォルトはASCII用のフォントでなければダメっぽい。
(set-face-attribute 'default nil :family "Inconsolata" :height 120)
;; ASCII以外のUnicodeコードポイント全部を一括で設定する。他国語を使用する人は細かく指定した方が良いかも。
(set-fontset-font nil '(#x80 . #x10ffff) (font-spec :family "MS Gothic"))
;; 記号をデフォルトのフォントにしない。(for Emacs 25.2)
(setq use-default-font-for-symbols nil)

なんでこんなことになってるんでしょうね。一貫性があったfontsetの挙動に対して、一部の文字種を特別扱いする筋の悪いやり方に見えますが。

Emacs25でSymbolをデフォルトフォントで表示するように変更されたみたいなのですが、Emacs 25.2になって従来(Emacs24)と同じ挙動が出来るように use-default-font-for-symbols が追加されたみたいです。

Improve font selection for punctuation and other symbols · emacs-mirror/emacs@e070728
Emacs25でフォントの選択が 改良 されたコミット。
Use another font for some characters
set-fontset-fontが効かなくて困るよという話。
bug#24644: 26.0.50; Emacs 25: set-fontset-font does not take effect with
set-fontset-fontが効かなくて困るよという話。
Allow selection of font for symbols as in Emacs 24.x · emacs-mirror/emacs@4ff4b66
use-default-font-for-symbolsを追加したコミット。
「GNU Emacs 25.2」がリリース | OSDN Magazine
Emacs 25.2の変更点として use-default-font-for-symbols のことに触れている。

大人しく プログラミングのストレス軽減!日本語が使えるコーディングに最適なフォント7選 みたいなプログラム用フォントと日本語フォントを合成したフォントを使った方が良いのかもしれません。

(2021-07-29追記:自分でFontForgeで合成しました)

Pingback / Trackback