VIM general strategies

2019-07-26 @Technology
By Vitaly Parnas

I spend most of my time on the computer in some VIM session, be it creative writing, programming, tinkering, taking notes, managing lists, email composition, “editing” web browser content (see W3M), or manipulating text of any sort. Below I demonstrate some of the more rewarding customizations and tactics I’ve employed.

Search related

set ignorecase " case insensitive regular expressions
set smartcase " overwrite ignorecase when uppercase characters are present
set incsearch " Automatically jump to search term
" Use <C-L> to clear the highlighting of :set hlsearch.
if maparg('<C-L>', 'n') ==# ''
    nnoremap <silent> <C-L> :nohlsearch<C-R>=has('diff')?'<Bar>diffupdate':''<CR><CR><C-L>
endif

" Lay out the replace all command template
nnoremap S :%s//gc<Left><Left><Left>

" vimgrep template to search through all buffers and append to error list
nnoremap <C-S> :silent bufdo vimgrepadd //g %<C-Left><C-Left><Right>

" search list (what is technically the 'error' list) shortcuts
nnoremap ;n :cnext<CR>
nnoremap ;p :cprev<CR>
nnoremap ;o :copen 6<CR>
nnoremap ;N :silent cnewer<CR>
nnoremap ;P :silent colder<CR>

Language features

Configure an alternative keymap, by default disabled. Use the CTRL-6 or CTRL-^ keys to toggle in insert/search/command mode.

set keymap=russian-yawerty
set iminsert=0 
set imsearch=-1

If you’re a multi-language typist as I am, you probably require spell checking. I’ve created the following two mappings to streamline the process. This assumes you’ve already installed the respective dictionaries.

" toggle spell-check 
nmap <F6> :setlocal spell!<CR>
" Fill in the desired language code (en,es,pt,pl,ru,...) and press enter
nmap <F7> :setlocal spelllang=

Handy registers

% - the currently edited buffer

# - the previously edited buffer

" - the paste buffer

. - the previously executed normal-mode command. Type simply . to repeat.

: - the previously executed command/EX- mode command. Repeat via @:. From then on, continue to repeat via @@.

/ - the previous search query, or the search part of any search/replace

Execute :reg to view all.

Command/insert mode insert

CTRL-R + to insert the respective content.

Normal-mode shortcuts

& - execute the last search query on the current line without any modifiers (flags that follow the s///).

g& - Like the above, but execute globally and including the previously entered search modifiers.

Handy marks

' - the previous jump position

< - the last visual-mode start position

> - the last visual-mode end position

^ - the last insert-mode position

. - the last change position

The respective commands:

'<mark> - jump to the line beginning of mark

`<mark> - jump to the exact line position of mark

Other vimrc features

set hidden " Unloaded buffers remain in memory, with all unsaved changes

" Map <space> as leader instead of the default backslash
let mapleader=" "

" Switch the current and next word
nmap <F3> <Esc>:s/\v(<\k*%#\k*>)(\_.{-})(<\k+>)/\3\2\1/<CR>``

" Easier shortcut to jump to alternate (last '#') file, also <C-^> 
nmap <leader><space> :b#<cr>
" List all buffers and offer selection or buffer operation by number/name
nmap <leader>l :ls<CR>:b

" Find-friendly settings
set path=.,**
nnoremap <leader>f :find *

" Useful one-finger navigation
nmap - <pageup>
nmap <down> <pagedown>
nmap = <pagedown>
nmap <up> <pageup>
nmap <left> :tabprevious<CR>
nmap <right> :tabnext<CR>
nmap <BS> :tabprevious<CR>
nmap <del> :tabnext<CR>
nmap \ :tabnext<CR>

" Open buffer or selection as a suckless sent presentation
map ,s :w !sent<CR>

" Pipe buffer content to the jrnl app
map ,j :w !jrnl

" Append the line or selection to the notes file in env $NOTES
nmap ,n :.w! >> $NOTES \| echo "Line written to notes"<CR>
vmap ,n :w! >> $NOTES \| echo "Selection written to notes"<CR>

" view the diff/gitdiff between buffer and respective file on disk
nmap ,d :w !diff -u % -<CR>
nmap ,gd :w !git diff -u % <CR>

" Make a backup of the file on disk
nmap ,b :!cp -v % %.bak<CR>

" Email the buffer or selection via mutt
map ,e :w !mutt <address>

" Move lines matching pattern to below current line 
nnoremap ,m :g//m''<Left><Left><Left><Left>

" Apply the first spelling correction
nmap <leader>z 1z=

" TMUX buffer integration
" Copy entire-line selection to tmux buffer. 
vmap <C-c> :w !tmux load-buffer -<cr>
" Cut text from selection to tmux buffer. Hit undo to return.
vmap <C-x> :!tmux load-buffer -<cr>
" Paste from tmux buffer
nmap <leader>p :r !tmux show-buffer<cr>
nmap <leader>P :.-1r !tmux show-buffer<cr>

" Save a few keystrokes for capitalizing or lower-casing words
nnoremap ;U gUiw
nnoremap ;u guiw
" Switch case of the first letter of word
nmap ;c gew~b
imap ;c <ESC>gew~`^i<Right>

" Emphasize the current word or selected text with asterisks
nnoremap ;e :call SurroundWordWithCharacter("*")<CR>
inoremap ;e <ESC>:call SurroundWordWithCharacter("*")<CR>a
vnoremap ;e <ESC>:call SurroundVisualWithCharacter("*")<CR>
" Single quotes around word or selected text
nnoremap ;' :call SurroundWordWithCharacter("'")<CR>
inoremap ;' <ESC>:call SurroundWordWithCharacter("'")<CR>a
vnoremap ;' <ESC>:call SurroundVisualWithCharacter("'")<CR>

function! SurroundWordWithCharacter(char)
   execute "normal gEwi" . a:char . "\<C-o>E\<right>" . a:char . "\<Esc>"
endfunction

function! SurroundVisualWithCharacter(char)
   execute "normal `>a" . a:char . "\<ESC>`<i" . a:char . "\<Esc>"
endfunction

" Renames the file and exchanges buffer accordingly
function! RenameFile()
    let old_name = expand('%')
    let new_name = input('New file name: ', expand('%'), 'file')
    if new_name != '' && new_name != old_name
        exec ':silent! !mv ' . old_name new_name
        exec ':e ' . new_name
        exec ':bd ' . old_name
        redraw!
    endif
endfunction
nmap <leader>n :call RenameFile()<cr>

Questions, comments? Connect.