Emacs の Prettify-symbols を複数文字対応にする
概要
, . 作成。
Emacs には、ある文字列を 1 文字に変換して表示する
prettify-symbols-mode
というものがある。
表示を変えるだけでファイルデータ自体は変わらないので、例えばラムダ式の lambda
を λ
にして可読性を向上させよう、という類の機能である。
一方、Emacs には composite.el
という機能がデフォルトで組み込まれている。これは……正直もう一度触る気になれないのだが、「複数の文字を組み合わせて一つの文字として振る舞わせる」ことができる。
このコンポジット機能を使えば、を文字列を文字列で置換することが可能になる。この方法と、設定例を示してみる。
prettify-symbols
とは
;; prettify for all text-modes (add-hook 'text-mode-hook (lambda () (push '("alpha" . ?α) prettify-symbols-alist) (push '("omega" . ?ω) prettify-symbols-alist) ))
実際は他にも書き方はあると思うが、文字列とキャラクタの対応を
prettify-symbols-alist
に追加している。
自分には上のコードの lambda
が λ
に見えている。この文字の上で M-x describe-character
すると、
position: 891 of 1788 (50%), column: 13 character: l (displayed as l) (codepoint 108, #o154, #x6c) charset: ascii (ASCII (ISO646 IRV)) code point in charset: 0x6C script: latin syntax: w which means: word category: .:Base, L:Left-to-right (strong), a:ASCII, l:Latin, r:Roman, u:Lowercase to input: type "C-x 8 RET 6c" or "C-x 8 RET LATIN SMALL LETTER L" buffer code: #x6C file code: #x6C (encoded by coding system utf-8-unix) display: composed to form "lambda" (see below) Composed with the following character(s) "ambda" by the rule: (?λ) The component character(s) are displayed by these fonts (glyph codes): λ: ftcrhb:-????-Sarasa Mono J-normal-normal-normal-*-14-*-*-*-*-0-iso10646-1 (#xB89A) See the variable ‘reference-point-alist’ for the meaning of the rule.
以上のようになる。
composite.el
の書き方
さて、問題の composite.el
である。詳細は Emacs 上で
M-x describe-variable reference-point-alist
をすると見ることができる。
Documentation: Alist of symbols vs integer codes of glyph reference points. A glyph reference point symbol is to be used to specify a composition rule in COMPONENTS argument to such functions as ‘compose-region’. The meaning of glyph reference point codes is as follows: 0----1----2 <---- ascent 0:tl or top-left | | 1:tc or top-center | | 2:tr or top-right | | 3:Bl or base-left 9:cl or center-left 9 10 11 <---- center 4:Bc or base-center 10:cc or center-center | | 5:Br or base-right 11:cr or center-right --3----4----5-- <-- baseline 6:bl or bottom-left | | 7:bc or bottom-center 6----7----8 <---- descent 8:br or bottom-right Glyph reference point symbols are to be used to specify a composition rule of the form (GLOBAL-REF-POINT . NEW-REF-POINT), where GLOBAL-REF-POINT is a reference point in the overall glyphs already composed, and NEW-REF-POINT is a reference point in the new glyph to be added. For instance, if GLOBAL-REF-POINT is ‘br’ (bottom-right) and NEW-REF-POINT is ‘tc’ (top-center), the overall glyph is updated as follows (the point ‘*’ corresponds to both reference points): +-------+--+ <--- new ascent | | | | global| | | glyph | | -- | | |-- <--- baseline (doesn’t change) +----+--*--+ | | new | | |glyph| +----+-----+ <--- new descent A composition rule may have the form (GLOBAL-REF-POINT NEW-REF-POINT XOFF YOFF), where XOFF and YOFF specify how much to shift NEW-REF-POINT from GLOBAL-REF-POINT. In this case, XOFF and YOFF are integers in the range -100..100 representing the shifting percentage against the font size.
最初の図が出てきた時点でやる気はゼロだと思うので、まずは例を見せよう。
;; prettify for all text-modes (add-hook 'text-mode-hook (lambda () (push '("tex" 32 (Br Bl -70 0) 119827 (Br cl -70 30) 119812 (Br Bl -50 0) 119831 (Br Bl -70 0) 32) prettify-symbols-alist) ;; Le bon Dieu est dans le détail ;; https://practicaltypography.com/line-spacing.html (setq line-spacing 1) ))
これを 最初のソースコード と比べると、以下が文字を組んだ結果となる。
32 (Br Bl -70 0) 119827 (Br cl -70 30) 119812 (Br Bl -50 0) 119831 (Br Bl -70 0) 32
要素 | 説明 |
---|---|
32 |
スペース。 |
(Br Bl -70 0) |
前の文字(スペース)と次の文字をくっつけて、次の文字を右に -0.7 文字分ずらす |
119827 |
Mathematical Bold Capital T。 |
(Br cl -70 30) |
前の文字の図中 5 番の位置と、次の文字の図中 9 番の位置をくっつけ、次の文字を右に -0.7 文字、上に 0.3 文字分ずらす |
119812 |
Mathematical Bold Capital E。 |
(Br Bl -50 0) |
前の文字の図中 5 番の位置と、次の文字の図中 3 番の位置をくっつけ、次の文字を右に -0.5 文字分ずらす |
119831 |
Mathematical Bold Capital X。 |
(Br Bl -70 0) |
前の文字の図中 5 番の位置と、次の文字の図中 3 番の位置をくっつけ、次の文字を右に -0.7 文字分ずらす |
32 |
スペース。 0x20 |
この括弧で囲まれた要素が、いわば「糊」となって前後の文字を繋いでいる。上の例ではオフセット(ずらし)が必要になったが、使わない場合は単に
(tl . bc)
などとすればよい。
ちなみに十進数の数字は、例えば http://unicode-table.com/en/1d413 の HTML Code の数字を見れ分かる。
折角なので \( \LaTeX \) も組んだので持って帰ってください。
("latex" 32 (Br Bl -75 0) 119819 (cr bl -90 -55) 119808 (Br Bl -65 0) 119827 (Br cl -70 30) 119812 (Br Bl -50 0) 119831 (Br Bl -75 0) 32)
文字組み関数を定義
さて、余計な知識を付けたところで、本題に入ろう。やりたいことは単に「前後の文字をくっつける」だけなので、糊は
(Br . Bl)
だけで良い。あとは受け取ったリストを次から次へとくっつけていく。
(defun private/prettify-list (l &optional merge) "Takes two lists and interleaves the (optional) second between each element of the first. Used to create multi-character sequences for use with prettify-symbols mode. If not supplied, MERGE defaults to '(Br . Bl)" (let ((merge (or merge '(Br . Bl))) (head (car l)) (tail (cdr l))) (cond ((not (consp l)) '()) ((not (consp tail)) (list head)) (t (cons head (cons merge (private/prettify-list tail merge))))))) (defun private/prettify-string (s &optional merge) "Takes a string and an optional list, and returns a list of the string's characters with MERGE interleaved between each character, for use with prettify-symbols mode. If no MERGE is supplied, uses the private/prettify-list default." (private/prettify-list (append s nil) merge))
任意の設定ファイルに上の関数を登録してから以下のようにする。 org-mode
での例を示す。
(add-hook 'org-mode-hook (lambda () (push (cons "#+BEGIN_SRC" (private/prettify-string "╱╱ CODE: ╱╱")) prettify-symbols-alist) (push (cons "#+END_SRC" (private/prettify-string "╱╱ :CODE ╱╱")) prettify-symbols-alist) ;; ... (push (cons "#+BEGIN_VERSE" (private/prettify-string "“— v e r s e")) prettify-symbols-alist) (push (cons "#+END_VERSE" (private/prettify-string "ə s ɹ ə ʌ —”")) prettify-symbols-alist) (prettify-symbols-mode) ))