Cocoa Emacs のフォント設定について

随時更新(最終更新:2012年3月28日)

書き散らかしている状態なので、ややこしく見えるかもしれないけどそんな事無いです。最終的には MacEmacs Wikiにできるだけ簡潔にかきます。

概要

フォント設定のスタンダードな方法は、初期フレームとそれ以降のフレームのフレームパラメータのデフォルト値を指定する連想リスト default-frame-alist でフォントを指定すること。日本語を使う場合は、複数のフォントを使い分けるためフォントセットを指定する。設定例(1)はその方針。もう1つ別の方法があり、フレームのフォントを set-face-attribute という関数を使って変更する。これもフォントセットが自動的に作られて、それを後で調整する。それが設定例(2)。いずれの方法でも、最終的にはフレームのフェイスに対して1つのフォントセットが選ばれた状態になる。

現在の Emacs 23.2 では、例(1)の方法だと初期画面を抑制したときにフォントが正しく設定されないバグがある。対処法としては、(text-scale-increase が動作しなくても気にならなければ)font-spec オブジェクトを作る時にサイズを指定する方法か、または初期設定ファイルの中で set-face-font を使ってフェイスのフォントを一度指定するという方法がある。このバグがなければ、例(2)より例(1)のほうが正しい方針だと思う。(Emacs 24.0.50で確認したところ、上の対処をしなくても動作する。でも不必要なフォントセットが生成されているのが気になる。)

方針

  • Emacs 23.2 (Cocoa Emacs)で適切な方法でフォントを設定する
  • 日本語と半角英数混在で等幅 (ascii : 日本語 = 1 : 2)
  • 日本語フォントもASCIIフォントもファミリー名で指定

使う関数

  • create-fontset-from-ascii-font : 1つのASCIIフォントをベースに新しいフォントセットを作る。その中で関数 new-fontset が呼ばれる。
  • set-face-attribute :フレーム上の(通常のテキスト領域やモードラインなど)フェイスの属性を設定する関数。
  • set-fontset-font : フォントセットを調整する関数。指定したターゲット(範囲や文字セット名)に対して、使うフォントを設定する(ターゲットが重なる時は、後の設定で上書きされるので注意)。フォントを指定する方法はいろいろある。
    • font-spec によって作った font-spec オブジェクト
    • (フォントファミリー名 . フォントレジストリ名) というコンスセル(cons)。
    • フォント名文字列
    • nil とすることで、あるターゲットに対してフォントの割当がないことを明示する。
  • font-spec: ファミリー名やその他の属性から、font-spec オブジェクトを作る関数。

言葉の説明

  • fontset フォントセット:いろんな種類の文字を扱うためのフォントの集合。名前は "-apple-menlo-medium-normal-normal-*-*-150-*-*-m-0-fontset-myfontset" といった感じ。名前の末尾がdefaultとstandardとstartupという3つのフォントセットは最初から用意されている。英字フォントしか使わない場合でも、フレームのデフォルトフェースはあるフォントセットに対応付けられている。(face-attribute 'default :fontset) を評価することで確認できる。
  • フレーム
  • フェイス

設定例 (1)「default-frame のフォントを設定」

  • 新たにフォントセットを作り default-frame-alist のフォントで、そのフォントセットを指定する方針。
  • フォントセットは create-fontset-from-ascii-font を使って作る。
  • フォントの指定はファミリー名から font-spec オブジェクトを作ってする。

設定例 (2) 「フレームのフォントを指定」

  • 関数 set-face-attribute を使いフレームのデフォルトフェイス(←通常のテキスト領域)のフォント変更する。
  • すると名前の末尾が auto1, auto2 となるフォントセットが自動生成され、現在のフレームのフォントセットに設定される。(auto1 は12ptのフォントで、それ以外のサイズを指定すると auto2 も作られる。)
  • set-face-attribute の第2引数は、nil なら全てのフレームの属性(attribute)を変更する。t なら、新しいフレームのためのデフォルトを変更する。起動時からのフォントを変更するには nil
  • set-fontset-font の第1引数は、フォントセットの名前だけど、nil ならフレームのフォントセットを、 t ならデフォルトのフォントセットになる。(set-face-attribute と同じように「フレーム」は「全てのフレーム」を意味しているようだ。)
  • default-frame-alist でフォントを指定していない場合、新しくフレームを作った時のフォントは set-face-attribute の設定に従う。(ちなみに set-frame-font で現在のフレームのフォントを設定しても、新しいフレームはそれに従わない。)
  • フォントの指定はファミリー名から font-spec オブジェクトを作ってする。

フォント関連のコマンド

  • 現在のフレームに設定されているフォントセットは (face-attribute 'default :fontset) を評価(C-x C-e)すればみれる。
  • (frame-parameters) を評価(C-x C-e)すれば、フレームパラメータがみれる。
  • フォントリストの一覧は M-x list-fontsets
  • M-x set-default-font はフレームのフォントを変更できるが、「This function is obsolete since 23.1」らしい。かわりに、set-frame-font を使うように指示されている。
  • M-x set-frame-font はインタラクティブに、現在のフレームのフォントを変更できる。
  • M-x set-face-font はインタラクティブに、Face のフォントを変えられる。Face を default にすると編集領域に。modeline のフォントなども変えられる。

メモ

  • 関数 font-spec を使った方法が紹介されているのは、そこでサイズを指定するため。rescale するなら、単純にフォント名ストリングでいいはず。
  • でも、フォント名≠フォントのファミリー名だから、やはり font-spec オブジェクトをファミリー名から作った方が確実?正しいフォント名の文字列はXFLDという記述法?
  • ヒラギノ角ゴ W6(太字)などを設定したい場合は、 set-fontset-fontの3つ目の引数を font-spec オブジェクトにして、そこで属性を指定すればできた。
;;ヒラギノ角ゴ ProN W6
(font-spec :family "Hiragino Kaku Gothic ProN" :weight 'bold)
;;ヒラギノ角ゴ StdN W8
(font-spec :family "Hiragino Kaku Gothic StdN" :weight 'bold)
  • face-font-rescale-alist はこちらを参考にした。
  • unicode 全域の文字セットにヒラギノを割り当てる方法は楽だけど、過去の方法をみると日本語関連の文字セットを1つ1つ割り当てているものが多いのでその方法に従う。使うところだけ指定する形。
  • 日本語の文字セットで jisx0208, jisx0212, jisx0213-1, jisx0213-2を全部指定していたけど重複があったみたい。ヒラギノは字数も多いのでjisx0213を指定したほうが良いかな(?)
  • いずれの方法も、(size, asciifont, jpfont) の3つの引数にまとまってきたけど関数にするべき?それはそれで柔軟性がなくなる?(追記:とりあえず書いてみた
  • 過去のメーリングリストで、こういうやりとりを発見(^^;) http://lists.gnu.org/archive/html/emacs-devel/2009-03/msg00191.html
  • フォントのファミリー名「ヒラギノ角ゴ ProN」を使っても大丈夫なはずだけど、コメントアウト用のフェイス(斜体)で等幅にならなかった。(これはただのバグかもしれない)
  • LaTeXコマンド毎にフェイスを使い分けるAUCTeXモードで、日英文字混在で等幅になるサイズ比が崩れた。(自分は YaTeX ユーザなので AUCTeX の設定の仕方が悪いのかもしれないけど)

  • face-font-rescale-alist で日英混在等幅になるのは、全てのサイズではなかったみたい。ちゃんと確認していなかった。Menloとヒラギノで実際に試したところ、次のサイズなら大丈夫だった。9pt, 10pt, 12pt, 14pt, 15pt, 17pt, 19pt, 20pt。
  • buffer-face-mode についての紹介があった。つまりモード毎に使うフォントを指定できる?(追記:2011-2-8)

fontset.c のコメントを転載

A fontset is a collection of font related information to give similar appearance (style, etc) of characters. A fontset has two roles. One is to use for the frame parameter `font' as if it is an ASCII font. In that case, Emacs uses the font specified for `ascii' script for the frame's default font.

Another role, the more important one, is to provide information about which font to use for each non-ASCII character.

There are two kinds of fontsets; base and realized. A base fontset is created by `new-fontset' from Emacs Lisp explicitly. A realized fontset is created implicitly when a face is realized for ASCII characters. A face is also realized for non-ASCII characters based on an ASCII face. All of non-ASCII faces based on the same ASCII face share the same realized fontset.

A fontset object is implemented by a char-table whose default value and parent are always nil.

An element of a base fontset is a vector of FONT-DEFs which itself is a vector [ FONT-SPEC ENCODING REPERTORY ].

An element of a realized fontset is nil, t, 0, or a vector of this form:

        [ CHARSET-ORDERED-LIST-TICK PREFERRED-RFONT-DEFRFONT-DEF0 RFONT-DEF1 ... ]

RFONT-DEFn (i.e. Realized FONT-DEF) has this form:

        [ FACE-ID FONT-DEF FONT-OBJECT SORTING-SCORE ]

RFONT-DEFn are automatically reordered by the current charset priority list.

The value nil means that we have not yet generated the above vector from the base of the fontset.

The value t means that no font is available for the corresponding range of characters.

The value 0 means that no font is available for the corresponding range of characters in this fontset, but may be available in the default fontset.


A fontset has 9 extra slots.

   The 1st slot: the ID number of the fontset

   The 2nd slot:
	base: the name of the fontset
	realized: nil

   The 3rd slot:
	base: nil
	realized: the base fontset

   The 4th slot:
	base: nil
	realized: the frame that the fontset belongs to

   The 5th slot:
	base: the font name for ASCII characters
	realized: nil

   The 6th slot:
	base: nil
	realized: the ID number of a face to use for characters that
		  has no font in a realized fontset.

   The 7th slot:
	base: nil
	realized: Alist of font index vs the corresponding repertory
	char-table.

   The 8th slot:
	base: nil
	realized: If the base is not the default fontset, a fontset
	realized from the default fontset, else nil.

   The 9th slot:
	base: Same as element value (but for fallback fonts).
	realized: Likewise.

All fontsets are recorded in the vector Vfontset_table.

DEFAULT FONTSET

There's a special base fontset named `default fontset' which defines the default font specifications. When a base fontset doesn't specify a font for a specific character, the corresponding value in the default fontset is used.

The parent of a realized fontset created for such a face that has no fontset is the default fontset.

These structures are hidden from the other codes than this file. The other codes handle fontsets only by their ID numbers. They usually use the variable name `fontset' for IDs. But, in this file, we always use varialbe name `id' for IDs, and name `fontset' for an actual fontset object, i.e., char-table.


変更履歴とその説明

  • 2012年3月28日: 設定例をgithub に置いた。
  • 4月4日: 設定例2のset-fontset-fontのところに分音符付きラテンを追加した。
  • 2月15日: 半角カナの文字セットを指定。(masutaka26 さんに教えていただいた)
  • 2月11日: フォントサイズの比を設定するときに add-to-list を使うように変更した。
  • 2月10日: fontset.c のコメントを転載を追加。いつも「C-h f」や「C-h v」で lisp のところまでは見に行くけど、C のコードまでは見ていなかった。
  • 2月8日: buffer-face-mode を紹介したブログをリンク
  • 2月4日: 設定例(1)と(2)の表現や順番を揃えた。
  • 2月3日: 任意サイズで等幅になるわけではないことに気がつき、大丈夫なサイズを書き加えた。
  • 2月1日: ファミリー名で日本語名を使った場合の不具合をメモの所に書いた
  • 1月25日: 設定例(1)を修正。あと、起動時のバグへの対処法として set-face-font を使った。これはバグが直れば必要ないはず。
  • 1月24日: 設定例(1) のミスを修正。概要の後半で default-frame-alist が無いときの挙動を勘違いしていたので削除。(だいたい様子は分かってきたつもりだけど、なかなか収束しない...)
  • 1月24日: 概要の文を修正。
  • 1月23日: 概要を追加。
  • 1月22日: フォントの設定を繰り返す時、set-fontset-font の所を append で設定していると前の設定を書き換える事ができないので、ターゲットを日本語の文字セットにして、append は使わないようにした。
  • 1月22日: 分音符付きラテンをアスキー文字用フォントに指定していたところは、set-face-attribute を使う場合は設定されているので必要なかった。create-fontset-from-ascii-font は ascii 文字のフォントしか設定しないので必要。
  • 2011年1月22日: 日本語の文字セットについて理解せずに、とりあえずもれのないようにと jisx0208, jisx0212, jisx0213 を設定したけどただの重複だった。いろいろ試して、最終的にsakitoさんが紹介されていた unicode を append で設定するほうが一番確実と判断した。