vterm 里用 lf 的行溢出

用 lf 浏览有中文文件名的目录时,由于默认的 doom-font 是英文字体,比如 Monaco,vterm 用 它来计算 term height, 于是会因为同样 font size 的中文字体的 height 比 Monaco 高而把 term 顶部的行顶出屏幕可见区域了。

大家怎么应对这个问题?

我不想用中文字体部分的西文部分,我用 face-font-rescale-alist 去缩小中文字体,但是得缩小到 76% 才行,此时中文字体看起来只有英文字体的 50%,看起来是中文字体的 leading 和 descent 部分不参与缩放,非常难看。

Emacs 29.1, macOS, Doom Emacs 的 modules/ui/unicode 探测出的中文字体是兰亭黑。

~/.doom.d/config.el:

(setq doom-font (font-spec :family "Menlo" :size 13 :weight 'medium))

(use-package! vterm
  :config
  (setq-hook! 'vterm-mode-hook
    ; decrease line height of CJK chars for ncurses application to avoid vertical overflow
    face-font-rescale-alist '(("-p-0-iso10646-1$" . 0.76)))
  (setq vterm-ignore-blink-cursor nil
        vterm-eval-cmds '(("find-file" find-file)
                          ("message" message)
                          ("vterm-clear-scrollback" vterm-clear-scrollback)
                          ("toggle-send-escape" evil-collection-vterm-toggle-send-escape))))

不仅仅是 Vterm, 其它的地方把中英文设置成一样高度体验也会更好。

你可以试试看 https://commitmono.com/ 这个英文字体,它这个网站可以自定义高度,你可以加高它使其正好等于你喜欢的中文字体的高度。

看了下这个字体,不太喜欢,也有点麻烦,得再装个字体。

那你就需要研究一下怎么给你喜欢的字体打补丁了

其实我有点疑惑,中英文字体都是 13pt,terminal emulator 比如 Terminal.app, iTerm2.app 就没问题,为啥 Emacs vterm 就得 rescale 中文字体 76% 搞得看起来只有英文字体的 50% 高度? 是不是中文字体有什么 padding?

终端模拟器每行高度是相同的,Emacs 每个字高度都可能不一样。

知道原因了,是 Emacs macfont.c 里取字体 metrics 错了:

use Typo metrics 开关打开了,就应该用 Typo Ascent, Typo Descent, Typo Line Gap, 不应该用老的 HHead 那些,后者把 line gap 实际融入到 ascent 和 descent 里了。

哪位出手改下 macfont_open_font 这个函数,把获取 ascent,descent,linegap改成用 os2 表里的数据?不懂 obj c :sob:

搞定这个问题了,根源是中英文字体的 ascent / descent 不同导致 line-height 因出现中文而变大,vterm 按英文字体(默认 face font) 计算的 total rows 在显示中文时超出了窗口高度。

需要两个修改:

  1. 使用OS/2 字体补丁,HHead font metrics 的中英文 ascent & descent 差距太大,用 Typo font metrics 好很多,TrueType 字体是推荐用后者的,HHead font metrics 是 macOS 历史遗留,Win font metrics 是 Windows 历史遗留;
  2. Emacs 计算 (line-pixel-height) 时,会计算 max(ascent) + max(descent) 作为 height,由于不同字体的 baseline 不同,因此要缩小字体,比如 (font-info "Menlo-13") 显示 height = 16, ascent=10, descent=6, (font-info "Alibaba PuHuiTi 3.0-13") 显示 height=16, ascent=11, descent=5,使用 face-font-rescale-alist 缩小后者到 99%, height=14, ascent=10, descent=4,因此 max(ascent) + max(descent) = 10 + 6 = 16 没有超过 Menlo-13;

这样调整后中文字体会矮一点点,有点丑,但总比之前要缩放到 76% 好太多了。

另一个解决办法是中英文用同一个字体,但是用了 Doom Emacs 的 modules/ui/unicode 后,它会根据字符集挑选字体,依然会在 Emacs 里混杂多个字体,从而出现一样的问题:vterm 里顶部的行被挤出屏幕可见范围。

$ brew install emacs-mac
$ cd /usr/local/Homebrew/Library/Taps/railwaycat/homebrew-emacsmacport
$ brew edit emacs-mac
$ brew reinstall emacs-mac --with-no-title-bars --with-starter
$ git diff
diff --git a/Formula/emacs-mac.rb b/Formula/emacs-mac.rb
index 1858132..7e1a39d 100644
--- a/Formula/emacs-mac.rb
+++ b/Formula/emacs-mac.rb
@@ -33,6 +33,11 @@ class EmacsMac < Formula
     end
   end
 
+  patch do
+    url "https://raw.githubusercontent.com/Dieken/homebrew-emacsmacport/prefer-typo-ascender-descender-linegap/patches/prefer-typo-ascender-descender-linegap.diff"
+    sha256 "318395d3869d3479da4593360bcb11a5df08b494b995287074d0d744ec562c17"
+  end
+
   option "without-modules", "Build without dynamic modules support"
   option "with-ctags", "Don't remove the ctags executable that emacs provides"
   option "with-no-title-bars",

~/.doom.d/config.el:

; 使用 M-x describe-char 查看某个字符使用的字体
(setq doom-font (font-spec :family "Menlo" :size 13 :weight 'medium))
(setq doom-symbol-font (font-spec :family "Alibaba PuHuiTi 3.0" :size 13))

(use-package! vterm
  :config
  (setq-hook! 'vterm-mode-hook
    ; decrease line height of CJK chars for ncurses application to avoid vertical overflow
    face-font-rescale-alist '(("-p-0-iso10646-1$" . 0.99)))
  (setq vterm-ignore-blink-cursor nil
        vterm-eval-cmds '(("find-file" find-file)
                          ("message" message)
                          ("vterm-clear-scrollback" vterm-clear-scrollback)
                          ("toggle-send-escape" evil-collection-vterm-toggle-send-escape))))

BTW,这个渲染问题在 M-x term 和 M-x ansi-term 里也存在,可以用同样办法解决。