Vim and NeoVim can be extended using a problematic language called VimScript, the single best source for which is Learn Vimscript the Hard Way, a book - and website - by Steve Losh. Today I'm going to cover writing functions in VimScript (although probably not as well as Losh did).
To re-indent an entire file, we would do this: gg=G
. Which is great, but ... gg
takes you to the top of the file, so I just lost my place. If you search on Google, you'll see a lot of answers to this problem that look like this:
msHmtgg=G'tzt`s
This is marking your cursor location and your window position, and then returning to it later (note the gg=G
trapped in the middle). Ignore all of these, as Vim introduced a couple wonderful functions to replace all that maneuvering: winsaveview()
and winrestview()
. So we can write a function:
function! ReindentFile()
let l:winview = winsaveview()
:normal! gg=G
call winrestview(l:winview)
endfunction
Saves the current view (both the cursor position and what portion of the file is visible in the window) to local variable l:winview
(where the 'l:' indicates a variable local to the current function - see Vimscript Variable Scoping and Pseudovariables). Invokes Normal Mode, but the "!" forces a state that ignores the user's over-ridden key mappings. (People end up making a lot of mappings - this forces default behaviour in case they overrode any commands we use here. This is also why I called VimScript "problematic" earlier: the behaviour of accepting user modifications to the language as a default is ... perverse and bad.) Then restore the view.
You can enter this at the command line, although I wouldn't particularly recommend it. You can add it to your ~/.vimrc (better) and then call it at the command line with :call ReindentFile()
, but better would be to map it:
nnoremap <leader>r :call ReindentFile()<cr>
See Map Leader and Normal mode mappings if you're not familiar with mapping.
Similarly, let's write another function to delete all trailing white space in a document:
function! DeleteTrailingWhiteSpace()
let l:winview = winsaveview()
:%s/\s\+$//
call winrestview(l:winview)
endfunction
As before, save (and restore) the window state, then search the entire file ('%' in the regex) for all whitespace ('s+') at the end of the line ('$') and replace it with nothing ('//'). Then restore your window view.
To make it useful, attach it to a mapped keyset:
nnoremap <leader>dw :call DeleteTrailingWhiteSpace()<CR>