随着Emacs的插件越来越多,Emacs的启动速度会越来越幔。
Emacs的启动速度慢,主要有两个原因:
- 加载时垃圾回收的阈值太小了,导致启动加载插件时触发了垃圾回收,减慢了启动速度
- 默认Emacs加载了过多的插件,导致启动的时候浪费了过多的时间去加载插件
解决第一个问题的方法如下:
(let (;; 加载的时候临时增大`gc-cons-threshold'以加速启动速度。
(gc-cons-threshold most-positive-fixnum)
;; 清空避免加载远程文件的时候分析文件。
(file-name-handler-alist nil))
;; Emacs配置文件内容写到下面.
)
上面的代码的目的时,在Emacs加载任何插件之前临时把 gc-cons-threshold 的值设置为最大,避免Emacs启动时触发垃圾回收。 Emacs配置文件加载完毕后,自动恢复变量 gc-cons-threshold 为默认值,避免运行时Emacs占用过多内存。
至于第二个问题的解决方案,就要用到今天我编写的 lazy-load.el 插件了。
2007 ~ 2008这两年期间,我几乎把当时所有的Emacs插件都玩过一遍,当你把几百个插件一股脑的全部默认加载,Emacs的启动时间可以从秒开延长到几分钟。 那时候就在思考怎么把Emacs的启动时间优化到秒开,同时不减少任何插件的使用,最终开发了 lazy-load.el 插件,即使我用 300+ 插件,Emacs启动速度依然是秒开。
原理
lazy-load.el 的原理很简单:
- 我们先把我们的 keymap 定义好,每个按键对应的函数都写好
- 告诉Emacs函数对应插件的文件名,这样当调用函数时,Emacs知道去哪里加载插件
- Emacs默认只加载非常少的插件, 加载完成后,当我们第一次触发按键时才让Emacs去动态按需加载插件和按键对应的函数
因为99%的Emacs插件在单独加载的时候,都可以在1s之内完成,所以相当于99%的插件都在运行时按需加载, 这样就大大减少了Emacs启动时需要加载的插件数量,从而最终达到提升Emacs启动时间的目的。
安装方法
- 下载 lazy-load 里面的 lazy-load.el 放到 ~/elisp 目录
- 把下面的配置加入到 ~/.emacs 中
(add-to-list 'load-path (expand-file-name "~/elisp"))
(require 'lazy-load)
使用方法
下面这段代码的意思是,第一次按 Alt + g 时,Emacs在 load-path 目录下去找 goto-line-preview.el 这个文件,加载插件并执行 goto-line-preview 这个函数。
(lazy-load-global-keys
'(("M-g" . goto-line-preview))
"goto-line-preview")
下面这段代码的意思是,第一次按在 ruby mode 中按 Ctrl + c t 时,Emacs在 load-path 目录下去找 ruby-extension.el 这个文件,加载插件并执行 ruby-hash-syntax-toggle 这个函数。
(lazy-load-local-keys
'(("C-c t" . ruby-hash-syntax-toggle))
ruby-mode-map
"ruby-extension")
很多全局按键默认已经被Emacs占用了,必须先卸载以后才能重新绑定这些全局按键,比如 Ctrl + x, 下面这段代码就是用 lazy-load-unset-keys 卸载默认绑定的全局按键:
(lazy-load-unset-keys '("C-x C-f" "C-z" "C-q" "s-W" "s-z" "M-h" "C-x C-c" "C-\\" "s-c" "s-x" "s-v"))
高级用法
有时候,我们会用一个前缀按键取分类插件中不同的函数,比如我的 sdcv.el 插件的不同函数就可以按照下面的代码用 Ctrl + z 这个按键作为前缀按键, 先按 Ctrl + z ,再按 p 就可以触发 sdcv-search-pointer 函数
(lazy-load-global-keys
'(("p" . sdcv-search-pointer)
("y" . sdcv-search-pointer+)
("i" . sdcv-search-input)
(";" . sdcv-search-input+))
"init-sdcv"
"C-z")
对应的 lazy-load-local-keys 也支持最后一个参数传递前缀按键,只不过 lazy-load-local-keys 对应的不是 global-map ,而是插件的 keymap 。
如果Emacs默认就加载了某个插件,而不需要在运行时动态加载,也可以使用 lazy-load-set-keys 函数做单独的按键绑定操作,不用手动写一行行的重复写类似 (define-key keymap key) 的配置
(lazy-load-set-keys
'(("M-;" . comment-dwim-with-haskell-style))
haskell-mode-map)