lsp-bridge -- 速度最快的语法补全插件

可以试试这个https://github.com/theFool32/tabnine-capf看看卡不卡。仿 lsp-bridge 的实现方式,需要依赖 corfu。

你用的是什么系统,另外工程大概有多大。我用的是mac mini M1芯片,在大型工程中基本上没啥问题。

我这边即使一 lsp-bridge 自己的 *.el 文件都会导致卡, 我最后把 TabNine 关了。

这就奇怪了,我看了下本地tabnine占用内存大概1个g,可能是内存满了。另外你们本地tabnine的设置是啥样的啊,打开后在补全的地方输入Tabnine::config就可以打开网页进行设置,我使用的是

还有个可能是你们用了cloud,所以需要请求接口就比较慢。

我原来是 Hybird , 我改成 local 还是很慢, 我的笔记本是 Dell XPS 13 顶配, 8核32G内存。

TabNine内存占用就1GB, 但是卡那一瞬间, 我8个核的CPU都满了, 那一瞬间主要是电脑卡, 都不是Emacs卡。

我找到了个之前的帖子,说的也是这个问题,应该是tabnine本身可能会造成cpu 100%,然后我写的插件是参考tabnine-capf的,这个应该是同步的,所以会卡顿。后续试试能不能改成异步的。

主要是还需要测试一下, 同步的问题都可以参考 lsp-bridge 的设计或者 idle 的时候再请求, TabNine 这种一运行就飙CPU的程序, 我估计要用 cgroups 限制一下CPU占用的方法比较好, 但是没有测试过限制CPU以后, 会不会学习速度更慢了。

嗯嗯,我刚试下了,看cpu占用也是会猛的升起来,然后又降下去,最高的时候90%,但是emacs上不会卡,可能还跟系统有关系,mac可能限制了cpu不会超100%。

我在window 11的wslg里试了下,打开tabnine确实卡的不行,mac上对比起来完全不卡。感觉应该是tabnine自身的问题,看issue上也有很多人反馈相同的问题。

13寸的电脑写代码不会难受吗,还是台式机比较效率吧

虽然外壳是13寸的,但是屏幕大小堪比15寸,最重要的是2k屏,其实比台式机显示更多。

我以为像你这种大佬,应该不会有太多的出差需求才对啊。搞个4k显示器,不香吗。

我天天出差呀。

那难怪了,紫薯布丁

@manateelazycat 发了一个 lsp-bridge 的 PR,应该能处理 lsp-bridge -- 速度最快的语法补全插件 - #1780,来自 EthanLin 里提到的问题,你看会不会有别的影响?

1 个赞

感觉没啥副作用, 这个补丁确实解决了问题, 感谢大佬帮助! :wink:

大佬不敢当😮,我有些问题想请教:

  • 如果 lsp server 返回的补全类型(trigger_kind)是 2 ,并且没有额外的additionalTextEdits 信息,那么就是把候选项 append 到单词末尾,如果返回是 1, 那么就是用候选词替换光标下的词吗?
  • 另外,如果我不开启 lsp server, 只用 lsp-bridge 提供的补全,当前默认基本就是 Search word 或者 file path, 但如果我想自己加一个补全后端到 lsp-bridge 里,比如说想添加一个从英文缩写到中文全称的后端,类似 abbrev (效果是,输入 DNA, 补全列表里能显示中文的 “脱氧核糖核酸”,然后按 tab 就自动把 DNA 替换成中文,如果输入 DNA:那么列表也显示中文的 “脱氧核糖核酸”,但此时我按 tab 它能把中文 append 到 DNA: 后面而不是替换),从哪段代码能够控制补全时是替换当前词还是在当前词后面 append 内容?

我先回答第一个问题, LSP协议规定 insertTextFormat 是1的时候代表候选词是纯文本,2代表是模板代码, 一般会调用 yasnippet 对LSP返回的模板代码进行展开, 具体可以看 Specification

至于你说的, 候选词是否是直接插入, 还是要替换, 其实要看LSP返回的 textEdit 参数, textEdit 参数会详细的告诉 LSP Client 删除文档的范围以及插入的内容, 比如写 vue 的时候, fun._ 的补全有可能会变成 fun?._ 的形式, 删除到 . 之前, 而什么时候直接插入, 还是删除到点之前再插入 ?._ 完全是 LSP Server返回的语义信息 textEdit 来决定的。

在开发 lsp-bridge 的实践中, 虽然每种语言都遵守了 JSON 的格式和大部分协议标准, 但是补全返回的这一块, 每个语言都有轻微的差别(或者说行为不完全一样), 比如 c、 golang、 vue、 clojure 等语言有各种小细节不一致, 最终导致 lsp-bridge 的实现要反过来照顾 LSP Server 的互不兼容的地方。

第一个问题的道理就是上面的道理, 但是纯文本、 模板、 删除再插入细节、 自动导入加上多个语言服务器的兼容, 最终的实现只能看函数 lsp-bridge/acm-backend-lsp.el at adec95fb4f84c4ed919a8d064da5a2ec5e91cd10 · manateelazycat/lsp-bridge · GitHub

第二个问题的解题思路:

  1. 首先模仿 english 后端写一下框架代码
  2. acm补全都在 acm-complete 函数中实现, acm-complete 会根据当前候选词对应的后端来调用对应的 acm-backend-*-expand 函数
  3. 在你自己后端的 expand 函数中, 我觉得你可以判断一下触发 acm-complete 的按键是 Tab 还是其他按键, 至于是插入候选词还是替换缩略词, 其实就是你后端 expand 函数自己控制的

不考虑性能之类的,单纯从补全内容的角度来说,citre的优点是可以跨语言补全,同时如果lsp不支持补全的东西,如果能够基于正则去获取关键词,用ctags写一个正则来获取关键词很容易。虽然现在lsp不能补全但是可以用正则进行补全的东西应该很少了吧。