跳转至

体验Typst

这篇是我的Typst学习笔记的摘要,不怕冗长、琐碎的可以看笔记(内附学习资源列表):Typst学习笔记

Typst体验很好,前途光明~

这几天看了两位作者的硕士论文和官方文档,试用了官方在线编辑器、命令行工具和非官方的vscode插件,尝试了我感兴趣的支持中文排版的可能性,如标点压缩、凸排、竖排、双行夹注等。代码还没看。

现有几点认识和感受:

语言特性#

Typst是一种文本和代码无缝衔接的排版编程语言(作者说是“用于出版的可编程标记语言”), 没有像诸TeX嵌入LuaTeX造成的种种麻烦,如宏展开、变量传递。文档结果是这样的:

  • Typst文件顶级是一个文本标记内容域[content],可以包含
    • 文本标记语言(标记+纯文本),其语法很接近markdown
    • 程序代码,即以标记 # 引导的
      • 单个程序语句、表达式,包括多行的条件语句、循环语句等
      • 程序代码域 {...}
  • [content]{...}两种域即是程序的作用域,它们可以不限深度地、交互地嵌套

Typst是函数式语言,内置支持排版的函数和常量库(实际上,所有文本标记都有对应的函数,是对应函数的语法糖),包括类型系统、设置样式函数的高阶函数(背后可能是Rust的macro_rules!,有待确认)、文档结构内省工具等。

运行效率#

Typst是用Rust语言写的,是typ(e+ru)st,目标运行平台是WASM,即浏览器本地离线运行;也编译成命令行工具。采用一种增量编译算法和一种有约束的版面缓存方案(a constrained layout caching scheme)。

据作者的论文,从解析到排版阶段的编译效率很好。下面是三种类型出版物每次编辑动作导致的解析、排版平均耗时(毫秒)和标准差:

Typst生成和导出PDF阶段没有这么绝对的优势,处理小文件时表现很好;但在导出多卷本文集(Tome)的PDF文件时,效率还略低于pdfTEX,只略高于XETEX:

可用情况#

目前官方有编辑平台/编辑器,支持语法高亮、代码自动完成,快捷键也接近vscode这类流行编辑器。结果渲染在浏览器画布上,可下载PDF,即键即得。

非官方的vscode插件(不需要额外装任何东西)也可以配置成“onTpye”时编译,流畅。

可以说基础扎实,框架比较基本完整,细节问题还比较多... 反响很好,据说代码库开源第一天即达到5000星,社区很活跃。这可能是希望所在,比如非官方的vscode插件没用几天就做出来了。

目前写英文文档问题不大,写中文比较难看。

题外话#

Typst会不会逼得ConTeXt+LuaTeX(LuaMetaTeX)团队放弃TeX宏包这个历史包袱呢?LuaMetaTeX的基础设施对TeX代码的依赖大概不多了。

当然,Typst在用途上面对标LaTeX,即学术写作,而ConTeXt+LuaMetaTeX主要目标是图书出版,两者定位差异比较大。

用例#

因为想做中文支持,试了试可编程特性,效果和代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
= 设置
// 不设置也能用(有缺省值)
// 页面设置
#set page(width: 10cm, height: 10cm)
// 设置text的字体、字号
#set text(
    font: "simsun",
    size: 11.5pt,
)
// 段落设置
#set par(
    first-line-indent: 2em, 
    justify: true,
    )

// 设置中文标题序号
#let arabic_to_chinese(str) = {
    let dict = (
        "0": "〇",
        "1": "一",
        "2": "二",
        "3": "三",
        "4": "四",
        "5": "五",
        "6": "六",
        "7": "七",
        "8": "八",
        "9": "九",
    )
    str.clusters().map(
        x => dict.at(x)
        ).join()
}

#let chinese_numbering(..nums) = {
    nums.pos()
        .map(str)
        .map(arabic_to_chinese)
        .join(".") + " "
}

#set heading(numbering: chinese_numbering)

= 一级标题

== 二级标题

=== 竖排旋转堆叠
#v(2em)


#let r(x) = rotate(-90deg,x) 
#let poem = "
惠崇春江晚景
宋·苏轼
竹外桃花三两枝,
春江水暖鸭先知。
蒌蒿满地芦芽短,
正是河豚欲上时。
"
#for l in poem.split() {
  stack(
    dir:ltr,
    ..l.clusters().map(
        x => rotate(-90deg,x)
    )
  )
}

=== 段落
#v(2em)


#[// 嵌入内容域
#set text(font: "simkai")

排版元素可以旋转位移可以手动堆叠成行成列
元素间可以放置正值或负值的空白
这么说可以做标点压缩竖排双行夹注等功能

但目前似乎没有操作底层数据的接口比如获取字体和字模信息操作抽象语法树模块树框架树

另外它的分行组段的算法似乎比较简陋不知道后面会不会移植 Knuth-Plass 的算法这个说法是错误的Typst 有一个optimized Knuth-Plass style)。
目前汉字间没有像 LuaTeX 那样加入零宽度的胶所以行校正时可拉伸点较少只能用标点前后的空格),拉得太狠很难看
]

主要参考资料:

  1. Typst语言手册
  2. 作者Martin E. Haug的硕士论文:fast typesetting incremental compilation
  3. 作者Laurenz Mädje的硕士论文:Typst: programmable markup language for typesetting

评论