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.

Here, if you ask me, command names (including, but not limited to zt, zz, zb, H, M and L) don't help a lot the muscle memory learning phase.

On the matter of gaining context in edit windows, Emacs adopts a very clever and elegant solution, 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:

  • the MoveCursorLine function 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-l is typically associated to screen redrawing, so doing that after moving the cursor line.

As usual, a (short) video is worth a thousand words:

Comments


Zoom current window in Vim

Fri 19 May 2017

A colleague of mine suggested to me to share some tricks I use in my daily Vim workflow; there aren't many, actually...

I normally have just one Vim window open in a tmux panel (I rarely use the GUI); but sometimes splitting comes handy and, even using one of those …

read more

A new site, for a better storytelling!

Sun 14 May 2017

Welcome to the new Atlantide website.

A complete restructuring has been put in place; pages are now statically generated by Pelican and served by lighttpd, as usual running on top of OpenBSD.

Most of the contents are still a work in progress (and probably they will always be) but, with …

read more