39.4 查找与展开缩写

缩写通常由特定交互命令展开,包括 self-insert-command。本节介绍编写此类命令时使用的子程序,以及它们用于通信的变量。

Function: abbrev-symbol abbrev &optional table

该函数返回表示名为 abbrev 的缩写的符号。如果该缩写未定义,则返回 nil。可选的第二个参数 table 是查找缩写的目标缩写表。如果 tablenil,该函数会先尝试当前缓冲区的局部缩写表,再尝试全局缩写表。

Function: abbrev-expansion abbrev &optional table

该函数返回 abbrev 对应的展开字符串(由当前缓冲区使用的缩写表定义)。如果 abbrev 不是有效缩写,则返回 nil。 可选参数 table 指定使用的缩写表,用法与 abbrev-symbol 一致。

Command: expand-abbrev

该命令展开光标前的缩写(如果存在)。如果光标后没有缩写,该命令不执行任何操作。展开时,它会无参调用变量 abbrev-expand-function 的值对应的函数,并返回该函数的执行结果。

默认展开函数在成功展开时返回缩写符号,否则返回 nil。如果缩写符号对应的钩子函数是一个符号,且其 no-self-insert 属性非 nil,同时该钩子函数返回 nil,那么即使实际完成了展开,默认展开函数也会返回 nil

Function: abbrev-insert abbrev &optional name start end

该函数插入 abbrev 的展开内容,替换 startend 之间的文本。如果省略 start,则默认使用光标位置。如果 namenil,它应当是查找到该缩写时使用的名称(字符串);用于判断是否调整展开内容的大小写格式。函数成功插入缩写则返回 abbrev,否则返回 nil

Command: abbrev-prefix-mark &optional arg

该命令将光标当前位置标记为缩写的起始位置。下一次调用 expand-abbrev 时,会将此处到当时光标位置的文本作为待展开缩写,而非像往常一样使用前一个单词。

首先,除非 argnil,否则该命令会先展开光标前的缩写。(交互使用时,arg 为前缀参数。) 然后在光标前插入一个连字符,标记下一个待展开缩写的起始位置。实际展开时会移除该连字符。

User Option: abbrev-all-caps

当该变量设为非 nil 时,全大写输入的缩写会以全大写形式展开。否则,全大写输入的缩写会将展开内容的每个单词首字母大写后展开。

Variable: abbrev-start-location

该变量的值是一个缓冲区位置(整数或标记),供 expand-abbrev 作为下一个待展开缩写的起始位置。该值也可以是 nil,表示使用光标前的单词。每次调用 expand-abbrev 时,abbrev-start-location 都会被置为 nil。该变量也会由 abbrev-prefix-mark 设置。

Variable: abbrev-start-location-buffer

该变量的值是设置了 abbrev-start-location 的缓冲区。尝试在其他缓冲区展开缩写时,会清空 abbrev-start-location。该变量由 abbrev-prefix-mark 设置。

Variable: last-abbrev

这是最近一次被展开的缩写的 abbrev-symbolexpand-abbrev 会保留该信息,供 unexpand-abbrev 命令使用(see Expanding Abbrevs in The GNU Emacs Manual)。

Variable: last-abbrev-location

这是最近一次被展开的缩写的位置。expand-abbrev 会保留该信息,供 unexpand-abbrev 命令使用。

Variable: last-abbrev-text

这是最近一次被展开的缩写经过大小写转换(如果有)后的精确展开文本。如果缩写已被撤销展开,其值为 nilexpand-abbrev 会保留该信息,供 unexpand-abbrev 命令使用。

Variable: abbrev-expand-function

该变量的值是一个函数,expand-abbrev 会无参调用它执行展开操作。该函数可以在展开前后执行任意操作。 如果完成展开,应当返回缩写符号。

以下示例代码展示了 abbrev-expand-function 的简单用法。假设 foo-mode 是一种编辑特定文件的模式,文件中以 ‘#’ 开头的行为注释。你希望这些行使用文本模式缩写,而常规的局部缩写表 foo-mode-abbrev-table 适用于其他所有行。local-abbrev-tabletext-mode-abbrev-table 的定义参见 see 标准缩写表add-function 的详细说明参见 see 为 Emacs Lisp 函数添加建议

(defun foo-mode-abbrev-expand-function (expand)
  (if (not (save-excursion (forward-line 0) (eq (char-after) ?#)))
      ;; 执行常规展开
      (funcall expand)
    ;; 处于注释内部:使用文本模式缩写
    (let ((local-abbrev-table text-mode-abbrev-table))
      (funcall expand))))

(add-hook 'foo-mode-hook
          (lambda ()
            (add-function :around (local 'abbrev-expand-function)
                          #'foo-mode-abbrev-expand-function)))