Visual Studio Code での Extension開発03(拡張機能)

# Visual Studio Code での Extension開発03(拡張機能)

<!-- @import "[TOC]" {cmd="toc" depthFrom=1 depthTo=6 orderedList=false} -->

<!-- code_chunk_output -->

* [Visual Studio Code での Extension開発03(拡張機能)](#visual-studio-code-での-extension開発03拡張機能)
	* [概要](#概要)
		* [前回までに作成したファイル](#前回までに作成したファイル)
	* [共通機能](#共通機能)
		* [共通機能の概説](#共通機能の概説)
		* [共通機能を詳しく](#共通機能を詳しく)
			* [1 Command](#1-command)
			* [2 Configuration](#2-configuration)
				* [Contribution Pointsについて](#contribution-pointsについて)
					* [1  commands | コマンドの登録とカテゴライズ](#1-commands-コマンドの登録とカテゴライズ)
					* [2  menus | メニューの設定](#2-menus-メニューの設定)
					* [3  keybindings | キーボードショートカットの設定](#3-keybindings-キーボードショートカットの設定)
			* [3 Keybinding](#3-keybinding)
			* [4 Context Menu](#4-context-menu)
			* [5 Data Storage](#5-data-storage)
			* [6 Display Notifications](#6-display-notifications)
			* [7 Quick Pick](#7-quick-pick)
			* [8 File Picker](#8-file-picker)

<!-- /code_chunk_output -->

## 概要
ここでは拡張機能について理解を深めたいと思います

公式ドキュメントと前回分は以下の通りです

- 公式ドキュメント  [あなたの最初の拡張 Visual Studioコード拡張API](https://code.visualstudio.com/api/get-started/your-first-extension)

- 前回分00: [Visual Studio Code での Extension 開発00(環境構築)](https://qiita.com/intertext543210/items/3a593f14c543ff4fed91)

- 前回分01: [Visual Studio Code での Extension開発01 (わたくしの最初の拡張)](https://qiita.com/intertext543210/items/75e8dedab69ae3b1cff7)

- 前回分02: [Visual Studio Code での Extension開発02(拡張の解剖学)](https://qiita.com/intertext543210/items/599b133ec925cc3c6195)

### 前回までに作成したファイル
<details><summary>extension.ts </summary><div>

```ts
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
    console.log('Congratulations, your extension "helloworld" is now active!');
  let disposable = vscode.commands.registerCommand('extension.helloWorld', () => {
    vscode.window.showWarningMessage("WarningMessag");
  });
  context.subscriptions.push(disposable);
}
export function deactivate() {}
```
</div></details>

<details><summary>package.json</summary><div>

```json
{
  "name": "helloworld",
  "displayName": "HelloWorld",
  "description": "LEAVE BLANK",
  "version": "0.0.1",
  "engines": {
    "vscode": "^1.33.0"
  },
  "categories": [
    "Other"
  ],
  "activationEvents": [
    "onCommand:extension.helloWorld"
  ],
  "main": "./out/extension.js",
  "contributes": {
    "commands": [
      {
        "command": "extension.helloWorld",
        "title": "myApp"
      }
    ]
  },
  "scripts": {
    "vscode:prepublish": "npm run compile",
    "compile": "tsc -p ./",
    "watch": "tsc -watch -p ./",
    "postinstall": "node ./node_modules/vscode/bin/install",
    "test": "npm run compile && node ./node_modules/vscode/bin/test"
  },
  "devDependencies": {
    "typescript": "^3.3.1",
    "vscode": "^1.1.28",
    "tslint": "^5.12.1",
    "@types/node": "^10.12.21",
    "@types/mocha": "^2.2.42"
  }
}
```
</div></details>



## 共通機能
>Common Capabilities are important building blocks for your extensions. Almost all extensions use some of these functionalities.
日本語google翻訳
共通機能はあなたの拡張のための重要な構成要素です
ほとんどすべての拡張機能はこれらの機能のいくつかを使用します

### 共通機能の概説

|no|機能|概要|
|---|---|---|
|1|Command| コマンドメニューを開いてコマンドを実行する<br>カスタムキーバインディングをコマンドにバインドする<br>右クリックしてコンテキストメニューのコマンドを呼び出す|
|2|Configuration|Contribution Pointを使用した拡張機能固有の設定|
|3|Keybinding|拡張機能のカスタムキーバインドの設定|
|4|Context Menu|右クリック時のコンテキストメニューの挙動を制御|
|5|Data Storage|データを保存|
|6|Display Notifications|通知の表示|
|7|Quick Pick|ユーザの入力補助|
|8|File Picker|ユーザのファイル選択補助|
|9|Output Channel|出力パネル|
|10|Progress API|進行状況の更新|

### 共通機能を詳しく

#### 1 Command
 コマンドは一意の識別子を持つ関数(コマンドハンドラとも呼ばれる)
コマンドの登録方法については以下の通りです

- `registerCommand` または `registerTextEditorCommand` 関数を使用して、コマンドハンドラをエディタに登録 
　(※メソッドについて➡　[vscode-api](https://code.visualstudio.com/api/references/vscode-api#commands.executeCommand))

- コマンド識別子を __package.json__ のcontributes.commands.__title__ に結びつける




#### 2 Configuration
設定項目 __Contribution Points__ を __package.json__ の`contributes`以下に設定します
>An extension can contribute extension-specific settings with the contributes.configuration
日本語google翻訳
エクステンションはcontrib.configurationでエクステンション特有の設定を提供することができます



##### Contribution Pointsについて
設定項目がたくさんあります
いまは以下の3つにとどめます

1. commands
1. menus
1. keybindings


###### 1  commands | コマンドの登録とカテゴライズ
設定箇所：`contributes.commands.category`
起動するタイトルとコマンドからなるエントリをコマンドパレットに設定できます
オプションで、コマンドタイトルの前に付けるカテゴリ文字列を定義し、グループ化もできます

|項目名|　|概要|
|---|---|---|
|contributes.commands.|command|コマンドの名前|
|^|title|コマンドパレットに表示させる名前|
|^|category|カテゴリ名|

✓helloworld\ __package.json__ のコマンドにカテゴリを追加してみます
`contributes.commands.category` に __"group1"__ を追加
⇩
実行結果
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347291/8cd398da-1086-021a-ae5c-75f7d5706a67.jpeg" width="200">
コマンドパレットに __group1:myApp__ と表示されるようになりました
(さらに`when節`によってコマンドパレットに表示されるタイミングも設定できるようです)



###### 2  menus | メニューの設定
設定箇所： `contributes.menus`
コマンドのメニュー項目をエディタまたはエクスプローラに設定できます

✓とりあえずサンプルをhelloworld\ __package.json__ 反映させてみます


```json
    "menus": {
        "editor/title": [{
            "when": "resourceLangId == markdown",
            "command": "markdown.showPreview",
            "alt": "markdown.showPreviewToSide",
            "group": "navigation"
        }]
    }
```
⇩
実行結果
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347291/c96268e8-f89f-c5de-86aa-4dd02f19646a.jpeg" width="30">
メニューバーにマークダウンのプレビューを開くアイコンが設定されました

✓ editor/ __title__ を editor/ __context__ に変更してみます
⇩
実行結果
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347291/7d3b581d-0fff-fd38-e292-d938cf301ecc.jpeg" width="300">
右クリック時のコンテキストメニューの中に項目が追加されました

✓extension.tsで作成した「helloWorld」をコンテキストメニューに加えてみます
commandを`extension.helloWorld`にします

```json
    "menus": {
      "editor/context": [{
          "command": "extension.helloWorld",
          "group": "navigation"
      }]
    }
```
⇩
実行結果
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347291/149eb570-5fd1-633a-9e25-20b6d7121105.jpeg" width="300">
右クリック時のコンテキストメニューの中に __myApp__ が追加されました


✓ __editor/context__ を __editor/title__ に変更してみます
⇩
実行結果
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347291/aeb961a7-1233-e75d-ab58-9c3f9f15537c.jpeg" width="200">
メニューバーに __myApp__ が追加されました

|項目名|　|概要|
|---|---|---|
|contributes.menus.|commandPalette|グローバルなコマンドパレットを設定対象にする|
|^|editor/context|エディタのコンテキストメニューを設定対象にする|
|^|editor/title|エディタのタイトルメニューバーを設定対象にする|
|contributes.menus.[設定対象].|when|条件節を設定する|
|^|command|コマンドを割り当てる __必須項目__ |
|^|group|メニュー項目のソートとグループ化を定義<br/>navigationグループは常にメニューの先頭に表示される|
※__when__ についてはまた別の機会で詳細の理解を深める必要がありそうです


###### 3  keybindings | キーボードショートカットの設定
設定箇所： `contributes.keybindings`

✓helloworld\ __package.json__ に以下を追記します

```json
    "keybindings": [{
        "command": "extension.helloWorld",
        "key": "ctrl+f1",
        "mac": "cmd+f1"
    }]
```
⇩
実行結果
`ctrl+f1`で`extension.helloWorld`が呼び出されました


#### 3 Keybinding
キーボードショートカットの競合に注意が必要
結構キーボードショートカットの割り当ては大変かもしれないです
さらに詳しく　[Visual Studioコードの主なバインディング](https://code.visualstudio.com/docs/getstarted/keybindings)

#### 4 Context Menu
上述しました

#### 5 Data Storage
割愛します


#### 6 Display Notifications
以下の通知表示があります

- window.showInformationMessage
- window.showWarningMessage
- window.showErrorMessage



#### 7 Quick Pick
ユーザの入力補助を実現します

- APIの解説 [vscode-api|QuickPick](https://code.visualstudio.com/api/references/vscode-api#QuickPick)
- [githubに用意されているサンプル](https://github.com/Microsoft/vscode-extension-samples/tree/master/quickinput-sample)

上記を参考にしながらサンプルを動かしたいと思います
githubからファイル群をダウンロード
ローカルで`quickinput-sample`フォルダを開き`F5`を押下したところ
以下のエラーが発生しました

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347291/36770575-fbc2-bf96-26c6-b8bda01a0bd2.jpeg" width="450">

`npm install`をコマンドラインで実行し動作するようになりました

コード内に記載されているキーワードと参考サイトを列挙します
※いったん保留

- __Promise__  
  - Qiita [Promiseについて0から勉強してみた](https://qiita.com/toshihirock/items/e49b66f8685a8510bd76)
  - MDM [Promise - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise)
- __async__
  - Qiita [async await の使い方](https://qiita.com/niusounds/items/37c1f9b021b62194e077)

- ExtensionContext
- subscriptions.push
- window.createQuickPick
- items
- onDidChangeSelection
- catch
- onDidHide
- dispose
- show


#### 8 File Picker
```showOpenDialog(options: OpenDialogOptions): Thenable<Uri[] | undefined>```
上記のメソッドでファイルオープンダイアログをユーザに表示することができます

#### 9 Output Channel
割愛します

#### 10 Progress API
`vscode.Progress`で進捗バーを表示できます

- APIの解説 [vscode-api|Progress](https://code.visualstudio.com/api/references/vscode-api#Progress)
- [githubに用意されているサンプル](https://github.com/Microsoft/vscode-extension-samples/tree/master/progress-sample)

進捗バーが表示されました
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347291/7e939474-8416-c12c-e2e2-ec4de6a60d18.jpeg" width="450">


## まとめ
`package.json`は設定
`extension.ts`はソース
ということが理解できました
そして`extension.ts`は`typeScript`,`javaScript`が土台にあって
`vscode-api`を絡めていくイメージが持てました
今更ですが、`typeScript`,`javaScript`の基礎がないと`extension.ts`が読めません
なので、少し迂回します
`typeScript`,`javaScript`の基礎学習に


## 参考
- 公式ドキュメント  [共通の機能| Visual Studioコード拡張API](https://code.visualstudio.com/api/extension-capabilities/common-capabilitiesn)

- quickinput [githubに用意されているサンプル](https://github.com/Microsoft/vscode-extension-samples/tree/master/quickinput-sample)
- Qiita [Promiseについて0から勉強してみた](https://qiita.com/toshihirock/items/e49b66f8685a8510bd76)
- MDM [Promise - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise)
- Qiita [async await の使い方](https://qiita.com/niusounds/items/37c1f9b021b62194e077)
- progress [githubに用意されているサンプル](https://github.com/Microsoft/vscode-extension-samples/tree/master/progress-sample)