资源说明:This repo is for my personal reading, translation's credit belongs to @unionx
# SLIME 使用手冊(帝归翻译) ## 目录 * [1. 简介](#-1) * [2. 开始](#-2) * [2.1 支持平台](#21-) * [2.2 下载 Slime](#22--slime) * [2.2.1 从 CVS 下载](#221--cvs-) * [2.2.2 使用 CVS](#222--cvs) * [2.3 安装](#23-) * [2.4 启动 Slime](#24--slime) * [2.5 调整设置](#25-) * [2.5.1 自动加载](#251-) * [2.5.2 多种 Lisp](#252--lisp) * [2.5.3 更快地加载 Swank](#253--swank) * [3. 使用 Slime 模式](#-slime-) * [3.1 用户介面须知](#31-) * [3.1.1 临时缓冲区](#311-) * [3.1.2 `inferior-lisp`缓冲区](#312-inferior-lisp) * [3.1.3 多线程](#313-) * [3.1.4 键绑定](#314-) * [3.2 求值命令](#32-) * [3.3 编译命令](#33-) * [3.4 补全命令](#34-) * [3.5 查找定义(“Meta-Point”命令)](#35-meta-point) * [3.6 文档命令](#36-) * [3.7 交叉引用命令](#37-) * [3.7.1 XREF 缓冲区命令](#371-xref) * [3.8 宏扩展命令](#38-) * [3.9 分解命令](#39-) * [3.10 中止 / 恢复命令](#310-) * [3.11 检查命令](#311-) * [3.12 分析命令](#312-) * [3.13 遮盖命令](#313--1) * [3.14 语义缩进](#314--1) * [3.15 根据读取器的结果字符化](#315-) * [4. SLDB:Slime 调试器](#sldbslime) * [4.1 检查窗口](#41-) * [4.2 重启](#42-) * [4.3 在不同的窗口间操作](#43-) * [4.4 单步调试](#44-) * [4.5 其它命令](#45-) * [5. 杂项](#-3) * [5.1 slime-selector](#51-slime-selector) * [5.2 slime-macroexpansion-minor-mode](#52-slime-macroexpansion-minor-mode) * [5.3 多重连接](#53-) * [6. 定制](#-4) * [6.1 Emacs 端定制](#61-emacs) * [6.1.1 钩子](#611-) * [6.2 Lisp 端(Swank)](#62-lispswank) * [6.2.1 通信模式](#621-) * [6.2.2 其它配置](#622-) * [7. 小技巧](#-5) * [7.1 连接到远程 Lisp](#71-lisp) * [7.1.1 设置 Lisp 镜像](#711-lisp) * [7.1.2 设置 Emacs](#712-emacs) * [7.1.3 设置路径名翻译](#713-) * [7.2 重定向全局 IO 到 REPL](#72-iorepl) * [7.3 自动连接到 Slime](#73-slime) * [8. 扩展包](#-6) * [8.1 加载扩展包](#81) * [8.2 REPL:“顶层环境”](#82-repl) * [8.2.1 REPL 命令](#821-repl) * [8.2.2 输入引导](#822-) * [8.2.3 快捷命令](#823-) * [8.3 多 REPL](#83-repl) * [8.4 inferior-slime-mode](#84-inferior-slime-mode) * [8.5 混合补全](#85-) * [8.6 模糊补全](#86-) * [8.7 slime-autodoc-mode](#87-slime-autodoc-mode) * [8.8 ASDF](#88-asdf) * [8.9 导航条](#89-) * [8.10 编辑命令](#810-) * [8.11 更好的检查器](#811-) * [8.12 对象描述](#812-) * [8.13 打印窗口](#813-) * [8.14 TRAMP](#814-tramp) * [8.15 文档链接](#815-) * [8.16 交叉引用和类查看器](#816-) * [8.17 高亮编辑](#817-) * [8.18 空白缓冲区](#818-) * [8.19 slime-sprof](#819-slime-sprof) * [8.20 元包 slime-fancy](#820--slime-fancy) * [9. 致谢](#-8) * [黑客们](#-9) * [多谢!](#-10) ## 一、简介 Slime 的意思是“Emacs 下优秀的 Lisp 交互式开发模式”。 通过支持 Common Lisp 的交互式编程,Slime 扩展了 Emacs。所以的特性都基于 slime-mode,一个 Emacs 的 minor-mode,它为标准的 lisp-mode 提供补充。lisp-mode 为编辑 Lisp 源文件提供支持,而 slime-mode 则提供了与一个 Lisp 进程进行交互的功能,包括编译、调试、文档查找等等。 slime-mode 开发环境效仿 Emacs 原生的 Emacs Lisp 环境。我们也从某些类似的系统(例如 ILISP)那里借鉴了一些,当然也包括我们自己的想法。 Slime 由两部分组成:用 Emacs Lisp 写的用户界面,和用 Common Lisp 写的服务器端。这两部分通过套接字连接在一起,并且使用一个类似于 RPC 的协议通信。 服务器端的 Lisp 主要是可移植的 Commom Lisp。所需要的跟特定 Lisp 实现相关的特性都由一个接口定义好,然后由不同的 Lisp 实现提供。这使得 Slime 非常容易移植。 ## 二、开始 本章告诉你如何配置和启动 Slime。 ### 2.1 支持平台 Slime 广泛地支持多种操作系统和 Lisp 实现。Slime 可以在类 Unix 系统、Mac OSX 和 Microsoft Windows 上运行。GNU Emacs 21、22 和 23 以及 XEmacs 21 都可以运行 Slime。 粗略地根据支持的良好程度来排序的话,所有支持的 Lisp 实现为: - CMU Common Lisp(CMUCL),19d 版或更新 - Steel Bank Common Lisp(SBCL),1.0 版或更新 - Clozure Common Lisp(CCL),1.3 版或更新 - LipsWorks,4.3 版或更新 - Allegro Common Lisp(ACL),6 版或更新 - CLISP,2.35 版或更新 - Armed Bear Common Lisp(ABCL) - Corman Common Lisp,2.51 版或更新,需要 http://www.grumblesmurf.org/lisp/corman-patches 的补丁 - Scieneer Common Lisp(SCL),1.2.7 版或更新 - Embedded Common Lisp(ECL) 绝大部分特性在不同实现上的表现都是一致的,但是有些可能会有所不同。这些包括放置编译信息的注释的精度、XREF 支持以及调试器命令(例如“重启缓冲区”)。 ### 2.2 下载 Slime 你可以选择使用发行版本的 Slime 或者直接通过 CVS 仓库使用 Slime。你可以从我们的网站下载最新发布版本: http://www.common-lisp.net/project/slime/ 。 我们建议加入了 slime-dev 邮件列表的用户使用 CVS 版本的代码。 ### 2.2.1 从 CVS 下载 可以从 common-lisp.net 的 CVS 仓库取得 Slime。你可以选择使用最新版本的代码或者是带有 FAIRLY-STABLE 标签的快照版本。 跟 FAIRLY-STABLE 版本的代码相比,最新版本的代码可能有更多的特性和更少的 BUG,但也有可能因为较大的改动而不稳定。根据经验法则,我们建议如果你加入了 slime-dev 邮件列表,你最好使用最新版本(当进行主要的变动时,我们会发出通告)。如果你没有加入邮件列表,你就无法得知最新版本代码的情况,所以使用 FAIRLY-STABLE 或者发布版本是一个安全的选择。 如果你从 CVS 迁出代码,记得经常更新。经常会有小的改进提交上去,而 FAIRLY-STABLE 标签也会随时推进。 ### 2.2.2 使用 CVS 要下载 Slime 你要先配置你的 CVSROOT 并且登录到仓库。 ``` export CVSROOT=:pserver:anonymous@common-lisp.net:/project/slime/cvsroot cvs login ``` 最新版的代码可以通过以下方式迁出: ``` cvs checkout slime ``` 或者可以通过以下方式迁出 FAIRLY-STABLE 版本: ``` cvs checkout -rFAIRLY-STABLE slime ``` 如果你想知道最新版本的代码跟你运行的版本有什么新的东西,你可以将本地的 ChangeLog 和版本仓库的进行对比: ```sh cvs diff -rHEAD ChangeLog # or: -rFAIRLY-STABLE ``` ## 2.3 安装 如果你已经有了一个可以从命令行启动的 Lisp 实现,那么仅需在 .emacs 文件中添加几行即可安装成功: ```emacs-lisp (setq inferior-lisp-program "/opt/sbcl/bin/sbcl") ; your Lisp system (add-to-list 'load-path "~/hacking/lisp/slime/") ; your SLIME directory (require 'slime) (slime-setup) ``` 在 README 文件里也可以见到上面这些代码。你可以从那里复制粘贴,但要记得替换正确的路径。 这是没有其它杂项的最小化配置。如果基本配置可以工作,那么你可以试附加模块。(8.1 加载扩展包) 我们建议如果你要使用 Slime 就不要在 Emacs 里加载 ILISP 包。如果你这么做了,那么在编辑 Lisp 源文件时就会加入许多键绑定,而且这些键绑定可能会跟 Slime 启动的 Lisp 进程发生冲突而无法正常工作。 ## 2.4 启动 Slime Emacs 命令 M-x slime 可以启动 Slime。它使用 inferior-lisp 包来启动一个 Lisp 进程,加载并启动 Lisp 端服务器(叫做“Swank”),然后在 Emacs 和 Lisp 之间建立一个 socket 连接。最后会生成一个 REPL 缓冲区,你可以在这里输入 Lisp 表达式并求值。 于是现在 Slime 启动完成,你可以开始使用了。 ## 2.5 调整设置 这一部分说明了如何减少 Slime 的启动时间和如何为多 Lisp 系统配置 Slime。 在进行本部分之前请确认你的基本配置已经可以工作。如果你对基本配置感到满意,那么请跳过这部分。 关于附加模块请看“8.1 加载扩展包”。 ### 2.5.1 自动加载 基本设置始终会加载 Slime,即使你不使用它。如果你只在需要的时候才加载 Slime,那么 Emacs 会启动的快一点。要这样,你需要稍微更改你的 .emacs 文件: ```emacs-lisp (setq inferior-lisp-program "the path to your Lisp system") (add-to-list 'load-path "the path of your slime directory") (require 'slime-autoloads) (slime-setup) ``` 跟基本配置相比,差别只在这一行 (require 'slime-autoloads)。它告诉 Emacs 当 M-x slime 或者 M-x slime-connect 命令第一次执行之后 Slime 的其它部分会被自动加载。 ### 2.5.2 多种 Lisp 默认情况下,M-x slime 命令启动的程序是由 inferior-lisp-program 指定的。如果你在执行 M-x slime 命令时添加了一个前缀参数,Emacs 会启动参数中指定的程序。如果你需要经常使用它或者命令的名称太长,那么在 .emacs 文件里设置 slime-lisp-implementations 变量则较为方便。例如,在这里我们定义了两个程序: ```emacs-lisp (setq slime-lisp-implementations '((cmucl ("cmucl" "-quiet")) (sbcl ("/opt/sbcl/bin/sbcl") :coding-system utf-8-unix))) ``` 这个变量包含了一个 Lisp 程序的列表,如果你通过一个减号前缀参数启动 Slime,M-- M-x slime,你可以从这个列表里选择一个程序。当不加前缀地启动该命令,slime-default-lisp 变量里指定的程序或者是列表中的第一项会被使用。列表的元素应该像这样: ```emacs-lisp (NAME (PROGRAM PROGRAM-ARGS...) &key CODING-SYSTEM INIT INIT-FUNCTION ENV) ``` - NAME 是一个符号,用来指定 Lisp 程序 - PROGRAM 是程序的文件名。注意文件名可以包含空格。 - PROGRAM-ARGS 是一个命令行参数的列表。 - CODING-SYSTEM 指定了连接的编码系统(见 6.1 Emacs 端 slime-net-coding-system)。 - INIT 应该是一个接受两个参数的函数:一个文件名和一个字符编码。这个函数应该返回一个字符串格式的 Lisp 表达式,来指导 Lisp 启动 Swank 服务器并且将端口号写入文件。启动时,Slime 启动一个 Lisp 进程并将此函数的结果发送给 Lisp 的标准输入。默认情况下,slime-init-command 会被使用。“2.5.3 更快地加载 Swank”里有一个例子。 - INIT-FUNCTION 应该是一个不接受参数的函数。连接建立之后它会被调用。(见 6.1.1 钩子 slime-connected-hook) - ENV 一个为子进程指定环境变量的列表。例如: ```emacs-lisp (sbcl-cvs ("/home/me/sbcl-cvs/src/runtime/sbcl" "--core" "/home/me/sbcl-cvs/output/sbcl.core") :env ("SBCL_HOME=/home/me/sbcl-cvs/contrib/")) ``` 在子进程中初始化 SBCL_HOME。 ### 2.5.3 更快地加载 Swank 对于 SBCL,我们建议你新建一个有 socket 支持和 POSIX 绑定的核心配置文件,因为这些模块加载起来很耗时。为了新建一个这样的核心,执行以下的命令: ```sh shell$ sbcl (mapc 'require '(sb-bsd-sockets sb-posix sb-introspect sb-cltl2 asdf)) (save-lisp-and-die "sbcl.core-for-slime") ``` 然后,在你的 .emacs 文件里加入如下代码: ```emacs-lisp (setq slime-lisp-implementations '((sbcl ("sbcl" "--core" "sbcl.core-for-slime")))) ``` 为了最大化启动速度,你可以在核心文件里直接包含 Swank 服务器。这样做的缺点是设置的时候比较麻烦,并且当你想升级你的 Slime 或者 SBCL 的时候你要新建一个核心文件。这样做的步骤是: ```sh shell$ sbcl (load ".../slime/swank-loader.lisp") (swank-loader:dump-image "sbcl.core-with-swank") ``` 然后在 .emacs 里加入如下代码: ```emacs-lisp (setq slime-lisp-implementations '((sbcl ("sbcl" "--core" "sbcl.core-with-swank") :init (lambda (port-file _) (format "(swank:start-server %S)\n" port-file))))) ``` 类似的配置对其它 Lisp 实现也适用。 # 三、使用 Slime 模式 Slime 的所有命令都通过 slime-mode 提供。它是一个与 Emacs 的 lisp-mode 配合使用的 minor-mode。本章描述 slime-mode 及其相关事项。 ## 3.1 用户介面须知 要方便地使用 Slime,了解一些“全局的”用户界面特性是十分重要的。这一部分描述了最为重要的原则。 ### 3.1.1 临时缓冲区 某些 Slime 命令会创建临时缓冲区来显示结果。虽然这些缓冲区有它们自己的为了特定目的而使用的 major-mode,但某些特定的约定是通用的。 可以通过按 q 键来关闭临时缓冲区。此操作会关闭缓冲区并且回复缓冲区显示之前的窗口配置。临时缓冲区也可以通过一般的命令例如 kill-buffer 来关闭,这样的话之前的窗口配置就不会被恢复。 按 RET 键被认为是“做最明显的有用的事情”。例如,在 apropos 缓冲区此操作会打印出当前光标处的符号的详细描述,而在 XREF 缓冲区此操作会显示当前光标处的索引的源代码。这样的行为是效仿 Emacs 的显示相关内容、补全结果等的缓冲区。 含有 Lisp 符号的临时缓冲区会使用 slime-mode 来补充它自己的特定的模式。这样就可以使用一般的 Slime 命令,例如描述符号、查找函数定义等等。 对这些“描述性的”缓冲区的初始聚焦由变量 slime-description-autofocus 确定。如果它是 nil(默认的),这些描述性缓冲区不会自动聚焦,反之则会。 ### 3.1.2 `*inferior-lisp*`缓冲区 Slime 在内部使用 comint 包来启动 Lisp 进程。这会产生一些用户可见的结果,有些是好的,另一些则不是。为了避免产生疑惑,理解其交互特性是很有用的。 *inferior-lisp* 缓冲区包含有 Lisp 进程自己的 top-level。这个与 Lisp 的直接连接对错误排查很有用,并且使用 inferior-slime-mode 可以达到某种程度上的 Slime 集成。许多人选择加载更好的集成模块 SLIME REPL 包(见 8.2 REPL)而无视 *inferior-lisp* 缓冲区。(见 8.1 加载扩展包 获得更多关于启动 REPL 的信息。) ### 3.1.3 多线程 如果 Lisp 支持多线程,对于每个请求 Slime 会生成一个新的线程,例如,C-x C-e 会创建一个新线程来对表达式求值。但是对于从 REPL 来的请求则是一个例外:所有在 REPL 缓冲区里输入的命令都会在一个专用的 REPL 线程里求值。 多线程和特殊变量会导致一些复杂性。非全局的特殊绑定是在本地线程里的,也就是说,在一个线程里改变一个由 let 绑定的特殊变量的值不会影响到其它线程里相同名字的变量的值。这增加了改变新线程的打印和读取行为的困难程度。变量 swank:*default-worker-thread-bindings* 就是为了应付这种情况的:不需要改变一个变量的全局的值,而是增加 swank:*default-worker-thread-bindings* 的绑定,例如,使用下面的代码,新的线程会默认将浮点值读取为 double。 ```emacs-lisp (push '(*read-default-float-format# . double-float) swank:*default-worker-thread-bindings*) ``` ### 3.1.4 键绑定 总体上我们会让我们的键绑定跟 Emacs 的键绑定配合良好。我们也使用了我们自己的某种不太寻常的约定:当键入一个三次按键的命令时,最后一次按键可以按 Control 也可以不按。例如,slime-describe-symbol 命令的键绑定是 C-c C-d d,但是按 C-c C-d C-d 也是同样的。我们将两种方式都绑定了,因为有些人喜欢三次按键都按着 Control 键,而有些人则不是。并且有两次按键作为前缀,我们不怕键不够用。 这条规则只有一个例外,希望不要让你中招。我们从来不在任何命令里绑定 C-h 键,所以 C-c C-d C-h 跟 C-c C-d h 做的事情是不一样的。这是因为 Emacs 内建的默认情况是,输入一个前缀,然后按 C-h,会显示处所有以该前缀开始的键绑定。所以 C-c C-d C-h 命令实际上会显示出所有的文档命令。这个特性太有用了所以我们不会替换它! “你是故意破坏 Emacs 超级牛逼的在线帮助机制吗?上帝都会震怒的!” 此建议十分有用。Emacs 的在线帮助机制是你最快捷、最完整和最新的关于键绑定的信息来源。它们是你的朋友: - C-h k或者 M-x describe-key 描述当前缓冲区的绑定到 的函数。 - C-h b 或 describe-bindings 列出当前缓冲区的所有键绑定。 - C-h m 或 describe-mode 显示所有当前缓冲区可用的 major-mode 的命令,然后是所有的 minor-mode 的命令。 - C-h l 或 view-lossage 按顺序显示出你刚刚按了的所有按键的序列。 注意:在本文档里 C-h 指定的意思是一个“典型键绑定”(canonical key),它可能是 Ctrl-h 或者是 F1。或者是普通情况下你的.emacs 文件里配置的 help-command 函数的绑定。下面是一种情形: ```emacs-lisp (global-set-key [f1] 'help-command) (global-set-key "\C-h" 'delete-backward-char) ``` 在这种情况下,在本文档中任何地方你看到的 C-h 你都可以用 F1 来代替。 你可以像这样用 global-set-key 函数在你的~/.emacs 文件里全局地更改默认的键绑定: ```emacs-lisp (global-set-key "\C-c s" 'slime-selector) ``` 这会绑定 slime-select 函数到 C-c s。 或者,如果你只是想在特定的 slime 模式下新建或改变键绑定,你可以像这样在你的~/.emacs 文件里使用 define-key 函数: ```emacs-lisp (define-key slime-repl-mode-map (kbd "C-c ;") 'slime-insert-balanced-comments) ``` 这会在 REPL 缓冲区里绑定 slime-insert-balanced-comments 函数到 C-c ; 键绑定。 ## 3.2 求值命令 这些命令每一个都以不同的方式来对一个 Common Lisp 表达式求值。一般来说它们模仿 Emacs Lisp 的求值命令。默认情况下它们会在显示区显示出结果,但是一个前缀参数会让结果插入到当前缓冲区中。 - C-x C-e 或 M-x M-x slime-eval-last-expression 对光标前的表达式求值并且将结果显示到显示区 - C-M-x 或 M-x slime-eval-defun 对当前 toplevel 的形式进行求值并将结果打印到显示区。“C-M-x”会特别对待“defvar”。正常来讲,如果定义的变量已经有一个值了,“defvar”表达式不会做任何事情。但是“C-M-x”命令无条件的将“defvar”表达式里定义的值初始化并赋予指定的值。这个特性十分便于调试 Lisp 程序。 如果带数字参数地执行 C-M-x 或者 C-x C-e,它会将结果插入到当前缓冲区,而不是将其打印到显示区。 - C-c : 或 M-x slime-interactive-eval 从迷你缓冲区读取一个表达式并求值 - C-c C-r 或 M-x slime-eval-region 对区域进行求值 - C-c C-p 或 M-x slime-pprint-eval-last-expression 对光标前的表达式进行求值并将结果漂亮地打印在一个新的缓冲区里 - C-c E 或 M-x slime-edit-value 在一个叫做“Edit
本源码包内暂不包含可直接显示的源代码文件,请下载源码包。