Typst 官方 VS Code 语言支持扩展解析:tools/support 的语言注册、编辑行为配置与 TextMate 语法规则
【免费下载链接】typstA markup-based typesetting system that is powerful and easy to learn.项目地址: https://gitcode.com/GitHub_Trending/ty/typst
本文为 Typst 仓库中 tools/support 目录下官方随附的 VS Code 语言支持扩展做逐文件解析。读完本篇,你将理解一个最小化语言扩展是如何通过package.json声明语言 ID 与语法、通过config.json控制注释切换与括号自动补全、通过typst.tmLanguage.json实现 markup 与 code 双上下文的 TextMate 高亮规则的,并掌握通过符号链接安装该扩展的具体方法及其维护状态。
扩展的定位与维护状态
根据 tools/support/README.md 的说明,该扩展为 Typst 提供最小化(minimal)的语言支持,内容仅包含两样东西:
- 一份语法定义(TextMate grammar),用于语法高亮;
- 一份语言配置(language configuration),用于注释切换、括号自动关闭等编辑器行为。
README 同时给出了三条明确的使用前提,这也是读者在评估是否采用前必须了解的事实:
- 该扩展最初是为 Typst 自身的开发目的而创建的("created for development purposes only"),主要服务于 Typst 仓库内部开发者编辑
.typ文件; - 它当前不被维护,且官方承认其语法规则存在 bug("It is not maintained and its grammar is buggy");
- 官方建议有日常编辑需求的用户改用第三方更积极维护的Tinymist 扩展,本仓库内的
tools/support应视为"轻量兜底方案"而非正式编辑器产品。
从仓库结构看,tools/目录下与 VS Code 生态相关的还有 tools/test-helper 扩展——这是一个帮助管理 Typst 测试套件的辅助扩展,二者都属于仓库开发工具链的一部分,而非发行给终端用户的组件。
扩展清单:package.json 如何声明一个 Typst 语言
package.json 是整个扩展的入口清单,虽然只有 29 行,但完整覆盖了 VS Code 语言扩展所需的最小字段集。
基本元信息
| 字段 | 值 | 说明 |
|---|---|---|
name | typst | 扩展标识名 |
displayName | Typst | 编辑器中显示的名称 |
description | Typst Language Support. | 扩展用途描述 |
version | 0.0.1 | 版本号为初始占位值,侧面印证 README 中"未正式维护"的定位 |
engines.vscode | ^1.53.0 | 要求 VS Code 1.53 及以上版本 |
categories | ["Programming Languages"] | 声明为编程语言类扩展 |
语言注册(contributes.languages)
清单在contributes.languages中注册了 Typst 语言:
"languages": [ { "id": "typst", "aliases": ["Typst", "typst"], "extensions": [".typ"], "configuration": "./config.json" } ]这一节做了四件事:
id: "typst":确定语言标识符,后续语法、主题覆盖、语言特定设置都以此为锚点;aliases:Typst与typst两种写法都可用于编辑器状态栏的语言切换器;extensions: [".typ"]:把.typ文件后缀绑定到该语言。仓库中大量.typ源文件(如 tests/suite 下的测试用例、docs 下的文档源文件)即依赖此绑定获得高亮;configuration: "./config.json":指向下一节要详细解析的语言行为配置文件。
语法注册(contributes.grammars)
"grammars": [ { "language": "typst", "scopeName": "source.typst", "path": "./typst.tmLanguage.json" } ]它将typst语言与 TextMate 语法文件绑定,并声明了顶层作用域名source.typst。这一点与 typst.tmLanguage.json 末尾的"scopeName": "source.typst"字段相互呼应——两个文件中的 scopeName 必须一致,语法主题才能正确命中规则。
语言行为配置:config.json 全字段解析
config.json 是 VS Code 语言配置协议(Language Configuration)的标准文件,共 29 行,定义了 Typst 在编辑器中的交互行为。逐项说明如下。
注释定义(comments)
"comments": { "lineComment": "//", "blockComment": ["/*", "*/"] }- 行注释前缀为
//,编辑器中Ctrl+/注释切换即基于此; - 块注释定界符为
/* ... */,支持 VS Code 的块注释插入与切换。
括号配对(brackets)
"brackets": [ ["[", "]"], { 实际为 ["{", "}"], ["(", ")"] ]声明了三组结构性括号,用于编辑器的括号跳转、选中扩展等功能。
自动闭合对(autoClosingPairs)
"autoClosingPairs": [ { "open": "[", "close": "]" }, { "open": "{", "close": "}" }, { "open": "(", "close": ")" }, { "open": "\"", "close": "\"", "notIn": ["string"] }, { "open": "$", "close": "$", "notIn": ["string"] } ]三组括号之外,还有两个与 Typst 语义直接相关的配置:
- 双引号自动闭合,且
notIn: ["string"]限定只在字符串作用域之外触发,避免在字符串内部再次输入"时被错误补全; - 美元符号
$自动闭合——这是针对 Typst 数学定界符的专门配置:在正文中敲入$时会自动补上闭合$,方便快速包裹行内数学。
自动闭合字符(autoCloseBefore)
"autoCloseBefore": "$ \n\t"表示$、空格、换行符与制表符这些字符出现前会先触发未闭合括号的自动闭合。将$列入其中,同样是服务于"在数学表达式结束处自然收束定界符"的编辑体验。
环境包裹对(surroundingPairs)
"surroundingPairs": [ ["[", "]"], ["{", "}"], ["(", ")"], ["\"", "\""], ["*", "*"], ["_", "_"], ["`", "`"], ["$", "$"] ]当光标位于一段选中文字之间时,输入该对的左侧字符会用整对符号包裹选区。除常规括号与引号外,特别纳入了*、_、`、$四组——它们正好对应 Typst 标记语言中的粗体(*text*)、斜体(_text_)、原始文本/代码块(反引号)、数学定界符四种行内语法,使得"选中一段文字后直接敲_变斜体"这类操作可以一步完成。
高亮引擎:typst.tmLanguage.json 语法结构详解
typst.tmLanguage.json 是一份标准 TextMate 语法定义(共约 382 行),也是该扩展的核心资产。它的整体组织方式如下:
顶层 patterns → #markup(入口) repository: ├─ comments 注释规则(块注释 + 行注释) ├─ common 公共 include(目前仅注释) ├─ markup 正文(markup 上下文)规则集 ├─ code 代码(code 上下文)规则集 ├─ constants 常量与字面量规则集 └─ arguments 函数参数规则集顶层只有一条{"include": "#markup"}(见 typst.tmLanguage.json#L3-L5),意味着所有规则都从 markup 上下文出发,进入#代码区后再切换到 code 上下文——这与 Typst "标记中嵌代码、代码中嵌标记"的双层语法结构完全对应。
双上下文设计:markup 与 code 的切换
markup 规则集末尾(#L206-L209)有一条兜底规则:
{ "name": "meta.block.content.typst", "begin": "#", "end": "\\s", "patterns": [{ "include": "#code" }] }它把#之后的代码段交给#code规则集处理;而 code 上下文(#L217-L228)又反过来处理两种嵌套容器:
{...}代码块 → 递归进入#code;[...]内容块 → 递归切回#markup。
这种双向递归使语法能够正确区分#let x = [正文]中的正文部分与代码部分,例如:
#let title = "Hello" #show heading.where(level: 1): set text(size: 14pt) = 第一章 这是 **粗体**、*斜体*、`raw` 文本与 $x^2$ 数学。 <figure-label>@figure-label #enum(items) { item => text[item] }注释规则的一个细节
markup 上下文的行注释规则(#L17-L21)使用了负向后顾(?<!:)//:
{ "name": "comment.line.double-slash.typst", "begin": "(?<!:)//" }要求//前不能紧跟冒号,目的是避免把http://这类 URL 中的斜杠误判为行注释起始(markup 中另有独立的 URL 高亮规则,#L80-L82)。而 code 上下文中的//注释(#L231-L235)则没有这个限制,因为 Typst 代码区里//就是纯粹的注释。
markup 上下文覆盖的典型语法点
从 typst.tmLanguage.json 的 markup 规则集(#L30-L212)可以核对以下 Typst 正文语法均被覆盖:
| 语法 | 作用域 / 匹配 | 位置 |
|---|---|---|
转义字符(\*\#\_及\u{...}等) | constant.character.escape.content.typst | L34-L36 |
手动换行\\ | punctuation.definition.linebreak.typst | L38-L40 |
不换行空格~、软连字符-? | punctuation.definition.nonbreaking-space.typst等 | L41-L48 |
破折号--/---、省略号... | punctuation.definition.en-dash.typst等 | L49-L60 |
符号引用:sym:(如:star:) | constant.symbol.typst | L62-L64 |
粗体*text*/ 斜体_text_ | markup.bold.typst/markup.italic.typst,且支持内部再递归#markup | L66-L78 |
| URL 高亮 | markup.underline.link.typst | L80-L82 |
| 原始文本:反引号行内与 ```` `` 块级 | markup.raw.inline.typst/markup.raw.block.typst | L84-L94 |
数学定界$...$ | string.other.math.typst | L96-L100 |
标题= 一级标题 | markup.heading.typst+entity.name.section.typst | L102-L108 |
| 无序/有序/描述列表 | punctuation.definition.list.*.typst | L110-L123 |
标签<label>与引用@label | entity.other.label.typst/entity.other.reference.typst | L125-L133 |
语句#let / #set / #show / #context / #import / #include / #export / #if | 各自keyword.*作用域,块体递归#code | L135-L186 |
控制流#for / #while / #break / #continue / #return | keyword.control.*.typst | L159-L186 |
函数名(#name(...)/#name[...]) | entity.name.function.typst | L188-L192 |
| 函数调用参数区 | 复用#arguments规则集 | L194-L199 |
变量插值#var | entity.other.interpolated.typst | L200-L204 |
code 上下文与常量体系
code 规则集(#L213-L314)处理裸代码(如{ ... }块内)中的词法单元:
- 分隔符与运算符:
,:分隔符,=>与..运算符,== != <= < >= >关系运算符,+= -= *= /= =赋值运算符,算术运算符+ * / -(其中减号用负向后顾排除标识符内部的-),以及and / or / not逻辑字面运算符; - 关键字:
let as in set show context、if else、for while break continue、import include export、return全部有对应的keyword.*规则; - 函数识别:两条
entity.name.function.typst规则分别匹配"标识符后跟[或("的函数调用,以及show 选择器:函数模式下的被绑定函数名(#L286-L294); - 兜底变量:任何未被前述规则命中的标识符都归入
variable.other.typst(#L303-L305)。
constants 规则集(#L315-L370)则把 Typst 的字面量做成了完整的常量家族:
| 常量类型 | 匹配示例 | 作用域 |
|---|---|---|
none/auto | 关键字常量 | constant.language.none.typst/constant.language.auto.typst |
| 布尔值 | truefalse | constant.language.boolean.typst |
| 长度 | 10pt1.5em2in12mm0.5cm | constant.numeric.length.typst |
| 角度 | 90deg1.5rad | constant.numeric.angle.typst |
| 百分比 | 50% | constant.numeric.percentage.typst |
| 弹性单位 | 1fr | constant.numeric.fr.typst |
| 整数(含进制) | 420xFF0b1010o7 | constant.numeric.integer.typst |
| 浮点数 | 3.141e-3 | constant.numeric.float.typst |
| 字符串(含转义) | "a\nb"\u{..}等 |string.quoted.double.typst` |
值得注意的是,fr、长度单位与角度单位在这里都有独立的高亮作用域——这与 Typst 语言本身把12pt、50%、1fr作为带类型数值一等公民的设计相呼应,也让基于作用域的自定义主题可以分别给不同量纲着色。
arguments 规则集(#L371-L379)负责函数参数列表的高亮:以:结尾的标识符被标记为variable.parameter.typst(具名参数/参数标签),其余部分继续按 code 规则处理。
安装方式:符号链接法
README 给出的唯一安装方式是符号链接:
The simplest way to install this extension (and keep it up-to-date) is to add a symlink from
~/.vscode/extensions/typst-supporttopath/to/typst/tools/support.
即把用户目录下的 VS Code 扩展挂载点~/.vscode/extensions/typst-support软链到本地仓库中的tools/support目录。这一方式有两个直接好处:
- 始终与仓库代码同步:软链指向的是源码目录本身,对语法文件的任何改动在编辑器侧无需"重装"即可生效,适合 Typst 仓库内部开发时边改语法边验证;
- 不产生副本:仓库中不存在打包/发布流程(从清单中也没有 marketplace 发布相关字段看,可以推断该扩展未走扩展市场分发),软链是最省事的挂载方式。
Windows 用户若需实现同样效果,可使用管理员权限的mklink /D创建目录符号链接。需要再次强调 README 的告诫:由于官方明确其"仅用于开发目的、不再维护、语法存在 bug",对高亮质量有更高要求的日常写作场景,建议转向第三方 Tinymist 扩展。
在仓库中的位置与验证方式
结合仓库现状可以这样理解该组件的边界:
- 它不参与编译管线:根 Cargo.toml 的 workspace members 为
crates/*、docs、tests等,tools/下的两个扩展均独立于 Rust 工作区,仅供编辑器侧使用; - 它是纯声明式资源:全部功能由三个 JSON 文件表达(清单、语言行为、语法规则),没有可执行代码,因此"运行"它的方式就是让 VS Code 加载这个目录;
- 语法覆盖是否有效,可以用仓库中现成的
.typ文件直接验证——例如打开 tests/suite/foundations 或 docs/content/tutorial 下的任一 Typst 源文件,观察标题、数学、#set语句与12pt类常量是否获得预期高亮; - 仓库对开发者的相关提示还散见于 tests/src/args.rs(建议用
code --diff在 VS Code 中查看测试 diff)与 tests/README.md(介绍tools/test-helper扩展),说明tools/目录整体是 Typst 团队内部开发工作流的配套工具。
小结
tools/support用一个不到 400 行的 TextMate 语法、一个 29 行的语言配置和一个 29 行的扩展清单,搭出了 Typst 在 VS Code 中的最小可用语言体验:语言 ID 与.typ后缀绑定、注释/括号/数学定界符的编辑行为、以及 markup 与 code 双上下文递归的高亮体系。它当前的官方定位是"开发用、未维护"的兜底方案,日常重度使用建议参考官方推荐的第三方 Tinymist 扩展;但作为理解 Typst 语法在编辑器侧如何被表达的一份"活文档",这三个 JSON 文件值得任何想要自定义 Typst 主题或构建自己编辑器集成的开发者逐条阅读。
【免费下载链接】typstA markup-based typesetting system that is powerful and easy to learn.项目地址: https://gitcode.com/GitHub_Trending/ty/typst
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考