save-excursion
在 append-to-buffer
中的应用在 append-to-buffer
中的 let
表达式的主体由一个 save-excursion
表达式组成。
save-excursion
函数保存 point 的位置,并在 save-excursion
主体表达式执行完成后将其恢复到该位置。此外,save-excursion
还跟踪原始缓冲区并将其恢复,这就是在 append-to-buffer
中使用 save-excursion
的方式。
顺便提一下,值得注意的是,Lisp 函数通常格式化为多行展开的形式,其中所有被包裹在多行展开的内容都比第一个符号缩进得更多。在这个函数定义中,let
的缩进比 defun
大,而 save-excursion
的缩进比 let
大,就像这样:
(defun … … … (let… (save-excursion …
这种格式约定使得很容易看到 save-excursion
主体中的行是由与 save-excursion
相关的括号括起来的,就像 save-excursion
本身由与 let
相关的括号括起来一样:
(let ((oldbuf (current-buffer))) (save-excursion … (set-buffer …) (insert-buffer-substring oldbuf start end) …))
使用 save-excursion
函数的方式可以看作是填充模板的过程:
(save-excursion 主体中的第一个表达式 主体中的第二个表达式 … 主体中的最后一个表达式)
在这个函数中,save-excursion
的主体只包含一个表达式,即 let*
表达式。你已经了解了 let
函数,而 let*
函数则不同。它允许 Emacs 按顺序设置 varlist 中的每个变量,依次设置在 varlist 较早部分设置的变量的值,以便 varlist 较后部分的变量可以使用 varlist 较早部分设置的值。
观察 append-to-buffer
中的 let*
表达式:
(let* ((append-to (get-buffer-create buffer)) (windows (get-buffer-window-list append-to t t)) point) BODY...)
我们可以看到,append-to
被绑定到由 (get-buffer-create buffer)
返回的值上。在下一行,append-to
作为参数传递给了 get-buffer-window-list
;这在 let
表达式中是不可能的。注意,point
被自动绑定为 nil
,就像在 let
语句中一样。
现在让我们专注于 let*
表达式的主体中的 set-buffer
和 insert-buffer-substring
函数。
在旧版本中,set-buffer
表达式是简单的
(set-buffer (get-buffer-create buffer))
但现在它是
(set-buffer append-to)
这是因为 append-to
在 let*
表达式中先绑定到了 (get-buffer-create buffer)
的值上。
append-to-buffer
函数定义将文本从当前缓冲区插入到一个命名的缓冲区中。巧合的是,insert-buffer-substring
恰好相反——它从另一个缓冲区复制文本到当前缓冲区——这就是为什么 append-to-buffer
定义以一个 let
开始的原因,该 let
将本地符号 oldbuf
绑定到在执行 append-to-buffer
命令时的 current-buffer
的值上。
insert-buffer-substring
表达式看起来像这样:
(insert-buffer-substring oldbuf start end)
insert-buffer-substring
函数将一个字符串从其第一个参数指定的缓冲区中复制并插入到当前缓冲区。在这种情况下,insert-buffer-substring
的参数是由 let
创建并绑定的变量的值,即 oldbuf
的值,这是在给出 append-to-buffer
命令时的当前缓冲区。
在 insert-buffer-substring
完成其工作后,save-excursion
将恢复操作到原始缓冲区,而 append-to-buffer
将完成其工作。
以骨架形式编写,主体的工作看起来像这样:
(let (将-current-buffer
的值绑定到-oldbuf
) (save-excursion ; 跟踪缓冲区。 更改缓冲区 从-oldbuf
中插入子串到缓冲区) 完成时切换回原始缓冲区 完成时使-oldbuf
的局部含义消失
总之,append-to-buffer
的工作方式如下:它保存了当前缓冲区的值在名为 oldbuf
的变量中。它获取新的缓冲区(如果需要,创建一个),并将 Emacs 的注意力切换到它。使用 oldbuf
的值,它将来自旧缓冲区的文本区域插入新缓冲区;然后使用 save-excursion
,它将你带回原始缓冲区。
通过查看 append-to-buffer
,你已经探索了一个相当复杂的函数。它展示了如何使用 let
、save-excursion
以及如何在不同缓冲区之间切换和返回的方法。许多函数定义都以这种方式使用 let
、save-excursion
和 set-buffer
。