SLIME 使用手冊
一、簡介
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) </ul>
絕大部分特性在不同實現上的表現都是一致的,但是有些可能會有所不同。這些包括放置編譯信息的注釋的精度、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 和版本倉庫的進行對比:
cvs diff -rHEAD ChangeLog # or: -rFAIRLY-STABLE
2.3 安裝
如果你已經有了一個可以從命令行啟動的 Lisp 實現,那么僅需在 .emacs 文件中添加幾行即可安裝成功:
(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 文件:
(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 變量則較為方便。例如,在這里我們定義了兩個程序:
(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 變量里指定的程序或者是列表中的第一項會被使用。列表的元素應該像這樣:
(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 一個為子進程指定環境變量的列表。例如:
(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 綁定的核心配置文件,因為這些模塊加載起來很耗時。為了新建一個這樣的核心,執行以下的命令:
shell$ sbcl (mapc 'require '(sb-bsd-sockets sb-posix sb-introspect sb-cltl2 asdf)) (save-lisp-and-die "sbcl.core-for-slime")
然后,在你的 .emacs 文件里加入如下代碼:
(setq slime-lisp-implementations '((sbcl ("sbcl" "--core" "sbcl.core-for-slime"))))
為了最大化啟動速度,你可以在核心文件里直接包含 Swank 服務器。這樣做的缺點是設置的時候比較麻煩,并且當你想升級你的 Slime 或者 SBCL 的時候你要新建一個核心文件。這樣做的步驟是:
shell$ sbcl (load ".../slime/swank-loader.lisp") (swank-loader:dump-image "sbcl.core-with-swank")
然后在 .emacs 里加入如下代碼:
(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。
(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 函數的綁定。下面是一種情形:
(global-set-key [f1] 'help-command) (global-set-key "\C-h" 'delete-backward-char)
在這種情況下,在本文檔中任何地方你看到的 C-h 你都可以用 F1 來代替。
你可以像這樣用 global-set-key 函數在你的~/.emacs 文件里全局地更改默認的鍵綁定:
(global-set-key "\C-c s" 'slime-selector)
這會綁定 slime-select 函數到 C-c s。
或者,如果你只是想在特定的 slime 模式下新建或改變鍵綁定,你可以像這樣在你的~/.emacs 文件里使用 define-key 函數:
(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
”的新緩沖區里編輯一個可以 setf 的形式的值。這個值會被插入一個臨時緩沖區以便編輯,然后用 C-c C-c 命令來提交設置于 Lisp 中。 -
C-x M-e 或 M-x slime-eval-last-expression-display-output
對光標前的表達式求值并將結果打印在顯示緩沖區里。如果表達式會寫一些內容到輸出流的話這會很有用。
-
C-c C-u 或 M-x slime-undefine-function
用 fmakunbound 來取消當前光標處函數的定義。
3.3 編譯命令
Slime 有許多很好的命令來編譯函數、文件和包。好的地方在于,很多 Lisp 編譯器生成的提示和警告會被攔截,然后直接注釋給 Lisp 源文件緩沖區里相應的表達式。(試一試看會發生什么。)
-
C-c C-c 或 M-x slime-compile-defun
編譯光標處的 top-level 形式。被選擇的區域會閃一下以給出回應,表明是哪一部分被選擇了。若給了一個(正的)前綴參數的時候,形式會以最小調試設置來編譯。若是一個負的前綴參數,編譯速度會被優化。區域里的代碼在編譯之后將要被執行,總的來說,此命令將該區域寫入一個文件,編譯該文件,然后加載結果代碼。
-
C-c C-k 或 M-x slime-compile-and-load-file
編譯和加載當前緩沖區的源文件。如果編譯步驟失敗了,那么文件不會被加載。編譯是否失敗并不總是那么容易判斷的:某些情況下你可能會在加載階段進入調試器。
-
C-c M-k 或 M-x slime-compile-file
編譯(但不加載)當前緩沖區的源文件。
-
C-c C-l 或 M-x slime-load-file
加載 Lisp 文件。此命令用到了 Common Lisp 的 LOAD 函數。
-
M-x slime-compile-region
編譯選中的區域。
Slime 通過在源代碼的形式下加下劃線來表示有提示信息。可以通過將鼠標置于文本處或者下面這些選擇命令來閱讀帶有提示信息的編譯器消息。
-
M-n 或 M-x slime-next-note
將光標移到下一個編譯器消息處并顯示消息。
-
M-p 或 M-x slime-previous-note
將光標移到上一個編譯器消息處并顯示消息。
-
C-c M-c 或 M-x slime-remove-notes
刪除緩沖區里的所有提示信息。
-
C-x ‘ 或 M-x next-error
訪問下一個錯誤消息。實際上這不是一個 Slime 命令,Slime 會創建一個隱藏的緩沖區,然后大部分的編譯模式的命令(見 info “emacs”文件的“Compilation Mode”節點)都會類似批處理編譯器一樣地編譯 Lisp。
3.4 補全命令
補全命令的作用是根據光標處已有的東西來補全一個符號或者形式。典型的補全假設一個確定的前綴,給出的選擇也只是可能發生的分支。模糊補全會做更多的嘗試。
-
M-TAB 或 M-x slime-complete-symbol
補全光標處的符號。注意,Slime 里有三種模式的補全;默認的模式跟正常的 Emacs 補全類似(見 6.1 slime-complete-symbol-function)
3.5 查找定義(“Meta-Point”命令)
Slime 提供了熟悉的 M-. 命令。對于廣泛函數來講此命令會找出所有的方法,而在某些系統上它會做一切其它事情(例如根據 DEFSTRUCT 定義來追蹤結構訪問器)。
-
M-. 或 M-x slime-edit-definition
跳至光標處符號的定義處
-
M-, 或 M-# 或 M-x slime-pop-find-definition-stack
回到 M-. 命令執行的光標處。如果 M-. 被執行了多次,那么此命令會多重地回溯。
-
C-x 4 . 或 M-x slime-edit-definition-other-window
類似 slime-edit-definition,但是會跳到另一個窗口來編輯其定義。
-
C-x 5 . 或 M-x slime-edit-definition-other-frame
類似 slime-edit-definition,但是會跳到另一個框架來編輯其定義。
-
M-x slime-edit-definition-with-etags
使用 ETAGES 的表來尋找當前光標處的定義。
3.6 文檔命令
Slime 的在線文檔命令效仿了 Emacs 的例子。這些命令都以 C-c C-d 為前綴,并且允許更改其鍵綁定或者取消更改(見 3.1.4 鍵綁定)
-
SPC 或 M-x slime-space
Space 鍵插入一個空格鍵,并且也查找并顯示出當前光標處函數的參數列表,如果有的話。
-
C-c C-d d 或 M-x slime-describe-symbol
描述當前光標處的符號。
-
C-c C-d f 或 M-x slime-describe-function
描述當前光標處的函數。
-
C-c C-d a 或 M-x slime-apropos
對于一個正則表達式執行一個合適的搜索,來搜索所有的 Lisp 符號名稱,并且顯示出相應的文檔字符串。默認情況下所有包的外部變量都會被搜索,你可以用一個前綴參數來指定特定的包或者是否包含未導出的符號。
-
C-c C-d z 或 M-x slime-apropos-all
類似 slime-apropos 但是默認包含所有內部符號。
-
C-c C-d p 或 M-x slime-apropos-package
顯示包內所有符號的合適的結果。這個命令是用來在一個較高層次瀏覽包的。加上包名補全,它可以差不多被當作是一個 Smalltalk 類似的圖像瀏覽器。
-
C-c C-d h 或 M-x slime-hyperspec-lookup
在《Common Lisp Hyperspec》里查找當前光標處的符號。它使用常用的 hyperspec.el 來在瀏覽器里顯示相應的部分。Hyperspec 可以在網絡上或者在 common-lisp-hyperspec-root 處,默認打開的瀏覽器通過 browse-url-browser-function 指定。
注意:這里就是一個 C-c C-d h 跟 C-c C-d C-h 不同的例子
-
C-c C-d ~ 或 M-x hyperspec-lookup-format
在《Common Lisp Hyperspec》里查找一個 foramt 格式控制符。
-
C-c C-d # 或 M-x hyperspec-lookup-reader-macro
在《Common Lisp Hyperspec》里查找一個讀取宏。
3.7 交叉引用命令
Slime 的交叉引用命令是基于 Lisp 系統的支持的,而此特性在不同 Lisp 實現上差異頗大。對于那些沒有內置 XREF 支持的 Lisp 系統,Slime 需要一個可移植的 XREF 包,這個包是從 CMU AI Repository 獲得并且與 Slime 綁定在一起的。
所以這些命令的操作對象都是當前光標處的符號,如果沒有,則會要求用戶輸入。如果有前綴參數,則總會要求用戶輸入符號。你可以輸入以下所示的鍵綁定,或者將最后一個鍵加上 control。見 3.1.4 鍵綁定。
-
C-c C-w c 或 M-x slime-who-calls
顯示該函數的調用者。
-
C-c C-w c 或 M-x slime-who-calls
顯示該函數調用了的函數。
-
C-c C-w r 或 M-x slime-who-references
顯示對全局變量的引用。
-
C-c C-w b 或 M-x slime-who-binds
顯示對全局標量的綁定。
-
C-c C-w s 或 M-x slime-who-sets
顯示對全局標量的賦值。
-
C-c C-w m 或 M-x slime-who-macroexpands
顯示某個宏擴展之后的結果。
-
M-x slime-who-specializes
顯示一個類所有已知的方法。
當然也有所謂的“列出調用者 / 被調用者”命令。這些操作會在一個很底層的層次上搜尋堆上的函數對象,來確定所有調用的情況。只有某些 Lisp 系統有此功能,并且在無法獲得精確的 XREF 信息時,這些功能可以作為備用。
-
C-c < 或 M-x slime-list-callers
列出一個函數的所有調用者。
-
C-c > 或 M-x slime-list-callees
列出一個函數所有調用的函數。
3.7.1 XREF 緩沖區命令
XREF 緩沖區可用的命令。
-
RET 或 M-x slime-show-xref
在另一個窗口里顯示當前光標處的符號的定義。不離開 XREF 緩沖區。
-
Space 或 M-x slime-goto-xref
在另一個窗口里顯示當前光標處的符號的定義并且關閉 XREF 緩沖區。
-
C-c C-c 或 M-x slime-recompile-xref
重新編譯當前光標處的定義。
-
C-c C-c 或 M-x slime-recompile-all-xrefs
重新編譯所有定義。
3.8 宏擴展命令
-
C-c C-m 或 M-x slime-macroexpand-1
將光標處的表達式宏展開一次。如果帶有一個前綴參數,則使用 macroexpand 代替 macroexpand-1。
-
C-c M-m 或 M-x slime-macroexpand-all
將光標處的表達式完全宏展開。
-
M-x slime-compiler-macroexpand-1
顯示光標處的編譯宏展開的 sexp。
-
M-x slime-compiler-macroexpand
反復展開光標處的編譯宏的 sexp。
更多的 minor-mode 命令及相關討論見 5.2 slime-macroexpansion-minor-mode。
3.9 分解命令
-
C-c M-d 或 M-x slime-disassemble-symbol
分解光標處的函數定義。
-
C-c C-t 或 M-x slime-toggle-trace-fdefinition
觸發對光標處函數的跟蹤。若有前綴參數,則讀取附加信息,例如跟蹤某個指定的方法。
-
M-x slime-untrace-all
停止跟蹤所有函數。
3.10 中止 / 恢復命令
-
C-c C-b 或 M-x slime-interrupt
中斷 Lisp 進程(發送 SIGINT)。
-
M-x slime-restart-inferior-lisp
重啟 inferior-lisp 進程。
-
C-c ~ 或 M-x slime-sync-package-and-default-directory
從 Emacs 到 Lisp 同步當前包到工作目錄。
-
C-c M-p 或 M-x slime-repl-set-package
設置 REPL 的包。
-
M-x slime-cd
設置 Lisp 進程所在的當前目錄。這也改變了 REPL 的當前目錄。
-
M-x slime-pwd
打印出 Lisp 進程的當前目錄。
3.11 檢查命令
Slime 查看器是一個基于 Emacs 的對普通 INSPECT 函數的替代選擇。Slime 查看器會在一個 Emacs 緩沖區中結合使用文本和對其它對象的超鏈接來展示一個對象。
Slime 查看器可以輕易地為你的程序里的對象做定制化。詳細用法見 swank-backend.lisp 里的 inspect-for-emacs 廣泛函數。
-
C-c I 或 M-x slime-inspect
查看輸入在一個迷你緩沖區里的表達式的值。
在查看器里可以使用的標準命令有:
-
RET 或 M-x slime-inspector-operate-on-point
如果光標處是一個值,那么對這個值遞歸地調用查看器查看它。如果光標處是一個命令,則調用它。
-
d 或 M-x slime-inspector-describe
描述光標處的槽。
-
v 或 M-x slime-inspector-toggle-verbose
在冗余模式和簡潔模式之間切換。默認值由 swank:inspector-verbose 指定。
-
l 或 M-x slime-inspector-pop
回到前一個對象(從 RET 返回)。
-
n 或 M-x slime-inspector-next
l 的逆操作。也綁定到了空格鍵。
-
g 或 M-x slime-inspector-reinspect
再次查看。
-
q 或 M-x slime-inspector-quit
關閉查看緩沖區。
-
p 或 M-x slime-inspector-pprint
在另一個緩沖區里打印出光標處的對象。
-
. 或 M-x slime-inspector-show-source
查看光標處的對象的源碼。
-
或 M-x slime-inspector-fetch-all
取得所有查看器的內容并且移到其最后。
-
M-RET 或 M-x slime-inspector-copy-down
將光標之后所有在“*”變量里的值存儲起來。這些對象可以之后在 REPL 中訪問。
-
TAB, M-x slime-inspector-next-inspectable-object 或 S-TAB, M-x slime-inspector-previous-inspectable-object
分別是跳至下一個或者前一個可查看對象。
3.12 分析命令
所有的分析命令都是給予 CMUCL 的分析器。它們都是對函數的簡單包裝,然后打印一些信息到輸出緩沖區。
-
M-x slime-toggle-profile-fdefinition
觸發對一個函數的分析。
-
M-x slime-profile-package
分析一個包里的函數。
-
M-x slime-profile-by-substring
分析所有名字含有某個子串的函數。
-
M-x slime-unprofile-all
停止所有分析。
-
M-x slime-profile-report
報告分析數據。
-
M-x slime-profile-reset
重置分析數據。
-
M-x slime-profiled-functions
顯示當前所有正在分析的函數。
3.13 遮蓋命令
-
C-c C-a, M-x slime-nop 和 C-c C-v, M-x slime-nop
此鍵綁定由 inf-lisp 遮蓋。
3.14 語義縮進
Slime 會自動地決定如何縮進你的 Lisp 程序里的宏。為了達到這個目的,Lisp 端會查看系統內所有的宏并且將有 &body 參數的宏報告給 Emacs。然后 Emacs 會對這些宏的縮進特殊處理,通常情況是,將其第一個參數縮進四個空格,而 body 參數縮進兩個空格。
這僅僅“夠用”。如果你是那種很幸運的人,那么你要閱讀本節剩下的內容。
為了簡化實現,Slime 并不區分宏和其他簡單的符號名,除了不同的包名。這使得 Slime 和 Emacs 自己的縮進方式兼容得很好。但是,如果你有些宏和某些簡單符號有相同的名字,那么它們的縮進會相同,使用它們的參數列表里任一縮進方式。你可以找出有哪些符號有縮進沖突:
(swank:print-indentation-lossage)
如果有沖突讓你很惱火,不要崩潰,只要用你喜歡的縮進方式覆蓋 elisp 符號的 common-lisp-indent-function 屬性就可以了。Slime 不會覆蓋你的定制變量,它只是嘗試給你最好的默認設置。
更加巧妙的是,有個不那么完美的緩存機制來保證良好的性能。
理想情況下,在每次 Emacs 操作之后,Lisp 會自動查看所有符號的縮進的改變情況。但是若要每次都執行,那么效率就太低了。所以,Lisp 通常只會查看那些 Emacs 使用到的屬于本地包的符號,而所有的請求都是從它們那里來的。這使得取得在交互環境下定義的宏的縮進變得十分高效。為了查看剩下的那些,當有新的 Lisp 包被創建的時候——例如新系統被加載,所有的符號都會被查看。
你可以使用 M-x slime-update-indentation 來強制要求所有符號的縮進信息都被查看。
3.15 根據讀取器的結果字符化
Slime 會自動對讀取器條件判斷表達式進行求值,例如#+linux,在源代碼緩沖區里,所有會被當前 Lisp 連接所忽略掉的代碼都會呈現為灰色以示不被讀取。
四、SLDB:Slime 調試器
Slime 有一個自己的基于 Emacs 的調試器,SLDB。Lisp 系統里的狀況(Condition)發出的信號會在 Emacs 里通過 Lisp 符號*DEBUGGER-HOOK*觸發 SLDB。
當有狀況發出信號時,SLDB 會生成一個新的緩沖區。這個緩沖區會顯示對狀況的描述、一系列重啟選項和調用棧。可以通過提供的命令來出發重啟、檢查調用棧和在堆棧調用窗口里移動。
4.1 檢查窗口
用來查看光標處的堆棧調用窗口的命令。
-
t 或 M-x sldb-toggle-details
出發顯示本地變量和 CATCH 標簽
-
v 或 M-x sldb-show-source
查看窗口處的當前代碼表達式。此表達式會被展現在 Lisp 源代碼的緩沖區里。
-
e 或 M-x sldb-eval-in-frame
對窗口里的表達式求值。表達式可以引用窗口里可用的局部變量。
-
d 或 M-x sldb-pprint-eval-in-frame
對窗口里的表達式求值,并且在一個臨時緩沖區里打印出來。
-
D 或 M-x sldb-disassemble
拆解窗口處的函數。包括例如窗口對指令指針等信息。
-
i 或 M-x sldb-inspect-in-frame
查看對窗口里一個函數求值后的結果。
-
C-c C-c 或 M-x sldb-recompile-frame-source
重新編譯窗口。C-u C-c C-c 是以最大調試模式重新編譯。
4.2 重啟
-
a 或 M-x sldb-abort
觸發 ABORT 重啟。
-
q 或 M-x sldb-quit
“QUIT”——THROW 一個 top-level 的 Slime 請求循環可以捕獲的標簽。
-
c 或 M-x sldb-continue
觸發 CONTINUE 重啟。
-
0 ... 9
通過數字觸發重啟。
重啟也可以通過在緩沖區里按 RET 或者 Mouse-2 來觸發。
4.3 在不同的窗口間操作
-
n 或 M-x sldb-down, p 或 M-x sldb-up
在不同窗口間移動。
-
M-n 或 M-x sldb-details-down, M-p 或 M-x sldb-details-up
有技巧地在不同窗口間移動:隱藏之前窗口的詳細信息,顯示下一個窗口的詳細信息和源代碼。這些小技巧讓你只看到當前窗口的詳細信息和源代碼。
-
或 M-x sldb-end-of-backtrace
獲取所有的堆棧調用并且到最后一個窗口。
-
< 或 M-x sldb-beginning-of-backtrace
到第一個窗口。
4.4 單步調試
單步調試并非在所有的 Lisp 實現里都是可用的,在那些可用的 Lisp 實現中,它的表現也很不同。
-
s 或 M-x sldb-step
單步運行窗口中的下一個表達式。對 CMUCL 來說,即時在從當前位置可到達的所有代碼的位置上設置斷點。
-
x 或 M-x sldb-next
單步運行函數里的下一個形式。
-
o 或 M-x sldb-out
暫時停止單步調試,當前函數一返回則恢復單步調試。
4.5 其它命令
-
r 或 M-x sldb-restart-frame
以當前窗口最先運行時的參數為參數重啟。(此命令并非在所有 Lisp 實現里都可用)
-
R 或 M-x sldb-return-from-frame
在 minibuffer 里輸入一個值,并以這個值為返回值回到窗口。(此命令并非在所有 Lisp 實現里都可用)
-
B 或 M-x sldb-break-with-default-debugger
退出 SLDB 并且以 Lisp 默認的調試器調試狀況。
-
C 或 M-x sldb-inspect-condition
查看當前正在調試的狀況。
-
: 或 M-x slime-interactive-eval
在 minibuffer 里輸入一個表達式并求值。
五、雜項
5.1 slime-selector
slime-selector 用來快速切換到重要的緩沖區:REPL、SLDB、你正在 hack 的 Lisp 源代碼等等。一旦觸發 slime-selector,該命令會要求你輸入一個字母來指定顯示哪一個緩沖區。這里是一些選項。
-
?
一個幫助緩沖區,它會列出所有 slime-selector 可以顯示的緩沖區。
-
r
當前 Slime 連接的 REPL 緩沖區。
-
d
當前連接最近使用的 SLDB 緩沖區。
-
l
最近訪問的 Lisp 源代碼緩沖區。
-
s
slime-scratch 緩沖區。
-
c
Slime 連接緩沖區。
-
t
Slime 線程緩沖區。
slime-selector 沒有一個默認的鍵綁定,但是我們建議你給它設置一個全局的鍵綁定。你可以像這樣將它設置為 C-c s:
(global-set-key "\C-c s" 'slime-selector)
然后你就可以通過 C-c s r 從任何地方切換到 REPL。
宏 def-slime-selector-method 可以用來定義 slime-selector 可識別的新緩沖區。
5.2 slime-macroexpansion-minor-mode
一個 Slime 宏擴展緩沖區提供了一些其它命令(這些命令一直是可用的,只是只有在宏擴展緩沖區里才綁定到了特定的鍵上)
-
C-c C-m 或 M-x slime-macroexpand-1-inplace
像 slime-macroexpand-1 一樣不過原來的形式被展開后的形式替代了。
-
g 或 M-x slime-macroexpand-1-inplace
最后的宏展開再次被執行,當前宏展開緩沖區的內容被新展開的內容替換掉了。
-
q 或 M-x slime-temp-buffer-quit
關閉展開緩沖區。
-
C-_ 或 M-x slime-macroexpand-undo
取消最后一次宏展開操作。
5.3 多重連接
Slime 可以同時連接到多個 Lisp 進程。當帶有前綴參數地調用 M-x slime 命令時,如果已經有一個 Lisp 進程了,它會創建一個新的 Lisp 連接。這很方便,但是這需要一些技巧來確保你的 Slime 命令是在你期望的 Lisp 進程里執行的。
有些緩沖區是連接到特定的 Lisp 進程的。每個 Lisp 進程都有自己的 REPL 緩沖區,在相應緩沖區里輸入的所有表達式和所有命令都會被發送到相應的連接。其它 Slime 創建的進程也類似地跟它們最開始的進程綁定在一起,包括 SLDB 緩沖區、搜索結果等等。這些緩沖區是跟 Lisp 進程交互的結果,所以在這些緩沖區里執行的命令也發送到相應的進程。
在其它地方執行的命令,例如 slime-mode 源代碼緩沖區,總是使用“默認的“鏈接。通常來講是最近建立的連接,但是這可以通過“連接列表“緩沖區重新指定。
-
C-c C-x c 或 M-x slime-list-connections
生成一個緩沖區并列出所有已建立的連接。
-
C-c C-x t 或 M-x slime-list-threads
生成一個緩沖區并顯示當前線程。
slime-list-connections 生成的緩沖區顯示對每個連接有個一行的簡介。簡介顯示了連接的序列號、Lisp 實現的名字以及其它的 Lisp 進程信息。當前的“默認”連接通過一個星號來指示。
connection-list 緩沖區里可用的命令有:
-
RET 或 M-x slime-goto-connection
顯示光標處連接的 REPL 緩沖區。
-
d 或 M-x slime-connection-list-make-default
讓光標處的連接成為“默認“連接。它會被 slime-mode 源代碼緩沖區的命令使用。
-
g 或 M-x slime-update-connection-list
更新緩沖區里的連接列表。
-
q 或 M-x slime-temp-buffer-quit
退出連接列表緩沖區(殺掉緩沖區,回到之前的窗口設置)
-
R 或 M-x slime-restart-connection-at-point
重啟光標處的進程的連接。
-
M-x slime-connect
連接到一個運行中的 Swank 服務器。
-
M-x slime-disconnect
退出所有連接。
-
M-x slime-abort-connection
取消當前的連接嘗試。
六、定制
6.1 Emacs 端定制
Slime 的 Emacs 部分可以通過 Emacs 的定制系統來進行配置,通過 M-x customize-group slime RET。由于此定制系統是自描述的,因此在本文檔里我們只會包含某些重要的或者可能有歧義的選項。
-
slime-truncate-lines
在 Slime 生成的 line-by-line 摘要緩沖區里使用 truncate-lines 的值。這是默認的,來保證行不會被以某種回溯的列表來折疊。它可能會造成某些信息超出屏幕。
-
slime-complete-symbol-function
用來補全 Lisp 符號的函數。有三種補全方式:slime-simple-complete-symbol,slime-complete-symbol*(見 8.5 混合補全),和 slime-fuzzy-complete-symbol(見 8.6 模糊補全)。
默認的是 slime-simple-complete-symbol,類似于 Emacs 的補全方式。
-
slime-filename-translations
這個變量控制 Emacs 和 Lisp 之間文件名的轉換。當你在不同的機器上運行 Emacs 和 Lisp,而它們的文件系統并不相同,或者它們有相同的文件系統但是布局不同,例如使用了 SMB 的文件共享的時候,這個變量就有用了。
-
slime-net-coding-system
如果你想在 Emacs 和 Lisp 之間傳送 Unicode 字符,你應該設置此變量。例如你使用 SBCL,你應該這樣設置:
(setq slime-net-coding-system 'utf-8-unix)
要顯示 Unicode 字符你還需要適當的字體,否則這些字符會被渲染成空心方塊。如果你使用的是 Allegro CL 和 GNU Emacs,你也可以使用 emacs-mule-unix 作為編碼系統。GNU Emacs 給較新的編碼提供了很不錯的字體。(不同的 Lisp 系統可以使用不同的編碼,見 2.5.2 多種 Lisp。)
6.1.1 鉤子
-
slime-mode-hook
每次有一個緩沖區進入 slime-mode,這個鉤子就會啟動。它最有用的是在你的 Lisp 源代碼緩沖區里設置當前緩沖區的配置。有個例子是用它來啟動 slime-autodoc-mode(見 8.7 slime-autodoc-mode)。
-
slime-connected-hook
這個鉤子在每次連接到 Lisp 服務器的時候建立。有個例子是用它來生成一個打印窗口(見 8.13 打印窗口)。
-
sldb-hook
這個鉤子在 SLDB 啟動時創建。這個鉤子的函數是從 SLDB 緩沖區建立后調用的。有個例子是添加 add sldb-print-condition 函數到這個鉤子,這會讓所有 SLDB 調試的狀況被 REPL 緩沖區記錄到。
6.2 Lisp 端(Swank)
Slime 的 Lisp 服務器端(也叫做“Swank”),提供幾個變量可供設置。初始化文件~/.swank.lisp 在啟動時會被自動求值,可以用來設置這些變量。
6.2.1 通信模式
最重要的可以配置的變量是 SWANK:COMMUNICATION-STYLE,它指定了 Lisp 端接收和讀取 Emacs 發出的信息的協議。通信方式的選擇會在全局影響 Slime 的行為。
可選的通信方式有:
-
NIL
這種方式只是簡單地循環地讀取通信套接字里的輸入和當 Slime 協議事件發生是提供服務。這種簡單意味著當處于 Slime 的控制的時候 Lisp 不能做其它的處理。
-
:FD-HANDLER
這種方式使用經典的 Unix 的“select-loop()”。Swank 通過一個事件分發框架(例如 CMUCL 和 SBCL 里的 SERVE-EVENT)來注冊一個通信套接字,當數據到達時接收一個回調。在這種方式下,從 Emacs 而來的請求只在 Lisp 進入了事件循環時才會被檢測到并處理。這種方式簡單并且可預測。
-
:SIGIO
這種方式使用帶有 SIGIO 信號處理函數的信號驅動 I/O。Lisp 接收來自 Emacs 的請求,附帶一個信號,使 Lisp 中斷任何正在做的事來處理請求。這種方式的好處是回應即時,因為 Emacs 可以使 Lisp 執行某些操作,即使 Lisp 正在忙于某些事情。它也允許 Emacs 并發地發起請求,例如發起一個長期的請求(例如編譯)然后在它完成前發起幾個短期的請求。它的缺點是它可能其它用戶的 Lisp 代碼的 SIGIO 信號沖突,而且在某些特殊的時刻中斷 Lisp 進程的話則可能產生很嚴重的后果。
-
:SPAWN
這種方式通過 Lisp 里的多線程支持來在每個線程里執行一個請求。這種方式跟:SIGIO 有某些類似的特性,但它不使用信號,并且所有來自 Emacs 的請求都可以并行處理。
默認的請求處理方式是根據你的 Lisp 系統的能力來選擇的。通常的選擇順序是::SPAWN,然后是:SIGIO,然后:FD-HANDLER,最后是 NIL。你可以通過調用 SWANK-BACKEND::PREFERRED-COMMUNICATION-STYLE 來查看默認的方式。你也可以通過在你的 Swank 初始化文件里設置 SWANK:COMMUNICATION-STYLE 變量來覆蓋默認設置。
6.2.2 其它配置
這些 Lisp 變量可以通過你的~/.swank.lisp 文件設置:
-
SWANK:CONFIGURE-EMACS-INDENTATION
這個變量控制宏里 &body 參數的縮進方式是否會被探測到并發送給 Emacs。它默認開啟。
-
SWANK:GLOBALLY-REDIRECT-IO
當它為真,標準輸出流(例如 standard-output)會被全局重定向到 Emacs 里的 REPL。當它為假(默認情況),這些流只是在處理請求時通過動態綁定臨時重定向到 Emacs。主意 standard-input 現在不會被全局重定向到 Emacs,因為當它嘗試從 Emacs 里讀取信息時,它跟 Lisp 原生的 REPL 交互得很差。
-
SWANK:GLOBAL-DEBUGGER
當它為真(默認情況),它讓 DEBUGGER-HOOK 全局設置為 SWANK:SWANK-DEBUGGER-HOOK,當后讓 Slime 處理 Lisp 進程里的所有調試工作。這是用來調試多線程或回調驅動的應用的。
-
SWANK:SLDB-PRINTER-BINDINGS 和 SWANK:MACROEXPAND-PRINTER-BINDINGS 和 SWANK:SWANK-PPRINT-BINDINGS
這些變量可以在不同的情況下設置打印器。這些變量的值是打印器變量名和對應的值組成的聯合列表。例如,在 SLDB 中開啟 pretty 打印器來處理調用棧,你可以這樣:
(push '(*print-pretty* . t) swank:*sldb-printer-bindings*)
-
SWANK:USE-DEDICATED-OUTPUT-STREAM
這個變量控制了是否用一個不安全但很有效的 hack 來從 Lisp 打印輸出到 Emacs。默認是 nil,并且強烈建議不要使用它。
當它為 t 時,會建立一個單獨的套接字來把 Lisp 的輸出打印到 Emacs,這比使用協議發送信息來將輸出發送到 Emacs 快。但是,由于不能保證一個專用的輸出流和一個給予協議消息的流之間的時間,Lisp 命令的輸出到達的時間可能在 REPL 相應時間之前或之后。輸出結果和 REPL 的顯示結果可能以錯誤的順序呈現,甚至在 REPL 里交叉出現。使用一個專用的輸出流也會讓用 SSH 跟一個在遠程服務器上的 Lisp 程序通信變得困難。(見 7.1 連接到遠程 Lisp)
-
SWANK:DEDICATED-OUTPUT-STREAM-PORT
當 USE-DEDICATED-OUTPUT-STREAM 是 t,流會在此端口開啟。默認值是 0,表示流會在某個隨機端口開啟。
-
SWANK:LOG-EVENTS
將這個變量設置為 t 會讓所有與 Emacs 交換的協議信息都打印到 TERMINAL-IO。這在底層調試和觀察 Slime 底層如何運行是很有用。TERMINAL-IO 的輸出可以在 Lisp 系統自己的監視器里看到,通常是inferior-lisp 緩沖區。
七、小技巧
7.1 連接到遠程 Lisp
7.1.1 設置 Lisp 鏡像
如果你不想通過一般的基于 Emacs 的方式加載 swank,只需要加載 swank-load.lisp 文件就可以了。只需要在一個運行中的 Lisp 鏡像 [1] 里執行以下代碼:
(load "/path/to/swank-loader.lisp")
現在,我們需要做的就是啟動 swank 服務器。在第一個例子里,我們假設使用默認配置。
(swank:create-server)
由于我們將要使用 ssh[2] 來建立鏈接并且只打開了一個端口,我們不希望 swank 使用另一個端口作為輸出(目前這在 swank 里是默認的):
(setf swank:*use-dedicated-output-stream* nil)
如果你有其它特別的需求(例如在結束后重新連接到 swank),請查看 swank:create-server 的其它參數。其中的一些參數如下:
-
:PORT
指定服務器所監聽的端口號(默認端口:4005)
-
:STYLE
見 6.2.1 通信模式
-
:DONE-CLOSE
布爾值,指明了在服務器在接受了第一個連接后是否還會接收其它連接(默認值:nil)。對于你希望可以隨時連接的長期運行的 Lisp 進程,指定:done-close t
-
:CODING-SYSTEM
字符串,指明了 Emacs 和 Lisp 之間進行通訊的編碼
更加完整的實例如下:
(swank:create-server :port 4005 :dont-close t :coding-system "utf-8-unix")
在 Emacs 端,你會進行類似如下的設置來連接到同一臺機器上的 Lisp 鏡像:
(setq slime-net-coding-system 'utf-8-unix) (slime-connect "127.0.0.1" 4005)
7.1.2 設置 Emacs
現在我們需要在本地機器和遠程機器之間建立連接。
ssh -L4005:127.0.0.1:4005 username@remote.example.com
這里調用的 ssh 在本地機器的 4005 端口和遠程機器的 4005 端口上建立了一個 ssh 連接 [3]。
最后,我們啟動 Slime:
M-x slime-connect RET RET
RET RET 按鍵表示我們要使用默認主機(127.0.0.1)和默認端口(4005)。雖然我們是連接到遠程機器上的,ssh 連接讓 Emacs 以為我們是在本地操作。
7.1.3 設置路徑名翻譯
遠程運行 swank 的一個主要問題就是,Emacs 以為可以通過普通的文件名找到文件。如果我們希望例如 slime-compile-and-load-file (C-c C-k)或者 slime-edit-definition (M-.)這樣的函數正常工作,我們需要找到一種方法讓本地的 Emacs 正確地找到遠程文件。
要做到這一點主要有兩種方式。第一種是掛載,使用 NFS 或者類似的東西。將遠程機器的硬盤掛載到本地機器的文件系統上,這樣的話例如 /opt/project/source.lisp 的文件名就可以在兩臺機器上都指向同一個文件。不幸的是,NFS 很慢,而且容易出錯,并且不總是可行的。幸運的是我們有 ssh 連接以及 Emacs 的 tramp-mode 來完成這項工作。
我們需要做的事情是讓 Emacs 接收一個遠程機器上的文件名,然后將其翻譯為某種 tramp 可以理解和使用的格式,反之亦然。假設遠程機器的主機名叫做 remote.example.com,cl:machine-instance 返回“remote”,我們以“user”用戶登陸,我們使用 slime-tramp 擴展包來設置適當的翻譯方式,如下:
(push (slime-create-filename-translator :machine-instance "remote.example.com" :remote-host "remote" :username "user") slime-filename-translations)
7.2 重定向全局 IO 到 REPL
默認情況下 Slime 并不會改變 standard-output 和 REPL 以外的其它事物。如果你有一些其它的線程,例如 format,write-string 等等,相應的輸出僅僅能在 inferior-lisp 緩沖區或者是終端下看到,通常來說這很不方便。所以如果你有這樣的代碼:
(run-in-new-thread (lambda () (write-line "In some random thread.~%" *standard-output*)))
并且想讓它輸出到 Slime 的 REPL 緩沖區而不是 inferior-lisp 緩沖區,只需要將 swank:globally-redirect-io 設置為 T。
注意,這個變量的值只會在 swank 接收連接的時候被檢查,所以你需要把它寫在~/.swank.lisp 文件里。否則你要自己調用 swank::globally-redirect-io-to-connection 命令,但是你不應該這樣做除非你知道原因。
7.3 自動連接到 Slime
如果想要在打開一個 Lisp 文件的時候自動啟動 Slime,將以下設置加入~/.emacs 文件里:
(add-hook 'slime-mode-hook (lambda () (unless (slime-connected-p) (save-excursion (slime)))))
7. 腳注
[1]
Slime 也提供了一個功能相同的 ASDF 系統定義
[2]
有一種不使用 ssh 來連接的方法,但是其副作用是將允許所有東西連接到你的 Lisp 鏡像,所以我們不討論這種方式
[3]
默認情況下 swank 監聽來自 4005 端口的連接,如果我們調用 swank:create-server 函數時指定:port 參數,我們就可以使用其它端口了。
八、擴展包
在 3.0 版中,我們將一些功能移到了單獨的包里。本章講述如何加載擴展包的模塊,并且描述了這些包的功能。
8.1 加載擴展包
默認情況下擴展包并沒有被加載。你必須稍微設置一下,這樣 Emacs 就可以知道在哪里找到這些擴展包、加載哪些擴展包。總的來說,你應該調用 slime-setup 函數,并將需要用的包的名字作為一個列表傳給它。例如,加載 slime-scratch 和 slime-editing-commands 包的設置如下:
(setq inferior-lisp-program "/opt/sbcl/bin/sbcl") ; your Lisp system (add-to-list 'load-path "~/hacking/lisp/slime/") ; your SLIME directory (require 'slime-autoloads) (slime-setup '(slime-scratch slime-editing-commands))
啟動 Slime 后,這些擴展包的命令應該都可用了。
這里要特別提到 REPL 和 slime-fancy 擴展包。許多用戶認為 REPL(見 8.2 REPL)很必要,而 slime-fancy(見 8.20 slime-fancy)加載了 REPL 包和其它幾乎所有常用的包。所以,如果你不知道怎樣啟動,試試:
(slime-setup '(slime-repl)) ; repl only
如果你喜歡你見到的,試試:
(slime-setup '(slime-fancy)) ; almost everything
8.2 REPL:“頂層環境”
Slime 使用定制的讀 - 寫 - 打印循環(REPL,也被稱作“頂層環境”,或者是監聽者)。REPL 界面使用 Emacs Lisp 寫成,因此與傳統的基于 comint 的 Lisp 交互相比,它與 Emacs 更加契合:
-
可以通過 SLDB 調試 REPL 里表達式的狀況信號
-
打印出的不同的返回值可以通過不同的 Emacs faces(顏色)加以區分
-
Emacs 通過不同的符號管理 REPL 提示符。這確保了 Lisp 的輸出被插入到正確的位置,并且不會和其它的用戶輸入搞混。
加載 REPL 需要在你的.emacs 文件里調用 (slime-setup '(slime-repl))。
-
C-c C-z 或 M-x slime-switch-to-output-buffer
選擇輸出緩沖區,一般是在另一個窗口里
-
C-c C-y 或 M-x slime-call-defun
在 REPL 里調用在當前光標處定義的函數
8.2.1 REPL 命令
-
RET 或 M-x slime-repl-return
如果輸入完成,則在 Lisp 里對當前輸入求值。如果沒有,則開啟一個新行并縮進。如果給出了前綴參數,則不檢查輸入完整性而直接求值。
-
C-RET 或 M-x slime-repl-closing-return
關閉所有未匹配的括號并對當前輸入求值。也綁定到了 M-RET。
-
TAB 或 M-x slime-indent-and-complete-symbol
縮進當前行并進行符號補全。
-
C-j 或 M-x slime-repl-newline-and-indent
新開一行并縮進。
-
C-a 或 M-x slime-repl-bol
到行首,但是在 REPL 提示符之后。
-
C-c C-c 或 M-x slime-interrupt
以 SIGINT 中斷 Lisp 進程。
-
C-c M-o 或 M-x slime-repl-clear-buffer
清空當前緩沖區,只留一個提示符。
-
C-c C-o 或 M-x slime-repl-clear-output
從緩沖區里清空之前表達式的輸出和結果
8.2.2 輸入引導
輸入導航(歷史)命令是模仿 coming-mode 的。如果你習慣了類似 Bash 的鍵綁定,那么要注意了: M-p 和 M-n 使用當前的輸入作為搜索樣本,并且類似 Bash 一樣只有在當前行是空的情況下才工作。C-和 C-像 Bash 里的 up 和 down 鍵效果一樣。
-
C- 或 M-x slime-repl-forward-input 和 C- 和 M-x slime-repl-backward-input
去到前一個 / 后一個歷史輸入
-
M-n 或 M-x slime-repl-next-input 和 M-p 或 M-x slime-repl-previous-input
使用當前的輸入作為搜索樣本,在輸入歷史里向前 / 向后搜索相關輸入。如果 M-n/M-n 被連續按兩次,第二次調用會使用相同的搜索樣本(即使當前輸入已經改變)。
-
M-s 或 M-x slime-repl-next-matching-input 和 M-r 或 M-x slime-repl-previous-matching-input
使用正則表達式在輸入歷史里向前 / 向后搜索
-
C-c C-n 或 M-x slime-repl-next-prompt 和 C-c C-p 或 M-x slime-repl-previous-prompt
在 REPL 緩沖區的當前和前一個提示符之間移動。在有之前輸入的一行里按 RET 會把那一行復制到最新的提示符處。
slime-repl-wrap-history 變量控控制了環繞行為,即是如果到了末尾那么是否應該重新跳轉到歷史的最開頭。
8.2.3 快捷命令
“快捷命令”是一組通過名稱調用的 REPL 命令。要調用一個快捷命令,你需要先在 REPL 提示符后輸入一個逗號,然后再輸入命令的名稱來執行。
快捷命令處理一些類似于切換目錄和加載編譯 Lisp 系統的事務。快捷命令在下面列出,或者你可以通過 help 快捷命令來交互式地列出來。
-
change-directory (aka !d, cd)
改變當前目錄
-
change-package (aka !p, in, in-package)
改變當前包
-
compile-and-load (aka cl)
編譯(如果)并加載一個 Lisp 文件
-
defparameter (aka !)
定義一個新的全局的特殊的變量
-
disconnect
關閉所有連接
-
help (aka ?)
顯示幫助
-
pop-directory (aka -d)
彈出當前目錄
-
pop-package (aka -p)
彈出包棧的頂端元素
-
push-directory (aka +d, pushd)
將一個新的目錄推到目錄棧里
-
push-package (aka +p)
將一個包推到包棧里
-
pwd
顯示當前目錄
-
quit
退出 Lisp
-
resend-form
再次發送最后的形式
-
restart-inferior-lisp
重啟 inferior-lisp 并重新連接 Slime
-
sayoonara
退出所有 Lisp 并關閉所有 Slime 緩沖區
8.3 多 REPL
slime-mrepl 擴展包為多監聽者緩沖區提供了支持。M-x slime-open-listener 命令創建一個新的緩沖區。在多線程 Lisp 里,每一個監聽者都與一個單獨的線程相連。在單線程 Lisp 里,創建多監聽者緩沖區也是可以的,但是其命令都是在同一個進程里順序執行的。
8.4 inferior-slime-mode
inferior-slime-mode 是一個用來與 inferior-lisp 緩沖區一起使用的次模式。它提供了一些 Slime 命令,例如符號補全和文檔查詢。它也跟蹤 Lisp 進程的當前目錄。將以下代碼加入.emacs 配置來使用它:
(slime-setup '(inferior-slime-mode))
-
M-x inferior-slime-mode
打開或關閉 inferior-slime-mode
inferior-slime-mode-map 變量包含了額外的鍵綁定
8.5 混合補全
slime-c-p-c 擴展包提供了不同的符號補全算法,它通過中劃線分割的符號名 [1] 的單詞子串來進行“并行”的補全。形式上來講,“a-b-c”可以補全任何匹配“^a.-b.-c.*”正則表達式的符號(“圓點”匹配任何除了中劃線之外的東西)。下面的例子會給你更直觀的感覺:
-
m-v-b 補全為 multiple-value-bind。
-
w-open 稍有歧義:它可以補全 with-open-file 或 with-open-stream。它會擴展到最長的相同匹配(with-open-)然后光標會停留在有歧義的第一個字符處,在這里就是最后一個單詞處。
-
w--stream 擴展為 with-open-stream
slime-c-p-c-unambiguous-prefix-p 變量定義了在補全符號后光標應該置于何處。例如 f-o 可能的補全是 finish-output 和 force-output,默認情況下光標會移動到 f 后面,因為這里是明確的前綴。如果 f-o are finish-output and force-output 是 nil,光標會到插入的文本的最后,在這里就是在 o 之后。
除此之外,slime-c-p-c 也為字符名提供補全(對很多可以識別 Unicode 的 Lisp 實現來講通常很有用):
CL-USER> #\Sp<TAB>
在這里 Slime 會將其補全為#\Space,但在一個可以識別 Unicode 的實現里,就可能會有以下的補全:
Space Space Sparkle Spherical_Angle Spherical_Angle_Opening_Left Spherical_Angle_Opening_Up
slime-c-p-c 擴展包也提供了對關鍵字的大小寫敏感的補全。例如:
CL-USER> (find 1 '(1 2 3) :s<TAB>
在這里 Slime 會補全為:start,而不是將所有以:s 開頭的關鍵字列出來。
- C-c C-s 或 M-x slime-complete-form
如果有的話,將當前光標處的函數的參數列表列出來并插入緩沖區。更加一般地,此命令給不完全的形式的缺失參數提供了一個模板。對于發現泛函數的額外參數,處理 make-instance、defmethod 和其它很多函數來說有特殊的代碼,例如:
(subseq "abc" <C-c C-s> --inserts--> start [end]) (find 17 <C-c C-s> --inserts--> sequence :from-end from-end :test test :test-not test-not :start start :end end :key key) (find 17 '(17 18 19) :test #'= <C-c C-s> --inserts--> :from-end from-end :test-not test-not :start start :end end :key key) (defclass foo () ((bar :initarg :bar))) (defmethod print-object <C-c C-s> --inserts--> (object stream) body...) (defmethod initialize-instance :after ((object foo) &key blub)) (make-instance 'foo <C-c C-s> --inserts--> :bar bar :blub blub initargs...)
8.6 模糊補全
slime-fuzzy 擴展包提供了另一種符號補全方式。
[最好有人描述一下這種算法到底是做什么的]
它嘗試一次性補全整個符號,而不是只補全一部分。例如,“mvb”會補全為“multiple-value-bind”,“norm-df”會補全為“least-positive-normalized-double-float”。
這種算法嘗試以不同的方式擴展每一個字符,然后以下列的方式將所有可能的補全排序列出。
根據在字符串里的位置,字母會被賦予一個權值。字符串最開頭,或者是前綴字母之后的字母的權值是最高的。分隔符之后的字符,例如#-,權值是次高的。字符串最后或者是后綴字母之前的字母有中等權值,其它地方的字母的權值最低。
如果一個字母在另一個匹配字母之后,它在此處的可能性就比之前字母的可能性低,所以就會使用之前的可能性。
最后,一個偏好因子會作用于一些常用的較短的匹配,其它的東西都是一樣的。
-
C-c M-i 或 M-x slime-fuzzy-complete-symbol
根據當前光標處的縮寫列出所有可能的補全。如果你將變量 slime-complete-symbol-function 的值設為這個命令,則可以通過 M-TAB 使用模糊補全。
8.7 slime-autodoc-mode
Autodoc 模式是一個用來自動顯示光標附近符號的相關信息的 minor-mode。對于函數名,參數列表會被顯示,對于全局變量,則顯示它的值。Autodoc 是通過 Emacs 的 eldoc-mode 來實現的。
該模式可以通過你~/.emacs 文件里的 slime-setup 調用來默認開啟:
(slime-setup '(slime-autodoc))
-
M-x slime-arglist NAME
顯示函數 NAME 的參數列表
-
M-x slime-autodoc-mode
根據參數的值開啟或關閉 autodoc-mode。當沒有參數時,觸發該模式。
如果變量 slime-use-autodoc-mode 被設置(默認情況),Emacs 會啟動一個計時器,否則信息只會在按 SPC 之后顯示。
8.8 ASDF
ASDF 是一個流行的“系統構建工具”。slime-asdf 擴展包提供了一些命令來從 Emacs 里加載和編譯這些系統。ASDF 本身沒有被包含在 Slime 里,你必須自己把它加載到 Lisp 里。還有,你必須在連接之前加載 ASDF,否則你會收到關于符號缺失的錯誤。
-
M-x slime-load-system NAME
編譯并加載 ASDF 系統。默認的系統名字是從當前目錄下第一個符合 *.asd 的文件里獲得的。
-
M-x slime-open-system NAME &optional LOAD
打開系統里的所有文件,如果 LOAD 不是 nil 的話則加載進來。
-
M-x slime-browse-system NAME
使用 Dired 瀏覽系統里的所有文件。
該擴展包也加載了一些新的 REPL 快捷命令(見 8.2.3 快捷命令);
-
load-system
編譯(根據需要)并加載一個 ASDF 系統
-
compile-system
編譯(但不加載)一個 ASDF 系統
-
force-compile-system
重新編譯(但不加載)一個 ASDF 系統
-
force-load-system
重新編譯并加載一個 ASDF 系統
-
open-system
打開系統里的所有文件
-
browse-system
使用 Dired 打開系統里的所有文件
8.9 導航條
slime-banner 擴展包在當前 REPL 緩沖區安裝一個位于窗口頂端的橫條。開始的時候還會播放一段動畫。
通過將 slime-startup-animation 設置為 nil,你可以關閉動畫,而 slime-header-line-p 可以設置橫條。
8.10 編輯命令
slime-editing-commands 擴展包提供了一些命令來編輯 Lisp 表達式。
-
C-c M-q 或 M-x slime-reindent-defun
重新縮進當前的 defun,或者重排當前段落。如果光標在一段注釋里,那么光標附近的文本會被當做一個段落,然后用 fill-paragraph 重排。否則,它會被當做 Lisp 代碼,當前 defun 會被重新縮進。如果當前 defun 有沒匹配的括號,在重新縮進前會嘗試修復。
-
C-c C-] 或 M-x slime-close-all-parens-in-sexp
補全當前光標處未閉合的 S 表達式的括號。插入足夠多的右括號,使得跟它的左括號數量匹配。刪除多余的左括號,將結尾處的括號格式化為 Lisp 形式。
如果 REGION 是 true,對該區域操作。否則對頂層環境光標前的表達式操作。
-
M-x slime-insert-balanced-comments
在包含光標的表達式里插入對稱的注釋。如果該命令被重復調用(多次調用之間沒有其它命令了),注釋逐漸從里面的表達式向外擴展。如果調用的時候有前綴參數,S 表達式的參數列表會有一個對稱的注釋。
-
M-C-a 或 M-x slime-beginning-of-defun
-
M-C-e 或 M-x slime-end-of-defun
8.11 更好的檢查器
有一個默認檢查器的替代物,由 slime-fancy-inspector 擴展包提供。該檢查器更加了解 CLOS 對象和方法。它提供很多用來使 Lisp 代碼檢查對象的行為。例如,為了展示一個泛函數,檢查器會以純文本的形式顯示其文檔,而對于每個方法則會列出它的超鏈接和一個你可以調用的“除去該方法” 行為。它的鍵綁定跟默認檢查器是一樣的。
8.12 對象描述
在 Slime 里,一個“對象描述” [2] 指的是跟一個 Lisp 對象有關的一塊文本。右鍵點擊文本會彈出操作該對象的一個菜單。有些操作,例如查看,對所有對象都適用,但對象也可以有自己特有的操作。例如,路徑對象有 Dired 相關的操作。
更加重要的是,可以使用所有標準的 Emacs 命令來剪切和粘貼這些描述(也就是 Lisp 對象,而不僅僅是打印出來的樣子)。通過這種方式,可以剪切和粘貼 REPL 里之前計算出來的結果。這對不可讀對象來說十分重要。
slime-presentations 擴展包在 REPL 里安裝這種對象描述,也就是求值命令的結果會被顯示出來。使用這種方法,相關描述會生成標準 Common Lisp REPL 歷史變量 *,**,*** 的用法。例如:
CL-USER> (find-class 'standard-class) #<STANDARD-CLASS STANDARD-CLASS> CL-USER>
在緩沖區里描述會以紅色顯示。使用標準的 Emacs 命令,描述可以被復制進 REPL 內的一個新的輸入里:
CL-USER> (eql '#<STANDARD-CLASS STANDARD-CLASS> '#<STANDARD-CLASS STANDARD-CLASS>) T
當你復制了一個不完整的描述,或者編輯描述里的文本,該描述會變為純文本,丟失與 Lisp 對象之間的關聯。在緩沖區里,這會通過其顏色從紅色變回黑色來表示,而且不能撤銷。
對象描述也可以在查看器(所有可以查看的部分都是對象描述)和調試器(所有的本地變量都是對象描述)里使用。這樣就可以使用出現在調試窗口里的對象來在 REPL 里求值。這比使用 M-x sldb-eval-in-frame 更加方便。警告:從查看器和調試器而來的對象只在相關窗口打開的時候才是可用的。否則的話會引起錯誤或者混淆。
對于某些 Lisp 實現,你還可以安裝 slime-presentation-streams 包,它讓對象描述適用于 standard-output 流和其它流。這意味著不只是計算的結果,而是某些對象都可以通過與對象描述相關聯來打印到標準輸出(作為計算的副作用)。目前所有的不可讀對象和路徑都被作為對象描述打印出來。
CL-USER> (describe (find-class 'standard-object)) #<STANDARD-CLASS STANDARD-OBJECT> is an instance of #<STANDARD-CLASS STANDARD-CLASS>: The following slots have :INSTANCE allocation: PLIST NIL FLAGS 1 DIRECT-METHODS ((#<STANDARD-METHOD SWANK::ALL-SLOTS-FOR-INSPECTOR (STANDARD-OBJECT T)>
這也使得可以復制粘貼、查看這些對象。
除了標準 Emacs 命令,還有一些鍵盤命令,一個 menu-bar 菜單,一個上下文菜單來操作對象描述。我們在下面解釋了這些鍵盤命令,它們也可以通過 menu-bar 訪問。
-
C-c C-v SPC 或 M-x slime-mark-presentation
如果光標在描述內,將其移到描述的最前并標記其末尾。這樣就可以復制該描述。
-
C-c C-v w 或 M-x slime-copy-presentation-at-point-to-kill-ring
如果光標在描述內,將該描述復制到 kill ring 里。
-
C-c C-v r 或 M-x slime-copy-presentation-at-point-to-repl
如果光標在描述內,將該描述復制到 REPL 里。
-
C-c C-v d 或 M-x slime-describe-presentation-at-point
如果光標在描述內,顯示相關對象的注釋。
-
C-c C-v i 或 M-x slime-inspect-presentation-at-point
如果光標在描述內,在 Slime 查看器里查看該對象。
-
C-c C-v n 或 M-x slime-next-presentation
將光標移到緩沖區里的下一個描述處。
-
C-c C-v p 或 M-x slime-previous-presentation
將光標移到緩沖區里的上一個描述處。
相關的操作也可以在每一個描述的上下文菜單里找到。在一個描述處單擊 mouse-3 打開上下文菜單會,會顯示可用的命令。對于某些對象,某些特別的命令也是可用的。用戶可以通過給 swank::menu-choices-for-presentation 定義方法來定義特殊的命令。
警告:對于沒有弱哈希表的 Lisp 實現,所有跟對象描述相關聯的對象都被垃圾回收保護起來。如果你的 Lisp 進程因此變得太大,使用 C-c C-v M-o(slime-clear-presentations)斷開這些關聯,這會清空 REPL 緩沖區,并且斷開所有對象描述的關聯。
警告:對象描述可能讓新用戶迷惑。
CL-USER> (cons 1 2) (1 . 2) CL-USER> (eq '(1 . 2) '(1 . 2)) T
可能有人會期望結果是 nil,因為這看起來像是兩個新創建的 cons 在相互比較,而忽視了它們的對象身份。但是在上例中,對象描述 (1 . 2) 是被兩次復制到 REPL 里的,所以 eq 確實是作用在相同的對象上的,也就是之前輸入到 REPL 里的 cons 對象。
8.13 打印窗口
打印窗口是一個特殊的 Emacs 窗口,用來代替顯示區域(mini 緩沖區)來顯示 Slime 命令的信息。這是一個可選的特性。跟顯示區域相比,打印窗口的優勢是可以顯示更多的文本,可以被滾動,而且當你按鍵時內容不會消失。所有可能的較長的信息都會被發送到打印窗口,例如參數列表、宏展開等等。
-
M-x slime-ensure-typeout-frame
保證打印窗口存在,如果需要就新建一個。
如果打印窗口關閉那么會重新使用顯示區域。
如果要在啟動時自動創建一個打印窗口,需要加載 slime-typeout-frame 擴展包。(見 8.1 加載擴展包)
slime-typeout-frame-properties 變量指定了打印窗口的長度和其它可能的特性。它的值會傳給 make-frame。
8.14 TRAMP
slime-tramp 擴展包提供了一些為 TRAMP 進行文件名轉換的函數。(見 7.1.3 設置路徑名翻譯)
8.15 文檔鏈接
對于某些錯誤信息,SBCL 包含了 ANSI 標準或者 SBCL 用戶手冊相關的參考。slime-references 擴展包將這些參考變為可以點擊的鏈接。這使得在 HyperSpec 里找到這些參考相關的章節更加容易。
8.16 交叉引用和類查看器
slime-xref-browser 擴展包提供了一個基礎的類查看器。
-
M-x slime-browse-classes
該命令需要一個類的名字,它會顯示出類的所有繼承關系。
-
M-x slime-browse-xrefs
該命令顯示一個符號及其交叉引用,即它的調用者。以該符號為根的引用樹會在之后顯示出來。
8.17 高亮編輯
slime-highlight-edits 是一個用來高亮顯示 Lisp 源代碼里被修改了的部分的 minor 模式。這對于快速找到那些需要重新編譯(用 C-c C-c)的函數十分有用。
-
M-x slime-highlight-edits-mode
打開或關閉 slime-highlight-edits-mode
8.18 空白緩沖區
由 slime-scratch 擴展包提供的 Slime 的空白緩沖區,模仿 Emacs 的 scratch 緩沖區。如果 slime-scratch-file 被設置,它被用來備份空白緩沖區,使其變得可持久。它跟其它的 Lisp 緩沖區是一樣的,除了綁定到 C-j 的命令。
-
C-j 或 M-x slime-eval-print-last-expression
對光標前的表達式求值,并將結果插入到當前緩沖區里。
-
M-x slime-scratch
創建一個 slime-scratch 緩沖區。在此緩沖區里你可以輸入 Lisp 表達式并用 C-j 來求值,類似于 Emacs 的scratch 緩沖區。
8.19 slime-sprof
slime-sprof 擴展包用來集成 SBCL 的靜態分析器,sb-sprof。
slime-sprof-exclude-swank 變量控制是否顯示 swank 函數,默認值是 nil。
-
M-x slime-sprof-start
開始分析。
-
M-x slime-sprof-stop
停止分析。
-
M-x slime-sprof-browser
報告分析結果
下面的命令在 slime-sprof-browser 模式里定義:
-
RET 或 M-x slime-sprof-browser-toggle
打開或折疊函數的詳細信息(調用者、調用)
-
v 或 M-x slime-sprof-browser-view-source
查看函數源碼
-
d 或 M-x slime-sprof-browser-disassemble-function
拆開該函數
-
s 或 M-x slime-sprof-toggle-swank-exclusion
標記 swank 函數使其不在報告里
8.20 元包 slime-fancy
slime-fancy 包是一個用來加載那些最受歡迎的包的元包。
腳注
[1]
這種類型的補全由 Chris McConnell 在 completer.el 里被構建。該包跟 ILISP 綁定在一起。
[2]
對象描述是來自于 Lisp 機的特性。可以通過定義 present 方法來適用于不同的設備,例如將對象繪到位圖顯示屏或者將文本寫到字符流。
九、致謝
黑客們
Slime 是由 Eric Marsden 寫的 Slim 的擴展版。在撰寫的時候,Slime 的作者和核心貢獻者是:
Helmut Eller | Tobias C. Rittweiler | Luke Gorrie |
Matthias Koeppe | Marco Baringer | Alan Ruttenberg |
Stas Boukarev | Nikodemus Siivola | Edi Weitz |
Juho Snellman | Peter Seibel | Martin Simmons |
Geo Carncross | Christophe Rhodes | Attila Lendvai |
Douglas Crosher | Mark Evenson | Daniel Barlow |
Wolfgang Jenkner | Michael Weber | Lawrence Mitchell |
G??bor Melis | Lu?s Oliveira | Brian Downing |
Bill Clementson | Andras Simon | Zach Beane |
Espen Wiborg | Antonio Menezes Leitao | Utz-Uwe Haus |
Thomas Schilling | Thomas F. Burdick | Takehiko Abe |
Richard M Kreuter | Matthew Danish | James Bielman |
Harald Hanche-Olsen | Andreas Fuchs | Willem Broekema |
Terje Norderhaug | Taylor R. Campbell | Stelian Ionescu |
Raymond Toy | Lars Magne Ingebrigtsen | John Paul Wallington |
Joerg Hoehle | Bryan O'Connor | Alan Shutko |
Travis Cross | Tobias Rittweiler | Tiago Maduro-Dias |
Stefan Kamphausen | Sean O'Rourke | Robert Lehr |
Robert E. Brown | Nathan Bird | Mark Harig |
Jouni K Seppanen | Ivan Toshkov | Ian Eslick |
Gary King | Eric Blood | Eduardo Mu?±oz |
David Reitter | Christian Lynbech | Chris Capel |
Bj??rn Nordb?? | Ariel Badichi | Anton Vodonosov |
Alexey Dejneka | Alan Caulkins | Yaroslav Kavenchuk |
Wolfgang Mederle | Wojciech Kaczmarek | William Bland |
Tom Pierce | Tim Daly Jr. | Sven Van Caekenberghe |
Svein Ove Aas | Steve Smith | StanisBaw Halik |
Russell McManus | Rui Patroc?nio | Robert Macomber |
R. Matthew Emerson | Reini Urban | Pawel Ostrowski |
Paul Collins | NIIMI Satoshi | Neil Van Dyke |
Mikel Bancroft | Matt Pillsbury | Matthew D. Swank |
M??sz??ros Levente | Masayuki Onjo | Mark Wooding |
Marco Monteiro | Lynn Quam | Levente M??sz??ros |
Lasse Rasinen | Knut Olav B??hmer | Kai Kaminski |
Julian Stecklina | Juergen Gmeiner | Jon Allen Boone |
Johan Bockg?¥rd | Jan Rychter | James McIlree |
Ivan Shvedunov | Ivan Boldyrev | Ignas Mikalajunas |
Hannu Koivisto | Gerd Flaig | Gail Zacharias |
Frederic Brunel | Dustin Long | Didier Verna |
Dan Weinreb | Dan Pierson | Daniel Koning |
B.Scott Michel | Brian Mastenbrook | Brandon Bergren |
Bob Halley | Barry Fishman | Aleksandar Bakic |
Alain Picard |
更不要說 hyperspec.el、CLOCC 和 CMU AI Repository 附帶而來的代碼。
許多在 slime-devel 郵件列表里的人雖然沒有寫代碼但都為 Slime 做出了貢獻。但是生活是殘酷的:你必須提交代碼才能將名字列在這里。:)
多謝
我們十分感謝 common-lisp.net 的人幫我們提供空間以及其它幫助,以及從“Sourceforge 地獄”里拯救我們。
我們支持的 Lisp 實現者都很有幫助。我們要感謝 CMUCL 維護者的很有幫助的回答,Franz 的 Craig Norvell 和 Kevin Layer 為 Slime 的開發提供了 Allegro CL 協議,Peter Graves 使 Slime 能跑在 ABCL 上。
對于加入到 Slime 開發里的 Lisp 實現者們,我們表示很高興跟他們一起工作:Dan Barlow and Christophe Rhodes of SBCL, Gary Byers of OpenMCL, and Martin Simmons of LispWorks. 同時感謝 Alain Picard 以及 Memetrics 贊助 Martin LispWorks 后臺的初期工作!