diff --git a/src/extension.ts b/src/extension.ts index f0b63e50..36ebce80 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -547,6 +547,51 @@ function proposedApiPrompt(active: boolean, added?: readonly vscode.WorkspaceFol } } +/** + * A map of SystemModes for known servers. + * The key is either `serverName`, or `host:port/pathPrefix`, lowercase. + * The value is the value of `^%SYS("SystemMode")`, uppercase. + */ +const systemModes: Map = new Map(); + +/** Output a message notifying the user of the SystemMode of any servers they are connected to. */ +async function systemModeWarning(wsFolders: readonly vscode.WorkspaceFolder[]): Promise { + if (!wsFolders || wsFolders.length == 0) return; + for (const wsFolder of wsFolders) { + const api = new AtelierAPI(wsFolder.uri), + mapKey = api.serverId.toLowerCase(), + serverUrl = `${api.config.host}:${api.config.port}${api.config.pathPrefix}`, + serverStr = ![undefined, ""].includes(api.config.serverName) + ? `'${api.config.serverName}' (${serverUrl})` + : serverUrl; + if (!api.active) continue; // Skip inactive connections + let systemMode = systemModes.get(mapKey); + if (systemMode == undefined) { + systemMode = await api + .actionQuery("SELECT UPPER(Value) AS SystemMode FROM %Library.Global_Get(?,'^%SYS(\"SystemMode\")')", [api.ns]) + .then((data) => data.result.content[0]?.SystemMode ?? "") + .catch(() => ""); // Swallow any errors, which will likely be SQL permissions errors + } + switch (systemMode) { + case "LIVE": + outputChannel.appendLine( + `WARNING: Workspace folder '${wsFolder.name}' is connected to Live System ${serverStr}` + ); + outputChannel.show(); // Steal focus because this is an important message + break; + case "TEST": + case "FAILOVER": + outputChannel.appendLine( + `NOTE: Workspace folder '${wsFolder.name}' is connected to ${ + systemMode == "TEST" ? "Test" : "Failover" + } System ${serverStr}` + ); + outputChannel.show(true); + } + systemModes.set(mapKey, systemMode); + } +} + /** The URIs of all classes that have been opened. Used when `objectscript.openClassContracted` is true */ let openedClasses: string[]; @@ -747,6 +792,9 @@ export async function activate(context: vscode.ExtensionContext): Promise { // Show the proposed API prompt if required proposedApiPrompt(proposed.length > 0); + // Warn about SystemMode + systemModeWarning(vscode.workspace.workspaceFolders); + iscIcon = vscode.Uri.joinPath(context.extensionUri, "images", "fileIcon.svg"); macLangConf = vscode.languages.setLanguageConfiguration(macLangId, getLanguageConfiguration(macLangId)); @@ -1296,6 +1344,8 @@ export async function activate(context: vscode.ExtensionContext): Promise { vscode.workspace.onDidChangeWorkspaceFolders((e) => { // Show the proposed API prompt if required proposedApiPrompt(proposed.length > 0, e.added); + // Warn about SystemMode + systemModeWarning(e.added); }), vscode.commands.registerCommand("vscode-objectscript.importXMLFiles", importXMLFiles), vscode.commands.registerCommand("vscode-objectscript.exportToXMLFile", exportDocumentsToXMLFile), diff --git a/syntaxes/vscode-objectscript-output.tmLanguage.json b/syntaxes/vscode-objectscript-output.tmLanguage.json index cd352c31..f0f0c01c 100644 --- a/syntaxes/vscode-objectscript-output.tmLanguage.json +++ b/syntaxes/vscode-objectscript-output.tmLanguage.json @@ -78,6 +78,14 @@ { "match": "\\b(?i:(0?x)?[0-9a-f][0-9a-f]+)\\b", "name": "constant.numeric" + }, + { + "match": "^WARNING:", + "name": "invalid" + }, + { + "match": "^NOTE:", + "name": "string.quoted" } ] }