然而,在讨论 save-excursion
之前,首先回顾一下在 GNU Emacs 中点(Point)和标记(Mark)的概念可能会很有用。点 是光标的当前位置。光标所在的位置就是点。更准确地说,在光标位于字符之上的终端上,点位于紧接在字符之前。在 Emacs Lisp 中,点是一个整数。缓冲区中的第一个字符是编号为一,第二个是编号为二,依此类推。函数 point
返回光标的当前位置作为一个数字。每个缓冲区都有其自己的点值。
标记 是缓冲区中的另一个位置;它的值可以通过诸如 C-SPC(set-mark-command
)的命令设置。如果已经设置了标记,可以使用命令 C-x C-x(exchange-point-and-mark
)使光标跳到标记位置,并将标记设置为点的先前位置。此外,如果设置了另一个标记,前一个标记的位置将保存在标记环中。可以通过键入 C-u C-SPC 一次或多次将光标跳到保存的标记位置。
点和标记之间的缓冲区部分称为区域。许多命令在区域上起作用,包括 center-region
、count-words-region
、kill-region
和 print-region
。
save-excursion
特殊形式保存点的位置,并在该特殊形式的主体内的代码被 Lisp 解释器评估后恢复这个位置。因此,如果点在文本的开头,某些代码将点移到缓冲区的末尾,save-excursion
将在函数主体中的表达式被评估后将点放回到它之前的位置。
在 Emacs 中,一个函数通常会在其内部工作的过程中移动点,尽管用户不希望这样。例如,count-words-region
会移动点。为了防止用户受到既意外又(从用户的角度)不必要的跳跃的困扰,通常使用 save-excursion
来保持点在用户预期的位置上。使用 save-excursion
是良好的编码风格。
为了确保代码书写规范,save-excursion
即使在其内部代码发生错误时也会恢复点的值(或者更准确地说,“在异常退出的情况下”)。这个特性非常有帮助。
除了记录点的值,save-excursion
还跟踪当前缓冲区,并在需要时进行恢复。这意味着你可以编写改变缓冲区的代码,并通过 save-excursion
切换回原始缓冲区。这就是 save-excursion
在 append-to-buffer
中的使用方式。(See append-to-buffer
的定义.)