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.

Alibaba Terminal Technology
Alibaba Terminal Technology
Alibaba Terminal Technology
Build Your Own VSCode Code Completion Plugin from Scratch

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

TypeScriptJavaScriptcode completionExtensionVSCodeDeveloper Tools@snippet
Alibaba Terminal Technology
Written by

Alibaba Terminal Technology

Official public account of Alibaba Terminal

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.