12. Snippets
12.1. Snippets vs Completions
Snippets, like Completions, are “smart templates” providing dynamically-populated template text to insert into whatever text is being edited. Snippets provide a part of the full Completions functionality of Sublime Text. Specifically, a Snippet can appear in a Completions popup list, and Snippets and Completions share 95% of their functionality.
The one thing that Completion Objects have that Snippets don’t is their “details” dictionary entry, whose value is designed to appear at the bottom of the Completions popup list. See Completions File Format for details.
And the one thing Snippets can do that a regular Completion cannot is accommodate Custom Variables from within Text Commands as described below.
Otherwise, technically, Snippets can do everything Completions can do, and vice versa.
However, there are some differences between the two that makes the choice of one over the other dependent on the nature of the template and when and where it will be used.
The difference between Snippets and Completions are:
A Completion is activated by the user simply typing, or calling up a Completions list by hitting
[Ctrl+Space]. This is most useful where there can be multiple choices of templates. For example, in some programming languages the trigger text “for” might be prefixes for:the “for” keyword,
the “foreach” keyword,
a function beginning with (or containing) “for”,
a variable beginning with (or containing) “for”,
etc.
A Snippet is activated by:
the user typing part or all of its “tabTrigger” text and hitting the
[Tab]key,by choosing it from a Completions popup list, or
running the
insert_snippetcommand wherever Commands can be run:Command Palette items, and
via calling
view.run_command('<command_name>', {args})from within a Plugin.
In this author’s opinion, Snippets are most useful when there is only one choice of which template to use.
Completions are more suited to providing smaller amounts of template text while the user is typing. Their content, is most commonly provided via
.sublime-completionsfiles using JSON strings.Customized control and content of the Completions list can also be provided via a Plugin. See Implementing Completions in a Plugin for details.
Snippets are more suited to longer and more complex (e.g. multi-line) content. Their content can be provided via
a string passed as the “contents” entry in the
argsdictionary passed to theinsert_snippetcommand, orthe
<content>tag inside a simplified XML file whose path is passed as the “name” entry in theargsdictionary passed to theinsert_snippetcommand.
It is this latter format that makes Snippets better suited to long and complex (especially multi-line) content in the template text.
Snippets do not have the “kind” and “details” entries that Completions have, since these details are geared toward decorating the Completions popup list. When Snippets appear in Completions popup lists, their “kind” is already pre-populated as a “snippet”, and the only details available are the annotation text provided by a Snippet file’s
<description>element. (See below.)Completions do not have the ability to use Custom Variables.
12.2. Snippet Files
Snippet files contain most of the same elements as Completion Objects, but are defined in simplified XML format, one Snippet per
file, with a .sublime-snippet extension. Snippet files can be found anywhere
inside Package directories (including the User Package); they are not restricted to
the root directory of the Package. Snippet files can have any file stem.
For example, the shipped XML Package contains a subdirectory named Snippets, where
all of its Snippet files are contained.
The content of Snippet files is identical to the scope, trigger, contents,
and details of Completion files, except for the format of the <content>
element—a single XML CDATA tag, which is what makes it easier to work with large
content, since it can contain line endings embedded in the formatted text, unlike
contents entries in Completion files, which, when they are contained in
.sublime-completions files (i.e. not from within a Plugin), must be
entirely contained inside JSON strings. Example:
<snippet>
<scope>source.python</scope>
<tabTrigger>fun</tabTrigger>
<content><![CDATA[def ${1:name}($2):
${0:pass}]]></content>
<description>function, non-async</description>
</snippet>
XML Element |
Completion Equivalent |
Description |
|---|---|---|
scope |
scope |
optional, selector syntax; see Selector |
tabTrigger |
trigger |
optional, text that begins snippet |
content |
contents |
required, a single |
description |
annotation |
optional, contains a short annotation shown to right of completions popup showing what it is |
An astute reader might ask why the <tabTrigger> element is not required when its
counterpart is required in Completions files. The answer is that it is required
only in the case when the Snippet is expected to be inserted as a result of the user
typing that text (or an approximation of it) followed by the [Tab] key (or
[Ctrl+Space] to insert it via the Completions popup list). The exception (making it
optional) is when Snippets are inserted via a Plugin calling the
insert_snippet Command, in which case the <tabTrigger> element is not
required in order to make use of it.
12.3. Smart-Template Syntax
Both Completions and Snippets provide the ability to dynamically insert static text. In addition, both can use the following dynamic text sources:
user-editable Fields which can optionally contain default or placeholder text
the contents of Predefined Variables
the contents of Custom Variables (via Plugin)
Substitutions, which can take input from any of the above dynamic sources.
12.3.1. Literal “$”
Because $ has special meaning inside Snippets, if you need for the Snippet to
insert an actual ‘$’ into the text, simply escape it with a ‘' like this: \$.
Example:
<snippet>
<content><![CDATA[
You owe me \$20.
]]></content>
...
</snippet>
12.3.2. Fields
Both Snippets and Completions can contain an unlimited number of user-editable
“fields”($1, $2, etc.). When fields are present, Sublime Text goes into a
“form mode” wherein hitting [Tab] and [Shift+Tab] makes the cursor jump to the next
and previous field respectively, until tabbing out of the last field where the $0
field, if present, marks the position where the cursor will be placed when the user
tabs past the last field. If the $0 field is not present, then the cursor is placed
at the end of the content. At any the user can [Esc]ape out of the template’s “form
mode”, in which case the cursor is left where it was when [Esc] was pressed, and any
default or placeholder text provided (see below) is left in its current state.
Any single “field” (e.g. $1) can appear in one or many places in the Snippet by simply
having that field number coded into the template in multiple places. The result of
this is that when the user tabs to that “field”, Sublime Text creates that many
selections so that subsequent keystrokes go into all N “fields” at once.
If needed for readability or parsability (to separate the field numbers from
surrounding text), these “fields” can also be coded with curly braces like this:
${1}, ${2}, etc.. This format can be mixed-and-matched with the bare format
shown above. When there is default text or a Substitution
involved, use of the curly-braces format is required.
12.3.2.1. Default Text
If you want to provide “default text” or “placeholder text”, you can do so by coding
the fields like this: ${1:placeholder text}. Whatever its purpose is, if the
user does not change it (i.e. escapes “form mode” or tabs past it), that text will be
left in the field as it is. When focus arrives in that field, the text is initially
selected, so any keystrokes of printable characters replaces the whole text.
If there are multiple fields with the same number (a.k.a. mirrored fields), the default text need only placed in ONE instance of that field. If you manage to have the same-numbered field in more than one place with different default text, the first one encountered wins and overwrites the other instances of default text when the template is expanded.
12.3.3. Predefined Variables
Any number of predefined “variables” can appear in Completion- or Snippet templates.
They look like this: $VAR_NAME or ${VAR_NAME}. Like numbered fields, braces
can also be used with them to make them more readable or more parse-able as the case
may be (i.e. to separate them from surrounding text).
Variables can be used:
by themselves
as default text in numbered fields
as input fields for Substitutions (see below).
In each case they will be dynamically replaced as the template is expanded.
The following predefined variables are provided by Sublime Text for this purpose:
Variable |
Description |
|---|---|
$SELECTION |
The text selected when template was expanded |
$TM_SELECTED_TEXT |
An alias for $SELECTION |
$TM_LINE_INDEX |
Column where template is being expanded, 0 based |
$TM_LINE_NUMBER |
Row where template is being expanded, 1 based |
$TM_CURRENT_LINE |
Content of cursor’s line when template was expanded |
$TM_CURRENT_WORD |
Word under cursor when template was expanded |
$TM_DIRECTORY |
Directory name of file being edited (since 3154) |
$TM_FILENAME |
Name of file being edited, including extension |
$TM_FILEPATH |
Full path of file being edited |
$TM_FULLNAME |
User’s user name |
$TM_TAB_SIZE |
Spaces per-tab (controlled by tab_size option) |
$TM_SOFT_TABS |
YES if |
$TM_SCOPE |
The scope of beginning of each selected region. (since build 3154) |
Example:
# Template Content:
=================================
USER NAME: $TM_FULLNAME
FILE NAME: $TM_FILENAME
TAB SIZE: $TM_TAB_SIZE
SOFT TABS: $TM_SOFT_TABS
=================================
# Output:
=============================
USER NAME: guillermo
FILE NAME: test.txt
TAB SIZE: 4
SOFT TABS: YES
=============================
12.3.4. Combining Form Fields with Variables
Inside a Snippet, you can provide default text for a “form field” using a variable, like this:
${1:${TM_FILENAME}}
${1:${my_custom_variable}}
See Custom Variables below for how to provide variables with custom names.
12.3.5. The insert_snippet Command
In addition to triggering a Snippet using prefix (trigger) text followed by the [Tab]
key, you can run the insert_snippet Command in all ways Commands can be run:
Command Palette items, and
via calling
view.run_command('<command_name>', {args})from within a Plugin.
In all of these cases, an args dictionary object is created and passed to the
command as its single argument.
12.3.5.1. insert_snippet Arguments
There is only one required argument in the args dictionary, and that is to tell
the insert_snippet command where to get the Snippet’s content. Do this by
supplying a single dictionary entry with one of these two keys:
“name”; value is the path to the target Snippet file
“contents”; value is a string containing the template content.
All additional dictionary entries become variables available from within the Snippet. Additional arguments are covered in Custom Variables below.
12.3.6. Custom Variables
Custom variables can be supplied to a Snippet by:
Running the
insert_snippetcommand from within a Plugin, passing it a singleargsdictionary object. The name of the variable usable within the Snippet is the name of the key in the dictionary entry. Python dictionaries are not limited in number of entries, and thus that dictionary argument is not limited in the number or names of the provided custom Snippet variables except for the reserved names mentioned above (“name” and “content”). For variables whose values need to be dynamically computed, using this method is the only option.Hard-coding a fixed
argsargument dictionary (names and values) in a Menu Option, Key Binding or Command Palette entry. This is somewhat limited because the actual argument names and values have to be hard-coded in the respective JSON files that make these up. Any number of variable names and hard-coded values can be used.
You do either of the above by creating an args dictionary with one of the required
keys mentioned above (“name” or “contents”), plus one additional entry for each
custom variable with:
key = variable name, and
value = variable (string) content [1]
This dictionary is then passed as the single argument to the insert_snippet
command like this:
args = {
"name": "path/to/snippet_file",
"var1": value1,
"var2": value2,
# etc.
}
# or
args = {
'contents': '${var1} other template content',
'var1': "It works!"
}
# ...followed by...
self.view.run_command("insert_snippet", args)
Here is a real example from the ProComment Package, which is used with a user-customizable Snippet file:
result_args = {
# Path to Snippet File
'name' : snippet_relative_path,
# Comment Parts
'original_start_comment': start_str,
'start_comment' : drawn_start_str,
'end_comment' : end_str,
'line_prefix' : line_prefix,
'trimmed_pfx' : line_prefix.rstrip(),
'drawn_top_line' : drawn_top_line,
'drawn_bottom_line' : drawn_bottom_line,
'initial_content' : initial_txt,
# Copyright Holder / Coding-Style Info
'copyright_holder' : copyright_holder,
'coding_style_info' : coding_style_info,
# Time Strings
'year' : year,
'timestamp' : timestamp,
'datestamp' : datestamp,
# File Names
'file_full_path' : file_full_path,
'file_dir' : file_dir,
'file_name' : file_name,
'file_ext' : file_ext,
'file_base_name' : file_base_name,
'file_base_name_lower' : file_base_name.lower(),
'file_base_name_upper' : file_base_name.upper(),
# Spaces
'incl_comment_alignment_spaces': incl_spaces
}
# ...
self.view.run_command("insert_snippet", args)
Note that variables are being used and functions are being called where the dictionary is being assembled in order to build or compute the needed strings.
Keep in mind:
The source of the value of the template’s contents is limited only by what you can do within a Text Command, so it could come from an external file, the returned text from a URL request, or virtually anywhere.
Each custom variable can appear any number of times within the template, including not appearing at all.
This opens the door to a very large potential for dynamically-populated templates!
12.3.7. Substitutions
Substitutions use input text, combined with Regular Expressions “replace” syntax, to operate on that input text to form additional dynamic replacement text “fields”.
The input thus supplied can be from:
user-editable Fields which can optionally contain default or placeholder text
the contents of Predefined Variables
the contents of Custom Variables (via Plugin)
The syntax for these “fields” looks like this:
${input_source/regex/format_string/}, or${input_source/regex/format_string/options}.
where
- input_source:
is a variable or numbered field name (e.g. 1, 2, TM_FILENAME, SELECTION, var1, pc_timestamp, etc.).
- regex:
Perl-style regular expression to interact with input text
- format_string:
Regular-Expression “replace” syntax (covered below)
- options:
Subset of Perl regex options:
i,gand/orm
Options:
i = ignore case,
g = global (continue repeating search/replace until input string is exhausted),
m = multi-line, makes
^and$match at start and end of each line.
Metacharacters recognized in “format_string” field:
- \1, \2, \3 ...:
Matches the text from the Nth group
- \g1 or \g{1}, \g2 ...:
Matches the text from the Nth group (this format enables field numbers to go higher than 9)
- \l:
Lowercase next character
- \u:
Title-case next character
- \L:
Lowercase until \E
- \U:
Uppercase until \E
- \F:
Fold-case until \E
- \Q:
Disable pattern metacharacters until \E
- \E:
End modification
Examples:
${1/(.)/\U\1/g} converts field ${1}’s final text to upper-case both the default
value and any keystrokes typed into the input field.
Two mirrored fields like this could serve to provide a document title and the underline just below it:
# Coding in Snippet content
${1:title}
${1/./=/g} <-- means all input characters are converted to '='
# Output
Your Document Title
===================
You might find this implementation of 4 mirrored fields useful for reStructuredText documents:
# Coding in Snippet content
.. include:: custom_tools.txt
.. _${1/(.)/\l\1/g}:
${1/./*/g}
${1:title}
${1/./*/g}
$0
# Output
.. include:: custom_tools.txt
.. _your document title:
*******************
Your Document Title
*******************
|
And this example might be used in a context dealing with JavaScript files:
# For TM_FILENAME=MyModule.js
# Coding in Snippet content
``${TM_FILENAME/(\w+)\.js/\1/g}``
# Output:
MyModule
12.4. Creating Snippets
Start a new Snippet by: Tools > Developer > New Snippet...
12.5. Finding Snippets
Find Snippets by: Tools > Snippets...
12.6. Further Reading
See https://docs.sublimetext.io/guide/extensibility/snippets.html#environment-variables for more details.