Typst 是 2019 年才出现的使用 Rust 编写的基于标记的排版语言,定位在 Markdown、Word 等初级工具和 LaTeX \LaTeX L A T E X 一类的高级工具之间,官方宣称其功能可以和 LaTeX \LaTeX L A T E X 一样强大,但是和 Markdown 一样简单、易用,主要应用于数学、物理和工程方面(特别是包含大量公式、图表)的论文、文章、作业、书籍和报告的编写。
基础教程 MacOS 和 Arch Linux 用户可以使用包管理器进行安装:
1 2 3 4 5 brew install typst pacman -S typst
具体支持的发行版本可以查看 参考资料 (5) 。Ubuntu 目前还只能下载编译好的二进制文件,或者安装 Rust 后从源码编译进行安装。除此之外,还需要安装编辑器的插件实现代码提示、预览等功能,VS Code 上的主要插件有:
除此之外,还有 Typst Sympy Calculator 插件实现了和 Python 的 SymPy 库的联动,可以进行公式的转化和计算。
对于从 LaTeX \LaTeX L A T E X 和 Markdown 迁移过来的用户,绝大部分语法内容都可以新学习,比较重要的区别有:
公式中命令不需要 \
开头,直接使用即可,例如使用 $e^(pi eta)$
显示 e π η e^{\pi\eta} e π η ,要在公式中显示成段的,不是命令的字符,可以使用 "
包裹起来。更具体而言,Typst 区分两种模式:「标记模式」和「代码模式」,前者是正常的文本模式,类似于 Markdown 的编写逻辑,后者以 #
开头,在该模式内的命令省略 #
(个人认为,公式是一种特殊的代码模式,命令在公式中也可以省略 #
) 函数定义要求函数名 + 括号,参数可以是位置参数或者命名参数,格式为 myfunc(keya: valuea, keyb: valueb)
Typst 的代码模式十分强大,通过 #if
条件判断和 #for
循环语句,可以实现 参考资料 (7) 中的效果: your browser does not support the video tag
具体的内容可以查看 参考资料 (3) ,入门的教程可以查看 参考资料 (2) ,一些 Typst、Markdown 和 LaTeX \LaTeX L A T E X 之间的对比可以查看 参考资料 (7)
常用代码 官方模组 目前官方收录的模组可以在 Typst Packages 进行查询,此外还有 Awesome Typst 项目收录了很多实用了模组,下面列举了部分常用的模组,一些我进行了自定义的模组将会在 (下一小节 ) 进行介绍。
Pinit 包用于创建批注,在制作 slides 的时候特别有用,效果如下:Physics 实现了向量、场、微分、导数、狄拉克符号等物理中常用符合的定义:Showybox 可以创建自定义的彩色盒,可以用于定义、定理等场景:Tablex 实现了高级的表格:Typst orange template 使用 Typst 实现了 Legrand Orange Book :i-figured 实现了图表、公式的按章节编号,参见 (论文 )自定义模板 幻灯片 Awesome Typst 中推荐的幻灯片模板中,个人推荐使用 Polylux 模板,提供了多种主题,目前我常用的是 [University] 主题,并进行了一定的修改。
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 # let matrix-slide (
title : none ,
new-section : none ,
columns : none ,
rows : none ,
.. bodies
) = {
let header = {
set align ( top )
grid ( rows : ( auto , auto ) , row-gutter : 3mm , progress-barline , header-text ( title : title , new-section : new-section ) )
}
let footer = {
set text ( size : 10pt )
set align ( center + bottom )
let cell ( fill : none , it ) = rect (
width : 100% , height : 100% , inset : 1mm , outset : 0mm , fill : fill , stroke : none ,
align ( horizon , text ( fill : white , it ) )
)
locate ( loc => {
let colors = uni . uni-colors . at ( loc )
show : block . with ( width : 100% , height : auto , fill : colors . b )
grid (
columns : ( 25% , 1fr , 15% , 10% ) ,
rows : ( 1.5em , auto ) ,
cell ( fill : colors . a , uni . uni-short-author . display ( ) ) ,
cell ( uni . uni-short-title . display ( ) ) ,
cell ( uni . uni-short-date . display ( ) ) ,
cell ( logic . logical-slide . display ( ) + [ ~ /~ ] + utils . last-slide-number )
)
} )
}
set page (
margin : ( top : 2em , bottom : 1em , x : 0em ) ,
header : header ,
footer : footer ,
footer-descent : 0em ,
header-ascent : .6em ,
)
uni . matrix-slide ( .. bodies )
}
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 # let slide-outline-length ( loc ) = {
let section-state = state ( "polylux-sections" , ( ) )
let sections = section-state . final ( loc )
sections . len ( ) - 1
}
# let slide-outline ( num ) = {
set text ( font : "Cascadia Mono" )
locate ( loc => {
let section-state = state ( "polylux-sections" , ( ) )
let sections = section-state . final ( loc )
for p in range ( 0 , num ) {
let section = sections . at ( p )
let content = {
let url = link ( section . loc , section . body )
let page = logic . logical-slide . at ( section . loc ) . at ( 0 )
let length = 46 - str ( page ) . len ( ) - count-length ( section . body )
let dots = " " + "." * length
[ # grid (
columns : ( auto , 1fr , 1fr ) ,
url , align [ # dots ] , align ( right ) [ # page ]
) ]
}
[ + # content ]
}
} )
}
论文 LaPreprint 是一个很美观的预印本模板,主要适用于英文,为了适应一些中文的需求,个人做出了一些修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # let lapreprint (
outline-show : true ,
outline-depth : 2 ,
lang : "en" ,
body
) = {
if ( outline-show ) { outline (
title : if ( lang == "en" ) { "Content" } else { "目录" } ,
indent : 2em ,
depth : outline-depth ,
) }
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# lapreprint (
set page (
paper-size ,
margin : ( left : 20% , bottom : 1.5cm ) ,
)
)
# lapreprint (
set page (
paper-size ,
margin : ( left : auto , bottom : 1.5cm ) ,
)
)
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 # lapreprint (
set page (
footer : block (
if ( date != none ) {
if ( lang == "en" ) {
date . display ( "[month repr:short] [day], [year]" )
} else {
[ # date . year ( ) 年 # date . month ( ) 月 # date . day ( ) 日]
}
}
)
)
place (
if ( lang == "en" ) {
text ( size : 7pt , d . date . display ( "[month repr:short] [day], [year]" ) )
} else { [
# set text ( 7pt )
# d . date . year ( ) -# d . date . month ( ) -# d . date . day ( )
] }
)
if abstracts != none {
if ( lang == "en" ) {
text ( fill : theme , weight : "semibold" , "Keywords" )
} else {
text ( fill : theme , weight : "semibold" , "关键词" )
}
}
)
1 2 3 4 5 6 7 8 # lapreprint (
show figure : i-figured . show-figure
show figure . where (
kind : table
) : set figure . caption ( position : top )
show math . equation : i-figured . show-equation
)
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 # lapreprint (
show link : it => [ # text ( fill : theme ) [ # it ] ]
show ref : it => [ # text ( fill : theme ) [ # it ] ]
show ref : it => {
let el = it . element
if ( el != none ) {
let fn = repr ( el . func ( ) )
if ( fn == "equation" ) { link (
it . target ,
if ( lang == "en" ) { "Eq." } else { "式 " } +
numbering (
el . numbering ,
.. counter ( math . equation ) . at ( el . location ( ) )
)
) } else if ( fn == "heading" ) { link (
it . target ,
if ( lang == "en" ) { "Section " } else { "第 " } +
numbering (
el . numbering ,
.. counter ( heading ) . at ( el . location ( ) )
) + if ( lang == "zh" ) { " 节" }
) }
else { it }
} else { it }
}
)
其他 借助 Tablex 可以实现三线表的样式: 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
# import "@preview/tablex:0.0.6" : tablex , rowspanx , colspanx , hlinex , vlinex
# let three-line-table ( columns , headers , contents , caption , lang : "en" , rows : auto ) = { figure (
tablex (
columns : columns ,
rows : rows ,
align : center + horizon ,
auto-lines : false ,
repeat-header : true ,
hlinex ( stroke : 1.5pt ) ,
.. headers ,
hlinex ( stroke : 0.75pt ) ,
.. contents ,
hlinex ( stroke : 1.5pt ) ,
) ,
kind : table ,
supplement : [ # if ( lang == "en" ) { "Table" } else { "表" } ] ,
caption : caption ,
) }
# three-line-table (
2 ,
( [ * 参数 * ] , [ * 结果 * ] ) ,
(
[ $ sin ^ 2 ( 2 theta _ ( 12 ) ) $ ] , [ $ 0.857 pm 0.024 $ ] ,
[ $ sin ^ 2 ( 2 theta _ ( 23 ) ) $ ] , [ $ > 0.95 $ ] ,
[ $ sin ^ 2 ( 2 theta _ ( 13 ) ) $ ] , [ $ 0.098 pm 0.013 $ ] ,
[ $ Delta \m _ ( 12 ) ^ 2 $ ] , [ $ ( 7.50 pm 0.20 ) times 10 ^ ( - 5 ) "eV" ^ 2 $ ] ,
[ $ Delta \m _ ( 23 ) ^ 2 $ ] , [ $ 0.00232 _ ( - 0.00008 ) ^ ( + 0.00012 ) "eV" ^ 2 $ ] ,
[ $ delta \/ pi $ ] , [ $ 1.35 _ ( - 0.43 ) ^ ( + 0.64 ) $ ]
) ,
[ 中微子振荡参数测量结果# super [ @zqw2015daya @zym2018daya ] ] ,
lang : "zh" ,
) <nu_para>
公式块 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # let box-quote ( body , width : 100% , inset : 5pt , outset : 0pt ) = { block (
fill : green . lighten ( 80% ) ,
width : width ,
inset : inset ,
outset : outset ,
radius : 4pt ,
stroke : green . darken ( 60% ) ,
breakable : true ,
body
) }
# box-quote [ $
P _ ( nu _ alpha -> nu _ beta ) approx sin ^ ( 2 ) 2 theta sin ^ ( 2 ) ( ( m _ 1 ^ 2 - m _ 2 ^ 2 ) / ( 4 p ) t ) approx sin ^ ( 2 ) 2 theta sin ^ ( 2 ) ( Delta \m ^ 2 L / ( 4 E ) )
$ <2flavor_mix_4> ]
数学符号的简易别名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # import "@preview/physica:0.9.0" as ph
# let sp = [ # h ( 0.5em ) ]
# let pm = [ # sym . plus . minus ]
# let le = [ # sym . lt . eq . slant ]
# let ge = [ # sym . gt . eq . slant ]
# let sim = [ # sym . tilde . op ]
# let inf = [ # sym . infinity ]
# let rm ( body ) = { math . upright ( body ) }
# let iso ( b , A ) = [ # ph . isotope ( b , a : A ) ]
# let isoz ( b , A , Z ) = [ # ph . isotope ( b , a : A , z : Z ) ]
# box-quote [ $
1 pm 2 le 3 ge 4 sim 5 inf 6 sp rm ( A \b ) sp 7 sp "Ab" 8 sp iso ( U , 235 ) sp 9 sp isoz ( L \i , 7 , 3 )
$ ]
参考资料 Typst Documentation 为LaTeX用户准备的Typst入门 Typst Tablex 简单教程 Typst on Repology 中文用户指南 Typst-"超越"LaTeX的文档排版工具 Typst Examples Book