如何在evil 的Insert模式定义jk 之类的快捷键

我尝试去看了一下evil-escape 的代码,但那个太复杂没完全看懂。 我想只到怎么delay > 0.1s 就输出 原来的 j 而不是卡在输入提示上 k -> evil-normal-state 我想知道相当的文档在哪?

只会evil-escape,

;; {{ https://github.com/syl20bnr/evil-escape
(setq-default evil-escape-delay 0.3)
(setq evil-escape-excluded-major-modes '(dired-mode))
(setq-default evil-escape-key-sequence "kj")
;; disable evil-escape when input method is on
(evil-escape-mode 1)
;; }}

如果是别的插件我就不懂了。

general.el 是这样:

  (general-def 'insert
	"k" (general-key-dispatch 'self-insert-command
		  :timeout 0.2
		  "j" 'evil-normal-state)
	"j" (general-key-dispatch 'self-insert-command
		  :timeout 0.2
		  "k" 'evil-normal-state))

本质上好象是借助key-chord

只绑定 jk 的话,这样:

(global-set-key [key-chord ?j ?k] #'evil-normal-state)
(setq input-method-function
      #'(lambda (first-char)
          (if (and (memq first-char '(?j ?k))
                   (not (sit-for 0.05 'no-redisplay)))
              (let* ((input-method-function nil)
                     (next-char (read-event)))
                (if (and (memq next-char '(?j ?k))
                         (not (eq first-char next-char)))
                    (list 'key-chord ?j ?k)
                  (push next-char unread-command-events)
                  (list first-char)))
            (list first-char))))

通用性更广一点的 key-chord ,这个实际上是从 key-chord 精简而来,用法很简单,将下面代码单独放在一个文件里 require 了之后, (key-chord-define "jk" #'evil-normal-state) 即可,不支持两个键位相同以及键盘宏中使用,想用更多功能还是直接使用 key-chord 比较好。

(defvar key-chord-last-unmatched nil)

;;;###autoload
(defun key-chord-define (keys command)
  "定义由两个连续按键启动的 COMMAND.
KEYS: string 或 vector of two elements, elements: 32~126 之间的 ascii codes."
  ;; Exotic chars in a string are >255 but define-key wants 128..255 for those
  (setq input-method-function #'key-chord-input-method)
  (let ((key1 (logand 255 (aref keys 0)))
        (key2 (logand 255 (aref keys 1))))
    (global-set-key (vector 'key-chord key1 key2) command)
    (global-set-key (vector 'key-chord key2 key1) command)))

(defsubst key-chord-lookup-key (key)
  "查找 KEY 的非数字定义,为数字则返回 nil."
  (let ((res (lookup-key (current-global-map) key)))
    (if (numberp res)
        nil
      res)))

(defun key-chord-input-method (first-char)
  "FIRST-CHAR 为每次输入时字符."
  (if (and (not (eq first-char key-chord-last-unmatched))
           (key-chord-lookup-key (vector 'key-chord first-char)))
      (if (sit-for 0.05 'no-redisplay)
          (progn
            (setq key-chord-last-unmatched nil)
            (list first-char))
        ;; else input-pending-p
        (let* ((input-method-function nil)
               (next-char (read-event)))
          (if (key-chord-lookup-key (vector 'key-chord first-char next-char))
              (list 'key-chord first-char next-char)
            ;; 吐出 (read-event) 吞掉的字符?
            (setq unread-command-events (cons next-char unread-command-events))
            (when (eq first-char next-char)
              (setq key-chord-last-unmatched first-char))
            (list first-char))))
    ;; else no key-chord keymap
    (setq key-chord-last-unmatched first-char)
    (list first-char)))

(provide 'key-chord)
1 个赞

这个代码用不了,我直接下了key-chord了,可以用key-chord解决了,但是有了key-chord为什么还有evil-escape ? 它们有什么不同 ? 我明白了evil-escape的用途了,key-chord会影响normal 和 viusual 模式,会让它变慢,如何只在insert模式定义这个快捷键?

没有用过 evil-escape,不清楚有什么区别。

只在insert模式定义:

 (key-chord-define evil-insert-state-map "jk" #'evil-normal-state)
2 个赞

就是这个主题贴来着,好像也是楼上这位仁兄回答的 :rofl:

我推荐用general和keychord配合,方便舒服

1 个赞

试了下evil-escape,能用jk退出minibuffer和一些special-mode的buffer,比用general.el方便点

我想加点别的比如用 jj 来代替emacs 的 C-f

  (general-def 'insert  C-j对应的keymap
	"j" (general-key-dispatch 'self-insert-command
		  :timeout 0.2
		  "j" 'C-j原来绑定的函数)

或者用general-translate-key,建议看下general.el的文档,doom-emacs用来绑定按键的宏map!就是基于general.el的,功能很多

PS:这里绑定到evil-insert-state-map,实际上根据需要可以绑定到其他evil-state对应的map