使用el-get管理emacs包

el-get是emacs的一个包管理器。你可以把它当作是emacs的synaptic、yum或者pacman,功能强大,用起来也十分方便。通过它你可以安装和管理各种elisp的包。对于我来说,el-get最大的功能在于,当你有多台机器时,仅仅需要一个.emacs文件就可以保证多个机器上的elisp包一致,而不是每个机器都需要手动管理。想想看,没有el-get的话,当你重装系统之后需要花多少时间来安装各种elisp包吧。有了el-get之后,只要一个.emacs文件,当你第一次打开emacs的时候,各种包已经开始默默的下载和安装了,完全不用你操心。这是一件多么美好的事啊。

el-get对软件包的描述放在recipe文件中,包括安装方式、url、安装完之后的操作,以及软件包的基本配置。也就是说当你用el-get安装完某个包之后,自己的.emacs文件基本上不用修改,新的包就可以用了。el-get支持多种安装方式,可以直接从github clone,也可以从指定的url下载回来然后解压,另外还支持ELPA,cvs,bzr,apt-get,pacman等等。最强大的地方在于你可以自己定义recipe,如果默认的recipe文件中没有你需要的包,那么你完全可以自己写一个。如果你在github上面fork了el-get,可以给作者提交pull request,请求将自己定义的recipe加入默认的recipe中。这样如果下次有别人需要用到这个包,你的recipe就派上用场了。

安装el-get非常简单,只要打开你的emacs,切换到scratch buffer,复制下面这段代码,然后在最后一个括号后面C-j就可以了。
[ccb_lisp]
(url-retrieve
“https://raw.github.com/dimitri/el-get/master/el-get-install.el”
(lambda (s)
(let (el-get-master-branch)
(goto-char (point-max))
(eval-print-last-sexp))))
[/ccb_lisp]

安装好el-get后,配置文件里面加入下面的内容
[ccb_lisp]
(setq
el-get-sources
‘((:name asciidoc
:type elpa
:after (progn
(autoload ‘doc-mode “doc-mode” nil t)
(add-to-list ‘auto-mode-alist ‘(“\.adoc$” . doc-mode))
(add-hook ‘doc-mode-hook ‘(progn
(turn-on-auto-fill)
(require ‘asciidoc)))))

(:name buffer-move ; have to add your own keys
:after (progn
(global-set-key (kbd ““) ‘buf-move-up)
(global-set-key (kbd ““) ‘buf-move-down)
(global-set-key (kbd ““) ‘buf-move-left)
(global-set-key (kbd ““) ‘buf-move-right)))

(:name smex ; a better (ido like) M-x
:after (progn
(setq smex-save-file “~/.emacs.d/.smex-items”)
(global-set-key (kbd “M-x”) ‘smex)
(global-set-key (kbd “M-X”) ‘smex-major-mode-commands)))

(:name lisppaste :type elpa)))

(setq my-packages
(append
‘(cssh el-get switch-window escreen vkill xcscope color-theme color-theme-railscasts color-theme-tomorrow yasnippet python-mode python-pep8 pymacs rope ropemacs ropemode pylookup haskell-mode anything helm emacs-w3m auto-complete browse-kill-ring sr-speedbar session popup markdown-mode xml-rpc-el)
(mapcar ‘el-get-source-name el-get-sources)))

(el-get ‘sync my-packages)
[/ccb_lisp]
上面的el-get-sources变量是自定义的recipe,my-packages则是需要安装的包。只要把包的名字写在my-packages里面,下次启动emacs的时候el-get就会自动安装。

使用el-get就是这么简单。但是在使用的过程中发现el-get还有些不完美的地方。比如用el-get安装color-theme这个插件的时候,总会提示下载的color-theme.tar.gz无法解压。经过一番调查发现原来是el-get的http-method有问题。el-get下载的color-theme.tar.gz总会比用wget下载的少几个字节。http-method的实现是先用url-retrieve把文件拉到当前的buffer中,再用write-file将当前buffer的内容写入文件。问题就出在write-file这里。write-file默认会对buffer进行一些编码的转换,结果导致丢掉了几个字节。修改的方法也很简单,只要将write-file替换为write-region即可。发现这个bug之后在github上给作者提交了pull request,已经被合并了。之后再有人用el-get就不会碰到这个问题了。

学习elisp

对我来说,Emacs已经成为日常用的最多的编辑器了,vi则只有在ssh的时候才会用到。不过emacs可是很需要调教的,如果没有好好配置,基本上处于不可用的状态。关于目前使用的emacs配置,改天会再详细写出来。今天只是分享一个自己写的函数。

我很庆幸,现在的我能够沉下心来去研究elisp这么神奇的语言。虽然elisp的用途很狭隘,但它绝对会对提升你的生产力产生巨大的帮助。emacs我用了很久,大概跟我用linux的时间一样长。但是从2012年开始我才算真正入了emacs的门。以前只是在网上搜罗各种配置文件,安装各种插件。但是配置却看不懂,做不到自己定制,只是简单的依葫芦画瓢。配置不适用也不知道该如何下手解决。

随着使用的深入,现在慢慢学会了如何解决遇到的emacs问题。搞定了以前一直很想解决的bug。有些bug,其实是emacs的某些feature没有配置好。比如之前python-mode中有时出现C-x C-f会卡死的情况,最后发现原来是网上广泛流传的python-mode配置中[ccib_lisp](setq ido-use-filename-at-point ‘guess)[/ccib_lisp]这一句,导致打开文件的时候会调用python-mode-path函数。只要把这句注释掉即可。再比如python-mode中M-b的跳转总是不正确,在其他的major mode中M-b总是会把“[ccib_lisp]_[/ccib_lisp]”当作单词的分隔符,但python-mode中却不会。这点实际使用中会造成很大的困扰,因为不仅和其他的major mode行为不一致,即便在python-mode中M-b和M-f的行为也不一致。后来到python-mode的项目主页上准备提交这个bug,结果发现已经有人提过了,原因是“[ccib_lisp]_[/ccib_lisp]”在python-mode的syntax table中是属于word类而不是symbol类。现在python-mode中已经有了一个自定义的变量[ccib_lisp]py-underscore-word-syntax-p[/ccib_lisp],只要把此变量的值设为nil即可。

解决了前面的几个bug之后,开始想自定义几个函数已满足自己的需求。以前用惯了vim的yy复制一行的功能,现在emacs里面没有,非常的不适应,这个操作如果自己做,需要按太多次键盘。先要C-a跳到行首,再C-spc设置标记,再C-e跳到行尾。于是开始翻阅elisp的文档。发现elisp的文档写的真是太人性化了,目录编排尤其合理,即便是我这种从来没用过的人也可以对着目录找到自己所需要的函数或者变量。下面是复制一行的函数
[ccb_lisp]
;;copy line
(defun copy-line ()
(interactive)
(kill-ring-save (save-excursion
(back-to-indentation)
(point))
(line-end-position))
(message “line copied”))
(global-set-key “C-cC-y” ‘copy-line)[/ccb_lisp]
实现起来很简单,[ccib_lisp]kill-ring-save[/ccib_lisp]的描述是“Save the region as if killed, but don’t kill it”,即我们通常理解的“复制”。这个函数会接受两个参数,待复制区域的起始和结束位置。[ccib_lisp]save-excursion[/ccib_lisp]的作用是再执行完函数参数内的操作后,把光标移动到执行之前的位置。[ccib_lisp]save-excursion[/ccib_lisp]这段的作用是获得行的起始位置,略去前面的缩进。[ccib_lisp]line-end-position[/ccib_lisp]很明显就是获得行的结束位置。这样就实现了复制一行的功能,再把这个函数绑定一个快捷键C-c C-y即可。

现在终于体会到了emacs的强大。emacs的各种插件还不足以让他成为神器,最强大的地方在与用户可以很容易的自己定制所需要的功能,而不用依赖于别人开发的插件。难怪有人说emacs是伪装成编辑器的操作系统了。