完整的 forward-sentence 函数定义

forward-sentence 代码如下:

(defun forward-sentence (&optional arg)
  "向前移动到下一个句子结尾。带参数时重复执行。
带负参数时,反复向后移动到句子开头。

变量 `sentence-end' 是匹配句子结尾的正则表达式。
同时,所有段落边界也会终止句子。"
  (interactive "p")
  (or arg (setq arg 1))
  (let ((opoint (point))
        (sentence-end (sentence-end)))
    (while (< arg 0)
      (let ((pos (point))
            (par-beg (save-excursion (start-of-paragraph-text) (point))))
       (if (and (re-search-backward sentence-end par-beg t)
                (or (< (match-end 0) pos)
                    (re-search-backward sentence-end par-beg t)))
           (goto-char (match-end 0))
         (goto-char par-beg)))
      (setq arg (1+ arg)))
    (while (> arg 0)
      (let ((par-end (save-excursion (end-of-paragraph-text) (point))))
       (if (re-search-forward sentence-end par-end t)
           (skip-chars-backward " \t\n")
         (goto-char par-end)))
      (setq arg (1- arg)))
    (constrain-to-field nil opoint t)))

该函数初看较长,最好先看整体框架再看细节。观察最左列开始的表达式即可看清框架:

(defun forward-sentence (&optional arg)
  "documentation..."
  (interactive "p")
  (or arg (setq arg 1))
  (let ((opoint (point)) (sentence-end (sentence-end)))
    (while (< arg 0)
      (let ((pos (point))
            (par-beg (save-excursion (start-of-paragraph-text) (point))))
       rest-of-body-of-while-loop-when-going-backwards
    (while (> arg 0)
      (let ((par-end (save-excursion (end-of-paragraph-text) (point))))
       rest-of-body-of-while-loop-when-going-forwards
    handle-forms-and-equivalent

这样看起来清晰很多!函数定义包含文档字符串、interactive 表达式、or 表达式、let 表达式与 while 循环。

下面逐一分析这些部分。

可以看到文档字符串详尽且清晰。

该函数使用 interactive "p" 声明。这意味着处理后的前缀参数(若有)会作为参数传递给函数。(该参数为数字。)若函数未接收参数(可选),则参数 arg 会绑定到 1。

当以非交互方式无参数调用 forward-sentence 时,arg 会绑定到 nilor 表达式用于处理这种情况:若 arg 已有绑定值则保持不变,若为 nil 则将其设为 1。

接下来是 let 表达式,定义了两个局部变量 opointsentence-end。搜索前的光标局部值用于 constrain-to-field 函数,该函数用于处理格式与等价内容。sentence-end 变量由 sentence-end 函数设置。