不过在讲解 save-excursion 之前,先回顾一下 GNU Emacs 中的
光标(point)和标记(mark)会很有帮助。光标(point)
就是当前指针所在位置。光标在哪里,point 就在哪里。
更精确地说,在光标显示在某个字符上方的终端上,point 位于该字符紧前方。
在 Emacs Lisp 中,point 是一个整数。缓冲区的第一个字符编号为 1,
第二个为 2,依此类推。函数 point 会以数字形式返回光标当前位置。
每个缓冲区都有自己的 point 值。
标记(mark) 是缓冲区中的另一个位置,可以通过
C-SPC(set-mark-command)等命令设置。
如果已经设置了标记,可以使用命令 C-x C-x
(exchange-point-and-mark)让光标跳转到标记处,
并将标记设为光标原先的位置。此外,如果你设置了新标记,
旧标记的位置会保存在标记环中。可以用这种方式保存多个标记位置。
输入一次或多次 C-u C-SPC 可以让光标跳转到已保存的标记。
缓冲区中光标与标记之间的区域称为选区(region)。
许多命令都作用于选区,包括 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 切回原始缓冲区。
append-to-buffer 中就是这样使用 save-excursion 的。
(See The Definition of append-to-buffer。)