周游抑或毁灭世界
现在,我们已经有了原子,有了发动机,也有了选择前进方向的能力,因此不用等明天,今天就可以喂马,劈柴,周游世界。
在 Emacs 里,世界就是缓冲区。(goto-char (point-min))
可以让准备周游世界的光标跳到世界的起点,同理 (goto-char (point-max))
可以让光标跳到世界的尽头。于是,光标就以光的速度周游了一遍世界。
当然不是这样。光标实际上是通过异次元空间从世界的起点开始仅用一步就跳到了世界的尽头。倘若让光标从起点开始一步一步走到终点,可以像下面这样做:
(defun 周游世界 (起点 终点) (if (= 起点 终点) (message "到终点了!") (progn (goto-char 起点) (sit-for 0.5) (周游世界 (+ 起点 1) 终点)))) (周游世界 1 (point-max))
之前,我们一直是在 init.el 中试验一些 Emacs Lisp 代码,主要是因为 Emacs 重新启动时,会自动加载 init.el,这样 init.el 中的函数定义就会生效。现在我们换一种方式,这种方式更方便随时测试一些代码片段。
随便找个目录,用 Emacs 随便创建一份空文件,只是让这个文件的扩展名为 .el
,例如 foo.el
。倘若你已经忘记了如何用 Emacs 创建一份新文件,那么我在此会友善地帮助你回忆一下。要么是启动 Emacs,然后向它发送指令,例如 C-x C-f ~/foo.el<RET>
,要么是在命令行窗口中,以指定文件名的方式启动 Emacs,例如:
$ emacs foo.el
假设你已经用 Emacs 创建了 foo.el 文件。现在,将上述代码复制到该文件在 Emacs 中对应的缓冲区,然后将光标移动到 周游世界
的函数定义的末尾,执行 C-x C-e
,再将光标移动到 周游世界
函数的求值表达式的末尾,执行 C-x C-e
,
倘若上述操作执行无误,那么接下来,你会看到光标会跳到缓冲区的起始位置,然后每隔 0.5 秒向前移动 1 个字符的距离。当光标走到缓冲区末尾的时候,周游世界
函数的求值过程结束,求值结果是:在微缓冲区中显现字符串原子 到终点了!
。
上述代码中,只有 message
与 sit-for
这两个函数第一次遇到。message
可以将字符串显示于微缓冲区。sit-for
可以让 Emacs Lisp 解释器在求值过程中停下来「休息」一段时间。
message
函数是将字符串显示于 Emacs 的 *Message*
缓冲区。使用 C-x b *Message* <RET>
可以切换到 *Messages*
缓冲区,查看 message
的输出。当我们将 goto-char
、sit-for
以及 message
这些函数形成的表达式与 周游世界
这个类似于发动机的函数「连接」起来,就形成了一种自驾车周游世界的运动,是不是很奇妙?
很快,我们就可以发现,世界是可以周游的,但也是可以毁灭的。看下面的代码:
(defun 毁灭世界 (起点 终点) (if (= 起点 终点) (message "吃掉了所有字符!") (progn (delete-char 1) (sit-for 0.5) (毁灭世界 (+ 起点 1) 终点)))) (progn (goto-char (point-min)) (毁灭世界 1 (point-max)))
在重新按照上述的方法重新求值,结果可以看到,当光标移动到缓冲器的起点之后,它会像黑洞一样,每隔 0.5 秒吞噬掉一个字符。
delete-char
的作用是从缓冲区中删除光标所在位置之后的 N 个字符。当 N 值为负数时,删除的则是光标之前的 |N| 个字符。
这里需要对 Emacs 的光标作更多一些的介绍。光标,其形状默认是一个矩形的小黑块,它在自身停留的位置上恰好能完整覆盖一个字符。这个小黑块会不停地闪动着。当我们谈及光标的位置时,实际上指的是这个小黑块的左侧边界线的位置。这个位置,Emacs Lisp 语言将其称为点。缓冲区的起始位置,就是坐标为 1 的点。不过,有的时候,缓冲区的范围会被人为地缩小,此时它的起始位置就不再是 1,而是 (point-min)
。在 Emacs Lisp 程序中,使用 (point-min)
与 (point-max)
表示缓冲区的起点与终点是最稳妥的办法。
马克·吐温说,哥伦布发现新大陆没什么了不起,他要是没发现,那才是真的见鬼了。上述的第一个小试验可以证明马克·吐温的说法是正确的。第二个小试验则可以证明……人类能够造出原子弹,也没什么了不起,要是造不出来,那才是真的见鬼了。
下一篇:无名