1

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 imaps 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 imapping <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.

2

This has nothing to do with the cursor shaping.

The whole reason the timeout settings exist is for the reason you found out in Update-2 -- some keys that you type send a byte sequence that starts with an <Esc>. This includes alt mappings, arrow keys, function keys, mouse interaction, etc.

Since most terminals aren't running in 8-bit mode, you're going to encounter a delay when typing <Esc>. Of course, nothing requires you to wait for that delay. If you just continue typing, you'll perform the same disambiguation that Vim is waiting for.

Since 8-bit mode isn't typical, it follows that mapping <Esc> is a terrible idea. That's going to interfere with more than just <Alt-...> mappings. The common workaround is to do exactly as you've suggested and reduce the timeout. This has even been adopted in defaults.vim.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.