从活字到字体源码(9):Ligconsolata Next 的连字改造
- 字形怎样学会复用
- 中文字体走进现代出版
- 西文字体穿过机器时代
- 那些熟悉的字体从哪里来
- 字体从像素格走向轮廓
- 可变字体把变化装进一个文件
- 连字让源码换一种读法
- 字体源码藏在哪些文件里
- Ligconsolata Next 的连字改造(当前)
- AI 改字体时到底在做什么
- 不会字体设计,也能看懂字体改动
Ligconsolata Next 的目标来自一个很具体的偏好:保留 Inconsolata 的字母、括号与阅读节奏,同时补齐常用编程连字。Fira Code 是行为与覆盖面的参考,新增字形仍从 Inconsolata 自己的轮廓派生。
这里集中讨论改造中的几个决定。完整支持清单由生成脚本与项目功能图库维护,文章的样例只覆盖下面解释的机制。
先让已有连字进入普通编辑器路径
Inconsolata 已有的 dlig baseline 包括 !==、===、->、=>、>=、<-、<=。Next 保留这层兼容,同时把固定替换同步到 liga,让普通编辑器的连字开关能使用它们。两字符的 !=、== 属于 Next 补充并修正的形态,不能算作上游 baseline 已有能力。
编辑器默认体验围绕 liga 与 calt 安排。dlig 继续兼容历史用法;字母风格等选择留给 ss / cv,避免默认体验依赖用户逐个配置高级特性。
两横线与三横线分别生成
早期生成方式从三横线字形横向缩放得到 == 与 !=。它保留了宽度,却没有改变横线数量,视觉上仍容易被读成 identity 运算符。
后来 == 改为从原始 equal 的两条横线派生,!= 使用相同的两横线结构并结合斜杠。=== 与 !== 则继续保留三条清楚的横线,整体视觉中心对齐原始等号。
图中关闭 calt,单独检查 liga 中的固定字形。早期方案的问题由项目的迁移复盘记录;图里展示的是当前轮廓。
独立输入也需要检查。早期规则在 calt=1 时会把孤立 === 当成长等号序列的开头,输出两条连续长线;同一份字体中的 a === b 却能命中三横线固定字形。修复后的规则要求三个等号后还有可延展序列的字符,才启动长线替换。这样既保留孤立 === 的三横线,也能继续处理 ===>、====> 等长箭头。字体 review 篇保留了修复前后的真实轮廓和采样记录。
更长的 ====、===== 用两条连续长线处理注释分割线,不能把这一规则套回 ===。类似地,-- 保留两个减号的间隔,---- 才承担连续分割线的样式。
比较符与箭头分开设计
<=、>= 表示比较,<==、==> 表示方向。项目默认比较符从 <、> 的下斜边派生一条平行、等长的下斜线,端点使用竖切。它参考 Fira Code 默认比较符的处理方向,轮廓来源仍是本字体。
这个调整不能只看包围盒居中。第二条斜线的视觉跨度、端点位置与切口,都需要和原始斜边对照。水平横线式比较符可以作为未来风格选项,但当前默认形态有明确选择。
长箭头用片段延展
固定枚举 ->、-->、---> 无法覆盖所有长度。项目用 start、middle、end 片段处理长箭头,各片段共同保留原始总推进宽度。
片段需要和固定连字协调。<==== 的剩余等号如果先被 === 接管,长箭头就会不完整。因此 calt 使用 start lookup 与多轮 extend lookup,并对 ==、===、!==、i-- 及共享前缀的固定组合设置避让。
这类冲突仅看 feature 文本很难判断,要检查最终 glyph 序列。新增一个固定操作符,也可能要求修改已有长箭头的 guard。
注释规则接受保守的上下文边界
无条件合并 // 会改到 URL,无条件合并 /*、*/ 会改到 glob。项目选择普通空格作为局部触发条件:
| 输入 | 当前处理 |
|---|---|
// comment、/// reference |
后接空格,启用注释前缀 |
https://example.com、//TODO |
保留 slash |
/* block */ |
起始边界后、结束边界前有空格时启用 |
**/*.{ts,tsx}、src/*.ts |
slash 与 asterisk 边界保持原样,** 仍可连写 |
a /\ b、x \/ y |
两侧普通空格下启用逻辑形态 |
/\d/、\/tmp |
保留对应组合,反斜杠仍可能使用默认细形态 |
//TODO 即使在语法上是注释,也不会得到该前缀连字。字体只能看到 shaping run 内的字形上下文,这个代价换来了更容易解释的 URL 与路径保护。
Markdown hash badge 同样依赖局部上下文。## title 到 ###### title 仅在 shaping run 开头且后接普通空格时显示可数徽标;它不能跨编辑器的语法分段判断整行含义。七个及以上井号使用无编号的延展序列。
用真实字体维护样张与 QA
overview-samples.txt、catalog 样例和功能图库从 ASCII 文本出发,经 HarfBuzz 排字后提取字体轮廓。静态图能够证明采样时的字形,源码变化后必须重新生成。documentation/demo/index.html 另外加载实际字体,允许输入自己的片段并切换 feature。
当前项目已有 100、400、700、900 字重与 11、13、16、20px 的深浅背景矩阵,不能再写成「尚未做多字重 QA」。它仍然只是已选样本和位置的检查,当前 upright 源码没有因此获得 Italic 支持。
总结
这次改造把固定操作符放进 liga,把长度与局部上下文交给 calt,并始终维护原始字符的总推进宽度。两横线、比较符与注释 guard 表明,覆盖更多组合之前,要先决定哪些差异必须看清、哪些上下文宁可保守。真实字体样张与回归样例让这些选择可以继续核查,而不只停留在设计描述里。