6.2 what-line

what-line 命令用于显示光标所在行的行号。该函数展示了 save-restrictionsave-excursion 的用法。函数原始代码如下:

(defun what-line ()
  "Print the current line number (in the buffer) of point."
  (interactive)
  (save-restriction
    (widen)
    (save-excursion
      (beginning-of-line)
      (message "Line %d"
               (1+ (count-lines 1 (point)))))))

(在新版 GNU Emacs 中,what-line 函数已扩展,可同时显示缩窄后与扩宽后的行号。新版比此处示例更复杂。若你愿意,可在理解该版本后查看新版实现,大概率需要使用 C-h fdescribe-function)。新版使用条件判断缓冲区是否缩窄。

另外,新版 what-line 使用了 line-number-at-pos,其中除 (goto-char (point-min)) 等简单表达式外,还使用 (forward-line 0) 而非 beginning-of-line 将光标移至当前行开头。)

此处展示的 what-line 函数包含文档字符串且为交互式,符合预期。接下来两行使用了 save-restrictionwiden

save-restriction 特殊形式会记录当前缓冲区的缩窄状态(如果有),并在主体代码执行完毕后恢复该状态。

save-restriction 之后是 widen。该函数会取消调用 what-line 时缓冲区可能存在的缩窄。(原有缩窄状态由 save-restriction 保存。)取消缩窄后,行统计命令可从缓冲区开头计数,否则只会在可访问区域内统计。函数结束前,save-restriction 会恢复原始缩窄状态。

widen 调用之后是 save-excursion,它会保存光标位置,并在主体代码使用 beginning-of-line 移动光标后恢复原位。

(注意 (widen) 表达式位于 save-restrictionsave-excursion 之间。连续编写两个 save-… 表达式时,应将 save-excursion 放在外层。)

what-line 函数最后两行用于统计缓冲区行数,并在回显区显示行号。

(message "Line %d"
         (1+ (count-lines 1 (point)))))))

message 函数在 Emacs 屏幕底部显示单行消息。第一个参数位于引号内,会作为字符串直接打印。其中可包含 ‘%d’ 表达式,用于打印后续参数。‘%d’ 以十进制形式输出参数,因此最终会显示类似 ‘Line 243’ 的内容。

替换 ‘%d’ 打印的数值由函数最后一行计算:

(1+ (count-lines 1 (point)))

该代码从缓冲区起始位置(由 1 表示)统计到 (point) 处的行数,然后加一。(1+ 函数会给参数加一。)加一的原因是:第二行之前只有一行,而 count-lines 只统计当前行 之前 的行数。

count-lines 执行完毕、回显区显示消息后,save-excursion 恢复光标位置,save-restriction 恢复原始缩窄状态(如果有)。