From a6e608e1fc38d095418479e4cb2ace2a52a92526 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Tue, 1 Apr 2025 15:18:32 -0400 Subject: [PATCH] major updates to Mocha/ZQL support for VSCode --- config/languages/zql.tmLanguage.json | 173 +++++++--- icons/decorations/class.png | Bin 0 -> 524 bytes icons/decorations/class.svg | 106 ++++++ package.json | 63 +++- src/StringExtensions.ts | 71 ++++ src/extension.ts | 305 +++++++++++++++--- src/mocha/core/InstanceKey.ts | 53 +++ .../ModuleExplorerTreeDataProvider.ts | 4 +- src/tdp/GenericTreeDataItem.ts | 8 + src/tdp/GenericTreeDataProvider.ts | 3 +- src/zq/ZqAttribute.ts | 53 +++ src/zq/ZqClass.ts | 84 +++++ src/zq/ZqDocumentLinkProvider.ts | 21 ++ src/zq/ZqFunctionDefinition.ts | 88 +++++ src/zq/ZqGenerator.ts | 30 ++ src/zq/ZqInstance.ts | 71 ++++ src/zq/ZqInstanceReference.ts | 46 +++ src/zq/ZqObject.ts | 40 +++ src/zq/ZqObjectDefinition.ts | 42 +++ src/zq/ZqRelationship.ts | 38 +++ src/zq/parser/ZqParser.ts | 186 +++++++++++ src/zq/parser/ZqParserContext.ts | 123 +++++++ src/zq/parser/ZqTokenInfo.ts | 53 +++ 23 files changed, 1561 insertions(+), 100 deletions(-) create mode 100644 icons/decorations/class.png create mode 100755 icons/decorations/class.svg create mode 100644 src/StringExtensions.ts create mode 100644 src/mocha/core/InstanceKey.ts rename src/{ => moduleExplorer}/ModuleExplorerTreeDataProvider.ts (84%) create mode 100644 src/zq/ZqAttribute.ts create mode 100644 src/zq/ZqClass.ts create mode 100644 src/zq/ZqDocumentLinkProvider.ts create mode 100644 src/zq/ZqFunctionDefinition.ts create mode 100644 src/zq/ZqGenerator.ts create mode 100644 src/zq/ZqInstance.ts create mode 100644 src/zq/ZqInstanceReference.ts create mode 100644 src/zq/ZqObject.ts create mode 100644 src/zq/ZqObjectDefinition.ts create mode 100644 src/zq/ZqRelationship.ts create mode 100644 src/zq/parser/ZqParser.ts create mode 100644 src/zq/parser/ZqParserContext.ts create mode 100644 src/zq/parser/ZqTokenInfo.ts 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 0000000000000000000000000000000000000000..7c27392d8c2552d95ccbd6864b6e6f0f65298e57 GIT binary patch literal 524 zcmV+n0`vWeP)LR}r;trz z;UJ;j!*qZr_O)327IP$F%VSf7!As!we;V(i@S)PxeFs3nLL0dbdW~rg(;V2F z2#aGH_eaeUWZxm)#UIRP^rZBuh49w0$ybP`-^Ed8Er9!Iokm zv=6aBV<}&vOt98-^1$CUPJ2q1zcxFFoSy-3eW2D;fGgFg)(YoHQ=nem0uDGnndr&) z-;cvvjXk~!>pYfVL=wzie?pbb^tJ3*&wu=eye&hvi z + + + + + + + + + + + + + + + + + + + + + + + + + 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