特集
» 2016年06月03日 05時00分 公開

特集:Visual Studio Code早分かりガイド:Visual Studio Codeの拡張機能を作成する (2/3)

[かわさきしんじ,Insider.NET編集部]

プロジェクトの構成

 VS Codeの[エクスプローラー]サイドバーを表示すると、このプロジェクトのディレクトリ/ファイル構造が表示される。

拡張機能のひな型のディレクトリ/ファイル構造 拡張機能のひな型のディレクトリ/ファイル構造

 主なディレクトリ/ファイルについて簡単にまとめる。

  • .vscodeディレクトリ: プロジェクトに固有の各種の設定ファイルを格納する
  • node_modulesディレクトリ: 拡張機能で必要になるモジュールを含む
  • outディレクトリ: コンパイル結果を格納する(TypeScriptのみ)
  • srcディレクトリ: 拡張機能本体のコードを格納する。デフォルトではextension.tsファイルのみ。JavaScriptで拡張機能を作成する場合にはsrcディレクトリはなくプロジェクトのルートにextension.jsファイルが置かれる
  • testディレクトリ: テストコードが含まれる
  • typingsディレクトリ: 型定義ファイルが格納される
  • package.jsonファイル: この拡張機能のマニフェストを記述する
  • tsconfig.jsonファイル: TypeScriptのコンパイル設定などを指定する

 これらのうち、特に重要になるのがpackage.jsonファイルと、もちろん拡張機能自体のコードを記述するsrc/extension.tsファイルの2つだ。

package.jsonファイル:拡張機能のマニフェスト

 package.jsonファイルでは、拡張機能に関する各種の設定を記述していく。generator-codeがデフォルトで出力するpackage.jsonファイルの内容を以下に示す。

{
  "name": "hellovscext",
  "displayName": "HelloVSCExt",
  "description": "sample",
  "version": "0.0.1",
  "publisher": "insidernet",
  "engines": {
    "vscode": "^1.0.0"
  },
  "categories": [
    "Other"
  ],
  "activationEvents": [
    "onCommand:extension.sayHello"
  ],
  "main": "./out/src/extension",
  "contributes": {
    "commands": [{
      "command": "extension.sayHello",
      "title": "Hello World"
    }]
  },
  "scripts": {
    "vscode:prepublish": "node ./node_modules/vscode/bin/compile",
    "compile": "node ./node_modules/vscode/bin/compile -watch -p ./",
    "postinstall": "node ./node_modules/vscode/bin/install"
  },
  "devDependencies": {
    "typescript": "^1.8.5",
    "vscode": "^0.11.0"
  }
}


package.jsonファイル(JSON)

 先頭にあるのは、「yo code」コマンド実行時に入力した各種事項(とバージョン番号)である。engines属性はこの拡張機能と互換性のあるVS Codeの最低バージョンを示す。categories属性はこの拡張機能の分類を示すもので、"Languages"、"Snippets"、"Linters"、"Themes"、"Debuggers"、"Other"を指定可能だ。name属性、version属性、publisher属性、engines属性は必須の属性となっている。

activationEvents属性

 activationEvents属性は、この拡張機能がアクティベートされるタイミングを示す。VS Codeの拡張機能は、それが必要になるまで読み込まれないようになっている。上の例では「"onCommand:extension.sayHello"」コマンドが実行されるまでは、拡張機能はロードされない。

"activationEvents": [
  "onCommand:extension.sayHello"
],


activationEvents属性(JSON)

 コマンドパレット(あるいはキーボードショートカット)で「extension.sayHello」コマンドが実行されると、拡張機能がアクティベートされる。この他にも特定の言語のファイルがオープンされた場合(例:"onLanguage:python")などに、拡張機能をアクティベートできるようになっている。特定のファイルの種類が開かれた場合に拡張機能をアクティベートする方法については拡張機能のサンプル「Word Count」を参考にしてほしい。

main属性

 main属性は、この拡張機能のエントリポイントを示す。上の構成では「"./out/src/extension"」となっているが、これはTypeScriptコードが最終的にJavaScriptコードにコンパイルされ、out/src/extension.jsファイルとなるからだ。

contributes属性

 次のcontributes属性も重要だ。これは拡張機能の「コントリビューションポイント」を示す(ここでは「contribute」は「貢献」というよりは「提供」といった意味合いに解釈すると分かりやすいかもしれない)。ここでは以下のようにコマンド(commands属性)を記述している。

"contributes": {
  "commands": [{
    "command": "extension.sayHello",
    "title": "Hello World"
  }]
},


コントリビューションポイントの指定(JSON)

 activationEvents属性の値にも含まれていた「extension.sayHello」コマンドが記述されている。コマンドパレット(あるいはキーボードショートカット)でこのコマンドが呼び出されると、onCommand:extension.sayHelloイベントが発行される。そして、このコマンドが(VS Codeのそのセッションで)初めて実行されたタイミングで、拡張機能がアクティベートされ、VS Codeにロードされる。

 キーボードショートカットを割り当てるには次のようにcontributes属性に記述を追加する。試したところではユーザーのキーボードショートカット設定(keybindings.jsonファイル)でもショートカットを割り当てることは可能だ。見ての通りなので説明は不要だろう。

"contributes": {
  "commands": [{
    "command": "extension.sayHello",
    "title": "Hello World"
  }],
  "keybindings": [{
    "command": "extension.sayHello",
    "key": "ctrl+shift+h",
    "mac": "cmd+shift+h"
  }]
},


キーボードショートカットの設定(JSON)

 これ以外にも、拡張機能のユーザーに拡張機能設定を公開するconfiguration属性なども記述可能だ。詳細については「Contribution Points - package.json」ページを参照してほしい。

 最後の2つの属性についても簡単にまとめておこう。

 scripts属性は拡張機能を使用したり、公開したりする前に必要となる処理を記述する。devDependencies属性は、拡張機能で必要となるNode.jsパッケージを示す。

 以上で、package.jsonファイルの説明は終わりだ。次に拡張機能本体のコードを見てみよう。

extension.tsファイル:拡張機能本体

 拡張機能本体のコードを以下に示す(コメントを削除したもの)。とてもシンプルだ。

'use strict';
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
  console.log('Congratulations, your extension "hellovscext" is now active!');

  let disposable = vscode.commands.registerCommand('extension.sayHello', () => {
    vscode.window.showInformationMessage('Hello World!');
  });

  context.subscriptions.push(disposable);
}

export function deactivate() {
}

extension.tsファイル(TypeScript)

 VS Codeの拡張機能は、「activate」関数をエクスポートする必要がある。このコードはTypeScriptで書かれているので、これを行うには「export function activate(…) { … }」のように書けばよい。拡張機能が終了されるタイミングで何らかの処理を行う必要があれば、同じくエクスポートしているdeactivate関数を利用する。

 上で見たように、package.jsonファイルのactivationEvents属性で指定したイベントが発生すると、この拡張機能のactivate関数が最初の一度だけ呼び出される。

 この拡張機能の場合は、コマンドパレットやキーボードを通じてextension.sayHelloコマンドが呼び出されると、onCommand:extension.sayHelloイベントが発行されるのであった。そして、このイベントが発行されると、このextension.tsファイル(をJavaScriptにコンパイルした結果であるextension.jsファイル)のactivate関数が呼び出されるという次第だ。

 activate関数では、コンソールにログを表示すると共に、コマンドハンドラーとなる関数をregisterCommand関数で登録している。ここではregisterCommand関数に引数と渡しているアロー関数がそうだ。そして、このアロー関数ではvscode.window.showInformationMessageメソッドを呼び出して、VS Codeにメッセージを表示している。

 このメソッドでは、最後に以下のコードを実行している。これはこの拡張機能の登録解除時にVS Codeから取得したリソースを解放するための処理だ。

context.subscriptions.push(disposable);

リソースを解放するための前準備(TypeScript)

 コマンドやイベントハンドラー、UI操作を伴う処理などは、VS Codeから何らかのリソースを取得する。そのため、最終的には取得したリソースを解放する必要がある。上で見たregisterCommand関数の戻り値はDisposable型のオブジェクトとなっており、リソースの解放時にはこれを利用できる。

 activateメソッドの引数context(vscode.ExtensionContext型)にはsubscriptionプロパティがある。これはdisposeメソッドをメンバに持つオブジェクトを要素とする配列だ。そして、Disposable型のオブジェクトはまさにdisposeメソッドをメンバに持つため、これを配列にプッシュしている。拡張機能の登録解除時にはこの配列に含まれる要素が自動的に解放される(disposeメソッドが呼び出される)ようになっている。

 最後にコマンドパレットで四則演算を行う簡易計算機を拡張機能として作成してみよう。

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。