Bob Glickstein O’REILLY
献给我的父母, 如果没有他们…… 好吧,我宁愿不去想这件事。
在你能够扩展Emacs之前,它已经是世界上功能最强大的文本编辑器了。它不仅能满足你平常所能想到的一切需求(段落排版,行居中对齐,正则搜索,将一整块文本设置为大写),不仅是它具有很多高级的特性(源代码中的括号匹配跳转,语法高亮,以及每个键位以及其他命令的在线帮助),而且它还具有许许多多你连做梦都想不到的特性。你可以使用Emacs来阅读和编写email以及浏览网页;你可以在里面使用FTP来自由的编写远程文件;你可以让它提醒你即将到来的会议、约会以及纪念日。假如这还不够的话,Emacs还可以陪你玩五子棋(大多数情况下它会赢);它可以告诉你今天是玛雅历的哪一天;它甚至还能分解质因数。
看上去Emacs用户花费这么多时间来做出如此多种多样的功能简直是疯了。大多数程序员将文本编辑器看成是编写其他软件的工具;为什么要花费这么多时间来改变编辑器本身呢?木匠不会耗费精力改造自己的锤子;管钳工不会耗费时间改造自己的钳子;他们只是使用他们的工具来完成自己手头的工作而已。Emacs用户为什么要不同呢?
答案是如果木匠和管钳工知道如何使自己的工具变得更好用的话,他们也会这么做。谁比他们自己更明白自己需要什么样的工具呢?但他们毕竟不是工具制作专家。另一方面,Emacs是一种特殊的工具:它是软件,它和使用它编写的软件并没有什么本质上的不同。Emacs的用户通常是程序员,而编写Emacs其实也就是编程。Emacs用户完全可以做自己的工具专家。
这本书将使用一系列的实例由浅入深的教给你如何编写Emacs Lisp。我们将以向Emacs启动配置文件中添加简单的配置作为开始,在最后我们将会着手编写“主模式(major modes)”以及修改Emacs自己的“命令循环(command loop)”。在这个过程中我们将会学到变量,键位表,交互式命令,buffers,窗口,处理I/O等。本书中所提到的Emacs特指GNU Emacs。有许多编辑器自称为Emacs。以下是权威的On-line Hacker Jargon File(version 4.0.0, 24-Jul-1996)所叙述的一点历史:
[Emacs] was originally written by Richard Stallman in TECO under ITS at the MIT Al lab; AI Memo
554 described it as "an advanced, self-documenting, customizable, extensible real-time display
editor." It has since been re-implemented any number of times, by various hackers, and versions exist
that run under most major operating systems. Perhaps the most widely used version, also written by
Stallman and now called "GNU EMACS" or GNUMACS, runs principally under UNIX. It includes
facilities to run compilation subprocesses and send and receive mail; many hackers spend up to 80%
of their tube time inside it. Other variants include GOSMACS, CCA EMACS, UniPress EMACS,
Montgomery EMACS, jove, epsilon, and MicroEMACS.
书中的示例全部在GNU Emacs 19.34以及20.1版本的一个预发行版本上编写以及测试通过。参看附录E,获取从哪里找到Emacs版本的信息。
我以自身使用Emacs的开发经历作为书中示例选择的指导。书中的示例实际上讲述了我自己的Emacs使用经历的演变。例如,我在最初使用Emacs的时候就知道一定要让该死的*BACKSPACE*键不要触发在线帮助!也许你也有这个问题。解决这个问题将作为下一章的第一个例子。
在我使用了Emacs一小段时间之后,我发现自己需要许多处理光标移动的快捷键。就我所知,使用Emacs提供的原生功能就可以轻松对其定制。我们将会在第二章中看到一些这样的例子。这之后我需要一种方法来避免我经常遇到的输入错误:我想要按下*CONTROL-b*,但实际上常常按下的却是*CONTROL-v*。我本想让光标向左移动一点,却向下移动了好几屏。在第三章中你将会看到这也很容易进行优化。当我开始处理记录着很多巧妙的谚语的文件时,我需要特定的工具来处理特定格式的文件。我们将会在第九章中看到一些这样的例子。
除了每章开始解决问题时提出的最初的例子之外,我们还会看到一些别的简单例子,每个例子都有自己的章节。每个章节都会提出一些需要使用Emacs Lisp解决的问题,然后展示出一个或一些方法来解决这些问题。然后,就像现实中的扩展都要变得更实用、更通用,我们通常会在前往下一个主题前对其进行一到两次改进。
每个例子都基于前面的例子,并且带入一些自己的新东西。在本书的最后,我们将覆盖大部分Emacs Lisp编程的概念并且讨论如何使用在线文档和其他信息来帮你更快的使用Emacs Lisp来满足你自己的需求。俗话说得好:授人以鱼不如授人以渔。
这本书假设你熟悉编程并且正在使用Emacs。如果你熟悉Lisp编程语言中的一些方言(Emacs Lisp也是其中一种)将会有帮助,但不是必要。通过我们每个章节中使用的例子,Lisp编程的要领将会很快很容易的理清。你也可以参考附录B,它简要的描述了Lisp的基本知识。
如果你不熟悉Emacs的基本概念,请阅读Debra Cameron,Bill Rosenblatt,和Eric Raymond所写的《Learning GNU Emacs, 2nd edition》。你也可以使用Emacs自带的在线帮助,特别是info手册,也就是《The GNU Emacs Manual》。如果你希望更全面的理解Lisp编程,我推荐阅读David Touretzky的《Common Lisp: A Gentle Introduction to Symbolic Computation》。
本书不是Emacs Lisp的参考手册;实际上也并没有特别深入的讲解语言方面的知识。主题的选择更倾向于更有教学意义而不是涵盖所有范畴。在阅读时最好以从前往后的顺序阅读以得到最好的效果。自由软件基金会发布的《The GNU Emacs Lisp Reference Manual》是这方面的权威。它有多种印刷本和电子版;详情参见附录E。
认为Emacs仅仅是一个可编程的文本编辑器是完全错误的。同样的说它是C语言编辑器也是不对的。虽然看起来很较真,但实际上编写C语言和编写文本是两种完全不同的工作,Emacs通过变成两个不同的编辑器来包容这种差异。当编写代码时,你不会关心段落结构。当编写文本时,你不会关心自动缩进。
Emacs同时也是一个Lisp代码编辑器。它也是16进制数据文件的编辑器。它也可以作为大纲的编辑器。它也可以作为文件目录的编辑器,压缩文件的编辑器,email的编辑器等等。每一种编辑器都是一种Emacs的模式(mode),即一系列将Emacs的原生要素和行为组合起来以实现新特性的Lisp代码。因此每个模式也就是Emacs的一种扩展,也就是说如果你把这些模式都除掉的话–删掉所有扩展并且只剩下Emacs的核心–那么你就根本没有了任何的编辑器;你只剩下制作编辑器的原材料。你只剩下了编辑器生成器(editor-builder)。
你能用编辑器生成器生成什么呢?当然是编辑器了,但是什么是编辑器呢?编辑器就是一个用来展示和修改某种数据,以及用来帮助与这些数据更友好的进行交互的程序。当编辑文本文件时,规则很简单:每个可见字符按照顺序展示出来,换行符执行换行;一个光标用来表示用户的下一个操作将会发生在数据的什么位置。当编辑目录时就不是那么直观了–路径文件中的数据必须先转换成可读的格式–最终的交互流程要看起来比较人性化。
这个关于编辑器的定义几乎涵盖了所有交互程序的范畴,而这绝非偶然。交互程序总是用来处理某种数据的编辑器。因此可以说,Emacs在广义上,是一种交互程序的生成器。它是一个UI工具包!就像很多好的工具包一样,Emacs提供了一套UI组件,一套操作它们的方法,一个事件循环,一套成熟的I/O机制,以及一种用来把它们整合起来的程序语言。UI组件看起来可能不如X11,Windows或者Macintosh所提供的那样漂亮,但是就像Emacs程序员所发现的,一个超级漂亮的图形工具集往往是多余的。99%的程序都是文本形式的,不管是数字列表,菜单项,或者填字游戏里的单词(参考第十章所展示的例子)。对于这些程序,Emacs在功能性、精巧性、简单性以及性能上都要优于其他。
“为什么Emacs用户不同?”,这个问题的真正答案并不仅仅是他们花费时间在改造他们的工具上。他们在使用Emacs来达到自己所期望的目的:创造出无穷无尽的新工具(a universe of new tools)。
书中的每章都基于前一章。我建议你从前往后顺序读这本书;这样的话里面的所有安排就都变得有意义了。
- 第1章 介绍一些你可以对Emacs做出的基本修改。这也会使你熟悉Emacs Lisp,如何对Lisp表达式求值,以及那会如何改变Emacs的行为。
- 第2章 教给你如何编写和安装Lisp函数来使其正确执行。钩子和一种称为修饰的特性将会被引入。
- 第3章 如何在不同函数调用间保存信息以及如何使多组函数共同工作–这是编写系统而不仅仅是编写命令的第一步。符号属性和标记将会在这中间被介绍。
- 第4章 展示一些你极有可能会经常用到的技术:用来改变当前buffer和其中字符串的方法。正则表达式会被介绍。
- 第5章 讨论加载、自动加载以及包的概念,这些特性会在你创建大量相关函数时用到。
- 第6章 加入一些关于Lisp重要特性的背景知识。
- 第7章 展示如何将相关函数和变量组装进称为“子模式”的包里。这个章节中的核心例子是使Emacs中的段落格式化功能工作的更像一个正常的文本处理软件。
- 第8章 展示Emacs Lisp解释器的灵活性,如何控制在何时执行什么,以及如何编写不受运行时错误影响的代码。
- 第9章 解释子、主模式间的差别,并且为后者提供一个简单的例子:一个专门用来处理谚语文件的主模式。
- 第10章 定义一个完全改变Emacs默认行为的主模式–一个填字游戏谜题编辑器,通过它向你展示Emacs对于开发文本相关的应用是多么灵活。
- 附录B 对Lisp的语法,数据类型以及控制结构提供了一个实用的介绍。
- 附录C 描述了可以用来追踪你的Emacs Lisp代码中问题的工具。
- 附录D 解释了把代码分享给别人时需要遵循的步骤。
- 附录E 概述了如何在你的系统上得到一个可用的Emacs版本。
通过浏览器,你可以获取到示例: ftp://ftp.oreilly.com/published/oreilly/nutshell/emacs_extensions
要使用FTP,你需要一台能直接访问网络的电脑。下面是一个例子,你需要输入的是其中粗体的部分:
% ftp ftp.oreilly.com Connected to ftp.oreilly.com. 220 FTP server (Version 6.21 Tue Mar 10 22:09:55 EST 1992) ready.
Name (ftp.oreilly.com:yourname): anonymous 331 Guest login ok, send domain style e-mail address as password. Password: yournameayourhost.com (use your user name and host here) 230 Guest login ok, access restrictions apply. ftp> cd /published/oreilly/nutshell/emacsextensions 250 CWD command successful. ftp> binary (Very important! You must specify binary transfer for
gzipped files.) 200 Type set to I. ftp> get examples.tar.gz 200 PORT command successful. 150 Opening BINARY mode data connection for examples.tar.gz. 226 Transfer complete.
ftp> quit 221 Goodbye.
文件格式为gzipped tar归档;输入下面的指令展开它:
% gzip -dc examples.tar.gz | tar -xvf -
System V 系统需要下面的tar指令:
% gzip -dc examples.tar.gz | tar -xvof -
如果gzip在你的系统上不存在,那么单独使用uncompress以及tar指令。
% uncompress examples.tar.gz
% tar xvf examples.tar
感谢Nathaniel Borenstein,他帮助我驱散了对于C的执念并且教会了我欣赏这个世界上多姿多彩的编程语言。
感谢Richard Stallman编写了Emacs–两次–他提出的令人惊奇的言论是对的:黑客编写更好的代码是为了满足自己而并非为了钱。
感谢Mike McInerny,他固执的坚持使我开始使用GNU Emacs–即使开始的几次我都认为这并不值得我花时间。
感谢Ben Liblit提供的想法,代码以及对于我的Defer包(本书中的一章,直到Emacs有了自己的功能相同的包,timer)的bug修正。其他的帮助来自于Simon Marshal,他在他的defer-lock中使用并且改进了很多其中的想法。Hi,Si。
感谢Linda Branagan向我展示了即使像我这样一个平凡的人也能写书。(她当然并不平凡;一点也不。)
感谢Emily Cox和Henry Rathvon提供的对于填字游戏谜题的一些内行知识。
感谢对于本书的早期草稿做出校对和建议的朋友们:Julie Epelboim,Greg Fox,David Hartmann,Bart Schaefer,Ellen Siever,以及Steve Webster。
感谢Zanshin Inc.以及Internet Movie Database允许我在这些工程和这本书之间分配我的工作精力。
感谢编辑,Andy Oram,能够灵活地应对我上面提到的这种杂乱无章的工作。
感谢Alex,我的狗,在我写这本书的大部分过程中都在我的脚边开心地打转。
最重要的是,感谢Andrea Dougherty,她鼓励着我,支持着我,做出了无数的牺牲,提供了数不清的服务,在我需要的时候给我陪伴并且在我需要独处的时候离开(而不是反过来),并且在其他所有方面都对我和这本书有益:这一定是爱。