Enhance json outline example

This commit is contained in:
Sandeep Somavarapu
2017-12-03 19:10:18 +01:00
parent f05010b51d
commit 60bd6be48b
4 changed files with 97 additions and 66 deletions

View File

@ -7,10 +7,14 @@
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceRoot}"],
"args": [
"--extensionDevelopmentPath=${workspaceRoot}"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": ["${workspaceRoot}/out/src/**/*.js"],
"outFiles": [
"${workspaceRoot}/out/src/**/*.js"
],
"preLaunchTask": "npm"
},
{
@ -18,21 +22,27 @@
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ],
"args": [
"--extensionDevelopmentPath=${workspaceRoot}",
"--extensionTestsPath=${workspaceRoot}/out/test"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": ["${workspaceRoot}/out/test/**/*.js"],
"outFiles": [
"${workspaceRoot}/out/test/**/*.js"
],
"preLaunchTask": "npm"
},
{
"type": "node",
"request": "attach",
"name": "Attach to Extension Host",
"protocol": "legacy",
"protocol": "inspector",
"port": 5870,
"sourceMaps": true,
"restart": true,
"outDir": "${workspaceRoot}/out/src"
"outFiles": [
"${workspaceRoot}/out/src"
]
}
]
}
}

View File

@ -55,10 +55,23 @@
{
"command": "openFtpResource",
"title": "Open FTP Resource"
},
{
"command": "jsonOutline.refresh",
"title": "Refresh",
"icon": {
"light": "resources/light/refresh.svg",
"dark": "resources/dark/refresh.svg"
}
}
],
"menus": {
"view/title": [
{
"command": "jsonOutline.refresh",
"when": "view == jsonOutline",
"group": "navigation"
},
{
"command": "nodeDependencies.refreshEntry",
"when": "view == nodeDependencies",

View File

@ -14,6 +14,7 @@ export function activate(context: vscode.ExtensionContext) {
const ftpExplorerProvider = new FtpTreeDataProvider();
vscode.window.registerTreeDataProvider('nodeDependencies', nodeDependenciesProvider);
vscode.commands.registerCommand('jsonOutline.refresh', () => jsonOutlineProvider.refresh());
vscode.window.registerTreeDataProvider('jsonOutline', jsonOutlineProvider);
vscode.window.registerTreeDataProvider('ftpExplorer', ftpExplorerProvider);

View File

@ -2,10 +2,10 @@ import * as vscode from 'vscode';
import * as json from 'jsonc-parser';
import * as path from 'path';
export class JsonOutlineProvider implements vscode.TreeDataProvider<json.Node> {
export class JsonOutlineProvider implements vscode.TreeDataProvider<string> {
private _onDidChangeTreeData: vscode.EventEmitter<json.Node | null> = new vscode.EventEmitter<json.Node | null>();
readonly onDidChangeTreeData: vscode.Event<json.Node | null> = this._onDidChangeTreeData.event;
private _onDidChangeTreeData: vscode.EventEmitter<string | null> = new vscode.EventEmitter<string | null>();
readonly onDidChangeTreeData: vscode.Event<string | null> = this._onDidChangeTreeData.event;
private tree: json.Node;
private text: string;
@ -13,20 +13,25 @@ export class JsonOutlineProvider implements vscode.TreeDataProvider<json.Node> {
constructor(private context: vscode.ExtensionContext) {
vscode.window.onDidChangeActiveTextEditor(editor => {
this.parseTree();
this._onDidChangeTreeData.fire();
this.refresh();
});
vscode.workspace.onDidChangeTextDocument(e => this.onDocumentChanged(e));
this.parseTree();
}
refresh(): void {
this.parseTree();
this._onDidChangeTreeData.fire();
}
private onDocumentChanged(changeEvent: vscode.TextDocumentChangeEvent): void {
if (changeEvent.document.uri.toString() === this.editor.document.uri.toString()) {
for (const change of changeEvent.contentChanges) {
const location = json.getLocation(this.text, this.editor.document.offsetAt(change.range.start));
const node = json.findNodeAtLocation(this.tree, location.path);
const path = json.getLocation(this.text, this.editor.document.offsetAt(change.range.start)).path;
path.pop();
const node = path.length ? json.findNodeAtLocation(this.tree, path) : void 0;
this.parseTree();
this._onDidChangeTreeData.fire(node);
this._onDidChangeTreeData.fire(node ? `${node.offset}` : void 0);
}
}
}
@ -41,38 +46,44 @@ export class JsonOutlineProvider implements vscode.TreeDataProvider<json.Node> {
}
}
getChildren(node?: json.Node): Thenable<json.Node[]> {
if (node) {
return Promise.resolve(this._getChildren(node));
getChildren(offset?: string): Thenable<string[]> {
if (offset) {
const path = json.getLocation(this.text, parseInt(offset)).path
const node = json.findNodeAtLocation(this.tree, path);
return Promise.resolve(this.getChildrenOffsets(node));
} else {
return Promise.resolve(this.tree ? this.tree.children : []);
return Promise.resolve(this.tree ? this.getChildrenOffsets(this.tree) : []);
}
}
private _getChildren(node: json.Node): json.Node[] {
return node.parent.type === 'array' ? this.toArrayValueNode(node) : (node.type === 'array' ? node.children[0].children : node.children[1].children);
}
private toArrayValueNode(node: json.Node): json.Node[] {
if (node.type === 'array' || node.type === 'object') {
return node.children;
private getChildrenOffsets(node: json.Node): string[] {
const offsets = [];
for (const child of node.children) {
const childPath = json.getLocation(this.text, child.offset).path
const childNode = json.findNodeAtLocation(this.tree, childPath);
if (childNode) {
offsets.push(childNode.offset.toString());
}
}
node['arrayValue'] = true;
return [node];
return offsets;
}
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';
let treeItem: vscode.TreeItem = new vscode.TreeItem(this.getLabel(node), hasChildren ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.None);
treeItem.command = {
command: 'extension.openJsonSelection',
title: '',
arguments: [new vscode.Range(this.editor.document.positionAt(node.offset), this.editor.document.positionAt(node.offset + node.length))]
};
treeItem.iconPath = this.getIcon(node);
treeItem.contextValue = this.getNodeType(node);
return treeItem;
getTreeItem(offset: string): vscode.TreeItem {
const path = json.getLocation(this.text, parseInt(offset)).path
const valueNode = json.findNodeAtLocation(this.tree, path);
if (valueNode) {
let hasChildren = valueNode.type === 'object' || valueNode.type === 'array';
let treeItem: vscode.TreeItem = new vscode.TreeItem(this.getLabel(valueNode), hasChildren ? valueNode.type === 'object' ? vscode.TreeItemCollapsibleState.Expanded : vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.None);
treeItem.command = {
command: 'extension.openJsonSelection',
title: '',
arguments: [new vscode.Range(this.editor.document.positionAt(valueNode.offset), this.editor.document.positionAt(valueNode.offset + valueNode.length))]
};
treeItem.iconPath = this.getIcon(valueNode);
treeItem.contextValue = valueNode.type;
return treeItem;
}
return null;
}
select(range: vscode.Range) {
@ -80,7 +91,7 @@ export class JsonOutlineProvider implements vscode.TreeDataProvider<json.Node> {
}
private getIcon(node: json.Node): any {
let nodeType = this.getNodeType(node);
let nodeType = node.type;
if (nodeType === 'boolean') {
return {
light: this.context.asAbsolutePath(path.join('resources', 'light', 'boolean.svg')),
@ -102,33 +113,29 @@ export class JsonOutlineProvider implements vscode.TreeDataProvider<json.Node> {
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();
let prefix = node.parent.children.indexOf(node).toString();
if (node.type === 'object') {
return prefix + ':{ }';
}
if (node.type === 'array') {
return prefix + ':[ ]';
}
return prefix + ':' + node.value.toString();
}
const property = node.children[0].value.toString();
if (node.children[1].type === 'object') {
return '{ } ' + property;
else {
const property = node.parent.children[0].value.toString();
if (node.type === 'array' || node.type === 'object') {
if (node.type === 'object') {
return '{ } ' + property;
}
if (node.type === 'array') {
return '[ ] ' + property;
}
}
const value = this.editor.document.getText(new vscode.Range(this.editor.document.positionAt(node.offset), this.editor.document.positionAt(node.offset + node.length)))
return `${property}: ${value}`;
}
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}`;
}
}
}