93

In vim, when I hit ESC to return to command mode, the cursor moves one character to the left. This is not what I would hope for, occasional I immediately hit l to move back to that spot, perhaps to delete a character.

Is there a reason for this behavior? Is this convenient for a pattern of usage that I'm missing?

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
Eric Wilson
  • 4,722
  • 1
    I've never even noticed this until just now... and I use vim everyday. I have no idea why, but I'm interested in hearing the answers. – gabe. Apr 15 '11 at 20:16
  • 7
    when going back to insert mode, you can press 'a' for append instead of 'i' for insert. You will then move back to the position you were in before pressing escape. – penguin359 Apr 18 '11 at 23:39

6 Answers6

56

In insert mode, the cursor is between characters, or before the first or after the last character. In normal mode, the cursor is over a character (newlines are not characters for this purpose). This is somewhat unusual: most editors always put the cursor between characters, and have most commands act on the character after (not, strictly speaking, under) the cursor. This is perhaps partly due to the fact that before GUIs, text terminals always showed the cursor on a character (underline or block, perhaps blinking). This abstraction fails in insert mode because that requires one more position (posts vs fences).

Switching between modes has to move the cursor by a half-character, so to speak. The i command moves left, to put the cursor before the character it was over. The a command moves right. Going out of insert mode (by pressing Esc) moves the cursor left if possible (if it's at the beginning of the line, it's moved right instead).

I suppose the Esc behavior sort of makes sense. Often, you're typing at the end of the line, and there Esc can only go left. So the general behavior is the most common behavior.

Think of the character under the cursor as the last interesting character, and of the insert command as a. You can repeat a Esc without moving the cursor, except that you'll be bumped one position right if you start at the beginning of a non-empty line.

  • 2
    Count me among the new-ish vim users who learned "i means you can start typing characters instead of moving around", and didn't know that a is another way to enter insert mode with appreciably different behavior. – Ari Lacenski Nov 04 '19 at 19:47
  • This makes more sense once I tried to prepend consecutive lines with a character. – mcp Jan 11 '22 at 22:23
29

Visually, it makes more sense in gvim:

When editing, your cursor is in between the characters:
enter image description here

When in normal mode, it is on top of the last character:
enter image description here

So it does not really go back a character, just from being between r and s to being on r

16

This behavior is editable as answered here, but stop and think about what's going on for a second. When you are in insert mode, you are not actually over a character but BETWEEN them. When you insert something, the cursor jumps to the end of what you inserted so that the next thing inserted will be after that. Now think about if you just typed a letter, then wanted to do something to it. Hitting Esc would put the select cursor directly over the last character you inserted. If it didn't do this, it would actually be rather awkward.

The situation you are probably thinking of is when you are in insert mode moving around as if you were normal mode and then switch. In that case the cursor does appear to go back one character, but if you think that way it shows that you were in insert mode and the last thing you did was NOT insert. Maybe you should spend more time in normal mode?

Caleb
  • 70,105
  • 19
    That doesn't make sense to me. How do you explain the walking-backwards behavior of repeated i and ESC keypresses? – Warren Young Apr 15 '11 at 19:41
  • 5
    Going into insert mode, not inserting anything, then leaving it is not a fair test. Why would you be in insert mode if you didn't insert something. If you do insert something, going back to normal mode leaves you with the character you inserted selected. Very intuitive. – Caleb Apr 15 '11 at 19:45
  • 5
    It's not about "fair", it's about explanatory power. If your theory of operation doesn't explain all the behavior, either it is incomplete or vi's behavior is inconsistent. I prefer to believe that vi is perfect in every way, and therefore consistent. :) – Warren Young Apr 15 '11 at 19:54
  • 1
    My "theory" does explain all the behavior, it precisely defines why the "moving backward" behavior you describe is happening and why that is the most consistent way the interface could handle the scenario. – Caleb Apr 15 '11 at 20:00
  • 11
    @Warren The "walking backwards" behavior of i followed by ESC is a function of i and is fully independent of ESC; specifically, when you hit i you are asking vim to insert a character, which by definition means "insert a character prior to the one I am on", as opposed to a which is "append a character after this one". – Kromey Apr 15 '11 at 20:14
  • 6
    In general, after each change, when I leave that change, I'm done with that change, and the next thing I would like to do will probably involve making a different change. Thus, to me, upon leaving insert mode (no matter how I entered it), I'd generally prefer the cursor to be on the next character so I'm ready for my next change, rather than being ready to change what I just inserted. – Kyle Strand Feb 07 '14 at 21:11
9

Type Alt+L to return to command mode.

It doesn't require any remapping or vim config change. It works because on most terminal emulators Alt+KEY sends an Esc followed by KEY (on xterm you might need to add a Xterm*metaSendsEscape: true line into your ~/.Xdefaults file). That behavior allows you to even "create" other insert mode combinations that work right out the box — like Alt+S to Backspace.

By the way, having the cursor on top of the character you've just written can be very inconvenient. For instance, Escdw won't delete the word following the text you've just inserted.

  • 1
    The inconvenience you refer can be avoided by always typing a space in insert mode before the escape. Then the cursor leaving the insert mode is put over the space, and you can type Esc d e to delete the word in front. I reverted back to the default behavior because I felt it changed other behaviors already encoded in my head. – mljrg Oct 23 '18 at 14:42
5

Here's my solution.

It's a more terse version of the solution offered on the wikia page about this.

au InsertLeave * call cursor([getpos('.')[1], getpos('.')[2]+1])
Steven Lu
  • 2,282
  • +1 here as well, for citing the wiki page, even though the user wasn't actually asking for a way to change this behavior. – Kyle Strand Feb 07 '14 at 21:44
  • You will note if you dig far enough into Vim that many plugins do rely on the default (slightly unintuitive) behavior, so if you see some stuff randomly eat or mangle a single character, could be caused by this. I don't use this autocommand myself; it works well, though. – Steven Lu Sep 09 '16 at 20:22
4

Just to supplement other answers, if i does not do exactly what you want, maybe one of the other insert modes will:

  • i Start insert mode at cursor
  • I Insert at the beginning of the line
  • a Append after the cursor
  • A Append at the end of the line
  • o Open (append) blank line below current line (no need to press return)
  • O Open blank line above current line
  • ea Append at end of word