关于 keybindings 的问题: 当 keybindings 与 evil-mode 冲突的时候谁起作用?

我本来是要为 realgud 的 source buffer 添加 tbreak 以及另一个自定义 command 的 keybindings. 但我遇到一个我无法理解的问题.

我是通过 spacemacs debug layer 安装的 realgud. realgud 的 source buffer 的 key map 是 realgud:shortkey-mode-map, 它定义在 realgud/common/cmds.el. spacemacs debug layer 有如下代码:

(defun debug/init-realgud ()
  (use-package realgud
    :defer t
    :init
    (progn
      (dolist (debugger (mapcar 'spacemacs/debug-generate-symbol
                                debug-additional-debuggers))
        (autoload debugger "realgud" nil t))
      (advice-add 'realgud-short-key-mode-setup
                  :before #'spacemacs/debug-short-key-state)
      (evilified-state-evilify-map realgud:shortkey-mode-map
        :eval-after-load realgud
        :mode realgud-short-key-mode
        :bindings
        "bb" 'realgud:cmd-break
        "bc" 'realgud:cmd-clear
        "bd" 'realgud:cmd-delete
        "bs" 'realgud:cmd-disable
        "be" 'realgud:cmd-enable
        "c" 'realgud:cmd-continue
        "i" 'realgud:cmd-step
        "J" 'realgud:cmd-jump
        "o" 'realgud:cmd-finish
        "q" 'realgud:cmd-quit
        "r" 'realgud:cmd-restart
        "s" 'realgud:cmd-next
        "S" 'realgud-window-cmd-undisturb-src
        "v" 'realgud:cmd-eval-dwim))))

如果这段代码起作用的行, 按理说, b 应该还是 evil mode 的上一个词 motion, 要按 bb 才是 realgud:cmd-break. 但是现实中, 按 b 就已经是 realgud:cmd-break, 而且用 describe-key, 也直接给的是 realgud/common/cmds.el 中的定义. 怎么回事? 我确认 source buffer 中是打开了 evil mode 的. 为什么起作用的不是 evil-mode 的 keybindings, 而是 realgud/common/cmds.el? spacemacs 关于 debug.el 的设置为什么又不起作用?

我会纠结这个问题是因为这个现象让我不确定如果某个 map 与 evil-mode map 发生冲突的情况, 比如 edebugger 再比如这里的 realgud, 我明明有时候感觉起作用的是 evil-mode (比如 edebugger, 以及最开始我没用 spacemacs 直接用 package-install 安装 realgud 后), 但此刻表现出来的却是 realgud 起作用.

补充: 看起来好像并不是 realgud:shortkey-mode-map 优先于 evil-mode, 比如 n 这个 key, 仍然是 evil-mode 中的而不是执行的 realgud:shortkey-mode-map 对应的命令, 所以难道还是 spacemacs 的设置起了作用? 但是 b 就很奇怪, spacemacs 这段代码明明没有定义 b, 只定义了 bb.

原因在于 evilified-state-evilify-map 这个宏: evil-evilified-state.el

它会将指定map下大部分绑定都转化成evil状态下的绑定,这里具体的evil状态就是spacemacs自定义的一个状态: evilified ,于是包括 realgud:shortkey-mode-map 下按键 b 的绑定也被转换成 evilified b ,进而在 evilified 状态下按 b 也会触发 realgud:cmd-break ,具体代码看 evilified-state-evilify-mapevilified-state--evilify-event 的调用。

Spacemacs文档中有对 evilified-state-evilify-map 宏的基本功能的描述: Evilified buffers ,但是它描述的不够完整,没有提到其他正常绑定也被会转换成 evilified 状态下绑定这件事。

至于Emacs下按键优先级这件事,以及如何处理evil-mode和其他绑定的冲突,是件比较繁琐的事情, 这里你首先得完整看完 Keymaps 这一章(Menu相关的可以先跳过),特别是 Searching the Active Keymaps 中对Keymap搜索优先级的总览以及各章节的细节,接着你得知道evil-mode、company-mode等包是在 emulation-mode-map-alists 这层的,evil-mode在 emulation-mode-map-alists 这一层又添加了自己的一套Keymap层级,具体你可以参考noctuid写的 evil-guide ,里面有很详细的分析以及告诉你需要注意的各种坑,最后你可以参考下 evil-collection 是如何对各种包的按键绑定进行适配的,特别是 evil-collection-magit.el ,你会发现稍微好用点的适配,是需要很多hack的。。说实话,不会Emacs Lisp,又没有一个包为大量包适配evil绑定,不学Emacs Lisp怎么可能用的舒服(evil-collection有很多包的适配是很原始的)。

1 个赞