关于 Emacs 行高的实现

Emacs 行高是:一行高度 = 这一行所有显示元素里的最大 ascent + 最大 descent + line-spacing,所以一些诸如 emoji 之类的总会撑高整行。因此在 master 中增加了上下行高的设置后,其实并没有什么实际作用。

如果按照 web 那样固定的 line box,内容放进去,配合 line-spacing 使用,就既不会遮盖,也不会撑高行高,不需要对 emoji 等字体去缩放了啊。

4 个赞

我之前纠结 emacs 的光标高度为字符高度,与行高不一致,问了 AI,答案是 emacs 不支持web css那样的行高模型。具体细节我也不了解,应该是因为底层图形库比较古老。

1 个赞

没法固定,这是文本输入并渲染,你并不能由一行的第一个字符决定行高,万一用户接着插入一个图片进来呢。

行高不正确的原因是算行高的逻辑没考虑字体复杂的 metrics 信息,更直白说,就是陈年老代码没考虑那么多文字、字体的差异,自己生生做了个补丁摞补丁的图文排版系统。

1 个赞

我现在感觉是pc或终端里这个问题还好不是很明显,最近在用android emacs gui版,感觉就不对劲了,怎么每行高度都不一样,变来变去的,也可能是google noto系列字体的问题

只能用字符比较完整的中英文合并字体,这样行高就确定了。

开启行号模式+字体改为使用的中文字体就行,原理是行号提前决定了当前行高度。

;; 1. 开启行号
(global-display-line-numbers-mode 1)

;; 2. 定义一个新面孔 (Face),用于行号区域
;; 关键是 :font 属性,我们指定一个中文字体
(make-empty-face 'my-line-number-face)
(set-face-attribute 'my-line-number-face nil
                    :font (font-spec :family "FangSongCode" :size 42))
;; 在这里替换为你系统中任意一款中文字体的名字
;; 例如 "Noto Sans CJK SC", "Sarasa Term SC", "Microsoft YaHei" 等

;; 3. 将这个面孔应用到行号上
(set-face-attribute 'line-number nil :inherit 'my-line-number-face)
(set-face-attribute 'line-number-current-line nil :inherit 'my-line-number-face)
2 个赞

这个思路到没有想过,不过还是解决不了特殊字符诸如emoji的问题。

(let ((emoji-font
       (cond
        ((eq system-type 'darwin) "Apple Color Emoji")
        ((eq system-type 'windows-nt) "Segoe UI Emoji")
        ((eq system-type 'gnu/linux) "Noto Color Emoji"))))

  (when (and emoji-font (find-font (font-spec :family emoji-font)))
    (set-fontset-font t 'emoji (font-spec :family emoji-font) nil 'prepend)
    (add-to-list 'face-font-rescale-alist `(,emoji-font . 0.8))))

尝试配置 Emacs 中 emoji-font 缩放试下,经过我自己的测试,0.8 是一个比较好的值。代码里包含 Windows 和 Linux 的判断,但是我基本上只在 macOS 下使用,因此不确定在其它系统上具体效果怎样。

让 Gemini 生成了一段中英文和 Emoji 混合的语句,macOS 上配合 Sarasa Term SC Nerd 字体效果如下:

1 个赞

缩放到0.7也会影响行高的,比如这一行都是小写字母,所以不是根本办法。

(setq default-text-properties '(line-height (56 70)))

这个怎么样? 56是最大ascent,70是56加上最大descent,可以通过 (query-font (font-at (point))) 获得。