Elevating Your Workflow With Custom Mappings
One of the greatest features in Vim is its customizability. A simple way to get started customizing Vim and one that will have the greatest effect in your daily coding is creating custom mappings. A mapping in Vim is the equivalent to a shortcut in other editors but with a strong focus on melodies of keys that are so natural to Vim.
Why Custom Mappings?
Custom mappings are useful for two reasons:
- They let you customize Vim and adapt it to the way you work by creating custom mappings for things that you use often
- They let you prioritize Vim functionality by bringing it nearer to your fingertips. Using custom mappings you can create a hierarchy of commands where the most useful ones can be reached from the commodity of your home row and the less useful ones can be reached through comfortable, yet more lengthy key combinations
Creating Custom Mappings
You can create custom mappings using Visual Studio Code preferences:
- Open the command palette with
CMD-SHIFT-P
orCTRL-SHIFT-P
- Type preferences
- Select the Preferences: Open User Settings Options
- Type
vim
And you’ll filter your Visual Studio Code preferences to display only VSCodeVim related ones. Now you can use the following settings to add your custom mappings in different modes:
- Normal Mode Key Bindings Non Recursive for normal mode
- Visual Mode Key Bindings Non Recursive for visual mode
- Insert Mode Key Bindings Non Recursive for insert mode
Having different mappings for different modes makes sense because each mode is a clean slate where you can redefine mappings to perform tasks specific to that mode. That allows you to reuse key keyboard real state in each mode and have powerful functionality near your fingertips.
Note that these settings can only be changed via the json
version of the settings:
A custom mapping normally takes the following shape:
{
"vim.insertModeKeyBindingsNonRecursive": [
{
"before": ["j", "k"],
"after": ["<ESC>"]
}
],
}
Where:
- before is the sequence of commands that you type.
- after is what the previous commands map to and what gets executed when you type them.
In the example above, whenever we type the sequence jk
in Insert Mode it will be the equivalent of typing <ESC>
and therefore it will bring us back to Normal mode. This is a great custom mapping that makes a very common task seamless, since both j
and k
are in the home row and just underneath your right hand.
Add this mapping to your configuration and you’ll see that it takes effect as soon as you save your settings. Now try to go into Insert mode and type jk
in rapid succession. ijk
, ijk
, ijk
… It should flow smoothly like a peaceful stream or like warm butter over a toast.
Guidelines For Creating Custom Mappings
The ability to create custom mappings gives you a lot of freedom and flexibility to define how you interact with Visual Studio Code. But because there’s nothing stopping you for doing whatever you like, you may end up shooting yourself in the foot. Here are some rules to guide you when creating your very own custom mappings and save those precious toes of yours:
- In general, use the leader key to define your custom mappings. The leader key is a special key in Vim whose purpose is to act as a namespace or gateway to user defined mappings. By default, the leader key is assigned to the backslash key
\
. - If there’s something in your workflow that you use all the time, then it is OK (encouraged in fact) to overwrite a less useful default Vim binding. This is the exception to the rule.
- Create mappings that are easy to remember. Follow Vim’s tradition and rely on mnemonics. (Remember?
c
for change,d
for delete, and such…)
If these rules seem too abstract don’t worry, in the next sections we’ll make them more practical as we define a series of custom mappings that you can add to your own VSCodeVim configuration.
Customizing The Leader Key
You can change the leader key to something easier to type than the backslash \
(I don’t know you, but I hate having important keys associated to my pinky fingers pinky). My personal favorite is the spacebar which is super convenient to type from both hands.
Go to your VSCode preferences and update the following setting:
{
"vim.leader": "<Space>",
}
From now on, whenever you see a custom mapping that refers to <leader>
you can translate that in you head to <Space>
.
Some Good Custom Mappings
Here are some other great examples of useful mappings:
Moving Up and Down Faster in Normal Mode
These mappings allow you to move up and down faster in Normal mode (although they are just as useful in Visual mode):
{
"vim.normalModeKeyBindingsNonRecursive": [
{
"before": ["J"],
"after": ["5", "j"]
},
{
"before": ["K"],
"after": ["5", "k"]
},
]
}
From now on you’ll be able to use:
J
to move down fasterK
to move up faster
This matches perfectly with Vim’s idea of commands in capital letters being stronger versions of the commands in lowercase. That is, J
allows you to move faster than j
and K
faster than k
.
Here we’ve overwritten two Vim default bindings because browsing the code up and down is something that you’ll do all the time. Whereas J
(join lines), although useful, is something that you do only from time to time. K
is used for keyword search but isn’t yet implemented in VSCodeVim.
Keep Joining Lines
Joining lines is still useful so we’re going to keep it. Although we will downgrade its importance in the hierarchy by making it slightly harder to type.
Update your VSCodeVim configuration to include this new mapping:
{
"vim.normalModeKeyBindingsNonRecursive": [
{
"before": ["<Leader>", "j"],
"after": ["J"]
},
]
}
So now whenever you type <Leader>j
, Vim will translate it to J
and join two lines together. Try it out!
<Leader>j
isn’t as fast as just typing J
but it is good enough based on how often you’ll join lines. The mnemonic in this case is join.
Easier Switching Between Splits
Switching split windows is something that you’ll do all the time so try out these bindings:
{
"vim.normalModeKeyBindingsNonRecursive": [
{
"before": ["<C-h>"],
"after": ["<C-w>", "h"]
},
{
"before": ["<C-j>"],
"after": ["<C-w>", "j"]
},
{
"before": ["<C-k>"],
"after": ["<C-w>", "k"]
},
{
"before": ["<C-l>"],
"after": ["<C-w>", "l"]
}]
}
They’ll make you that much faster and agile when traversing splits because they require one less keystroke.
Easier Tab Handling
The only way to interact with tabs in VSCodeVim is through commands which require you to type a colon followed by a bunch of letters.
We can do better:
{
"vim.normalModeKeyBindingsNonRecursive": [
{
"before": ["<Leader>", "t", "t"],
"commands": [":tabnew"]
},
{
"before": ["<Leader>", "t", "n"],
"commands": [":tabnext"]
},
{
"before": ["<Leader>", "t", "p"],
"commands": [":tabprev"]
},
{
"before": ["<Leader>", "t", "o"],
"commands": [":tabo"]
}]
}
Taking advantage of the <Leader>
key we can now open new tabs, move around and close all tabs but the current one.
Did you notice something different about these custom mappings?
Exactly! You use a slightly different syntax when mapping keys to commands. Instead of using before
and after
. We use before
and commands
. commands
represent either the Ex commands or Visual Studio native commands that should be run whenever we type the key mapping defined by before
.
Cleaning Highlighted Text
When you search for patterns in Vim using the /{pattern}
and ?{pattern}
commands, the matching patterns will be highlighted. In order to remove the highlights you can use the :noh
(no higlighting) command.
This is such a common task that I prefer the following mapping:
{
"vim.normalModeKeyBindingsNonRecursive": [
{
"before": ["<Leader>", "/"],
"commands": [":noh"]
}]
}
Now you can type the <Space>/
and get rid of the highlights until your next search. The mnemonic is the / which is normally used to search for a pattern. So you can think of /{pattern}
as something that you do to start a search, and <Leader>/
as something you when you’re done with a search.
Creating Custom Mappings To VSCode Actions
Yet another cool thing that you can do with VSCode is to use Vim mappings that trigger Visual Studio Code native commands. For instance, the following binding:
{
"vim.normalModeKeyBindingsNonRecursive": [
{
"before": ["leader", "w"],
"commands": [
"workbench.action.files.save",
]
}
}
Let’s you save a file using <leader>w
by triggering VSCode "workbench.action.files.save"
action.
Let’s look at another example. There’s four features in VSCode that I find extremely useful:
- The Command Palette (
CTRL-SHIFT-P
orCMD-SHIFT-P
) - Go To File (
CTRL-P
orCMD-P
) - Go To Symbol in File (
CTRL-SHIFT-O
orCMD-SHIFT-O
) - Go To Symbol in Workspace (
CMD-T
orCTRL-T
)
The command palette and go to symbol in file are particularly hard to type so let’s create a custom mapping to keep our wrists healthy:
{
"vim.normalModeKeyBindingsNonRecursive": [
{
"before": ["<Leader>", "p"],
"commands": [
"workbench.action.showCommands",
]
},
{
"before": ["<Leader>", "t"],
"commands": [
"workbench.action.gotoSymbol",
]
}
]
}
Now you no longer need to contort your fingers to open the command palette or go to symbol. Just type <Leader>p
and <Leader>t
respectively and you’ll quickly access either of these panels. Yihoo!
There are a lot more interesting and useful mappings in the VSCodeVim documentation. Take a look!. But remember to be critical. Before you add a custom mapping in your VSCodeVim configuration consider whether it offers a better workflow than whatever you use today. Never add things to your configuration blindly.
A significant part of becoming more effective with Vim is to be mindful of your development workflow. Revisiting your Vim configuration now and then, and adding new mappings that enhance the way you work. So be mindful from now on, and keep your Vim configuration razor sharp.
- Perhaps I should start doing pinky curls and weighted pinky extensions. I’m sure I can find some pinky dumbbells on Amazon…↩
Written by Jaime González García , dad, husband, software engineer, ux designer, amateur pixel artist, tinkerer and master of the arcane arts. You can also find him on Twitter jabbering about random stuff.