Build Your Own VSCode Code Completion Plugin from Scratch
This tutorial walks you through the entire process of creating a custom VSCode code‑completion extension, covering environment setup, the mechanics of suggestion panels, snippet configuration, core API usage, and advanced personalization techniques such as dictionary‑based word completion and automatic updates.
Introduction
As a front‑end developer you have probably used VSCode, whose powerful extension ecosystem now hosts over 30,000 plugins. While many extensions provide code suggestions (e.g., TabNine, Copilot), this guide shows how to build your own dedicated code‑completion plugin.
Preparation
Environment Setup
Set up the VSCode extension development environment following the official guide at code.visualstudio.com/api/get-started/your-first-extension .
Understanding Code Suggestions
VSCode shows a panel with possible completions based on the current input. Press enter or tab (configurable) to insert the selected suggestion, dramatically speeding up coding.
The suggestions come from several sources:
LSP (Language Server Protocol) implementations, e.g., TypeScript provides keywords like const, console, continue when you type con.
Built‑in code snippets, which can be customized or extended with your own snippets.
Object‑path and export suggestions that automatically add import statements.
Other installed extensions that contribute completion items.
Plugin Development
Snippet Configuration
There are two ways to add snippets:
Directly configure them in VSCode via the command palette and edit the language‑specific JSON file.
Create a snippet‑contributing extension by adding a JSON file to the extension root and declaring it in package.json:
{
"contributes": {
"snippets": [
{"language": "typescriptreact", "path": "./snippets.json"},
{"language": "typescript", "path": "./snippets.json"},
{"language": "javascript", "path": "./snippets.json"},
{"language": "javascriptreact", "path": "./snippets.json"}
]
}
}Snippet Ideas
Example component snippet:
{
"component": {
"prefix": ["component"],
"body": [
"import * as React from 'react';",
"",
"export interface IProps {",
"\t${1}",
"}",
"",
"const ${2}: React.FC<IProps> = (props) => {",
"\tconst { } = props;",
"",
"\treturn (",
"\t\t<div className=\"component-${3}\">",
"\t\t\t${4}",
"\t\t</div>",
"\t);",
"};",
"",
"export default ${2};",
""
],
"description": "Generate component template"
}
}Import snippet (fixes double‑quote issue):
{
"import": {
"prefix": "import",
"body": ["import ${1} from '${2}';"],
"description": "Import statement"
}
}Region snippet for custom code blocks:
{
"region": {
"prefix": "region",
"body": ["// #region ${1}
${2}
// #endregion"],
"description": "Custom code block"
}
}Code Recommendation Plugin
After scaffolding the extension, edit src/extension.ts. The file contains two lifecycle methods, activate and deactivate. The completion logic lives inside activate.
The core API is vscode.languages.registerCompletionItemProvider, which registers a provider for specified languages.
Basic Completion Example
import * as vscode from 'vscode';
const LANGUAGES = ['typescriptreact', 'typescript', 'javascript', 'javascriptreact'];
export function activate(context: vscode.ExtensionContext) {
const triggers = [' '];
const completionProvider = vscode.languages.registerCompletionItemProvider(
LANGUAGES,
{
async provideCompletionItems(document, position, token, context) {
const completionItem: vscode.CompletionItem = { label: 'Hello VsCode' };
return [completionItem];
}
},
...triggers
);
context.subscriptions.push(completionProvider);
}Word‑Based Completion
Load a simple dictionary and suggest words that start with the current text:
import * as vscode from 'vscode';
const LANGUAGES = ['typescriptreact', 'typescript', 'javascript', 'javascriptreact'];
const dictionary = ['hello', 'nihao', 'dajiahao', 'leihaoa'];
export function activate(context: vscode.ExtensionContext) {
const triggers = [' '];
const completionProvider = vscode.languages.registerCompletionItemProvider(
LANGUAGES,
{
async provideCompletionItems(document, position) {
const range = new vscode.Range(new vscode.Position(position.line, 0), position);
const text = document.getText(range);
const items = dictionary
.filter(item => item.startsWith(text))
.map((item, idx) => ({
label: item,
preselect: idx === 0,
documentation: 'My custom VSCode suggestion',
sortText: `my_completion_${idx}`
}));
return items;
}
},
...triggers
);
context.subscriptions.push(completionProvider);
}Improvements can include more robust matching (e.g., fuzzy matching) and richer documentation for each word.
Personalized Recommendations
To make suggestions truly personal, record the developer’s own code usage, build a dictionary from the codebase, and update it automatically when a suggestion is chosen. The extension registers a command that runs on selection to update the dictionary.
function registerCommand(command: string) {
vscode.commands.registerTextEditorCommand(command, (editor, edit, ...args) => {
const [text] = args;
// TODO: Record current content to the dictionary and update it
});
}
const COMMAND_NAME = 'my_code_completion_choose_item';
export function activate(context: vscode.ExtensionContext) {
const triggers = [' '];
registerCommand(COMMAND_NAME);
const completionProvider = vscode.languages.registerCompletionItemProvider(
LANGUAGES,
{
async provideCompletionItems(document, position) {
const range = new vscode.Range(new vscode.Position(position.line, 0), position);
const text = document.getText(range);
const items = dictionary
.filter(item => item.startsWith(text))
.map((item, idx) => ({
label: item,
preselect: idx === 0,
documentation: 'My custom VSCode suggestion',
sortText: `my_completion_${idx}`,
command: { arguments: [text], command: COMMAND_NAME, title: 'choose item' }
}));
return items;
}
},
...triggers
);
context.subscriptions.push(completionProvider);
}Further enhancements could move the update logic to a background process, suggest whole sentences, and refine ranking based on usage frequency.
Conclusion
By following these simple examples you can see that building a VSCode extension is not difficult. Create your own personalized plugin to boost productivity, and experiment with custom ideas to turn your editor into a powerful development assistant.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
