aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--evil-commands.el24
-rw-r--r--evil-core.el85
-rw-r--r--evil-integration.el17
-rw-r--r--evil-tests.el11
-rw-r--r--evil-vars.el10
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."