Create Your Own Vim Commands
Tags: vim, productivity
Published: 2019-01-22 06:13:54

---
title: Create Your Own Vim Commands
published: true
description: Have you ever wanted to build your own Ex commands in Vim? This short guide will show you the basics and build a couple commands that might be useful for you.
tags: vim, productivity
canonical_url: https://davidlains.com/posts/create-your-own-vim-commands
---

If you have used Vim for any length of time you have run across Ex commands. Hell, you use an Ex command to exit Vim; `:quit`, or just `:q`. There are Ex commands available to do pretty much anything that can be done in Vim.

You can make your own Ex commands as well. Many Vim plugins add their own Ex commands as part of the plugin. You might think it is hard to create a new Vim command, but it isn't. I'll show you the basics here, and where to look for more information.

## Open a Reference File

I find it much easier to learn things if there is something I want to build, so this is the command that will be built.

There is a particular code editing situation that I find myself in very often. I'm working on a bit of code, say an HTML page, and I need to add a class name that is defined in one of the project's CSS files. I can't remember the class name though. I want to open the CSS file in a split window so I can see it, but I don't need to edit it.

This is easy enough to do in Vim, simply `:vsplit [path_to_css_file]` and the CSS file is available in a split window.

Ahh, but there is a problem. Using `:vsplit` opens the CSS file in a new Vim window, makes it the active window and moves the HTML file I'm editing to the right. What I really want is to open the CSS file in a window on the right and continue editing the HTML file.

I just need the CSS file for reference.

I'll actually create two commands in this post. One to open a reference file in a vertical window to the right and leave the current window active, and a horizontal version of the same command that opens the reference file in the bottom window.

Along the way I will describe the Vim `:command` command and its options so you can create your own Vim commands if you need to.

## The `:command` Command

That's right, the Vim command to create user defined commands is `:command`. You can use `:command` on its own in Vim to get a list of user defined commands. It is handy if you ever forget a command name you created or one you loaded from a plugin. When creating a user command `:command` takes the following form:

```vim
:command [args] Name actions
```

The new command you create has to have a name, of course, otherwise how could you call it. The name must start with a capital letter. This is a requirement of Vim and is used to keep user defined commands separate from internal Vim commands. There is one exception though, it can not be named `:Next`. Apparently Vim broke its own rule.

Once the command is working you can use it in Vim by entering `:Name`, but, you know, replacing Name with the actual command name.

I'll name these commands `:Ref` and `:Vref` to stick to the Vim convention of `:split` for a horizontal window and `:vsplit` for a vertical window. So the commands so far are:

```vim
:command Ref
:command Vref
```

### Optional Args

The `:command` command takes zero or more optional arguments. The most important of these is the `-nargs=` argument. This lets Vim know if the command takes any arguments. The possible values it can be set to are:

* 0 : The command takes no arguments. This is the default, so it can be omitted entirely.
* [1-9]: The command takes the specified number of arguments.
* *: The command takes zero or more arguments.
* +: The command takes one or more arguments.
* ?: The command take zero or one argument.

The commands I want to build will take a single argument, the path to the reference file to open, so I'll be using `-nargs=1`.

You can access the arguments in a number of ways. First, just using `<args>` somewhere in the `actions` part of the command. Second, if you need to make sure the arguments are properly escaped for use in an expression you can use `<q-args`. Finally, if you are going to pass the arguments to a Vim function you can use `<f-args>`.

Another argument that will be used in these commands will be `-complete=`. This argument lets Vim know what kind of tab completion is available for the command. There are over thirty different values that this can be set to. Far too many to cover here, but some of the values are `buffer` to complete buffer names, `dir` to complete directory names, `help` to complete help topic name and `file` to complete file and directory names.

The last argument that will be needed is the `-bar` arguments. This tells `:command` that the `actions` can contain a vertical bar `|` followed by additional Ex commands, or a double quote `"` followed by comments. I'll need two different Ex commands in these new commands, so they will need to be separated with a vertical bar.

Some of the other arguments you can supply to `:command` are:

* `-range` allows the command can accept a range of lines in the current buffer to operate on.
* `-count` allows you to supply a repeat count for the command.
* `-register` allows you to specify a register other than the unnamed register.

For more on the available `:command` arguments look at `:h user-commands`.

With the arguments defined for the new commands we end up with:

```vim
:command -nargs=1 -complete=file -bar Ref
:command -nargs=1 -complete-file -bar Vref
```

All that is left is to create the actions to take when the commands are executed.

### Command Action

The Vim documentation actually calls this the replacement, because it replaces your command name with the command or commands you specify here. I find actions to be a bit more intuitive. In any case, this is what you want to have happen when you enter your command into Vim.

The user command documentation doesn't say anything else about the actions, I suppose because all of the other documentation is applicable. Any Ex command can be used here to achieve the desired effect.

For my case I want to open a new window to the right or bottom with the file specified in the command, but leave the current window active. The built in `:split` and `:vsplit` Ex commands don't have the behavior I want.

I looked at the Vim documentation for `:split`, thinking that perhaps there was an argument that would give me the behavior I wanted. It does take a couple of arguments, but they are related to the file format, and cursor positioning when the file opens. Not really what I was looking for.

A little further down in the documentation for `:split` I found the `splitbelow` and `splitright` settings. If you `:set splitbelow` then new windows created with `:split` are created below the active window instead of above. The same goes for `:set splitright`; new windows will be created to the right.

That looked like exactly what I wanted. I can set those values in my `.vimrc` right before I define the commands and everything will work like I want.

While that would work I wasn't in love with the solution. That will change the default for every split window. I don't like changing the default settings if I don't have to. A little more digging the the Vim documentation near the `:split` docs and I found the exact right thing.

There are command modifiers for the split window commands called `:rightbelow`, `:leftabove`, `:topleft` and `:botright`. These are Ex commands, but are called modifiers because they only take another Ex command as an argument and override the `splitbelow` and `splitright` settings.

The `:rightbelow` modifier just executes whatever command you supply as an argument. If the supplied argument opens a split window it will open it to the right, or below, depending on the argument. So, now the commands are:

```vim
:command -nargs=1 -complete=file -bar Ref :rightbelow :split <args>
:command -nargs=1 -complete=file -bar Vref :rightbelow :vsplit <args>
```

The commands are almost complete. The only issue left to deal with is that the new window that is created is still made active. That is simple enough to fix, I can just add a window movement command to make the previous window active again.

My initial thought was to use the Vim window movement commands; `<C-w>k` to move to the upper window and `<C-w>h` to move to the left window. Vim didn't parse that correctly though. Apparently all of the commands have to be Ex commands.

I had to dig through Vim help topics for a bit but I found what I needed. All of the Vim window commands can be activated through the `:wincmd` Ex command. So, whenever you type `<C-w>x` you could also use `:wincmd x`.

The final commands, then, are as follows.

```vim
:command -nargs=1 -complete=file -bar Ref :rightbelow :split <args> | :wincmd k
:command -nargs=1 -complete=file -bar Vref :rightbelow :vsplit <args> | :wincmd l
```

There you have it; two brand new Vim commands. They take one argument, the path to a file, which can be `<Tab>` completed. They open the file  in a new split window, either to the right or below the currently active window and then move to the previously active window.

I hope you enjoyed this little trip through Vim commands. There is so much flexibility available in Vim. With a little bit of effort and digging through the help files you can build your own Vim Commands to do pretty much anything you need.