使用 Vibe Coding 编写一个属于自己的 VSCode 插件
在写这个博客里的内容以及类似的文章的时候,我一般使用VSCode和Typora两个软件进行编辑。
Typora的优点是可以实时预览文章内容,可以正确显示博客里引用的图片。Hexo博客会将图片存在与markdown文件同名的文件夹中[1],而Typora支持通过在YAML Front Matter里面指定typora-root-url[2]作为图片路径的前缀。
而VSCode的优点在于输入公式比较方便,可以在编辑数学公式的时候自动切换中英文[3],通过配置[4]也可以支持正确添加图片,但是图片文件的路径是相对于markdown文件所在文件夹的路径,这个Hexo的设置是不一样的。一旦修改成Hexo需要的路径之后,VSCode就无法找到正确的图片了。
这点在写新的文章的时候还不太要紧,因为可以在写完文章后统一修改图片路径。但是在修改旧的文章的时候,由于无法正确预览图片,就不太方便了。
要让VSCode实现这个功能,就必须通过插件来完成。但是由于我不懂VSCode插件的开发,甚至不熟悉Typescript的语法,这个想法一直被我放下了。最近看到了oh-my-opencode项目,于是想着能否利用vibe coding来写一个插件,满足我上面的要求。
1. 第一次尝试
去年在MiniMax M2.1刚发布的时候,限时免费了一段时间,加上赠送的代金券,我尝试用它配合Cline来日常使用,效果还可以。因此我这次打算用opencode免费提供的minimax-m2.1-free模型,配oh-my-opencode的ulw模式使用。
就在我写这个插件的第2天,Minimax发布了M2.5模型,之后第3天opencode就把免费模型替换成了新的M2.5模型。所以实际上是两个模型混着用的。
起初我把需求丢给opencode,结果确实写出了一个像模像样的插件,包括了扩展入口、一个markdown-it插件和一个yaml front matter解析器。尝试对它进行调试,它还在调试日志中告诉你「插件已成功加载」,但就是没有任何实际的作用。
尝试让它自己去debug,但是多次尝试始终未能成功。
无奈,只能手动去查看文档。
发现主要的问题出现在两个地方:
- 注册markdown-it插件的方法完全是错误的。
- 在markdown-it插件里面,获取文档内容的方法完全是错误的,致使实际上无法获取yaml front matter的内容。
这就导致了插件彻底无法工作。而且,在debug的过程中,它完全没有想到要求修改这两个地方。
也就是说,整个插件都是废的。
猜测主要原因是这两部分的语法没有问题,「表面」上的语义也没有问题,但实际上它用到的东西根本不存在。
2. 手动搭建框架
无奈,还是只能从头开始手写。
首先,使用yo code搭建项目架构。根据官方文档,VSCode使用markdown-it来解析markdown文件,因此我们只需要实现一个markdown-it插件即可。
我们先实现一个markdown-it插件:
1 | import type MarkdownIt from 'markdown-it'; |
核心代码是重写了图片渲染逻辑md.renderer.rules.image,在正常渲染图片之前修改了图片的src属性。
然后使用extendMarkdownIt调用插件:
1 | export function activate(context: vscode.ExtensionContext) { |
这里为了检查代码逻辑,图方便先写死了imageDir。
另外,还需要在package.json中将这个扩展注册为markdown-it插件:
1 | "contributes": { |
调试插件,终于能够正常修改图片的路径了。
3. 动态加载图片路径
接下来,要解决的问题就是如何针对每个markdown文件获取typora-root-url信息,并使用它作为图片所在目录。
我的第一个想法是把imageDir存到env中,这样只需要读取一次,然后之后直接从env中调用即可:
1 | import fs from 'fs'; |
上面的代码确实能够满足要求,但是有一个问题,就是对修改typora-root-url的响应非常不及时,有很大的滞后性。
于是,我又尝试了第二种方法,就是每次从YAML Front Matter里动态获取imageDir:
1 | import frontMatter from 'markdown-it-front-matter'; |
这样只要已修改typora-root-url的配置,立马就会在渲染中响应。
4. 支持图片链接的跳转和悬停预览
上面解决的是在右侧预览窗口里面的图片路径问题。另外还有一个需要适配的是在编辑界面的预览。
VSCode在鼠标指向图像链接的时候,会弹出该图像的预览。按住Ctrl单击,会跳转到对应的图片文件。我需要复现这两个功能。
这个部分让我自己写是完全不可能的,因此只能再次尝试vibe coding了。
好在,这次的结果还基本让人满意。
把需求喂给opencode之后,按住Ctrl单击的功能第一次就实现了,但是图像预览没有成功。不过让它自己进行debug,最终还是成功基本完成了这个任务。
不过,还是有一些小问题需要手动处理。
4.1. 问题一
其中一个是我提出的一个新的功能要求。上面实现的图像预览虽然成功了,但是由于有一些图像本身特别大,无法在预览框里完整显示(VSCode自带的图像预览是可以缩放到合适的大小的)。
尝试多次让opencode进行修改,都没有成功。无奈只能手动修改。
这里面最关键的点,在于VSCode到底是如何渲染markdown的图片的。
查看VSCode的源代码,从markdownRenderer.ts可以看到,它调用了parseHrefAndDimensions函数来识别图像的高度和宽度,该函数的定义位于htmlContent.ts,具体定义如下:
1 | export function parseHrefAndDimensions(href: string): { href: string; dimensions: string[] } { |
从这里可以看出,VSCode接受这样指定图片尺寸的方式。由此,我们可以根据图片的长宽比例指定预览的宽度或高度。
4.2. 问题二
另一个问题是显示的链接下划线部分,长度和VSCode显示的不一致。尝试让opencode进行修改,但是最终还是差了1个长度,而且固执地认为算的没有问题。
奇怪的是,它在思考链中的分析其实是正确的,但是最终计算的offset值始终不对。
好在,这个错误很容易修改。
5. 总结
最终的代码我放在了vscode-markdown-hexo仓库。虽然还有一些bug,但是基本上个人使用够了。
回过头来看这次vibe coding的经历,整体的评价还是正面的,因为利用它我完成了一个之前我个人不可能完成的任务。
但是问题还是比较多的,主要是涉及到一些不是很常见的功能的时候,AI无法找到对应的代码,于是就开始瞎编了,编完了还像模像样地告诉你没有问题。
回想一下,当时应该直接把官方文档对应的页面直接扔给AI,让它根据具体的文档来写代码,应该会好一些。
另外一个藏在VSCode源代码里面的功能,这个AI不知道情有可原,因为我没有在任何公开的地方找到这个用法的说明。
下次可以尝试让AI分析VSCode的源代码,看看它能否找到这个功能的实现方法。
总体来说,和我这几年使用AI的感觉是一致的:就是AI强于逻辑,但是弱在事实核查。
说到事实核查,我不得不祭出当年GPT-3.5刚出来的时候的几张截图:




呃。。。
需要在
_config.yml中启用post_asset_folder: true。 ↩︎利用插件Shift IM for Math ↩︎
参考之前的文章:使用VSCode编辑Markdown的几个常用设置 ↩︎