lsp-mode 快速参考卡全解:核心命令速查与 PDF 再生成指南
lsp-mode 快速参考卡全解:核心命令速查与 PDF 再生成指南
lsp-mode 是 Emacs 下的 Language Server Protocol 客户端/库,其功能命令数量庞大且分散在多个前缀组合中。为了帮助用户快速上手,仓库提供了一个单页 PDF 形式的“快速参考卡”(Quick Reference Card),浓缩了使用 lsp-mode 最需要记住的核心命令。本文以 refcard/README.md 为骨架,完整讲解参考卡的内容、从 TeX 源文件重新生成 PDF 的方法,并结合 lsp-mode.el 的源码揭示这些按键绑定背后的实现原理。读完本文,你将能看懂参考卡上的每一个组合键,能自行修改并重新生成属于你自己的速查卡,也能理解哪些命令依赖额外的 lsp-ui / lsp-treemacs 扩展包。
什么是 lsp-mode Quick Reference Card
lsp-mode 的快速参考卡是一份单页 PDF,位于 refcard/lsp-refcard.pdf,它只收录“有效使用 lsp-mode 所必需的关键命令”(the essential commands one needs to know to use lsp-mode effectively)。项目文档 refcard/README.md 中给出了相当直白的建议:
You're encouraged to print it, laminate it and keep it on your desk.
即:把它打印出来、塑封好、放在桌面上随时查阅。这份参考卡的设计目标就是在不翻文档的前提下,快速找到“跳转到定义”“重启语言服务器”“触发代码操作”等高频操作的按键。它不追求穷尽 lsp-mode 的全部 100 余条命令,而是精选出日常开发中最常用的部分,按功能域分组排版成双栏。
参考卡的排版布局定义在 refcard/lsp-refcard.tex 中。这是一个 LaTeX 源文件,内容分为以下功能分组:
- Programming > Change Server State:服务器生命周期管理
- Toggle Actions:各类显示特性的开关
- GoTo:符号跳转导航
- Workspace:工作区文件夹管理
- Peek:内联预览(依赖 lsp-ui)
- Find Actions:悬停描述、签名帮助等查询
- Refactor:重命名、整理导入
- Code Actions:代码操作与符号高亮
修改与再生成:从 .tex 到 .pdf
参考卡是文本可维护的:PDF 并非手工绘制,而是由 LaTeX 源文件 refcard/lsp-refcard.tex 编译生成。若想增删按键、调整分组或修改标题,应先编辑 .tex 源文件,再重新编译出 PDF,而不是直接修改 PDF 文件本身。
重新生成 PDF 的命令极其简单(在 refcard/ 目录下执行):
$ pdflatex lsp-refcard.tex
运行后会在同一目录下生成(或覆盖)refcard/lsp-refcard.pdf。
需要注意以下几点前提:
- 安装
pdflatex:README 明确指出“you might have to installpdflatexfirst”。pdflatex是 TeX 发行版提供的编译命令,常见发行版包括 TeX Live(Linux/macOS/Windows)、MacTeX(macOS)与 MiKTeX(Windows)。例如在 Debian/Ubuntu 系系统上安装texlive相关软件包、在 macOS 上安装 MacTeX、在 Windows 上安装 MiKTeX,即可获得pdflatex可执行文件。安装完成后可用pdflatex --version验证。 - 宏包依赖:
lsp-refcard.tex头部加载了geometry、multicol、menukeys、enumitem、xcolor、xparse、calc、tcolorbox等宏包(见 refcard/lsp-refcard.tex)。其中menukeys用于渲染键盘按键外观(如s-l w s的键帽样式),tcolorbox用于绘制顶部“Getting Help for lsp-mode”提示框,multicol实现双栏排版。建议安装完整的 TeX 发行版,以免因缺少宏包导致编译报错。 - 排版细节:文档类为
a4paper,10pt的article,页边距1cm,无页码(\pagestyle{empty}),双栏间距1cm,并在中栏位置使用\columnbreak强制分栏(见 refcard/lsp-refcard.tex),保证双栏内容均衡。
参考卡命令全览:前缀约定
参考卡上所有命令都遵循同一个前缀约定:s-l(super 键 + l 键),随后再按功能分组字母与操作键。例如 s-l w s 表示“按 super-l 后,再按 w 再按 s”,启动语言服务器。
这一约定在源码中由自定义变量 lsp-keymap-prefix 定义,默认值为字符串 "s-l"(见 lsp-mode.el):
(defcustom lsp-keymap-prefix "s-l"
"LSP-mode keymap prefix."
:group 'lsp-mode
:type 'string
:package-version '(lsp-mode . "6.3"))
也就是说,参考卡中的 s-l 前缀并非写死的常量,而是可以整体替换的:若你的 super 键不顺手,可通过 setq lsp-keymap-prefix "C-l" 之类的配置改为 C-l 前缀,参考卡上的所有组合键随之整体平移。绑定本身在 lsp-mode.el 中完成:
(when lsp-keymap-prefix
(define-key map (kbd lsp-keymap-prefix) lsp-command-map))
即当 lsp-keymap-prefix 非 nil 时,把前缀键映射到 lsp-command-map(一个稀疏键表)。注意区分大小写:参考卡上 w d(Describe session)与 w D(Disconnect buffer)是不同命令,G g 的大写 G 是 Peek 分组的专属前缀。
参考卡左上角还有一个提示框 “Getting Help for lsp-mode”,强调:所有 lsp 命令都以该前缀命令开始——记住了 s-l,就等于掌握了进入整个命令体系的入口。
服务状态管理(Change Server State)
这一组命令管理语言服务器的生命周期,对应源码中 lsp-command-map 的 w* 绑定(见 lsp-mode.el):
| 按键 | 功能 | 源码绑定 | 可用条件 |
|---|---|---|---|
s-l w s |
启动语言服务器(Start server) | lsp |
始终可用 |
s-l w r |
重启语言服务器(Restart server) | lsp-workspace-restart |
已有活动 workspace |
s-l w q |
关闭语言服务器(Shutdown server) | lsp-workspace-shutdown |
已有活动 workspace |
s-l w d |
描述当前会话(Describe session) | lsp-describe-session |
始终可用 |
s-l w D |
将当前 buffer 与语言服务器断开(Disconnect buffer from LS) | lsp-disconnect |
已有活动 workspace |
其中 lsp-describe-session(见 lsp-mode.el)会打开一个会话描述 buffer,展示各 workspace 的状态、已连接客户端与服务器信息,是排查“服务器到底起没起、连没连上”的首选诊断命令。
开关类操作(Toggle Actions)
T 分组集中了 lsp-mode 的显示特性开关,对应源码 T* 绑定(见 lsp-mode.el):
| 按键 | 功能 | 源码绑定 | 可用条件 |
|---|---|---|---|
s-l T l |
切换 Code Lens(Toggle lenses) | lsp-lens-mode |
服务器支持 textDocument/codeLens |
s-l T L |
切换 I/O 日志(Toggle log I/O) | lsp-toggle-trace-io |
始终可用 |
s-l T h |
切换符号高亮(Toggle symbol highlighting) | lsp-toggle-symbol-highlight |
服务器支持 textDocument/documentHighlight |
s-l T S |
切换 Sideline(需 lsp-ui,红色标记) | lsp-ui-sideline-mode |
已加载 lsp-ui-sideline |
s-l T d |
切换文档弹窗(需 lsp-ui,红色标记) | lsp-ui-doc-mode |
已加载 lsp-ui-doc |
s-l T s |
切换签名自动激活(Toggle signature) | lsp-toggle-signature-auto-activate |
服务器支持 textDocument/signatureHelp |
s-l T f |
切换输入时格式化(Toggle on Type Formatting) | lsp-toggle-on-type-formatting |
服务器支持 textDocument/onTypeFormatting |
参考卡源文件中,T S 与 T d 两项以红色印刷(refcard/lsp-refcard.tex),提示用户这两项依赖独立的 lsp-ui 扩展包。源码中的可用条件也印证了这一点:(featurep 'lsp-ui-sideline) 与 (featurep 'lsp-ui-doc)。
lsp-toggle-on-type-formatting 的实现(见 lsp-mode.el)会在 after-change-functions 中挂钩,在每次输入后请求服务器执行按需格式化,属于“边打字边自动排版”的能力开关。
跳转导航(GoTo)
g 分组是日常使用频率最高的一组导航命令,对应源码 g* 绑定(见 lsp-mode.el):
| 按键 | 功能 | 源码绑定 | 可用条件 |
|---|---|---|---|
s-l g g |
查找定义(Find Definitions) | lsp-find-definition |
textDocument/definition |
s-l g r |
查找引用(Find References) | lsp-find-references |
textDocument/references |
s-l g i |
查找实现(Find Implementations) | lsp-find-implementation |
textDocument/implementation |
s-l g t |
查找类型定义(Find Type Definition) | lsp-find-type-definition |
textDocument/typeDefinition |
s-l g d |
查找声明(Find Declarations) | lsp-find-declaration |
textDocument/declaration |
s-l g h |
显示调用层次(需 lsp-treemacs,蓝色标记) | lsp-treemacs-call-hierarchy |
服务器支持 callHierarchy/incomingCalls 且已加载 lsp-treemacs |
s-l g e |
Treemacs 错误列表(需 lsp-treemacs,蓝色标记) | lsp-treemacs-errors-list |
已加载 lsp-treemacs |
s-l g a |
在工作区查找符号(Find Symbol in Workspace) | xref-find-apropos |
workspace/symbol |
这组命令在源码中均为 cl-defun 定义的异步跳转函数,例如 lsp-find-definition(见 lsp-mode.el)、lsp-find-references(见 lsp-mode.el)。参考卡中以蓝色标记的 g h 与 g e 两项,从源码条件可以看出它们依赖 lsp-treemacs 包(fboundp 'lsp-treemacs-call-hierarchy、fboundp 'lsp-treemacs-errors-list)。
工作区管理(Workspace)
F 分组管理 workspace 文件夹,对应源码 F* 绑定(见 lsp-mode.el):
| 按键 | 功能 | 源码绑定 | 可用条件 |
|---|---|---|---|
s-l F a |
向 workspace 添加文件夹 | lsp-workspace-folders-add |
始终可用 |
s-l F r |
从 workspace 移除文件夹 | lsp-workspace-folders-remove |
始终可用 |
s-l F b |
将文件夹移出 workspace 黑名单 | lsp-workspace-blocklist-remove |
始终可用 |
这三项与源码条件均为 t(无条件可用),它们操作的是 lsp-mode 的 workspace 会话模型:语言服务器通常以整个 workspace(根目录树)为单位提供服务,而黑名单机制用于排除不需要纳入管理的目录。
Peek 内联预览
G(大写)分组提供 lsp-ui 的 peek 内联预览功能,全部以红色标记(依赖 lsp-ui),对应源码 G* 绑定(见 lsp-mode.el):
| 按键 | 功能 | 源码绑定 | 可用条件 |
|---|---|---|---|
s-l G g |
Peek 定义(内联预览) | lsp-ui-peek-find-definitions |
支持 textDocument/definition 且已加载 lsp-ui-peek |
s-l G r |
Peek 引用 | lsp-ui-peek-find-references |
支持 textDocument/references 且已加载 lsp-ui-peek |
s-l G i |
Peek 实现 | lsp-ui-peek-find-implementation |
支持 textDocument/implementation 且已加载 lsp-ui-peek |
s-l G s |
Peek 工作区符号 | lsp-ui-peek-find-workspace-symbol |
支持 workspace/symbol 且已加载 lsp-ui-peek |
与 g 组的“跳转到目标位置”不同,peek 是在当前窗口内弹出内联预览列表,选中后才会真正跳转,适合快速浏览而不丢失当前编辑上下文。
查询与帮助(Find Actions)
h 分组提供符号查询与帮助,对应源码 h* 绑定(见 lsp-mode.el):
| 按键 | 功能 | 源码绑定 | 可用条件 |
|---|---|---|---|
s-l h h |
描述光标处符号(Describe Symbol at Point) | lsp-describe-thing-at-point |
服务器支持 textDocument/hover |
s-l h s |
签名帮助(Signature Help) | lsp-signature-activate |
服务器支持 textDocument/signatureHelp |
s-l h g |
lsp-ui 文档速览(Glance,红色标记) | lsp-ui-doc-glance |
已加载 lsp-ui-doc 且支持 textDocument/hover |
其中 lsp-describe-thing-at-point(见 lsp-mode.el)把 LSP 的 hover 信息以富文本形式展示出来;lsp-signature-activate(见 lsp-mode.el)激活当前函数调用的参数签名提示,并可用 M-n / M-p 在多个重载签名间切换(见 lsp-mode.el)。
重构(Refactor)
r 分组是重构操作,对应源码 r* 绑定(见 lsp-mode.el):
| 按键 | 功能 | 源码绑定 | 可用条件 |
|---|---|---|---|
s-l r r |
重命名符号(Rename) | lsp-rename |
服务器支持 textDocument/rename |
s-l r o |
整理导入(Organize Imports) | lsp-organize-imports |
服务器支持 textDocument/codeAction |
lsp-rename(见 lsp-mode.el)会要求输入新名称并调用 textDocument/rename,由服务器计算整个项目范围内的重命名编辑;lsp-organize-imports 则通过 codeAction 请求服务器清理未使用的导入语句。
代码操作(Code Actions)
a 分组提供代码操作入口,对应源码 a* 绑定(见 lsp-mode.el):
| 按键 | 功能 | 源码绑定 | 可用条件 |
|---|---|---|---|
s-l a a |
执行代码操作(Code actions) | lsp-execute-code-action |
服务器支持 textDocument/codeAction |
s-l a h |
高亮符号(Highlight Symbol) | lsp-document-highlight |
服务器支持 textDocument/documentHighlight |
lsp-execute-code-action(见 lsp-mode.el)会请求服务器返回当前光标位置可用的 code actions(如快速修复、生成实现等)并以交互方式让用户选择执行;lsp-document-highlight(见 lsp-mode.el)则高亮当前符号在文档中的所有出现位置,便于目视追踪。
源码视角:条件按键绑定的实现原理
参考卡上的命令之所以“该出现时出现、不该出现时消失”,源于 lsp-command-map 采用了一种条件按键绑定机制。其核心定义位于 lsp-mode.el,而机制本身由宏 lsp-define-conditional-key 实现(见 lsp-mode.el)。
该宏与 define-key 类似,区别在于多了一个 COND 条件参数:
(defmacro lsp-define-conditional-key (keymap key def desc cond &rest bindings)
"In KEYMAP, define key sequence KEY as DEF conditionally.
This is like `define-key', except the definition disappears
whenever COND evaluates to nil."
...)
实现上,它把每个绑定展开为带 :filter 的 menu-item:
`((define-key ,keymap ,key
'(menu-item
,(format "maybe-%s" def)
,def
:filter
(lambda (item)
(when (with-current-buffer (or (when (buffer-live-p lsp--describe-buffer)
lsp--describe-buffer)
(current-buffer))
,cond)
item))))
menu-item 的 :filter 会在按键被查询时求值 COND:条件成立则返回该菜单项(按键可用),条件不成立则返回 nil(按键从键表中“消失”)。这样,s-l g g(Find Definitions)只有在当前语言服务器声明支持 textDocument/definition 时才有效;若当前 buffer 未启用任何语言服务器,整组 g* 命令都会自动失效,从而避免误触。这也解释了参考卡上每个命令旁“可用条件”一栏的来源——它们直接对应源码中 lsp-command-map 里各绑定的条件表达式。
此外,lsp-define-conditional-key 在定义绑定时会同时把 (key desc) 对追加到 lsp--binding-descriptions 列表(见 lsp-mode.el),为 which-key 集成提供描述数据。参考卡上每个命令旁边的英文说明(如 “start server”“toggle lenses”)正是这些描述,它们与 which-key 弹层中显示的提示文本同源。
参考卡之外的扩展:完整命令表与 which-key
参考卡是精选子集,并非完整清单。lsp-command-map(lsp-mode.el)中还包含若干未印上参考卡的命令,例如:
- 格式化:
s-l = =(lsp-format-buffer格式化整个 buffer)、s-l = r(lsp-format-region格式化选中区域),对应源码=*绑定(见 lsp-mode.el)。 - 更多开关:
s-l T D(modeline 诊断显示)、s-l T T(lsp-treemacs 同步)、s-l T a(modeline 代码操作计数)、s-l T b(headerline 面包屑),以及s-l a i(接受 inlay hint)、s-l a l(avy 跳转 lens)等(见 lsp-mode.el)。
如果你使用的是 which-key 插件,可以调用 lsp-enable-which-key-integration(见 lsp-mode.el)为当前 major-mode(或传 t 时为所有模式)注册按键描述:
(lsp-enable-which-key-integration) ; 当前 major-mode
(lsp-enable-which-key-integration t) ; 所有模式
该函数把 lsp--binding-descriptions 中的描述信息配合分组说明(w → workspaces、F → folders、T → toggle、g → goto、h → help、r → refactor、a → code actions、G → peek,见 lsp-mode.el)注入 which-key,按下 s-l 后即可看到分组提示——相当于把参考卡“搬进了” Emacs 交互界面,且能随服务器能力动态增减条目。参考卡与 which-key 描述同源,二者互为补充:纸质卡适合全局概览,which-key 弹层适合即时提示。
小结
快速参考卡是 lsp-mode 高频命令的“一页纸”浓缩:以 s-l 前缀为入口,w(服务器状态)、T(开关)、g(跳转)、F(工作区)、G(peek)、h(帮助)、r(重构)、a(代码操作)八大分组覆盖了日常开发的核心操作。参考卡本身是可持续维护的 LaTeX 产物,修改 refcard/lsp-refcard.tex 后执行 pdflatex lsp-refcard.tex 即可重新生成 refcard/lsp-refcard.pdf。而所有按键背后的条件绑定机制、可用能力判断与 which-key 描述,都可以在 lsp-mode.el 的 lsp-command-map 定义中逐一验证——这正是从“背按键”走向“理解 lsp-mode 命令体系”的进阶路径。