Skip to content

Snippet Format

zhangxh edited this page Aug 16, 2026 · 1 revision

Snippet 格式

TeXLeaf 的 Snippet 是经过结构验证的 JSON/JSONC 数据,不是 JavaScript 模块。推荐先使用 片段与模板 中的结构化管理器;只有需要批量审阅、版本控制项目附加规则或修复原始数据时,才直接编辑 JSONC。

安全模型

TeXLeaf 不使用 evalFunction、动态 import 或脚本沙箱执行 Snippet 文件。因此:

  • triggerreplacement 必须是字符串;
  • 正则表达式写成 JSON 字符串,并加入 r 选项;
  • 允许 JSONC 的 ///* ... */ 注释和尾随逗号;
  • 不允许 /pattern/ RegExp literal;
  • 不允许箭头函数、普通函数、变量引用、模板字符串或导入;
  • 无效条目会产生诊断并被跳过,不应阻止其他有效条目加载;
  • replacement 可以插入任意文本,但不能借此执行任意 JavaScript。

从网络复制规则时仍应审阅它最终会写入文档的 LaTeX 内容。

推荐库结构

当前全局库的文件格式版本是 1,出厂迁移 revision 是 3

{
  "version": 1,
  "defaultsRevision": 3,
  "variables": {
    "GREEK": "alpha|beta|gamma|delta",
  },
  "snippets": [
    {
      "id": "greek-name",
      "trigger": "(${GREEK})",
      "replacement": "\\@[0]",
      "options": "rmA",
      "flags": "u",
      "priority": 0,
      "description": "展开希腊字母名称",
      "category": "Greek",
      "enabled": true,
      "syntaxVersion": 2,
    },
  ],
}

顶层字段:

字段 类型 说明
version number 片段库文件格式版本,当前为 1
defaultsRevision number 工厂库迁移版本;全局主库应保留,项目附加文件可省略
variables object 可选的字符串映射,用于在 trigger 中展开 ${NAME}
snippets array Snippet 对象数组

少量导入规则或项目附加文件也可以使用数组简写:

[
  {
    "trigger": ";R",
    "replacement": "\\mathbb{R}",
    "options": "mA"
  }
]

数组简写不能保存 defaultsRevision 或顶层变量,不适合作为长期维护的全局主库。

Snippet 字段

字段 类型 必需 含义
trigger string 字面触发词;带 r 时是正则模式
replacement string 插入文本、tabstop、捕获组或 Visual 占位符
options string t/m/M/n/A/r/v/w 行为标志;默认空
priority number 冲突时数值越大越优先;默认 0
description string 搜索、补全和诊断中的说明
flags string 正则 flags,只允许 i/m/s/u/v
id string 稳定内部标识;便于迁移、导入导出和管理
category string 管理器和片段视图中的分类
enabled boolean 是否加载;默认 true
syntaxVersion 12 replacement 占位符语法;新规则推荐 2

不接受有状态的正则 flags gy。未知选项、类型错误、非法正则、NUL 字符或互相冲突的模式会使该条目被跳过。

模式选项

选项 作用
t 仅数学区域之外的文本模式
m 任意数学区域,相当于同时允许行内和块级
M 仅块级数学,例如 $$...$$\[...\] 或 align
n 仅行内数学,例如 $...$\(...\)

没有模式选项时,规则可在任何模式匹配。不要把互相矛盾的模式限制堆在同一条规则上。

行为选项

选项 作用
A 条件满足时自动展开
r 把 trigger 当作正则表达式
v Visual 规则,只对非空选区生效
w 要求 trigger 两侧满足词边界

省略 A 时,使用 texleaf.manualTrigger 指定的确认键,默认是 Tab,也可设为空格。宽泛或可能误触的规则适合手动确认;自动规则应选择明确 trigger。

rv 属于不同输入模型,不应混用。

v2 Tabstop

replacement 中的 @0@1@2 是展开后的光标停靠点:

{
  "trigger": "//",
  "replacement": "\\frac{@0}{@1}@2",
  "options": "mA",
  "syntaxVersion": 2
}

展开后光标先到 @0,按 Tab 依次到 @1@2。标记会转换为 VS Code 原生 snippet tabstop,不会写入源文件。

带默认文本的形式:

{
  "trigger": "dint",
  "replacement": "\\int_{@{0:0}}^{@{1:\\infty}} @2 \\, d@{3:x}",
  "options": "m"
}
  • @{0:0}:第 0 个停靠点,默认选中文本 0
  • @{1:\\infty}:第 1 个停靠点,默认 \infty
  • @@:插入字面量 @

正则捕获组

r 的 trigger 是紧邻光标之前匹配的正则字符串。v2 replacement 使用:

  • @[0]:第一个括号捕获组;
  • @[1]:第二个括号捕获组;
  • @[name]:命名捕获组 (?<name>...)
  • 捕获编号从零开始,@[0] 不是整个匹配。

例:

{
  "trigger": "([A-Za-z])(\\d)",
  "replacement": "@[0]_{@[1]}",
  "options": "rmA",
  "flags": "u",
  "description": "单字母数字下标",
  "syntaxVersion": 2
}

数学区域中输入 x2,结果是 x_{2}

JSON 字符串本身会处理一次反斜杠,所以正则的 \d 要写成 "\\d";要匹配 LaTeX 源码中的一个字面反斜杠,通常需要在 JSONC 中写四个反斜杠。

TeXLeaf 最多扫描光标前 texleaf.maxRegexScanLength 个字符,默认 512。应避免嵌套歧义量词和灾难性回溯模式。

Visual 选区

Visual replacement 用 @{VISUAL} 引用当前选择:

{
  "trigger": "U",
  "replacement": "\\underbrace{@{VISUAL}}_{@0}",
  "options": "mv",
  "description": "下花括号包裹选择",
  "syntaxVersion": 2
}

使用步骤:

  1. 选择数学源码;
  2. 运行 TeXLeaf: 用片段包裹所选内容
  3. 选择对应 Visual 规则。

Visual replacement 仍必须是字符串,不支持 (selection) => ... 函数。

v1 兼容与 v2 迁移

为了导入旧 snippet-leaf/HSnips 风格数据,TeXLeaf 保留 v1 占位符兼容:

含义 v1 v2(推荐)
第一个 tabstop $0 @0
第一个正则捕获组 [[0]] @[0]
Visual 内容 ${VISUAL} @{VISUAL}

Snippet 对象字段叫 syntaxVersion;不要把它和顶层库格式 version: 1 混淆。管理器新建规则默认采用 v2。

变量

顶层 variables 只允许字符串值:

{
  "variables": {
    "LETTER": "[A-Za-z]",
    "DIGIT": "[0-9]"
  },
  "snippets": [
    {
      "trigger": "(${LETTER})(${DIGIT})",
      "replacement": "@[0]_{@[1]}",
      "options": "rmA"
    }
  ]
}

变量用于构造 trigger,不会执行表达式。项目附加文件可以覆盖同名全局变量。

冲突与优先级

匹配选择会综合:

  1. 是否满足文件、模式、环境和词边界;
  2. 数字 priority,更大者优先;
  3. trigger 匹配具体程度和长度;
  4. 来源优先级:同等条件下,显式项目附加文件优先于全局库;
  5. 稳定加载顺序。

精确 Tab 兜底与自动展开共用同一套规则选择。若一条规则总被另一条抢先,先检查 priority、模式和 trigger 是否过于宽泛,而不是简单复制更多同名规则。

完整示例

{
  "version": 1,
  "defaultsRevision": 3,
  "variables": {},
  "snippets": [
    {
      "id": "user.real-numbers",
      "trigger": ";R",
      "replacement": "\\mathbb{R}",
      "options": "mA",
      "category": "User",
      "enabled": true,
      "syntaxVersion": 2
    },
    {
      "id": "user.norm",
      "trigger": "norm",
      "replacement": "\\left\\lVert @0 \\right\\rVert@1",
      "options": "m",
      "priority": 5,
      "category": "User"
    },
    {
      "id": "user.index",
      "trigger": "([A-Za-z])(\\d)",
      "replacement": "@[0]_{@[1]}",
      "options": "rmA",
      "flags": "u",
      "syntaxVersion": 2
    },
    {
      "id": "user.underbrace",
      "trigger": "U",
      "replacement": "\\underbrace{@{VISUAL}}_{@0}",
      "options": "mv",
      "syntaxVersion": 2
    }
  ]
}

校验与诊断

保存后 watcher 会自动重载。TeXLeaf: 重载片段 用于显式刷新和排错,不是每次保存的必需步骤。

遇到规则不生效时检查:

  • 文件是否已保存为 .tex.bib
  • language ID 是否位于 texleaf.languageIds
  • texleaf.enabledtexleaf.autoSnippets 是否开启;
  • t/m/M/n 是否符合当前位置;
  • 当前环境是否在 texleaf.excludedEnvironments
  • 是否位于 \label\tag\tag* 参数;
  • 是否有更高 priority 或更具体规则;
  • VS Code “问题”面板是否有 TeXLeaf 诊断;
  • 项目附加文件是否在未信任工作区中被禁用。

更完整的处理流程见 故障排查

相关页面

Clone this wiki locally