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:

  1. 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.

  2. 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_snippet command wherever Commands can be run:

    In this author’s opinion, Snippets are most useful when there is only one choice of which template to use.

  3. Completions are more suited to providing smaller amounts of template text while the user is typing. Their content, is most commonly provided via .sublime-completions files 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.

  4. 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 args dictionary passed to the insert_snippet command, or

    • the <content> tag inside a simplified XML file whose path is passed as the “name” entry in the args dictionary passed to the insert_snippet command.

    It is this latter format that makes Snippets better suited to long and complex (especially multi-line) content in the template text.

  5. 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.)

  6. 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 <![CDATA[...]]> tag with “smart template” syntax detailed below

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:

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 translate_tabs_to_spaces is true, otherwise NO

$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:

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_snippet command from within a Plugin, passing it a single args dictionary 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 args argument 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:

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, g and/or m

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.