Visual Studio Codeの拡張機能を一通り触って自分用に公開するまで


## なに？

ちょっと思うところがあってVisual Studio Codeの拡張機能が作りたくなったのでやってみた。
（同じような投稿はいくらでもあったのですがわたしの勉強もかねて車輪の再発名）

一通り拡張機能をさわって実際に自分のVisual Studio Codeにインストールするまで出来るようになります。

## 前提

node.js がインストールされていること。

## 最初の一歩


`yo`とVisual Studio Codeのひな形生成用の`generator-code`をインストールします。

```
npm install -g yo generator-code
```

```
yo code
```

ちょっと時間かかるかもしれないですがこんな感じで yo おじさんが出てきて質問してくれます。
今回は `TypeScript` で `praise` という名前のプロジェクトを作ります。

```
$ yo code

     _-----_     ╭──────────────────────────╮
    |       |    │   Welcome to the Visual  │
    |--(o)--|    │   Studio Code Extension  │
   `---------´   │        generator!        │
    ( _´U`_ )    ╰──────────────────────────╯
    /___A___\   /
     |  ~  |
   __'.___.'__
 ´   `  |° ´ Y `
```

作成されたら試しに動かします。

```
cd praise
code .
```

Visual Studio Codeが普通に立ち上がるので、そこから今回の作成途中の拡張機能が組み込まれたデバッグ用Visual Studio Codeを立ち上げます。

- メニューの[デバッグ]→「デバッグの開始」をクリック（ショートカットはF5です）
- 新しく出てきたVisual Sutdio Codeウィンドウで「Ctrl + Shift + p」をおして「> Hello World」でEnter
- 右下に Hello World! って出てきたら成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33095/6110bf28-789d-7fe3-e0fa-39bf0921d4f8.png)

## 少しずつ変えていきます

メッセージを変えてみましょう。

```typescript:src/extension.ts
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';

// 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 "praise" 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('extension.helloWorld', () => {
		// The code you place here will be executed every time your command is executed

		// Display a message box to the user
		vscode.window.showInformationMessage('Hello World!');
	});

	context.subscriptions.push(disposable);
}

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

のコードの `Hello World!` を好きなメッセージに変えてみます。

```typescript
		// Display a message box to the user
		vscode.window.showInformationMessage('Hello World!');
```

例えば `Goog morning!` とかにしてみます。

```typescript
		// Display a message box to the user
		vscode.window.showInformationMessage('Good morning!');
```

デバッグ中であれば画面上部にこんなコントロールがでていると思うので「再起動」させると更新が反映されます。
出てなかったら再度F5なりおしてデバッグ用のVisual Studio Codeを立ち上げてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33095/38c1e294-d62a-c8a9-7e76-c3baadb5ae67.png)

そして再度「Ctrl + Shift + p」→「> Hello World」で今後は画面右下に「Good morning!」と出ることが確認できたと思います。

「> Hello World」で「Good morning!」と出るのも気持ち悪いので呼び出しコマンドも変えてみます。
`package.json` の `title ` を書き換えます。

```json:./package.json
            :
	"contributes": {
		"commands": [
			{
				"command": "extension.helloWorld",
				"title": "Good Morning"
			}
		]
	},
            :
```

また再起動して今度は「Ctrl + Shift + p」→「> Good Morning」でEnterします。
ちゃんと「Good morning!」が出たと思います。

ここまでで何となく慣れたと思うので次のステップへ。

## 選択した文字数をカウントする

選択した文字列を取得してそのlengthを表示してみます。

```typescript:src/extension.ts
            :
	let disposable = vscode.commands.registerCommand('extension.helloWorld', () => {
		let editor = vscode.window.activeTextEditor;
		if (!editor) {
			vscode.window.showWarningMessage('No active text editor found!');
			return;
		}

		let text = editor.document.getText(editor.selection);
		vscode.window.showInformationMessage("length:"+text.length);
	});
            :
```

まず `activeTextEditor` でエディタのオブジェクトを取得します。Visual Studio Code上で何かしらのファイルが開いていれば取得できるし開いてなければエラーのメッセージを出して終了します。

次に `editor.document.getText(editor.selection)` で選択済みのテキストを取得。
`vscode.window.showInformationMessage("length:"+text.length)` で文字長を表示。

ここまでくるとVisual Studio Codeの拡張機能のTipsというよりも単にTypeScript(JavaScript)の話になってきます。
ここで取得した文字列を加工してみてもいいですし、自然言語処理をしてもいいですし、よきにはからってください！

## テキストが変更したらイベントを起こす

次はトリガーを変えてみます。

色々書き換えたので全文のせておきます。コメントも消してさっぱりしました。

```typescript:src/extension.ts
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {

	let activeEditor = vscode.window.activeTextEditor;
	vscode.workspace.onDidChangeTextDocument(event => {
		if (activeEditor && event.document === activeEditor.document) {
			for (const change of event.contentChanges) {
				console.log(change.text);
			}
		}
	}, null, context.subscriptions);

}

export function deactivate() {}
```

`onDidChangeTextDocument` でテキスト変更時のイベントがひろえるので変更点（配列ではいっている）のテキストをログで出力してみます。

あと起動方法を変えたので設定ファイルもいじっておきます。
`activationEvents` が `*` ワイルドカード指定になっています。
不要になった `contributes` の中身も消しておきます。
ついでに後々パッケージ化するときに必要になってくる `publisher` も追加しておきます。名前は自分の名前でもいれてください。
こちらも全文掲載。

```json:package.json
{
	"name": "praise",
	"publisher": "me",
	"displayName": "praise",
	"description": "",
	"version": "0.0.1",
	"engines": {
		"vscode": "^1.29.0"
	},
	"categories": [
		"Other"
	],
	"activationEvents": [
		"*"
	],
	"main": "./out/extension.js",
	"contributes": {
	},
	"scripts": {
		"vscode:prepublish": "npm run compile",
		"compile": "tsc -p ./",
		"watch": "tsc -watch -p ./",
		"pretest": "npm run compile",
		"test": "node ./out/test/runTest.js"
	},
	"devDependencies": {
		"@types/glob": "^7.1.1",
		"@types/mocha": "^5.2.6",
		"@types/node": "^10.12.21",
		"@types/vscode": "^1.29.0",
		"glob": "^7.1.4",
		"mocha": "^6.1.4",
		"typescript": "^3.3.1",
		"tslint": "^5.12.1",
		"vscode-test": "^1.0.0-next.0"
	}
}
```

ついにで `README.md` も何かしら書き換えておきます。
これも次のステップでパッケージングする時に必要となる手順です。
> 公開する前にREADMEをちゃんと書いておく必要があるので何かしら初期状態から書き換えておかないとパッケージングできないようです

```README.md
「後で書く」とか適当に書いておく
```


これでエディタでテキストを変更するとうるさいくらいにログが出るようになったと思います。

## 公開する

公開すると言っても単なるサンプルなので別に世の中に公開するようなものでもないので……ローカルで使えるようにだけしておきます。 本当はどんなささいなもので公開してフィードバックを受けるべきだとは思いますけど……あくまで今回はサンプルなので！

まずパッケージを作るためのコマンドをインストールします。

```
npm install -g vsce
```

拡張機能を開発していたフォルダで以下のコマンドを実行します。

```
vsce package
```

すると `praise-0.0.1.vsix` というファイルができたと思います。
ファイルが確認できたら次は普段つかっている Visual Studio Code の拡張機能から「VSIXからインストール」というのでできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33095/6e861067-8455-bf85-6b33-3cea575a828d.png)

ちなみいまの段階のコードのVSIXをインストールしても何もおきないので手順だけ覚えてください。

## さいごに

あとはやりたいことを決めたらVS Code Extension APIや各種サンプルを参考にしながらどんどん作ってみてください。
自作の拡張機能でぜひ素敵なVisual Studio Codeライフを!!