mirror of
https://github.com/microsoft/vscode-extension-samples.git
synced 2026-04-27 16:55:44 +08:00
Implement sample tree views
- Node depedencies tree - Json outline tree
This commit is contained in:
10
tree-explorer-sample/.vscode/launch.json
vendored
10
tree-explorer-sample/.vscode/launch.json
vendored
@ -23,6 +23,16 @@
|
||||
"sourceMaps": true,
|
||||
"outFiles": ["${workspaceRoot}/out/test/**/*.js"],
|
||||
"preLaunchTask": "npm"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"name": "Attach to Extension Host",
|
||||
"protocol": "legacy",
|
||||
"port": 5870,
|
||||
"sourceMaps": true,
|
||||
"restart": true,
|
||||
"outDir": "${workspaceRoot}/out/src"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -5,22 +5,30 @@
|
||||
"version": "0.0.1",
|
||||
"publisher": "octref",
|
||||
"engines": {
|
||||
"vscode": "^1.7.0"
|
||||
"vscode": "^1.12.0"
|
||||
},
|
||||
"enableProposedApi": true,
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"*"
|
||||
"onView:nodeDependencies",
|
||||
"onView:jsonOutline"
|
||||
],
|
||||
"main": "./out/src/extension",
|
||||
"icon": "media/dep.png",
|
||||
"contributes": {
|
||||
"explorer": {
|
||||
"treeLabel": "Dependencies",
|
||||
"icon": "media/dep.svg",
|
||||
"treeExplorerNodeProviderId": "depTree"
|
||||
"views": {
|
||||
"explorer": [
|
||||
{
|
||||
"id": "nodeDependencies",
|
||||
"name": "Node Dependencies"
|
||||
},
|
||||
{
|
||||
"id": "jsonOutline",
|
||||
"name": "Json Outline"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
@ -32,5 +40,8 @@
|
||||
"typescript": "^2.1.4",
|
||||
"vscode": "^1.0.0",
|
||||
"@types/node": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonc-parser": "^0.4.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
1
tree-explorer-sample/resources/light/boolean.svg
Normal file
1
tree-explorer-sample/resources/light/boolean.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-fg{fill:#f0eff1}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M16 14H0V2h16v12z" id="outline"/><path class="icon-vs-bg" d="M1 3v10h14V3H1zm13 9H8V8.507l3.998.006-2.121 2.129.707.707 3.35-3.35-3.35-3.338-.707.706 2.138 2.146L8 7.507V4h6v8z" id="iconBg"/><path class="icon-vs-fg" d="M14 4v8H8V8.507l3.998.006-2.121 2.129.707.707 3.35-3.35-3.35-3.338-.707.706 2.138 2.146L8 7.507V4h6zM6.057 5.367L5.35 4.66 2 8.01l3.35 3.338.707-.707-2.139-2.146L8 8.501v-1l-4.064-.005 2.121-2.129z" id="iconFg"/></svg>
|
||||
|
After Width: | Height: | Size: 738 B |
1
tree-explorer-sample/resources/light/number.svg
Normal file
1
tree-explorer-sample/resources/light/number.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.st0{opacity:0}.st0,.st1{fill:#f6f6f6}.st2{fill:#f0eff1}.st3{fill:#424242}</style><g id="outline"><path class="st0" d="M0 0h16v16H0z"/><path class="st1" d="M0 1h16v13H0z"/></g><path class="st2" d="M2 3v9h12V3H2zm3.141 7H4.063l.005-3.999-.973.21H3v-.875l2.141-.432V10zm4.162-.916V10H6v-.86l1.438-1.375c.152-.145.279-.276.382-.393.102-.116.185-.225.246-.325a1.043 1.043 0 0 0 .17-.574.797.797 0 0 0-.049-.281.597.597 0 0 0-.379-.361.995.995 0 0 0-.328-.051c-.119 0-.234.014-.347.04-.112.027-.22.064-.325.112a2.133 2.133 0 0 0-.297.165 2.78 2.78 0 0 0-.263.198v-.974a2.1 2.1 0 0 1 .268-.146 2.876 2.876 0 0 1 1.203-.27c.277 0 .518.037.723.11.203.074.371.175.504.303.134.129.231.28.296.453.064.174.096.36.096.558a1.752 1.752 0 0 1-.233.879 2.832 2.832 0 0 1-.322.453 4.693 4.693 0 0 1-.484.485l-1.032.917v.021h2.036zm3.777-.012a1.25 1.25 0 0 1-.346.483 1.616 1.616 0 0 1-.592.325c-.24.081-.527.12-.857.12-.121 0-.244-.006-.367-.02a3.547 3.547 0 0 1-.352-.052 2.795 2.795 0 0 1-.316-.081 1.686 1.686 0 0 1-.25-.1v-.961a1.884 1.884 0 0 0 .57.276 2.308 2.308 0 0 0 .606.09c.293 0 .516-.063.67-.188a.607.607 0 0 0 .232-.502.581.581 0 0 0-.311-.531 1.164 1.164 0 0 0-.35-.128 2.254 2.254 0 0 0-.441-.042h-.451v-.844h.416c.174 0 .32-.016.445-.049a.887.887 0 0 0 .305-.137.548.548 0 0 0 .237-.465.671.671 0 0 0-.043-.245.486.486 0 0 0-.137-.194.635.635 0 0 0-.236-.128 1.18 1.18 0 0 0-.342-.046c-.096 0-.189.01-.283.028-.092.02-.18.044-.262.073a2.072 2.072 0 0 0-.435.225v-.903a2.713 2.713 0 0 1 .486-.177 3.109 3.109 0 0 1 .746-.088c.293 0 .543.036.748.11.205.073.371.17.498.287.129.118.221.251.279.398.059.148.088.299.088.45 0 .143-.02.277-.055.407a1.108 1.108 0 0 1-.48.641c-.123.08-.273.142-.449.184v.018c.184.023.348.069.49.14a1.122 1.122 0 0 1 .65 1.033c0 .211-.037.41-.111.593z" id="icon_x5F_fg"/><g id="icon_x5F_bg"><path class="st3" d="M1 2v11h14V2H1zm13 10H2V3h12v9z"/><path class="st3" d="M8.299 8.146c.191-.168.353-.33.484-.485.133-.155.24-.307.322-.453a1.737 1.737 0 0 0 .137-1.437 1.204 1.204 0 0 0-.296-.453 1.393 1.393 0 0 0-.505-.302 2.151 2.151 0 0 0-.723-.11 2.958 2.958 0 0 0-1.202.269 2.232 2.232 0 0 0-.268.146v.974c.082-.07.17-.136.263-.198a1.99 1.99 0 0 1 .623-.277c.112-.026.227-.04.346-.04.123 0 .232.018.327.051a.645.645 0 0 1 .236.142.63.63 0 0 1 .145.219c.032.086.049.18.049.281a1.038 1.038 0 0 1-.171.574c-.061.1-.144.209-.246.325-.103.117-.23.248-.382.393L6 9.14V10h3.303v-.916H7.267v-.021l1.032-.917zM12.898 7.706a1.221 1.221 0 0 0-.357-.261 1.576 1.576 0 0 0-.49-.14v-.017c.176-.042.326-.104.449-.184.125-.081.229-.175.307-.283.08-.109.137-.228.174-.357.035-.13.055-.265.055-.407a1.21 1.21 0 0 0-.088-.45 1.078 1.078 0 0 0-.279-.398 1.438 1.438 0 0 0-.498-.287 2.219 2.219 0 0 0-.748-.11c-.143 0-.277.009-.402.024a2.58 2.58 0 0 0-.83.241v.903a1.978 1.978 0 0 1 .435-.225c.082-.029.17-.054.262-.073.094-.019.188-.028.283-.028.133 0 .246.017.342.046a.62.62 0 0 1 .236.128c.063.055.108.12.137.194a.671.671 0 0 1-.014.504.548.548 0 0 1-.18.206.906.906 0 0 1-.305.137 1.748 1.748 0 0 1-.445.049h-.416v.847h.451c.158 0 .307.015.441.042.135.028.252.071.35.128a.66.66 0 0 1 .229.219.579.579 0 0 1 .082.312c0 .21-.076.378-.232.502-.154.125-.377.188-.67.188-.094 0-.191-.007-.295-.022a2.472 2.472 0 0 1-.311-.068 1.884 1.884 0 0 1-.571-.28v.962c.07.035.154.068.25.1.098.031.203.059.316.081a3.817 3.817 0 0 0 .719.071c.33 0 .617-.039.857-.119.24-.078.438-.187.592-.325.156-.138.272-.299.346-.483.074-.184.111-.382.111-.595a1.122 1.122 0 0 0-.293-.772zM3 6.211h.095l.972-.21L4.063 10h1.078V4.904L3 5.336z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
1
tree-explorer-sample/resources/light/string.svg
Normal file
1
tree-explorer-sample/resources/light/string.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.st0{opacity:0}.st0,.st1{fill:#f6f6f6}.st2{fill:#f0eff1}.st3{fill:#424242}</style><g id="outline"><path class="st0" d="M0 0h16v16H0z"/><path class="st1" d="M1 2h15v12H1z"/></g><g id="icon_x5F_fg"><path class="st2" d="M12.078 7.977a.645.645 0 0 0-.57-.32.678.678 0 0 0-.332.082.783.783 0 0 0-.256.232 1.162 1.162 0 0 0-.168.36 1.646 1.646 0 0 0-.061.465v.506c0 .137.02.264.057.381a.994.994 0 0 0 .154.307.746.746 0 0 0 .236.207.675.675 0 0 0 .651-.016.755.755 0 0 0 .264-.266c.074-.117.129-.266.168-.445.041-.18.061-.387.061-.622a2.12 2.12 0 0 0-.053-.494 1.239 1.239 0 0 0-.151-.377zM7.102 9.224a.541.541 0 0 0-.195.133c-.047.053-.08.111-.098.18s-.027.146-.027.232c0 .078.014.15.041.219a.489.489 0 0 0 .302.285.774.774 0 0 0 .579-.031.801.801 0 0 0 .256-.199.897.897 0 0 0 .165-.295c.038-.113.059-.234.059-.365v-.347l-.762.11c-.13.017-.237.044-.32.078z"/><path class="st2" d="M3 4v8h11V4H3zm5.961 6.907h-.785v-.529h-.013c-.12.203-.267.358-.439.463-.173.107-.374.16-.604.16-.181 0-.339-.027-.479-.084a.966.966 0 0 1-.567-.595A1.398 1.398 0 0 1 6 9.858c0-.164.021-.318.065-.461a1.09 1.09 0 0 1 .562-.661c.146-.074.321-.125.525-.152l1.03-.154c0-.275-.058-.475-.174-.6-.116-.123-.28-.185-.493-.185-.214 0-.423.039-.627.117a1.909 1.909 0 0 0-.544.313v-.768c.051-.035.121-.072.213-.113a3.196 3.196 0 0 1 .672-.195c.127-.021.249-.033.368-.033.234 0 .438.033.608.102.171.068.313.166.424.295.111.127.195.285.249.469.056.186.083.399.083.637v2.438zm3.947-1.201a2.18 2.18 0 0 1-.273.672 1.34 1.34 0 0 1-.443.443c-.176.107-.379.16-.609.16a.93.93 0 0 1-.291-.043.81.81 0 0 1-.238-.121.99.99 0 0 1-.191-.186 1.507 1.507 0 0 1-.152-.228h-.012v.484H10V5h.697v2.656h.012c.055-.105.115-.201.182-.289.066-.086.141-.16.225-.223a.99.99 0 0 1 .615-.198c.221 0 .412.05.572.153.16.102.291.24.395.416.104.176.178.379.229.612.048.233.073.477.073.735 0 .305-.031.584-.092.844z"/></g><g id="icon_x5F_bg"><path class="st3" d="M2 3v10h13V3H2zm12 9H3V4h11v8z"/><path class="st3" d="M8.629 7.361a1.084 1.084 0 0 0-.423-.295 1.646 1.646 0 0 0-.609-.101c-.119 0-.241.012-.368.033a3.196 3.196 0 0 0-.672.195 1.287 1.287 0 0 0-.213.114v.768c.158-.132.341-.235.544-.313.204-.078.413-.117.627-.117.213 0 .377.063.494.186.116.125.174.325.174.6l-1.03.154a1.645 1.645 0 0 0-.526.152 1.09 1.09 0 0 0-.562.66A1.562 1.562 0 0 0 6 9.858c0 .17.025.322.074.463a.945.945 0 0 0 .568.595c.14.057.298.084.479.084.229 0 .431-.053.604-.16a1.3 1.3 0 0 0 .439-.463h.014v.529h.785V8.469c0-.238-.027-.451-.083-.637a1.289 1.289 0 0 0-.251-.471zm-.446 2.021c0 .131-.021.252-.059.365a.897.897 0 0 1-.165.295.76.76 0 0 1-.593.271.682.682 0 0 1-.242-.041.528.528 0 0 1-.186-.113.48.48 0 0 1-.116-.172.583.583 0 0 1-.04-.218c0-.086.01-.164.027-.232s.051-.127.098-.18a.541.541 0 0 1 .195-.133c.083-.033.189-.061.32-.078l.761-.109v.345zM12.697 7.516a1.194 1.194 0 0 0-.394-.416 1.028 1.028 0 0 0-.572-.153 1.016 1.016 0 0 0-.615.198 1.187 1.187 0 0 0-.225.223 2.12 2.12 0 0 0-.182.289h-.012V5H10v5.888h.697v-.484h.012c.045.082.096.158.152.228.057.07.119.133.191.186a.81.81 0 0 0 .238.121.93.93 0 0 0 .291.043c.231 0 .434-.053.609-.16a1.33 1.33 0 0 0 .443-.443c.121-.188.211-.412.273-.672A3.58 3.58 0 0 0 13 8.862a3.54 3.54 0 0 0-.074-.734 2.044 2.044 0 0 0-.229-.612zm-.476 1.954c-.039.18-.094.328-.168.445a.747.747 0 0 1-.264.266.675.675 0 0 1-.651.016.736.736 0 0 1-.236-.207.983.983 0 0 1-.154-.307 1.257 1.257 0 0 1-.057-.381v-.507c0-.17.02-.326.061-.465.039-.139.096-.258.168-.36a.762.762 0 0 1 .256-.232.678.678 0 0 1 .332-.082.642.642 0 0 1 .57.32c.066.106.117.231.15.377.035.146.053.311.053.494 0 .236-.019.443-.06.623z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@ -1,145 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { TreeExplorerNodeProvider } from 'vscode';
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { DepNodeProvider } from './nodeDependencies'
|
||||
import { JsonOutlineProvider } from './jsonOutline'
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
const rootPath = vscode.workspace.rootPath;
|
||||
const jsonOutlineProvider = new JsonOutlineProvider(context);
|
||||
|
||||
// The `providerId` here must be identical to `contributes.explorer.treeExplorerNodeProviderId` in package.json.
|
||||
vscode.window.registerTreeExplorerNodeProvider('depTree', new DepNodeProvider(rootPath));
|
||||
vscode.window.registerTreeDataProvider('nodeDependencies', new DepNodeProvider(rootPath));
|
||||
vscode.window.registerTreeDataProvider('jsonOutline', jsonOutlineProvider);
|
||||
|
||||
// This command will be invoked using exactly the node you provided in `resolveChildren`.
|
||||
vscode.commands.registerCommand('extension.openPackageOnNpm', (node: DepNode) => {
|
||||
if (node.kind === 'leaf') {
|
||||
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(`https://www.npmjs.com/package/${node.moduleName}`));
|
||||
}
|
||||
vscode.commands.registerCommand('extension.openPackageOnNpm', (node: vscode.TreeItem) => {
|
||||
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(`https://www.npmjs.com/package/${node.label}`));
|
||||
});
|
||||
|
||||
vscode.commands.registerCommand('extension.openJsonSelection', node => {
|
||||
jsonOutlineProvider.select(node);
|
||||
});
|
||||
}
|
||||
|
||||
class DepNodeProvider implements TreeExplorerNodeProvider<DepNode> {
|
||||
constructor(private workspaceRoot: string) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* As root node is invisible, its label doesn't matter.
|
||||
*/
|
||||
getLabel(node: DepNode): string {
|
||||
return node.kind === 'root' ? '' : node.moduleName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaf is unexpandable.
|
||||
*/
|
||||
getHasChildren(node: DepNode): boolean {
|
||||
return node.kind !== 'leaf';
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke `extension.openPackageOnNpm` command when a Leaf node is clicked.
|
||||
*/
|
||||
getClickCommand(node: DepNode): string {
|
||||
return node.kind === 'leaf' ? 'extension.openPackageOnNpm' : null;
|
||||
}
|
||||
|
||||
provideRootNode(): DepNode {
|
||||
return new Root();
|
||||
}
|
||||
|
||||
resolveChildren(node: DepNode): Thenable<DepNode[]> {
|
||||
if (!this.workspaceRoot) {
|
||||
vscode.window.showInformationMessage('No dependency in empty workspace');
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
switch (node.kind) {
|
||||
case 'root':
|
||||
const packageJsonPath = path.join(this.workspaceRoot, 'package.json');
|
||||
if (this.pathExists(packageJsonPath)) {
|
||||
resolve(this.getDepsInPackageJson(packageJsonPath));
|
||||
} else {
|
||||
vscode.window.showInformationMessage('Workspace has no package.json');
|
||||
resolve([]);
|
||||
}
|
||||
break;
|
||||
/**
|
||||
* npm3 has flat dependencies, so indirect dependencies are still in `node_modules`.
|
||||
*/
|
||||
case 'node':
|
||||
resolve(this.getDepsInPackageJson(path.join(this.workspaceRoot, 'node_modules', node.moduleName, 'package.json')));
|
||||
break;
|
||||
case 'leaf':
|
||||
resolve([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the path to package.json, read all its dependencies and devDependencies.
|
||||
*/
|
||||
private getDepsInPackageJson(packageJsonPath: string): DepNode[] {
|
||||
if (this.pathExists(packageJsonPath)) {
|
||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
||||
|
||||
const toDep = (moduleName: string): DepNode => {
|
||||
if (this.pathExists(path.join(this.workspaceRoot, 'node_modules', moduleName))) {
|
||||
return new Node(moduleName);
|
||||
} else {
|
||||
return new Leaf(moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
const deps = packageJson.dependencies
|
||||
? Object.keys(packageJson.dependencies).map(toDep)
|
||||
: [];
|
||||
const devDeps = packageJson.devDependencies
|
||||
? Object.keys(packageJson.devDependencies).map(toDep)
|
||||
: [];
|
||||
return deps.concat(devDeps);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private pathExists(p: string): boolean {
|
||||
try {
|
||||
fs.accessSync(p);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
type DepNode = Root // Root node
|
||||
| Node // A dependency installed to `node_modules`
|
||||
| Leaf // A dependency not present in `node_modules`
|
||||
;
|
||||
|
||||
class Root {
|
||||
kind: 'root' = 'root';
|
||||
}
|
||||
|
||||
class Node {
|
||||
kind: 'node' = 'node';
|
||||
|
||||
constructor(
|
||||
public moduleName: string
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
class Leaf {
|
||||
kind: 'leaf' = 'leaf'
|
||||
|
||||
constructor(
|
||||
public moduleName: string
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
117
tree-explorer-sample/src/jsonOutline.ts
Normal file
117
tree-explorer-sample/src/jsonOutline.ts
Normal file
@ -0,0 +1,117 @@
|
||||
import * as vscode from 'vscode';
|
||||
import * as json from 'jsonc-parser';
|
||||
import * as path from 'path';
|
||||
|
||||
export class JsonOutlineProvider implements vscode.TreeDataProvider<json.Node> {
|
||||
|
||||
private _onDidChange : vscode.EventEmitter<json.Node | null> = new vscode.EventEmitter<json.Node | null>();
|
||||
readonly onDidChange : vscode.Event<json.Node | null> = this._onDidChange.event;
|
||||
|
||||
private tree: json.Node;
|
||||
private editor: vscode.TextEditor;
|
||||
|
||||
constructor(private context: vscode.ExtensionContext) {
|
||||
vscode.window.onDidChangeActiveTextEditor(editor => {
|
||||
if (this.parseTree()) {
|
||||
this._onDidChange.fire();
|
||||
}
|
||||
});
|
||||
this.parseTree();
|
||||
}
|
||||
|
||||
private parseTree() : boolean {
|
||||
this.editor = vscode.window.activeTextEditor;
|
||||
if (this.editor && this.editor.document.languageId === 'json') {
|
||||
this.tree = json.parseTree(this.editor.document.getText());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getChildren(node?: json.Node): Thenable<json.Node[]> {
|
||||
if (node) {
|
||||
return Promise.resolve(node.parent.type === 'array' ? this.toArrayValueNode(node) : (node.type === 'array' ? node.children[0].children : node.children[1].children));
|
||||
} else {
|
||||
return Promise.resolve(this.tree.children);
|
||||
}
|
||||
}
|
||||
|
||||
private toArrayValueNode(node: json.Node): json.Node[] {
|
||||
if (node.type === 'array' || node.type === 'object') {
|
||||
return node.children;
|
||||
}
|
||||
node['arrayValue'] = true;
|
||||
return [node];
|
||||
}
|
||||
|
||||
getTreeItem(node: json.Node): vscode.TreeItem {
|
||||
let valueNode = node.parent.type === 'array' ? node : node.children[1];
|
||||
let hasChildren = (node.parent.type === 'array' && !node['arrayValue']) || valueNode.type === 'object' || valueNode.type === 'array';
|
||||
return <vscode.TreeItem> {
|
||||
label: this.getLabel(node),
|
||||
collapsibleState: hasChildren ? vscode.TreeItemCollapsibleState.Collapsed : null,
|
||||
command: !hasChildren ? {
|
||||
command: 'extension.openJsonSelection',
|
||||
title: '',
|
||||
} : null,
|
||||
iconPath: this.getIcon(node)
|
||||
};
|
||||
}
|
||||
|
||||
select(node: json.Node) {
|
||||
this.editor.selection = new vscode.Selection(this.editor.document.positionAt(node.offset), this.editor.document.positionAt(node.offset + node.length));
|
||||
}
|
||||
|
||||
private getIcon(node: json.Node): any {
|
||||
let nodeType = this.getNodeType(node);
|
||||
if (nodeType === 'boolean') {
|
||||
return {
|
||||
light: this.context.asAbsolutePath(path.join('resources', 'light', 'boolean.svg')),
|
||||
dark: this.context.asAbsolutePath(path.join('resources', 'dark', 'boolean.svg'))
|
||||
}
|
||||
}
|
||||
if (nodeType === 'string') {
|
||||
return {
|
||||
light: this.context.asAbsolutePath(path.join('resources', 'light', 'string.svg')),
|
||||
dark: this.context.asAbsolutePath(path.join('resources', 'dark', 'string.svg'))
|
||||
}
|
||||
}
|
||||
if (nodeType === 'number') {
|
||||
return {
|
||||
light: this.context.asAbsolutePath(path.join('resources', 'light', 'number.svg')),
|
||||
dark: this.context.asAbsolutePath(path.join('resources', 'dark', 'number.svg'))
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private getNodeType(node: json.Node): json.NodeType {
|
||||
if (node.parent.type === 'array') {
|
||||
return node.type;
|
||||
}
|
||||
return node.children[1].type;
|
||||
}
|
||||
|
||||
private getLabel(node: json.Node): string {
|
||||
if (node.parent.type === 'array') {
|
||||
if (node['arrayValue']) {
|
||||
delete node['arrayValue'];
|
||||
if (!node.children) {
|
||||
return node.value.toString();
|
||||
}
|
||||
} else {
|
||||
return node.parent.children.indexOf(node).toString();
|
||||
}
|
||||
}
|
||||
const property = node.children[0].value.toString();
|
||||
if (node.children[1].type === 'object') {
|
||||
return '{ } ' + property;
|
||||
}
|
||||
if (node.children[1].type === 'array') {
|
||||
return '[ ] ' + property;
|
||||
}
|
||||
const value = this.editor.document.getText(new vscode.Range(this.editor.document.positionAt(node.children[1].offset), this.editor.document.positionAt(node.children[1].offset + node.children[1].length)))
|
||||
return `${property}: ${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
90
tree-explorer-sample/src/nodeDependencies.ts
Normal file
90
tree-explorer-sample/src/nodeDependencies.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import * as vscode from 'vscode';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
export class DepNodeProvider implements vscode.TreeDataProvider<Dependency> {
|
||||
|
||||
constructor(private workspaceRoot: string) {
|
||||
}
|
||||
|
||||
getTreeItem(element: Dependency): vscode.TreeItem {
|
||||
return element;
|
||||
}
|
||||
|
||||
getChildren(element?: Dependency): Thenable<Dependency[]> {
|
||||
if (!this.workspaceRoot) {
|
||||
vscode.window.showInformationMessage('No dependency in empty workspace');
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
if (element) {
|
||||
resolve(this.getDepsInPackageJson(path.join(this.workspaceRoot, 'node_modules', element.label, 'package.json')));
|
||||
} else {
|
||||
const packageJsonPath = path.join(this.workspaceRoot, 'package.json');
|
||||
if (this.pathExists(packageJsonPath)) {
|
||||
resolve(this.getDepsInPackageJson(packageJsonPath));
|
||||
} else {
|
||||
vscode.window.showInformationMessage('Workspace has no package.json');
|
||||
resolve([]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the path to package.json, read all its dependencies and devDependencies.
|
||||
*/
|
||||
private getDepsInPackageJson(packageJsonPath: string): Dependency[] {
|
||||
if (this.pathExists(packageJsonPath)) {
|
||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
||||
|
||||
const toDep = (moduleName: string): Dependency => {
|
||||
if (this.pathExists(path.join(this.workspaceRoot, 'node_modules', moduleName))) {
|
||||
return new Node(moduleName);
|
||||
} else {
|
||||
return new Dependency(moduleName, {
|
||||
command: 'extension.openPackageOnNpm',
|
||||
title: ''
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const deps = packageJson.dependencies
|
||||
? Object.keys(packageJson.dependencies).map(toDep)
|
||||
: [];
|
||||
const devDeps = packageJson.devDependencies
|
||||
? Object.keys(packageJson.devDependencies).map(toDep)
|
||||
: [];
|
||||
return deps.concat(devDeps);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private pathExists(p: string): boolean {
|
||||
try {
|
||||
fs.accessSync(p);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class Dependency implements vscode.TreeItem {
|
||||
|
||||
constructor(
|
||||
public readonly label: string,
|
||||
public readonly command?: vscode.Command
|
||||
) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Node extends Dependency {
|
||||
|
||||
readonly collapsibleState = vscode.TreeItemCollapsibleState.Collapsed;
|
||||
|
||||
}
|
||||
178
tree-explorer-sample/typings/vscode.proposed.d.ts
vendored
178
tree-explorer-sample/typings/vscode.proposed.d.ts
vendored
@ -13,76 +13,158 @@ declare module 'vscode' {
|
||||
}
|
||||
|
||||
export namespace window {
|
||||
|
||||
/**
|
||||
* Register a [TreeExplorerNodeProvider](#TreeExplorerNodeProvider).
|
||||
*
|
||||
* @param providerId A unique id that identifies the provider.
|
||||
* @param provider A [TreeExplorerNodeProvider](#TreeExplorerNodeProvider).
|
||||
* @return A [disposable](#Disposable) that unregisters this provider when being disposed.
|
||||
* Register a [TreeDataProvider](#TreeDataProvider) for the registered view `id`.
|
||||
* @param id View id.
|
||||
* @param treeDataProvider A [TreeDataProvider](#TreeDataProvider) that provides tree data for the view
|
||||
*/
|
||||
export function registerTreeExplorerNodeProvider(providerId: string, provider: TreeExplorerNodeProvider<any>): Disposable;
|
||||
export function registerTreeDataProvider<T>(id: string, treeDataProvider: TreeDataProvider<T>): Disposable;
|
||||
}
|
||||
|
||||
/**
|
||||
* A node provider for a tree explorer contribution.
|
||||
*
|
||||
* Providers are registered through (#workspace.registerTreeExplorerNodeProvider) with a
|
||||
* `providerId` that corresponds to the `treeExplorerNodeProviderId` in the extension's
|
||||
* `contributes.explorer` section.
|
||||
*
|
||||
* The contributed tree explorer will ask the corresponding provider to provide the root
|
||||
* node and resolve children for each node. In addition, the provider could **optionally**
|
||||
* provide the following information for each node:
|
||||
* - label: A human-readable label used for rendering the node.
|
||||
* - hasChildren: Whether the node has children and is expandable.
|
||||
* - clickCommand: A command to execute when the node is clicked.
|
||||
* A data provider that provides tree data for a view
|
||||
*/
|
||||
export interface TreeExplorerNodeProvider<T> {
|
||||
export interface TreeDataProvider<T> {
|
||||
/**
|
||||
* An optional event to signal that an element or root has changed.
|
||||
*/
|
||||
onDidChange?: Event<T | undefined | null>;
|
||||
|
||||
/**
|
||||
* Provide the root node. This function will be called when the tree explorer is activated
|
||||
* for the first time. The root node is hidden and its direct children will be displayed on the first level of
|
||||
* the tree explorer.
|
||||
* get [TreeItem](#TreeItem) representation of the `element`
|
||||
*
|
||||
* @return The root node.
|
||||
* @param element The element for which [TreeItem](#TreeItem) representation is asked for.
|
||||
* @return [TreeItem](#TreeItem) representation of the element
|
||||
*/
|
||||
provideRootNode(): T | Thenable<T>;
|
||||
getTreeItem(element: T): TreeItem;
|
||||
|
||||
/**
|
||||
* Resolve the children of `node`.
|
||||
* get the children of `element` or root.
|
||||
*
|
||||
* @param node The node from which the provider resolves children.
|
||||
* @return Children of `node`.
|
||||
* @param element The element from which the provider gets children for.
|
||||
* @return Children of `element` or root.
|
||||
*/
|
||||
resolveChildren(node: T): T[] | Thenable<T[]>;
|
||||
getChildren(element?: T): T[] | Thenable<T[]>;
|
||||
}
|
||||
|
||||
export interface TreeItem {
|
||||
/**
|
||||
* Label of the tree item
|
||||
*/
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* Provide a human-readable string that will be used for rendering the node. Default to use
|
||||
* `node.toString()` if not provided.
|
||||
*
|
||||
* @param node The node from which the provider computes label.
|
||||
* @return A human-readable label.
|
||||
* The icon path for the tree item
|
||||
*/
|
||||
getLabel?(node: T): string;
|
||||
iconPath?: string | Uri | { light: string | Uri; dark: string | Uri };
|
||||
|
||||
/**
|
||||
* Determine if `node` has children and is expandable. Default to `true` if not provided.
|
||||
*
|
||||
* @param node The node to determine if it has children and is expandable.
|
||||
* @return A boolean that determines if `node` has children and is expandable.
|
||||
* The [command](#Command) which should be run when the tree item
|
||||
* is open in the Source Control viewlet.
|
||||
*/
|
||||
getHasChildren?(node: T): boolean;
|
||||
command?: Command;
|
||||
|
||||
/**
|
||||
* Get the command to execute when `node` is clicked.
|
||||
*
|
||||
* Commands can be registered through [registerCommand](#commands.registerCommand). `node` will be provided
|
||||
* as the first argument to the command's callback function.
|
||||
*
|
||||
* @param node The node that the command is associated with.
|
||||
* @return The command to execute when `node` is clicked.
|
||||
* Context value of the tree node
|
||||
*/
|
||||
getClickCommand?(node: T): string;
|
||||
contextValue?: string;
|
||||
|
||||
/**
|
||||
* Collapsible state of the tree item.
|
||||
* Required only when item has children.
|
||||
*/
|
||||
collapsibleState?: TreeItemCollapsibleState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapsible state of the tree item
|
||||
*/
|
||||
export enum TreeItemCollapsibleState {
|
||||
/**
|
||||
* Determines an item is collapsed
|
||||
*/
|
||||
Collapsed = 1,
|
||||
/**
|
||||
* Determines an item is expanded
|
||||
*/
|
||||
Expanded = 2
|
||||
}
|
||||
|
||||
/**
|
||||
* The contiguous set of modified lines in a diff.
|
||||
*/
|
||||
export interface LineChange {
|
||||
readonly originalStartLineNumber: number;
|
||||
readonly originalEndLineNumber: number;
|
||||
readonly modifiedStartLineNumber: number;
|
||||
readonly modifiedEndLineNumber: number;
|
||||
}
|
||||
|
||||
export namespace commands {
|
||||
|
||||
/**
|
||||
* Registers a diff information command that can be invoked via a keyboard shortcut,
|
||||
* a menu item, an action, or directly.
|
||||
*
|
||||
* Diff information commands are different from ordinary [commands](#commands.registerCommand) as
|
||||
* they only execute when there is an active diff editor when the command is called, and the diff
|
||||
* information has been computed. Also, the command handler of an editor command has access to
|
||||
* the diff information.
|
||||
*
|
||||
* @param command A unique identifier for the command.
|
||||
* @param callback A command handler function with access to the [diff information](#LineChange).
|
||||
* @param thisArg The `this` context used when invoking the handler function.
|
||||
* @return Disposable which unregisters this command on disposal.
|
||||
*/
|
||||
export function registerDiffInformationCommand(command: string, callback: (diff: LineChange[], ...args: any[]) => any, thisArg?: any): Disposable;
|
||||
}
|
||||
|
||||
export interface Terminal {
|
||||
|
||||
/**
|
||||
* The name of the terminal.
|
||||
*/
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* The process ID of the shell process.
|
||||
*/
|
||||
readonly processId: Thenable<number>;
|
||||
|
||||
/**
|
||||
* Send text to the terminal. The text is written to the stdin of the underlying pty process
|
||||
* (shell) of the terminal.
|
||||
*
|
||||
* @param text The text to send.
|
||||
* @param addNewLine Whether to add a new line to the text being sent, this is normally
|
||||
* required to run a command in the terminal. The character(s) added are \n or \r\n
|
||||
* depending on the platform. This defaults to `true`.
|
||||
*/
|
||||
sendText(text: string, addNewLine?: boolean): void;
|
||||
|
||||
/**
|
||||
* Show the terminal panel and reveal this terminal in the UI.
|
||||
*
|
||||
* @param preserveFocus When `true` the terminal will not take focus.
|
||||
*/
|
||||
show(preserveFocus?: boolean): void;
|
||||
|
||||
/**
|
||||
* Hide the terminal panel if this terminal is currently showing.
|
||||
*/
|
||||
hide(): void;
|
||||
|
||||
/**
|
||||
* Dispose and free associated resources.
|
||||
*/
|
||||
dispose(): void;
|
||||
|
||||
/**
|
||||
* Experimental API that allows listening to the raw data stream coming from the terminal's
|
||||
* pty process (including ANSI escape sequences).
|
||||
*
|
||||
* @param callback The callback that is triggered when data is sent to the terminal.
|
||||
*/
|
||||
onData(callback: (data: string) => any): void;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user