完整的 kill-region 定义

我们将逐步讲解 condition-case 代码。首先,让我们看一下 kill-region 的定义,附带注释:

(defun kill-region (beg end)
  "Kill (\"cut\") text between point and mark.
This deletes the text from the buffer and saves it in the kill ring.
The command \\[yank] can retrieve it from there. … "

  ;; • 由于顺序很重要,首先传递 point。
  (interactive (list (point) (mark)))
  ;; • 并告诉我们如果无法剪切文本要怎么办。
  ;; 'unless' 是没有 then 部分的 'if'。
  (unless (and beg end)
    (error "The mark is not set now, so there is no region"))

  ;; • 'condition-case' 接受三个参数。
  ;;    如果第一个参数是 nil,就像这里一样,
  ;;    错误信号的信息就不会被存储以供其他函数使用。
  (condition-case nil

      ;; • 'condition-case' 的第二个参数告诉 Lisp 解释器
      ;;    一切正常时要做什么。

      ;;    它以一个 'let' 函数开始,提取字符串并测试它是否存在。
      ;;    如果存在(这是 'when' 检查的内容),它调用一个 'if' 函数,
      ;;    用于确定前一个命令是否是对 'kill-region' 的另一个调用;
      ;;    如果是,则新文本附加到先前的文本;如果不是,则调用
      ;;    另一个函数 'kill-new'。

      ;;    'kill-append' 函数连接新字符串和旧字符串。
      ;;    'kill-new' 函数将文本插入到 kill 环中的新项目中。

      ;;    'when' 是没有 else 部分的 'if'。
      ;;    第二个 'when' 再次检查当前字符串是否存在;
      ;;    此外,它还检查前一个命令是否是对 'kill-region' 的另一个调用。
      ;;    如果其中一个条件为真,则将当前命令设置为 'kill-region'。
      (let ((string (filter-buffer-substring beg end t)))
        (when string                    ; 如果 BEG = END,则 STRING 为 nil
          ;; 将该字符串添加到 kill ring 中,以某种方式。
          (if (eq last-command 'kill-region)
              ;;    − 'yank-handler' 是传递给 'kill-region' 的可选参数,
              ;;    告诉 'kill-append' 和 'kill-new' 函数如何处理添加到文本中的属性,
              ;;    例如 'bold' 或 'italics'。
              (kill-append string (< end beg) yank-handler)
            (kill-new string nil yank-handler)))
        (when (or string (eq last-command 'kill-region))
          (setq this-command 'kill-region))
        nil)

    ;;  • 'condition-case' 的第三个参数告诉解释器
    ;;    发生错误时要做什么。
    ;;    第三个参数有一个条件部分和一个体部分。
    ;;    如果满足条件(在这种情况下,如果文本或缓冲区是只读的)
    ;;    那么就执行体部分。
    ((buffer-read-only text-read-only) ;; 条件部分
     ;; … 体部分
     (copy-region-as-kill beg end)
     ;;    接下来,同样作为体部分的一部分,设置 this-command,
     ;;    这样它将在错误中被设置。
     (setq this-command 'kill-region)
     ;;    最后,在体部分,如果可以在不发出错误的情况下将文本复制到 kill ring 中,则发送消息,否则不发送。
     (if kill-read-only-ok
         (progn (message "Read only text copied to kill ring") nil)
       (barf-if-buffer-read-only)
       ;; 如果缓冲区不是只读的,则文本是只读的。
       (signal 'text-read-only (list (current-buffer)))))))