mode hook的先后顺序

作为初学者,有一些lisp的开发经验,但还没系统学习过emacs lisp。有个问题不是很清楚,我在term-mode-hook中绑定了C-a键,但总是被evil-commands.el的evil-paste-last-insertion这个函数抢先绑定了。不论我把(evil-mode t)写在哪里,都被它给绑定了。希望哪位朋友给简单解释一下。

你没说你是怎么绑定 C-a 的(用的是哪一个 Keymap),两个同样的按键到底哪一个生效,取决于它们所在 Keymap 的优先级,比如 Minor Mode 的 Keymap 优先于 Major Mode 的 Keymap。

multi-term中,我在term-raw-map里绑定了C-a,主模式是Term,被evil-insert-state-map的C-a覆盖了。我没有特意针对multi-term加evil的模式,只是在init.el文件里写了(evil-mode t)。这种情况下,我如何从multi-term去掉evil的模式?

我不能确定你所遇到的问题,一来 M-x term 是个复杂的 Major Mode,它有 Char Mode 和 Line Mode 两种输入模式,分别使用不同的 Keymap;二来我没用过 Evil 和 multi-term。

evil-insert-state-map 是应该 Evil Minor Mode 提供的,优先于 Term Major Mode 的 Keymap。所以如果你可以不需要这个 C-a 的话,试试直接解绑之(用 define-key 设置到 nil)。

好的,我试一下,非常感谢你的答复!

evil的keymap优先级非常高,高于major-mode和minor-mode

evil 有这么多 *-entry-hook / *-exit-hook:

evil-emacs-state-entry-hook
evil-emacs-state-exit-hook
evil-insert-state-entry-hook
evil-insert-state-exit-hook
evil-motion-state-entry-hook
evil-motion-state-exit-hook
evil-normal-state-entry-hook
evil-normal-state-exit-hook
evil-operator-state-entry-hook
evil-operator-state-exit-hook
evil-replace-state-entry-hook
evil-replace-state-exit-hook
evil-visual-state-entry-hook
evil-visual-state-exit-hook

普通的 mode-hook 在你打开 buffer 的时侯执行一次。而 evil 的这些 hook,在你后续的编辑过程中随时会触发,也就是说它总在最后执行,所以你设置的快捷键会被覆盖。

正确的设置方式:

  • 修改所有模式在 normal-state 下的快捷键

      (define-key evil-normal-state-map (kbd "zm") 'hs-hide-level)
    
  • 修改特定模式在 insert-state 下的快捷键

      (evil-define-key 'insert web-mode-map (kbd "RET") 'web/newline-and-indent)
2 个赞

好的,我试一下,若有不明白的地方,我再请教。

非常感谢,我已经按照你给的方式解决了。

上面注释掉的,是我以前的写法,下面两行是你给的解决办法。虽然效果一样,但你的更好。

evil的热键绑定真是个麻烦的事,我在edebug mode下操作,edebug的热键被evil优先绑定了。

所以,我加了下面这段代码

(add-hook 'edebug-mode-hook
          (lambda ()
            (let ((edebug-cmd-list '("S" "SPC" "n" "t" "T" "g" "c" "C" "G" "b" "u" "x" "B" "?")))
              (dolist (cmd edebug-cmd-list)
                (define-key evil-motion-state-map (kbd cmd) nil))))) ; 禁止evil中的热键

但这样的话,再打开别的文件,在edebug-mode-hook中禁止的evil热键,不能再使用了。大家有别的办法吗?

或者一次性把evil的所以热键前追加一个prefix,比如C-e或SPC,能做到吗?

我是从VIM转过来的,操作习惯一时半会儿还改不了。

你可以考虑一下使用evil-collection,很多常用的包都已经有人帮你绑定完了,剩下的可以根据自己的喜好微调。 用evil的话,最好用evil-define-key去给mode-map做绑定,比如(evil-define-key 'normal 'edebug-mode-map “n” 'edebug-next-mode)

刚才试用了一下evil-collection

(use-package evil
  :ensure t
  :init
  (setq evil-want-integration t) ;; This is optional since it's already set to t by default.
  (setq evil-want-keybinding nil))
(evil-mode t)

(use-package evil-collection
  :after evil
  :ensure t
  :custom (evil-collection-setup-minibuffer t)
  :config
  (evil-collection-init))

不太会用了,比如magit,我以前用的是evil-magit,用evil-collection后,magit里 hjkl 键的功能没有了,难道我还得把evil-magit也安装上吗?我看里面有evil-collection-magit.el呀。

你可以选择性加载,比如:

(use-package evil-collection
  :after evil
  :ensure t
  :config
  (with-eval-after-load 'ibuffer (evil-collection-init 'ibuffer))
  (with-eval-after-load 'ediff (evil-collection-init 'ediff))
  (with-eval-after-load 'imenu-list (evil-collection-init 'imenu-list)))

magit,我用的还是evil-magit,没用evil-collection

好的,谢谢,我已经按照你的方式改了,挺好用的。:blush:

这样不分major-mode来绑结果自然是这样。如楼上所说,用evil-define-key

用evil需要多了解一点binding相关的内容,推荐阅读:evil-guide、general.el的文档

非常感谢!要看的东西还挺多。:grinning:

给大家拜个早年!

新年明けましておめでとうございます!

用evi真是折翼的天使,装好evi后,对每一个新的mode可能都要看一看是不是兼容,而不像vim真的就是原生支持

哪里不兼容,evil-emacs-state了解一下【滑稽

1 个赞

我的兼容意思是看evil的按键是否生效,谁覆盖谁的问题,大部分情况是evil的快捷键起作用。但也有例外,就像magit,进入后evil的hjkl就不是移动命令了,需要自己根据mode进行专门的配置,相当于又折腾快捷键配置

下午我按上面的配置,在mac上好好的,在Linux上却不好使了,edebug的热键还是被evil覆盖,看来得好好研究一下了。