mcpField
T
typst-writing-document

typst-writing-document

github.com/myriad-dreamin文档处理3.6k40 次安装2 天前更新
代码仓库

关于 typst-writing-document

这项自包含技能用于撰写、修复和验证 Typst 文档,内置语法示例,并指导通过编译检查文本内容或视觉布局。

主要功能

  1. 01内置 Typst 语法示例
  2. 02渐进式编辑流程
  3. 03通过编译验证
  4. 04检查 HTML 文本
  5. 05结合 Playwright MCP 检查 SVG 布局

适用场景

  1. 01参考现有语法模式撰写 Typst 文档
  2. 02每次修改后通过编译检查
  3. 03检查文档文本或渲染布局

MCP 相关

需要检查视觉布局时,技能建议使用 Playwright MCP 查看 SVG 输出。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/myriad-dreamin/tinymist --skill typst-writing-document

安装后在 Claude Code 中输入/typst-writing-document确认已加载。

详细介绍

编写和验证 Typst 文档

当用户需要起草、修复或验证 Typst 文档时,使用此技能。本文件包含语法查询所需的一切内容,因此可以复制到其他代码库中,无需附带同级脚本或参考文件。

工作流

  1. 从本文件的语法查询部分开始,选择最接近的现有模式,再考虑发明新语法。
  2. 复制最匹配的最小示例,然后逐步调整。
  3. 每次完成重要编辑后,运行 typst compile。任何非零退出代码都表示阻塞性失败。
  4. 编译成功后,如果措辞或内容顺序很重要,请使用 HTML 输出检查渲染后的文本和文档结构。
  5. 如果需要检查视觉布局、间距、编号、换行或强调效果,请使用 SVG 输出和 Playwright MCP。

验证

编译验证:

typst compile --root . path/to/document.typ target/typst-grammar-authoring-check/document.pdf

通过 HTML 验证文本:

typst compile --root . --features html path/to/document.typ target/typst-grammar-authoring-check/document.html
rg "expected text" target/typst-grammar-authoring-check/document.html

通过 SVG 进行视觉验证:

typst compile --root . path/to/document.typ target/typst-grammar-authoring-check/document.svg
typst compile --root . path/to/document.typ target/typst-grammar-authoring-check/document-{0p}.svg

Playwright 检查:

  • 仅在成功生成 SVG 后使用 Playwright。
  • 如果 MCP 服务支持本地文件,请直接打开 SVG。
  • 否则,使用一个嵌入 SVG 的简易本地 HTML 包装页,然后截取屏幕截图并检查布局、间距、编号、换行和强调效果。

防护规则

  • 所有由此技能编写的说明和指令都必须使用英文。
  • 规范语法示例可以保留其源示例中的非英文文本字面量。
  • 不要将 Tinymist 或编辑器诊断视为事实依据。
  • 在其他地方使用此技能时,不要假定存在同级更新脚本、参考文件或代码库本地元数据。
  • 多页 SVG 输出路径中使用 {p} 或 {0p}。
  • 将 HTML 导出视为验证辅助工具,而非生产环境契约。
  • 命令示例应使用正斜杠或占位符路径,以确保跨平台兼容。

语法查询

本节有意嵌入于此,以确保技能自包含。示例改编自非官方教程中的语法样例,并经过精简,以便在单个文件中使用。

基础元素
  • paragraph:writing-markup
  • heading:= Heading;== Heading
  • strong:*Strong*
  • emph:_emphasis_;*_emphasis_*
  • list:
+ List 1
+ List 2
  • continue-list:
4. List 1
+ List 2
  • emum:
- Enum 1
- Enum 2
  • mix-list-emum:
- Enum 1
  + Item 1
- Enum 2
  • raw:
`code`
  • long-raw:
``` code```
  • lang-raw:
```rs  trait World```
  • blocky-raw:
```typ
= Heading
```
  • image:#image("/assets/files/香風とうふ店.jpg", width: 50pt)
  • image-stretch:#image("/assets/files/香風とうふ店.jpg", width: 50pt, height: 50pt, fit: "stretch")
  • image-inline:在一段话中插入一个#box(baseline: 0.15em, image("/assets/files/info-icon.svg", width: 1em))图片。
  • figure:
#figure(```typ
#image("/assets/files/香風とうふ店.jpg")
```, caption: [用于加载香風とうふ店送外卖的宝贵影像的代码])
  • link:#link("https://zh.wikipedia.org")[维基百科]
  • http-link:https://zh.wikipedia.org
  • internal-link:
== 某个标题 <ref-internal-link>
#link(<ref-internal-link>)[链接到某个标题]
  • table:#table(columns: 2, [111], [2], [3])
  • table-align:#table(columns: 2, align: center, [111], [2], [3])
  • inline-math:$sum_x$
  • display-math:$ sum_x $
  • escape-sequences:>\_<
  • unicode-escape-sequences:\u{9999}
  • newline-by-space:A \ B
  • newline:
A \
B
  • shorthand:北京--上海
  • shorthand-space:A~B
  • inline-comment:// 行内注释
  • cross-line-comment:
/* 行间注释
  */
  • box:在一段话中插入一个#box(baseline: 0.15em, image("/assets/files/info-icon.svg", width: 1em))图片。
文本样式
  • highlight:#highlight[高亮一段内容]
  • underline:#underline[Language]
  • underline-evade:
#underline(
  evade: false)[ጿኈቼዽ]
  • overline:#overline[ጿኈቼዽ]
  • strike:#strike[ጿኈቼዽ]
  • subscript:威严满满#sub[抱头蹲防]
  • superscript:香風とうふ店#super[TM]
  • text-size:#text(size: 24pt)[一斤鸭梨]
  • text-fill:#text(fill: blue)[蓝色鸭梨]
  • text-font:#text(font: "Microsoft YaHei")[板正鸭梨]
Script Declarations
  • enter-script: #1
  • code-block: #{"a"; "b"}
  • content-block: #[内容块]
  • none-literal: #none
  • false-literal: #false
  • true-literal: #true
  • integer-literal: #(-1), #(0), #(1)
  • n-adecimal-literal: #(-0xdeadbeef), #(-0o644), #(-0b1001)
  • float-literal: #(0.001), #(.1), #(2.)
  • exp-repr-float: #(1e2), #(1.926e3), #(-1e-3)
  • string-literal: #"Hello world!!"
  • str-escape-sequences: #"\""
  • str-unicode-escape-sequences: #"\u{9999}"
  • array-literal: #(1, "OvO", [一段内容])
  • dict-literal: #(neko-mimi: 2, "utterance": "喵喵喵")
  • empty-array: #()
  • empty-dict: #(:)
  • paren-empty-array: #(())
  • single-member-array: #(1,)
  • var-decl: #let x = 1
  • func-decl: #let f(x) = x * 2
  • closure: #let f = (x, y) => x + y
  • named-param: #let g(named: none) = named
  • variadic-param: #let g(..args) = args.pos().join([、])
  • destruct-array: #let (one, hello-world) = (1, "Hello, World")
  • destruct-array-eliminate: #let (_, second, ..) = (1, "Hello, World", []); #second
  • destruct-dict: #let (neko-mimi: mimi) = (neko-mimi: 2); #mimi
  • array-remapping:
#let (a, b, c) = (1, 2, 3)
#let (b, c, a) = (a, b, c)
#a, #b, #c
  • array-swap:
#let (a, b) = (1, 2)
#((a, b) = (b, a))
#a, #b
  • placeholder:
#let last-two(t) = {
  let _ = t.pop()
  t.pop()
}
#last-two((1, 2, 3, 4))
Script Statements
  • if:
#if true { 1 },
#if false { 1 } else { 0 }
  • if-if:
#if false { 0 } else if true { 1 },
#if false { 2 } else if false { 1 } else { 0 }
  • while:
#{
  let i = 0;
  while i < 10 {
    (i * 2, )
    i += 1;
  }
}
  • for:
#for i in range(10) {
  (i * 2, )
}
  • for-destruct: #for (特色, 这个) in (neko-mimi: 2) [猫猫的 #特色 是 #这个\ ]
  • break: #for i in range(10) { (i, ); (i + 1926, ); break }
  • continue:
#for i in range(10) {
  if calc.even(i) { continue }
  (i, )
}
  • return:
#let never(..args) = return
#type(never(1, 2))
  • include: #include "other-file.typ"
Script Styling
  • set:
#set text(size: 24pt)
四斤鸭梨
  • scope:
两只#[兔#set text(fill: rgb("#ffd1dc").darken(15%))
  #[兔白#set text(fill: orange)
  又白],真可爱
]
  • set-if:
#let is-dark-theme = true
#set rect(fill: black) if is-dark-theme
#set text(fill: white) if is-dark-theme
#rect([wink!])
  • show-set:
#show: set text(fill: blue)
wink!
  • show:
#show raw: it => it.lines.at(1)
获取代码片段第二行内容:```typ
#{
set text(fill: true)
}
```
  • text-selector:
#show "cpp": strong(emph(box("C++")))
在古代,cpp是一门常用语言。
  • regex-selector:
#show regex("[”。]+"): it => {
  set text(font: "KaiTi")
  highlight(it, fill: yellow)
}
“无名,万物之始也;有名,万物之母也。”
  • label-selector:
#show <一整段话>: set text(fill: blue)
#[$lambda$语言是世界上最好的语言。] <一整段话>

另一段话。
  • selector-exp:
#show heading.where(level: 2): set text(fill: blue)
= 一级标题
== 二级标题
  • here: #context here().position()
  • here-calc: #context [ 页码是偶数:#calc.even(here().page()) ]
  • query: #context query(<ref-internal-link>).at(0).body
  • state: #state("my-state", 1)
Script Expressions
  • func-call: #calc.pow(4, 3)
  • content-param: #emph[emphasis]
  • member-exp:
#`OvO`.text
  • method-exp: #"Hello World".split(" ")
  • dict-member-exp:
#let cat = (neko-mimi: 2)
#cat.neko-mimi
  • content-member-exp:
#`OvO`.text
  • repr: #repr[ 一段文本 ]
  • type: #type[一段文本]
  • eval: #type(eval("1"))
  • eval-markup-mode: #eval("== 一个标题", mode: "markup")
  • array-in:
#let pol = (1, "OvO", [])
#(1 in pol)
  • array-not-in:
#let pol = (1, "OvO", [])
#([另一段内容] not in pol)
  • dict-in:
#let cat = (neko-mimi: 2)
#("neko-mimi" in cat)
  • logical-cmp-exp:
#(1 < 0), #(1 >= 2),
#(1 == 2), #(1 != 2)
  • logical-calc-exp: #(not false), #(false or true), #(true and false)
  • plus-exp: #(+1), #(+0), #(1), #(++1)
  • minus-exp:
#(-1), #(-0), #(--1),
#(-+-1)
  • arith-exp:
#(1 + 1), #(1 + -1),
#(1 - 1), #(1 - -1)
  • assign-exp: #let a = 1; #repr(a = 10), #a, #repr(a += 2), #a
  • string-concat-exp: #("a" + "b")
  • string-mul-exp: #("a" * 4), #(4 * "ab")
  • string-cmp-exp: #("a" == "b"), #("a" != "b"), #("a" < "ab"), #("a" >= "a")
  • int-to-float: #float(1), #(type(float(1)))
  • bool-to-int: #int(true), #(type(int(true)))
  • float-to-int: #int(1), #(type(int(1)))
  • dec-str-to-int: #int("1"), #(type(int("1")))
  • nadec-str-to-int:
#let safe-to-int(x) = {
  let res = eval(x)
  assert(type(res) == int, message: "should be integer")
  res
}
#safe-to-int("0xf"), #(type(safe-to-int("0xf"))) \
#safe-to-int("0o755"), #(type(safe-to-int("0o755"))) \
#safe-to-int("0b1011"), #(type(safe-to-int("0b1011"))) \
  • num-to-str:
#repr(str(1)),
#repr(str(.5))
  • int-to-nadec-str: #str(501, base:16), #str(0xdeadbeef, base:36)
  • bool-to-str: #repr(false)
  • int-to-bool:
#let to-bool(x) = x != 0
#repr(to-bool(0)),
#repr(to-bool(1))

评论

支持 Markdown