Recenter cursor line in Vim (a-la-emacs)Sat 27 May 2017
No modeless editor can beat Vim (or even Vi) in cursor movement efficiency, that's a fact. When in normal mode, you can easily jump to the exact desired document's position using just a few commands.
But very often, either you need to see another part of the text, scrolling the edit window and showing the point you want to reach, or change the cursor line to the top, the middle or the bottom of the screen as an intermediate jump, enabling the use of a quick (but rather generic) motion afterward.
Vim has of course a rich set of commands for both scrolling relative to the cursor and various other motions. The drawback of this flexibility is that you could get confused about all those commands and repeatedly stop the move sequence thinking if the correct command to scroll up is zt (t for top, which is by the way the correct one), or zu (u for up) or zh (h for high) or whatever.
On the matter of gaining context in edit windows, Emacs adopts a very clever
mapping just one key sequence to different actions on subsequent consecutive
invocations; this way, repeatedly typing
Ctrl-l will make the current line
the center-most text line, the top line, the bottom line, and so on in cyclic
order, possibly redisplaying the screen too.
Of course, a very simple Vimscript function can easily mimic this behavior:
function! MoveCursorLine(...) let l:top = line('w0') let l:bottom = line('w$') let l:center = (l:top + l:bottom) / 2 if line('.') == l:center let l:cmd = a:0 ? "zt" : "H" elseif line('.') <= (l:top + &scrolloff) let l:cmd = a:0 ? "zb" : "L" else let l:cmd = a:0 ? "zz" : "M" endif execute "normal " . l:cmd endfunction nnoremap <silent> <C-l> :call MoveCursorLine("scroll")<CR>:redraw!<CR> nnoremap <silent> <leader>m :call MoveCursorLine()<CR>:redraw!<CR>
As an additional bonus: with only a bindkey more (
<leader>m, m for move),
we can change the cursor line to the top/middle/bottom of the window, without
scrolling. Try it, you won't be able to do without!
Some general comments about the code:
MoveCursorLinefunction will recenter the edit window only when invoked with an argument, whichever it is (more details about variable-length argument lists here); by default, jump without scrolling;
- all variables are local to the function (see l:var);
- most of the job is done by line(), which returns the line number of the file position specified as argument (here used for retrieving the cursor position and the first and last visible lines);
- the function itself is a simple state machine:
- if current line is in the middle of the window, jump to top;
- if it is on the top, jump to bottom;
- else, jump to the middle;
Ctrl-lis typically associated to screen redrawing, so doing that after moving the cursor line.
As usual, a (short) video is worth a thousand words: