GeekRicardo
|
0504e3918b
|
fix(terminal): 自定义字体解析失败时兜底到等宽,避免掉进比例字体毁掉网格
在设置页「侧边卡片」→ 终端卡片填入自定义「终端字体」后,若该族名在浏览器里
解析不到,终端不是退化成"没有想要的字体",而是整个网格崩掉:字符间距被撑开、
字形变成比例字形、Nerd Font 图标全部消失。
用户实测(macOS + Chrome,填 `Maple Mono NF CN`):
| 「终端字体」的值 | DevTools Rendered Fonts | 结果 |
| --- | --- | --- |
| `Maple Mono NF CN` | **PingFang SC** | cell 12.09px @ 13px 字号(0.93em),网格崩坏 |
| `Maple Mono NF CN, monospace` | **Menlo** | 间距恢复正常 |
`resolveTerminalFont` 对用户值(以及主题 `--ds-font-family-code` token 值)
原样返回,只有内置的 `DEFAULT_TERMINAL_FONT_FAMILY` 末尾带 `monospace`。
字体栈若不以通用族收尾,浏览器解析不到任何具名字体时会落到**标准字体**
(standard font,macOS 中文环境是 PingFang SC)——它是**比例字体**。
xterm 用它的推进宽度量 cell(0.93em,等宽字体应为 0.6em),网格随即失真。
这条路径比想象中容易踩:终端里跑的 shell 在 host 上,字体却由**浏览器所在机器**
提供,两者不同机时(远程/容器化的 DSH)用户按 host 侧装的字体填名字必然解析失败。
新增 `withMonospaceFallback()`,在 `resolveTerminalFont` 出口保证字体栈以通用族收尾。
- **不做字体嗅探**:终端字体设计文档 §2 把"字体合法性嗅探"列为非目标;本改动
不检测具名字体是否存在,只补一个通用族尾项。
- **已有通用族则原样保留**:包括用户主动写的非等宽通用族(`sans-serif` 等)
——那是用户的选择,不该被覆盖。
- **主题 token 值同样兜底**:它掉进比例字体的后果与用户值完全一样。
- **CSS 全局关键字单独处理**:`inherit` / `initial` / `unset` / `revert` /
`revert-layer` 追加逗号后是非法 CSS,会被 CSSOM 整条丢弃,反而让 xterm
一个字体都拿不到;这类值直接回落内置栈。
- 字体栈按**顶层逗号**切分并感知引号、转义与括号,避免拆坏 `"Foo, Bar"`
与 `var(--x, y)`;通用族匹配大小写不敏感且只认未加引号的项。
- `tests/terminal-font.spec.ts` 4 → 13 例(兜底追加、已有通用族免动、大小写与
引号边界、顶层逗号切分、幂等性、CSS 全局关键字、空值)
- `pnpm typecheck` 零错误
- 全量 `pnpm test`:941 passed(改动前基线 932 passed,+9 为本次新增);
另有 31 例失败在本分支基线(干净 main)上同样失败,与本改动无关
互补、不重叠。#190 解决"字体解析成功、但栈里没显式列 Nerd Font 导致补充平面
PUA 图标缺字";本 PR 解决"字体压根没解析到、栈又没有通用族尾项导致落进比例
字体"。两者都落在 `terminal-font.ts` 的同一出口,合并时按先后 rebase 即可。
|
2026-08-29 15:49:35 +08:00 |
|