I play the great game called VIM adventures (from which are the images bellow). The question is from the game, but is also reproducible in VIM so this is the place I ask.

Assume you are in normal mode, standing on some line n and column m. If you press key j, your position becomes line n+1 and same column m. If the line n+1 has less columns than m, say o, you are placed at column o. Again press j. You are moved to line n+2, on column m (same check as before). See, column you started at, m, is remembered. This can be seen on the first image, with red lines representing j movement.

However, if you are in normal mode and press key $, you are moved to the end of the current line. Now consider the same sequence of movements as desribed in paragraph before. Each movement j will move you to the last character on that line. m is not remembered in this case. This can be seen on the second image. By pressing first $, coursor is placed at the end of the first line. Then, by pressing multiple j movements, each lands coursor on the end of line, ignoring m, which was remembered in the first paragraph.

I can't find this in any VIM documentation. Can you explain me how this remembering mechanism works or point me to the part of documentation which explains this ?

enter image description here enter image description here

  • 3
    Welcome to Vi and Vim! – D. Ben Knoble Aug 22 '20 at 11:57
  • 1
    Special thanks to a simple, precise and unambiguous description of the behavior. – Quasímodo Aug 22 '20 at 13:12

Indeed, there are not very direct references to this behavior in the documentation of the $ command itself.

The documentation of the g$ motion actually refers to this behavior though, in explaining how g$ differs from $:

Differs from $ when the last character of the line is not on the screen or when a count is used. Additionally, vertical movements keep the column, instead of going to the end of the line.

Other than through documentation, you can take a peek at how Vim actually implements this column tracking, since functions such as getcurpos() export that information as a "curswant" attribute:

The curswant number is the preferred column when moving the cursor vertically.

(You'll also find the "curswant" attribute in the Dict returned by winsaveview().)

For instance, if you've moved horizontally on a long line to column 24, then vertically to a line that only has 17 columns, you'll see this:

:echo getcurpos()
[0, 39, 17, 0, 24]

So you can see you're on column 17, but "curswant" is column 24 and Vim will go to a column up to 24 if a line has enough columns.

After you press $ and take another look at the getcurpos() output, you'll now see:

:echo getcurpos()
[0, 39, 17, 0, 2147483647]

So you'll see Vim is implementing the $ behavior by setting "curswant" to a very large number, which is the largest number of columns Vim can possibly store in a single line.

(That number is actually 231 - 1, which is the maximum positive integer number you can store in a signed int type in the C language.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.