怎样让vim的j/k行移动功能在大多数buffer中(如recentf-open-files)都生效?

我是从vim转到Emacs的,对vim的按键方式依赖较大。 参照山人第二季前10集简单配置了Emacs,发现虽然使用了 evil mode , 但是在有些buffer中vim的motion并不能工作,比如:

  1. list-buffers
  2. agenda view
  3. recenf-dialog

这些mode都使用了 n/p 和 C-n/C-p 实现光标的上下移动。

我做了如下配置,使得buffer-list 和 agenda view里可以使用 j/k 进行光标移动:

;;在buffer list中使j/k键绑定为下/上移一行
(evil-define-key 'normal tabulated-list-mode-map
    (kbd "j") 'next-line
    (kbd "k") 'previous-line) 
;;在agenda view中使j/k键绑定为下/上移一行(与默认的n/p交换)
(require 'org-agenda)
(define-key org-agenda-mode-map "j" 'org-agenda-next-line)
(define-key org-agenda-mode-map "k" 'org-agenda-previous-line)
(define-key org-agenda-mode-map "n" 'org-agenda-goto-date)
(define-key org-agenda-mode-map "p" 'org-agenda-capture)

查阅了 'recentf-open-files所打开的 major mode后我觉得下面的代码可以使得 j/k 移动生效,但是却没有成功:

;;在recentf-dialog中使j/k键绑定为下/上移一行(失败)
(evil-define-key 'normal recentf-dialog-mode-map
     (kbd "j") 'next-line
     (kbd "k") 'previous-line)

我不清楚为什么,请教大家该怎么设置? 我使用如下方式可以让vim的键移动都生效:

 (setq evil-motion-state-modes (append evil-emacs-state-modes evil-motion-state-modes))

但是这样替换量太大了,会使得一些本来好用的键绑定不再生效。 我对lisp还不熟,不知道下面的代码为什么也不行:

(with-eval-after-load 'recentf-dialog
 (setq evil-motion-state-modes (append evil-emacs-state-modes evil-motion-state-modes))
   (setq evil-emacs-state-modes nil)
   )

这个需求在spacemacs体验好像挺好的,不过我想先熟悉一下emacs。

是想改recentf-open-files打开的buffer里的按键还是helm-recentf(SPC f r)呢?
前者的话注意是蓝色的,也就是emacs-state,evil当然改了没用了。后者就不是你改的map了,是helm的某一个。

想改recentf-open-files 蓝色的是什么意思呢?

我打开的 recentf-open-files 是这样的:

我的emacs全部配置放在了coding.net上: https://coding.net/u/ziyuan/p/emacs-config/git/blob/master/init.el

(defun my-recentf-map ()
  "add my keys for recentf-open-files"
  (define-key recentf-dialog-mode-map (kbd "j") 'next-line)
  (define-key recentf-dialog-mode-map (kbd "k") 'previous-line)
  )
(add-hook 'recentf-dialog-mode-hook 'my-recentf-map)

我测了一下似乎可以这样写。hook表示只在打开recentf-dialog的时候设置,也就不影响其他mode的buffer
spacemacs下面evil-normal是黄色,evil-insert绿色,emacs蓝色 (光标颜色) ,我recentf-open-files是蓝色。你用的白板emacs就没这设定了,我搞错了。不过我验证了一下这个buffer里是emacs-state,所以你的肯定也是。

另外有一个问题,我上面这样写是不是把recentf-dialog里面所有state(包括evil)的按键都覆盖了呢?我evil-exit-emacs-state切到evil-state试了一下(切回来是evil-emacs-state),j仍然是evil-next-line,那就没问题吧,evil-state maps remain untouched here~

1 个赞

不对我二了,给recentf-dialog-mode-map加绑定就已经是只会在recentf-dialog-mode里生效了,不会影响其他类型的buffer,这里直接在全局写define-key就行了。。

可以直接使用下面这个宏:

    (evil-add-hjkl-bindings package-menu-mode-map 'emacs)

上面这个宏可以让你在 package-menu-mode 下面使用 hjkl 绑定,同时 package-menu-mode 使用是 emacs-state

1 个赞

就这一句就可以吗?我用了并不行

你是怎么使用的?

:+1:可以啦!是我刚代码写错了。

我现在是这么用的:

(evil-add-hjkl-bindings recentf-dialog-mode-map 'emacs)

这样也行啊,可以接受。不过感觉山人的方式更方便。