七、小技巧

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)

在Emacs端,你会进行类似如下的设置来连接到同一台机器上的Lisp镜像:

(setq slime-net-coding-system 'utf-8-unix)
(slime-connect "127.0.0.1" 4005)

7.1.2 设置Emacs

现在我们需要在本地机器和远程机器之间建立连接。

ssh -N -f -L 4005: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)))))

脚注

Footnotes

[1]SLIME也提供了一个功能相同的ASDF系统定义
[2]有一种不使用ssh来连接的方法,但是其副作用是将允许所有东西连接到你的Lisp镜像,所以我们不讨论这种方式
[3]默认情况下swank监听来自4005端口的连接,如果我们调用swank:create-server函数时指定:port参数,我们就可以使用其它端口了。