5.1 copy-to-buffer 的定义

理解 append-to-buffer 之后,理解 copy-to-buffer 就很容易。该函数将文本复制到目标缓冲区,但不会追加内容,而是替换目标缓冲区中原有的全部文本。

copy-to-buffer 的函数体如下:

...
(interactive "BCopy to buffer: \nr")
(let ((oldbuf (current-buffer)))
  (with-current-buffer (get-buffer-create buffer)
    (barf-if-buffer-read-only)
    (erase-buffer)
    (save-excursion
      (insert-buffer-substring oldbuf start end)))))

copy-to-bufferinteractive 表达式比 append-to-buffer 更简单。

定义接下来的语句是:

(with-current-buffer (get-buffer-create buffer) ...

首先看最内层的表达式,它会被优先执行。该表达式以 get-buffer-create buffer 开头,让计算机使用指定名称的缓冲区作为复制目标,不存在则创建。随后,with-current-buffer 函数会临时将该缓冲区设为当前缓冲区并执行其函数体,执行完毕后切回当前缓冲区13

(这展示了另一种只切换程序操作目标、不改变用户显示窗口的方法。append-to-buffer 使用 save-excursionset-buffer 实现了同样效果,而 with-current-buffer 是更新、更易用的机制。)

barf-if-buffer-read-only 函数会在缓冲区不可修改时,提示缓冲区为只读并报错。

下一行仅包含 erase-buffer 函数,该函数会清空缓冲区。

最后两行是 save-excursion 表达式,其函数体为 insert-buffer-substringinsert-buffer-substring 从你当前所在的缓冲区复制文本(你不会察觉到程序已切换缓冲区,该原始缓冲区已被记为 oldbuf)。

顺便一提,这就是 “替换(replacement)” 的含义:Emacs 先清空原有文本,再插入新文本。

框架结构上,copy-to-buffer 的函数体如下:

(let (bind-oldbuf-to-value-of-current-buffer)
    (with-the-buffer-you-are-copying-to
      (but-do-not-erase-or-copy-to-a-read-only-buffer)
      (erase-buffer)
      (save-excursion
        insert-substring-from-oldbuf-into-buffer)))

Footnotes

(13)

这相当于一次性调用 (save-excursion (set-buffer …) …),尽管其定义略有不同,感兴趣的读者可通过 describe-function 查看。