×
Community Blog Develop a Dedicated Code Hinting Plug-In for VsCode

Develop a Dedicated Code Hinting Plug-In for VsCode

The article explains code hinting and simple examples of code completion to show the ability of the VsCode plug-ins to assist development.

By Qinqi

Most frontend developers have used VsCode. It is a handy tool, and its powerful plug-in capability undoubtedly makes us fall deeply in love with it. According to incomplete statistics, the number of VsCode plug-ins in the plug-in market has exceeded 30,000, which shows how enthusiastic everyone is about VsCode plug-ins. Plug-ins involve various features, such as thematic songs and code development, including code snippets, Git plug-ins, tslint, etc. As a developer, you must have used various plug-ins for code hinting represented by TabNine, Copilot, etc. Today, let's develop a dedicated code hinting plug-in by ourselves.

Pre-Development Preparation

Environment Setup

There are many tutorials on the development environment setup of VsCode plug-ins online, which will not be repeated in this article. Please refer to this link for more details.

About Code Hinting

The code hinting here means that in the process of writing code, based on the current input, VsCode will pop up with a panel showing some of the possible input. If there is the input you expect, you can directly press the Enter or Tab key (which can be modified in the setting) to enter the recommended code into the editor. This can improve the efficiency of development. After all, writing a line of code by directly pressing a key is far more efficient than typing characters one by one.

1

So far, you may have been curious about a few things. Where does the code come from among so many recommended options? Why are some options recommended that you do not expect at all? According to my research (I have not seen the source code), the sources of those options are listed below:

1.  The specific implementation of Language Service Protocol (LSP) is the language supported by VsCode. For example, if you select TypeScript, when you write code, there will be hints related to ts syntax. For example, if con is entered, the const, console, and continue are keywords in ts syntax.

2.  Various Built-In Code Snippets: VsCode has many built-in code snippets, which can also help us input quickly. General code snippets have more than one line of code, which can help us omit a lot of input. In addition to the built-in code snippets, we can configure our code snippets, which are also part of our dedicated plug-ins.

2
3

3.  Object Path and Exported Object Hints: For example, I set an APP constant and a Test method in another file. Then, if I enter the AP in the current file, I can see that the first item is the constant defined previously. After pressing the Tab key at this time, the variable name will be completed, and the import sentence will be added at the top.

4
5

4.  The last part is options provided by various plug-ins. This part is also the main content of our development of the dedicated plug-ins today. The numerous plug-ins have brought a lot of hints, but they have also increased the burden on us to identify and think. We are required to find the code we want among pages of hints, but we would have already typed out the whole code during that time. Therefore, a plug-in is not a panacea, and more plug-ins do not lead to better effects. It is enough to install some commonly used and easy-to-use plug-ins.

6

Plug-In Development

The Configuration of Code Snippets

There are two ways to configure code snippets:

1.  The code snippets are directly configured in VsCode:

  • Call out the VsCode command panel and find the configuration of code snippets.

7

  • Select the language to be configured. For example, select typescriptrect here, which is the commonly used .tsx file. (This is the key of the tsx file in VsCode.)

8

  • After you select this option, the current local default code snippet configuration is displayed. For example, it is the configuration for Python. All we have to do is add our code snippets in this json file.

9

2.  Plug-ins for developing code snippets:

At the same time, you can develop a plug-in related to a code snippet, so no matter where you are, the corresponding plug-in directly downloaded can be common to multiple editors, which is much better than saving locally. The development of plug-ins of code snippets is relatively simple and only requires two steps:

  • Add a configuration file in the json format to the plug-in scaffolding root directory
  • Add the following configuration to the package.json: The effect is to declare the information related to the code snippets, including the corresponding language, which is, the file type and paths corresponding to the code snippets. The following shows the same configuration file applied to ts, tsx, js, and jsx files at the same time.
"contributes": {
        "snippets": [
            {
                "language": "typescriptreact",
                "path": "./snippets.json"
            },
            {
                "language": "typescript",
                "path": "./snippets.json"
            },
            {
                "language": "javascript",
                "path": "./snippets.json"
            },
            {
                "language": "javascriptreact",
                "path": "./snippets.json"
            }
        ]
    },

Some Ideas for Code Snippets

The code snippets are relatively simple, which configure some fixed modes and enter them directly through shortcut keys. Here are several ideas:

  • Code Snippets of Component Development: Since the development of new components has a lot of fixed contents every time, it is easy to put the code into the code snippets. Here is a piece of reference:
"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 templates"
    },
  • The Import Statement: The import statement exists, but the default state is double quotation marks, and it is very annoying to use autofix every time. You can use a few lines of code to fix it.
"import": {
        "prefix": "import",
        "body": [
            "import ${1} from '${2}';"
        ],
        "description": "import"
    }
  • I prefer to customize some blocks of code, so I often use the operation of region and write the operation down as a code snippet.
 "region": {
        "prefix": "region",
        "body": [
            "// #region ${1}\n ${2}\n// #endregion"
        ],
        "description": "customized code blocks"
    },

Tips: There are many variables above, such as ${1}. Please see the official documents for more information. It is convenient to record some commonly used and fixed templates.

Code Recommendation Plug-Ins

Let's customize our dedicated plug-ins.

Understanding Scaffold Holders

First of all, after the scaffold is initialized, let's look at the code directory. The extension.ts in src directory is the code of plug-ins we want to write, and we can see that the initialized file looks like this:

It contains two methods, activate and deactivate, and a large number of comments. Generally, each plug-in has its own lifecycle, and these two lifecycle methods correspond to the lifecycles of activation and deregistration of a plug-in. Our main recommendation logic is also written in the activate method.

10

API in Use

The most basic API we use is the registerCompletionItemProvider, which is located under the vscode.languages namespace. As the name implies, this method registers a provider for code completion. Please see the official documents for more information on API.

Basic Code

import * as vscode from 'vscode';

/** Supported language type */
const LANGUAGES = ['typescriptreact', 'typescript', 'javascript', 'javascriptreact'];

export function activate(context: vscode.ExtensionContext) {
    /** Trigger a list of recommended characters */
    const triggers = [' '];
    const completionProvider = vscode.languages.registerCompletionItemProvider(LANGUAGES, {
        async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) {
            const completionItem: vscode.CompletionItem = {
                label: 'Hello VsCode',
            };
            return [completionItem];
        }
    }, ...triggers);

    context.subscriptions.push(completionProvider);
}

The section above is the most basic code for code completion. Register a completionProvider and return the vscode.CompletionItem array. You can see the result of the code above by pressing F5.

11

Customized Logic

The effect of the demo above is not what we expected. Since our goal is to develop dedicated plug-ins, it must be something different.

Support for Word Completion

If you are weak in English, you have to look up a slightly longer word in a dictionary. Why not use a plug-in to help us achieve this operation? The idea is simple. It is only requires a well-compiled English dictionary, download it to the local drive, and then look up the current input in the dictionary every time to return the best matching word. Here is the simplest implementation logic:

import * as vscode from 'vscode';

/** Supported language type */
const LANGUAGES = ['typescriptreact', 'typescript', 'javascript', 'javascriptreact'];

const dictionary = ['hello', 'nihao', 'dajiahao', 'leihaoa'];

export function activate(context: vscode.ExtensionContext) {
    /** Trigger a list of recommended characters */
    const triggers = [' '];
    const completionProvider = vscode.languages.registerCompletionItemProvider(LANGUAGES, {
        async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) {
            const range = new vscode.Range(new vscode.Position(position.line, 0), position);
            const text = document.getText(range);

            const completionItemList: vscode.CompletionItem[] = dictionary.filter(item => item.startsWith(text)).map((item, idx) => ({
                label: item,
                preselect: idx === 0,
                documentation: 'My dedicated VsCode plug-ins provider',
                sortText: `my_completion_${idx}`,
            }));
            return completionItemList;
        }
    }, ...triggers);

    context.subscriptions.push(completionProvider);
}

Here is the effect:

12

The code snippet above still needs a lot to improve, such as:

  • The Matching Logic of the Recommended Items: Currently, it is the string of the current line that matches the beginning of the word, which is problematic. If another character is added in the middle, it will be unable to match. Word segmentation or non-continuous matching needs to be considered. For example, when you input lh, leihaoa is recommended. Another way is to add no matching logic. No matter what input is, it will be thrown to VsCode, and VsCode matches itself. This is also possible. However, when your dictionary is large, it is not good enough. It is better to do a simple screening by yourself first.
  • There is too little information about words. Currently, there are only words, so it is better to add some explanation and usage.

Personalized Code Recommendation

There is nothing suiting you better than personalized code completion. After all, no one knows you better than you. Our general idea is simple and does not involve deep learning or the like. It requires you to record your input in the process of writing code and then process this data and form a document similar to a dictionary. The method is similar to the word completion mentioned above: looking up the input in the dictionary to obtain the best matching recommendation. At the same time, this dictionary must be updated automatically to meet our personalized requirements. Here are a few things to do:

  1. How can I obtain the initial document?
  2. How can I implement the automatic update logic of a dictionary?

Simple ideas:

1.  Take the code of your code library directly for extraction and processing to form an initial dictionary. Theoretically, the richer the code library, the more accurate the dictionary. However, it causes another problem:

  • How can I convert it from code to dictionary? If it is also processed simply, you can directly divide the code according to spaces and record the corresponding dictionary.
  • How can I determine the order of recommendations? The order of recommendations can be determined according to the number of appearances of the word: The larger the number, the higher the order.

2.  You can record the current document contents and update the dictionary every time you accept recommendations.

The process of transforming code into a dictionary and the code for automatically updating the dictionary are not displayed in this article. The preceding code is modified, and the general code is listed below:

import * as vscode from 'vscode';

/** The command triggered when the recommended item is registered */
function registerCommand(command: string) {
    vscode.commands.registerTextEditorCommand(
        command,
        (editor, edit, ...args) => {
            const [text] = args;
            // TODO records the current content in the dictionary and automatically updates the dictionary.
        }
    );
}

/** Supported language type */
const LANGUAGES = ['typescriptreact', 'typescript', 'javascript', 'javascriptreact'];

const dictionary = ['hello', 'nihao', 'dajiahao', 'leihaoa'];
/** Commands that are triggered after the user chooses items */
const COMMAND_NAME = 'my_code_completion_choose_item';

export function activate(context: vscode.ExtensionContext) {
    /** Trigger a list of recommended characters */
    const triggers = [' '];
    registerCommand(COMMAND_NAME);
    const completionProvider = vscode.languages.registerCompletionItemProvider(LANGUAGES, {
        async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext) {
            const range = new vscode.Range(new vscode.Position(position.line, 0), position);
            const text = document.getText(range);
            const completionItemList: vscode.CompletionItem[] = dictionary.filter(item => item.startsWith(text)).map((item, idx) => ({
                label: item,
                preselect: idx === 0,
                documentation: 'My dedicated VsCode plug-ins provider',
                sortText: `my_completion_${idx}`,
                command: {
                    arguments: [text],
                    command: COMMAND_NAME,
                    title: 'choose item'
                },
            }));
            return completionItemList;
        }
    }, ...triggers);

    context.subscriptions.push(completionProvider);
}

There is an additional registerCommand method, compared with word completion, and a command parameter is added to each recommended item. The logic is to trigger this command every time a recommended item is chosen and then update the dictionary. The implementation is for reference only. If you want to do it better, you can try it:

  1. To improve the logic of automatic update and put it backstage
  2. To implement the completion of a sentence, not just a single word
  3. To optimize the logic of sorting.

Summary

The simple examples of code completion mentioned above show the ability of the VsCode plug-ins to assist development. It is not difficult to write a plug-in. I hope you can write personalized plug-ins. At the same time, I expect to provide you with an idea. In the development, you can try some ideas by writing plug-ins that may be amazing tools for improving efficiency.

0 0 0
Share on

Alibaba F(x) Team

54 posts | 1 followers

You may also like

Comments