狠狠地折腾了一把Emacs中文字体

1 Emacs中文字体的最基本问题

从23版开始,Emacs的中文显示可以说很轻松就可以基本解决。比如网上这位 强者(强是他的名字) 的配置方法,可以自动适配当前机器上已有的中文字体,有好的就用好的,没 有就将就一点。我最近也把他的配置抄过来了。

但这么一抄抄出问题来了(其实问题以前也一直存在,但折腾一开始就停不下来,必须把问题解决为止。这是身为Emacs狂粉儿必须付的代价?)。

2 等高还是等宽?

我以前的配置一直都是等高。估计大部分同学的选择是等宽。其实它们都各有缺点。

2.1 等宽不等高的问题

我用的是自己写的输入法SDIM,跟其他Emacs自带的输入法一样,它的候选词是在 echo area里显示的,如果不等高的话,echo area的高度会不断跳动,在上下两 个窗口的时候,第二个窗口中的输入会很痛苦:echo area的高度变化会导致第二 窗口的位置也发生变化,从而产生抖动,眼睛吃不消。

2.2 等高不等宽的问题

org-mode里的中英文混排、尤其是在表格中,如果不选等宽(指的是一个中文字 符与两个英文字符等宽),表格就没法看了。邮件程序gnus的排版也会大受影响, 导致不够美观。

2.3 等高或者等宽共有的问题

不管你选的是等高还是等宽,只要你选,估计在放大、缩小的时候( C-x C-+C-x C-- ),英文可以缩放,中文不会;你用 put-text-property 等都 只会对英文有效,中文无效!搞什么嘛!除非你不选,这样出来的结果可能既不 等高也不等宽,从而表格排版问题和输入抖动问题同时存在,囧死算了……

3 解决的方法

问题的关键出在下面的 :size 参数。以我的英文字体为Monaco-14为例,中文 字体为 Microsoft Yahei 为例,如果我要等高的话,我需要把 :size 设为16, 如果我要等宽的话,要设为一个较小的值。

(set-fontset-font t 'han (font-spec :family "Microsoft Yahei" :size 16)

但只要你一设,等高还是等宽你只能选一个,附加赠送上面说的缩放的问题。如 果不设,则中文字体跟英文字体的size保持一致,也是14,根据不同中文字体可 能既不等高又不等宽。

解决的方法是不设 :size ,而是修改另一个变量:

(setq face-font-rescale-alist '(("Microsoft Yahei" . 1.2) ("WenQuanYi Zen Hei" . 1.2)))

并且一定要重启Emacs(见 这个坑爹的bug ,浪费我N多时间,都准备上gdb了)!

改完之后由于缩放对中文也有效,我只要把输入法的中文字体设小一点就可以了。见图:

perfect-emacs-chinese-font.png

配置脚本见 github

另外,这个设置在Windows上也可以用,但是好像不是很可靠(我见到它有时候不 起作用,不明白怎么回事),并且在我的Win7系统上必须把 微软雅黑 给加到 face-font-rescale-alist 里去(可以用 C-u C-x = 来看当前汉字是用什么字体显示的,从而决定应该在这个变量里加什么。另一个有用的函数是 describe-fontset ):

(setq face-font-rescale-alist '(("微软雅黑" . 1.2) ("Microsoft Yahei" . 1.2) ("WenQuanYi Zen Hei" . 1.2)))

见图:

perfect-emacs-chinese-font-win7.png

4 全局缩放

这篇博客

5 完美英文斜体

先贴一下效果:

italic-font.png

当初在水木Emacs版的 这个贴子 里提了一下,这里自己再转一遍:

发信人: flonk (flonk), 信区: Emacs
标  题: 完美搞定Emacs英文斜体
发信站: 水木社区 (Fri May 10 11:39:06 2013), 转信  [累计积分奖励: 100/0]

所谓完美,就是跟正体保持等高等宽,并且一起(全局)缩放

提供斜体的等宽字体好像只知道Courier New。

要点在于一定要用浮点数指定point size,而不是整数指定pixel size。

代码见:https://github.com/baohaojun/system-config/raw/master/.emacs_d/lisp/bhj-fonts.el

全局放到最大后效果图:http://baohaojun.github.io/images/post/italic-font.png

6 Mac和Linux下的不同参数

在不同的系统下和不同的字体尺寸下,要达到中英文等宽,中文的scale参数要设成不一样。所以我后来增加了相应的变参机制,见代码:

;; On different platforms, I need to set different scaling rate for
;; differnt font size.
(cond
 ((and (boundp '*is-a-mac*) *is-a-mac*)
  (setq chinese-font-size-scale-alist '((10.5 . 1.3) (11.5 . 1.3) (16 . 1.3) (18 . 1.25))))
 ((and (boundp '*is-a-win*) *is-a-win*)
  (setq chinese-font-size-scale-alist '((11.5 . 1.25) (16 . 1.25))))
 (t ;; is a linux😊
  (setq chinese-font-size-scale-alist '((16 . 1.25)))))