I set a couple terminal options so that Vim changes the cursor shape to a vertical bar when I enter Insert mode, an underbar for Replace mode, and a block when I return to Normal mode:
let &t_SI="\<Esc>[6 q"
let &t_SR="\<Esc>[4 q"
let &t_EI="\<Esc>[0 q"
If 'ttimeoutlen'
has a high enough setting, there's a noticeable delay when leaving Insert mode, because you type Escape and Vim waits to see if it was the beginning of an <Esc>[0 q
sequence. It waits 'ttimeoutlen'
milliseconds before deciding the <Esc>
was an actual Escape keypress.
I usually keep 'ttimeoutlen'
set at 5, so it's not really noticeable. But I was also curious to try a "sledgehammer" workaround:
inoremap <Esc> <Esc><Esc>
and it works. Even more interesting is this works as well:
inoremap <Esc> <Esc>
I guess because Vim knows the right-hand-side of a mapping is the result of a keypress, not an input keycode, so it doesn't apply 'ttimeoutlen'
(but would apply 'timoutlen'
if you had other imap
s that started with <Esc>
).
It seems a little weird, but I'm having a hard time thinking of any downside this approach could have. I plan on keeping my 'ttimeoutlen'
low anyway, but maybe this could shave a couple extra milliseconds off the delay? Not that I'll actually notice :P
Is there any reason not to do this? What could it break?
Or is there a better solution altogether that I've missed? I suspect the answer is to just leave 'ttimeoutlen'
set to a low number and forget about it, but I am curious if anyone else has found different solutions.
Update:
I found a caveat to this approach. The imap
effects escaping from Insert and Replace modes, and you can do the same for Visual mode with vmap
, but none of these affects the timeout when canceling an r
command in Normal mode using Escape.
It still seems like a useful hack -- escaping from an r
command is a corner case -- but it's not a full solution.
Update-2: I found what this breaks. If you want to use a Meta/Alt key in an imap
, e.g. inoremap <M-d> foo
, the inoremap <Esc> <Esc>
breaks that functionality because <M-d>
consists of an Escape byte (0x1b
) followed by the D byte. To take it to the extreme, imagine you'd defined a mapping:
inoremap <M-d>d bar
Typing <M-d>d
in insert mode would end up deleting the current line! That's a corner case, but mapping Meta/Alt keys is not, so this is enough to convince me that imap
ping <Esc>
to itself is a bad idea. It is, after all, a hack.
The above won't apply if your terminal runs in 8-bit mode, since Alt/Meta will be represented by the high-bit instead of a leading Esc byte, but on 7-bit terminals (gnome-terminal, alacritty, etc.) it does apply.