VS 代码扩展:所有定义的任务都使用 vscode.CustomExecution return 最后定义任务的结果

VS Code Extension: All defined tasks using vscode.CustomExecution return result of last defined task

进入

我创建了一个简单的 VS 代码扩展,它定义了多个任务:

ExamplePseudoterminal1 Task 1, ExamplePseudoterminal1 Task 2, ExamplePseudoterminal1 Task 3
ExamplePseudoterminal2 Task 1, ExamplePseudoterminal2 Task 2, ExamplePseudoterminal2 Task 3

ExamplePseudoterminal1 Task <number> 任务接受一个参数 <number> 并在终端上打印出 <number>ExamplePseudoterminal2 Task <number> 任务接收参数 <number> 并向终端打印 2 *<number>


问题

当我运行一个任务(Terminal -> Run Task... -> "MyTask")时,上面列出的所有任务都显示出来了。 但是,every 其中一项任务的结果是最后添加的任务(即 ExamplePseudoterminal2 Task 3 -> 6).

我做错了什么?

我忘记了什么吗?


示例代码

>>> yo code

? What type of extension do you want to create? New Extension (TypeScript)
? What's the name of your extension? ExampleExt
? What's the identifier of your extension? exampleext
? What's the description of your extension? Example extension
? Initialize a git repository? No
? Bundle the source code with webpack? No
? Which package manager to use? npm

更改的文件:

src/extension.ts

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {

    console.log('Congratulations, your extension "exampleext" is now active!');

    const use_type: string = "MyTask"
    const myTask_TaskProvider: vscode.Disposable = vscode.tasks.registerTaskProvider(use_type, {
        provideTasks(token?: vscode.CancellationToken) {
            const output_taks: vscode.Task[] = [];

            const use_type: string = "MyTask"
            for (const entry of [1, 2, 3]){

                console.log(`Processing ${entry}`);

                const new_task_1: vscode.Task = new vscode.Task(
                    {type: use_type}, vscode.TaskScope.Workspace,
                    `ExamplePseudoterminal1 Task ${entry}`, use_type,
                    new vscode.CustomExecution(
                        async function(resolvedDefinition: vscode.TaskDefinition): Promise<vscode.Pseudoterminal> {
                            return new ExamplePseudoterminal1(entry);
                        }),
                    [""]
                );
                output_taks.push(new_task_1);

                const new_task_2: vscode.Task = new vscode.Task(
                    {type: use_type}, vscode.TaskScope.Workspace,
                    `ExamplePseudoterminal2 Task ${entry}`, use_type,
                    new vscode.CustomExecution(
                        async function(resolvedDefinition: vscode.TaskDefinition): Promise<vscode.Pseudoterminal> {
                            return new ExamplePseudoterminal2(entry);
                        }),
                    [""]
                );
                output_taks.push(new_task_2);

            }

            return output_taks;
        },
        resolveTask(task: vscode.Task, token?: vscode.CancellationToken) {
            return task;
        }
    });
    context.subscriptions.push(myTask_TaskProvider);
}

export function deactivate() {
}

class ExamplePseudoterminal1 implements vscode.Pseudoterminal {

    private readonly writeEmitter = new vscode.EventEmitter<string>();
    public onDidWrite: vscode.Event<string> = this.writeEmitter.event;

    private readonly closeEmitter = new vscode.EventEmitter<void>();
    public onDidClose?: vscode.Event<void> = this.closeEmitter.event;

    private value: number;

    public constructor(in_number: number) {
        this.value = in_number;
        console.log(`this.value: ${this.value}`);
    }

    public open(initialDimensions: vscode.TerminalDimensions | undefined) {
        console.log("open");

        this.writeEmitter.fire(`${this.value}`);

        this.closeEmitter.fire();
    }

    close(): void {
        console.log("close");
    }
}

class ExamplePseudoterminal2 implements vscode.Pseudoterminal {

    private readonly writeEmitter = new vscode.EventEmitter<string>();
    public onDidWrite: vscode.Event<string> = this.writeEmitter.event;

    private readonly closeEmitter = new vscode.EventEmitter<void>();
    public onDidClose?: vscode.Event<void> = this.closeEmitter.event;

    private value: number;

    public constructor(in_number: number) {
        this.value = in_number * 2;
        console.log(`this.value: ${this.value}`);
    }

    public open(initialDimensions: vscode.TerminalDimensions | undefined) {
        console.log("open");

        this.writeEmitter.fire(`${this.value}`);

        this.closeEmitter.fire();
    }

    close(): void {
        console.log("close");
    }
}

包-lock.json

{
  "name": "exampleext",
  "displayName": "ExampleExt",
  "description": "Example extension",
  "version": "0.0.1",
  "engines": {
    "vscode": "^1.46.0"
  },
  "categories": [
    "Other"
  ],
  "activationEvents": [
    "onCommand:workbench.action.tasks.runTask"
  ],
  "main": "./out/extension.js",
  "contributes": {
    "taskDefinitions": [
      {
        "type": "MyTask"
      }
    ]
  },
  "scripts": {
    "vscode:prepublish": "npm run compile",
    "compile": "tsc -p ./",
    "watch": "tsc -watch -p ./",
    "pretest": "npm run compile && npm run lint",
    "lint": "eslint src --ext ts",
    "test": "node ./out/test/runTest.js"
  },
  "devDependencies": {
    "@types/glob": "^7.1.3",
    "@types/mocha": "^8.0.4",
    "@types/node": "^12.11.7",
    "@types/vscode": "^1.46.0",
    "@typescript-eslint/eslint-plugin": "^4.14.1",
    "@typescript-eslint/parser": "^4.14.1",
    "eslint": "^7.19.0",
    "glob": "^7.1.6",
    "mocha": "^8.2.1",
    "typescript": "^4.1.3",
    "vscode-test": "^1.5.0"
  }
}

系统

基于 github: microsoft/vscode-extension-samples 示例的解决方案。 这使用了 vscode.TaskProvider 的更完整定义。重要的部分似乎是:interface CustomBuildTaskDefinition extends vscode.TaskDefinitionpackage.json 中的完整 taskDefinitions

src/extension.ts

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {

    console.log('Congratulations, your extension "exampleext" is now active!');

    const myTask_TaskProvider: vscode.Disposable = vscode.tasks.registerTaskProvider(
        CustomBuildTaskProvider.TaskType, new CustomBuildTaskProvider()
    );

    context.subscriptions.push(myTask_TaskProvider)
}

export function deactivate() {
}


interface CustomBuildTaskDefinition extends vscode.TaskDefinition {
    number: number;
}

export class CustomBuildTaskProvider implements vscode.TaskProvider {
    static TaskType = 'custombuildscript';
    private tasks: vscode.Task[] | undefined;

    constructor() { }

    public async provideTasks(): Promise<vscode.Task[]> {
        return this.getTasks();
    }

    public resolveTask(_task: vscode.Task): vscode.Task | undefined {
        const type: string = _task.definition.type;
        if (type === CustomBuildTaskProvider.TaskType) {
            const definition: CustomBuildTaskDefinition = <any>_task.definition;
            return this.getTask(definition);
        }
        return undefined;
    }

    private getTasks(): vscode.Task[] {
        if (this.tasks !== undefined) {
            return this.tasks;
        }

        const in_values: number[] = [1, 2, 3];

        this.tasks = [];
        in_values.forEach(value => {
            const active_def: CustomBuildTaskDefinition = {
                type: CustomBuildTaskProvider.TaskType,
                number: value
            }
            this.tasks!.push(this.getTask(active_def));
        });
        return this.tasks;
    }

    private getTask(definition: CustomBuildTaskDefinition): vscode.Task {

        return new vscode.Task(
            definition,
            vscode.TaskScope.Workspace,
            `TestTask ${definition.number}`,
            definition.type, new vscode.CustomExecution(
                async (): Promise<vscode.Pseudoterminal> => {
                    return new ExamplePseudoterminal1(definition.number);
                }
            ),
            [""]
        );
    }
}


class ExamplePseudoterminal1 implements vscode.Pseudoterminal {

    private readonly writeEmitter = new vscode.EventEmitter<string>();
    public onDidWrite: vscode.Event<string> = this.writeEmitter.event;

    private readonly closeEmitter = new vscode.EventEmitter<void>();
    public onDidClose?: vscode.Event<void> = this.closeEmitter.event;

    private value: number;

    public constructor(in_number: number) {
        this.value = in_number;
        console.log(`this.value: ${this.value}`);
    }

    public open(initialDimensions: vscode.TerminalDimensions | undefined) {
        console.log("open");

        this.writeEmitter.fire(`${this.value}`);

        this.closeEmitter.fire();
    }

    close(): void {
        console.log("close");
    }
}

包-lock.json

{
  "name": "exampleext",
  "displayName": "ExampleExt",
  "description": "Example extension",
  "version": "0.0.1",
  "engines": {
    "vscode": "^1.46.0"
  },
  "categories": [
    "Other"
  ],
  "activationEvents": [
    "onCommand:workbench.action.tasks.runTask"
  ],
  "main": "./out/extension.js",
  "contributes": {
    "taskDefinitions": [
      {
        "type": "MyTask",
        << -- Complete (and matching) definition ----------- >>
        "required": ["number"],
        "properties": {
                    "number": {
                        "type": "number",
                        "description": "Input number"
                    }
                }
      << --------------------------------------------------- >>
      }
    ]
  },
  "scripts": {
    "vscode:prepublish": "npm run compile",
    "compile": "tsc -p ./",
    "watch": "tsc -watch -p ./",
    "pretest": "npm run compile && npm run lint",
    "lint": "eslint src --ext ts",
    "test": "node ./out/test/runTest.js"
  },
  "devDependencies": {
    "@types/glob": "^7.1.3",
    "@types/mocha": "^8.0.4",
    "@types/node": "^12.11.7",
    "@types/vscode": "^1.46.0",
    "@typescript-eslint/eslint-plugin": "^4.14.1",
    "@typescript-eslint/parser": "^4.14.1",
    "eslint": "^7.19.0",
    "glob": "^7.1.6",
    "mocha": "^8.2.1",
    "typescript": "^4.1.3",
    "vscode-test": "^1.5.0"
  }
}