Categories

Calendar

October 2017
M T W T F S S
« Jun    
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

ELPA: Emacs Lisp Package Archive

EmacsTeX 有 CTAN,Perl 有 CPAN,Python 有 PyPI 和 easy_install (虽然好像至今还不支持自动 uninstall),Ruby 有 RubyForge 和 gem ,诸如 Eclipse 、NetBeans、Firefox 这样的大型软件都有方便的插件/扩展查找和自动安装的功能,更别说各大流行的 Linux 发行版所带的那些包管理器了。然而号称具有无穷可扩展性的超强编辑器:GNU Emacs ,虽然确实具有无数的扩展,但是这些扩展往往各式各样、散落各地,并且正是由于这无穷的扩展性,让各个扩展的安装定制方式千奇百怪,很难统一在一起。我想这也是 Emacs 长久以来一直没有统一的扩展管理的原因之一吧。

不过一直被人们说成不“Modern”的 Emacs 近年来也确实有发愤图强,添加了 GTK 界面的支持,新的编码系统,对 XFT 的支持等等。而 EmacsWiki 的兴起也终于让大部分的 Emacs 相关的信息有了一个统一的汇集地,大部分的扩展都可以在上面找到相关的下载和安装指南。不过这离自动管理还有一定的距离。不过,再后来,我们终于有了 ELPA (Emacs Lisp Package Archive)

ELPA 是一个集中存放 Emacs Lisp Package 的地方,它同时还提供了一个工具可以自动查找、安装和卸载在 ELPA 中注册的 Package 。实际上,正像前面说的那样,Emacs 的扩展 Package 可以说是各式各样,仅仅要把它们搜集到一起就已经很不容易了,更别说提供全自动的安装和卸载功能了。但是最难的还是要有人去做这个事情吧。一旦有人发起了,建立了一个平台,后面的工作主要由各个扩展的作者将自己的代码按照 ELPA 的规范定制一下并添加到 ELPA 中去。这也是我在这里宣传 ELPA 的原因,让更多人知道这个平台,让它逐渐丰富完善起来。

实际上,现在的 ELPA 中已经包含了诸如 emmsMuse 以及 nxml 等 80 多个扩展。当然,这个数目实在是不多,不过也正是如此,才需要大家去加以完善。现在 ELPA 提供的功能也比较简单。打开 Emacs ,到它的主页上,把那段代码复制到 Emacs 中 eval 一下就算 ELPA 安装好了。

之后 M-x pakcage-list-packages 就可以查看所有的 Package 列表了,操作方式和 dired 类似,按 i 标记为安装,d 标记为卸载,u 取消标记,x 是执行。在这里安装的扩展,下次重启 Emacs 的时候就会有了。如果检查 ~/.emacs 的话,会发现它添加了这样一段:

;;; This was installed by package-install.el.
;;; This provides support for the package system and
;;; interfacing with ELPA, the package archive.
;;; Move this code earlier if you want to reference
;;; packages in your .emacs.
(when
    (load
     (expand-file-name "~/.emacs.d/elpa/package.el"))
  (package-initialize))

ELPA 会在 package-initialize 中加载安装的扩展,如果要在扩展加载之前或者之后做一些定制的话,写到那段代码之前或之后就可以了。这也是 ELPA 有待完善的地方,并不能方便地直接对扩展做一些简单的定制。其实 Emacs 本身已经提供了很强大的“不用写 elisp 代码”的定制方式,就是 customize- 开头的那一堆函数,如下图所示:

emacs-customize

不过可惜的是有不少扩展的作者(比如我 :p )都偷懒没有提供支持。不过总的来说,ELPA 也算是一个好的开始,希望它能发展壮大,让以后的 Emacser 们能更方便地安装和管理各种扩展。所以,如果你是某个 Emacs 扩展的作者或者维护人员,抽个空把你的扩展加到 ELPA 的索引中去吧。它的文档页面关于添加的扩展要符合什么样的约定写得不是特别清楚,可以直接看 package.el 前面的注释。

下面我大致总结一下单文件的扩展需要遵循的一些约定:首先,文件的开始和结束要按照 Elisp 的规范标记出来,并且头部要包含必要的 header 信息,拿 yasnippet.el 来做个例子,整个文件的结构大致上是这个样子:

;;; yasnippet.el --- Yet another snippet extension for Emacs.
 
;; Copyright 2008 pluskid
 
;; Author: pluskid <pluskid@gmail.com>
;; Created: 02 Mar 2008
;; Version: 0.5.9
;; Keywords: snippet, textmate
;; URL: http://code.google.com/p/yasnippet/
;; EmacsWiki: YaSnippetMode
 
;; <<licence here snipped>>
 
;;; Commentary:
 
;; <<usages here snipped>>
 
;;; Code:
 
;; <<codes here snipped>>
 
;;; yasnippet.el ends here

其次通常扩展并不会在 Emacs 启动的时候一股脑加载进来,最常见的扩展通常是各种 major mode ,比如 css-mode ,它在 Emacs 启动的时候会做两件事:

  • 让 Emacs 知道有 css-mode 这个函数的存在。
  • css-mode 加入到 auto-mode-alist 中,这样在打开 css 文件的时候能自动调用 css-mode

第一件事情由 autoload 来完成,你只要在代码中定义要实现 autoload 的函数之前写上这样的注释:

;;;###autoload
(defun css-mode ()

ELPA 就会自动为其生成相应的 autoload 代码,而为了完成第二件事情,我们用类似的 magic comment 来告知 ELPA :

;;;###autoload(add-to-list 'auto-mode-alist '("\\.css\\'" . css-mode))

这样,ELPA 为为其生成相应的 autoload 文件,包含下面的内容:

(add-to-list 'auto-mode-alist '("\\.css\\'" . css-mode))
 
(autoload 'css-mode "css-mode" "\
Major mode for editing CSS source code.
 
Key bindings:
 
\\{css-mode-map}
 
\(fn)" t nil)

在 Emacs 启动的时候实际上只有这个文件被加载了,css-mode 被添加到 auto-mode-alist 中,但是如果你没有打开过 css 文件的话,css-mode 的实际的代码是不会被加载的。当第一次打开 css-mode 的时候,Emacs 注意到这是一个 autoload 函数,就会去加载相应的文件,得到函数的完整定义,这实际上是一个 lazy loading 的过程。

另外,如果你需要在本地测试自己的扩展是否和 ELPA 兼容的话,只要用 ELPA 的 package-install-file 命令即可。

实际上之前 ELPA 的作者曾经和我联系过把 YASnippet 加入到其中的问题,不过之前我实在是特别忙,而且也没有把 autoload 搞得太明白,就一直拖了很久,现在又有人提出来,我终于动工添加了支持。yasnippet.el 虽然是一个单独的文件,但是仅有这个东西实际上没什么用处(因为没有任何预定义的 snippet),但是如果要提供 tar ball 的话,好像改动会比较复杂一点,所以我决定把 yasnippet-bundle.el 加入到 ELPA 中。YASnippet 默认情况下是全局打开的,不存在 lazy-loading 的问题,所以除了一些规范性的修改之外,我直接在 bundle 中加入了下面这一句 comment :

;;;###autoload(require 'yasnippet-bundle)

就可以了,因为 YASnippet 本身就是做得(对于不需要定制的用户来说)尽量全自动的。目前正在和 ELPA 的作者交涉,不出什么意外的话,下一个版本的 yasnippet-bundle 就可以直接通过 ELPA 进行安装了。当然如果要使用 tarball 的话,还是要自己去下载安装的,虽然其实也不是很麻烦。 :p

9 comments to ELPA: Emacs Lisp Package Archive

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>