Snippets plugin¶
Type a short prefix, press ++tab++, and it expands into a whole construct —
a for loop, a class skeleton, a Markdown table — with the caret ready on the
first blank you need to fill. Tab/Shift+Tab cycle the fields,
Esc finishes. The plugin also provides File ▸ New from Template… for
scaffolding whole files.
Expanding a snippet¶
- Type a snippet's prefix (say
forin a C++ file). - Press ++tab++. The prefix is replaced by the snippet body — as one undo step — and the first field is selected, ready to overtype.
- Press ++tab++ to jump to the next field, ++shift+tab++ to go back.
- After the last field, ++tab++ places the caret at the snippet's final position. ++esc++ ends the session at any point, leaving the text as typed.
If the word before the caret is not a snippet prefix, ++tab++ indents as usual — the key is only borrowed when there is something to expand. While the completion popup is open, ++tab++ belongs to the popup.
A multi-line expansion inherits the indentation of the line you typed it on, and its line endings follow the document's convention (CRLF/LF).
Snippets in the completion popup¶
Snippet prefixes also appear in the auto-completion popup, marked with a small glyph so they stand out from plain words. Accepting a snippet item expands it immediately and starts the field session — the same as typing the prefix and pressing ++tab++.
What a snippet can contain¶
| Token | Meaning |
|---|---|
$1 … $9 |
Tab-stop fields, visited in numeric order (regardless of their position in the body). |
${1:default} |
A field with initial content, selected when visited. |
$0 |
Where the caret ends up after the last field (defaults to the end of the snippet). |
$FILENAME |
The document's file name (empty for unsaved buffers). |
$DATE |
Today's date, ISO format (2026-07-06). |
$SELECTION |
The text selected when the snippet was triggered. |
$CLIPBOARD |
The clipboard's current text. |
\$ |
A literal dollar sign. |
Anything malformed is inserted literally rather than failing. A field index repeated in the body keeps only its first occurrence as a live field.
Managing snippets¶
Preferences ▸ Snippets lists every snippet — the bundled sets and your own. From there you can:
- Add… a new snippet: prefix, scope (comma-separated language ids such as
cpp, c; empty or*applies everywhere), description, and the body. - Edit… your snippets. Editing a bundled snippet creates your own copy, which takes precedence over the bundled one (same prefix and scope).
- Remove your snippets (bundled ones cannot be removed — shadow them instead).
Bundled sets ship for C/C++, Python, JavaScript/TypeScript and Markdown, plus
two universal helpers (date, clip). Your snippets are stored as JSON in
the plugin's data directory (snippets/user.json); you can also drop
additional *.json files there — the format matches the bundled files:
{
"language": ["cpp", "c"],
"snippets": [
{
"prefix": "for",
"description": "indexed for loop",
"body": ["for (${1:int i = 0}; ${2:i < count}; ${3:++i})", "{", "\t$0", "}"]
}
]
}
Bodies are arrays of lines. A per-snippet "scopes" array overrides the
file-level "language" default.
File templates¶
File ▸ New from Template… opens a picker of file scaffolds — a C++ source
with main, a header with an include guard, a Python script, a Markdown
document, an HTML page. The chosen template opens as a new unsaved document
with its variables ($DATE, $CLIPBOARD, …) already substituted; field
tokens collapse to their default text.
Templates are JSON files too (templates/*.json, both bundled and in the
plugin's data directory):
{
"templates": [
{
"name": "Python script",
"suggestedName": "script.py",
"body": ["#!/usr/bin/env python3", "", ""]
}
]
}
Limitations¶
- A repeated field index is not mirrored (typing in field 1 does not update
a second
$1); later occurrences are plain text. - Nested placeholders (
${1:${2:x}}) are not supported; the inner text is taken literally. $FILENAMEis empty in unsaved buffers.