beginning-of-buffer 完整实现 ¶以下是 beginning-of-buffer 函数的完整代码:
(defun beginning-of-buffer (&optional arg) "将光标移至缓冲区开头;在原位置保留标记。 带 \\[universal-argument] 前缀时,不在原位置设置标记。 带数字参数 N 时,将光标置于距开头 N/10 处。 若缓冲区被缩窄,该命令会使用缓冲区可访问部分的开头与大小。
不要在 Lisp 程序中使用该命令!
\(goto-char (point-min)) 速度更快,且不会覆盖标记。"
(interactive "P")
(or (consp arg)
(and transient-mark-mode mark-active)
(push-mark))
(let ((size (- (point-max) (point-min))))
(goto-char (if (and arg (not (consp arg)))
(+ (point-min)
(if (> size 10000)
;; 避免大缓冲区数值溢出!
(* (prefix-numeric-value arg)
(/ size 10))
(/ (+ 10 (* size (prefix-numeric-value arg)))
10)))
(point-min))))
(if (and arg (not (consp arg))) (forward-line 1)))
除两处细节外,前文已说明该函数的工作原理。第一处是文档字符串中的细节,第二处是函数最后一行的逻辑。
文档字符串中引用了如下表达式:
\\[universal-argument]
该表达式左方括号前使用了 ‘\\’。这个 ‘\\’ 告知 Lisp 解释器,将 ‘[…]’ 替换为当前绑定的按键。对于 universal-argument,该按键通常为 C-u,但也可能不同。(更多信息参见 See Tips for Documentation Strings in The GNU Emacs Lisp Reference Manual。)
最后,beginning-of-buffer 命令的最后一行表示:若命令带参数调用,则将光标移至下一行开头:
(if (and arg (not (consp arg))) (forward-line 1))
这会将光标置于缓冲区对应十分之几位置的下一行行首。这一细节处理确保光标 至少 位于缓冲区目标比例位置之后,属于锦上添花的设计——虽非必需,但缺少则很可能引发用户抱怨。((not (consp arg)) 部分用于避免:仅使用 C-u 而不带数字时,即原始前缀参数只是一个序对节点时,命令不会将光标跳至第二行开头。)