Template-based completions with field navigation, supporting placeholders, default values, and tab-stop functionality for creating interactive code templates.
Functions for creating and managing snippet-based completions with field navigation.
/**
* Convert a snippet template to a function that can apply it
*/
function snippet(template: string): (editor: {state: EditorState, dispatch: (tr: Transaction) => void}, completion: Completion | null, from: number, to: number) => void;
/**
* Create a completion from a snippet template
*/
function snippetCompletion(template: string, completion: Completion): Completion;Template Syntax:
Snippets use ${} or #{} placeholders for fields:
${} or #{name} - Named field with optional default content${1} or ${1:default} - Numbered field with optional default\\{ or \\} - Literal braces (escaped)Usage Examples:
import { snippet, snippetCompletion } from "@codemirror/autocomplete";
// Simple snippet templates
const forLoopSnippet = snippet("for (let ${index} = 0; ${index} < ${end}; ${index}++) {\n\t${}\n}");
const functionSnippet = snippet("function ${name}(${params}) {\n\t${body}\n\treturn ${return};\n}");
// Numbered fields for specific order
const ifElseSnippet = snippet("if (${1:condition}) {\n\t${2}\n} else {\n\t${3}\n}");
// Snippet completions
const snippetCompletions = [
snippetCompletion("for (let ${i} = 0; ${i} < ${length}; ${i}++) {\n\t${}\n}", {
label: "for",
detail: "for loop",
type: "snippet"
}),
snippetCompletion("console.log(${message});", {
label: "log",
detail: "console.log statement",
type: "snippet"
}),
snippetCompletion("try {\n\t${}\n} catch (${error}) {\n\t${}\n}", {
label: "try",
detail: "try-catch block",
type: "snippet"
})
];Commands and utilities for navigating between snippet fields.
/**
* Move to the next snippet field
*/
const nextSnippetField: StateCommand;
/**
* Move to the previous snippet field
*/
const prevSnippetField: StateCommand;
/**
* Clear the active snippet
*/
const clearSnippet: StateCommand;
/**
* Check if there is a next field available
*/
function hasNextSnippetField(state: EditorState): boolean;
/**
* Check if there is a previous field available
*/
function hasPrevSnippetField(state: EditorState): boolean;Usage Examples:
import { nextSnippetField, prevSnippetField, clearSnippet, hasNextSnippetField } from "@codemirror/autocomplete";
// Check field availability and navigate
const handleTabKey = (view: EditorView) => {
if (hasNextSnippetField(view.state)) {
return nextSnippetField(view);
}
// Handle normal tab behavior
return false;
};
// Custom snippet navigation
const customSnippetCommands = [
{
key: "Tab",
run: nextSnippetField
},
{
key: "Shift-Tab",
run: prevSnippetField
},
{
key: "Escape",
run: clearSnippet
}
];Configurable key bindings for snippet field navigation.
/**
* Facet for configuring snippet key bindings
*/
const snippetKeymap: Facet<readonly KeyBinding[], readonly KeyBinding[]>;Default Bindings:
Tab - Move to next field (nextSnippetField)Shift-Tab - Move to previous field (prevSnippetField)Escape - Clear snippet (clearSnippet)Usage Examples:
import { snippetKeymap } from "@codemirror/autocomplete";
import { keymap } from "@codemirror/view";
// Custom snippet key bindings
const customSnippetKeys = [
{ key: "Tab", run: nextSnippetField },
{ key: "Shift-Tab", run: prevSnippetField },
{ key: "Ctrl-Escape", run: clearSnippet }
];
const view = new EditorView({
extensions: [
// Override default snippet keymap
snippetKeymap.of(customSnippetKeys),
keymap.of(customSnippetKeys)
]
});Complex snippet templates with multiple fields, default values, and nested structures.
Usage Examples:
// Class definition with multiple fields
const classSnippet = snippetCompletion(`class \${1:ClassName} {
constructor(\${2:params}) {
\${3:// constructor body}
}
\${4:methodName}(\${5:params}) {
\${6:// method body}
return \${7:result};
}
}`, {
label: "class",
detail: "class definition",
type: "snippet"
});
// React component snippet
const reactComponentSnippet = snippetCompletion(`import React from 'react';
interface \${1:ComponentName}Props {
\${2:prop}: \${3:string};
}
const \${1:ComponentName}: React.FC<\${1:ComponentName}Props> = ({ \${2:prop} }) => {
return (
<div>
\${4:// component content}
</div>
);
};
export default \${1:ComponentName};`, {
label: "rfc",
detail: "React functional component",
type: "snippet"
});
// Function with JSDoc
const jsdocFunctionSnippet = snippetCompletion(`/**
* \${1:Description}
* @param {\${2:type}} \${3:param} \${4:Parameter description}
* @returns {\${5:type}} \${6:Return description}
*/
function \${7:functionName}(\${3:param}) {
\${8:// function body}
return \${9:result};
}`, {
label: "jsfunc",
detail: "function with JSDoc",
type: "snippet"
});Integrating snippets with completion sources and language support.
Usage Examples:
import { autocompletion, snippetCompletion, completeFromList } from "@codemirror/autocomplete";
// Combine snippets with other completions
const jsCompletions = [
// Regular completions
...["const", "let", "var", "function", "class"].map(kw => ({ label: kw, type: "keyword" })),
// Snippet completions
snippetCompletion("const ${name} = ${value};", {
label: "const",
detail: "const declaration",
type: "snippet"
}),
snippetCompletion("function ${name}(${params}) {\n\t${}\n}", {
label: "func",
detail: "function declaration",
type: "snippet"
})
];
// Language-specific snippet source
const jsSnippetSource = completeFromList(jsCompletions);
const view = new EditorView({
extensions: [
autocompletion({
override: [jsSnippetSource]
})
]
});Creating snippets programmatically based on context.
Usage Examples:
import { CompletionContext } from "@codemirror/autocomplete";
// Context-aware snippet generation
const dynamicSnippetSource = (context: CompletionContext) => {
const token = context.matchBefore(/\w+$/);
if (!token) return null;
const snippets = [];
// Generate different snippets based on context
if (token.text.startsWith("for")) {
snippets.push(
snippetCompletion("for (let ${i} = 0; ${i} < ${arr}.length; ${i}++) {\n\t${}\n}", {
label: "fori",
detail: "for loop with index",
type: "snippet"
}),
snippetCompletion("for (const ${item} of ${arr}) {\n\t${}\n}", {
label: "forof",
detail: "for-of loop",
type: "snippet"
})
);
}
if (token.text.startsWith("if")) {
snippets.push(
snippetCompletion("if (${condition}) {\n\t${}\n}", {
label: "if",
detail: "if statement",
type: "snippet"
})
);
}
return snippets.length ? {
from: token.from,
options: snippets
} : null;
};