Updated: 2021-01-22 20:28:26

I finally (2007) bit the bullet and commited to learning a real text editor. Having dabbled with vi since the late 90s, decided on Vim. Once you break through its initial, steep, learning curve, its truly life changing. Level up, and become a text surgeon today.

I usually clone my dotfiles git repo straight into my home directory i.e. ~/dots. A couple of symlinks later, I’m away:

ln -nfs ~/dots/vim/vimrc ~/.vimrc
ln -nfs ~/dots/vim ~/.vim

Vim is incredibly customisable. Its important to take the time to craft your own vimrc. Type :options to understand the various levers you can pull to make Vim your editor. 10+ years later, I still fine tune the editor to my needs and workflows.


Vim has brilliant built-in help. Its only one :help away, :h operator or :h motion.

  • :h cmd normal mode cmd help
  • :h i_cmd insert mode cmd help
  • :h v_cmd visual mode cmd help
  • :h c_cmd command line cmd help


Trigger Effect
c change
d delete
y yank
g~ swap case
gu lower case
gU upper case
g? ROT13 encode
> shift right
< shift left
= autoindent
! filter through a program

See :h operator for more. All of these support being combined with a motion (or a visual mode selection). Some examples:

  • gUaw - make a word shout case
  • dap - delete entire paragraph
  • g?ap - ROT13 encode paragraph
  • gUgU - shout case entire line (factoid: when two operators are invoked in duplicate, applies to current line)

Object Selection

Learning object selectors is one of the best ways of becoming more efficient with Vim. Commands that start with i select inner objects without white space, and thus always select less text than their a equivalents. When you discover these can be paired with operators (discussed above), life changing, e.g. daw delete a word, gUis uppercase inner sentence, and so on.

Selector Effect
aw a word
iw inner word
as a sentence
is inner sentence
ap a paragraph
ip inner paragraph
a] a[ a [] block
i] i[ inner [] block
a) a( a block
i) i( inner block
a> a< a <> block
i> i< inner <> block
at tag block, as in XML tags <a> to </a>
it inner tag block
a} a{ a {} block
i} i{ inner {} block
a" a' quoted string including back ticks
i" i' quoted string including back ticks


Leverage the built-in windows manager, which can do splits to view multiple files at the same time.

  • :sp horizontal split
  • :vs vertical split
  • ctrl+w o - close all windows other than the active one.
  • ctrl+w x - exchange active window with the next one.
  • ctrl+w c - close the current window.
  • ctrl+w r - rotate windows clockwise (or counter clockwise).

The Edit (e) Command

Vim’s built-in edit command, will present you with a nice file system explorer, for example :e . to present the current working directory.


Makes line numbering relative. So good! Makes it fast to figure out how many lines up or down you need to move, to get to the line you want. Example, 14j to jump 14 lines down.

  2 I usually clone my `scripts` git repo straight into my home
  1 ¬
13      ln -nfs ~/git/scripts/linux/vim/vimrc ~/.vimrc¬
  1     ln -nfs ~/git/scripts/linux/vim ~/.vim¬
  2 ¬
  3 Vim has brilliant built-in help. Its only one `:help` away.


By typing <C>r= in insert mode, can do quick calculations are spit the out into the buffer.

For example, <C>r=16*4<CR> will output 128 where the cursor is currently located.

Spell checking

Built in spell checker, enable with :set spell.

  • ]s jump to next error
  • [s jump to previous error
  • z= suggest corrections for current word
  • zg add word to dictionary
  • zw remove word from dictionary
  • zug undo zg or zw for current word

Sudo Save

Editing a file, but don’t have privileges to save.

:w !sudo tee %

:w writes to sudo tee %. tee flows the output of the file write to %, the name of the current file. I have a handy key binding w!! to do this:

cmap w!! w !sudo tee %

Normalise line endings

The classic #!/bin/bash no such file or directory error message. Shebang is busted likely due to encoding problems.

Litmus test:

$ head -1 <your_file> | od -c

Should show:

0000000   #   !   /   b   i   n   /   b   a   s   h  \n

Vim to the rescue:

vim <your_file>
:set ff=unix
:set nobomb


While core Vim functionality is like a rock, changing rarely, the plugin eco-system is where you can make Vim level up to doing tasks you commonly do with it. Consequently plugin selection can be quite personal based on specific langs one works with.

The Vim community seems obsessed with writing new plug-in managers, there’s quite a bit of choice and tradeoffs, I have used a few in the past (Pathogen, Vundle) and as of 2020 have settled with vim-plug, which balances minimalism and functionality nicely.

Coming from bloated power tool IDE’s like awesome JetBrains tools, in order to be remotely productive, I need to be able to efficiency locate and jump between files within a large code base.


Ditch NERDTree, and instead surface the nnn terminal file manager within Vim, genius.

  • <leader>n start nnn in window
  • ^G discard selection


Buffer management and fuzzy finder. Quickly fuzzy find files recursively in a source tree e.g. Person.java or all shell scripts .sh. I’ve configured it to use ripgrep under the hood.

Launch shortcuts:

  • ; browse currently open buffers
  • <leader>f browse list of files in current directory
  • <leader>g recursive grep from current directory for occurences of given term and close window if no results
  • <leader>j recursive grep from current directory for occurences of word under cursor

Once launched shortcuts:

  • q or <Esc> quit denite window
  • d delete currenly selected file
  • p preview currently selected file
  • <C-o> or i switch to insert mode inside of filter prompt
  • <C-t> open currently selected file in a new tab
  • <C-v> open currently selected file a vertical split
  • <C-h> open currently selected file in a horizontal split


Surround chunks of text with quotes or tags.

  • ysiw" surround word with double quotes
  • v$S" surround visual selection with double quotes
  • vipS<p> surround paragraph with <p></p>
  • cs"' change double quotes to single quotes


Make a table of contents inferred from markdown heading tags.

  • :GenTocGFM
  • :GenTocGitLab
  • :UpdateToc


OCD much? This helps to line up code based on a particular symbol.

  • vipga= visual select code block, align all = symbols by padding out


Smart commenting based on the file type.

  • gcc comment current line
  • gc<motion> comment motion based selection e.g. gcap for paragraph selection


Vim motioning on steroids! Creates micro jumps based on a search pattern you provide, and dims down the buffer with each highlight getting a unique id you can hit.

  • <leader><leader>w beginning of all words
  • <leader><leader>fo motion all o characters going forward
  • <leader><leader>to motion before (till) o characters
  • <leader><leader>n jump to latest / or ?
  • <leader><leader>s search


Utilities to highlight and remove redundant use of whitespace.

  • :EnableWhitespace
  • :DisableWhitespace
  • ToggleWhitespace
  • :StripWhitespace


  • <leader>p run the current buffer through prettier


Colorise hex codes in the buffer based on CSS standards.


An LSP based completion framework and language server client which supports extension features of VSCode.

Like VSCode, Emacs and many others, can sit upon the Langserver.org Protocol (LSP) originally created by Microsoft, to provide language aware intelligence such as auto complete, go to definition and find all references.

To install a coc extension that supports a language, have a look on npm for one, and install with CocInstall for example to install Go language completion CocInstall coc-gocode. Make sure to also install gocode for this particular plugin, with a quick go get -u github.com/nsf/gocode.

CoC Go support:

You can manually register LSP servers in jsonc format in the ~/.config/nvim/coc-settings.json (use :CocConfig to auto jump you to this file). For example, the below registers gopls, Google’s offical LSP for golang:

    "languageserver": {
    "golang": {
        "command": "gopls",
        "args": [],
        "rootPatterns": ["go.mod", ".vim/", ".git/", ".hg/"],
        "filetypes": ["go"]

CoC web dev support (JS, ES6 and CSS):

:CocInstall coc-tsserver coc-eslint coc-json coc-prettier coc-css

Setup behind a proxy

Getting my Vim setup on a corporate network.

TODO: Investigate containerising it.

  • git config --global http.proxy http://proxy.evilcorp.com:8080
  • nnn.vim: nnn
  • prettier: node v10+
  • denite: python3, pip3 install –user pynvim
  • coc.nvim:
    • node v10+
    • yarn
    • yarn config set proxy http://proxy.evilcorp.com:8080
    • yarn config set https-proxy http://proxy.evilcorp.com:8080