Am 07.06.2014 09:45, schrieb Justin M. Keyes:
Hi,
I'm trying to bind a command to the "unused namespace" that happens to start with "c". By "unused namespace" I mean things like "cp" or "co" for which there is no valid text object or motion. In Vim, you can bind "cow" and it does not affect the behavior of "cdw", "ciw", etc, because "o" is not defined as a text object. For example, in unimpaired.vim[1], "cow" toggles word-wrap. I would like to do this in emacs evil, so I tried:
(define-key evil-normal-state-map (kbd "c o w") 'toggle-truncate-lines)
It reports "eval-region: Key sequence c p w starts with non-prefix key c". But I don't want to unbind "c" because then I can't use the evil-change operator.
Something like this is currently not possible. That's because of the way Emacs key-sequences and Evil operators work: The parsing of a key-sequence does not happen when the sequence is complete but in steps. "c" is bound to the command `evil-change`, so when "c" is typed Emacs immediately executes `evil-change` without waiting for further keys (i.e., the decision which command has to be executed is taken as soon as "c" is typed--that's also the reason why you cannot define a command "c" and another "cp" in the same keymap: a keymap is a lookup-table and "c" can either be mapped to a command or to another keymap, not both). What Evil does is to manually wait for further keys before the body of `evil-change` is executed. This happens in the `interactive` form of `evil-change` (and each other operator--in fact, the magic behind `evil-define-operator` is to automatically generate an appropriate interactive form). This second key-sequence is looked up in `evil-operator-state-map` (and inherited keymaps like `evil-motion-state-map`). If the sequence completely defines a (motion) command, this command is executed and used to build the range parameter for the operator. Then the body of the operator is executed (with that range). So there is a real limitation of key sequence in Evil. What you could to, however, is to provide a "fake" motion, that executes whatever you want but does not execute the operator's body: ``` (defun my-command () (interactive) (do-what-you-want) (setq evil-inhibit-operator t)) (define-key evil-operator-state-map "p" 'my-command) ``` The important thing is the last line, which causes Evil to not execute the operators body. However, this would cause "p" to work with *any* operator. But you're free to do whatever you want in your command, so you could dispatch depending on the current operator: ``` (defun my-command () (interactive) (case evil-this-operator (evil-change (do-what-you-want)) (evil-delete (do-something-else)) (t (keyboard-quit))) (setq evil-inhibit-operator t)) ```
I tried defining a custom operator, but after looking at the evil source code I couldn't figure out how to hook into evil-change to preserve its behavior while listening for "o" and then routing it somewhere else.
Maybe you can do something with advice tricks, too, or some temporary keymaps together with `unread-command-events`. The suggestion above is only one possibility. But as I said, there is no direct support for what you want because of Emacs keymaps and/or the current implementation. Best regards, Frank