如何编写 VS Code 扩展
VSCode 扩展

> 
> 通过为流行的代码编辑器编写自己的扩展来添加缺失的功能。
> 
> 
> 


![](/data/attachment/album/202006/13/105415w5u1d0z5bdoneb82.jpg)


Visual Studio Code（VS Code）是微软为 Linux、Windows 和 macOS 创建的跨平台代码编辑器。遗憾的是，微软版本的 [VS Code](https://code.visualstudio.com/) 是在 [Microsoft Software License](https://code.visualstudio.com/license) 下发布的，这不是一个开源的许可证。然而，它的源代码是开源的，在 MIT 许可证下由 [VSCodium](https://vscodium.com/) 项目发布。


VSCodium 和 VS Code一样，支持扩展、内嵌式 Git 控制、GitHub 集成、语法高亮、调试、智能代码补完、代码片段等。换句话说，对于大多数用户来说，使用 VS Code 和 VSCodium 没有什么区别，而且后者是完全开源的！ 


### 什么是 VS Code 扩展？


<ruby> 扩展 <rt>  extension </rt></ruby>可以让你为 VS Code 或 VSCodium 添加功能。你可以在 GUI 中或从终端安装扩展。


你也可以构建自己的扩展。有几个你可能想学习如何构建扩展的原因：


1. **想要添加一些功能：** 如果缺失你想要的功能，你可以创建一个扩展来添加它。
2. **为了乐趣和学习：** 扩展 API 允许你探索 VSCodium 是如何工作的，这是一件有趣的事情。
3. **为了提高您的技能：** 创建扩展可以提高你的编程技能。
4. **为了成名：** 创建一个对他人有用的扩展可以提高你的公众形象。


### 安装工具


在你开始之前，你必须已经安装了 [Node.js](https://nodejs.org/en/)、[npm](https://www.npmjs.com/) 和 VS Code 或 [VSCodium](https://vscodium.com/)。


要生成一个扩展，你还需要以下工具：[Yeoman](https://yeoman.io/)，是一个开源的客户端脚手架工具，可以帮助你搭建新项目；以及 [vscode-generator-code](https://github.com/Microsoft/vscode-generator-code)，是 VS Code 团队创建的 Yeoman 生成器。


### 构建一个扩展


在本教程中，你将构建一个扩展，它可以为应用程序初始化一个 Docker 镜像。


#### 生成一个扩展骨架


要在全局范围内安装并运行 Yeoman 生成器，请在命令提示符或终端中输入以下内容： 



```
npm install -g yo generator-code

```

导航到要生成扩展的文件夹，键入以下命令，然后按回车： 



```
yo code

```

根据提示，你必须回答一些关于你的扩展的问题：


* **你想创建什么类型的扩展？** 使用上下箭头选择其中一个选项。在本文中，我将只介绍第一个选项，`New Extension (TypeScript)`。
* **你的扩展名称是什么？** 输入你的扩展名称。我的叫 `initdockerapp`。（我相信你会有一个更好的名字。）
* **你的扩展的标识符是什么？** 请保持原样。
* **你的扩展的描述是什么？** 写一些关于你的扩展的内容（你可以现在填写或稍后编辑它）。
* **初始化 Git 仓库？** 这将初始化一个 Git 仓库，你可以稍后添加 `set-remote`。
* **使用哪个包管理器？** 你可以选择 `yarn` 或 `npm`；我使用 `npm`。


按回车键后，就会开始安装所需的依赖项。最后显示：



> 
> "Your extension **initdockerapp** has been created!"
> 
> 
> 


干的漂亮！


### 检查项目的结构


检查你生成的东西和项目结构。导航到新的文件夹，并在终端中键入 `cd initdockerapp`。


一旦你进入该目录，键入 `.code`。它将在你的编辑器中打开，看起来像这样。


![Project file structure in VSCodium](/data/attachment/album/202006/13/105508u16aztgy1pe4dy8t.png "Project file structure in VSCodium") 


（Hussain Ansari, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）


最需要注意的两个文件是 `src` 文件夹内的 `package.json` 和 `extension.ts`。


#### package.json


首先来看看 `package.json`，它应该是这样的： 



```
{
        "name": "initdockerapp",
        "displayName": "initdockerapp",
        "description": "",
        "version": "0.0.1",
        "engines": {
                "vscode": "^1.44.0"
        },
        "categories": [
                "Other"
        ],
        "activationEvents": [
                "onCommand:initdockerapp.initialize"
        ],
        "main": "./out/extension.js",
        "contributes": {
                "commands": [
                        {
                                "command": "initdockerapp.initialize",
                                "title": "Initialize A Docker Application"
                        }
                ]
        },
        "scripts": {
                "vscode:prepublish": "npm run compile",
                "compile": "tsc -p ./",
                "lint": "eslint src --ext ts",
                "watch": "tsc -watch -p ./",
                "pretest": "npm run compile && npm run lint",
                "test": "node ./out/test/runTest.js"
        },
        "devDependencies": {
                "@types/vscode": "^1.44.0",
                "@types/glob": "^7.1.1",
                "@types/mocha": "^7.0.2",
                "@types/node": "^13.11.0",
                "eslint": "^6.8.0",
                "@typescript-eslint/parser": "^2.26.0",
                "@typescript-eslint/eslint-plugin": "^2.26.0",
                "glob": "^7.1.6",
                "mocha": "^7.1.1",
                "typescript": "^3.8.3",
                "vscode-test": "^1.3.0"
        }
}
{
        "name": "initdockerapp",
        "displayName": "initdockerapp",
        "description": "",
        "version": "0.0.1",
        "engines": {
                "vscode": "^1.44.0"
        },
        "categories": [
                "Other"
        ],
        "activationEvents": [
                "onCommand:initdockerapp.initialize"
        ],
        "main": "./out/extension.js",
        "contributes": {
                "commands": [
                        {
                                "command": "initdockerapp.initialize",
                                "title": "Initialize A Docker Application"
                        }
                ]
        },
        "scripts": {
                "vscode:prepublish": "npm run compile",
                "compile": "tsc -p ./",
                "lint": "eslint src --ext ts",
                "watch": "tsc -watch -p ./",
                "pretest": "npm run compile && npm run lint",
                "test": "node ./out/test/runTest.js"
        },
        "devDependencies": {
                "@types/vscode": "^1.44.0",
                "@types/glob": "^7.1.1",
                "@types/mocha": "^7.0.2",
                "@types/node": "^13.11.0",
                "eslint": "^6.8.0",
                "@typescript-eslint/parser": "^2.26.0",
                "@typescript-eslint/eslint-plugin": "^2.26.0",
                "glob": "^7.1.6",
                "mocha": "^7.1.1",
                "typescript": "^3.8.3",
                "vscode-test": "^1.3.0"
        }
}

```

如果你是 Node.js 开发者，其中一些可能看起来很熟悉，因为 `name`、`description`、`version` 和 `scripts` 是 Node.js 项目的常见部分。


有几个部分是非常重要的：


* `engines`：说明该扩展将支持哪个版本的 VS Code / VSCodium。
* `categories`：设置扩展类型；你可以从 `Languages`、`Snippets`、`Linters`、`Themes`、`Debuggers`、`Formatters`、`Keymaps` 和 `Other`中选择。
* `contributes`：可用于与你的扩展一起运行的命令清单。
* `main`：扩展的入口点。
* `activationEvents`：指定激活事件发生的时间。具体来说，这决定了扩展何时会被加载到你的编辑器中。扩展是懒加载的，所以在激活事件触发之前，它们不会被激活。


#### src/extension.ts


接下来看看 `src/extension.ts`，它应该是这样的：



```
// The module 'vscode' contains the VSCodium extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from "vscode";
const fs = require("fs");
const path = require("path");

// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {

        // Use the console to output diagnostic information (console.log) and errors (console.error)
        // This line of code will only be executed once when your extension is activated
        console.log('Congratulations, your extension "initdockerapp" is now active!');
       
        // The command has been defined in the package.json file
        // Now provide the implementation of the command with registerCommand
        // The commandId parameter must match the command field in package.json
        let disposable = vscode.commands.registerCommand('initdockerapp.initialize', () => {
                // The code you place here will be executed every time your command is executed

                let fileContent =`
                FROM node:alpine
                WORKDIR /usr/src/app

                COPY package.json .
                RUN npm install
               
                COPY . .
               
                EXPOSE 3000
                CMD ["npm", "start"]
                `;
               
                fs.writeFile(path.join(vscode.workspace.rootPath, "Dockerfile"), fileContent, (err:any) => {
                        if (err) {
                                return vscode.window.showErrorMessage("Failed to initialize docker file!");
                        }
                        vscode.window.showInformationMessage("Dockerfile has been created!");
                });
        });

        context.subscriptions.push(disposable);
}

// this method is called when your extension is deactivated
export function deactivate() {}

```

这是为你的扩展写代码的地方。已经有一些自动生成的代码了，我再来分析一下。


注意，`vscode.command.registerCommand` 里面的 `initdockerapp.initialize` 和 `package.json` 里面的命令是一样的。它需要两个参数。


1. 要注册的命令名称
2. 执行命令的功能


另一个需要注意的函数是 `fs.writeFile`，这是你写在 `vscode.command.registerCommand` 函数里面的。这将在你的项目根目录下创建一个 Dockerfile，并在其中附加代码来创建一个 Docker 镜像。 


### 调试扩展


现在你已经写好了扩展，是时候调试它了。点击“Run”菜单，选择“Start Debugging”（或者直接按 `F5`）打开调试窗口。


在调试窗口里面点击“Add Folder”或“Clone Repository”按钮，打开该项目。


接下来，用 `Ctrl+Shift+P`（在 macOS 上，用 `Command` 键代替 `Ctrl`）打开命令面板，运行 `Initialize A Docker Application`。


* 第一次运行此命令时，自 VSCodium 启动后，激活函数尚未执行。因此，调用激活函数，并由激活 函数注册该命令。
* 如果命令已注册，那么它将被执行。


你会看到右下角有一条信息，上面写着：`Dockerfile has been created!`。这就创建了一个 Dockerfile，里面有一些预定义的代码，看起来是这样的： 


![Running the new extension command](/data/attachment/album/202006/13/105512l8sb7sjcnvmafni8.png "Running the new extension command")


（Hussain Ansari, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）


### 总结


有许多有用的 API 可以帮助你创建你想要构建的扩展。VS Code 扩展 API 还有许多其他强大的方法可以使用。


你可以在 VS Code 扩展 API 文档中了解更多关于 VS Code API 的信息。




---


via: <https://opensource.com/article/20/6/vs-code-extension>


作者：[Ashique Hussain Ansari](https://opensource.com/users/uidoyen) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
Visual Studio Code (VS Code) is a cross-platform code editor created by Microsoft for Linux, Windows, and macOS. Unfortunately, Microsoft's version of [VS Code](https://code.visualstudio.com/) is released under the [Microsoft Software License](https://code.visualstudio.com/license), which is not an open source license. However, the source code is open source, released under the MIT license, with releases distributed by the [VSCodium](https://vscodium.com/) project.

VSCodium, like VS Code, has support for extensions, embedded Git control, GitHub integration, syntax highlighting, debugging, intelligent code completion, snippets, and more. In other words, for most users there's no difference between using VS Code and VSCodium, and the latter is completely open source!

## What are VS Code extensions?

Extensions allow you to add capabilities to VS Code or VSCodium. You can install extensions in the GUI or from a terminal.

You can also build your own extensions. There are several reasons you might want to learn to build an extension:

**To add something:**If a feature you want is missing, you can create an extension to add it.**For fun and learning:**The extension API allows you to explore how VSCodium works, which is a fun thing to do.**To improve your skills:**Creating an extension enhances your programming skills.**For fame:**Creating an extension that is useful to others can increase your public profile.

## Install the tools


Before you begin, you must already have [Node.js](https://nodejs.org/en/), [npm](https://www.npmjs.com/), and VS Code or [VSCodium](https://vscodium.com/) installed.

To generate an extension, you will also need the following tools: [Yeoman](https://yeoman.io/), an open source client-side scaffolding tool that helps you kickstart new projects, and [vscode-generator-code](https://github.com/Microsoft/vscode-generator-code), a Yeoman generator build created by the VS Code team.

## Build an extension

In this tutorial, you will build an extension that initializes a Docker image for an application.

### Generate an extension skeleton

To install and run the Yeoman generator globally, enter the following in a command prompt or terminal:

`npm install -g yo generator-code`


Navigate to the folder where you want to generate the extension, type the following command, and hit **Enter**:

`yo code`


At the prompt, you must answer some questions about your extension:

**What type of extension do you want to create?**Choose one of the options by using the Up and Down arrows. In this article, I will explain only the first one,**New Extension (TypeScript)**.**What's the name of your extension?**Enter the name of your extension. Mine is called**initdockerapp**. (I am sure you will have a better name.)**What's the identifier of your extension?**Leave this as it is.**What's the description of your extension?**Write something about your extension (you can fill this in or edit it later, too).**Initialize a Git repository?**This initializes a Git repository, and you can add`set-remote`

later.**Which package manager to use?**You can choose yarn or npm; I will use npm.

Hit the **Enter** key, and it will start installing the required dependencies. And finally:

"Your extension

initdockerapphas been created!"

Excellent!

## Check the project's structure

Examine what you generated and the project structure. Navigate to the new folder and type `cd initdockerapp`

in your terminal.

Once you are in, type `.code`

. It will open in your editor and look something like this:

![Project file structure in VSCodium Project file structure in VSCodium](https://opensource.com/sites/default/files/uploads/vscode-tree.png)

(Hussain Ansari, CC BY-SA 4.0)

The two most important files to pay attention to are `package.json`

and `extension.ts`

inside the `src`

folder.

### package.json

First, look at `package.json`

, which should look something like this:

```
{
"name": "initdockerapp",
"displayName": "initdockerapp",
"description": "",
"version": "0.0.1",
"engines": {
"vscode": "^1.44.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:initdockerapp.initialize"
],
"main": "./out/extension.js",
"contributes": {
"commands": [
{
"command": "initdockerapp.initialize",
"title": "Initialize A Docker Application"
}
]
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"lint": "eslint src --ext ts",
"watch": "tsc -watch -p ./",
"pretest": "npm run compile && npm run lint",
"test": "node ./out/test/runTest.js"
},
"devDependencies": {
"@types/vscode": "^1.44.0",
"@types/glob": "^7.1.1",
"@types/mocha": "^7.0.2",
"@types/node": "^13.11.0",
"eslint": "^6.8.0",
"@typescript-eslint/parser": "^2.26.0",
"@typescript-eslint/eslint-plugin": "^2.26.0",
"glob": "^7.1.6",
"mocha": "^7.1.1",
"typescript": "^3.8.3",
"vscode-test": "^1.3.0"
}
}
{
"name": "initdockerapp",
"displayName": "initdockerapp",
"description": "",
"version": "0.0.1",
"engines": {
"vscode": "^1.44.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:initdockerapp.initialize"
],
"main": "./out/extension.js",
"contributes": {
"commands": [
{
"command": "initdockerapp.initialize",
"title": "Initialize A Docker Application"
}
]
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"lint": "eslint src --ext ts",
"watch": "tsc -watch -p ./",
"pretest": "npm run compile && npm run lint",
"test": "node ./out/test/runTest.js"
},
"devDependencies": {
"@types/vscode": "^1.44.0",
"@types/glob": "^7.1.1",
"@types/mocha": "^7.0.2",
"@types/node": "^13.11.0",
"eslint": "^6.8.0",
"@typescript-eslint/parser": "^2.26.0",
"@typescript-eslint/eslint-plugin": "^2.26.0",
"glob": "^7.1.6",
"mocha": "^7.1.1",
"typescript": "^3.8.3",
"vscode-test": "^1.3.0"
}
}
```


If you are a Node.js developer, some of this might look familiar since `name`

, `description`

, `version`

, and `scripts `

are common parts of a Node.js project.

There are a few sections that are very important.

`engines`

: States which version of VSCodium the extension will support`categories`

: Sets the extension type; you can choose from Languages, Snippets, Linters, Themes, Debuggers, Formatters, Keymaps, and Other`contributes`

: A list of commands that can be used to run with your extension`main`

: The entry point of your extension`activationEvents`

: Specifies when the activation event happens. Specifically, this dictates when the extension will be loaded into your editor. Extensions are lazy-loaded, so they aren't activated until an activation event occurs

### src/extension.ts

Next, look at `src/extension.ts`

, which should look something like this:

```
// The module 'vscode' contains the VSCodium extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from "vscode";
const fs = require("fs");
const path = require("path");
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
// Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
console.log('Congratulations, your extension "initdockerapp" is now active!');
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
let disposable = vscode.commands.registerCommand('initdockerapp.initialize', () => {
// The code you place here will be executed every time your command is executed
let fileContent =`
FROM node:alpine
WORKDIR /usr/src/app
COPY package.json .
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
`;
fs.writeFile(path.join(vscode.workspace.rootPath, "Dockerfile"), fileContent, (err:any) => {
if (err) {
return vscode.window.showErrorMessage("Failed to initialize docker file!");
}
vscode.window.showInformationMessage("Dockerfile has been created!");
});
});
context.subscriptions.push(disposable);
}
// this method is called when your extension is deactivated
export function deactivate() {}
```


This is where you write the code for your extension. There's already some auto-generated code, which I'll break down.

Notice that the name `initdockerapp.initialize`

inside `vscode.command.registerCommand`

is the same as the command in `package.json`

. It takes two parameters:

- The name of the command to register
- A function to execute a command

The other function to note is `fs.writeFile`

, which you wrote inside the `vscode.command.registerCommand`

function. This creates a dockerfile inside your project root, and appends the code to create a Docker image.

## Debug the extension

Now that you've written the extension, its time to debug it. Click the **Run** menu and select **Start Debugging** (or just press **F5**) to open a debugging window.

Open the project inside the debugging window by clicking on either the **Add Folder** or the **Clone Repository** button.

Next, open a command panel with **Ctrl+Shift+P** (on macOS, substitute the Command key for Ctrl) and run **Initialize A Docker Application**.

- The first time you run this command, the activate function has not been executed since VSCodium was launched. Therefore, activate is called, and the activate function registers the command.
- If the command has already been registered, then it executes.

You'll see a message in the lower-right corner that says: "Dockerfile has been created!" This created a Dockerfile with some pre-defined code that looks something like this:

![Running the new extension command Running the new extension command](https://opensource.com/sites/default/files/uploads/vscode-run-command.png)

(Hussain Ansari, CC BY-SA 4.0)

## Summary

There are many helpful APIs that will help you create the extensions you want to build. The VS Code extension API has many other powerful methods you can use.

You can learn more about VS Code APIs in the VS Code Extension API documentation.

## Comments are closed.