Sublime Snippet Basics
Yesterday I covered some tips and tricks I've learned over the past few months of using Sublime. Something I didn't touch on is Sublime's Snippet architecture.
Essentially a snippet is a little piece of code that gets executed when you type some characters and hit the tab
key. For instance I have a snippet that spits out console.log()
whenever I type lg
and press tab
. One clever feature of snippets is that they can be bound to a keyboard shortcut if the key binding calls the insert_snippet
command and passes the path to the snippet file as an argument. For example:
{
"keys": ["super+shift+r"],
"command": "insert_snippet",
"args": {
"name": "Packages/XML/long-tag.sublime-snippet"
}
}
That will tell Sublime that when I press cmd+shift+r
it should act as if I triggered the long-tag snippet for XML files. Basically that will let me highlight some text, hit cmd+shift+r
and then I can type some HTML or XML tags to wrap my text. Cool. So let's go about writing our own snippet to learn a bit more about this process.
Getting Started
The previously mentioned snippet is great for wrapping an item in HTML/XML tags but it totally breaks if we need to wrap our selection in anything not existing within brackets: </>
. Since I write a lot of Markdown I'm always wrapping text in some kind of markdown syntax, *like this*
, but there's no easy way to do this. The aforementioned snippet is close so we're going to copy it and tweak it to do what we need.
We're going to copy the file located at /Library/Application\ Support/Sublime\ Text\ 2/Packages/XML
and move it into our /Packages/User
directory. I chose to rename the file to wrap-anything.sublime-snippet
. The original snippet looks like this:
<snippet>
<content><![CDATA[<${1:p}>${2:$SELECTION}</${1/([^ ]+).*/$1/}>]]></content>
<tabTrigger><</tabTrigger>
<scope>text.xml</scope>
<description>Long Tag</description>
</snippet>
<content>
is where we put everything that's going to be spit out by our snippet when it's executed. Items are wrapped in a CDATA
tag so they don't interfere with the rest of the XML.
The first part <${1:p}>
outputs a <
followed by a variable, $1
which has a default value of the letter "p" and it closes with a >
. If our snippet only contained this bit of code then when we ran it the output would be <p>
.
The second part uses one of the environment variables talked about in the snippet documentation.$SELECTION
will take whatever we've highlighted and make it part of the snippet output. You'll notice this variable is prefixed with a 2:
meaning it's our second variable and it's default output is going to be whatever was highlighted. The 2 also indicates that if the user hits tab
this is the second place they'll go.
The third part contains a block of regex which, I think, just matches whatever the user types after the snippet has executed. My regex sucks so correct me if I'm wrong.
<tabTrigger>
indicates what character should be typed before hitting tab
to fire off the snippet. In this case it's a <
<scope>
defines where the snippet should run I believe.. But I'm not entirely sure. The documentation just says "Scope selector to activate this snippet." I didn't see a text.xml file anywhere in the Packages/XML/
folder and I know this snippet works in non-xml files so...yeah...shrug
<description>
lets you describe the thing. duh.
OK let's make our own simplified snippet:
<snippet>
<content><![CDATA[${1:`}${2:$SELECTION}${1}]]></content>
<tabTrigger></tabTrigger>
<scope></scope>
<description>Wrap any block of text</description>
</snippet>
Our snippet is less sophisticated than the previous one since we've excluded the regex. With the above snippet located in our Packages/User/
folder we can tie it to a keyboard shortcut like so:
{ "keys": ["super+r"], "command": "insert_snippet", "args": { "name": "Packages/User/wrap-anything.sublime-snippet" } },
Now when we hit cmd+r
it will let us wrap our current selection in whatever we want :)
For good measure here's a really useful console.log snippet that's triggered by typing lg
and then pressing tab
.
<snippet>
<content><![CDATA[console.log(${1});]]></content>
<tabTrigger>lg</tabTrigger>
<scope>source.js</scope>
<description>console.log()</description>
</snippet>
No need to bind this to a keyboard shortcut (unless you want to) because it defines a tab trigger. I know this wasn't super in-depth but hopefully it gives you a little bit of a start. Read the documentation on snippets and tighten up your regex! - Rob
You should follow me on Twitter here.
- Mood: Tired, Lazy
- Sleep: 5
- Hunger: 0
- Coffee: 1