lspce - rust实现的LSP客户端

一个比较简陋的lsp客户端。之所以做这个东西,一是lsp mode在我电脑上用着卡,eglot代码看不懂,也没感觉比lsp mode明显快;更重要的是想学习下rust,至少写个真实可用的东西出来。

设计目标:

  1. 只计划实现我自己必需的一些功能(跳转、补全、诊断、code action等)
  2. 尽量利用Emacs本身的功能(capf, flymake)
  3. 尽量把数据处理放在rust代码中,只有那些必要的数据才放在elisp代码里处理(过期的响应,不关心的通知都在rust里干掉了)
  4. 代码写得容易看懂,不要到处都是宏啊啥的(没学习过elisp的宏,eglot里那些宏看得够够的)

已经实现的功能:

  1. 跳转(作为xref的后端)
  2. 补全(capf,使用company测试) 不过目前实现的不完整,只会看label/insertText,而且不支持snippet。下面有个图展示存在的问题。
  3. 诊断(作为flymake的后端)
  4. hover

就这些。我目前已经在用lspce写lspce了,基本还是可用的。另外还测试过pyright。

rs代码里应该还有些错误没有处理,所以可能会出现panic。代码写得也比较丑(尤其是rs),还需要整理。

计划还要做的:

  1. 完善补全(包括snippet)
  2. 支持code action
  3. 支持signatureHelp
  4. java支持(我自己工作中主要用的语言)
  5. 其它待定

配置

(use-package lspce
  :load-path "/path/to/lspce/lisp"
  :init (progn
          (add-to-list 'load-path "/path/to/lspce/rs/target/debug")

          (require 'lspce-module)
          )
  :config (progn
           ;; (add-hook 'rust-mode-hook 'lspce-mode)
            )
  )

来几张图

补全:

上面这张图展示了目前的问题:rust-analyzer返回的补全项的label就是clone (as Clone),补全后还需要删除一部分。

诊断:

跳转定义/引用等

写在最后

  1. 欢迎大家试用,但谨!慎!试用
  2. 时间精力有限,进度/改bug都比较慢
  3. 感谢前辈eglot/lsp mode,“借鉴”了eglot不少代码,靠lsp mode的日志解决了一些协议理解上的问题
  4. 代码在 GitHub - zbelial/lspce: LSP Client for Emacs implemented as a module using rust. (因为众所周知的原因,我这儿经常连不上github,代码经常不能及时push)
  5. 我在linux开发,日志文件写死了/tmp/lspce.log,windows上测试的话需要改改。
  6. 协议处理不是完全异步的,所以还是可能会出现卡手的情况
34 个赞

沙发沙发,大佬厉害呀。

2 个赞

哈哈哈,竞品来了呀

没有啊, 大佬也是 lsp-bridge 的开发者呀,哪有啥竞争呀,都是自己写代码让自己舒服, 我们不是太在乎别人的需求。 :wink:

2 个赞

也在断断续续学 rust,但因为工作中用不到,就只是写点玩具玩玩感受下,佩服大佬的行动力,加油

努力向大佬学习

哈哈,不是竞品,我自己也用lsp-bridge。我确实也算是lsp-bridge的开发者,虽然贡献很小。

热烈欢迎神仙们「打架」,哈哈。 多种选择总是好的。

我和楼主原来都是 EAF 的开发者,五一节的时候和楼主一起大量交流 LSP 协议,我们自己有个群,天天交流LSP实现细节。

不存在竞争的,都是为了实现自己爽的小愿望。

2 个赞

我知道,我就是指你们的技术和观点交流很有益,比如一定程度上促进了这个 rust 项目的诞生,给社区提供了更多选择。感谢你们。 :grinning:

和lsp-bridge有什么区别呢?我又如何选择 lspce 和lsp-bridge呢

如果不是很看重跟Emacs内置设施(xref,flymake,capf这些)的集成,那就选lsp-bridge。

lspce目前特意做成了同步模式,好处是容易支持我上面说的xref之类的,缺点是如果server处理请求慢(例如补全的时候),会出现卡手。

没有像lsp-bridge那样 使用多线程?

lspce是使用了多线程的,其实在rs那部分代码里,消息处理是异步的,有线程加队列。只不过是以同步的方式提供了给elisp的接口。代价就是补全的时候会卡。

这么做是为了支持xref/capf这些,因为觉得既然Emacs已经有这些东西了,没必要另做一套,另外也怕自己时间不够。我也在考虑怎么同时提供同步和异步的接口(异步接口对补全来说还是很必要的,对其他功能来说倒无所谓),不过暂时还没有完整的设计,实现出来更不知道什么时候了。

1 个赞

功能更新:补全初步支持snippet了,需要yasnippet。

1 个赞

这个做好了应该能完全解决lsp卡顿问题啊,赞!期待能上melpa/elpa :grin:

这个很期待,rust的性能还是值得期待的

lspce目前的实现还是做不到不卡顿的,补全还是会卡。lsp-bridge倒是可以尝试下。

感谢支持。水平有限,还是不要期待太高哈。

lsp并不是计算密集的,就性能来说,用rust还是python区别应该不明显。