emacs 中的中英文对齐对于稍微有点强迫症的人来说算是个可以折腾的人直挠头的问题了,特别是当你使用 org-mode ,并且在文章中添加表格的时候。在不做任何设置的情况下,默认的结果可能是这样的:

在网上搜索一番之后,会找到一个 cnfonts 的解决方案,思路是为中文和英文字体分别设置不同大小,经过一番调整,得到结果是这样的:

但这个方案其实还是有些个问题:

  1. 对齐的设置是按照宽度来设置的,这就导致了有些英文字体小,但对应的中文字体太大,宽度虽然对上了,高度却差了很多,照成上图中的中英文行距明显大于英文之间的行距。

  2. 不能够放大缩小,我用的 emacs-mac 的 fork,可以使用 trackpad 的手势对字体进行缩放,但是 cnfonts 调整过后的中英文放到缩小的比例是不同的,导致不仅对不齐,而且中英字体的字号差距太大,没法看。

  3. 在有些主题中,buffer 的字体设置有些不同,和设置字体的设置可能有冲突,有可能会导致一些字体突然变得特别大,我就遇到过在某一个主题中 org-agenda 的英文字体突然大到夸张的情况。

除了这三点,其实还有一点是我选择直接拷贝 cnfonts 生成的 elispcustom.el 来设置字体, cnfonts 生成的默认字体大小对于有些字体来说太小了,加大一号又太大了,中间的大小又没有对齐。所以在使用了一段时间之后我决定再想想办法。

其他方案

在放弃了 cnfonts 的解决方案之后,我想到的最后的解决方案是找到一对严格或者近似符合 2:1 的中英文字体,这样不管在放大或缩小的情况下,两个字体都能配合的比较完美,不会出现忽大忽小的问题。最终我找到的是 Ubuntu Mono 配合 Sarasa Mono SC,以及 Iosevka 配合 Sarasa Mono SC 。其中来说 Iosevka 搭配 Sarasa Mono SC 比较完美,因为是同一人之手。而 Ubuntu Mono 会稍微有一点点差距,在 size < 15 的时候都是能完美对齐,另外高度会有一点点差距。可以通过使用下面的方法来进行设置。

(let ((default-font (font-spec :name "Iosevka" :size 15))
      (cn-font (font-spec :name "Sarasa Mono SC")))
  (set-face-attribute 'default nil :font default-font)
  (dolist (charset '(kana han symbol cjk-misc bopomofo))
    (set-fontset-font t charset cn-font)))

更进一步

进行到上一步的时候其实已经差不多了,除了,对于有些喜新厌旧的人来说某一个字体看久就会老想着换到别的字体,那怎么办?在搜索方案的过程中我看到了 emacs 的一个叫做 face-font-rescale-alist 的变量,查看变量和帮助文档,可以看到如下描述:

This variable specifies scaling for certain faces. Its value should be a list of elements of the form
 
(fontname-regexp . scale-factor)
 
If fontname-regexp matches the font name that is about to be used, this says to choose a larger similar font according to the factor scale-factor. You would use this feature to normalize the font size if certain fonts are bigger or smaller than their nominal heights and widths would suggest.

所以我们可以将中英文字体的大小设置为相同,然后通过这边变量来单独的放大或缩小英文字体的显示,以便和英文字体对齐。于是结合上面的设置我将新的设置方案写成了一个函数方便快速的调整我想要的字体。

(defun max/set-font (FONT-NAME CN-FONT-NAME &optional INITIAL-SIZE CN-FONT-RESCALE-RATIO)
  "Set different font-family for Latin and Chinese charactors."
  (let* ((size (or INITIAL-SIZE 14))
	 (ratio (or CN-FONT-RESCALE-RATIO 0.0))
	 (main (font-spec :name FONT-NAME :size size))
	 (cn (font-spec :name CN-FONT-NAME)))
    (set-face-attribute 'default nil :font main)
    (dolist (charset '(kana han symbol cjk-misc bopomofo))
      (set-fontset-font t charset cn))
    (setq face-font-rescale-alist (if (/= ratio 0.0) `((,CN-FONT-NAME . ,ratio)) nil))))

这样我就能通过如下的办法来设置我想要的字体,并且通过一个参数来调整中文的对齐了。

(max/set-font "JetBrains Mono" "Hiragino Sans GB" 13 1.25)
(max/set-font "Fira Code" "Hiragino Sans GB" 13 1.25)
(max/set-font "Monaco" "Sarasa Mono SC" 13 1.25)
(max/set-font "Fira Code" "Source Han Serif SC" 13 1.3)

部分的效果如下,总体来说 Sarasa Mono SC 的效果会比其他的中文字体好一些,其他的中文字体应该自身并不是 monospace,所有只有在特定的 size 下才会对齐,就当作是中调剂吧。

相关的一些链接