Vim tricks collection

The following is a bunch of various useful Vim tricks that I rarely see anyone else use.

  1. Completion
  2. Transpose two characters
  3. Visual put to exchange two snippets of text
  4. Put at current indent level
  5. Navigate by paragraphs
  6. Repeated changes across files using argdo
  7. Use arrow keys for scrolling
  8. Different cursor shapes in GNOME Terminal
  9. Jedi-Vim configuration
  10. Flake8 plugin configuration
  11. Ale plugin configuration
  12. clang_complete configuration
  13. Replace raw Unicode character with named equivalent
  14. Insert Unicode character by name

Completion

:help i_CTRL-N i_CTRL-X_CTRL-L

In insert mode, press CTRL-N to complete the current token using existing tokens from open buffers, and press CTRL-X CTRL-L to complete the current line using existing lines in the file. This can be very useful if you have a lot of } catch (IOException e) { in your code.

Transpose two characters

In Emacs, you have C-t (transpose-chars) which transposes the two characters before the cursor, for instance to turn normla into normal. The equivalent keypress in Vim is xp (or Xp, depending on cursor position): Delete a character and put it after the following character.

Visual put to exchange two snippets of text

:help v_p

Occasionally you may want to exchange two snippets of text, for instance swapping the first and third entry in the tuple (foo, bar, baz) so it becomes (baz, bar, foo). When you press p in Visual mode, you exchange the current visual selection with the contents of the unnamed register. This means the exchange can be achieved in the following way:

  1. Place the cursor at the f in foo
  2. dw to store foo in the unnamed register
  3. Place the cursor at the b in baz (e.g. 2W)
  4. ve to select baz in visual mode
  5. p to exchange the two
  6. Go back and put baz, e.g. F(p.

In summary, dw2WvepF(p.

Put at current indent level

:help ]p

]p puts below current line at current indent level, and [p puts above.

Navigate by paragraphs

:help paragraph

To navigate between empty lines, use { and }. Use empty lines accordingly in your code to ease navigation between logical blocks. To delete the current paragraph, use either {d} or dap (delete a paragraph). Very useful for reorganizing code.

Repeated changes across files using argdo

:help arglist

In Vim, the arglist is the set of files specified on the command line when you started Vim, and it can be reset to a new list using the :args command. To perform a command in all files in the arglist, use :argdo. Remember to :set autowrite to automatically write the buffer before switching to the next file.

For instance, to perform a global search and replace in all files matching *.txt:

:set autowrite
:args *.txt
:argdo %s/FOO/bar/g

You can also insert a header guard in all C header files using the following:

:set autowrite
:args *.h
:argdo exec "norm ggO".expand("%")
:argdo exec "norm gggUU:s/\\./_/g\"
:argdo exec "norm ggI#ifndef "
:argdo exec "norm ggyypR#define"
:argdo exec "norm Go#endif"

Use arrow keys for scrolling

nmap <Down> 3<C-E>
nmap <Up> 3<C-Y>
vmap <Down> 3<C-E>
vmap <Up> 3<C-Y>
imap <Down> <C-O>3<C-E>
imap <Up> <C-O>3<C-Y>

Different cursor shapes in GNOME Terminal

GNOME Terminal, xterm, and others, support the VT520 DECSCUSR escape codes for changing the cursor style. To mimic GVim and have a bar cursor in insert mode and underline cursor in replace mode:

let &t_SI="\<Esc>[5 q"
let &t_SR="\<Esc>[3 q"
let &t_EI="\<Esc>[0 q"

Jedi-Vim configuration

The default configuration of the Vim plugin for Jedi (awesome Python autocomplete/goto definition) adds a lot of unnecessary popups at unwanted times. A sane configuration is as follows:

let g:jedi#popup_on_dot = 0
let g:jedi#show_call_signatures = 2
let g:jedi#show_call_signatures_delay = 0
let g:jedi#auto_vim_configuration = 0
let g:jedi#smart_auto_mappings = 0
set noshowmode

Ale plugin configuration

The Ale plugin for Vim 8 runs Flake8 in the background. The default configuration runs Flake8 all the time, but I prefer to only run it on demand.

let g:ale_lint_on_enter = 0
let g:ale_lint_on_save = 0
let g:ale_lint_on_text_changed = 0
let g:ale_set_highlights = 1
let g:ale_set_loclist = 0
let g:ale_set_quickfix = 1
let g:ale_set_signs = 0
nnoremap <F5> :<C-u>call ale#Lint()<CR>
nnoremap <Esc>u :<C-U>noh<Bar>call ale#highlight#SetHighlights(bufnr('%'), [])<CR>
nnoremap <A-U> :<C-U>noh<Bar>call ale#highlight#SetHighlights(bufnr('%'), [])<CR>

clang_complete configuration

The default configuration of the clang_complete Vim plugin (awesome C++ autocomplete/goto definition) adds a lot of unnecessary popups at unwanted times. A sane configuration is as follows:

let g:clang_make_default_keymappings = 0
au FileType cpp nnoremap <buffer> <Leader>d :call g:ClangGotoDeclaration()<CR>
au FileType cpp nnoremap <buffer> <Leader>g :call g:ClangFollowReference()<CR>
let g:clang_auto_select = 2
let g:clang_complete_auto = 0
let g:clang_auto_user_options = "compile_commands.json"

Replace raw Unicode character with named equivalent

Run :Uniname on one or more lines to replace non-ASCII characters with named Unicode literals (or hexadecimal escapes in case of 8-bit control codes).

py3 <<EOF
def uniname(ch):
    import unicodedata
    try:
        return '\\N{%s}' % unicodedata.name(ch)
    except ValueError:
        return repr(ch)[1:-1]
EOF
command! -range Uniname <line1>,<line2>py3do import re; return re.sub(r'[^\x20-\x7f]', lambda mo: uniname(mo.group()), line)

Insert Unicode character by name

Press CTRL-B in Insert mode and type the name of a Unicode character, e.g. SQUARE ROOT, to insert the given symbol at the cursor. Completion is possible if you install font-unicode from PyPI.

py3 <<EOF
def unisyms(needle):
    import os, sqlite3, fontunicode.glyphlist
    db_filepath = os.path.join(os.path.dirname(fontunicode.glyphlist.__file__), 'unicode.db')
    con = sqlite3.connect(db_filepath, isolation_level=None)
    cur = con.cursor()
    cur.execute(
    """SELECT unilongname
    FROM Unicodes WHERE unilongname LIKE ?""", (needle + '%',))
    return [result[0] for result in cur.fetchall()]
EOF
function! Unisyminputcomplete(ArgLead, CmdLine, CursorPos)
return py3eval('unisyms(' . json_encode(a:CmdLine) . '[:' . a:CursorPos . '])')
endfunction
let g:unisyminputlast = ''
function! Unisyminput()
    let g:unisyminputlast = input('', g:unisyminputlast, 'customlist,Unisyminputcomplete')
    return py3eval('"\N{' . g:unisyminputlast . '}"')
endfunction
inoremap <C-b> <C-r>=Unisyminput()<CR>