Create a VSCode Snippet with Multi-Cursor Support

5 min read

VSCode is a powerful editor right out of the box, but it becomes even more powerful when you customize it. A lot of VSCode customization takes the form of extensions, but in this post we're going to cover how you can add your own custom code snippets.

The Goal

We'll be building a custom snippet that handles some repetitive code for us and supports multi-cursor editing to cut the typing to a minimum and ensure we maintain consistent naming within our resulting code.

I frequently add some defensive code to verify that a function exists, and that it is, in fact, a function before invoking it. That code always follows the same pattern.

doThing && typeof doThing === 'function' && doThing(args)

In this example, doThing is repeated three times and the logic will always be the same, regardless of the function name.

Editing Snippets

You can edit your "user snippets" in VSCode through the command palette.

  1. Open the command palette (⇧⌘P on mac, ctrl+shift+p on windows)
  2. start typing "snippet"
  3. Select the option labeled "Preferences:Configure User Snippets"
  4. Select the language you want this snippet for. For this example, I'll be using the javascript.json snippets file.

This will open the selected json file.

The Structure of a VSCode Snippet

VSCode snippets are defined and stored in a json file. There are separate files for each language along with a global snippets file.

Each snippet is defined as an object that is, itself a property of the overall json object like this.

{
  "Some Snippet": {}
}

That object requires some specific keys. The first is prefix, which is what you will type to trigger the snippet in your code.

{
  "Some Snippet": {
    "prefix": "type_this_thing"
  }
}

The next critical piece is the body key. The body of your snippet will be defined as an array where each element represents a line of code.

{
  "Some Snippet": {
    "prefix": "type_this_thing",
    "body": [
      "This will be a line of code",
      "This will be the second line",
      "This will be the third"
    ]
  }
}

In order to be ergonomic, we can define tab stops in a snippet so once a snippet is generated with the prefix, the snippet can be updated in a logical order by tabbing through the code to the places we need to customize, then finally dropping the cursor where it will be needed next. You define placeholders, in order with $1, $2, etc. and if you use the same placeholder in multiple places, you automatically get multiple cursors for that tab stop. You can define a default value with ${1:fn} where this is the first tab stop and fn is the default value. For the end of your snippet, $0 is reserved as the final tab stop.

Now that we have all the tools we need, let's put them to use in a real snippet.

Building the Snippet

To get started, we'll call our snippet "Safe Callback" and give it a prefix of "sfn" (you can use whatever makes the most sense for you), and we'll define the array the will hold the body of the snippet.

{
  "Safe Callback": {
    "prefix": "sfn",
    "body": []
  }
}

With the basic structure in place, let's turn our attention to the snippet body. In this case, we only need a single line, so we'll have one element in our body array. We'll base this on our earlier code example:

doThing && typeof doThing === 'function' && doThing(args)

We'll start by replacing each instance of doThing with a placeholder. We want a default value, we'll go with fn for this example. That will mean our placeholder looks like this ${1:fn}.

We also want to edit all three instances at the same time, so we'll use the same placeholder in each spot. This will automatically giving us multi-cursor editing in our snippet.

${1:fn} && typeof ${1:fn} === 'function' && ${1:fn}()"

We'll want a second tab stop for any arguments that need to be passed to our function, so we'll add $2 inside the parens.

-${1:fn} && typeof ${1:fn} === 'function' && ${1:fn}()"
+${1:fn} && typeof ${1:fn} === 'function' && ${1:fn}($2)"

And finally, we'll drop the cursor at the end of the line with $0

-${1:fn} && typeof ${1:fn} === 'function' && ${1:fn}($2)"
+${1:fn} && typeof ${1:fn} === 'function' && ${1:fn}($2)$0"

Here's what the fully filled out snippet looks like.

{
  "Safe Callback": {
    "prefix": "sfn",
    "body": ["${1:fn} && typeof ${1:fn} === 'function' && ${1:fn}($2)$0"]
  }
}

Use It

Now in any JavaScript file, you can type sfn, hit the tab key and your should see the snippet. You should have multiple cursors (3), and they should each have an instance of fn selected. You can type out your function name, hit tab again and you should be dropped inside the parens to add arguments. Once you're done with your arguments, hit tab one last time and you'll be left at the end of the line to continue editing.

Conclusion

There are plenty of extensions available for VSCode that will provide useful snippets. Knowing how to build your own can still be quite useful when you find yourself completing repetitive coding tasks. Whether you use snippets released by others in extensions or create your own, they can take your coding productivity to the next level.

If video is your thing, you can see this lesson in video form on egghead.io.