《elisp 每日一练》——Major Mode 中的keymap 管理

《elisp 每日一练》——Major Mode 中的keymap 管理

Masimaro
2026-09-18 / 0 评论 / 0 阅读 / 正在检测是否收录...

本节我们来介绍 Major Mode 中对于keymap 的管理,我们前面介绍过 define-minor-mode:keymap 关键字。 但是我们查询文档的话发现,它并不支持 :keymap 关键字

背景知识

我们还是准备一个测试用例,看看宏展开是什么样的

(defvar my-code-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "C-c c c") #'compile)
    (define-key map (kbd "C-c c r") #'recompile)
    map)
  "Keymap for `my-code-mode'.")

(define-derived-mode my-code-mode prog-mode "MyCode"
  "带有快捷键绑定的代码主模式。")

在函数定义开始之前,它是这样处理keymap的

(unless (boundp 'my/code-mode-map)
    (put 'my/code-mode-map 'definition-name 'my/code-mode))
  (with-no-warnings (defvar my/code-mode-map (make-sparse-keymap)))
  (unless (get 'my/code-mode-map 'variable-documentation)
    (put 'my/code-mode-map 'variable-documentation
         (purecopy "Keymap for `my/code-mode'.")))

这段代码表明,Major Mode 处理 keymap 的时候强制使用 mode 名称后带 -map 的符号。我们无法使用自己名称命名的keymap。

(unless (boundp 'my/code-mode-map)
  (put 'my/code-mode-map 'definition-name 'my/code-mode))

上述代码先检查对应名称的keymap 变量是否被绑定,如果没有被绑定,它会给这个符号挂一个 definition-name 属性,属性的值是mode 的符号。这个属性是 Emacs 29 引入的,用于告诉 find-function / describe-symbol 之类的工具:“这个 keymap 变量是由 my/code-mode 这个模式定义出来的”,方便用户跳转到定义处。

后面它使用 defvar 直接重新定义了一个新的变量。请注意我们之前提到过 defvar 的特性,如果变量未定义则定义,如果变量已定义它就什么都不做。这里因为我们提前定义了同名的变量,所以这段代码实际上是什么都没有做。

(unless (get 'my/code-mode-map 'variable-documentation)
    (put 'my/code-mode-map 'variable-documentation
         (purecopy "Keymap for `my/code-mode'.")))

这段我们之前介绍过,它是在设置变量的文档,如果文档存在则不进行操作。

函数中,keymap 采用的继承的方案,这部分的内容我们在之前已经详细分析过了,就不再继续了。

总结

本篇我们详细分析了Major Mode 中 keymap 的管理。与 minor mode 不同,我们发现它不支持通过 :keymap 关键字自定义 keymap 的名称,而是必须采用统一的名称:mode名+ -map

0

评论 (0)

取消