After a decade of honing my skills as a mini-golfer, I’ve recently progressed onto playing a new version of golf: VimGolf. I’ve been using Vim for a few years now, and noticed that my Vim skillset had plateaued. The premise of VimGolf is simple: challenges consist of a start file and an end file. The goal is to get from the start file to the end file, using Vim, in as few keystrokes as possible. I’ve been playing VimGolf as a way to acquire new skills.

I’ve learned all kinds of new keystrokes and Vim tips through playing. Predictably, some of them are very niche and forgettable. But, I’ve found others which I didn’t know and now incorporate daily into my Vim usage. I’d imagine reading this, some will be familiar, and some new. This is not meant to be an introduction to Vim. Rather if (like me) you’ve been using Vim for a little bit but haven’t recently looked up Vim commands, I’m hoping some of these will be helpful.

My recommendation in reading through this post is to have a file open in Vim, and try out these commands as you read them. I hope at least a few are helpful for your workflow and make their way into your regular Vim usage!

Insertion

  • Ctrl-n in insertion mode inserts based on context. It will prompt a word based on contents of the file. Keep hitting Ctrl-n to get the contextually next word
  • O moves into insertion mode in a new line above the cursor
  • ci<char> to delete within the <char> and put you in insertion mode. For example, ci( deletes everything within the (...) and puts you in insertion mode. Also helpful, ci” and ci{
  • S deletes the current line and puts you in insertion mode
  • . repeats the previous action (specifically helpful for insertion)
  • Ctrl-o in insertion mode escapes for one command in normal mode. This is very helpful for movement while inserting
  • I inserts at the beginning of the line

Movement

  • ^ moves the cursor to the first non-whitespace character on the line
  • + moves to the beginning of the first word (non-whitespace character) on next line
  • Ctrl-o (backwards) and Ctrl-i (forwards) together jump the cursor around to where it was previously in any files. Keep using Ctrl-o to go backwards, and Ctrl-i to go forwards. (:help jumplist for more info here)
  • B (backwards) and E (forwards) move the cursor using only whitespace as delimiters
  • F<char> (backwards) and f<char> (forwards) find a character or word on the current line

Copy Paste

  • Y highlights the line and copies it (I had been using Vy for this)
  • "+y copies highlighted words to the clipboard so you can paste the value outside of Vim
  • "+Y copies the line the cursor is on to the clipboard so you can paste the value outside of Vim
  • Ctrl-y in insertion mode pastes the contents of the line directly above

Tip: If you highlight a word (or lines) and then replace it, the highlighted word moves into the register, and will be the next word you paste

Indenting Text

  • << (left) and >> (right) shifts the current line
  • <iB (left) and >iB (right) shifts the code in the current block
  • =i{ fixes indentation of block excluding the braces
  • =a{ fixes indentation of block including the braces
  • gg=G to indent the full file

Tip: Use gg=G and then Ctrl-o to get the cursor back to where it was

Refocusing the page

  • zt moves the line the cursor is on to the top of the page
  • zz moves the line the cursor is on to the middle of the page
  • zb moves the line the cursor is on to the bottom of the page

Specific Characters

  • ~ switches the case of a character
  • Ctrl-a increments numbers
  • Ctrl-x decrements numbers

Tip: The cursor doesn’t need to be on the number itself, it’ll increment or decrement any number after the cursor on the same line

Miscellaneous

  • ZZ and :x both only save the file if it has been modified, and then quit
  • :!<command> to run a bash command from Vim (for example :!ls)
  • gql will split one line to the currently set width. To set the width of the split lines to be different from your current setting, you can use :set textwidth=<n>. This can be helpful for 80 character linting, for example
  • dat deletes everything inside an HTML tag including the tag
  • dit deletes everything inside an HTML tag excluding the tag