Vim Tips Wiki
(why is this inconsistent?)
Tag: Visual edit
(/added a new method of toggling between insert and normal modes without moving cursor/)
Tag: Visual edit
Line 84: Line 84:
 
I don't think it's fair to say that if you want this behavior, then "you don't care about consistency". The default behavior is also "inconsistent" when you are at the beginning of a line; those two behaviors are totally symmetric in that sense.
 
I don't think it's fair to say that if you want this behavior, then "you don't care about consistency". The default behavior is also "inconsistent" when you are at the beginning of a line; those two behaviors are totally symmetric in that sense.
   
  +
----
  +
  +
== Toggle Insert and Normal modes without moving cursor ==
  +
These solutions (and those found on similar pages) do not work on my terminal (Yakuake). Specifically, mapping Esc to <Esc>`^ causes strange behaviour (insertion of line breaks and 'A', 'B', 'C' or 'D' characters) with arrow keys, and the del key. And while one may argue we are not to touch these keys in vim, for me, I'd rather something not go wrong if I do once in a while.
  +
  +
My advice is to leave the Esc mapping alone, meaning don't map Esc to anything else. I have swapped my CapsLock to Esc at the shell level (google this -- easy to do), so my terminal and anything in it, accept CapsLock as Esc and vice versa. But once you remap Esc to anything else, you will have side effects somewhere.
  +
  +
Thankfully, combining some of the ideas here did work nicely and provides a clean way of switching back and forth from insert to normal modes without moving the cursor. The Escape command is left alone and still works as before, as do the various ways of entering insert mode. Note below I include the mapping for either order of the key sequence, as no doubt when typed fast, you will type one or the other. Choose the sequence of your liking, but fj or jf use both hands, do not take you off the home keys and don't occure frequently in English. If you need to type "fjudge" for some reason, you have to pause about half a second after the "f". If you want another binding, then replace the left hand side below. Note: Ctrl-c does the same as pressing Esc. nnoremap is non-recursive mapping in normal mode, and inoremap is the same for insert mode. Of course the i and l you know what they do, or you would not be reading this. Using <A-l> causes side effects. And <C-o> is problematic
  +
  +
Add the following to your .vimrc and restart your shell. Don't use in-line comments. Enjoy.
  +
" Toggle INSERT and NORMAL mode without moving cursor (press fj or jf)
  +
nnoremap fj i
  +
nnoremap jf i
  +
inoremap fj <C-c>l
  +
inoremap jf <C-c>l
  +
This works fine too:
  +
" Toggle INSERT and NORMAL mode without moving cursor (press fj or jf)
  +
nnoremap fj i
  +
nnoremap jf i
  +
inoremap fj <C-c>l
  +
inoremap jf <C-c>l
 
----
 
----

Revision as of 17:17, 15 September 2014

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


Original Solution

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

Putting the above in your vimrc keeps track of the cursor position when in INSERT mode. When exiting INSERT mode, it will move the cursor ahead one column if the cursor position has changed after leaving insert.

Comments

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:

http://groups.yahoo.com/group/vim/message/66414
http://groups.yahoo.com/group/vim/message/66451

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?


If you are on a terminal, a quick and dirty way is to type Alt+L to switch to normal mode.


I don't think it's fair to say that if you want this behavior, then "you don't care about consistency". The default behavior is also "inconsistent" when you are at the beginning of a line; those two behaviors are totally symmetric in that sense.


Toggle Insert and Normal modes without moving cursor

These solutions (and those found on similar pages) do not work on my terminal (Yakuake). Specifically, mapping Esc to <Esc>`^ causes strange behaviour (insertion of line breaks and 'A', 'B', 'C' or 'D' characters) with arrow keys, and the del key. And while one may argue we are not to touch these keys in vim, for me, I'd rather something not go wrong if I do once in a while.

My advice is to leave the Esc mapping alone, meaning don't map Esc to anything else. I have swapped my CapsLock to Esc at the shell level (google this -- easy to do), so my terminal and anything in it, accept CapsLock as Esc and vice versa. But once you remap Esc to anything else, you will have side effects somewhere.

Thankfully, combining some of the ideas here did work nicely and provides a clean way of switching back and forth from insert to normal modes without moving the cursor. The Escape command is left alone and still works as before, as do the various ways of entering insert mode. Note below I include the mapping for either order of the key sequence, as no doubt when typed fast, you will type one or the other. Choose the sequence of your liking, but fj or jf use both hands, do not take you off the home keys and don't occure frequently in English. If you need to type "fjudge" for some reason, you have to pause about half a second after the "f". If you want another binding, then replace the left hand side below. Note: Ctrl-c does the same as pressing Esc. nnoremap is non-recursive mapping in normal mode, and inoremap is the same for insert mode. Of course the i and l you know what they do, or you would not be reading this. Using <A-l> causes side effects. And <C-o> is problematic

Add the following to your .vimrc and restart your shell. Don't use in-line comments. Enjoy.

" Toggle INSERT and NORMAL mode without moving cursor (press fj or jf)
nnoremap fj i
nnoremap jf i
inoremap fj <C-c>l
inoremap jf <C-c>l

This works fine too:

" Toggle INSERT and NORMAL mode without moving cursor (press fj or jf)
nnoremap fj i
nnoremap jf i
inoremap fj <C-c>l
inoremap jf <C-c>l