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! ;)