加速你的 Emacs

article from:

http://lifegoo.pluskid.org/wiki/FasterEmacs.html

Emacs 会随着你定制的内容增多而启动速度越来越慢,当然,在很多服务器上是 启动之后就一直不会关闭的,但是自己的电脑不做服务器,会经常关机,而且有 些时候会临时启动一下编辑器,比如说环境变量里面的 EDITOR 就是很多程序经 常会调用的。那么,如何来加速自己的 Emacs 呢?下面给出了几个解决办法:

  • 不加载任何配置文件进行启动
  • 用 emacsclient 来连接 emacs server
  • 使用 multi-tty 补丁
  • 配合窗口管理器

不加载任何配置文件进行启动

emacs -q 命令启动可以跳过加载自己的 ~/.emacs 而进行启动,如果版本比 较新的 Emacs ,还支持 -Q 选项,表示快速启动,其实这个选项是等价于这样 启动: emacs -q --no-site-file --no-splash 。这样一般就能够达到比较快 的速度了,不足的地方就是跳过了所有定制的部分,自己熟悉的定制的功能都没 有了,见到的只是一个陌生的朋友而已。

用 emacsclient 来连接 emacs server

这个方法首先要有一个启动好了的 Emacs ,并且要已经启动了 server 模式, 你可以用 M-x server-start 来启动 server 模式,或者在自己的~/.emacs里 面加入(server-start)来自动启动 server 。

然后,你就可以通过emacsclient filename来快速使用 Emacs 打开文件了! 事实上,文件是在作为 server 的那个 Emacs 里面打开的,而 emacsclient 将 等待 server 编辑文件。这个时候你可以转到 server 那里去编辑文件,编辑好 之后用C-x #来关闭文件并通知 emacsclient 文件已经编辑完成。现在,你就 可以把自己的 EDITOR 变量设置成emacsclient而不用怕启动速度慢了:

EDITOR="emacsclient +%d %s"

不过如果没有事先启动了一个 emacs server 的话,这个命令就会失败,他提供 的一个解决办法就是--alternate-editor参数,表示连接失败的时候调用的命 令,你可以把他设置成 vi 或者是其他小巧的编辑器,或者,你也可以在这儿直 接设置成 emacs ,不过这也许并不如想象中的那么美妙,也许你认为如果没有 启动 emacs ,那么在这儿就启动它,然后后面就可以顺利地调用 emacsclient 了!但是如果这儿是其他程序比如 mutt 或者 svn 之类的使用 EDITOR 环境变 量来调用的编辑器,他会等待编辑器退出来表示编辑完成,这个时候看着刚刚启 动的 emacs 马上又要关闭了,实在是不忍心呀!😃 1 不过这个也有个不爽的 地方就是打开文件都是在 server 里面打开的,还不能自动跳转到 server 那里 去,比较麻烦。

使用 multi-tty 补丁

简介
引用作者的一句话: 2

My goal is to allow opening multiple, different tty devices and simultaneous X (graphical) and tty frames from a single Emacs session.

这里是扩展了 emacs server 的这种方法。使用 emacsclient 的时候可以另外 打开一个 X 窗口或者是 tty 窗口进行编辑,而不是简单地把编辑任务发送到 emacs server 那里。

获取和安装
使用 Debian 的 apt-get 直接安装
要使用这个补丁版本的 Emacs ,如果是 Debian 系统的话,可以直接使用他提 供的源下载安装或者下载源代码包自己编译:

# Multi-tty Emacs
deb http://aszt.inf.elte.hu/~lorentey/mirror/apt unstable multi-tty
deb-src http://aszt.inf.elte.hu/~lorentey/mirror/apt unstable multi-tty

获取 emacs—multi-tty 的源代码
其他系统可以直接下载源代码进行编译。作者提供了一个仓库,可以用 bazzar 软件来获取仓库中的源代码,他有好几个镜像,具体可以参见他的 README 文件 ,我使用其中一个仓库:

baz register-archive -f http://lorentey.hu/arch/2004/
baz get lorentey@elte.hu--2004/emacs--multi-tty emacs-multi-tty

在我这里速度很慢,不知道是为什么,连接上去以后接近半个小时才开始真正下 载文件,几分钟之后就下载完毕了,我开始还一直以为是根本无法下载呢。

获取 emacs 22 的代码和 multi-tty 的补丁文件
另外,也可以用 cvs 来获取的 Emacs 22 的源码,并打上最新的multi-tty 给的 补丁,可以在 这里 找到补丁文件,然后把他们打到 check out 出来的 emacs 的源码树上面去。这样也许速度会快一些,但是需要注意的是,最好是先下载补 丁文件,看是哪个日期的,再去获取对应那天的 Emacs 的源代码,不过,即使是 同一天的源代码,也可能会有巨大变动的,所以还是直接获取 emacs—multi-tty 的源代码安全一点。

cvs -z3 -d:pserver:anonymous@cvs.savannah.gnu.org:/cvsroot/emacs co emacs

然后到 emacs 的目录里面去,打上补丁:

cd emacs
patch -p 1 < ../emacs--multi-tty--0--patch-555.2006-05-05.patch

修改与编译

PURESIZE

编译之后尝试运行一下,有可能会出现 warning 说 ``Building Emacs overflow pure space'' 3 。事实上,因为 emacs 启动的时候有一部分只读的 不可扩展的内存,因为这儿用了 multi-tty 补丁,导致预先定义的那些内存无法 容纳下所有的预加载库,于是只有动态分配,所以会在启动的时候产生 warning 。

要解决这个问题,需要修改一下 src/pursize.h 文件,找到里面定义 PURESIZE_RATION 的地方,把值改大一点就可以了。我是把

#define PURSIZE_RATIO 1

改成了

#define PURSIZE_RATIO 4

输入法问题导致的段错误
这样可以重现这个问题:

以非 X 方式启动 Emacs : emacs -nw
在 Emacs 里面启动 server : M-x server-start
以 X 方式启动一个 emacsclient 连接到 server : emacsclient
退出这个 emacsclient : C-x 5 0
这个时候可以看到 server 已经 Segment fault 退出了。galilette@Linuxsir 指出这是由于对 server 的不存在的 XIM 对象进行释放而造成的。如果不使用 X 下的输入法作为 Emacs 的输入的话,这个问题很好解决,在 ~/.Xresources 里面加入

emacs*UseXIM: false

就可以了。但是通常 Emacs 内置的输入法不如 X 下的输入法好用,这个问题已 经发送到 emacs—multi-tty 的邮件列表,可是至今还没有得到很好的解决。 galilette@Linuxsir 提供了一个解决办法,有些 dirty ,而且可能会导致资源 泄漏,但还是可以忍受的。除了心里面觉得不舒服以外,我还没有真正因为这个 碰到任何问题,即使一直开着 X 几个月后也许会发现可用资源越来越少,系统会 越来越慢,重新起动一下 X 也应该并不是件很难办的事情吧。

galilette@Linuxsir 的方法是这样的,打开src/xterm.c,定位到这里

if (dpyinfo->display)
  XCloseIM (dpyinfo->xim);

并把这两行注释掉。

编译
接下来就可以编译了4:

$ ./configure --without-gtk
$ make bootstrap
$ make
# make install

配置与使用
试用
启动 Emacs (可以以 X 或者非 X 方式启动),并启动 server : M-x server-start 。现在可以去另外一个地方使用 emacsclient 了。扩展后的 emacsclient 支持更多选项,例如, -t 选项告诉 emacsclient 直接在终端里 面打开,而不是建立一个 X 窗口。启动之后会有提示,如果是有文件名作为参 数,编辑完成之后可以使用C-x #退出,否则可以使用C-x 5 0退出。

一次启动随处运行
在 emacs—multi-tty 的 README 文件中提供了一个很 cool 的脚本,使用 Screen 把 Emacs 服务器隐藏起来,事实上,只需要在计算机启动的时候启动 Emacs 的 server ,之后就可以一直使用 emacsclient 进行连接,甚至在不同 的 X 会话中,甚至在重新登陆以后。非常舒服。

galilette@Linuxsir 提议说仅仅为了一个从来不会切换到前台进行使用的 Emacs 的 server 而启动一个 Screen 会话对其进行维护太浪费了。使用更轻量 级的 dtach 更舒服一些5。下面就是相关脚本。

首先是 preload-emacs ,用于检查是否有指定的 server 在运行,如果没有, 则启动它。

首先是 emacs—multi-tty README 里面提到的脚本,使用 Screen :

#!/bin/bash
# Usage: preload-emacs <name> [<waitp>]
#
# Preloads the Emacs instance called NAME in a detached screen
# session. Does nothing if the instance is already running. If WAITP
# is non-empty, the function waits until the server starts up and
# creates its socket; otherwise it returns immediately.

name="$1"
waitp="$2"
screendir="/var/run/screen/S-$USER"
serverdir="/tmp/emacs$UID"
emacs="/usr/local/bin/emacs" # Or wherever you installed your multi-tty Emacs

if [ -z "$name" ]; then
    echo "Usage: preload_emacs <name> [<waitp>]" >&2
    exit 1
fi

if [ ! -e "$screendir"/*."$name" ]; then
    if [ -e "$serverdir/$name" ]; then
# Delete leftover socket (for the wait option)
        rm "$serverdir/$name"
    fi
 screen -dmS "$name" "$emacs" -nw --no-splash --eval "(setq server-name \"$name\")" -f server-start
fi
if [ ! -z "$waitp" ]; then
    while [ ! -e "$serverdir/$name" ]; do sleep 0.1; done
fi

这是 galilette@Linuxsir 提议使用 dtach 的脚本。

#!/bin/bash
# Usage: preload-emacs <name> [<waitp>]
#
# Preloads the Emacs instance called NAME in a detached screen
# session. Does nothing if the instance is already running. If WAITP
# is non-empty, the function waits until the server starts up and
# creates its socket; otherwise it returns immediately.

name="$1"
waitp="$2"
dtachdir=~/.dtach_socks #pick up your own
serverdir="/tmp/emacs$UID"
emacs="/usr/local/bin/emacs" # Or wherever you installed your multi-tty Emacs

if [ -z "$name" ]; then
    echo "Usage: preload_emacs <name> [<waitp>]" >&2
    exit 1
fi

if [ ! -e "$dtachdir"/"$name" ]; then
    if [ -e "$serverdir/$name" ]; then
# Delete leftover socket (for the wait option)
        rm "$serverdir/$name"
    fi
    dtach -n "$dtachdir"/"$name" "$emacs" -nw --no-splash --eval "(setq server-name \"$name\")" -f server-start
fi
if [ ! -z "$waitp" ]; then
    while [ ! -e "$serverdir/$name" ]; do sleep 0.1; done
fi

然后是 connect-emacs

#!/bin/bash
# Usage: connect-emacs <name> <args>...
#
# Connects to the Emacs instance called NAME. Starts up the instance
# if it is not already running. The rest of the arguments are passed
# to emacsclient.

name="$1"
shift

if [ -z "$name" ]; then
    echo "Usage: connect_emacs <name> <args>..." >&2
    exit 1
fi
preload-emacs "$name" wait
/usr/local/bin/emacsclient -s "$name" "$@"

然后分别是eet

#!/bin/bash
connect-emacs editor $@
#!/bin/bash
connect-emacs editor -t $@

在把 EDITOR 环境变量设置成 et 就可以了。

配合窗口管理器

有很多可定制性很高的窗口管理器,比如 fvwmSawfish 之类的,可以写一个 脚本,调用 emacsclient 的同时叫窗口管理器切换到 Emacs 窗口处,就非常方 便了,使用 Sawfish 的一个例子可以在这里找到。

Footnote

  1. 有关 emacs 的 server 模式的更多内容,请参见 Emacs 的手册。
  2. emacs multi-tty 的扩展主页在这里。
  3. 关于此的详细内容请参见 elisp 的手册: C-h i m elisp RET m Pure Storage RET 。
  4. 注意这儿要选择 --without-gtk ,因为作者说了,目前对于编译为 gtk 的 模式还有问题,不过 x-toolkit 用什么都无所谓吧,因为平时使用的时候 用到 x-toolkit 的东西并不多嘛。
  5. 当我在 Sawfish 里面直接调用(例如使用 run-shell-command) dtach 的时 候,dtach 会报错,说“tcgetattr: inappropriate ioctl for device” , 应该是没有通过一个真正的终端来运行而造成的原因吧。因为我总是使用 Sawfish 的 jump-or-exec 来调用我常用的程序,而且我平时也一直在使用 Screen ,所以我还是使用Screen 的那个脚本而不是 dtach 的那个。
posted @ 2016-12-23 10:30  风在山路吹  阅读(298)  评论(0编辑  收藏  举报