You guys always find strange situations I've never thought off ... ;) On Tue, May 29, 2012 at 11:41:32AM -0400, York Zhao wrote:
"\ <char>" is a good tip for inputing one char without entering insert mode, however, it is not dot repeatable. I used to have my own function bound to SPC to insert one char and was repeatable, but I'm now binding SPC to ace-jump which I found to be even more useful. Is it possible to make "\<command>" repeatable?
No, not easily. There are two reasons for this. The first one is that Emacs state is not repeatable by intention. When Evil switches to Emacs state, then evil is essentially turned off (as far as it could be). This means the repeat system ignores all commands in Emacs state completely. That's because Emacs state is, well, plain Emacs, and it is very difficult to do repeat-recording right if there is no distinction between different states like normal state and insert state. Furthermore almost all commands active in Emacs state are non-Evil commands, which makes it even more difficult (they usually do not carry appropriate :repeat attributes). Furthermore the one-shot Emacs state, i.e., the command `evil-execute-in-emacs-state', essentially simply switches to Emacs state and installs a post-command-hook that returns to the previous state after the next command. So there is no easy way for the repeat system to distinguish the one-shot emacs state from the "real" emacs state. The second problem is that the repeat system relies on post-command-hook, too, in this interferes easily with the post-command-hook of `evil-execute-in-emacs-state'. A compromise could be to use insert-state instead of emacs-state. Both states are almost equivalent except for the repeat-recording and a few key-bindings (especially the ESC key) in `evil-insert-state-map' (In fact, in almost all situations insert state could be used whenever emacs state is desired). Still, the post-command-problem needs to be respected. The following command can be used (highly untested!!!) to execute a single command in insert state (it's almost equivalent to `evil-execute-in-emacs-state' except for the two lines dealing with the repeat system). (evil-define-command evil-execute-in-insert-state (&optional arg) "Execute the next command in Insert state." (cond ((called-interactively-p 'any) (add-hook 'post-command-hook #'evil-execute-in-insert-state t) (evil-insert 1) (evil-echo "Switched to Insert state for the next command ...")) ((not (eq this-command #'evil-execute-in-insert-state)) (remove-hook 'post-command-hook 'evil-execute-in-insert-state) (evil-change-to-previous-state) ;; ensure the command is recorded if we return to normal state (when (evil-normal-state-p) (evil-repeat-stop))))) (define-key evil-normal-state-map "\\" 'evil-execute-in-insert-state) One could also clear `evil-insert-state-map' temporarily to make insert-state in this special situation even more like emacs state. An alternative could be to implement `evil-execute-in-insert-state' or `evil-execute-in-emacs-state' by directly reading the next command with `read-key-sequence' and to call the appropriate binding directly, i.e., something like (evil-define-command evil-execute-in-emacs state () (let (evil-local-mode) (let ((key (read-key-sequence ""))) ... (call-interactively (key-binding key)) ... ))) This could probably be much more robust (no post-command-hook magic necessary), but I've never thought of this (there are certainly a lot of other problems with this approach). Frank