describe-key 给出的按键与实际按键不一致(`interactive "<R>"` 的意义?)

我想写一个函数, 先取消注释选中内容, 执行某动作, 再恢复注释, 我需要知道哪个函数对应 toggle comments. 我用的 spacemacs, 我早就发现 gcc 这个快捷键就是用于 toggle comments 的, 于是我 describe-key gcc, 得到的结果是:

g c runs the command evilnc-comment-operator (found in evil-normal-state-map),
which is an autoloaded interactive Lisp closure in
‘evil-nerd-commenter-operator.el’.

It is bound to SPC ;, g c, M-m ;.

奇怪的地方在这里, 明明这里给出的是 g c 绑定到 evilnc-comment-operator, 但我按键其实 gc 没有完成动作, 必须是 gcc 才可以, 我按 gc 效果会是这样:

也就是 evil 动作没完成的样子.

我的问题是: 为什么 describe-key 给出的是 gc 而不是 gcc 呢? 明明 gc 完成不了动作, gcc 才会完成动作.

gc 对应的函数 evilnc-comment-operator, 前几行是:

(evil-define-operator evilnc-comment-operator (start end type)
  "Comments text from START to END with TYPE."
  (interactive "<R>")

我怀疑这个现象与 <R> 有关, 但在 interactive 的 help 中我没有看到 <R> 的说明, 连 R 的说明也没看到, 只看到 r 的.

我发现这个情况在 evil 很常见, 再比如 dd, describe-key dd 看到的也是:

It is bound to d.

(evil-org-delete BEG END &optional TYPE REGISTER YANK-HANDLER)

evil-org-delete 的定义也是:

(interactive "<R><x><y>")

因为 vim 的按键的逻辑和 emacs 的按键的逻辑是冲突的。emacs 的按键逻辑是一组按键序列就是一个命令,不存在命令的组合的说法。

而在 vim 里面命令是可以组合的,比如 gcap (注释一个段落),gc 对应的是一个 operator,这个 operator 会接收下一个命令,然后对通过下一个命令得到的文本进行操作,这个命令有两种形式, motion 或者 text object, 然后下一个命令是 ap,代表一个段落,是一个 text object。

所以如果你想要查看 evil 有关的快捷键,首先是 operator,你可以直接 describe-key,然后要看 motion 对应的是什么,得去查看 evil-motion-map, evil-outer-textobjects-map, evil-inner-textobjects-map

具体的这些 <R><x><y> 代表什么意思,参考 evil-types.el

1 个赞

vim 的逻辑就是这样,可以是 operation + textobj/motion,也可以是 visual + operation。即先选操作再选对象,或先选对象再选操作。你先选择一个区域再按快捷键 gc 应该也可以,这时就不需要 gcc了。

gc 之后再按 c 这个是要选中当前行作为范围。大概逻辑就是重复按一下绑定快捷键的最后一个键,就会选中当前行。

1 个赞