VS Codeのワークスペース

## ワークスペースとは
ワークスペースは、複数ルートのフォルダーを同時に開く機能です。イメージとしては、Visual Studioのソリューション内で複数のプロジェクトを開けるのと同じです。アプリケーションを複数のルートフォルダーに分割していたり、テストを別ルートフォルダーに分けていたりした方には便利だと思います。もちろんルートフォルダーは、それぞれ異なるパスに配置してあっても問題ありません。

ワークスペースは、従来のバージョンからプレビュー機能として実装が進められていましたが、[VS Code 1.18](https://code.visualstudio.com/updates/v1_18#_support-for-multi-root-workspaces)から正式リリースされました。

## ワークスペースの使用方法
使い方は簡単で、[ファイル]-[ワークスペースにフォルダーを追加]を選択するだけです。もう少し直感的に追加したい方は、エクスプローラーにフォルダーをドラック＆ドロップしても追加できます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/67429/5d4618d8-5d05-056f-416c-0d3f2c33045d.png)

ワークスペースの設定を保存したいなら、[ファイル]-[名前を付けてワークスペースを保存]を選択します。**.code-workspace**の拡張子で設定を保存できます。保存後は、VS Codeの[ファイル]-[ワークスペースを開く]や**.code-workspace**ファイルをダブルクリックすれば再度ワークスペースを開けます。

## ワークスペースの設定
**.code-workspace**ファイルはJSON形式のファイルになっていて、エイリアスの設定などを追加できます。最初にファイルの記述例を示します。

```json:sample.code-workspace
{
	"folders": [
		{
			"name": "Product",
			"path": "app3"
		},
		{
            "name": "Test",
			"path": "app2"
		},
		{
			"path": "C:\\app3"
		}
	],
	"settings": {
		"window.zoomLevel": 2
	},
	"extensions": {
		"recommendations": [
			"yuichinukiyama.vscode-preview-server"
		]
	}
}
```

ワークスペースの保存を設定した直後は**path**の設定だけがされています。pathには**.code-workspace**ファイルからの相対パスか絶対パスでワークスペースのフォルダーが指定されています。つまり、**.code-workspace**ファイルのパスを保存後変更すると、pathを修正しないと読み込めなくなるので注意してください。

**name**を指定するとフォルダーにエイリアス（別名）を付けられます。また、**settings**を指定すれば、ワークスペース共通のVS Codeの設定ができます。設定できる項目はワークスペースを使っていないときと同じです。

**recommendations**は推奨の拡張機能です。ワークスペースを開いたタイミングで推奨機能のインストールを表示したり、拡張機能画面の推奨欄に拡張機能を表示したりできます。共同開発時に、共通で使ってほしい拡張機能がある場合などに便利です。**recommendations**の書き方は少々癖があって、**著者名.拡張機能名**です。拡張機能画の拡張機能名の横に出ているので、そちらで確認してください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/67429/0c99dab0-792e-1d63-4fab-a3c06d517991.png)


## 拡張機能への影響
今まで見てきたように、ワークスペースは複数のルートフォルダーを開いたり、VS Codeの設定ができるため、フォルダーにアクセスしたり、ローカルのVS Code設定にアクセスする拡張機能は影響を受けます。公式のwikiに影響を受けるケースが列挙されているので、抄訳すると以下のようになります。

- **workspace.rootPath**プロパティを使用している拡張機能
- グローバルではなくファイルレベルでコントリビューションのポイントを持っている拡張機能
- language Serverを含む拡張機能

私の作っている拡張機能も**workspace.rootPath**プロパティを使用しているので、影響を受ける対象でした。このプロパティは非推奨になったので、代替えのAPIが提供されています。

|  メソッド  |  説明  |
| ---- | ---- |
|  workspace.workspaceFolders  |  すべてのWorkspaceFolderにアクセスする（ワークスペースを開いていない場合はundefined）  |
|  workspace.onDidChangeWorkspaceFolders  |  WorkspaceFolderが追加されたり削除されたりした場合、イベントが実行される  |
|  workspace.getWorkspaceFolder(uri)  |  指定したWorkspaceFolderを取得する（ワークスペースを開いていない場合はundefined）  |

ワークスペースが入ることにより、VS Codeが開いているものが、ファイル/フォルダー/ワークスペースの3つに増えています。それぞれどれを開いているか確認するためには、workspaceFoldersをチェックします。

```ts
const folders = workspace.workspaceFolders;
if (folders === undefined) {
  // undefinedだった場合はファイルを開いている
} else if (folders.length === 1) {
  // workspaceFolders配列の要素数が1つだった場合はフォルダーを開いている
} else {
  // それ以外（workspaceFolders配列の要素数が2以上）だった場合はワークスペースを開いている。
}
```

また、ファイルの相対パスを取得している方は、**workspace.asRelativePath(pathOrUri: string | Uri, includeWorkspaceFolder?: boolean): string;**の動作が変更されていることに注意してください。includeWorkspaceFolderパラメーターを**true**に設定すると、取得する相対パス名がcode-workspaceファイルのnameプロパティで付けた名前になります。しかも、trueが既定値のため、パラメーターを渡していないと正確な相対パスではなく、ワークスペースのエイリアスが取得されています。従来どおりの相対パスを取得する場合はfalseを指定してください。

コントリビューションポイントや設定もグローバルとフォルダーレベルに加えて、ワークスペースで設定できるようになったため、拡張機能の設定をどこにするかを決められるようになりました。具体的には、**package.json**に**scope**プロパティが追加されています。**window**は既定値で、従来通り、グローバルの設定を使います。一方、**resource**はアクティブなリソースに依存して使われる設定が変わります。

```json:package.json
{
"keywords": ["multi-root ready"],
"contributes": {
  "configuration": [
    {
      "title": "Configuration Samples",
      "properties": {
        "conf.view": {
          "type": "string",
          "description": "window scope",
          "scope": "window"
        },
        "conf.resource": {
          "type": "object",
          "default": {},
          "description": "resource scope",
          "scope": "resource"
        }
      }
    }
  ]
}
```

なお、ワークスペースに対応した拡張機能には、**"keywords": ["multi-root ready"]**を付けることが推奨されています。急ぎで対応したため、コードが汚いですが、私の拡張機能に加えた[コミット](https://github.com/YuichiNukiyama/vscode-preview-server/commit/c4f989b8cc2cd35821dcc2edf3d0a119c9da59a9)が参考になるかもしれないので、リンクを張っておきます。

## 参考
- [Extension Authoring: Adopting Multi Root Workspace APIs](https://github.com/Microsoft/vscode/wiki/Extension-Authoring:-Adopting-Multi-Root-Workspace-APIs)
- [Multi-root Workspaces](https://code.visualstudio.com/docs/editor/multi-root-workspaces)