Emacs 宏和 Power-Macros 包
人们有时容易忘记,计算机是能够让他们的生活变得更轻松的工具。计算机尤其擅长,并且很容易教会它们做的一件事就是单调、重复性的工作。更棒的是,这类工作似乎也是人类最不擅长做的;也就是说,单调、重复性的工作往往非常容易出错。Emacs 可以通过一个非常有用的概念,称为宏,来消除重复性的工作。宏基本上就是 Emacs 为您键入的按键序列。
本文将介绍 Emacs 宏,并展示一些有用的示例。此外,它还将讨论我编写的一个 Emacs 包,名为 power-macros,它可以非常容易地将宏绑定到按键,并将其保存到文件中,以便在以后的 Emacs 会话中使用。
定义 Emacs 宏是通过按下 CTRL-x ( 来完成的。也就是说,按下 CTRL 键并保持按下,然后按下 x 键,释放两个键,然后按下左括号。随后的按键将成为您宏的一部分;也就是说,当您要求 Emacs 执行您的宏时,这些按键将被为您键入。当您完成宏的定义后,按下 CTRL-x )。
当宏被定义后,您可以通过简单地按下 CTRL-x e 来要求 Emacs 尽可能多次地模仿您的按键。
如果您需要多次重复一个宏,那么必须按下两个键来执行它可能会很烦人。一个解决方案是将 “execute-last-defined-keyboard macro” 命令绑定到一个单独的按键。例如,您可以通过将以下代码插入到您的 .emacs 文件中,将此命令绑定到 SHIFT-F1
(global-set-key [(shift f1)] 'call-last-kbd-macro)
这些是宏的基础知识。我相当肯定您还没有感觉到这会给您的世界带来多大的改变,对吧?因此,这里有一个小例子来激起您的兴趣。稍后会有更多内容。
想象一下,您经常想要将当前单词加粗。在 HTML 文档中,您可以通过简单地在单词周围插入 <b> 和 </b> 来做到这一点。这不算什么大工程,但如果您正在校对一本书,并且每小时需要将单词加粗数百次,那么一个执行此操作的宏可以为您节省大量时间。
宏很容易录制:按下 CTRL-x (,移动到单词的开头,键入 <b>,移动到单词的结尾,键入 </b>,CTRL-x ),然后在文档中您希望加粗的每个单词的开头按下 CTRL-x e。
关于这一点,有一个非常重要的注意事项:您不能通过多次按下箭头键来移动到单词的开头或结尾!为什么不能?嗯,如果您这样做,那么当您的单词长度与定义宏时使用的单词长度不同时,宏将无法找到单词的边界。您必须改用 forward-word 和 backward-word 命令。这些命令绑定到 CTRL 键和箭头键。因此,要移动到单词的结尾,只需按下 CTRL 键和右箭头键。
基本上,宏有两种:一种是不经常使用的宏,另一种是连续使用多次然后永远不再使用的宏。“将单词加粗” 示例是第一种宏。第二种宏的描述超出了本文的范围,但一个例子可能是向行的开头添加 /* REMOVE:,并向行的结尾添加 */ 的宏。您可能会连续多次使用这样的宏来注释掉 C 语言中的整个函数,以便以后删除。
在一些 C++ 程序中,您经常会发现类似于以下结构的构造
for (bool ... }
从一个场合到下一个场合,唯一的区别是名称的集合:cont、iterator、value 以及花括号之间的内容。
如果您经常插入上述代码,您可能希望构建一个宏来帮助您完成此操作。您的第一次尝试可能是定义一个宏,它只是简单地插入
for (bool =.First(); ; =.Next()) { }
也就是说,一个宏,它只是简单地省略所有可能不时更改的部分。然而,这并没有预期的那么有用,仅仅是因为您需要键入 cont 三次,iterator 和 value 各两次。您真正想要的是让 Emacs 询问您要使用哪些名称。您可以使用宏来做到这一点。诀窍称为 “递归编辑”。通过递归编辑,您可以告诉 Emacs 在宏中的特定位置停止,进行一些编辑,并在完成后,告诉 Emacs 继续执行宏。
当您录制宏时,您可以通过按下 CRTL-u CTRL-x q 来告诉 Emacs 进入递归编辑。然后,每当您执行宏时,Emacs 将在该点停止宏的执行,让您进行一些编辑,然后当您按下 CTRL-META-c 时,宏将继续执行。(如果您的键盘上没有 META 键,那么它很可能是 ALT 键。)
当您录制宏时,Emacs 也将在该点进入递归编辑。也就是说,从您按下 CTRL-u CTRL-x q 到您按下 CTRL-META-c 期间所做的编辑不会成为宏的一部分。
我们几乎准备好开发一个简洁而有用的宏了,但首先让我们用一个简单的例子来练习一下我们到目前为止所学到的知识。键入以下内容:CTRL-x ( 键入一个单词 ==> CTRL-u CTRL-x q。
现在键入 Hello World,完成后,继续键入以下内容:CTRL-META-CTRL <== CTRL-x )
上面在您的缓冲区中插入了以下文本
Type a word ==>Hello World<==此外,它还定义了一个宏,该宏插入此文本,除了单词 “Hello World”。每当您执行刚刚定义的宏时,Emacs 将在插入 Type a word ==> 后暂停,当您按下 CTRL-META-c 时,它将继续执行宏,这意味着它将插入文本 <==。
您能看到我们的方向了吗?现在我们有了工具来询问用户所需的三个名称,所以现在我们所需要的只是一种方法来获取他键入的信息,并将其插入到适当的位置。
获取信息可以通过几种方式完成。最简单的方式(即,需要最少的 Emacs 知识的方式)是简单地切换到临时缓冲区,让用户在那里键入信息,并且每当需要其中一个单词时,只需转到此缓冲区并在那里获取它。
一种更聪明的方法是使用寄存器。寄存器是一个容器,您可以在其中保存当前区域的文本以供以后使用。要将文本插入寄存器,请标记一个区域,然后按下 CTRL-x r s 和一个字母(该字母指示要保存信息的寄存器)。稍后,您可以通过按下 CTRL-x r i 并按下您上面键入的字母,将寄存器的内容插入到缓冲区中。
列表 1 显示了录制此宏所需的所有按键。引号之间的文本应按字面意思键入,斜体文本是注释,不应键入。获得此宏似乎需要大量的键入,但另一方面,当您完成时,您将拥有一个非常用户友好的界面来插入给定的 for 循环。
Power Macros 是一个 Emacs 包,是我在因无法定义宏、将其绑定到按键,并在以后的 Emacs 会话中保持绑定(或者更确切地说,无法轻松地做到这一点)而感到沮丧时开发的。
要使用这个 Emacs 包,请从其主页 http://www.imada.sdu.dk/~blackie/emacs/ 下载文件。将 Lisp 文件复制到您的加载路径中的某个位置,并将以下内容插入到您的 .emacs 文件中
(require 'power-macros) (power-macros-mode) (pm-load)
如果您不知道加载路径是什么,或者没有加载路径,请在您的主目录中创建一个名为 Emacs 的目录,将文件复制到此目录,并将以下行插入到您上面的 .emacs 文件中
(setq load-path (cons "~/Emacs" load-path))完成此操作后,当您定义宏后,您可以简单地按下 CTRL-c n,Emacs 将在迷你缓冲区中询问您以下问题。
要将宏绑定到哪个键? 首先,Emacs 必须知道宏应该绑定到哪个键。当您完成回答这些问题后,只需按下此键即可使用该宏。通过绑定到不同的键,您可以同时定义多个宏。
宏应该如何访问? 使用 power-macros,您可以使宏通过以下两种方式之一访问
全局:在每个缓冲区中都可以访问。
主模式特定宏:宏只能在具有给定主模式的缓冲区中访问。
作为模式特定宏的示例,请考虑上面示例中的 for 循环宏。此宏仅在编写 C++ 程序时有用。此外,您可能需要一个类似的宏,使用 Java 语法来编程 Java。使用 power-macros,您可以将 C++ 模式的宏和 Java 模式的宏都绑定到同一个键(例如 CTRL-m-f);然后,将为给定的模式使用正确的宏。
应该将它保存到哪个文件? 默认情况下,Emacs 将使用 power-macro 定义的宏保存到名为 ~/.power-macros 的文件中。如果这对于您正在定义的宏来说是可以接受的,只需在此问题处按下 ENTER 键即可。如果您不想将给定的宏保存到文件中以供以后的 Emacs 会话使用,请删除建议的文本(即,用空字符串回答问题)。此外,您可以命名另一个文件。下面的部分描述了在什么情况下这样做可能特别有趣。
它的描述是什么? 最后,您必须为刚刚定义的宏编写描述。这将使您以后更容易识别它,当您忘记它绑定到哪个键时,或者当您正在搜索要绑定新宏的键时。
作为将宏绑定到键的一部分,Emacs 还会检查给定的绑定是否会覆盖现有的绑定。如果是这种情况,它会警告您并要求确认以继续定义。
不久前,我打算做一个关于 Emacs 的演讲。我以前做过很多次了,所以我没有为这次特定的演讲做任何特别的准备。当我在火车上前往活动现场时,我决定浏览一下我的演示文稿。我震惊地发现演示程序突然在我的机器上无法工作了。我该怎么办?答案是显而易见的:为什么不使用 Emacs 来制作演示文稿呢?幸运的是,另一个演示程序的输入是 ASCII,我在演示文稿中使用的唯一结构是枚举列表,因此很容易重写演示文稿,使其在 Emacs 缓冲区中看起来不错(字体略微放大)。
现在只有一个问题:我如何轻松地前进/后退一页演示文稿页面?答案是创建两个宏:一个前进一页,另一个后退一页。
前进一页是以以下方式完成的
搜索以若干个等号开头的行,即每个演示文稿页面的第二行(正好在页面标题下方)。
按下 CTRL-1 CTRL-l(即,control-(数字)一 control-(字母)l)。这将把该行定位为屏幕的第二行,因此,页面标题将是第一行。
移动到下一行的开头。这是必要的,以便后续搜索不会找到当前页面。
刚刚定义的两个宏仅对给定的文件有用,以后对所有包含为使用 Emacs 查看而制作的演示文稿的文件都有用。因此,一直定义这些宏并将其绑定到按键有点烦人,特别是考虑到可能要过几个月才会有我的下一次 Emacs 演示文稿。
因此,这两个宏被保存到一个单独的文件中,并且在需要时,我可以简单地加载它们。加载 power-macro 是通过使用函数 pm-load 完成的。因此,我可以通过按下 META-x,键入 pm-load,按下 ENTER,然后键入要加载的文件名来加载宏。通过将以下行作为文件的最后几行插入,可以更自动地加载演示文稿宏
Local Variables: eval: (pm-load "presentation.macro") End:
在这里,假设包含宏的文件名称为 presentation.macro。现在,每当文件打开时,Emacs 会自动加载演示文稿宏。
当您定义了许多宏后,您可能想要执行各种功能来管理您的宏。这是通过按下 CTRL-c m 完成的。它将弹出一个类似于以下的缓冲区
the one shown in Figure 1.
您在此缓冲区中看到的是您的 power-macros,每个宏都用虚线分隔开。许多键在此缓冲区中具有特殊含义(就像键在缓冲区管理缓冲区或 dired 缓冲区中具有特殊含义一样)。
在其中一个字段的顶部按下 ENTER 键允许您编辑给定的字段。编辑字段意味着更改其内容或将宏复制到具有给定字段更改的新宏。当您在字段上按下 ENTER 键时,您将指定您想要的这些含义中的哪一个。

图 1. Emacs Power-Macro 缓冲区
宏的删除分两步完成。首先,您标记要删除的宏,然后您告诉 Emacs 实际删除它们。如果您熟悉缓冲区管理缓冲区或 dired 模式,您将熟悉这个两步过程。
如果您现在准备好了解更多关于 Emacs 的信息,请访问我之前提到的 URL 的主页。
本文最初发表在 LinuxGazette.com 第 47 期,这是一个在线电子杂志,以前由 Linux Journal 出版。
