How is it possible? Because it's implemented that way. ;)
Vim help details this is at the end of the :h up-down-motions
section and it says:
[j
and k
] put the cursor in the same column (if possible) as it was after the last command that changed the column
Two things that I take from this are
- There is no mention of a builtin alternative that goes straight up/down, and Vim's help is usually pretty good about noting such things. That suggests there isn't one. (I thought for a moment Up and Down arrows would behave differently but they appear to have the same effect. They're off the home row anyways.)
- Since it mentions "the last command that changed the column" that suggests you can precede
k
with something like hl
and you'll remain in the column.
So if that's something you prefer you could add to your vimrc:
nnoremap j hlj
nnoremap k hlk
There's a problem, though. That won't work if the cursor is at the beginning of the line. You'll be in the second column since h
can't actually move the cursor. (If you used lh
instead it would break at the end of the line.)
This works better (and has a less "hacky" feel to it)...
nnoremap j :call cursor(getcurpos()[1]+1, 0)<CR>
nnoremap k :call cursor(getcurpos()[1]-1, 0)<CR>
The second parameter is column number. A value of 0 there means you want to stay in the same column.
Be forewarned, though, that this may act funky in some circumstances. For instance, if you're leaning on j
or k
to scroll up/down a bunch of lines (which, to be honest, means you rely on j/k way too much) then once you hit an empty line the cursor will remain in column 1 the rest of the way.
So if there are things that bother you a better idea might be to use some unmapped keys and leave the native commands as is. Use the mappings only when you're in a situation where you definitively want to apply straight up/down movement. One easy-to-remember alternative is nnoremap <leader>j ...
.