Vim Tips Wiki

Prevent escape from moving the cursor one character to the left

Revision as of 10:45, April 21, 2013 by Trusktr (Talk | contribs)

1,619pages on
this wiki
Tip 1167 Printable Monobook Previous Next

created March 13, 2006, Updated April 21, 2013 · complexity intermediate · author Paul Donohue (Alternative by Joe Pea) · version 7.0

From the Vim FAQ:

10.2. In insert mode, when I press the <Esc> key to go to command mode, the
 cursor moves one character to the left (except when the cursor is on
 the first character of the line). Is it possible to change this
 behavior to keep the cursor at the same column?

No. It is not possible to change this behavior. The cursor is *always*
positioned on a valid character (unless you have virtual-edit mode
enabled). So, if you are appending text to the end of a line, when you
return to command mode the cursor *must* drop back onto the last character
you typed. For consistency sake, the cursor drops back everywhere, even if
you are in the middle of a line.

You can use the CTRL-O command in insert mode to execute a single ex
command and return back to insert mode without moving the cursor column.

If you don't care about consistency and only want the cursor to drop back when necessary when exiting insert mode, try:

inoremap <silent> <Esc> <C-O>:stopinsert<CR>

If the cursor is not on a valid character (for example, at the end of a line), it will still be moved back one character (unless virtual-edit mode is enabled).

If you are in paste mode and hit <Esc>, the cursor will still be moved back one character (since all mappings are ignored in paste mode).

But, otherwise, when using this mapping, <Esc> generally won't move the cursor.

If you have any other mappings which begin with <Esc> (for example, 'map <S-Up> ...' doesn't seem to work right for me, so I use 'map ^[[1;2A ...', which starts with <Esc>), then 'timeoutlen' will apply to this mapping, and the cursor will move one character to the left until 'timeoutlen' expires, then will move back to the proper position.

Programmatic Alternative

Mapping the <esc> key leads to problems most of the time. Here's how to do it programmatically:

    let CursorColumnI = 0 "the cursor column position in INSERT
    autocmd InsertEnter * let CursorColumnI = col('.')
    autocmd CursorMovedI * let CursorColumnI = col('.')
    autocmd InsertLeave * if col('.') != CursorColumnI | call cursor(0, col('.')+1) | endif


The way it's suggested in the tip, it breaks the immensely useful Visual-block Insert mode (:h v_b_i). This seems to not break anything (except when used in console Vim over ssh -- then any <Esc> remapping breaks escape sequences for some reason):

inoremap <silent> <Esc> <Esc>`^

Here are some suggestions regarding making keycode maps more responsive:

hmmm... interesting... when I remove all my mappings beginning with an <Esc> character, this little trick causes all sorts of problems. It only seems to work properly when there is some mapping beginning with an <Esc> character. Very strange behavior.

Perhaps that's why the Karma on this tip is horrible?

Around Wikia's network

Random Wiki