上次让AI基于DriectX11开发了一个3D渲染引擎,过程中自己敲代码发现手感总是少点东西,说直白点,就是代码敲起来不爽。早期在写VS Code插件的时候,因为LSP这块文档比较少,基本要靠去VS Code官网啃英文文档,对其中的协议理解也不是特别透彻,故感觉工作量相当庞大。于是先把精力集中在了脚本解释器的开发上。
但最近我发现一个事:让 AI 来做 LSP 开发,简直太对路了。
为什么 AI 干这个特别合适
首先,LSP协议是标准协议,里面的补全提示协议,hover提示协议每个字段如果自己去看,理解不一定准确,因为老外和中国人的思维习惯还是有一些差异的。这类型工作在现在我根本不需要自己查文档,我直接把vscode工程源码让它读一遍后,告诉它“我要增强代码补全能力,我要新增hover提示能力,应该怎么做”,它直接告诉我在我原有框架的基础上扩展哪几个协议,哪几个字段如何填写,甚至照葫芦画瓢直接帮我把协议扩展好了,我直接在里面填空即可。
还有一部分工作,就是文档的搬运,官网文档上百个内置类型,上千个接口,每个接口的参数、返回值、文档描述、用例如果我自己手动去搬,没一个月体力劳动我都干不完。现在好了,我就打样一个类型和一个接口,把补全提示规则定好,把hover提示的显示样式和规则定好,告诉它:“按照XX类与XX方法的方式,从文档中提取所有类型与方法,补齐hover需要的数据。注:准确率比速度重要”,它哼哧哼哧半个小时就帮我全部搬进来了。我就简单运行代码后鼠标放到一些代码上直接看提示信息验收就可以了。这活以前我根本不想碰,现在应该叫什么?叫鸟枪换炮。
这次最重要的东西:类型传递推导

以前只有 X = new Y这种写法,插件才能记住 X 是 Y 类型。你敲 X.能弹出 Y 的成员。但如果是这样:
var returnA = funcA(proA);funcA返回个值赋给 returnA,以前完全不知道 returnA 是什么类型。
但这种写法太常见了。我看了其他无类型脚本语言的做法,很多是靠 JSDoc 注解,让用户在函数上标返回值类型。我本来也想这么搞,但心里那个"能自动就别手动"的念头过不去。最后我在推导引擎里加了静态模拟执行——把变量在代码里的传递路径全算出来,宁可多给提示,也别漏。具体能追到什么程度:
var proA = proB; // 赋值,proA 继承 proB 的类型funcA(proA); // 入参 parmA 拿到 proA 的类型function funcA(parmA) //这里传导了入参类型{var localA = parmA;// localA 继承 parmAreturn localA; //return 的类型被记下来}var returnA = funcA(proA); // 返回值 returnA 拿到 localA 的类型
只要工程里某个地方这个变量名曾经被赋过值,就能被追到并提示出来。我专门写了个跨文件、层层嵌套几十层的复杂测试用例,也推导对了。正常写代码哪有那么深,够用了。

hover 提示终于补上了


接下来想解决一个问题,想听听大家意见
之前的代码提示功能不是太强,所以也没发现。我一直不想在脚本里加 public/ private关键字——脚本嘛,灵活点,运行时都能访问,这才是脚本该有的样子。但补全变强以后发现了问题:比如 Scene3D这个类,我敲 s3d.

所有东西全弹出来了——一大堆内部实现细节,用户根本不需要看这些。所以得有个机制控制"哪些该提示、哪些不该提示"。但我的想法是:这个机制只影响编辑器,不影响运行时。 脚本该灵活还是灵活。目前两个想法:
//方式一,直接增加关键字classA{public:var m_A = 1;private:var m_B = 2;}//方式二,注解方式classB{//@publicvar m_A = 1;//@privatevar m_B = 2;}
夜雨聆风