This tip discusses how to exit from insert mode without needing to press Esc. The Vi editor was originally written on an ADM-3A terminal, which had the Escape key positioned where the Tab key occurs on most modern keyboards. Many touch typists appreciate the fact that they can leave their hands on the keyboard home row while using Vim, so there are several ideas for avoiding the Esc key at its current location (pressing Esc generally requires stretching to the top of the keyboard).
No utility programs or operating system tweaks are required for this tip. For other suggestions involving mapping keys with the operating system or utilities, see Map caps lock to escape in XWindows (for Unix-based systems), Map caps lock to escape in Windows (for Windows), or Map caps lock to escape in macOS. Some of the suggestions involve more than avoiding escape; topics also discussed include using the CapsLock key for Ctrl, and avoiding irritations from accidental use of CapsLock.
Avoiding the Esc key[]
If you have an American English keyboard, pressing Ctrl-[ (control plus left square bracket) is equivalent to pressing Esc. This provides an easy way to exit from insert mode.
If you have a keyboard where the bracket is already mapped to Alt Gr-something (like the spanish keyboard), press Ctrl-c to quit insert mode (however, Ctrl-c does not expand abbreviations). :help i_CTRL-C
Use Alt/Meta In a Terminal[]
Alt keys appear on most PC keyboards. Meta keys were used on some old systems.
If you use Vim in a terminal, simply press alt/meta+normal_mode_key. Most terminals send an escape character followed by the normal_mode_key that you pressed, removing the need to press escape yourself.
The terminals konsole and gnome terminal send the escape by default when you press alt/meta+normal_mode_key. For Xterm you can ctrl+click and select the option "Meta sends escape" or "Alt sends escape". [1]
Thus in insert mode pressing alt+h alt+j alt+k alt+l all take you to normal mode and move in the expected direction. You can hold down alt when moving even while in normal mode since the additional ESC that is sent does no harm.
The advantage of using this scheme is that you can use the alt/meta+key combination with any normal mode key, e.g.
- Alt+o opens a new line below the one you are currently editing,
- Alt+A appends to the end of the current line,
- Alt+p pastes at the current insert location.
- Alt+k moves up
Thus using vim via a terminal gives you these short cut powers on any stock standard system without the need to edit each systems vim mappings.
Mappings[]
It can be convenient to use a mapping so that pressing a key, or sequence of keys, generates Escape. The :imap
command is used to create the mapping so that it only applies while in insert mode (but see note about :inoremap
below).
For example, the following allows you to press jj
to exit from insert mode: (or jk
,kj
, etc)
:imap jj <Esc>
To generate Escape, jj
has to be typed quickly. :help 'timeout'
A problem with mapping a sequence like jj
is that Vim will pause whenever you type j
in insert mode (it is waiting for the next key to determine whether to apply the mapping). The pause is merely a visual distraction which you may not notice, and it does not slow down typing.
For simplicity, we will show :imap
but careful Vimmers are in the habit of using :inoremap
which does not attempt to interpret the result of the mapping (with the :imap
command, the result is scanned to see whether it contains another mapping).
If you are considering putting this map in your .vimrc be careful to not put any comments after it, imap will try to interpret the blank spaces after <Esc> producing random jumps after entering normal mode.
For a better solution without visual distraction, you can consider using https://github.com/zhou13/vim-easyescape/.
Alternative mappings[]
Here are some alternative suggestions:
" Can be typed even faster than jj, and if you are already in " normal mode, you (usually) don't accidentally move: :imap jk <Esc> :imap kj <Esc> " If want to avoid jk in certain languages can use: " (and to make it where order doesn't matter, the second mapping also) :imap jw <Esc> :imap wj <Esc> " Press i to enter insert mode, and ii to exit. :imap ii <Esc> " Pressing Ctrl-L leaves insert mode in evim, so why not in regular vim, too. :imap <C-L> <Esc> " This is a variation on the previous mapping that checks for evim " and only changes the function of <C-L> in regular vim. This allows <C-L> " to still work as usual in evim. See :help insertmode for more. :inoremap <expr> <C-L> &insertmode ? '<C-L>' : '<Esc>' " This is a variation on the previous mapping that additionally checks " for the popup menu (present when doing completions). During completions, " <C-L> adds a character from the current match, so this mapping will " preserve that behavior. See :help popupmenu-keys for more. :inoremap <expr> <C-L> (pumvisible() <bar><bar> &insertmode) ? '<C-L>' : '<Esc>' " Use backtick. :imap ` <Esc> " Two semicolons are easy to type. :imap ;; <Esc> " Press Shift-Space (may not work on your system). :imap <S-Space> <Esc> " Try the following so Shift-Space also enters insert mode. :nmap <S-Space> i " Or just Space to enter insert mode. :nmap <Space> i " In Mac OS X, mapping <S-space> does not work, but the following " is better (press the "apple" key and the space key). " Note that this will conflict with the spotlight shortcut :imap <D-space> <Esc> " On gvim and Linux console Vim, you can use Alt-Space. :imap <M-Space> <Esc>
Using the Tab key[]
- If using MacVim under Mac OS X, see below for a working procedure.
It is possible to map the Tab key but that is not desirable because Ctrl-o and Ctrl-i (Tab) are very useful for jumping to previously visited locations.
With the following in your vimrc, you can press Tab to return to normal mode:
nnoremap <Tab> <Esc> vnoremap <Tab> <Esc>gV onoremap <Tab> <Esc> cnoremap <Tab> <C-C><Esc> inoremap <Tab> <Esc>`^ inoremap <Leader><Tab> <Tab>
In normal mode, you can press prefix keys before a command (for example, 12 for a count). The nnoremap
causes Tab to cancel any prefix keys.
The vnoremap
causes Tab to cancel any selection (gV
is required to prevent automatic reselection).
The onoremap
causes Tab to cancel any operator-pending command (for example, y
).
The cnoremap causes Tab to cancel any command that was entered.
The first inoremap
causes Tab to exit insert mode, and the `^
restores the cursor position so exiting insert does not move the cursor left.
The second inoremap
, assuming the default leader key, allows you to press \
then Tab to insert a tab character. You may prefer an alternative mapping to make it easier to insert a tab. For example, on some systems, you may be able to use Alt-Tab to insert a tab character with:
inoremap <M-i> <Tab>
Some plugins may remap the Tab key. To remap them back from .vimrc
, use autocmd
:
au VimEnter * map <Tab> <Esc> au VimEnter * imap <Tab> <Esc> au VimEnter * vmap <Tab> <Esc>
Due to the way that Vim read keys, Ctrl-i is the same as Tab. Therefore, you cannot map Tab to generate Escape, and map Ctrl-i to do something different.
When adjusting indents, you can avoid tabs altogether:
- In normal mode: Type
<<
to shift the line left one 'shiftwidth', or>>
to shift right (and press.
to repeat). - In insert mode: Press Ctrl-d to shift left, or Ctrl-t to shift right.
Tab key under Mac OS X[]
If you are using MacVim under Mac OS X, there is a good method to use the Tab key for Escape. The tool KeyRemap4MacBook can configure the Tab key to act as an Esc key in MacVim only (leaving the rest of the system untouched). Then you can press Ctrl-i to insert a tab character, and can press the Tab key to send Escape to MacVim. To do this, add the following to your private.xml
file:
<!-- TAB key changed to act as ESC, for MacVim only --> <appdef> <appname>MACVIM</appname> <equal>org.vim.MacVim</equal> </appdef> <item> <name>Change Tab to Esc in MacVim</name> <identifier>private.macvimdef</identifier> <only>MACVIM</only> <autogen>--KeyToKey-- KeyCode::TAB, KeyCode::ESCAPE</autogen> </item>
Vim Extension for Visual Code Studio (and Github Codespaces)[]
The popular Vim extension for Visual Code Studio does not support `imap` or `inoremap` as of 2023. However, you can create insert mappings with the `insertModeKeyBindings` field of your `settings.json` file. In the following example, mapping `jk` to Escape:
"vim.insertModeKeyBindings": [ { "before": ["j", "k"], "after": ["<esc>"] } ]
Vim Mode in Obsidian[]
Obsidian is a cross-platform note-taking app with some (limited) Vim capability.
First, enable Vim key bindings under "Editor" settings. Then enable Community Plugins, browse the plugins, and search for "vimrc". You should see the "Vimrc Support" plugin — install it, enable it, and in its settings, choose ".obsidian.vimrc" as your Vimrc file name (or whatever you wish to call it; note if it begins with a dot, you'll need to edit it in the file system as it won't be visible in Obsidian itself). In the configured vimrc file, enter *exactly* the following, assuming you want to map jk to Escape.
imap jk <Esc>
Notes/gotchas:
- You must use imap as inoremap is unsupported
- You must use <Esc> and not <esc> or <ESC> (source)
- You'll need to do all of the above for each of your vaults
- You may need to restart Obsidian for this to take effect
Using the Enter key[]
It's very easy to exit insert mode using the Enter key:
:inoremap <CR> <Esc>
An example of using the above would be to type ce
to change to the end of a word, then type new text, then press Enter to return to normal mode.
When you want to enter a newline, you may find that Shift-Enter or Ctrl-Enter works (it should always work in gvim, but might not in a terminal, depending upon your system). If your Shift-Enter or Ctrl-Enter works, and you can get used to it, the above might be all you need. CTRL-J (:help i_CTRL-J) or CTRL-M (:help i_Ctrl-M) could also work.
An alternative would be to map Shift-Enter to generate Escape:
:inoremap <S-CR> <Esc>
Then Enter will always work as expected, and Shift-Enter will always exit insert mode. If Shift-Enter does not work on your system, you might find that Ctrl-Enter (<C-CR>
) does.
Another, more elaborate, alternative is:
function! ToggleEnterMapping() if empty(mapcheck('<CR>', 'i')) inoremap <CR> <Esc>`^ return "\<Esc>" else iunmap <CR> return "\<CR>" endif endfunction call ToggleEnterMapping() inoremap <expr> <S-CR> ToggleEnterMapping() " Optional (so <CR> cancels prefix, selection, operator). nnoremap <CR> <Esc> vnoremap <CR> <Esc>gV onoremap <CR> <Esc>
- Features
- Initially, pressing Enter returns to normal mode.
- In insert mode, pressing Shift-Enter enters "multiline" mode, meaning that pressing Enter will insert a newline.
- In insert mode, after pressing Shift-Enter to enter "multiline" mode, pressing Shift-Enter again exits (returns to normal mode).
- Explanation
The mapcheck()
function returns the current insert-mode mapping for <CR>
(Enter). The empty()
function returns nonzero (true) if there is no such mapping.
The inoremap <expr>
command maps Shift-Enter to generate the expression returned by calling ToggleEnterMapping()
(the code for either Escape or Enter). Calling the function toggles the insert-mode mapping for Enter: if it is mapped, it is unmapped; otherwise it is mapped to <Esc>`^
(generate Escape then go to the ^
mark).
Toggling insert mode[]
Press Ctrl-Space to start and to stop insert mode (the same suggestion using Shift-Space is above):
nnoremap <C-space> i imap <C-space> <Esc>
Or you may prefer to map Ctrl-Space to a
rather than i
so that repeatedly pressing Ctrl-Space does not move the cursor back (remember that pressing I
allows you to insert a character at the beginning of the line):
nnoremap <C-space> a imap <C-space> <Esc>
In the terminal <C-space> doesn't work, but <C-@> worked out (at least for me).
<C-space> worked for me in Macvim but not <C-@> or <Nul>, and vice-versa for command-line vim. I ended up mapping <C-space> to <Nul> and mapping with <Nul> for a more general mapping.
An alternative follows. It uses /i
to toggle insertion at the cursor, and /a
to toggle insertion at the end of the line. If you use /i
(or /a
) to insert, you must /i
(or /a
) to exit (not Esc).
nnoremap <silent> /i :let &insertmode=1-&insertmode<CR> inoremap <silent> /i <Esc>:let &insertmode=1-&insertmode<CR> nnoremap <silent> /a :let &insertmode=1-&insertmode<Bar>if &insertmode<Bar>:startinsert!<Bar>endif<CR> inoremap <silent> /a <Esc>:let &insertmode=1-&insertmode<Bar>if &insertmode<Bar>:startinsert!<Bar>endif<CR>
- References
- Comment
Probably can use :set insertmode!
to toggle.
The /
is easy to type, but did you mean to use <Leader>
? Also, why toggle 'insertmode'
? Why not the following (and similar for append):
nnoremap <Leader>i i inoremap <Leader>i <Esc>
Automatically exit Insert mode when you use Up or Down arrows[]
Many people recommend exiting Insert mode if you use the up or down arrow to move to another line. To do so, it is recommended that you add two lines to your vimrc:
inoremap <silent> <Up> <ESC><Up> inoremap <silent> <Down> <ESC><Down>
These two lines mean that pressing ESC is no longer necessary, simply moving the cursor vertically will automatically do it for you.
This works for most simple edits that one encounters but I often found myself having to edit a few lines in close proximity to each other. So this forced me to enter insert mode once for each line. And I would often move to the second or third line with the arrow keys and start typing but nothing would be entered. The fix I found was adding a few short lines to my vimrc:
autocmd InsertEnter * let s:insertLineStart = line(".") function! <SID>InsertModeDown() if line(".") > s:insertLineStart + 1 stopinsert endif return "\<Down>" endfunction function! <SID>InsertModeUp() if line(".") < s:insertLineStart - 1 stopinsert endif return "\<Up>" endfunction inoremap <expr> <Down> <SID>InsertModeDown() inoremap <expr> <Up> <SID>InsertModeUp()
This would allow me to enter Insert Mode and make any necessary changes within 3 lines up or down from where I started Insert mode. If I move further, it automatically returns to Normal mode.
Improving the Esc key[]
You may not find attempts to replace the Esc key satisfactory. However, if you don't like the cursor moving left when you exit from insert mode, you may want to try this variation from the Tab key section above:
inoremap <Esc> <Esc>`^
The above trick means that the cursor will not move if you press i
to enter insert mode, then press Esc to exit. However, pressing a
(append) then Esc will move the cursor, so this "improvement" may not satisfy you.
Command-line mode[]
If you want to map another key to Esc in command-line mode, if you attempt a mapping like
cmap <C-space> <Esc>
the resulting mapping will submit the command-line as if pressing Return rather. To create a mapping to act like Esc in command-line mode, you must map to <C-c>
instead.
cmap <C-space> <C-c>
Mapping problems[]
Vim runs on many different hardware and software platforms. Therefore some key sequences may not be available. For example, you may be able to map Shift-Space in a GUI Vim, but not in a terminal Vim (and even if you could, if you were running via PuTTY, for example, Vim might not receive the key code).
For Shift-Space in terminal Vim, I used "URxvt.keysym.S-space: \033" in .Xresources. (for the rxvt-unicode terminal emulator).
To test your system, enter insert mode then press Ctrl-K followed by the key of interest (for example, press Ctrl-K then Shift-Space). :help i_CTRL-K
Related tips[]
The following advises using <C-o>
instead of <Esc>
in insert mode mappings.
The following are not related to the Esc key. They try to avoid CapsLock applying in normal mode (so you can insert text in uppercase when needed, but not type in uppercase after exiting insert mode).
Comments[]
Use META + <next action>
Depending on your terminal and vim settings it is possible that ^[ is sent firstly while you are pressing META(Alt)+<key>. So during Insert mode you can press META+j to finish editing, return to Normal mode and move to the next line.
Remap Bash Shell's Escape Key for Readline VI mode
Although slightly off-topic here, you can also remap the ESC key for Bash's Readline VI emulation mode to another key sequence.
Create or modify your $HOME/.inputrc:
# Remap ESC to use my double 'i' keypress to toggle insert or movement # mode. $if mode=vi set keymap vi-command "ii": vi-insertion-mode set keymap vi-insert "ii": vi-movement-mode $endif
You'll likely need to exit all Bash shells for this change to take effect.
NOTE: There is currently a patch proposed on Jan 23 2012 (after bash-4.2_p20 release) for creating a time-out value for readline for double key mappings. This patch can be found on the bug-bash mailing list under the subject "Bash readline remap ESC insert/command mode key". An additional note, the shorter timeout value for double key mappings versus Vim's timeout is much quicker (using approx. half of Vim's wait time) making typing much quicker. Vim's timeout value seems to allow users to type the first char with a finger, and the second using a toe. Without this patch, users will have have problems typing commands containing an 'i' and a work around is to type 'i' and then the 'right cursor' key. In short, get the patch or await >bash-4.2_p20?
META + <normal key> prints accent character since upgrade to Vim 8
As of Vim 8, modifyOtherKeys is used by default which enables mapping of keys with arbitrary modifiers. This needs to be disabled in order for META + <normal key> to work, see: https://github.com/vim/vim/issues/5200
Put this into your .vimrc:
let &t_TI = ""
let &t_TE = ""