B.3 yank-pop

在理解了 yankcurrent-kill 之后,你就知道如何处理 yank-pop 函数了。为了节省空间,下面是省略了文档的函数定义:

(defun yank-pop (&optional arg)
  "…"
  (interactive "*p")
  (if (not (eq last-command 'yank))
      (error "上一个命令不是 yank"))
  (setq this-command 'yank)
  (unless arg (setq arg 1))
  (let ((inhibit-read-only t)
        (before (< (point) (mark t))))
    (if before
        (funcall (or yank-undo-function 'delete-region) (point) (mark t))
      (funcall (or yank-undo-function 'delete-region) (mark t) (point)))
    (setq yank-undo-function nil)
    (set-marker (mark-marker) (point) (current-buffer))
    (insert-for-yank (current-kill arg))
    ;; 如果可能,将窗口的起始位置设置回 yank 命令之前的位置。
    (set-window-start (selected-window) yank-window-start t)
    (if before
        ;; 这类似于 exchange-point-and-mark,
        ;; 但不激活标记。
        ;; 即使命令循环会因为我们插入文本而取消激活标记,
        ;; 这样做更干净,因为我们避免了激活。
        (goto-char (prog1 (mark t)
                     (set-marker (mark-marker)
                                 (point)
                                 (current-buffer))))))
  nil)

这个函数是交互式的,带有一个小的 ‘p’,因此前缀参数会被处理并传递给函数。该命令只能在先前的 yank 后使用;否则会发送错误消息。此检查使用变量 last-command,该变量由 yank 设置,并在其他地方进行了讨论。(See copy-region-as-kill。)

let 子句将变量 before 设置为 true 或 false,具体取决于 point 是否在 mark 之前,然后删除 point 和 mark 之间的区域。这是由前一个 yank 命令刚插入的区域,也就是将被替换的文本。

funcall 将其第一个参数作为函数调用,并将其余参数传递给它。第一个参数是 or 表达式返回的内容。其余两个参数是由前一个 yank 命令设置的 point 和 mark 的位置。

还有更多内容,但这是最难的部分。