怎样让 evil 只在 prog-mode下开启

我的想法是只在 prog-mode 下 开启 evil,其它地方都用emacs就好了(evil 的 insert-mode 也用emacs 的默认按键)。 我的第一反应是用hook

(use-package evil
  :ensure t
  :init
  (setq evil-disable-insert-state-bindings t)
  (add-hook 'prog-mode-hook (lambda () (evil-mode 1))))

但是重启后发现 evil 似乎覆盖到整个emacs ,所以我想应该是 (evil-mode 1) 把整个emacs都变evil了,evil-mode似乎只能作用到全局(elisp不很懂,猜测)。

然后我想,把evil 的默认state设为 emacs , 用hook把 prog-mode 的默认 state 设成 normal。

(use-package evil
  :ensure t
  :init
  (setq evil-disable-insert-state-bindings t)
  (setq evil-default-state 'emacs)
  :config
  (evil-mode 1)
  (evil-set-initial-state 'prog-mode 'normal))

但是这样在很多不该有evil的地方他都出现了(比如 info mode 变成了 evil 的 motion state),而且我不知道这样会不会影响到emacs的原生键绑定和一些其他东西。

有什么好的方式可以实现我的想法吗?

(add-hook 'prog-mode-hook (lambda () (evil-local-mode 1)))
1 个赞

我推荐给 evil-initial-state-for-buffer 加 advice,可以按自己的需要魔改。

(defun +evil-initial-state-for-buffer-override (&optional buffer)
  (with-current-buffer (or buffer (current-buffer))
    (if (derived-mode-p 'prog-mode)
        'normal
      'emacs)))

(advice-add 'evil-initial-state-for-buffer
            :override '+evil-initial-state-for-buffer-override)

还是推荐开启 evil-mode,否则全局 markerjump 和终端的 ESC 不能正常工作。

2 个赞

谢谢!看起来工作的很好

全局marker、 jump是指 不同 buffer 之间,如果 有的buffer没开 evil就不可以相互跳转吗。另外emacs 的 jump是指什么,我在终端下用nvim。

marker 小写字母是 buffer 本地的,大写字母是全局的;jumpC-iC-o,你可以关掉 evil-mode 打开 evil-local-mode 测试这些功能能否正常工作。

额 直接调用 set-evil-initial-state 设置每个模式的初始化就可以了?

这个方案是正解。推荐还是全局evil,在某些模式设置为 emacs state。

jump是per window的,可以在不同的buffer之间跳转。

可以,不过工作量很大。evil 的模式选择基于 major-mode 而不是 major-mode 和 parent-modes,也就是说要先清空 evil-*-state-modes,然后把 prog-mode 的所有 child-mode 都设置一遍。

(setq evil-default-state 'emacs)
;; http://bling.github.io/blog/2015/01/06/emacs-as-my-leader-1-year-later/

(with-eval-after-load 'evil
(evil-set-initial-state 'fundamental-mode 'normal)
(evil-set-initial-state 'text-mode 'normal)
(evil-set-initial-state 'prog-mode 'normal)
)

(setq evil-normal-state-modes   nil)
(setq evil-insert-state-modes   nil)
(setq evil-visual-state-modes   nil)
(setq evil-replace-state-modes  nil)
(setq evil-operator-state-modes nil)
(setq evil-motion-state-modes   nil)
(setq evil-emacs-state-modes    nil)

我是这样设置的,感觉不需要额外的设置呀

你说的info mode是motion state,是因为"evil-motion-state-modes"默认有info mode

(setq evil-motion-state-modes nil)

就可以了