Iosevka 预定义连字集(Predefined Ligation Sets)配置指南:inherits 继承机制与自定义构建实战
【免费下载链接】IosevkaVersatile typeface for code, from code.项目地址: https://gitcode.com/GitHub_Trending/io/Iosevka
Iosevka 在caltOpenType 特性上默认启用一组连字(ligation),同时内置了面向 C-Like、JavaScript、Haskell、Raku 等 20 余种编程语言/风格的预定义连字集。本文以ligations小节中的inherits参数为核心,讲解如何通过private-build-plans.toml自定义构建,一键继承任一预定义连字集,并结合仓库源码说明其底层解析与 GSUB 查表生成原理。读完本文,你将掌握预定义连字集的完整清单、inherits的取值语义、与enables/disables摘樱桃式(cherry-picking)微调的配合方式,以及从 TOML 配置到 OpenType 查表的完整构建链路。
一、背景:Iosevka 的连字体系与预定义连字集
Iosevka 的等宽子家族支持连字。官方 README.md 明确指出:Iosevka 的默认连字集被指派给calt特性,但并非所有连字默认开启。calt(Contextual Alternates)是文本编辑器默认开启的 OpenType 特性,因此开箱即用的连字效果正是来自这个默认集。
与此同时,Iosevka 还提供了一批语言相关连字集(Language-Specific Ligations),它们被指派给自定义特性标签。要启用这些集,需要关闭calt并开启对应特性(如CLIK、JSPT、HSKL等),完整标签与效果预览见 doc/language-specific-ligation-sets.md。
而**预定义连字集(Predefined Ligation Sets)**则是指可以直接通过inherits继承、从而整体替换默认calt行为的连字集。它们全部定义在 params/ligation-set.toml 中,由构建系统读取并驱动 GSUB 查表生成。
二、配置入口:ligations 小节与 inherits 参数
在自定义构建中,连字配置位于构建计划的ligations子节,其作用是定制指派给calt特性的连字集。相关参数说明由构建脚本自动生成后嵌入 doc/custom-build.md,其片段源文件即 tools/amend-readme/src/fragments/description-predefined-ligation-sets.md。
inherits参数语义如下:
inherits:可选,String,定义所继承的连字集。缺省时,该连字集不继承任何其他集合。
也就是说,inherits决定了一个自定义连字集的"基底":设置它等于先把某个预定义集的全部组成(buildup)复制过来,再在其上进行增删。结合 packages/param/src/ligation.mjs 的实现可见,inherits的处理优先级是:先以继承的集合重置当前 sink,再叠加enables与buildup的内容,最后剔除disables指定的组,且enables与buildup都可以递归引用 simple 组或其他 composite 组。
2.1 可继承的预定义连字集完整清单
以下 21 个值均可作为inherits的合法取值(与 doc/custom-build.md 一致,其 README 描述由 tools/amend-readme/src/sections/lig-set-pre-def.mjs 根据ligation-set.toml自动生成):
inherits取值 | 说明 | 对应特性标签 |
|---|---|---|
default-calt | 继承默认连字集(文本编辑器默认设置) | calt |
dlig | 默认连字集指派给 Discretionary ligatures | dlig |
clike | C-Like | CLIK |
javascript | JavaScript | JSPT |
php | PHP | PHPX |
julia | Julia | JLIA |
raku | Raku | RAKU |
ml | ML | MLXX |
fsharp | F# | FSHP |
fstar | F* | FSTA |
haskell | Haskell | HSKL |
idris | Idris | IDRS |
elm | Elm | ELMX |
purescript | PureScript | PURS |
swift | Swift | SWFT |
dafny | Dafny | DFNY |
coq | Coq | COQX |
matlab | Matlab | MTLB |
verilog | Verilog | VRLG |
wolfram | Wolfram Language (Mathematica) | WFLM |
erlang | Erlang Language | ERLA |
注意其中elm与purescript共用同一份组成(ELMX/PURS合并显示),idris在haskell基础上追加brack-bar,fsharp直接继承ml(见 params/ligation-set.toml 的 composite 定义)。
2.2 预定义集在源码中的定义方式
这些预定义集在 params/ligation-set.toml 中全部以[composite.<name>]形式声明。以默认集与 Haskell 集为例:
[composite.default-calt] tag = 'calt' brief = 'Default' desc = 'Default setting in text editors' readmeDesc = 'Inherit default ligation set' buildup = [ '--default-center-ops--', '--default-equality-inequality--', '--default-kern--', '--default-chaining--', 'arrow-l', 'arrow-r', 'arrow-lr', 'html-comment', 'ltgt-diamond-tag', 'ltgt-slash-tag', 'trig', 'slash-asterisk', 'llgg', 'llggeq', ] [composite.haskell] tag = 'HSKL' desc = 'Haskell' buildup = [ '--default-center-ops--', 'center-op-influence-dot', '--haskell-equality-inequality--', '--default-kern--', '--fast-chaining--', 'arrow-l', 'arrow-r', 'arrow-lr', 'counter-arrow-l', 'counter-arrow-r', 'trig', 'llgg', 'ltgt-diamond', 'logic', ]其中buildup列出的既可以是 simple 组(如arrow-l、trig),也可以是其他 composite 组(如--default-kern--、haskell这样的语言集),且允许递归组合;带--前缀的组是仅用于继承的内部组,不直接暴露为特性标签(见 params/ligation-set.toml 的注释与定义)。
三、实战:用 inherits 定制自己的连字集
3.1 创建私有构建计划
参照 doc/custom-build.md 的说明:
- 若仓库根目录下没有
private-build-plans.toml,则创建它(与仓库自带的 build-plans.toml 平级)。 - 在文件中以
[buildPlans.<计划名>]添加一个构建计划(建议计划名使用 PascalCase)。 - 运行
npm run build -- contents::<计划名>,产物输出到dist/目录。
除contents::<plan>外,还可用ttf::<plan>(仅 TTF)、ttf-unhinted::<plan>、webfont::<plan>(CSS + WOFF2)、woff2::<plan>等目标(见 doc/custom-build.md)。
3.2 示例一:整体继承一个语言连字集
下面的计划继承了 Haskell 的连字集作为自己的calt默认行为:
[buildPlans.MyHaskellPlan] family = "My Haskell Iosevka" ligations.inherits = "haskell"构建后,该字体的calt特性即等效于 Haskell 集(HSKL的组成),无须在编辑器中手动关闭calt、开启HSKL。
3.3 示例二:继承后微调(enables / disables)
inherits只是基底,配合摘樱桃式参数disables与enables可以精确增删。例如继承默认集、去掉双箭头并加入 Markdown 复选框连字:
[buildPlans.MyPlan] family = "My Iosevka" [buildPlans.MyPlan.ligations] inherits = "default-calt" enables = ["markdown-checkboxes"] disables = ["arrow-lr"]注意:由于连字形成时存在复杂交互,摘樱桃式调整必须使用自定义构建,无法在成品字体上通过 OpenType 特性开关实现,这一点在 README.md 中已明确提示。摘樱桃可用的全部取值(如arrow-l、eqeqeq、ltgt-diamond、center-op-trigger-equal-l、markdown-checkboxes等 60 余项)见 doc/custom-build.md,其片段源为 tools/amend-readme/src/fragments/description-cherry-picking-ligation-sets.md。
3.4 示例三:完全从零构建(不继承)
省略inherits,仅用enables/disables组合出一个全新的连字集:
[buildPlans.MyMinimalPlan] family = "My Minimal Iosevka" [buildPlans.MyMinimalPlan.ligations] enables = ["eqeq", "exeq", "lteq", "gteq", "arrow-r"]当inherits缺省时,该连字集不继承任何其他集合,因此只有你显式enables的组会被编入calt。
四、源码级原理:从 TOML 到 OpenType GSUB 查表
4.1 参数解析与展开
构建时,packages/font/src/param/index.mjs 读取params/ligation-set.toml,调用 packages/param/src/ligation.mjs 的applyLigationData:
- 遍历所有带
tag的 composite 组,用createBuildupForComposite把递归的buildup展开为扁平的 simple 组集合,存为para.ligationBuildups; - 若构建计划定义了
ligations(即你在[buildPlans.xxx.ligations]写的配置),则用其生成新的calt组成; - 还支持
customLigationTags为自定义特性标签注入组成。
addComposite中inherits的实现逻辑(packages/param/src/ligation.mjs)值得细读:它先递归展开被继承的集合填充新 sink,然后sink.clear()清空当前集合并替换,随后叠加enables/buildup,最后按disables集合逐一delete。而addSimple(同文件 L57-L65)会顺着implies字段把隐式关联的组一并加入——例如启用tilde-tilde会自动带上tilde-tilde-tilde(见 params/ligation-set.toml)。
4.2 生成 GSUB 查表
展开后的扁平集合交由 packages/font-otl/src/gsub-ligation.ptl 的buildLigations生成 GSUB 连字查表;入口在 packages/font-otl/src/index.ptl:仅当para.enableLigation为真时才构建。该开关对应 params/parameters.toml 的enableLigation = true,并可通过构建计划的noLigation属性关闭(见 doc/custom-build.md)。每个 simple 组的samples字段既是连字文本样例,也是 README 预览图与渲染测试的取材来源(见 tools/data-export/src/ligation-data.mjs 中parseLigationData对ligation-set.toml的解析)。
4.3 文档的自动生成机制
值得留意的是,你看到的这份inherits取值清单并不是手写维护的:doc/custom-build.md中的Section-Predefined-Ligation-Sets区块由 tools/amend-readme/src/sections/lig-set-pre-def.mjs 生成,它遍历parseLigationData返回的rawSets,凡是有desc且未被标记为showAsCherryPicking的 composite 组都会出现在清单中;tools/amend-readme/src/sections/lig-set-cherry-picking.mjs 则负责生成摘樱桃清单。这保证了文档与 params/ligation-set.toml 始终同步。
五、预定义集的行为差异速览
不同语言集的核心差异主要落在相等/不等号处理、箭头方向、chaining(连续符号连接)与注释符号四类 simple 组的取舍上。从 params/ligation-set.toml 的 composite 定义可以总结出以下模式:
- 等号风格差异:
--default-equality-inequality--使用eqeq+exeq+lteq+gteq;C 系(clike/javascript/php)额外加入eqeqeq与exeqeq(--c-equality-inequality--);ML 系(ml/coq)使用ltgt-ne把<>处理为不等号;Haskell 使用slasheq;Matlab 使用tildeeq(~=不等号);Verilog 使用lteq-separate/gteq-separate分离形状;Wolfram 使用eqexeq-dl双线=!=(详见 params/ligation-set.toml)。 - chaining 取舍:
--default-chaining--只连接 3 个及以上符号(plus-plus-plus、minus-minus-minus等),--fast-chaining--从 2 个起就连;--c-like-chaining--则混合二者(2 个加号、2 个下划线,但减号/井号/tilde 需 3 个),见 params/ligation-set.toml。 - 注释符号:
slash-asterisk(/*、*/)出现在多数命令式语言集;brst((*、*)星号居中)只出现在 ML/F*/Wolfram/Coq 等函数式与符号化语言集中。 - 箭头方向:多数语言集仅含右向与双向箭头(
arrow-r、arrow-lr);默认集与 Julia/Raku/Haskell/Swift/Dafny/Coq 等额外包含左向箭头arrow-l;Haskell/Swift/Dafny/Coq 还包含反向箭头(counter-arrow-*)。
以上差异均可直接对照 doc/language-specific-ligation-sets.md 中各标签的渲染预览图进行直观验证。
六、FAQ 与注意事项
Q1:为什么改连字必须重新构建字体?因为连字涉及多个字形间的交互替换,成品字体中的calt查表在构建时即已固化。README 明确说明 cherry-picking 需要自定义构建(README.md),而inherits更是只存在于构建计划中的配置参数,与 OpenType 特性开关无关。
Q2:语言相关连字集和预定义集是什么关系?语言相关连字集(CLIK、JSPT等)是编入成品字体、按特性标签调用的集合;预定义集则通过inherits在构建期整体套用。两者在ligation-set.toml中共用同一批 composite 定义:带tag的会以特性标签形式暴露,供inherits引用的名字则直接来自[composite.<name>]的键名。
Q3:exportGlyphNames与连字有什么关系?若在 Kitty 等终端中使用连字,需要把构建计划的exportGlyphNames设为true,否则连字支持可能失效(见 doc/custom-build.md)。仓库自带的 build-plans.toml 中默认计划即开启了该选项,可作为参考。
Q4:构建时资源占用过高怎么办?构建系统默认并发任务数等于 CPU 线程数,每个任务峰值内存超过 1 GB,可追加--jCmd=<并发数>参数限制(见 doc/custom-build.md)。
七、总结
inherits是 Iosevka 自定义连字配置中最关键的单一参数:它以 21 个预定义集为基底,配合enables/disables实现"继承 + 微调"的完整定制闭环。其取值清单由 params/ligation-set.toml 自动派生,底层经由 packages/param/src/ligation.mjs 展开为扁平 simple 组,最终由 packages/font-otl/src/gsub-ligation.ptl 编译为 GSUB 查表。理解了这条从 TOML 到字体的链路,你就能按自己的编程语言习惯精确塑造 Iosevka 的连字体验。
【免费下载链接】IosevkaVersatile typeface for code, from code.项目地址: https://gitcode.com/GitHub_Trending/io/Iosevka
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考