diff --git a/config/languages/zql.tmLanguage.json b/config/languages/zql.tmLanguage.json
index 54ad480..5df2490 100644
--- a/config/languages/zql.tmLanguage.json
+++ b/config/languages/zql.tmLanguage.json
@@ -28,12 +28,23 @@
"name": "text.bracketed"
},
{
- "match": "\\b(?i)(class||static|stub|function)\\b",
- "name": "keyword.other.sql"
+ "match": "^\\s*(public|private|root|protected)\\s?+(static\\s*)?+(class|function)\\b",
+ "name": "storage.modifier.zql"
+ },
+ {
+ "match": "\\b(?i)(class|static|stub|published|function|extends|if|then|else|let|optional|token|update|create|yield|set|override|this)\\b",
+ "name": "keyword.basic.zql"
+ },
+ {
+ "match": "\\b(test|case|assert)\\b",
+ "name": "keyword.testing.zql"
},
{
"include": "#comments"
},
+ {
+ "include": "#type-operators"
+ },
{
"captures": {
"1": {
@@ -92,58 +103,12 @@
"name": "meta.alter.sql"
},
{
- "captures": {
- "1": {
- "name": "storage.type.sql"
- },
- "2": {
- "name": "storage.type.sql"
- },
- "3": {
- "name": "constant.numeric.sql"
- },
- "4": {
- "name": "storage.type.sql"
- },
- "5": {
- "name": "constant.numeric.sql"
- },
- "6": {
- "name": "storage.type.sql"
- },
- "7": {
- "name": "constant.numeric.sql"
- },
- "8": {
- "name": "constant.numeric.sql"
- },
- "9": {
- "name": "storage.type.sql"
- },
- "10": {
- "name": "constant.numeric.sql"
- },
- "11": {
- "name": "storage.type.sql"
- },
- "12": {
- "name": "storage.type.sql"
- },
- "13": {
- "name": "storage.type.sql"
- },
- "14": {
- "name": "constant.numeric.sql"
- },
- "15": {
- "name": "storage.type.sql"
- }
- },
- "match": "(?xi)\n\n\t\t\t\t# normal stuff, capture 1\n\t\t\t\t \\b(bigint|bigserial|bit|boolean|box|bytea|cidr|circle|date|double\\sprecision|inet|int|integer|line|lseg|macaddr|money|oid|path|point|polygon|real|serial|smallint|numeric|text)\\b\n\n\t\t\t\t# numeric suffix, capture 2 + 3i\n\t\t\t\t|\\b(bit\\svarying|character\\s(?:varying)?|tinyint|var\\schar|float|interval)\\((\\d+)\\)\n\n\t\t\t\t# optional numeric suffix, capture 4 + 5i\n\t\t\t\t|\\b(char|number|varchar\\d?)\\b(?:\\((\\d+)\\))?\n\n\t\t\t\t# special case, capture 6 + 7i + 8i\n\t\t\t\t|\\b(numeric|decimal)\\b(?:\\((\\d+),(\\d+)\\))?\n\n\t\t\t\t# special case, captures 9, 10i, 11\n\t\t\t\t|\\b(times?)\\b(?:\\((\\d+)\\))?(\\swith(?:out)?\\stime\\szone\\b)?\n\n\t\t\t\t# special case, captures 12, 13, 14i, 15\n\t\t\t\t|\\b(timestamp)(?:(s|tz))?\\b(?:\\((\\d+)\\))?(\\s(with|without)\\stime\\szone\\b)?\n\n\t\t\t"
+ "match": "(boolean|date|numeric|text|xml|file)",
+ "name": "support.class"
},
{
- "match": "(?i:\\b((?:primary|foreign)\\s+key|references|on\\sdelete(\\s+cascade)?|check|constraint)\\b)",
- "name": "storage.modifier.sql"
+ "match": "functions:",
+ "name": "markup.bold"
},
{
"match": "\\b\\d+\\b",
@@ -295,6 +260,108 @@
"repository": {
"comments": {
"patterns": [
+ {
+ "name": "meta.return.type.colon.zql",
+ "begin": ":\\s*(\\w*)",
+ "beginCaptures": {
+ "1": {
+ "name": "support.class"
+ }
+ },
+ "end": "\\s"
+ },
+ {
+ "name": "meta.return.value.equals.zql",
+ "begin": "=\\s*(\\w*)",
+ "beginCaptures": {
+ "1": {
+ "name": "support.variable"
+ }
+ },
+ "end": "\\n"
+ },
+ {
+ "name": "section.instances",
+ "begin": "instances:\\s*",
+ "end": "\\n",
+ "beginCaptures": {
+ "0": {
+ "name": "markup.bold"
+ }
+ },
+ "patterns": [
+ {
+ "match": "\\s*(\\w*)\\s*,\\s*(\\d*\\$\\d*)\\s*",
+ "captures": {
+ "1": {
+ "name": "support.variable"
+ },
+ "2": {
+ "name": "markup.italic"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "section.attributes",
+ "begin": "attributes:\\s*",
+ "end": "\\n",
+ "beginCaptures": {
+ "0": {
+ "name": "markup.bold"
+ }
+ },
+ "patterns": [
+ {
+ "match": "\\s*(\\w*)\\s*,\\s*(\\d*\\$\\d*)\\s*:\\s*(\\w*)\\s*",
+ "captures": {
+ "1": {
+ "name": "support.variable"
+ },
+ "2": {
+ "name": "markup.italic"
+ },
+ "3": {
+ "name": "support.class"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "section.relationships",
+ "begin": "relationships:\\s*",
+ "end": "\\n",
+ "beginCaptures": {
+ "0": {
+ "name": "markup.bold"
+ }
+ },
+ "patterns": [
+ {
+ "match": "\\s*(\\w*)\\s*,\\s*(\\d*\\$\\d*)\\s*",
+ "captures": {
+ "1": {
+ "name": "support.variable"
+ },
+ "2": {
+ "name": "markup.italic"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "begin": "//",
+ "beginCaptures": {
+ "0": {
+ "name": "punctuation.definition.comment.zql"
+ }
+ },
+ "end": "\\n",
+ "name": "comment.line.double-slash.zql"
+ },
{
"begin": "(^[ \\t]+)?(?=--)",
"beginCaptures": {
@@ -334,7 +401,7 @@
}
},
"end": "\\*/",
- "name": "comment.block.c"
+ "name": "comment.block.zql"
}
]
},
diff --git a/icons/decorations/class.png b/icons/decorations/class.png
new file mode 100644
index 0000000..7c27392
Binary files /dev/null and b/icons/decorations/class.png differ
diff --git a/icons/decorations/class.svg b/icons/decorations/class.svg
new file mode 100755
index 0000000..447a0f0
--- /dev/null
+++ b/icons/decorations/class.svg
@@ -0,0 +1,106 @@
+
+
+
+
diff --git a/package.json b/package.json
index fcc464b..ab92a2d 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,7 @@
"displayName": "Mocha for VSCode",
"description": "Tools for working with the Mocha Advanced Database Infrastructure platform",
"version": "0.0.1",
+ "publisher": "mochapowered",
"engines": {
"vscode": "^1.92.0"
},
@@ -18,6 +19,11 @@
"title": "",
"category": "Mocha"
},
+ {
+ "command": "mocha.suvmanager.suv_select",
+ "title": "Select Preferred SUV",
+ "category": "Mocha"
+ },
{
"command": "mocha.suvmanager.suv_manager",
"title": "Manage SUVs",
@@ -70,17 +76,17 @@
"category": "Mocha"
},
{
- "command": "mocha.publish_zq_stub_with_implementation",
+ "command": "mocha.zq_publish_stub_with_implementation",
"title": "Publish as ZQ stub and upload implementation",
"category": "Mocha"
},
{
- "command": "mocha.publish_zq_stub",
+ "command": "mocha.zq_publish_stub",
"title": "Publish as ZQ stub method",
"category": "Mocha"
},
{
- "command": "mocha.import_function_implementation_from_zq",
+ "command": "mocha.zq_import_function_implementation",
"title": "Import Function Implementation from ZQ",
"category": "Mocha"
},
@@ -97,13 +103,33 @@
{
"command": "mocha.zq_open_document",
"title": "Open ZQ Document",
- "enablement": "never",
"category": "Mocha"
},
{
"command": "mocha.zq_import_function_signature",
"title": "Import ZQ Function Signature",
"category": "Mocha"
+ },
+
+ {
+ "command": "mocha.moduleExplorer.module_import_zq_implementation",
+ "title": "Import ZQ Implementation",
+ "category": "Mocha"
+ },
+ {
+ "command": "mocha.moduleExplorer.module_show_in_web",
+ "title": "Show in Web Browser",
+ "category": "Mocha"
+ },
+ {
+ "command": "mocha.moduleExplorer.module_copy_text",
+ "title": "Copy Text",
+ "category": "Mocha"
+ },
+ {
+ "command": "mocha.moduleExplorer.module_copy_instance_id",
+ "title": "Copy Instance ID",
+ "category": "Mocha"
}
],
"keybindings": [
@@ -180,8 +206,35 @@
],
"view/item/context": [
{
- "command": "mocha.suvmanager.suv_show",
+ "command": "mocha.moduleExplorer.module_import_zq_implementation",
"group": "0_view@1",
+ "when": "view == mocha.moduleExplorer"
+ },
+ {
+ "command": "mocha.moduleExplorer.module_show_in_web",
+ "group": "0_view@2",
+ "when": "view == mocha.moduleExplorer"
+ },
+ {
+ "command": "mocha.moduleExplorer.module_copy_text",
+ "group": "1_copy@1",
+ "when": "view == mocha.moduleExplorer"
+ },
+ {
+ "command": "mocha.moduleExplorer.module_copy_instance_id",
+ "group": "1_copy@2",
+ "when": "view == mocha.moduleExplorer"
+ },
+
+
+ {
+ "command": "mocha.suvmanager.suv_select",
+ "group": "0_view@1",
+ "when": "view == mocha.suvManager"
+ },
+ {
+ "command": "mocha.suvmanager.suv_show",
+ "group": "0_view@2",
"when": "view == mocha.suvManager"
},
{
diff --git a/src/StringExtensions.ts b/src/StringExtensions.ts
new file mode 100644
index 0000000..6d4199d
--- /dev/null
+++ b/src/StringExtensions.ts
@@ -0,0 +1,71 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+export class IndexOfAnyResult {
+
+
+ private _Index : number;
+ public get Index() : number {
+ return this._Index;
+ }
+ public set Index(v : number) {
+ this._Index = v;
+ }
+
+
+ private _Needle : string;
+ public get Needle() : string {
+ return this._Needle;
+ }
+ public set Needle(v : string) {
+ this._Needle = v;
+ }
+
+ constructor(index: number, needle: string) {
+ this._Index = index;
+ this._Needle = needle;
+ }
+}
+
+export class StringExtensions {
+
+ static indexOfAny(line: string, needle: string[], position?: number): number {
+ let idx: number = -1;
+ for (var i = 0; i < needle.length; i++) {
+ let idx2: number = line.indexOf(needle[i], position);
+ if (idx2 > -1 && (idx2 < idx || idx === -1)) {
+ idx = idx2;
+ }
+ }
+ return idx;
+ }
+
+ static indexOfAnyEx(line: string, needle: string[], position?: number): IndexOfAnyResult {
+ let idx: number = -1;
+ let realNeedle: string = "";
+
+ for (var i = 0; i < needle.length; i++) {
+ let idx2: number = line.indexOf(needle[i], position);
+ if (idx2 > -1 && (idx2 < idx || idx === -1)) {
+ idx = idx2;
+ realNeedle = needle[i];
+ }
+ }
+ return new IndexOfAnyResult(idx, realNeedle);
+ }
+
+}
\ No newline at end of file
diff --git a/src/extension.ts b/src/extension.ts
index c888f52..2c56b3e 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -4,7 +4,7 @@ import * as vscode from 'vscode';
import { GenericTreeDataProvider } from './tdp/GenericTreeDataProvider';
import { GenericTreeDataItem } from './tdp/GenericTreeDataItem';
-import { ModuleExplorerTreeDataProvider } from './ModuleExplorerTreeDataProvider';
+import { ModuleExplorerTreeDataProvider } from './moduleExplorer/ModuleExplorerTreeDataProvider';
import { userInfo } from 'os';
import { Machine } from './Machine';
@@ -14,11 +14,38 @@ import { SuvManagerTreeDataProvider } from './suvManager/SuvManagerTreeDataProvi
import * as path from 'path';
import https from 'node:https';
+import { stat } from 'node:fs';
+import { ZqGenerator } from './zq/ZqGenerator';
+import { ZqFunctionDefinition } from './zq/ZqFunctionDefinition';
+import { ZqClass } from './zq/ZqClass';
+import { InstanceKey } from './mocha/core/InstanceKey';
+import { ZqAttribute } from './zq/ZqAttribute';
+import { ZqRelationship } from './zq/ZqRelationship';
+import { ZqInstance } from './zq/ZqInstance';
+import { ZqInstanceReference } from './zq/ZqInstanceReference';
+import { ZqObject } from './zq/ZqObject';
+import { ZqParser } from './zq/parser/ZqParser';
const cp = require('child_process');
+const extension = vscode.extensions.getExtension('mochapowered.mocha-vscode');
+
let dpModuleExplorer = new ModuleExplorerTreeDataProvider();
let treeSuvManager: vscode.TreeView | undefined = undefined;
+let currentSuvId: string | null = null;
+let statusBarItem : vscode.StatusBarItem | undefined = undefined;
+const updateStatusBarText = () => {
+ if (statusBarItem !== undefined) { statusBarItem.text = `$(server-environment) ${currentSuvId || "(none)"}`; }
+}
+const updateStatusBarItemVisibility = () => {
+ let showStatusbar: boolean = true;
+ if (statusBarItem !== undefined) { showStatusbar ? statusBarItem.show() : statusBarItem.hide(); }
+}
+
+export function getCurrentSuvId() {
+ return currentSuvId;
+}
+
// register the decoration provider
vscode.window.registerFileDecorationProvider(new SuvManagerTreeDecorationProvider());
@@ -31,6 +58,7 @@ export function mkotsuri(suvId : string, tenantName : string, command : string,
function updateModuleExplorerTreeView() {
+ /*
dpModuleExplorer.items.push(new GenericTreeDataItem("tools", "tools", [
new GenericTreeDataItem("tools:xpresso", "xpressO", [
new GenericTreeDataItem("tools:xpressO:method", "method", [
@@ -53,28 +81,28 @@ function updateModuleExplorerTreeView() {
}
));
return;
+ */
- let suvId : string = "i-0c0398f84acecb702";
- let tenantName : string = "super";
- let otsuri = mkotsuri(suvId, tenantName, "module/list");
+ let suvId: string | null = getCurrentSuvId();
+ if (suvId !== null) {
+ let tenantName: string = "super";
+ let otsuri = mkotsuri(suvId, tenantName, "module/list");
- cp.exec("curl " + otsuri.toString(), (err: string, stdout: string, stderr: string) =>
- {
- if (err != "")
- {
- vscode.window.showErrorMessage(err);
- }
- let json = JSON.parse(stdout);
- for (var i = 0; i < json.items.length; i++)
- {
- recursiveAddItemToTreeView(dpModuleExplorer, json.items[i], null);
- }
+ cp.exec("curl " + otsuri.toString(), (err: string, stdout: string, stderr: string) => {
+ if (err !== "") {
+ vscode.window.showErrorMessage(err);
+ }
+ let json = JSON.parse(stdout);
+ for (var i = 0; i < json.items.length; i++) {
+ recursiveAddItemToTreeView(dpModuleExplorer, json.items[i], null);
+ }
- dpModuleExplorer.refresh();
+ dpModuleExplorer.refresh();
- //let treeModuleExplorer = vscode.window.createTreeView("mocha.moduleExplorer", { "canSelectMany": true, "showCollapseAll": true, "treeDataProvider": dpModuleExplorer });
- //console.log(stdout);
- });
+ //let treeModuleExplorer = vscode.window.createTreeView("mocha.moduleExplorer", { "canSelectMany": true, "showCollapseAll": true, "treeDataProvider": dpModuleExplorer });
+ //console.log(stdout);
+ });
+ }
}
function recursiveAddItemToTreeView(dp : GenericTreeDataProvider, item : any, parent : GenericTreeDataItem | null)
@@ -88,6 +116,7 @@ function recursiveAddItemToTreeView(dp : GenericTreeDataProvider, item : any, pa
{
p = new GenericTreeDataItem(item.name, item.title, undefined, { "type": item.type });
}
+ p.description = item.instanceId;
if (item.items)
{
for (var i = 0; i < item.items.length; i++)
@@ -117,6 +146,79 @@ function launchSuv(name : string)
let outputChannel: vscode.OutputChannel | undefined = undefined;
+const options = {
+ borderWidth: '1px',
+ borderStyle: 'solid',
+ overviewRulerColor: 'blue',
+
+ overviewRulerLane: vscode.OverviewRulerLane.Right,
+ light: {
+ // this color will be used in light color themes
+ borderColor: 'darkblue',
+ contentIconPath: extension?.extensionPath + '/icons/light/explorer/class.svg'
+
+ },
+ dark: {
+ // this color will be used in dark color themes
+ borderColor: 'lightblue',
+ contentIconPath: extension?.extensionPath + '/icons/dark/explorer/class.svg'
+ }
+}
+const classDecorationType = vscode.window.createTextEditorDecorationType({
+ before:
+ {
+ contentIconPath: extension?.extensionPath + '/icons/decorations/class.svg',
+ margin: "2px 2px 0px 2px"
+ }
+});
+
+function openEditorForInstance(filename: string, instanceId: string)
+{
+ let tdi = vscode.workspace.openTextDocument(vscode.Uri.file(path.join(userInfo().homedir, filename + ".zql") ).with({ scheme: "untitled" })).then( (doc) =>
+ {
+ vscode.window.showTextDocument(doc).then((editor) =>
+ {
+ editor.edit(edit => {
+ // let zq = new ZqGenerator();
+ let clz = new ZqClass();
+ clz.name = filename.replaceAll(' ', '').replaceAll('-', '_');
+ clz.instanceKey = InstanceKey.parse(instanceId);
+ clz.attributes = [
+ new ZqAttribute("name", InstanceKey.parse("4$1"), "text"),
+ new ZqAttribute("order", InstanceKey.parse("4$1"), "text")
+ ];
+ clz.relationships = [
+ new ZqRelationship("snapshotsSystemName", InstanceKey.parse("3$61051"))
+ ];
+
+ clz.functions = [
+ new ZqFunctionDefinition(),
+ new ZqFunctionDefinition()
+ ];
+ clz.functions[0].name = "getMethodAccessPublicInstance";
+ clz.functions[0].isStatic = true;
+ clz.functions[0].returnDataType = "AccessModifier";
+ clz.functions[0].returnValue = "Public";
+
+ clz.functions[1].name = "getMostRestrictiveFromSet";
+ clz.functions[1].isStatic = true;
+ clz.functions[1].isStub = true;
+ clz.functions[1].returnDataType = "AccessModifier";
+ clz.functions[1].returnValue = "Public";
+
+ clz.instances = [
+ new ZqInstanceReference("Public", InstanceKey.parse("934$102"))
+ ];
+
+ edit.delete(new vscode.Range(new vscode.Position(0, 0), new vscode.Position(editor.document.lineCount - 1, editor.document.lineAt(editor.document.lineCount - 1).range.end.character)));
+ edit.insert(new vscode.Position(0, 0), clz.toString());
+ }).then(success => {
+ updateZqEditor(editor);
+ });
+ });
+ });
+}
+
export function openWebBrowser(url: vscode.Uri) {
cp.exec("xdg-open " + url.toString(), (err: string, stdout: string, stderr: string) => {
@@ -134,7 +236,6 @@ export function activate(context: vscode.ExtensionContext) {
treeSuvManager = vscode.window.createTreeView("mocha.suvManager", { "canSelectMany": true, "showCollapseAll": true, "treeDataProvider": treeDataProvider });
treeDataProvider.treeview = treeSuvManager;
treeSuvManager.badge = { "value": 1, "tooltip": "1 SUV(s) running" };
-
let treeModuleExplorer = vscode.window.createTreeView("mocha.moduleExplorer", { "canSelectMany": true, "showCollapseAll": true, "treeDataProvider": dpModuleExplorer });
@@ -153,7 +254,36 @@ export function activate(context: vscode.ExtensionContext) {
let list = stdout.trim().split('\n');
console.log(list[0]);
});
- });
+ });
+
+ vscode.commands.registerCommand("mocha.suvmanager.suv_copy_id", (item: Machine) => {
+ if (item.name !== undefined) {
+ vscode.env.clipboard.writeText(item.name);
+ }
+ });
+
+ vscode.commands.registerCommand("mocha.zq_import_function_implementation", () => {
+
+ let ed = vscode.window.activeTextEditor;
+ if (ed !== undefined) {
+ if (ed.document.languageId === 'zql') {
+
+ // thanks https://stackoverflow.com/questions/68342626
+ const selection = ed.selection;
+ const currentLineRange = ed.document.lineAt(selection.active.line).range;
+ const line: string = ed.document.getText(currentLineRange).trim();
+
+ let c = ZqParser.parse("class Relationship, 1$3 {\n\nattributes:\n name, 4$1 : text\n order, 4$8 : text\n\nrelationships:\n snapshotsBySystemTarget, 3$418926\n\ninstances:\n testRel, 3$112842\n}");
+
+ let decl = ZqParser.parse(line);
+ if (decl !== null) {
+ (decl as ZqFunctionDefinition).isStub = false;
+
+ ed.edit(edit => edit.replace(currentLineRange, decl.toString()));
+ }
+ }
+ }
+ });
let cmd_zq_import_function_signature = vscode.commands.registerCommand("mocha.zq_import_function_signature", () => {
/*s
@@ -206,7 +336,14 @@ export function activate(context: vscode.ExtensionContext) {
var qqq = ppp[1].replaceAll(" ", "").replaceAll(".", "");
var xxx = qqq.substring(0, qqq.indexOf('('));
- edit.insert(ed.selection.active, "static stub function " + xxx + "() : AccessModifier");
+ let spct: number = ed.selection.start.character;
+ edit.insert(ed.selection.active, "/**\n" + indentLines(spct, [
+ " formerly known as: " + choice,
+ "",
+ " @return the Public access modifier",
+ " */",
+ "static stub function " + xxx + "() : AccessModifier = Public"
+ ]));
}
}
@@ -217,25 +354,16 @@ export function activate(context: vscode.ExtensionContext) {
});
- let cmd_mocha_open_doc = vscode.commands.registerCommand("mocha.zq_open_document", (item : GenericTreeDataItem) => {
-
- console.log(item.name);
-
- if (item.customAttributes["instanceId"])
- {
- let tdi = vscode.workspace.openTextDocument(vscode.Uri.file(path.join(userInfo().homedir, item.title + ".zql") ).with({ scheme: "untitled" })).then( (doc) =>
- {
- vscode.window.showTextDocument(doc).then((editor) =>
- {
- editor.edit(edit => {
- edit.delete(new vscode.Range(new vscode.Position(0, 0), new vscode.Position(editor.document.lineCount - 1, editor.document.lineAt(editor.document.lineCount-1).range.end.character)))
-
- edit.insert(new vscode.Position(0, 0), "class " + item.title + ", " + item.customAttributes["instanceId"] + " {\n\nattributes:\n name: 4$1 : text\n order, 4$7 : text\n\nrelationships:\n forMetadataWithAccessModifier, 3$11854\n\nfunctions:\n\ninstances:\n Public, 4170$1\n}");
- });
- });
- });
+ vscode.commands.registerCommand("mocha.moduleExplorer.module_import_zq_implementation", (item: GenericTreeDataItem) => {
+ if (item.customAttributes["instanceId"]) {
+ openEditorForInstance(item.title, item.customAttributes["instanceId"]);
}
+ });
+ let cmd_mocha_open_doc = vscode.commands.registerCommand("mocha.zq_open_document", (item : GenericTreeDataItem) => {
+ if (item.customAttributes["instanceId"]) {
+ openEditorForInstance(item.title, item.customAttributes["instanceId"]);
+ }
});
// The command has been defined in the package.json file
@@ -306,6 +434,46 @@ export function activate(context: vscode.ExtensionContext) {
launchSuv(machine.name);
}
});
+
+ statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 10);
+ statusBarItem.name = "Mocha SUV Manager";
+ statusBarItem.tooltip = "Choose preferred SUV";
+ statusBarItem.command = "mocha.suvmanager.suv_select";
+ // statusBarItem.setText = text => statusBarItem.text = `$(currentSuvId) ${currentSuvId || "(none)"}`;
+ // statusBarItem.setText();
+
+ updateStatusBarText();
+ updateStatusBarItemVisibility();
+
+ let cmd_suv_select = vscode.commands.registerCommand('mocha.suvmanager.suv_select', (...args) => {
+ if (args.length === 0) {
+ cp.exec('mocha suv list', (err: string, stdout: string, stderr: string) => {
+
+
+ vscode.window.showInformationMessage(stdout);
+ let list = stdout.split('\n');
+ let list2 = new Array();
+ list.forEach((element) => {
+ if (element.trim() === "") {
+ return;
+ }
+
+ list2.push(element.trim());
+ });
+
+ var w = vscode.window.showQuickPick(list2, { "title": "Select Preferred SUV", "placeHolder": "Choose your preferred SUV" }).then((value) => {
+ if (value !== undefined) {
+ selectPreferredSuv(value);
+ }
+ });
+ });
+ }
+ else
+ {
+ let machine : Machine = args[0] as Machine;
+ selectPreferredSuv(machine.name);
+ }
+ });
let cmd_suv_new = vscode.commands.registerCommand('mocha.suvmanager.suv_new', () => {
outputChannel?.appendLine("Provisioning a new persistent SUV...");
@@ -330,11 +498,70 @@ export function activate(context: vscode.ExtensionContext) {
});
});
context.subscriptions.push(cmd_suv_up);
+
+ context.subscriptions.push(vscode.window.onDidChangeTextEditorSelection((e) => {
+ if (e.textEditor.document.languageId === "zql") {
+ let clz = ZqParser.parse(e.textEditor.document.getText()) as ZqClass;
+ if (clz !== null)
+ {
+ clz.relationships.forEach(rel => {
+
+
+
+ });
+
+ }
+ }
+ }));
+
+ context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor((editor) => {
+ if (editor?.document !== undefined) {
+ updateZqEditor(editor);
+ }
+ }));
+}
+
+function updateZqEditor(editor: vscode.TextEditor) {
+ if (editor?.document.languageId !== 'zql') {
+ return;
+ }
+
+ if (editor?.document.getText().startsWith("class ")) {
+ addClassDecoration(editor);
+ }
+}
+
+function addClassDecoration(editor : vscode.TextEditor) {
+ const decorations: vscode.DecorationOptions[] = [];
+ const myContent = new vscode.MarkdownString(editor?.document.fileName + '\n[Open in Mocha](command:myCommand?arg1)');
+ myContent.isTrusted = true;
+
+ const decoration = { range: new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 0)), hoverMessage: myContent };
+
+ decorations.push(decoration);
+ editor.setDecorations(classDecorationType, decorations);
}
// This method is called when your extension is deactivated
export function deactivate() {}
+
+export function selectPreferredSuv(value: string) {
+ currentSuvId = value;
+ updateStatusBarText();
+
+ updateModuleExplorerTreeView();
+}
+
+function indentLines(count: number, lines: string[]): string {
+ let indent: string = " ".repeat(count);
+ let retval: string = "";
+ lines.forEach(line => {
+ retval += indent + line + "\n";
+ });
+ retval += indent;
+ return retval;
+}
/*
// This method is called when your extension is activated
diff --git a/src/mocha/core/InstanceKey.ts b/src/mocha/core/InstanceKey.ts
new file mode 100644
index 0000000..a092371
--- /dev/null
+++ b/src/mocha/core/InstanceKey.ts
@@ -0,0 +1,53 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+export class InstanceKey {
+
+ static parse(value : string): InstanceKey | null {
+ let p = value.split('$', 2);
+ if (p.length === 2) {
+ let ik = new InstanceKey(parseInt(p[0]), parseInt(p[1]));
+ return ik;
+ }
+ return null;
+ }
+
+ private _ClassIndex : number;
+ public get ClassIndex() : number {
+ return this._ClassIndex;
+ }
+ public set ClassIndex(v : number) {
+ this._ClassIndex = v;
+ }
+
+ private _InstanceIndex : number;
+ public get InstanceIndex() : number {
+ return this._InstanceIndex;
+ }
+ public set InstanceIndex(v : number) {
+ this._InstanceIndex = v;
+ }
+
+ toString(): string {
+ return this.ClassIndex + "$" + this.InstanceIndex;
+ }
+
+ constructor(classIndex: number, instanceIndex: number) {
+ this._ClassIndex = classIndex;
+ this._InstanceIndex = instanceIndex;
+ }
+}
\ No newline at end of file
diff --git a/src/ModuleExplorerTreeDataProvider.ts b/src/moduleExplorer/ModuleExplorerTreeDataProvider.ts
similarity index 84%
rename from src/ModuleExplorerTreeDataProvider.ts
rename to src/moduleExplorer/ModuleExplorerTreeDataProvider.ts
index b558be0..544653c 100644
--- a/src/ModuleExplorerTreeDataProvider.ts
+++ b/src/moduleExplorer/ModuleExplorerTreeDataProvider.ts
@@ -2,9 +2,9 @@ import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
-import { GenericTreeDataItem } from './tdp/GenericTreeDataItem';
+import { GenericTreeDataItem } from '../tdp/GenericTreeDataItem';
import { Uri } from 'vscode';
-import { GenericTreeDataProvider } from './tdp/GenericTreeDataProvider';
+import { GenericTreeDataProvider } from '../tdp/GenericTreeDataProvider';
export class ModuleExplorerTreeDataProvider extends GenericTreeDataProvider {
diff --git a/src/tdp/GenericTreeDataItem.ts b/src/tdp/GenericTreeDataItem.ts
index f014448..9ab589f 100644
--- a/src/tdp/GenericTreeDataItem.ts
+++ b/src/tdp/GenericTreeDataItem.ts
@@ -34,6 +34,14 @@ export class GenericTreeDataItem
public set title(v : string) {
this._title = v;
}
+
+ private _description : string = "";
+ public get description() : string {
+ return this._description;
+ }
+ public set description(v : string) {
+ this._description = v;
+ }
private _customAttributes? : Dictionary;
public get customAttributes() : Dictionary {
diff --git a/src/tdp/GenericTreeDataProvider.ts b/src/tdp/GenericTreeDataProvider.ts
index 324c98f..2df47f6 100644
--- a/src/tdp/GenericTreeDataProvider.ts
+++ b/src/tdp/GenericTreeDataProvider.ts
@@ -44,8 +44,9 @@ export class GenericTreeDataProvider implements vscode.TreeDataProvider
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+import { InstanceKey } from "../mocha/core/InstanceKey";
+import { ZqInstance } from "./ZqInstance";
+
+export class ZqAttribute extends ZqInstance {
+
+ private _dataType : string | null;
+ public get dataType() : string | null {
+ return this._dataType;
+ }
+ public set dataType(v : string | null) {
+ this._dataType = v;
+ }
+
+ constructor(name: string, instanceKey: InstanceKey | null, dataType: string | null) {
+ super();
+
+ this.name = name;
+ this.instanceKey = instanceKey;
+ this._dataType = dataType;
+ }
+
+ toString(): string {
+
+ let s: string = "";
+ s += this.name;
+
+ if (this.instanceKey !== null) {
+ s += ", " + this.instanceKey.toString();
+ }
+ if (this.dataType !== null) {
+ s += ": " + this.dataType;
+ }
+ return s;
+ }
+
+}
\ No newline at end of file
diff --git a/src/zq/ZqClass.ts b/src/zq/ZqClass.ts
new file mode 100644
index 0000000..d6952b8
--- /dev/null
+++ b/src/zq/ZqClass.ts
@@ -0,0 +1,84 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+import { ZqInstance } from "./ZqInstance";
+
+export class ZqClass extends ZqInstance {
+
+ toString(): string {
+
+ let r = "";
+ r += "class " + this.name;
+ if (this.instanceKey !== null) {
+ r += ", " + this.instanceKey.toString();
+ }
+ r += " {\n";
+ r += "\n";
+
+ r += "attributes:\n";
+ if (this.attributes.length > 0) {
+ this.attributes.forEach(attr => {
+ r += " " + attr.name;
+ if (attr.instanceKey !== null) {
+ r += ", " + attr.instanceKey.toString();
+ }
+ if (attr.dataType !== null) {
+ r += ": " + attr.dataType;
+ }
+ r += "\n";
+ });
+ }
+ r += "\n";
+
+ r += "relationships:\n";
+ if (this.relationships.length > 0) {
+ this.relationships.forEach(rel => {
+ r += " " + rel.name;
+ if (rel.instanceKey !== null) {
+ r += ", " + rel.instanceKey.toString();
+ }
+ r += "\n";
+ });
+ }
+ r += "\n";
+
+ r += "functions:\n";
+ if (this.functions.length > 0) {
+ this.functions.forEach(func => {
+ r += func.toString();
+ r += "\n";
+ });
+ }
+ r += "\n";
+
+ r += "instances:\n";
+ if (this.instances.length > 0) {
+ this.instances.forEach(inst => {
+ r += " " + inst.name;
+ if (inst.instanceKey !== null) {
+ r += ", " + inst.instanceKey.toString();
+ }
+ r += "\n";
+ });
+ }
+ r += "\n";
+ r += "}\n";
+ return r;
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/zq/ZqDocumentLinkProvider.ts b/src/zq/ZqDocumentLinkProvider.ts
new file mode 100644
index 0000000..1c0fed5
--- /dev/null
+++ b/src/zq/ZqDocumentLinkProvider.ts
@@ -0,0 +1,21 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+class ZqDocumentLinkProvider
+{
+
+}
\ No newline at end of file
diff --git a/src/zq/ZqFunctionDefinition.ts b/src/zq/ZqFunctionDefinition.ts
new file mode 100644
index 0000000..8e31c28
--- /dev/null
+++ b/src/zq/ZqFunctionDefinition.ts
@@ -0,0 +1,88 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+import { ZqObject } from "./ZqObject";
+
+export class ZqFunctionDefinition extends ZqObject {
+
+ private _isPublished : boolean = false;
+ public get isPublished() : boolean {
+ return this._isPublished;
+ }
+ public set isPublished(v : boolean) {
+ this._isPublished = v;
+ }
+
+ private _isStatic : boolean = false;
+ public get isStatic() : boolean {
+ return this._isStatic;
+ }
+ public set isStatic(v : boolean) {
+ this._isStatic = v;
+ }
+
+ private _isStub: boolean = false;
+ public get isStub() : boolean {
+ return this._isStub;
+ }
+ public set isStub(v : boolean) {
+ this._isStub = v;
+ }
+
+
+ private _returnValue : string | undefined;
+ public get returnValue() : string | undefined {
+ return this._returnValue;
+ }
+ public set returnValue(v : string | undefined) {
+ this._returnValue = v;
+ }
+
+ private _returnDataType : string | undefined;
+ public get returnDataType() : string | undefined {
+ return this._returnDataType;
+ }
+ public set returnDataType(v : string | undefined) {
+ this._returnDataType = v;
+ }
+
+
+ toString(): string {
+ let r = "";
+
+ if (this.isPublished) {
+ r += "published ";
+ }
+ if (this.isStatic) {
+ r += "static ";
+ }
+ if (this.isStub) {
+ r += "stub ";
+ }
+ r += "function " + this.name + "(";
+ r += ")";
+ if (this.returnDataType !== undefined) {
+ r += " : " + this.returnDataType;
+ }
+ if (this.returnValue !== undefined) {
+ r += " = " + this.returnValue;
+ }
+ return r;
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/zq/ZqGenerator.ts b/src/zq/ZqGenerator.ts
new file mode 100644
index 0000000..5c02576
--- /dev/null
+++ b/src/zq/ZqGenerator.ts
@@ -0,0 +1,30 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+export class ZqGenerator
+{
+ generateClass(title : string, instanceId : string, attributes : string[]) : string
+ {
+ let retval: string = "class " + title.replaceAll(' ', '').replaceAll('-', '_') + ", " + instanceId + " {\n\n";
+ retval += "attributes: \n name, 4$1: text\n order, 4$7: text\n\nrelationships: \n forMetadataWithAccessModifier, 3$11854\n\n" +
+ "functions: \n static function getMethodAccessPublicInstance() : AccessModifier = Public\n" +
+ " static stub function getMostRestrictiveFromSet(accessModifier_Nonsingular_ : AccessModifier*) : AccessModifier = Public\n" +
+ "\ninstances: \n Public, 4170$1\n" +
+ "\n}";
+ return retval;
+ }
+}
\ No newline at end of file
diff --git a/src/zq/ZqInstance.ts b/src/zq/ZqInstance.ts
new file mode 100644
index 0000000..30af9e3
--- /dev/null
+++ b/src/zq/ZqInstance.ts
@@ -0,0 +1,71 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+import { InstanceKey } from "../mocha/core/InstanceKey";
+import { ZqFunctionDefinition } from "./ZqFunctionDefinition";
+import { ZqAttribute } from "./ZqAttribute";
+import { ZqInstanceReference } from "./ZqInstanceReference";
+import { ZqObject } from "./ZqObject";
+import { ZqRelationship } from "./ZqRelationship";
+
+export class ZqInstance extends ZqObject {
+
+
+ private _instanceKey: InstanceKey | null = null;
+ public get instanceKey() : InstanceKey | null {
+ return this._instanceKey;
+ }
+ public set instanceKey(v : InstanceKey | null) {
+ this._instanceKey = v;
+ }
+
+ private _attributes : ZqAttribute[] = [ ];
+ public get attributes() : ZqAttribute[] {
+ return this._attributes;
+ }
+ public set attributes(v : ZqAttribute[]) {
+ this._attributes = v;
+ }
+
+
+ private _relationships : ZqRelationship[] = [ ];
+ public get relationships() : ZqRelationship[] {
+ return this._relationships;
+ }
+ public set relationships(v : ZqRelationship[]) {
+ this._relationships = v;
+ }
+
+ private _functions : ZqFunctionDefinition[] = [ ];
+ public get functions() : ZqFunctionDefinition[] {
+ return this._functions;
+ }
+ public set functions(v : ZqFunctionDefinition[]) {
+ this._functions = v;
+ }
+
+ private _instances : ZqInstanceReference[] = [ ];
+ public get instances() : ZqInstanceReference[] {
+ return this._instances;
+ }
+ public set instances(v : ZqInstanceReference[]) {
+ this._instances = v;
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/src/zq/ZqInstanceReference.ts b/src/zq/ZqInstanceReference.ts
new file mode 100644
index 0000000..a86de40
--- /dev/null
+++ b/src/zq/ZqInstanceReference.ts
@@ -0,0 +1,46 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+import { InstanceKey } from "../mocha/core/InstanceKey";
+import { ZqObject } from "./ZqObject";
+
+export class ZqInstanceReference extends ZqObject {
+
+ private _instanceKey : InstanceKey | null;
+ public get instanceKey() : InstanceKey | null {
+ return this._instanceKey;
+ }
+ public set instanceKey(v : InstanceKey | null) {
+ this._instanceKey = v;
+ }
+
+ constructor(name: string, instanceKey: InstanceKey | null) {
+ super();
+ this.name = name;
+ this._instanceKey = instanceKey;
+ }
+
+ toString(): string {
+
+ let r = "";
+ r += this.name;
+ if (this.instanceKey !== null) {
+ r += ", " + this.instanceKey.toString();
+ }
+ return r;
+ }
+}
\ No newline at end of file
diff --git a/src/zq/ZqObject.ts b/src/zq/ZqObject.ts
new file mode 100644
index 0000000..5f964ec
--- /dev/null
+++ b/src/zq/ZqObject.ts
@@ -0,0 +1,40 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+import { ZqObjectDefinition } from "./ZqObjectDefinition";
+
+export class ZqObject {
+
+ private _name : string = "";
+ public get name() : string {
+ return this._name;
+ }
+ public set name(v : string) {
+ this._name = v;
+ }
+
+
+ private _definition : ZqObjectDefinition = new ZqObjectDefinition(0, 0);
+ public get definition() : ZqObjectDefinition {
+ return this._definition;
+ }
+ public set definition(v : ZqObjectDefinition) {
+ this._definition = v;
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/zq/ZqObjectDefinition.ts b/src/zq/ZqObjectDefinition.ts
new file mode 100644
index 0000000..6e656d7
--- /dev/null
+++ b/src/zq/ZqObjectDefinition.ts
@@ -0,0 +1,42 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+export class ZqObjectDefinition {
+
+
+ private _lineIndex : number = 0;
+ public get lineIndex() : number {
+ return this._lineIndex;
+ }
+ public set lineIndex(v : number) {
+ this._lineIndex = v;
+ }
+
+ private _columnIndex : number = 0;
+ public get columnIndex() : number {
+ return this._columnIndex;
+ }
+ public set columnIndex(v : number) {
+ this._columnIndex = v;
+ }
+
+ constructor(lineIndex: number, columnIndex: number) {
+ this.lineIndex = lineIndex;
+ this.columnIndex = columnIndex;
+ }
+
+}
\ No newline at end of file
diff --git a/src/zq/ZqRelationship.ts b/src/zq/ZqRelationship.ts
new file mode 100644
index 0000000..bbba5cf
--- /dev/null
+++ b/src/zq/ZqRelationship.ts
@@ -0,0 +1,38 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+import { InstanceKey } from "../mocha/core/InstanceKey";
+import { ZqInstanceReference } from "./ZqInstanceReference";
+
+export class ZqRelationship extends ZqInstanceReference {
+
+ constructor(name: string, instanceKey: InstanceKey | null) {
+ super(name, instanceKey);
+ }
+
+ toString(): string {
+
+ let s: string = "";
+ s += this.name;
+
+ if (this.instanceKey !== null) {
+ s += ", " + this.instanceKey.toString();
+ }
+ return s;
+ }
+
+}
\ No newline at end of file
diff --git a/src/zq/parser/ZqParser.ts b/src/zq/parser/ZqParser.ts
new file mode 100644
index 0000000..328b066
--- /dev/null
+++ b/src/zq/parser/ZqParser.ts
@@ -0,0 +1,186 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+import { InstanceKey } from "../../mocha/core/InstanceKey";
+import { StringExtensions } from "../../StringExtensions";
+import { ZqAttribute } from "../ZqAttribute";
+import { ZqClass } from "../ZqClass";
+import { ZqFunctionDefinition } from "../ZqFunctionDefinition";
+import { ZqInstanceReference } from "../ZqInstanceReference";
+import { ZqObject } from "../ZqObject";
+import { ZqRelationship } from "../ZqRelationship";
+import { ZqParserContext } from "./ZqParserContext";
+import { ZqTokenInfo } from "./ZqTokenInfo";
+
+export class ZqParser {
+
+ static parse(line: string): ZqObject {
+
+ let idx: number = 0;
+
+ let insideBlock: boolean = false;
+ let nextStatic: boolean = false;
+ let nextStub: boolean = false;
+ let retval: any = null;
+ let ctx: ZqParserContext = new ZqParserContext(line);
+
+ while (!ctx.endOfStream) {
+ let token: ZqTokenInfo | null = ctx.readToken();
+ if (token !== null) {
+ if (token.value === "{") {
+ insideBlock = true;
+ }
+ else if (token.value === "static") {
+ nextStatic = true;
+ }
+ else if (token.value === "stub") {
+ nextStub = true;
+ }
+ else if (token.value === "class") {
+ let obj = parseClass(line, token.nextStart);
+ return obj;
+ }
+ else if (token.value === "function") {
+ let obj = new ZqFunctionDefinition();
+ let re = new RegExp("(public|private|protected)?\\s*(static)?\\s*(stub)?\\s*(function)\\s*(\\w*)\\s*\\(((\\s*\\w*\\s*\\:\\s*\\w*\\*?\\,?)*)\\)\\s*\\:\\s*(\\w*\\*?)\\s*(?:=\\s*(\\w*))?");
+ let result = re.exec(line);
+
+ let returnDataType = result?.at(8);
+ if (returnDataType !== undefined) {
+ obj.returnDataType = returnDataType;
+ }
+
+ let returnValue = result?.at(9);
+ if (returnValue !== undefined) {
+ obj.returnValue = returnValue;
+ }
+
+ obj.isStatic = nextStatic;
+ obj.isStub = nextStub;
+ obj.name = line.substring(token.nextStart, line.indexOf('(', token.nextStart)).trim();
+ token.nextStart = token.nextStart + obj.name.length + 1;
+ retval = obj;
+ }
+
+ line = line.substring(token.nextStart).trim();
+ // idx = token.NextStart;
+ idx = 0;
+ }
+ }
+ return retval;
+ }
+}
+
+function parseClass(line: string, NextStart: number) {
+ let obj = new ZqClass();
+ let re = new RegExp("class\\s*(\\w*)(?:\\s*,\\s*(\\d*\\$\\d*))?");
+ let result = re.exec(line);
+ if (result !== null) {
+ let r = result.at(0);
+ if (r !== undefined) {
+ let name: string | undefined = result.at(1);
+ let instanceKey: string | undefined = result.at(2);
+ if (name !== undefined) {
+ obj.name = name;
+ }
+ if (instanceKey !== undefined) {
+ obj.instanceKey = InstanceKey.parse(instanceKey);
+ }
+ line = line.substring(r.length).trim();
+ }
+ }
+
+ if (line.startsWith("{") && line.endsWith("}"))
+ {
+ let i: number = 0;
+ let section: string = "";
+ let ctx: ZqParserContext = new ZqParserContext(line.substring(1, line.length - 2).trim());
+
+ while (!ctx.endOfStream) {
+ if (section === "attributes") {
+ let line = ctx.readLine();
+ if (line === '') {
+ section = "";
+ continue;
+ }
+
+ let re = new RegExp("\\s*(\\w*)\\s*(?:,\\s*(\\d*\\$\\d*))\\s*:\\s*(\\w*)\\s*");
+ let result = re.exec(line);
+
+ let name = result?.at(1);
+ let instanceKey = result?.at(2);
+ let dataType = result?.at(3);
+
+ if (name !== undefined && instanceKey !== undefined && dataType !== undefined) {
+ obj.attributes.push(new ZqAttribute(name, InstanceKey.parse(instanceKey), dataType));
+ }
+ }
+ else if (section === "relationships" || section === "instances") {
+ let line = ctx.readLine();
+ if (line === '') {
+ section = "";
+ continue;
+ }
+
+ let re = new RegExp("\\s*(\\w*)\\s*,\\s*(\\d*\\$\\d*)");
+ let result = re.exec(line);
+
+ let name = result?.at(1);
+ let instanceKey = result?.at(2);
+
+ if (name !== undefined) {
+ let instanceKeyObj: InstanceKey | null = null;
+ if (instanceKey !== undefined) {
+ instanceKeyObj = InstanceKey.parse(instanceKey);
+ }
+
+ if (section === "relationships") {
+ let rel = new ZqRelationship(name, instanceKeyObj);
+ rel.definition.columnIndex = ctx.columnIndex;
+ rel.definition.lineIndex = ctx.lineIndex;
+
+ obj.relationships.push(rel);
+ }
+ else if (section === "instances") {
+ obj.instances.push(new ZqInstanceReference(name, instanceKeyObj));
+ }
+ }
+ }
+ else if (section === "") {
+ let tok = ctx.readToken();
+ if (tok !== null) {
+ if (tok.token === ":") {
+ section = tok.value;
+ ctx.readLine();
+ }
+ }
+ }
+ else {
+ // unknown section, let's just skip over it
+ section = "";
+ while (true) {
+ let line = ctx.readLine();
+ if (line === "") {
+ break;
+ }
+ }
+ }
+ }
+ let t = null;
+ }
+ return obj;
+}
diff --git a/src/zq/parser/ZqParserContext.ts b/src/zq/parser/ZqParserContext.ts
new file mode 100644
index 0000000..42fad66
--- /dev/null
+++ b/src/zq/parser/ZqParserContext.ts
@@ -0,0 +1,123 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+import { StringExtensions } from "../../StringExtensions";
+import { ZqTokenInfo } from "./ZqTokenInfo";
+
+export class ZqParserContext {
+ private _value: string = "";
+ public get value(): string {
+ return this._value;
+ }
+
+ private _currentIndex: number = 0;
+ public get currentIndex(): number {
+ return this._currentIndex;
+ }
+
+ public get currentValue(): string {
+ return this.value.substring(this.currentIndex);
+ }
+
+ public get endOfStream(): boolean {
+ return this.currentIndex >= this.value.length;
+ }
+
+ private _lineIndex : number = 0;
+ public get lineIndex() : number {
+ return this._lineIndex;
+ }
+ public set lineIndex(v : number) {
+ this._lineIndex = v;
+ }
+
+ private _columnIndex : number = 0;
+ public get columnIndex() : number {
+ return this._columnIndex;
+ }
+ public set columnIndex(v : number) {
+ this._columnIndex = v;
+ }
+
+ constructor(value: string) {
+ this._value = value;
+ }
+
+ readLine() : string {
+
+ let idxNewline = this._value.indexOf("\n", this._currentIndex);
+ let retval = this._value.substring(this._currentIndex);
+
+ if (idxNewline > -1) {
+ retval = this._value.substring(this._currentIndex, idxNewline);
+ this._currentIndex += retval.length + 1;
+
+ this._lineIndex++;
+ this._columnIndex = 0;
+ }
+ else {
+ this._currentIndex += retval.length;
+
+ this._lineIndex++;
+ this._columnIndex = 0;
+ }
+ return retval;
+ }
+ readChars(count: number) {
+ let before: string = this._value.substring(this._currentIndex, this._currentIndex + count);
+ this._currentIndex += count;
+ return before;
+ }
+
+ readToken(): ZqTokenInfo | null {
+ let end = this._value.length;
+
+ let token = "";
+ let index = StringExtensions.indexOfAnyEx(this._value, [' ', '(', '{', ':'], this._currentIndex);
+ if (index.Index > -1) {
+ token = index.Needle;
+ end = index.Index;
+ }
+
+ let tok : ZqTokenInfo | null = null;
+
+ let val = this._value.substring(this._currentIndex, end);
+ if (val === '' && this._value.length > 0) {
+ tok = new ZqTokenInfo(this._value.substring(this._currentIndex, end + 1), end + 1);
+ } else {
+ tok = new ZqTokenInfo(val, end);
+ }
+ this._currentIndex += val.length + token.length;
+ tok.token = token;
+ return tok;
+ /*
+
+ const id = line.indexOf('function');
+ const id2 = line.indexOf('(', id);
+
+ let name: string = "";
+ if (id > -1) {
+ name = line.substring(id + 'function'.length, id2).trim();
+ }
+
+ return null;
+ */
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/src/zq/parser/ZqTokenInfo.ts b/src/zq/parser/ZqTokenInfo.ts
new file mode 100644
index 0000000..5e0f258
--- /dev/null
+++ b/src/zq/parser/ZqTokenInfo.ts
@@ -0,0 +1,53 @@
+// Copyright (C) 2025 Michael Becker
+//
+// This file is part of mocha-vscode.
+//
+// mocha-vscode is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// mocha-vscode is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with mocha-vscode. If not, see .
+
+export class ZqTokenInfo {
+
+
+ private _value : string;
+ public get value() : string {
+ return this._value;
+ }
+ public set value(v : string) {
+ this._value = v;
+ }
+
+
+ private _token : string = "";
+ public get token() : string {
+ return this._token;
+ }
+ public set token(v : string) {
+ this._token = v;
+ }
+
+
+ private _nextStart : number;
+ public get nextStart() : number {
+ return this._nextStart;
+ }
+ public set nextStart(v : number) {
+ this._nextStart = v;
+ }
+
+ constructor(value: string, nextStart: number) {
+
+ this._value = value;
+ this._nextStart = nextStart;
+ }
+
+}
\ No newline at end of file