current-kill 的函数体

函数定义的主体是一个 let 表达式,它自身除了 varlist 变量列表外也包含函数体。

let 表达式声明了一个仅在此函数内部可用的变量。这个变量名为 interprogram-paste,用于向其他程序复制内容,而非在当前 GNU Emacs 实例内部复制。大多数窗口系统都提供程序间粘贴功能,但遗憾的是,该功能通常只支持最近一条内容。尽管 Emacs 提供环形剪切缓冲区已有数十年,多数窗口系统仍未采用支持多条记录的环形结构。

if 表达式分为两部分:存在 interprogram-paste 时的分支,以及不存在时的分支。

我们来看 current-kill 函数的 else 分支。(then 分支使用了 kill-new 函数,该函数我们已经介绍过。See The kill-new function。)

(or kill-ring (error "Kill ring is empty"))
(let ((ARGth-kill-element
       (nthcdr (mod (- n (length kill-ring-yank-pointer))
                    (length kill-ring))
               kill-ring)))
  (or do-not-move
      (setq kill-ring-yank-pointer ARGth-kill-element))
  (car ARGth-kill-element))

代码首先检查剪切环是否有内容;若无,则抛出错误。

注意 or 表达式与使用 if 判断长度的写法非常相似:

(if (zerop (length kill-ring))          ; if-part
    (error "Kill ring is empty"))       ; then-part
  ;; No else-part

如果剪切环中没有任何内容,其长度必然为零,此时会向用户发送错误提示:‘Kill ring is empty’。current-kill 函数使用了更简洁的 or 表达式,但 if 表达式能更直观地体现逻辑。

if 表达式使用了 zerop 函数,当检测值为零时返回真。当 zerop 检测为真时,会执行 if 的 then 分支。then 分支是以 error 函数开头的列表,该函数与 message 函数类似(see The message Function),都会在回显区显示单行信息。不过,error 除了显示信息外,还会终止其所在函数的后续执行。这意味着,若剪切环长度为零,函数剩余部分将不会执行。

随后 current-kill 函数会选定要返回的元素。选择结果取决于 current-kill 轮转的位数,以及 kill-ring-yank-pointer 当前指向的位置。

接下来,若可选参数 do-not-move 为真,则不移动指针;否则将 kill-ring-yank-pointer 的当前值设为指向对应列表。最后,即便 do-not-move 为真,仍有表达式返回列表的首个元素。