kill-append 函数

kill-append 函数的定义如下:

(defun kill-append (string before-p &optional yank-handler)
  "将STRING追加到kill环中最新的kill的末尾。
如果BEFORE-P非空,则将STRING插入到kill的开头。
… "
  (let* ((cur (car kill-ring)))
    (kill-new (if before-p (concat string cur) (concat cur string))
              (or (= (length cur) 0)
                  (equal yank-handler
                         (get-text-property 0 'yank-handler cur)))
              yank-handler)))

kill-append 函数非常直观。它使用了稍后我们将详细讨论的 kill-new 函数。

(此外,该函数提供了一个可选的参数叫做 yank-handler;当调用时,此参数告诉函数如何处理添加到文本的属性,比如粗体或斜体。)

它使用 let* 函数将kill环的第一个元素的值设置为 cur。(我不知道为什么函数不使用 let 替代;表达式中只设置了一个值。也许这是一个不会产生问题的bug?)

考虑到条件语句是 kill-new 的两个参数之一。它使用 concat 将新文本连接到kill环的 CAR(第一个元素)。无论是插入还是追加文本,都取决于 if 表达式的结果:

(if before-p                            ; if-part
    (concat string cur)                 ; then-part
  (concat cur string))                  ; else-part

如果要删除的区域位于上一次命令中删除的区域之前,那么它应该插入到之前保存的文本之前;反之,如果删除的文本跟随刚刚删除的文本,它应该追加到先前的文本之后。 if 表达式依赖于谓词 before-p 来决定新保存的文本是应该放在先前保存的文本之前还是之后。

符号 before-pkill-append 函数的参数之一的名称。当评估 kill-append 函数时,它被绑定到通过评估实际参数返回的值。在这种情况下,这是表达式 (< end beg)。此表达式不直接确定此命令中删除的文本是在上次命令中删除的文本之前还是之后;它的作用是确定变量 end 的值是否小于变量 beg 的值。如果是,这意味着用户很可能朝着缓冲区的开头前进。此外,谓词表达式 (< end beg) 的评估结果将为真,文本将在先前文本之前插入。另一方面,如果变量 end 的值大于变量 beg 的值,则文本将在先前文本之后追加。

当新保存的文本将被插入时,字符串与新文本将被连接到旧文本之前:

(concat string cur)

但如果文本将被追加,它将在旧文本之后连接:

(concat cur string))

为了理解这是如何工作的,我们首先需要复习一下 concat 函数。concat 函数将两个文本字符串链接或合并在一起。结果是一个字符串。例如:

(concat "abc" "def")
     ⇒ "abcdef"

(concat "new "
        (car '("first element" "second element")))
     ⇒ "new first element"

(concat (car
        '("first element" "second element")) " modified")
     ⇒ "first element modified"

现在我们可以理解 kill-append:它修改了kill环的内容。kill环是一个列表,其中每个元素都是保存的文本。kill-append 函数使用 kill-new 函数,后者又使用 setcar 函数。