LoginSignup
14
14

More than 3 years have passed since last update.

[VSCode] Task作成の覚書

Last updated at Posted at 2020-08-11

Visual Studio Codeで外部プログラムを実行するためにExtensionでタスクが提供することができるようになっている。ただ、公式のサンプル(Task Providerのサンプル)は、タスク自体が高度過ぎてどこまでがタスクの本質か分かりにくく感じたので、実用的ではないが簡単なタスクの例で作り方をまとめる。

タスクとは

Visual Studio Codeで、ビルドやデバッグなど何かを実行することはタスクと呼ばれ、Run Task...から都度実行に必要なパラメータを設定して実行したり、Configure Taskで予め実行に必要なパラメータを設定したものを実行することができるようになっている。

プロジェクトだけで使用するタスクなら、「Custom Tasks」に載っている方法で以下のように定義できる。Configure TaskからCreate task.json from templateを選択し、タイプを選択するとtask.jsonが生成される。
image.png

task.json
{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "echo",
      "type": "shell",
      "command": "echo Hello"
    }
  ]
}

task.jsonで定義したタスクは、Run Task...で選択可能になる。
image.png

実行しようとすると、タスクの実行結果(メッセージなど)をどうするかという確認が表示される。(この辺は未調査)
image.png
実行するとechoの結果がコンソールに表示される。

Extensionでタスクを提供するには

Extensionでは、以下のようにしてタスクを提供する。ここで「タスク」とはVisual Studio Codeが実際に何かを実行するために使うvscode.Taskクラスのオブジェクトを指し、「タスク定義」は「タスク」を生成するための情報を指すものとする。タスク定義には、Visual Studio Codeがタスクを識別するためのtypeや、タスクが受け取るパラメータ(型や説明)が含まれる。

  1. package.jsoncontributesに「タスク定義」を登録する
  2. extension.tsなどで、TaskProviderを定義する。
    1. provideTasks: Run Task...で利用可能なタスクを取得するのに使われる。
    2. resolveTask: Configure Taskで設定済みの「タスク定義」から「タスク」を生成するのに使われる。
  3. activate時にTaskProvidrを登録する

Task Providerの定義

vscode.TaskProviderを継承したクラスを定義する。Visual Studio Codeがタスクを必要とするときにコールするメソッドprovideTasksresolveTaskを定義する。

extension.ts抜粋
import * as vscode from 'vscode';
const taskType = 'greeting';  // package.json の taskDefinitions で設定した type の値

// Discriminated Unions でミス防止(いるかどうか)
// https://basarat.gitbook.io/typescript/type-system/discriminated-unions
interface GreetingTaskDefinition extends vscode.TaskDefinition {
  type: typeof taskType;
  message: string;         // taskDefinitions の properties に対応するプロパティ
}

// Task Providerの定義
class GreetingTaskProvider implements vscode.TaskProvider {  
  provideTasks(): Thenable<vscode.Task[]> | undefined {
    // 利用可能なタスクを返す。
    // Run Task...で一覧表示する度にコールされる。
    // 毎回生成し直す必要が無ければ、一度作成したものを保持して、要求されたときに返しても良い。
    return generateTasks();
  }

  resolveTask( task: vscode.Task ): vscode.Task | undefined {
    // task.json で定義したタスク定義を受け取り、Visual Studio Codeが実行するタスクを作成する
    const definition: GreetingTaskDefinition = <any>task.definition;
    return createGreetingTask( definition );
  }
}

タスクの生成

provideTasksでもresolveTaskでも同じような要領でタスクを作成するので、例えば以下のように「タスク定義」から「タスク」を生成する関数として切り出しておくと良いと思う。また、resolveTaskではタスク名の表示はないようなので、nameを省略できるようにしても良いと思う。

extension.ts抜粋
function createGreetingTask( definition: GreetingTaskDefinition, name: string = '' ) {
  // Visual Studio Codeが実行するタスクの作成
  return new vscode.Task(
    definition,                       // 最低限タスクを識別するための type があれば良い
    vscode.TaskScope.Workspace,       // Global/Workspace...Globalは未対応の模様
    name,                             // name
    definition.type,                  // source
                                      // Run Taks...での表示を決める。表示は「source: name」となる。
    new vscode.ShellExecution( `echo ${definition.message} > greeting.txt` ) // 実行するコマンド
  );
}

provideTasksは利用可能なタスクを返すので、複数のタスクをまとめて生成する関数を作成しても良いと思う。
なお、ここではasyncである必要性はないものの、provideTasksは要求があった時にすぐタスクを作れないことを想定し、Promise<vscode.Task[]>が戻り値となっているため、それに合わせた戻り値にしている。

extension.ts抜粋
async function generateTasks(): Promise<vscode.Task[]> {
  const now = Date.now().toString();
  const task: vscode.Task[] = [
    createGreetingTask( { type: taskType, message: 'Good morning.' }, 'morning' ),
    createGreetingTask( { type: taskType, message: 'Good evening.' }, 'evening' ),
    createGreetingTask( { type: taskType, message: now }, 'now' )
  ];
  return task;
}

Task Providerの登録

これはお決まりのコード。

extension.ts抜粋
const disposables: vscode.Disposable[] = [];

export function activate(context: vscode.ExtensionContext) {
  // Task Providerの登録
  disposables.push( vscode.tasks.registerTaskProvider( taskType, new GreetingTaskProvider() ) );
}

export function deactivate() {
  disposables.forEach( disposable => disposable.dispose() );
}

Extensionのタスクの利用

Extensionが提供するタスクは、以下ようにして実行する。

  • Run Task...から選択する
  • Configure Taskで設定したものを実行する
  • Extensionから実行する

例えば、Configure Task以下のように設定すると、

task.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "greeting",
      "message": "Greeting from task.json",
      "label": "greeting: task.json"
    }
  ]
}

以下の一番下のように設定したタスクが表示される。実行すればGreeting from task.jsonと書かれたテキストファイルが生成される。
image.png

Extension内部から実行することもでき、例えば以下のようにすればcommandから実行することができる。

extension.ts抜粋
vscode.commands.registerCommand( 'execute-task', () => {
  vscode.tasks.executeTask( createGreetingTask( { type: taskType, message: 'Greeting from command.' } ) );
}

まとめ

Visual Studio Codeでは、外部のプログラムの実行をタスクとして提供できる。タスク(vscode.Task)はTaskProvideractivate時に登録することで、Configure Taskで設定したり、Run Task...で実行したりできるようになる。また、vscode.tasks.executeTaskにより、Extension内から直接実行することもできる。

このページでは扱っていないが、stderrに出力されるエラーを整形したい場合は、Defining a problem matcherに載っているようにProblem Matcherを作ると良いらしい。

14
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
14