I would like to press physical Esc key on my keyboard only once to exit insert mode & enter normal mode, irrespective of other usual settings in .vimrc
. With my .vimrc
settings, I always need to press Esc key twice to fully exit insert mode. With same .vimrc
loaded in neovim, I just need to press Esc once to exit normal mode.
As a test/proof, try something like: :imap <Esc> <Nop>
in vim and neovim; enter insert mode and press arrow or mouse keys. Cursor would scroll correctly in neovim, but in vim we will see partial escape sequences being appended to where we started scrolling.
The solution is to decouple physical Escape key on keyboard from escape sub-sequence ^[
, and vim can then (like neovim) detect Escape key on keyboard to always enter normal mode from insert mode on single keypress. This decoupling could also allow remapping physical Escape key to other keys (again like neovim one source)
Things I tried (TL;DR): I have tried many possible workarounds (like mapping F1 key to <Esc><Esc>
), but they are all ugly IMHO (F1 is shared with screen brightness on my computer, and one keyboard I have doesn't even have dedicated function keys (requires pressing two keys)). Other trials like inoremap <Esc> <Esc><Esc>
, make rest of the keys that generate some escape sequence like ^[
dangerous (as they write spurious codes to the buffer). Yet another solution I tried, successfully moves vim out of insert mode on pressing escape once, but pressing any arrow keys/ delete/mouse keys also exits it out of insert mode. The popular inoremap jj <Esc>
moves the cursor to left by one position anytime I press j; even if it worked I would never set this. In short there seems to press Esc key once, and exit insert mode once a user has some reasonable .vimrc
file.
Given Vim is modal, and users most often move between insert and normal mode, it is worth the optimization.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.
You can do this by putting the terminal in 8-bit mode. Then instead of ESC [ it will send the one byte CSI character. No "escape sequences" will then start with the ESC byte.
Problem is that the tendency is that terminals use the ESC prefix for meta. That's a terrible choice. It works fine most of the time, which is why users tend to do this, but it always causes a problem eventually.
Check your options for timeouts, you probably have ttimeoutlen set to a larger number. For most situations the value 100 (as it's set in defaults.vim) works well.
@brammool Thanks! I had set notimeout
& given by default ttimeout
is off, my settings made it never timeout on key codes. This is what I did, and resolves it solves my problem:
set notimeout
set ttimeout
set ttimeoutlen=10
A couple of questions:
Am not a terminal emulator expert, I wonder if terminal emulators really send partial key codes to a listening program when arrow or mouse keys are pressed? In my imaginary world, it should send complete sequences at once to a listening program. In that case ttimeoutlen=0
should work (src), and the real value of setting ttimeoutlen
to large value would be for users to test/play with key-code stuff.
:h ttimeoutlen
suggests it is also used to timeout <C-\><C-n>
"... Also used for CTRL-\ CTRL-N and CTRL-\ CTRL-G
when part of a command has been typed. ...". I don't see that happening. When I open a terminal window using :terminal
, and do this: <C-\>
(wait few seconds) <C-n>
, it works (and am happy about that as I cannot enter <C-\>
& <C-n>
with 10ms delay in between). So what do you mean by that statement?
Yes, I have seen each byte arrive separately. It depends on the system and what kind of connection is being used (when using a remote terminal). That's also why it works fine for most people until they start a remote connection.
For 'ttimeoutlen' note the remark "when part of a command has been typed". Thus not the whole command.
Closed #7946.