Nox - 轻量级 LSP 客户端
Emacs
LSP
2020-03-29 2349字

LSP

Emacs,因其丰富的插件生态和高度一致的协同环境,不论敲代码还是写文章都有行云流水的感觉。 一直以来 Emacs 的短板都在智能语法补全上,不能像 VSCode 那样非常智能的补全代码。

随着 VSCode 的流行和微软在开源社区的发力,LSP(编程语言服务器协议)逐渐发展成为代码智能补全领域的佼佼者。 通过标准的 LSP 协议,只用为编辑器或 IDE 开发一款 LSP 客户端,即可对所有的编 程语言提供智能补全支持,以解决原来众多编辑器(N)和补全后端(M)相互组 合产生的 M x N 问题,避免了大家反复造轮子,可以集中社区更多的资源在语 言服务器后端的开发和优化上。

协议研究

Emacs 目前也有两个 LSP 客户端: lsp-modeeglot, 但是这两个客户端的性能却不是很好,特别是 lsp-mode, 写一会代码就会卡一下,非常影响编程思路。

周末完整的研读了 LSP 的协议规范细节, 并调研了 Rust, Golang 和 Python 的 JSONRPC 库用法,最后决定用 Python 来实现一个新的 LSP 代理客户端,因为 Python 有完整的多线程支持,所以不会出现预想的 LSP 数据流堵塞 Emacs 输入的问题。

经过昨天一天的研究和调试,发现其实 LSP Server 在代码补全时返回的数据并不 大,为什么 lsp-mode 和 eglot 还会卡住 Emacs 呢?难道不是之前猜想的 Elisp 解析 JSON 慢的问题?

为了弄明白性能瓶颈,随即裁剪了 Eglot 进行对比测试,主要针对代码补全以外的功能进行裁剪

  1. 用 posframe 替代 eldoc 来显示文档,避免每次输入一个单词就从服务器请求一次文档
  2. 去掉了所有 LSP Server 返回的代码诊断消息和处理函数,并从 Eglot 中移除 flymake 相关的代码
  3. 默认只补全符号,并禁止补全代码模板,因为 yasnippet 的参数选中状态很容易消 失,一旦模板代码写错了,要修改调整反而效率更低
  4. 去掉 documentHighlight 协议,没啥用,反而经常通过 overlay 污染代码空间

通过上面的裁剪过后,Eglot 居然异常流畅,真是喜出望外啊。

Nox

在 Eglot 的代码基础之上,今天发布了新的 Emacs LSP 客户端 – Nox

目前 Nox 已经支持以下编程语言:

Nox

Nox 的项目目标主要有三个:

  1. 功能上:只提供代码补全、代码定义跳转、代码引用和重命名功能这四个最核心的功能
  2. 设计上:保持界面交互简洁无打扰, 不会像 lsp-ui 提供花里胡哨的功能,减少对用户专注力的干扰
  3. 性能上:裁剪无用功能, 优化代码效率,保证代码补全时的流畅手感

在我看来,像语法检测和代码模板,flycheck 以及 yasnippet 这些插件的资源占 用率更低,也更为专业。

如果你追求 LSP 所有功能,lsp-mode 和 Eglot 是更好的选择,如果你追求极致的编 码流畅度,Nox 肯定是目前用户体验和性能最好的 LSP 客户端。

安装

  1. 先安装依赖组件 company-modeposframe
  2. 拷贝Nox代码到 Emacs 的 load-path 路径
  3. 把下面的配置加到 ~/.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! ;)