チュートリアルを行う

https://code.visualstudio.com/api/extension-guides/tree-view

チュートリアルではサイドバーにnode dependenciesを表示し、各packageのpackage.jsonを表示するサンプルを作っている。 しかしチュートリアルをそのまま試してもEditorにpackage.jsonの内容が表示されなかった。

その理由が知りたくて色々と調査した

結果として、githubのサンプルを実行するとわかるが、クリック時に発火するコマンドを指定しないと行けなかった

コマンド発火のコードリーディング

TreeViewをみると、チュートリアルに加えてvscode.Commandを付与している


return new Dependency(moduleName, version, vscode.TreeItemCollapsibleState.None, {
	command: 'extension.openPackageOnNpm',
	title: '',
	arguments: [moduleName]
});

併せてopenPackageOnNpmの登録もチュートリアルから追加されている

vscode.commands.registerCommand('extension.openPackageOnNpm', moduleName => vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(`https://www.npmjs.com/package/${moduleName}`)));

実際、これらを実装するとクリックしたらNPMのwebpageに飛ぶ挙動が確認できた

TreeItemオブジェクトはcommandをフィールドに保存しているが、自クラスでフィールドを操作している形跡はない つまり、vscode本体でTreeItem.commandを呼び出していると考えられる

vscode本体をコードリーディング

TreeItemの定義はこちら command自体は存在している よって、vscode本体でTreeItem.commandを呼び出す仮説は正しそう

https://github.com/microsoft/vscode/blob/main/src/vs/vscode.d.ts#L9136

この説明を見るに、clickをフックしてcommandを呼んでいる模様。

	async resolveTreeItem(treeItemHandle: string, token: vscode.CancellationToken): Promise<ITreeItem | undefined> {
		if (!this.dataProvider.resolveTreeItem) {
			return;
		}
		const element = this.elements.get(treeItemHandle);
		if (element) {
			const node = this.nodes.get(element);
			if (node) {
				const resolve = await this.dataProvider.resolveTreeItem(node.extensionItem, element, token) ?? node.extensionItem;
				// Resolvable elements. Currently only tooltip and command.
				node.item.tooltip = this.getTooltip(resolve.tooltip);
				node.item.command = this.getCommand(node.disposableStore, resolve.command);
				return node.item;
			}
		}
		return;
	}

https://github.com/microsoft/vscode/blob/8aff878db2542eea2dfb571c8bb485118bbb3113/src/vs/workbench/api/common/extHostTreeViews.ts#L376-L392

TreeItemを取得するときにクリックハンドラをgetCommandで取得していた