Skip to content

Commit dd779ca

Browse files
committed
COS explorer
1 parent e4d81c4 commit dd779ca

11 files changed

+518
-191
lines changed

explorer/explorer.ts

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,82 @@
1-
const vscode = require('vscode');
1+
import * as vscode from "vscode";
2+
import { NodeBase } from "./models/nodeBase";
3+
import { RootNode } from "./models/rootNode";
4+
import { resolve } from "url";
5+
6+
export class COSExplorerProvider implements vscode.TreeDataProvider<NodeBase>, vscode.TextDocumentContentProvider {
7+
onDidChange?: vscode.Event<vscode.Uri>;
8+
private _onDidChangeTreeData: vscode.EventEmitter<NodeBase> = new vscode.EventEmitter<NodeBase>();
9+
readonly onDidChangeTreeData: vscode.Event<NodeBase> = this._onDidChangeTreeData.event;
10+
private _classesNode: RootNode;
11+
private _routinesNode: RootNode;
12+
private _api;
13+
14+
constructor() { }
15+
16+
setAPI(api): void {
17+
this._api = api;
18+
}
19+
20+
refresh(): void {
21+
this._onDidChangeTreeData.fire(this._classesNode);
22+
this._onDidChangeTreeData.fire(this._routinesNode);
23+
}
24+
25+
getTreeItem(element: NodeBase): vscode.TreeItem {
26+
return element.getTreeItem();
27+
}
28+
29+
async getChildren(element?: NodeBase): Promise<NodeBase[]> {
30+
if (!element) {
31+
return this.getRootNodes();
32+
}
33+
return element.getChildren(element);
34+
}
35+
36+
private async getRootNodes(): Promise<RootNode[]> {
37+
const rootNodes: RootNode[] = [];
38+
let node: RootNode;
39+
let data: any;
40+
41+
data = await this.getDocNames("CLS");
42+
node = new RootNode("Classes", "classesRootNode", this._onDidChangeTreeData, data);
43+
this._classesNode = node;
44+
rootNodes.push(node);
45+
46+
data = await this.getDocNames("RTN");
47+
node = new RootNode("Routines", "routinesRootNode", this._onDidChangeTreeData, data);
48+
this._routinesNode = node;
49+
rootNodes.push(node);
50+
51+
return rootNodes;
52+
}
53+
54+
getDocNames(category: string): Promise<any> {
55+
return new Promise((resolve, reject) => {
56+
this._api.getDocNames({
57+
category
58+
}, (error, data) => {
59+
if (error) {
60+
reject(error);
61+
} else {
62+
let content = data.result.content;
63+
resolve(content);
64+
}
65+
});
66+
});
67+
}
68+
69+
provideTextDocumentContent(uri: vscode.Uri, token: vscode.CancellationToken): vscode.ProviderResult<string> {
70+
let fileName = uri.path.split('/')[1];
71+
return new Promise((resolve, reject) => {
72+
this._api.getDoc(fileName,
73+
(error, data) => {
74+
if (error) {
75+
reject(error);
76+
} else {
77+
resolve(data.result.content.join('\n'));
78+
}
79+
});
80+
});
81+
}
82+
}

explorer/models/classesNode.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import * as vscode from 'vscode';
2+
import { NodeBase } from './nodeBase';
3+
4+
export class ClassNode extends NodeBase {
5+
6+
constructor(
7+
public readonly label: string,
8+
public readonly fullName: string
9+
) {
10+
super(label)
11+
}
12+
13+
getTreeItem(): vscode.TreeItem {
14+
let displayName: string = this.label;
15+
16+
return {
17+
label: `${displayName}`,
18+
collapsibleState: vscode.TreeItemCollapsibleState.None,
19+
contextValue: "classNode",
20+
command: {
21+
command: 'cosExplorer.openClass',
22+
arguments: [vscode.Uri.parse(encodeURI(`cos:///${this.fullName}`))],
23+
title: 'Open class'
24+
}
25+
// iconPath: {
26+
// light: path.join(__filename, '..', '..', '..', '..', 'images', 'light', 'class.svg'),
27+
// dark: path.join(__filename, '..', '..', '..', '..', 'images', 'dark', 'class.svg')
28+
// }
29+
}
30+
}
31+
}

explorer/models/nodeBase.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as vscode from "vscode";
2+
3+
export class NodeBase {
4+
readonly label: string;
5+
6+
protected constructor(label: string) {
7+
this.label = label;
8+
}
9+
10+
getTreeItem(): vscode.TreeItem {
11+
return {
12+
label: this.label,
13+
collapsibleState: vscode.TreeItemCollapsibleState.None
14+
};
15+
}
16+
17+
async getChildren(element): Promise<NodeBase[]> {
18+
return [];
19+
}
20+
}

explorer/models/packageNode.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as vscode from 'vscode';
2+
import { NodeBase } from './nodeBase';
3+
import { ClassNode } from './classesNode';
4+
5+
export class PackageNode extends NodeBase {
6+
7+
constructor(
8+
public readonly label: string,
9+
private readonly _items,
10+
) {
11+
super(label)
12+
}
13+
14+
getTreeItem(): vscode.TreeItem {
15+
let displayName: string = this.label;
16+
17+
return {
18+
label: `${displayName}`,
19+
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
20+
contextValue: "packageNode",
21+
// iconPath: {
22+
// light: path.join(__filename, '..', '..', '..', '..', 'images', 'light', 'package.svg'),
23+
// dark: path.join(__filename, '..', '..', '..', '..', 'images', 'dark', 'package.svg')
24+
// }
25+
}
26+
}
27+
28+
async getChildren(element): Promise<NodeBase[]> {
29+
return this._items.map(({name, fullName, nodes}) => nodes.length ? new PackageNode(name, nodes) : new ClassNode(name, fullName));
30+
}
31+
32+
}

explorer/models/rootNode.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import * as vscode from "vscode";
2+
3+
import { NodeBase } from "./nodeBase";
4+
import { PackageNode } from "./packageNode";
5+
import { RoutineNode } from "./routineNode";
6+
7+
export class RootNode extends NodeBase {
8+
9+
constructor(
10+
public readonly label: string,
11+
public readonly contextValue: string,
12+
public eventEmitter: vscode.EventEmitter<NodeBase>,
13+
private _items: any[]
14+
) {
15+
super(label);
16+
}
17+
18+
getTreeItem(): vscode.TreeItem {
19+
return {
20+
label: this.label,
21+
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
22+
contextValue: this.contextValue
23+
}
24+
25+
}
26+
27+
async getChildren(element): Promise<NodeBase[]> {
28+
if (element.contextValue === 'classesRootNode') {
29+
return this.getClasses();
30+
}
31+
32+
if (element.contextValue === 'routinesRootNode') {
33+
return this.getRoutines();
34+
}
35+
36+
}
37+
38+
private async getClasses(): Promise<PackageNode[]> {
39+
let items = this.makeTree(this._items);
40+
41+
return items.map(({name, nodes}) => new PackageNode(name, nodes));
42+
}
43+
44+
private async getRoutines(): Promise<RoutineNode[]> {
45+
return this._items.map(({name}) => new RoutineNode(name, name));
46+
}
47+
48+
private makeTree(items: any[]): any[] {
49+
let tree;
50+
tree = items.map(({name}) => ({name}));
51+
tree.forEach(el => {
52+
let parent = el.name.split('.').slice(0, -2);
53+
el.parent = parent.join('.');
54+
el.fullName = el.name;
55+
el.name = el.name.split('.').slice(-2).join('.');
56+
let parents = parent.map((name, i) => { return {name, fullName: (parent.slice(0, i+1).join('.')), parent: (parent.slice(0, i).join('.'))}});
57+
tree = tree.concat(parents);
58+
});
59+
tree = tree.filter((value, index, self) => self.findIndex(({fullName}) => fullName === value.fullName) === index);
60+
tree = tree.sort((el1, el2) => el1.fullName < el2.fullName ? -1 : el1.fullName > el2.fullName ? 1 : 0);
61+
tree.forEach(el => {
62+
el.nodes = tree.filter(ch => el.fullName === ch.parent);
63+
});
64+
tree = tree.filter(el => el.parent === "");
65+
66+
return tree;
67+
}
68+
}

explorer/models/routineNode.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import * as vscode from 'vscode';
2+
import { NodeBase } from './nodeBase';
3+
4+
export class RoutineNode extends NodeBase {
5+
6+
constructor(
7+
public readonly label: string,
8+
public readonly fullName: string
9+
) {
10+
super(label)
11+
}
12+
13+
getTreeItem(): vscode.TreeItem {
14+
let displayName: string = this.label;
15+
16+
return {
17+
label: `${displayName}`,
18+
collapsibleState: vscode.TreeItemCollapsibleState.None,
19+
contextValue: "routineNode",
20+
command: {
21+
command: 'cosExplorer.openRoutine',
22+
arguments: [vscode.Uri.parse(encodeURI(`cos:///${this.fullName}`))],
23+
title: 'Open routine'
24+
}
25+
// iconPath: {
26+
// light: path.join(__filename, '..', '..', '..', '..', 'images', 'light', 'routine.svg'),
27+
// dark: path.join(__filename, '..', '..', '..', '..', 'images', 'dark', 'routine.svg')
28+
// }
29+
}
30+
}
31+
}

extension.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import vscode = require("vscode");
22
const { workspace, window } = vscode;
3-
const http = require("http");
3+
import http = require("http");
44

55
const API = require("cos-api4node");
66
const LOG = require("./log");
@@ -9,13 +9,19 @@ const CmdExport = require("./commands/export");
99
const { CurrentDoc } = require("./commands/currentdoc");
1010
const IsApiError = require("./is-api-error");
1111

12-
const activate = context => {
12+
import { COSExplorerProvider } from './explorer/explorer';
13+
export var cosExplorerProvider: COSExplorerProvider;
14+
15+
export async function activate(context: vscode.ExtensionContext): Promise<void> {
1316
const languages = require(context.asAbsolutePath("./package.json"))[
1417
"contributes"
1518
]["languages"].map(lang => lang.id);
1619

1720
const log = LOG(window);
1821

22+
cosExplorerProvider = new COSExplorerProvider();
23+
vscode.window.registerTreeDataProvider('cosExplorer', cosExplorerProvider);
24+
1925
const Config = workspace => {
2026
let options = null;
2127
const init = () => {
@@ -52,6 +58,7 @@ const activate = context => {
5258
log("Connected " + conn);
5359
panel.set(conn);
5460
});
61+
cosExplorerProvider.setAPI(api);
5562
};
5663

5764
const config = Config(workspace);
@@ -144,8 +151,13 @@ const activate = context => {
144151

145152
context.subscriptions.push(
146153
vscode.commands.registerCommand("cos.compile", importCompileExport),
147-
vscode.commands.registerCommand("cos.export", exportAll)
154+
vscode.commands.registerCommand("cos.export", exportAll),
155+
vscode.commands.registerCommand('vscode-cos.explorer.refresh', () => cosExplorerProvider.refresh()),
156+
vscode.commands.registerCommand('cosExplorer.openClass', vscode.window.showTextDocument),
157+
vscode.commands.registerCommand('cosExplorer.openRoutine', vscode.window.showTextDocument),
158+
159+
vscode.workspace.registerTextDocumentContentProvider('cos', cosExplorerProvider)
148160
);
149161
};
150162

151-
module.exports = { activate, deactivate: () => {} };
163+
export async function deactivate() {}

images/InterSystems.svg

Lines changed: 7 additions & 0 deletions
Loading

images/dark/refresh.svg

Lines changed: 1 addition & 0 deletions
Loading

images/light/refresh.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)