一个VSCode插件:支持TikZ预览

1. 起因

我的博客文章里面的插图大部分都是使用TikZ画的,而这个没有办法直接预览,就导致我需要在多个编辑器之间不断切换。

大致流程是这样的:

  1. 使用VSCode写文章的主体。(可以自动在编辑LaTeX的时候切换中英文)
  2. 期间使用VSCode写单独的TikZ代码。(可以自动补全TikZ函数)
  3. 同时使用KtikZ预览TikZ代码。(可以实时预览图片,方便修正语法错误和微调)
  4. 之后利用pdf2svg将TikZ代码转化成SVG图片,然后插入到文章中
  5. 最后利用Typora预览整个文章。(可以正确显示图片)

之前我使用Vibe Coding搓了一个插件,让VSCode的Markdown预览和鼠标悬停预览能够识别文档顶部的YAML元数据中的typora-root-url字段,这样保存在子文件夹里面的图片就能够正常加载了。

顺带着,也让VSCode的Markdown预览支持了NexT主题的Note标签。

这样预览看着就更舒服了。

因此,现在再写文章的时候就不需要上面第5个步骤了,最终文章的预览可以直接在VSCode里面完成。

这次,我的目标是干掉第3个步骤,这样就可以把所有的流程都留在VSCode里完成了。

2. 已有的类似解决方法

目前已有的一些能够预览TikZ代码的插件,基本都是基于tikzjax或它的移植,详细介绍可见这篇文章

这个技术有两个问题:

  • 不支持LuaLaTeX
  • 不支持shell escape

第一个问题导致tkz-elements宏包无法使用,第二个问题导致tkz-fct宏包无法使用。

其中

  • tkz-elements宏包是用来画几何图形;
  • tkz-fct宏包是用来画函数图像的,依赖shell escape来调用gnuplot

由于这些使用tikzjax插件底层都依赖于web2js 这个项目,它是将原始的TeX引擎编译为WASM。因此都没有办法支持LuaLaTeX。

能够支持LuaLaTeX的WASM引擎确实有,例如TeXlyre BusyTeX,但是也有两个问题:

  • 使用LuaLaTeX至少需要texlive-recommended这个级别的宏包集合,因此需要大量的空间:
    • WASM约占32MB;
    • texlive-recommemded约占200MB;
    • 如果是包含tkz系列宏包的texlive-extra则占340MB。
  • 它不支持shell escape。

因此,我最终决定,还是仿照KtikZ,使用本地已有的TeX环境。

3. Vibe Coding

这次我主要使用的是Claude Code配合deepseek-v4-pro。

具体实现方法是使用本地TeX环境在临时文件夹编译TikZ代码,然后使用PDF.js进行预览。

另外,这次使用了superpower这个skill,主要作用是在给出目标后会先通过提问来完善结构、补充细节。

它的使用体验感很好,很多问题在还没有开始写代码的时候就解决了。

开始生成的代码无法正确渲染PDF,不过通过几轮debug最终自己解决了。

之后又增加了SVG预览的模式。

截至功能基本完成(v0.2.1),花费的tokens如下:

模型 deepseek-v4-flash deepseek-v4-pro
输入(缓存) 2,109,696 55,529,600
输入(非缓存) 244,834 167,874
输出 48,470 130,584
价格(¥) 0.38 2.67
缓存命中率 89.7% 99.7%

其中deepseek-v4-flash部分主要是在使用superpower的时候,实际编写代码时其实是拉起了sub-agent来处理的。

也就是说,编写spec/plan的时候用的是pro模型,具体写代码用的是flash模型。

不过,实际上我看主要的代码在plan里都已经写好了。

4. Code Review

第二天,我又使用Codex(gpt-5.5)进行code review,找到了一个关键的bug,还有几个不影响使用的小问题。

关键的bug是如果在编辑完一个TikZ文件之后快速切换到另一个TikZ文件,会导致渲染的还是之前的文件,不会切换到新的文件。

这个bug我在实际调试的时候没有发现,因为之前在使用KtikZ的时候习惯了在编辑完文档之后等待图像刷新。这个完全是根据它给出的步骤复现的。

最终通过三轮debug解决了。

不过,解决完这几个问题,免费版的月余额就只剩12%了。

具体的Tokens用量如下:

项目 用量
输入(缓存) 3,608,448
输入(非缓存) 184,453
输出 19795
输出(思考) 5715

5. 成果

最终的插件源代码见vscode-tikz-preview,VSCode插件见TikZ Preview

使用插件的实际情况如下:

使用PDF预览:

PDF预览

使用SVG预览(调用SVG插件):

SVG预览

具体的配置选项基本是照搬KtikZ的:

选项 默认值 说明
latexCommand pdflatex 可根据实际需要改为lualatex或xelatex
shellEscape false 使用tkz-fct等宏包需要启用这个选项
templatePath "" 默认为自带的模板文件
和KtikZ的默认模板相同
templatePlaceholder <> 和KtikZ相同
autoOpen false 在打开TikZ文件的时候是否自动打开预览界面
autoOpenExtensions .tikz
.pgf
.tkz
TikZ文件的后缀
previewMode pdf 预览模式,支持pdf和svg两种
svgConverter pdftocairo PDF转换成SVG的命令
可选pdftocairo和pdf2svg

其它的使用体验也和KtikZ是一致的,停止编辑1s之后,会自动编译文件并渲染到右侧。

如果编译出现错误,会输出在下面的输出栏。如果是使用PDF模式,错误也会显示在右边的预览区域。

因此,如果之前使用的是KtikZ的话,可以无缝切换到这个插件。

顺带说一句,KtikZ可以只使用QT6进行编译,这样就不用依赖KDE组件了,不过需要一点修改。

具体方法和patch可见我的Gentoo仓库

6. 感想

6.1. Tokens用量

之前在网上有讨论每天用一亿tokens如何如何,对此评价不一。

这次实际从零开始写了一个小项目,从上面的表格可以看到,使用了超过50M的tokens。

当然,大部分其实都是多轮对话的缓存(中间没有中断过会话,也没有压缩过上下文)。

而这一共花了多长时间呢?5个小时。

因此,如果是重度使用Vibe Coding,一天烧一亿tokens并不算多。

6.2. 编写skill

完成一定功能之后,发布新版本是一个比较机械且无聊的事情。于是我决定让Claude Code来自己完成这个任务。

它自动调用了skill-creator来创建了一个skill,并将我的要求自动转换成了skill文件。之后,我只用输入bump major/minor/patch version,他就会自动发布新版本,并更新ChangeLog和README文件。

不过,这种自动生成的skill文件务必要手动检查一下,否则很有可能造成错误的修改。

6.3. 慎用resume

第二天我在修改代码的时候,顺手使用了claude --resume,然后Tokens就爆炸了。好死不死的,我还连着resume了三次,于是:

alt text

未命中的输入tokens数量甚至超过了昨天的4倍!!!

这就导致,虽然第二天我只是用Claude Code更新了一些文档,花的钱几乎和第一天持平了。。。