github instagram email
Writing Vim Commands, An Example
Mar 24, 2018
3 minutes read

Make vim more powerful by customizing it with your own commands! I recently had a problem that was pretty easy to solve with a few vim commands. After sorting it out, I realized that I might need to solve this problem again in the future; this was not premature optimization, I promise. After years of using vim, I still wasn’t confident in writing my own commands. Turns out it’s a lot easier than I had expected once I took the time to learn. Here’s a simple breakdown through example of what it takes to start adding your own custom commands to your vim experience.

unsplash-logo Jantine Doornbos

Step 0: The Problem

I prefer spaces over tabs. I was writing html and css files with a tabstop of four spaces and realized I would like each file to only have two spaces per tab. I updated my filetype settings so all new files would have the correct tab spacing. Then I decided to find a solution to update all the existing files to my liking.

Step 1: The Solution

Stack Overflow to the rescue. I quickly found an answer that solved my problem. All I had to do was open each file and enter the following commands.

:set ts=4 sts=4 noet
:retab!
:set ts=2 sts=2 et
:retab

Perfect. I tested it out. All my 4 space tabs turned into 2 space tabs. I opened the next file, pressed the up arrow several times, pressed enter a few times and repeated the necessary commands to adjust the tabs once again.

Then I decided this was boring. I wanted a quick reusable solution.

Step 2: Turn the Solution into a Function

Vim allows you to write your own functions. For now, just place them in your .vimrc.

  • Vimscript functions must start with a capital letter if they are unscoped!
  • Add a bang (!) to the function definition in order to overwrite any existing definitions.
  • Functions can take parameters. And commands can pass params to functions.
  • Assign local variables with &l:foo
function! ChangeTabStops(current, new)
        let &l:tabstop = a:current
        let &l:softtabstop = a:current
        set noexpandtab
        retab!
        let &l:tabstop = a:new
        let &l:softtabstop = a:new
        set expandtab
        retab
endfunction

And here’s the short version.

fu! ChangeTabStops(c, n)
        let &l:ts = a:c | let &l:sts = a:c | set noet ret!
        let &l:ts = a:n | let &l:sts = a:n | set et | ret
endf

Cool! I prefer the longer version. Vim script is arcane enough as it is. Either way, now it’s a lot simpler to update each file. All we have to do is:

:call ChangeTabStops(4, 2)

But we can do even better.

Step 3: Turn the Function into a Command

By adding a command that calls our new function, it will be even easier to update each file. The following line creates the command that will pass all the arguments to the function we made:

command! -nargs=* ChangeTabStops call ChangeTabStops(<f-args>)

Now to update a file, I just have to type:

:ChangeTabStops 4 2

If this command ends up being used all the time, we could assign a mnemonic mapping to call it with even less keystrokes. How about ct for change tabs?

nnoremap <leader>ct :ChangeTabStops 4 2<CR>

The End

That’s it. It’s really pretty simple to create your own commands/functions that will supercharge your vim experience. I don’t recommend running out and writing a function for every little thing you do. When you notice that you’re spending a lot of time doing something or always repeating the same actions over and over, take a step back see if there’s a better way to achieve the result. Don’t be afraid to dive into vim’s :help system. If you can streamline something you do over and over again it can really pay dividends in the long run.


Back to posts