emacs-evil / evil

The extensible vi layer for Emacs.
GNU General Public License v3.0
3.34k stars 282 forks source link

key-translation-map not honored in Evil O state #177

Open TheBB opened 12 years ago

TheBB commented 12 years ago

Originally reported by: epich (Bitbucket: epich, GitHub: epich)


Background:

Because C-c is one way of escaping in Vim, and because it is more ergonomic than C-g, I aim to use it for escaping insert state and keyboard-quit. I use this in my .emacs .

(defun my-esc (prompt)
  "Functionality for escaping generally.  Includes exiting Evil insert state and C-g binding. "
  (cond
   ((or (evil-insert-state-p) (evil-motion-state-p)) [escape])
   ;; This is the best way I could infer for now to have C-c work during evil-read-key.
   ((eq overriding-terminal-local-map evil-read-key-map) (keyboard-quit) (kbd ""))
   (t (kbd "C-g"))))
(define-key key-translation-map (kbd "C-c") 'my-esc)
(set-quit-char "C-c")

(As an aside, I've also created: (define-key evil-motion-state-map "cc" mode-specific-map) so I have my own means of getting the usual keymap bound to C-c.)

I've found this works in all cases except when I'm in the Operator Pending state.

Problem details:

When I do: d or = I enter the operator pending state and find C-g successfully exits.

However, I find that when I use C-c instead of C-g, it doesn't keyboard-quit. The output in the minibuffer indicates it is using C-c for key lookup and finding it bound to another keymap (presumably the global one). Why is the key-translation-map not translating the C-c to C-g before the key lookup in this Evil state?

Workaround:

I get the behavior I seek when I put this in my .emacs: (define-key evil-operator-state-map (kbd "C-c") 'keyboard-quit).


TheBB commented 12 years ago

Original comment by Frank Fischer (Bitbucket: lyro, GitHub: lyro):


Maybe, but there are probably some difficulties. First, evil advices read-key-sequence for some recording in the repeat system so there may be some interference. Second, using read-event allows to handle the escape-key (in terminals) specifically. Using read-key-sequence instead would require some other tricks because it only returns complete key sequences (one would have to add a special command bound to ESC to intercept the escape key and possibly re-read to complete input sequence in case of another event arriving, i.e. a M- combination. Maybe the evil-esc can be used, but I don't know.)

Another possibility would be to stay with read-event but do the translation manually. But this is not necessarily easier to do right.

TheBB commented 12 years ago

Original comment by epich (Bitbucket: epich, GitHub: epich):


I looked it over a little and found evil-read-motion calls evil-keypress-parser, then reads events iteratively using read-event. I put (read-event) in scratch and evaluated it. Inputting C-c returned 3 in the minibuffer and C-g quit the input. The Elisp manual (http://www.gnu.org/software/emacs/manual/html_mono/elisp.html#Translation-Keymaps) says that read-key-sequence uses the key-translation-map. I put (read-key-sequence) in scratch and evaluated it. Whether I type C-c or C-g, I see "^G" displayed in the minibuffer. Would read-key-sequence be appropriate for Evil to use in operator pending state?

TheBB commented 12 years ago

Original comment by Frank Fischer (Bitbucket: lyro, GitHub: lyro):


Operator state is somehow special. When a command is called its interactive statement is responsible for getting the motion. This implies that the key sequence for the motion is read while the command is about being executed. In order to do this evil reads the key sequence manually and translates it using the currently active keymaps. I do not know for sure but it may be possible that this approach does not respect key-translation-map, which would explain the problem (if you're interested, the corresponding code is in the function evil-read-motion in file evil-common.el)