execute-kbd-macro和执行对应函数的诡异微小区别(one works, the other doesn't)

evil默认<是shift left,同时如果是visual state,在shift一步后会退出visual,通常我们会希望按一下<之后能保持visual,这样可以按多下:

(general-define-key
 :states '(visual)
 ">" (lambda () (interactive) (call-interactively 'evil-shift-left) (evil-visual-restore))
 )

但是这样是不成功的,按下<之后仍然会退出visual,无论是(evil-visual-restore)还是(call-interactively 'evil-visual-restore)都一样。于是我去看了一下spacemacs的做法,发现它有个函数,最后整理下来的结果是

...
 "<" (lambda () (interactive) (call-interactively 'evil-shift-left) (execute-kbd-macro "gv"))
...

这样写是会正常工作的。可是(evil-visual-restore)(execute-kbd-macro "gv")有什么区别呢?它们调用的是同一个函数啊?

一点不太相关的内容:本来按evil提供的设施应该(evil-set-command-property 'evil-shift-left :keep-visual t)就可以了,但不行,不过这是另一个话题了。

直接 restore 恢复的是它前一个状态,即 shift:

+- visual ---------+
| +- lambda -----+ |
| | shift <----. | |
| | restore ---' | |
| +-------------+  |
+------------------*

execute-kbd-macro 发送的两个按键在 lambda 外层生效了,所以它恢复的也就是 lambda 之前的状态:

+- visual ---------+ <-.
| +- lambda -----+ |   |
| | shift        | |   |
| | "gv"    -----------'
| +-------------+  |
+------------------*

就好像,坐在车上推车,跟往下跳的同时推一把,效果大不同。