diff options
| -rw-r--r-- | evil-commands.el | 24 | ||||
| -rw-r--r-- | evil-core.el | 85 | ||||
| -rw-r--r-- | evil-integration.el | 17 | ||||
| -rw-r--r-- | evil-tests.el | 11 | ||||
| -rw-r--r-- | evil-vars.el | 10 |
5 files changed, 67 insertions, 80 deletions
diff --git a/evil-commands.el b/evil-commands.el index f80f5fb..ed05e32 100644 --- a/evil-commands.el +++ b/evil-commands.el @@ -3637,30 +3637,6 @@ if the previous state was Emacs state." (evil-change-to-previous-state))) (setq evil-execute-in-emacs-state-buffer)))) -;; TODO: this will probably not work well with the repeat-system. -(evil-define-command evil-esc (arg) - "Wait for further keys within `evil-esc-delay'. -Otherwise send [escape]." - :repeat ignore - (interactive "P") - (if (sit-for evil-esc-delay t) - (progn - (push 'escape unread-command-events) - (when defining-kbd-macro - ;; we need to replace the ESC by 'escape in the currently - ;; defined keyboard macro - (evil-save-echo-area - (end-kbd-macro) - (setq last-kbd-macro (vconcat last-kbd-macro [escape])) - (start-kbd-macro t t)))) - (push last-command-event unread-command-events) - ;; preserve prefix argument - (setq prefix-arg arg)) - ;; disable interception for the next key sequence - (evil-esc-mode -1) - (setq this-command last-command) - (add-hook 'pre-command-hook #'evil-turn-on-esc-mode nil t)) - (defun evil-exit-visual-and-repeat (event) "Exit insert state and repeat event. This special command should be used if some command called from diff --git a/evil-core.el b/evil-core.el index 506b422..0419212 100644 --- a/evil-core.el +++ b/evil-core.el @@ -105,6 +105,8 @@ ;;; Code: +(declare-function evil-emacs-state-p "evil-states") + (define-minor-mode evil-local-mode "Minor mode for setting up Evil in a single buffer." :init-value nil @@ -180,10 +182,12 @@ To enable Evil globally, do (evil-mode 1)." ;; changed back by `evil-local-mode' (setq-default major-mode 'turn-on-evil-mode) (ad-enable-regexp "^evil") - (ad-activate-regexp "^evil")) + (ad-activate-regexp "^evil") + (with-no-warnings (evil-esc-mode 1))) (setq-default major-mode 'fundamental-mode) (ad-disable-regexp "^evil") - (ad-update-regexp "^evil"))) + (ad-update-regexp "^evil") + (with-no-warnings (evil-esc-mode -1)))) (put 'evil-mode 'function-documentation "Toggle Evil in all buffers. @@ -531,27 +535,54 @@ may be specified before the body code: ,@body)) ',keymap))) -;; Intercept the ESC event when running in the terminal. This allows -;; keys that use "ESC" as a prefix key, such as "M-x". If "ESC" is -;; immediately followed by another key, or another key is pressed -;; within `evil-esc-delay', the prefixed key sequence is sent. -;; Otherwise only [escape] is sent. -(evil-define-keymap evil-esc-map - "Keymap for intercepting ESC." - :intercept t) - -(defun evil-turn-on-esc-mode () - "Enable interception of ESC." - (unless (eq this-command #'evil-esc) - (evil-esc-mode 1) - (remove-hook 'pre-command-hook #'evil-turn-on-esc-mode t))) -(put 'evil-turn-on-esc-mode 'permanent-local-hook t) - -;; `evil-esc' is bound to (kbd "ESC"), while other commands -;; are bound to [escape]. That way `evil-esc' is used only when -;; (kbd "ESC") and [escape] are the same event -- i.e., when -;; running Emacs in the terminal. -(define-key evil-esc-map (kbd "ESC") 'evil-esc) +;; The ESC -> escape translation code has been provided by Stefan +;; Monnier in the discussion of GNU Emacs bug #13793. +(defun evil-esc-mode (&optional arg) + "Toggle interception of \\e (escape). +Enable with positive ARG and disable with negative ARG. + +When enabled, `evil-esc-mode' modifies the entry of \\e in +`input-decode-map'. If such an event arrives, it is translated to +a plain 'escape event if no further event occurs within +`evil-esc-delay' seconds. Otherwise no translation happens and +the ESC prefix map (i.e. the map originally bound to \\e in +`input-decode-map`) is returned." + (cond + ((or (null arg) (eq arg 0)) + (evil-esc-mode (if evil-esc-mode -1 +1))) + + ((> arg 0) + (unless evil-esc-mode + (setq evil-esc-map (lookup-key input-decode-map [?\e])) + (define-key input-decode-map [?\e] + `(menu-item "" ,evil-esc-map :filter ,#'evil-esc)) + (setq evil-esc-mode t))) + ((< arg 0) + (when evil-esc-mode + (define-key input-decode-map [?\e] evil-esc-map))))) + +(defun evil-esc (map) + "Translate \\e to 'escape if no further event arrives. +This function is used to translate a \\e event either to 'escape +or to the standard ESC prefix translation map. If \\e arrives, +this function waits for `evil-esc-delay' seconds for another +event. If no other event arrives, the event is translated to +'escape, otherwise it is translated to the standard ESC prefix +map stored in `input-decode-map'. If `evil-inhibit-esc' is +non-nil or if evil is in emacs state, the event is always +translated to the ESC prefix. + +The translation to 'escape happens only if the current command +has indeed been triggered by \\e. In other words, this will only +happen when the keymap is accessed from `read-key-sequence'. In +particular, if it is access from `define-key' the returned +mapping will always be the ESC prefix map." + (if (and (not evil-inhibit-esc) + evil-local-mode + (not (evil-emacs-state-p)) + (equal (this-single-command-keys) [?\e]) + (sit-for evil-esc-delay)) + [escape] map)) (defun evil-state-p (sym) "Whether SYM is the name of a state." @@ -713,7 +744,6 @@ See also `evil-mode-for-keymap'." (when (setq map (evil-intercept-keymap-p map state)) (push (cons (evil-mode-for-keymap map t) map) result))) (setq result (nreverse result)) - (add-to-list 'result `(evil-esc-mode . ,evil-esc-map)) result)) (defun evil-set-auxiliary-keymap (map state &optional aux) @@ -928,7 +958,6 @@ the local keymap will be `evil-test-state-local-map', and so on. (exit-hook (intern (format "%s-exit-hook" toggle))) (modes (intern (format "%s-modes" toggle))) (predicate (intern (format "%s-p" toggle))) - (intercept-esc t) arg cursor-value enable entry-hook-value exit-hook-value input-method key message-value suppress-keymap tag-value) ;; collect keywords @@ -954,8 +983,6 @@ the local keymap will be `evil-test-state-local-map', and so on. (setq enable arg)) ((eq key :input-method) (setq input-method arg)) - ((eq key :intercept-esc) - (setq intercept-esc arg)) ((eq key :suppress-keymap) (setq suppress-keymap arg)))) @@ -1029,7 +1056,6 @@ If ARG is nil, don't display a message in the echo area.%s" name doc) (let ((evil-state ',state)) (run-hooks ',exit-hook) (setq evil-state nil) - (evil-esc-mode -1) (evil-normalize-keymaps) ,@body)) (t @@ -1044,9 +1070,6 @@ If ARG is nil, don't display a message in the echo area.%s" name doc) ',state evil-previous-state) (let ((evil-state ',state)) (evil-normalize-keymaps) - (if ,intercept-esc - (evil-esc-mode 1) - (evil-esc-mode -1)) (if ',input-method (activate-input-method evil-input-method) (deactivate-input-method)) diff --git a/evil-integration.el b/evil-integration.el index 9dea69e..73a0879 100644 --- a/evil-integration.el +++ b/evil-integration.el @@ -74,23 +74,6 @@ ;;; key-binding -;; disable evil-esc-mode during a call to key-binding -(defadvice key-binding (around evil activate) - (let (evil-esc-mode) - ad-do-it)) - -;; disable evil-esc-mode during the read of a key-sequence -;; TODO: should we handle the special ESC-delay, too? -(defadvice read-key-sequence (around evil activate) - (let (evil-esc-mode) - ad-do-it)) - -;; disable evil-esc-mode during the read of a key-sequence -;; TODO: should we handle the special ESC-delay, too? -(defadvice read-key-sequence-vector (around evil activate) - (let (evil-esc-mode) - ad-do-it)) - ;; Calling `keyboard-quit' should cancel repeat (defadvice keyboard-quit (before evil activate) (when (fboundp 'evil-repeat-abort) diff --git a/evil-tests.el b/evil-tests.el index 2c04e42..55c57de 100644 --- a/evil-tests.el +++ b/evil-tests.el @@ -542,8 +542,7 @@ the end of the execution of BODY." (defun evil-test-state-keymaps (state) "Verify that STATE's keymaps are pushed to the top" (let ((actual (evil-state-keymaps state)) - (expected `((evil-esc-mode . ,evil-esc-map) - (,(evil-state-property state :local) + (expected `((,(evil-state-property state :local) . , (evil-state-property state :local-keymap t)) (,(evil-state-property state :mode) . ,(evil-state-property state :keymap t))))) @@ -551,8 +550,7 @@ the end of the execution of BODY." (cond ((eq state 'operator) (setq expected - `((evil-esc-mode . ,evil-esc-map) - (evil-operator-shortcut-mode + `((evil-operator-shortcut-mode . ,evil-operator-shortcut-map) (evil-operator-state-local-minor-mode . ,evil-operator-state-local-map) @@ -571,10 +569,7 @@ the end of the execution of BODY." (should (equal actual expected)) (dolist (map actual) (setq map (cdr-safe map)) - (should (keymapp map)) - ;; Emacs state disables `evil-esc-map' - (unless (and (eq state 'emacs) (eq map evil-esc-map)) - (should (memq map (current-active-maps)))))))) + (should (keymapp map)))))) (ert-deftest evil-test-exit-normal-state () "Enter Normal state and then disable all states" diff --git a/evil-vars.el b/evil-vars.el index a1fa25c..bba1e39 100644 --- a/evil-vars.el +++ b/evil-vars.el @@ -278,6 +278,16 @@ This should be a regexp set without the enclosing []." :type 'number :group 'evil) +(defvar evil-esc-mode nil + "Non-nil if `evil-esc-mode' is enabled.") + +(defvar evil-esc-map nil + "Original ESC prefix map in `input-decode-map'. +Used by `evil-esc-mode'.") + +(defvar evil-inhibit-esc nil + "If non-nil, the \\e event will never be translated to 'escape.") + (defcustom evil-show-paren-range 0 "The minimal distance between point and a parenthesis which causes the parenthesis to be highlighted." |
