LSP
Emacs,因其丰富的插件生态和高度一致的协同环境,不论敲代码还是写文章都有行云流水的感觉。 一直以来Emacs的短板都在智能语法补全上,不能像VSCode那样非常智能的补全代码。
随着VSCode的流行和微软在开源社区的发力,LSP(编程语言服务器协议)逐渐发展成为代码智能补全领域的佼佼者。 通过标准的LSP协议,只用为编辑器或IDE开发一款LSP客户端,即可对所有的编 程语言提供智能补全支持,以解决原来众多编辑器(N)和补全后端(M)相互组 合产生的 M x N 问题,避免了大家反复造轮子,可以集中社区更多的资源在语 言服务器后端的开发和优化上。
协议研究
Emacs目前也有两个LSP客户端: lsp-mode 和 eglot, 但是这两个客户端的性能却不是很好,特别是lsp-mode, 写一会代码就会卡一下,非常影响编程思路。
周末完整的研读了LSP的协议规范细节, 并调研了Rust, Golang和Python的JSONRPC库用法,最后决定用Python来实现一个新的LSP代理客户端,因为Python有完整的多线程支持,所以不会出现预想的LSP数据流堵塞Emacs输入的问题。
经过昨天一天的研究和调试,发现其实LSP Server在代码补全时返回的数据并不 大,为什么lsp-mode和eglot还会卡住Emacs呢?难道不是之前猜想的Elisp解析JSON慢的问题?
为了弄明白性能瓶颈,随即裁剪了Eglot进行对比测试,主要针对代码补全以外的功能进行裁剪
- 用posframe替代eldoc来显示文档,避免每次输入一个单词就从服务器请求一次文档
- 去掉了所有LSP Server返回的代码诊断消息和处理函数,并从Eglot中移除 flymake相关的代码
- 默认只补全符号,并禁止补全代码模板,因为yasnippet的参数选中状态很容易消 失,一旦模板代码写错了,要修改调整反而效率更低
- 去掉 documentHighlight 协议,没啥用,反而经常通过overlay污染代码空间
通过上面的裁剪过后,Eglot居然异常流畅,真是喜出望外啊。
Nox
在Eglot的代码基础之上,今天发布了新的Emacs LSP客户端 – Nox
目前Nox已经支持以下编程语言:
- Javascript: javascript-typescript-stdio
- Rust: rls
- Python: pyls
- Ruby: solargraph
- Java: Eclipse JDT Language Server
- Bash: bash-language-server
- PHP: php-language-server
- C/C++: ccls
- Haskell: IDE engine
- Elm: elm-language-server
- Kotlin: kotlin-language-server
- Go: gopls
- Ocaml: ocaml-language-server
- R: languageserver
- Dart: dart_language_server
- Elixir: elixir-ls
- Ada: ada_language_server
- Scala: metals
- TeX/LaTeX: Digestif
- Dockerfile: dockerfile_language_server
- HTML html_language_server
- CSS: css_language_server
- JSON: json_language_server
Nox的项目目标主要有三个:
- 功能上:只提供代码补全、代码定义跳转、代码引用和重命名功能这四个最核心的功能
- 设计上:保持界面交互简洁无打扰, 不会像 lsp-ui 提供花里胡哨的功能,减少对用户专注力的干扰
- 性能上:裁剪无用功能, 优化代码效率,保证代码补全时的流畅手感
在我看来,像语法检测和代码模板,flycheck以及yasnippet这些插件的资源占 用率更低,也更为专业。
如果你追求LSP所有功能,lsp-mode和Eglot是更好的选择,如果你追求极致的编 码流畅度,Nox肯定是目前用户体验和性能最好的LSP客户端。
安装
- 先安装依赖组件 company-mode和posframe
- 拷贝Nox代码到Emacs的 load-path 路径
- 把下面的配置加到 ~/.emacs 中
(require 'nox)
(dolist (hook (list
'js-mode-hook
'rust-mode-hook
'python-mode-hook
'ruby-mode-hook
'java-mode-hook
'sh-mode-hook
'php-mode-hook
'c-mode-common-hook
'c-mode-hook
'c++-mode-hook
'haskell-mode-hook
))
(add-hook hook '(lambda () (nox-ensure))))
安装配置好以后,打开源码文件,即可享受流畅的智能补全体验。
常用命令
命令 | 解释 |
---|---|
nox | 启动Nox客户端 |
nox-reconnect | 重新链接LSP服务器 |
nox-shutdown | 终止LSP服务器 |
nox-show-doc | 显示光标处符号的文档 |
nox-rename | 项目范围内批量重命名 |
nox-format | 格式化当前文件或选中区域 |
xref-find-definitions | 查找光标处符号定义 |
xref-find-definitions-other-window | 在其他窗口中查找光标处符号定义 |
xref-pop-marker-stack | 返回定义跳转前的位置 |
xref-find-references | 查找光标处符号的所有引用 |
nox-event-buffer | 切换到LSP消息文件,查看LSP协议消息 |
nox-stderr-buffer | 切换到子进程管道文件,查看通讯细节和排错信息 |
更多命令和设置选项可以查看Nox。
Enjoy! ;)