2.4 Task插件
Task是一个可以用于定制处理流程的特性,特别是可以在不用写代码就能完成定制,可以完成类似Makefile的功能。本节我们将尝试如果通过插件编程来扩展Task的功能。
2.4.1 MnBook插件定制
VS Code针对常用的Go、Node.js、Ruby、TypeScript等语言都定制了配套的Task。特别是工作区对应某种类型的语言时,内置的插件系统会自动注册相应的Task。我们也可以通过Task插件给MnBook也实现类似的功能。
最终效果是对应一组MnBook的Task,如图所示:
点击后可以看到mnbook类型的Task下有build、preview和clean三个功能:
因为是新的类型,也可以在.vscode/tasks.json
配置:
{
"version": "2.0.0",
"tasks": [
{
"label": "mnbook: build",
"type": "mnbook",
"task": "build"
}
]
}
这是用户视角的MnBook插件的效果。
2.4.2 package.json
增加Task规范
要定义新的mnbook插件类型需要下定义其规范,对应的task有哪些功能和属性等。contributes
部分如下:
{
// 基础配置和其他插件类似
"contributes": {
"taskDefinitions": [
{
"type": "mnbook",
"required": [ "task" ],
"properties": {
"task": {
"type": "string",
"description": "The mnbook task",
"examples": ["build", "preview", "clean"]
}
}
}
]
}
}
在贡献点的taskDefinitions
属性增加了mnbook
新类型(依赖基础的task
):其中有一个task
属性,有build、preview和clean三个功能。
另外在activationEvents
配置插件激活的事件:
{
"activationEvents": [
"onCommand:workbench.action.tasks.runTask"
]
}
当运行Task命令时插件被激活。
2.4.3 插件注册和销毁代码
插件的入口和销毁函数实现如下:
const vscode = require('vscode');
const pkg = require("./mnbookTaskProvider");
function activate(context /** @param {vscode.ExtensionContext} */) {
const workspaceRoot = vscode.workspace.workspaceFolders[0].uri.fsPath;
mnbookTaskProvider = vscode.tasks.registerTaskProvider(
pkg.MnbookTaskProvider.MnbookType,
new pkg.MnbookTaskProvider(workspaceRoot)
);
}
function deactivate() {
if (mnbookTaskProvider) {
mnbookTaskProvider.dispose();
}
}
在activate
函数先获取工作区路径,然后通过vscode.tasks.registerTaskProvider
注册新的插件类型。新的插件动力由MnbookTaskProvider
类实现,在mnbookTaskProvider.js
文件定义:
class MnbookTaskProvider {
static MnbookType = 'mnbook';
/** @type {string} */
workspaceRoot = undefined;
/** @type {Thenable<vscode.Task[]> | undefined} */
mnbookPromise = undefined;
constructor(workspaceRoot /** @param {string} */) {
this.workspaceRoot = workspaceRoot;
}
provideTasks() {
if(!this.mnbookPromise) {
this.mnbookPromise = this.getTasks();
}
return this.mnbookPromise;
}
resolveTask(_task) {
return undefined;
}
}
Task的Provider实现必须提供provideTasks
和resolveTask
两个方法,分别用于构造和修复用户要执行的Task。查看provideTasks
实现可以看到this.mnbookPromise
记录全部的task对象,由this.getTasks()
方法初始化。
getTasks
方法实现如下:
getTasks() {
const buildTask = new vscode.Task(
{type: 'mnbook', task: 'build'}, // kind
vscode.TaskScope.Workspace, // scope
'build', // name
'mnbook', // source
new vscode.ShellExecution(`mnbook build`), // execution
`mnbook_build`
);
const previewTask = new vscode.Task(...);
const cleanTask= new vscode.Task(...);
return [buildTask, previewTask, cleanTask];
}
定义好每个task,然后作为列表返回。每个task可以绑定执行的命令,比如vscode.ShellExecution("mnbook build")
等价于执行一个mnbook build
命令(也可以自定义扩展命令)。
2.4.4 插件输出信息
如果在使用Task的过程中输出一些信息,可以通过vscode.OutputChannel
功能实现。比如:
/**@type {vscode.OutputChannel} */
let _channel = null;
/** @return {vscode.OutputChannel} */
function getOutputChannel() {
if (!_channel) {
_channel = vscode.window.createOutputChannel('Mnbook Task Provider');
}
return _channel;
}
function activate(context /** @param {vscode.ExtensionContext} */) {
const workspaceRoot =
vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0
? vscode.workspace.workspaceFolders[0].uri.fsPath
: undefined;
if (!workspaceRoot) {
getOutputChannel().appendLine('Mnbook task provider requires a workspace root.');
getOutputChannel().show(true);
return;
}
...
}
如果缺少工作区就不注册Task类型,并输出提示信息。
2.4.5 插件感知
最好的插件是不用的时候感觉不到它的存在,在需要的时候自然就出现了。可以在插件代码中识别工作区的某些特征,然后针对性提供功能。另外在不同的操作系统环境,也可以提供更本地化的功能。