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

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