Reputation: 1979
I want to create a tree in VS code, but my problem is how to manually add a node to my tree. I am not sure from where to start. I tried to review all the projects that created a tree for VScode as an extension.
My problem is that I am not an expert in Typescript and the examples are not so clear or I am not sure how it is working.
Would you mind helping me to understand how to create the tree in VS code? My problem is with creating a node and then adding the node to tree.
I reviewed these projects:
vscode-code-outline
vscode-extension-samples
vscode-git-tree-compare
vscode-html-languageserver-bin
vscode-mock-debug
Update1: I managed to use "vscode-extension-samples" and generate the below code examples; now I don't know what I should do, or in other words, how to fill the tree. I tried to use mytree class to fill the data but it didn't work. Would you mind advising me what is next?
extension.ts
'use strict';
import * as vscode from 'vscode';
import { DepNodeProvider } from './nodeDependencies'
import { JsonOutlineProvider } from './jsonOutline'
import { FtpExplorer } from './ftpExplorer.textDocumentContentProvider'
import { FileExplorer } from './fileExplorer';
//mycode
import { SCCExplorer } from './sccExplorer';
export function activate(context: vscode.ExtensionContext) {
// Complete Tree View Sample
new FtpExplorer(context);
new FileExplorer(context);
//mycode
new SCCExplorer(context);
// Following are just data provider samples
const rootPath = vscode.workspace.rootPath;
const nodeDependenciesProvider = new DepNodeProvider(rootPath);
const jsonOutlineProvider = new JsonOutlineProvider(context);
vscode.window.registerTreeDataProvider('nodeDependencies', nodeDependenciesProvider);
vscode.commands.registerCommand('nodeDependencies.refreshEntry', () => nodeDependenciesProvider.refresh());
vscode.commands.registerCommand('nodeDependencies.addEntry', node => vscode.window.showInformationMessage('Successfully called add entry'));
vscode.commands.registerCommand('nodeDependencies.deleteEntry', node => vscode.window.showInformationMessage('Successfully called delete entry'));
vscode.commands.registerCommand('extension.openPackageOnNpm', moduleName => vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(`https://www.npmjs.com/package/${moduleName}`)));
vscode.window.registerTreeDataProvider('jsonOutline', jsonOutlineProvider);
vscode.commands.registerCommand('jsonOutline.refresh', () => jsonOutlineProvider.refresh());
vscode.commands.registerCommand('jsonOutline.refreshNode', offset => jsonOutlineProvider.refresh(offset));
vscode.commands.registerCommand('jsonOutline.renameNode', offset => jsonOutlineProvider.rename(offset));
vscode.commands.registerCommand('extension.openJsonSelection', range => jsonOutlineProvider.select(range));
}
sccExplorer.ts
import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
import * as mkdirp from 'mkdirp';
import * as rimraf from 'rimraf';
//#region Utilities
interface Entry {
uri: vscode.Uri,
type: vscode.FileType
}
//#endregion
export class FileSystemProvider implements vscode.TreeDataProvider<Entry> {
getTreeItem(element: Entry): vscode.TreeItem | Thenable<vscode.TreeItem> {
throw new Error("Method not implemented.");
}
onDidChangeTreeData?: vscode.Event<Entry>;
getChildren(element?: Entry): vscode.ProviderResult<Entry[]> {
throw new Error("Method not implemented.");
}
getParent?(element: Entry): vscode.ProviderResult<Entry> {
throw new Error("Method not implemented.");
}
private _onDidChangeFile: vscode.EventEmitter<vscode.FileChangeEvent[]>;
constructor() {
this._onDidChangeFile = new vscode.EventEmitter<vscode.FileChangeEvent[]>();
}
}
export class SCCExplorer {
private fileExplorer: vscode.TreeView<any>;
constructor(context: vscode.ExtensionContext) {
const treeDataProvider = new myTree().directories;
this.fileExplorer = vscode.window.createTreeView('scc_Explorer', { treeDataProvider });
vscode.commands.registerCommand('scc_Explorer.openFile', (resource) => this.openResource(resource));
}
private openResource(resource: vscode.Uri): void {
vscode.window.showTextDocument(resource);
}
}
export class myTree{
directories: any;
constructor()
{
this.directories = [
{
name: 'parent1',
child: [{
name: 'child1',
child: []
},
{
name: 'child2',
child: []
}]
},
{
name: 'parent2',
child: {
name: 'child1',
child: []
}
},
{
name: 'parent2',
child: [{
name: 'child1',
child: []
},
{
name: 'child2',
child: []
}]
}];
}
}
Upvotes: 4
Views: 6292
Reputation: 20497
I finally got it working. It took me very long and I had it right all the time. My issue was I never did explicitly expand the items, so I would never see nested results and only the top level.
import * as vscode from "vscode";
export class OutlineProvider
implements vscode.TreeDataProvider<any> {
constructor(private outline: any) {
console.log(outline);
}
getTreeItem(item: any): vscode.TreeItem {
return new vscode.TreeItem(
item.label,
item.children.length > 0
? vscode.TreeItemCollapsibleState.Expanded
: vscode.TreeItemCollapsibleState.None
);
}
getChildren(element?: any): Thenable<[]> {
if (element) {
return Promise.resolve(element.children);
} else {
return Promise.resolve(this.outline);
}
}
}
export function activate(context: vscode.ExtensionContext) {
let disposable = vscode.commands.registerCommand(
"outliner.outline",
async () => {
vscode.window.registerTreeDataProvider(
"documentOutline",
new OutlineProvider([dataObject])
);
}
);
context.subscriptions.push(disposable);
}
const dataObject = {
label: "level one",
children: [
{
label: "level two a",
children: [
{
label: "level three",
children: [],
},
],
},
{
label: "level two b",
children: [],
},
],
}
And of course in package.json
"contributes": {
"commands": [
{
"command": "outliner.outline",
"title": "Outline"
}
],
"views": {
"explorer": [
{
"id": "documentOutline",
"name": "Document Outline"
}
]
}
},
note the type for treeDataProvider is not neccecarly what you return. Only the getTree item has to return a tree item or a class that extends it.
interface CustomType {
label: string
children?: CustomType[]
}
export class TypeExample
implements vscode.TreeDataProvider<CustomType> {
constructor(private data: CustomType[]) { }
getTreeItem(element: CustomType): vscode.TreeItem {
return new vscode.TreeItem(
element.label,
(element.children?.length ?? 0) > 0
? vscode.TreeItemCollapsibleState.Expanded
: vscode.TreeItemCollapsibleState.None
);
}
getChildren(element?: CustomType): Thenable<CustomType[]> {
return element && Promise.resolve(element.children ?? [])
|| Promise.resolve(this.data);
}
}
I thought at first the type of the data provider should be the return type of the tree item, this doesnt make much sense of course and I was trying to wrap my head around the reasoning. Now I understand that you pass your custom type in and all other methods inherit this type and expect this type as its argument. Only the getTreeItem method has to return a valid tree item that can be rendered.
Upvotes: 5