From e594a0500174f37d89f925d51ff2401cf49bb96b Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 12:56:46 -0500 Subject: [PATCH 01/46] Refactor tooltip generation by replacing instance methods with direct imports from tools module Signed-off-by: worksofliam --- src/api/IBMiContent.ts | 77 ++----------- src/api/Tools.ts | 141 +----------------------- src/views/LibraryListView.ts | 3 +- src/views/debugView.ts | 9 +- src/views/ifsBrowser.ts | 9 +- src/views/objectBrowser.ts | 11 +- src/views/tools.ts | 207 +++++++++++++++++++++++++++++++++++ 7 files changed, 236 insertions(+), 221 deletions(-) create mode 100644 src/views/tools.ts diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index 8455e5f1c..b01b9d136 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -104,7 +104,7 @@ export default class IBMiContent { * @param encoding Optional encoding to write. */ async writeStreamfileRaw(originalPath: string, content: Uint8Array, encoding?: string) { - const client = this.ibmi.client; + const client = this.ibmi.client!; const features = this.ibmi.remoteFeatures; const tmpobj = await tmpFile(); @@ -212,7 +212,7 @@ export default class IBMiContent { sourceFile = this.ibmi.upperCaseName(sourceFile); member = this.ibmi.upperCaseName(member); - const client = this.ibmi.client; + const client = this.ibmi.client!; const tmpobj = await tmpFile(); let retry = false; @@ -1004,55 +1004,6 @@ export default class IBMiContent { return { valid: !Boolean(missing.length), missing }; } - objectToToolTip(path: string, object: IBMiObject) { - const tooltip = new MarkdownString(Tools.generateTooltipHtmlTable(path, { - "Type": object.type, - "Attribute": object.attribute, - "Text": object.text, - "Size": object.size, - "Created": safeIsoValue(object.created), - "Changed": safeIsoValue(object.changed), - "Created by": object.created_by, - "Owner": object.owner, - "IASP": object.asp - })); - tooltip.supportHtml = true; - return tooltip; - } - - async sourcePhysicalFileToToolTip(path: string, object: IBMiObject) { - const tooltip = new MarkdownString(Tools.generateTooltipHtmlTable(path, { - "Text": object.text, - "Members": await this.countMembers(object), - "Length": object.sourceLength, - "CCSID": (await this.getAttributes(object, "CCSID"))?.CCSID || '?', - "IASP": object.asp - })); - tooltip.supportHtml = true; - return tooltip; - } - - memberToToolTip(path: string, member: IBMiMember) { - const tooltip = new MarkdownString(Tools.generateTooltipHtmlTable(path, { - "Text": member.text, - "Lines": member.lines, - "Created": safeIsoValue(member.created), - "Changed": safeIsoValue(member.changed) - })); - tooltip.supportHtml = true; - return tooltip; - } - - ifsFileToToolTip(path: string, ifsFile: IFSFile) { - const tooltip = new MarkdownString(Tools.generateTooltipHtmlTable(path, { - "Size": ifsFile.size, - "Modified": ifsFile.modified ? safeIsoValue(new Date(ifsFile.modified.getTime() - ifsFile.modified.getTimezoneOffset() * 60 * 1000)) : ``, - "Owner": ifsFile.owner ? ifsFile.owner.toUpperCase() : `` - })); - tooltip.supportHtml = true; - return tooltip; - } - async getSshCcsid() { const sql = ` with SSH_DETAIL (id, iid) as ( @@ -1093,27 +1044,19 @@ export default class IBMiContent { } } - async uploadFiles(files: { local: string | Uri, remote: string }[], options?: node_ssh.SSHPutFilesOptions) { - await this.ibmi.client.putFiles(files.map(f => { return { local: Tools.fileToPath(f.local), remote: f.remote } }), options); + async uploadFiles(files: { local: string, remote: string }[], options?: node_ssh.SSHPutFilesOptions) { + await this.ibmi.client!.putFiles(files.map(f => { return { local: f.local, remote: f.remote } }), options); } - async downloadFile(localFile: string | Uri, remoteFile: string) { - await this.ibmi.client.getFile(Tools.fileToPath(localFile), remoteFile); + async downloadFile(localFile: string, remoteFile: string) { + await this.ibmi.client!.getFile(localFile, remoteFile); } - async uploadDirectory(localDirectory: string | Uri, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { - await this.ibmi.client.putDirectory(Tools.fileToPath(localDirectory), remoteDirectory, options); + async uploadDirectory(localDirectory: string, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { + await this.ibmi.client!.putDirectory(localDirectory, remoteDirectory, options); } - async downloadDirectory(localDirectory: string | Uri, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { - await this.ibmi.client.getDirectory(Tools.fileToPath(localDirectory), remoteDirectory, options); - } -} - -function safeIsoValue(date: Date | undefined) { - try { - return date ? date.toISOString().slice(0, 19).replace(`T`, ` `) : ``; - } catch (e) { - return `Unknown`; + async downloadDirectory(localDirectory: string, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { + await this.ibmi.client!.getDirectory(localDirectory, remoteDirectory, options); } } \ No newline at end of file diff --git a/src/api/Tools.ts b/src/api/Tools.ts index c879e41d2..8f9e286af 100644 --- a/src/api/Tools.ts +++ b/src/api/Tools.ts @@ -1,10 +1,7 @@ -import Crypto from 'crypto'; -import { readFileSync } from "fs"; + import os from "os"; import path from "path"; -import vscode from "vscode"; import { IBMiMessage, IBMiMessages, QsysPath } from '../typings'; -import { API, GitExtension } from "./import/git"; export namespace Tools { export class SqlError extends Error { @@ -229,35 +226,10 @@ export namespace Tools { } } - let gitLookedUp: boolean; - let gitAPI: API | undefined; - export function getGitAPI(): API | undefined { - if (!gitLookedUp) { - try { - gitAPI = vscode.extensions.getExtension(`vscode.git`)?.exports.getAPI(1); - } - catch (error) { - console.log(`Git extension issue.`, error); - } - finally { - gitLookedUp = true; - } - } - return gitAPI; - } - export function distinct(value: any, index: number, array: any[]) { return array.indexOf(value) === index; } - export function md5Hash(file: vscode.Uri): string { - const bytes = readFileSync(file.fsPath); - return Crypto.createHash("md5") - .update(bytes) - .digest("hex") - .toLowerCase(); - } - export function capitalize(text: string) { return text.charAt(0).toUpperCase() + text.slice(1); } @@ -298,60 +270,6 @@ export namespace Tools { } } - /** - * Check whether two given uris point to the same file/member - */ - export function areEquivalentUris(uriA: vscode.Uri, uriB: vscode.Uri) { - return uriStringWithoutFragment(uriA) === uriStringWithoutFragment(uriB); - } - - /** - * We do this to find previously opened files with the same path, but different case OR readonly flags. - * Without this, it's possible for the same document to be opened twice simply due to the readonly flag. - */ - export function findExistingDocumentUri(uri: vscode.Uri) { - const possibleDoc = findExistingDocument(uri); - return possibleDoc?.uri || uri; - } - - export function findExistingDocument(uri: vscode.Uri) { - const baseUriString = uriStringWithoutFragment(uri); - const possibleDoc = vscode.workspace.textDocuments.find(document => uriStringWithoutFragment(document.uri) === baseUriString); - return possibleDoc; - } - - export function findExistingDocumentByName(nameAndExt: string) { - const possibleDoc = vscode.workspace.textDocuments.find(document => document.fileName.toLowerCase().endsWith(nameAndExt.toLowerCase())); - return possibleDoc ? possibleDoc.uri : undefined; - } - - /** - * We convert member to lowercase as members are case insensitive. - */ - function uriStringWithoutFragment(uri: vscode.Uri) { - // To lowercase because the URI path is case-insensitive - const baseUri = uri.scheme + `:` + uri.path; - const isCaseSensitive = (uri.scheme === `streamfile` && /^\/QOpenSys\//i.test(uri.path)); - return (isCaseSensitive ? baseUri : baseUri.toLowerCase()); - } - - /** - * Given the uri of a member or other resource, find all - * (if any) open tabs where that resource is being edited. - */ - export function findUriTabs(uriToFind: vscode.Uri | string): vscode.Tab[] { - let resourceTabs: vscode.Tab[] = []; - for (const group of vscode.window.tabGroups.all) { - group.tabs.filter(tab => - (tab.input instanceof vscode.TabInputText) - && (uriToFind instanceof vscode.Uri ? areEquivalentUris(tab.input.uri, uriToFind) : tab.input.uri.path.startsWith(`${uriToFind}/`)) - ).forEach(tab => { - resourceTabs.push(tab); - }); - } - return resourceTabs; - } - /** * Fixes an SQL statement to make it compatible with db2 CLI program QZDFMDB2. * - Changes `@clCommand` statements into Call `QSYS2.QCMDEX('clCommand')` procedure calls @@ -379,17 +297,6 @@ export namespace Tools { return statements; } - export function generateTooltipHtmlTable(header: string, rows: Record) { - return `` - .concat(`${header ? `${header}` : ``}`) - .concat(`${Object.entries(rows) - .filter(([key, value]) => value !== undefined && value !== '') - .map(([key, value]) => ``) - .join(``)}` - ) - .concat(`
${vscode.l10n.t(key)}: ${value}
`); - } - export function fixWindowsPath(path: string) { if (process.platform === `win32` && path[0] === `/`) { //Issue with getFile not working propertly on Windows @@ -415,43 +322,6 @@ export namespace Tools { return number; } - const activeContexts: Map = new Map; - /** - * Runs a function while a context value is set to true. - * - * If multiple callers call this function with the same context, only the last one returning will unset the context value. - * - * @param context the context value that will be set to `true` during `task` execution - * @param task the function to run while the context value is `true` - */ - export async function withContext(context: string, task: () => Promise) { - try { - let stack = activeContexts.get(context); - if (stack === undefined) { - await vscode.commands.executeCommand(`setContext`, context, true); - activeContexts.set(context, 0); - } - else { - stack++; - activeContexts.set(context, stack); - } - return await task(); - } - finally { - let stack = activeContexts.get(context); - if (stack !== undefined) { - if (stack) { - stack--; - activeContexts.set(context, stack); - } - else { - await vscode.commands.executeCommand(`setContext`, context, undefined); - activeContexts.delete(context); - } - } - } - } - /** * Converts a timestamp from the attr command (in the form `Thu Dec 21 21:47:02 2023`) into a Date object * @param timestamp an attr timestamp string @@ -464,15 +334,6 @@ export namespace Tools { } return 0; } - - export function fileToPath(file: string | vscode.Uri): string { - if (typeof file === "string") { - return Tools.fixWindowsPath(file); - } - else { - return file.fsPath; - } - } /** * Transforms a file path into an OS agnostic path. diff --git a/src/views/LibraryListView.ts b/src/views/LibraryListView.ts index 69fa679aa..0cb6c32f5 100644 --- a/src/views/LibraryListView.ts +++ b/src/views/LibraryListView.ts @@ -2,6 +2,7 @@ import vscode, { commands, l10n } from "vscode"; import { ConnectionConfiguration, GlobalConfiguration } from "../api/Configuration"; import { instance } from "../instantiate"; import { IBMiObject, WithLibrary } from "../typings"; +import { objectToToolTip } from "./tools"; export class LibraryListProvider implements vscode.TreeDataProvider { private readonly _emitter: vscode.EventEmitter = new vscode.EventEmitter(); @@ -300,7 +301,7 @@ class LibraryListNode extends vscode.TreeItem implements WithLibrary { ((context === `currentLibrary` ? `${l10n.t(`(current library)`)}` : ``) + (object.text !== `` && showDescInLibList ? ` ${object.text}` : ``) + (object.attribute !== `` ? ` (*${object.attribute})` : ``)).trim(); - this.tooltip = instance.getContent()?.objectToToolTip([object.library, object.name].join(`/`), object); + this.tooltip = objectToToolTip([object.library, object.name].join(`/`), object); } } diff --git a/src/views/debugView.ts b/src/views/debugView.ts index e894c31ca..9a931f77f 100644 --- a/src/views/debugView.ts +++ b/src/views/debugView.ts @@ -5,6 +5,7 @@ import { DebugConfiguration, getDebugServiceDetails } from "../api/debug/config" import { DebugJob, getDebugServerJob, getDebugServiceJob, isDebugEngineRunning, readActiveJob, readJVMInfo, startServer, startService, stopServer, stopService } from "../api/debug/server"; import { instance } from "../instantiate"; import { BrowserItem } from "../typings"; +import { withContext } from "./tools"; const title = "IBM i debugger"; type Certificates = { @@ -47,9 +48,9 @@ export function initializeDebugBrowser(context: vscode.ExtensionContext) { debugTreeViewer, vscode.commands.registerCommand("code-for-ibmi.debug.refresh", updateDebugBrowser), vscode.commands.registerCommand("code-for-ibmi.debug.refresh.item", (item: DebugItem) => debugBrowser.refresh(item)), - vscode.commands.registerCommand("code-for-ibmi.debug.job.start", (item: DebugJobItem) => Tools.withContext(`code-for-ibmi:debugWorking`, () => item.start())), - vscode.commands.registerCommand("code-for-ibmi.debug.job.stop", (item: DebugJobItem) => Tools.withContext(`code-for-ibmi:debugWorking`, () => item.stop())), - vscode.commands.registerCommand("code-for-ibmi.debug.job.restart", async (item: DebugJobItem) => Tools.withContext(`code-for-ibmi:debugWorking`, async () => await item.stop() && item.start())), + vscode.commands.registerCommand("code-for-ibmi.debug.job.start", (item: DebugJobItem) => withContext(`code-for-ibmi:debugWorking`, () => item.start())), + vscode.commands.registerCommand("code-for-ibmi.debug.job.stop", (item: DebugJobItem) => withContext(`code-for-ibmi:debugWorking`, () => item.stop())), + vscode.commands.registerCommand("code-for-ibmi.debug.job.restart", async (item: DebugJobItem) => withContext(`code-for-ibmi:debugWorking`, async () => await item.stop() && item.start())), ); } @@ -66,7 +67,7 @@ class DebugBrowser implements vscode.TreeDataProvider { } async getChildren(item?: DebugItem) { - return Tools.withContext(`code-for-ibmi:debugWorking`, async () => item?.getChildren?.() || this.getRootItems()); + return withContext(`code-for-ibmi:debugWorking`, async () => item?.getChildren?.() || this.getRootItems()); } private async getRootItems() { diff --git a/src/views/ifsBrowser.ts b/src/views/ifsBrowser.ts index 6a73b7812..6438f7f6f 100644 --- a/src/views/ifsBrowser.ts +++ b/src/views/ifsBrowser.ts @@ -10,6 +10,7 @@ import { GlobalStorage } from "../api/Storage"; import { Tools } from "../api/Tools"; import { instance } from "../instantiate"; import { BrowserItem, BrowserItemParameters, FocusOptions, IFSFile, IFS_BROWSER_MIMETYPE, OBJECT_BROWSER_MIMETYPE, SearchHit, SearchResults, WithPath } from "../typings"; +import { fileToPath, findUriTabs, ifsFileToToolTip } from "./tools"; const URI_LIST_MIMETYPE = "text/uri-list"; const URI_LIST_SEPARATOR = "\r\n"; @@ -100,7 +101,7 @@ class IFSItem extends BrowserItem implements WithPath { constructor(readonly file: IFSFile, parameters: BrowserItemParameters) { super(file.name, parameters); this.path = file.path; - this.tooltip = instance.getContent()?.ifsFileToToolTip(this.path, file); + this.tooltip = ifsFileToToolTip(this.path, file); } sortBy(sort: SortOptions) { @@ -519,7 +520,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { for (const directory of directoriesToUpload) { const name = path.basename(directory.fsPath); progress.report({ message: l10n.t(`sending {0} directory...`, name) }) - await connection.getContent().uploadDirectory(directory, path.posix.join(root, name), { concurrency: 5 }) + await connection.getContent().uploadDirectory(fileToPath(directory), path.posix.join(root, name), { concurrency: 5 }) } } @@ -621,14 +622,14 @@ Please type "{0}" to confirm deletion.`, dirName); return; } // Check if the streamfile is currently open in an editor tab - oldFileTabs.push(...Tools.findUriTabs(node.resourceUri)); + oldFileTabs.push(...findUriTabs(node.resourceUri)); if (oldFileTabs.find(tab => tab.isDirty)) { vscode.window.showErrorMessage(l10n.t(`Error renaming/moving {0}! {1}`, typeLabel, l10n.t("The file has unsaved changes."))); return; } } else { // Check if there are streamfiles in the directory which are currently open in an editor tab - oldFileTabs.push(...Tools.findUriTabs(node.file.path)); + oldFileTabs.push(...findUriTabs(node.file.path)); if (oldFileTabs.find(tab => tab.isDirty)) { vscode.window.showErrorMessage(l10n.t(`Error renaming/moving {0}! {1}`, typeLabel, l10n.t("The directory has file(s) with unsaved changes."))); return; diff --git a/src/views/objectBrowser.ts b/src/views/objectBrowser.ts index 538d1d7a7..8d2c7c3e9 100644 --- a/src/views/objectBrowser.ts +++ b/src/views/objectBrowser.ts @@ -13,6 +13,7 @@ import { getMemberUri } from "../filesystems/qsys/QSysFs"; import { instance } from "../instantiate"; import { BrowserItem, BrowserItemParameters, CommandResult, FilteredItem, FocusOptions, IBMiMember, IBMiObject, MemberItem, OBJECT_BROWSER_MIMETYPE, ObjectItem, WithLibrary } from "../typings"; import { editFilter } from "../webviews/filters"; +import { findUriTabs, memberToToolTip, objectToToolTip, sourcePhysicalFileToToolTip } from "./tools"; const URI_LIST_SEPARATOR = "\r\n"; @@ -305,8 +306,8 @@ class ObjectBrowserSourcePhysicalFileItem extends ObjectBrowserItem implements O return deleteObject(this.object); } - async getToolTip() { - return await getContent().sourcePhysicalFileToToolTip(this.path, this.object); + getToolTip() { + return sourcePhysicalFileToToolTip(getConnection(), this.path, this.object); } } @@ -325,7 +326,7 @@ class ObjectBrowserObjectItem extends ObjectBrowserItem implements ObjectItem, W this.updateDescription(); this.contextValue = `object.${type.toLowerCase()}${object.attribute ? `.${object.attribute}` : ``}${isLibrary ? '_library' : ''}${this.isProtected() ? `_readonly` : ``}`; - this.tooltip = getContent().objectToToolTip(this.path, object); + this.tooltip = objectToToolTip(this.path, object); this.resourceUri = vscode.Uri.from({ scheme: `object`, @@ -377,7 +378,7 @@ class ObjectBrowserMemberItem extends ObjectBrowserItem implements MemberItem { this.resourceUri = getMemberUri(member, { readonly }); this.path = this.resourceUri.path.substring(1); - this.tooltip = getContent().memberToToolTip(this.path, member); + this.tooltip = memberToToolTip(this.path, member); this.sortBy = (sort: SortOptions) => parent.sortBy(sort); @@ -709,7 +710,7 @@ export function initializeObjectBrowser(context: vscode.ExtensionContext) { let newNameOK; // Check if the member is currently open in an editor tab. - const oldMemberTabs = Tools.findUriTabs(oldUri); + const oldMemberTabs = findUriTabs(oldUri); // If the member is currently open in an editor tab, and // the member has unsaved changes, then prevent the renaming operation. diff --git a/src/views/tools.ts b/src/views/tools.ts new file mode 100644 index 000000000..363f13516 --- /dev/null +++ b/src/views/tools.ts @@ -0,0 +1,207 @@ + +import Crypto from 'crypto'; +import { readFileSync } from "fs"; +import vscode, { MarkdownString } from "vscode"; +import { API, GitExtension } from "../api/import/git"; +import { Tools } from '../api/Tools'; +import { IBMiObject, IBMiMember, IFSFile } from '../typings'; +import IBMi from '../api/IBMi'; + +let gitLookedUp: boolean; +let gitAPI: API | undefined; +export function getGitAPI(): API | undefined { + if (!gitLookedUp) { + try { + gitAPI = vscode.extensions.getExtension(`vscode.git`)?.exports.getAPI(1); + } + catch (error) { + console.log(`Git extension issue.`, error); + } + finally { + gitLookedUp = true; + } + } + return gitAPI; +} + +export function md5Hash(file: vscode.Uri): string { + const bytes = readFileSync(file.fsPath); + return Crypto.createHash("md5") + .update(bytes) + .digest("hex") + .toLowerCase(); +} + +/** + * Check whether two given uris point to the same file/member + */ +export function areEquivalentUris(uriA: vscode.Uri, uriB: vscode.Uri) { + return uriStringWithoutFragment(uriA) === uriStringWithoutFragment(uriB); +} + +/** + * We do this to find previously opened files with the same path, but different case OR readonly flags. + * Without this, it's possible for the same document to be opened twice simply due to the readonly flag. + */ +export function findExistingDocumentUri(uri: vscode.Uri) { + const possibleDoc = findExistingDocument(uri); + return possibleDoc?.uri || uri; +} + +export function findExistingDocument(uri: vscode.Uri) { + const baseUriString = uriStringWithoutFragment(uri); + const possibleDoc = vscode.workspace.textDocuments.find(document => uriStringWithoutFragment(document.uri) === baseUriString); + return possibleDoc; +} + +export function findExistingDocumentByName(nameAndExt: string) { + const possibleDoc = vscode.workspace.textDocuments.find(document => document.fileName.toLowerCase().endsWith(nameAndExt.toLowerCase())); + return possibleDoc ? possibleDoc.uri : undefined; +} + +/** + * We convert member to lowercase as members are case insensitive. + */ +function uriStringWithoutFragment(uri: vscode.Uri) { + // To lowercase because the URI path is case-insensitive + const baseUri = uri.scheme + `:` + uri.path; + const isCaseSensitive = (uri.scheme === `streamfile` && /^\/QOpenSys\//i.test(uri.path)); + return (isCaseSensitive ? baseUri : baseUri.toLowerCase()); +} + +/** + * Given the uri of a member or other resource, find all + * (if any) open tabs where that resource is being edited. +*/ +export function findUriTabs(uriToFind: vscode.Uri | string): vscode.Tab[] { + let resourceTabs: vscode.Tab[] = []; + for (const group of vscode.window.tabGroups.all) { + group.tabs.filter(tab => + (tab.input instanceof vscode.TabInputText) + && (uriToFind instanceof vscode.Uri ? areEquivalentUris(tab.input.uri, uriToFind) : tab.input.uri.path.startsWith(`${uriToFind}/`)) + ).forEach(tab => { + resourceTabs.push(tab); + }); + } + return resourceTabs; +} + + + +export function generateTooltipHtmlTable(header: string, rows: Record) { + return `` + .concat(`${header ? `${header}` : ``}`) + .concat(`${Object.entries(rows) + .filter(([key, value]) => value !== undefined && value !== '') + .map(([key, value]) => ``) + .join(``)}` + ) + .concat(`
${vscode.l10n.t(key)}: ${value}
`); +} + + +const activeContexts: Map = new Map; +/** + * Runs a function while a context value is set to true. + * + * If multiple callers call this function with the same context, only the last one returning will unset the context value. + * + * @param context the context value that will be set to `true` during `task` execution + * @param task the function to run while the context value is `true` + */ +export async function withContext(context: string, task: () => Promise) { + try { + let stack = activeContexts.get(context); + if (stack === undefined) { + await vscode.commands.executeCommand(`setContext`, context, true); + activeContexts.set(context, 0); + } + else { + stack++; + activeContexts.set(context, stack); + } + return await task(); + } + finally { + let stack = activeContexts.get(context); + if (stack !== undefined) { + if (stack) { + stack--; + activeContexts.set(context, stack); + } + else { + await vscode.commands.executeCommand(`setContext`, context, undefined); + activeContexts.delete(context); + } + } + } +} + +export function fileToPath(file: string | vscode.Uri): string { + if (typeof file === "string") { + return Tools.fixWindowsPath(file); + } + else { + return file.fsPath; + } +} + +export function objectToToolTip(path: string, object: IBMiObject) { + const tooltip = new MarkdownString(generateTooltipHtmlTable(path, { + "Type": object.type, + "Attribute": object.attribute, + "Text": object.text, + "Size": object.size, + "Created": safeIsoValue(object.created), + "Changed": safeIsoValue(object.changed), + "Created by": object.created_by, + "Owner": object.owner, + "IASP": object.asp + })); + tooltip.supportHtml = true; + return tooltip; +} + +export async function sourcePhysicalFileToToolTip(connection: IBMi, path: string, object: IBMiObject) { + const content = connection.getContent(); + const tooltip = new MarkdownString(generateTooltipHtmlTable(path, { + "Text": object.text, + "Members": await content.countMembers(object), + "Length": object.sourceLength, + "CCSID": (await content.getAttributes(object, "CCSID"))?.CCSID || '?', + "IASP": object.asp + })); + tooltip.supportHtml = true; + return tooltip; +} + +export function memberToToolTip(path: string, member: IBMiMember) { + const tooltip = new MarkdownString(generateTooltipHtmlTable(path, { + "Text": member.text, + "Lines": member.lines, + "Created": safeIsoValue(member.created), + "Changed": safeIsoValue(member.changed) + })); + tooltip.supportHtml = true; + return tooltip; +} + +export function ifsFileToToolTip(path: string, ifsFile: IFSFile) { + const tooltip = new MarkdownString(generateTooltipHtmlTable(path, { + "Size": ifsFile.size, + "Modified": ifsFile.modified ? safeIsoValue(new Date(ifsFile.modified.getTime() - ifsFile.modified.getTimezoneOffset() * 60 * 1000)) : ``, + "Owner": ifsFile.owner ? ifsFile.owner.toUpperCase() : `` + })); + tooltip.supportHtml = true; + return tooltip; +} + + + +function safeIsoValue(date: Date | undefined) { + try { + return date ? date.toISOString().slice(0, 19).replace(`T`, ` `) : ``; + } catch (e) { + return `Unknown`; + } +} \ No newline at end of file From ce5ac12c424f30b1422c0d4080562ac35f546971 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 13:22:07 -0500 Subject: [PATCH 02/46] Refactor CompileTools to remove anything vscode related Signed-off-by: worksofliam --- src/api/CompileTools.ts | 666 +---------------------- src/api/Instance.ts | 4 +- src/api/debug/certificates.ts | 3 +- src/api/debug/index.ts | 8 +- src/api/local/deployTools.ts | 8 +- src/api/local/git.ts | 6 +- src/commands/actions.ts | 6 +- src/commands/open.ts | 7 +- src/extension.ts | 6 +- src/filesystems/qsys/FSUtils.ts | 4 +- src/sandbox.ts | 4 +- src/testing/action.ts | 7 +- src/testing/deployTools.ts | 7 +- src/typings.ts | 1 + src/views/actions.ts | 650 ++++++++++++++++++++++ src/{api/errors => views}/diagnostics.ts | 18 +- src/webviews/settings/index.ts | 5 +- 17 files changed, 708 insertions(+), 702 deletions(-) create mode 100644 src/views/actions.ts rename src/{api/errors => views}/diagnostics.ts (89%) diff --git a/src/api/CompileTools.ts b/src/api/CompileTools.ts index d87fd71be..8df6a8fb7 100644 --- a/src/api/CompileTools.ts +++ b/src/api/CompileTools.ts @@ -1,20 +1,7 @@ -import path from 'path'; -import vscode, { CustomExecution, EventEmitter, Pseudoterminal, TaskGroup, TaskRevealKind, WorkspaceFolder, commands, tasks } from 'vscode'; -import { parseFSOptions } from '../filesystems/qsys/QSysFs'; -import { Action, BrowserItem, CommandResult, DeploymentMethod, RemoteCommand, StandardIO } from '../typings'; -import { GlobalConfiguration } from './Configuration'; -import { CustomUI } from './CustomUI'; +import { Variable, RemoteCommand, CommandResult, StandardIO } from '../typings'; import IBMi from './IBMi'; -import Instance from './Instance'; import { Tools } from './Tools'; -import { EvfEventInfo, refreshDiagnosticsFromLocal, refreshDiagnosticsFromServer, registerDiagnostics } from './errors/diagnostics'; -import { getLocalActions } from './local/actions'; -import { DeployTools } from './local/deployTools'; -import { getBranchLibraryName, getEnvConfig } from './local/env'; -import { getGitBranch } from './local/git'; - -const NEWLINE = `\r\n`; export interface ILELibrarySettings { currentLibrary: string; @@ -22,22 +9,7 @@ export interface ILELibrarySettings { } export namespace CompileTools { - type Variable = Record; - - interface CommandObject { - object: string - library?: string - } - - const PARM_REGEX = /(PNLGRP|OBJ|PGM|MODULE)\((?.+?)\)/; - - const actionUsed: Map = new Map; - - export function register(context: vscode.ExtensionContext) { - context.subscriptions.push( - ...registerDiagnostics() - ); - } + export const NEWLINE = `\r\n`; function expandVariables(variables: Variable) { for (const key in variables) { @@ -49,7 +21,7 @@ export namespace CompileTools { } } - function expandCommand(inputValue: string, variables: Variable, currentVar?: string) { + function expandCommand(inputValue: string, variables: Variable) { for (const key in variables) { if (variables[key]) { inputValue = inputValue.replace(new RegExp(key, `g`), variables[key]); @@ -76,512 +48,10 @@ export namespace CompileTools { } } - export async function runAction(instance: Instance, uri: vscode.Uri, customAction?: Action, method?: DeploymentMethod, browserItem?: BrowserItem, workspaceFolder?: WorkspaceFolder): Promise { - const connection = instance.getConnection(); - - const uriOptions = parseFSOptions(uri); - if (connection) { - const config = connection.getConfig(); - const content = connection.getContent(); - - const extension = uri.path.substring(uri.path.lastIndexOf(`.`) + 1).toUpperCase(); - const fragment = uri.fragment.toUpperCase(); - - const isProtected = uriOptions.readonly || config?.readOnlyMode; - - if(!workspaceFolder) { - workspaceFolder = vscode.workspace.getWorkspaceFolder(uri); - } - let remoteCwd = config?.homeDirectory || `.`; - - let availableActions: { label: string; action: Action; }[] = []; - if (!customAction) { - // First we grab a copy the predefined Actions in the VS Code settings - const allActions = [...GlobalConfiguration.get(`actions`) || []]; - - // Then, if we're being called from a local file - // we fetch the Actions defined from the workspace. - if (workspaceFolder && uri.scheme === `file`) { - const localActions = await getLocalActions(workspaceFolder); - allActions.push(...localActions); - } - - // We make sure all extensions are uppercase - allActions.forEach(action => { - if (action.extensions) { - action.extensions = action.extensions.map(ext => ext.toUpperCase()); - }; - }); - - // Then we get all the available Actions for the current context - availableActions = allActions.filter(action => action.type === uri.scheme && (!action.extensions || action.extensions.includes(extension) || action.extensions.includes(fragment) || action.extensions.includes(`GLOBAL`)) && (!isProtected || action.runOnProtected)) - .sort((a, b) => (actionUsed.get(b.name) || 0) - (actionUsed.get(a.name) || 0)) - .map(action => ({ - label: action.name, - action - })); - } - - if (customAction || availableActions.length) { - const chosenAction = customAction || ((availableActions.length === 1) ? availableActions[0] : await vscode.window.showQuickPick(availableActions))?.action; - if (chosenAction) { - actionUsed.set(chosenAction.name, Date.now()); - const environment = chosenAction.environment || `ile`; - - let workspaceId: number | undefined = undefined; - - // If we are running an Action for a local file, we need a deploy directory even if they are not - // deploying the file. This is because we need to know the relative path of the file to the deploy directory. - if (workspaceFolder && chosenAction.type === `file`) { - if (chosenAction.deployFirst) { - const deployResult = await DeployTools.launchDeploy(workspaceFolder.index, method); - if (deployResult !== undefined) { - workspaceId = deployResult.workspaceId; - remoteCwd = deployResult.remoteDirectory; - } else { - vscode.window.showWarningMessage(`Action "${chosenAction.name}" was cancelled.`); - return false; - } - } else { - workspaceId = workspaceFolder.index; - const deployPath = DeployTools.getRemoteDeployDirectory(workspaceFolder); - if (deployPath) { - remoteCwd = deployPath; - } else { - vscode.window.showWarningMessage(`No deploy directory setup for this workspace. Cancelling Action.`); - return false; - } - } - } - - let fromWorkspace: WorkspaceFolder | undefined; - - if (chosenAction.type === `file` && vscode.workspace.workspaceFolders) { - fromWorkspace = vscode.workspace.workspaceFolders[workspaceId || 0]; - } - - const variables: Variable = {}; - const evfeventInfo: EvfEventInfo = { - object: '', - library: '', - extension, - workspace: fromWorkspace - }; - - if (workspaceFolder) { - const envFileVars = await getEnvConfig(workspaceFolder); - Object.entries(envFileVars).forEach(([key, value]) => variables[`&${key}`] = value); - } - - switch (chosenAction.type) { - case `member`: - const memberDetail = connection.parserMemberPath(uri.path); - evfeventInfo.library = memberDetail.library; - evfeventInfo.object = memberDetail.name; - evfeventInfo.extension = memberDetail.extension; - evfeventInfo.asp = memberDetail.asp; - - variables[`&OPENLIBL`] = memberDetail.library.toLowerCase(); - variables[`&OPENLIB`] = memberDetail.library; - - variables[`&OPENSPFL`] = memberDetail.file.toLowerCase(); - variables[`&OPENSPF`] = memberDetail.file; - - variables[`&OPENMBRL`] = memberDetail.name.toLowerCase(); - variables[`&OPENMBR`] = memberDetail.name; - - variables[`&EXTL`] = memberDetail.extension.toLowerCase(); - variables[`&EXT`] = memberDetail.extension; - break; - - case `file`: - case `streamfile`: - const pathData = path.parse(uri.path); - const basename = pathData.base; - const ext = pathData.ext ? (pathData.ext.startsWith(`.`) ? pathData.ext.substring(1) : pathData.ext) : ``; - const parent = path.parse(pathData.dir).base; - let name = pathData.name; - - // Logic to handle second extension, caused by bob. - const bobTypes = [`.PGM`, `.SRVPGM`]; - const secondName = path.parse(name); - if (secondName.ext && bobTypes.includes(secondName.ext.toUpperCase())) { - name = secondName.name; - } - - // Remove bob text convention - if (name.includes(`-`)) { - name = name.substring(0, name.indexOf(`-`)); - } - - if (variables[`&CURLIB`]) { - evfeventInfo.library = variables[`&CURLIB`]; - - } else { - evfeventInfo.library = config.currentLibrary; - } - - evfeventInfo.library = evfeventInfo.library.toUpperCase(); - evfeventInfo.object = name.toUpperCase(); - evfeventInfo.extension = ext; - - if (chosenAction.command.includes(`&SRCFILE`)) { - variables[`&SRCLIB`] = evfeventInfo.library; - variables[`&SRCPF`] = `QTMPSRC`; - variables[`&SRCFILE`] = `${evfeventInfo.library}/QTMPSRC`; - } - - switch (chosenAction.type) { - case `file`: - variables[`&LOCALPATH`] = uri.fsPath; - if (fromWorkspace) { - const relativePath = path.relative(fromWorkspace.uri.path, uri.path).split(path.sep).join(path.posix.sep); - variables[`&RELATIVEPATH`] = relativePath; - - // We need to make sure the remote path is posix - const fullPath = path.posix.join(remoteCwd, relativePath); - variables[`&FULLPATH`] = fullPath; - variables[`{path}`] = fullPath; - variables[`&WORKDIR`] = remoteCwd; - variables[`&FILEDIR`] = path.posix.parse(fullPath).dir; - - const branch = getGitBranch(fromWorkspace); - if (branch) { - variables[`&BRANCHLIB`] = getBranchLibraryName(branch); - variables[`&BRANCH`] = branch; - variables[`{branch}`] = branch; - } - } - break; - - case `streamfile`: - const relativePath = path.posix.relative(remoteCwd, uri.path); - variables[`&RELATIVEPATH`] = relativePath; - - const fullName = uri.path; - variables[`&FULLPATH`] = fullName; - variables[`&FILEDIR`] = path.parse(fullName).dir; - break; - } - - variables[`&PARENT`] = parent; - - variables[`&BASENAME`] = basename; - variables[`{filename}`] = basename; - - variables[`&NAMEL`] = name.toLowerCase(); - variables[`&NAME`] = name; - - variables[`&EXTL`] = extension.toLowerCase(); - variables[`&EXT`] = extension; - break; - - case `object`: - const [_, library, fullName] = uri.path.toUpperCase().split(`/`); - const object = fullName.substring(0, fullName.lastIndexOf(`.`)); - - evfeventInfo.library = library; - evfeventInfo.object = object; - - variables[`&LIBRARYL`] = library.toLowerCase(); - variables[`&LIBRARY`] = library; - - variables[`&NAMEL`] = object.toLowerCase(); - variables[`&NAME`] = object; - - variables[`&TYPEL`] = extension.toLowerCase(); - variables[`&TYPE`] = extension; - - variables[`&EXTL`] = extension.toLowerCase(); - variables[`&EXT`] = extension; - break; - } - - const viewControl = GlobalConfiguration.get(`postActionView`) || "none"; - const outputBuffer: string[] = []; - let actionName = chosenAction.name; - let hasRun = false; - - const exitCode = await new Promise(resolve => - tasks.executeTask({ - isBackground: true, - name: chosenAction.name, - definition: { type: `ibmi` }, - scope: workspaceFolder, - source: 'IBM i', - presentationOptions: { - showReuseMessage: true, - clear: GlobalConfiguration.get(`clearOutputEveryTime`), - focus: false, - reveal: (viewControl === `task` ? TaskRevealKind.Always : TaskRevealKind.Never), - }, - problemMatchers: [], - runOptions: {}, - group: TaskGroup.Build, - execution: new CustomExecution(async (e) => { - const writeEmitter = new vscode.EventEmitter(); - const closeEmitter = new vscode.EventEmitter(); - - writeEmitter.event(s => outputBuffer.push(s)); - closeEmitter.event(resolve); - - const term: Pseudoterminal = { - onDidWrite: writeEmitter.event, - onDidClose: closeEmitter.event, - open: async (initialDimensions: vscode.TerminalDimensions | undefined) => { - let successful = false; - let problemsFetched = false; - - try { - writeEmitter.fire(`Running Action: ${chosenAction.name} (${new Date().toLocaleTimeString()})` + NEWLINE); - - // If &SRCFILE is set, we need to copy the file to a temporary source file from the IFS - if (variables[`&FULLPATH`] && variables[`&SRCFILE`] && evfeventInfo.object) { - const [lib, srcpf] = variables[`&SRCFILE`].split(`/`); - - const createSourceFile = content.toCl(`CRTSRCPF`, { - rcdlen: 112, //NICE: this configurable in a VS Code setting? - file: `${lib}/${srcpf}`, - }); - - const copyFromStreamfile = content.toCl(`CPYFRMSTMF`, { - fromstmf: variables[`&FULLPATH`], - tombr: `'${Tools.qualifyPath(lib, srcpf, evfeventInfo.object)}'`, - mbropt: `*REPLACE`, - dbfccsid: `*FILE`, - stmfccsid: 1208, - }); - - // We don't care if this fails. Usually it's because the source file already exists. - await runCommand(connection, {command: createSourceFile, environment: `ile`, noLibList: true}); - - // Attempt to copy to member - const copyResult = await runCommand(connection, {command: copyFromStreamfile, environment: `ile`, noLibList: true}); - - if (copyResult.code !== 0) { - writeEmitter.fire(`Failed to copy file to a temporary member.\n\t${copyResult.stderr}\n\n`); - closeEmitter.fire(copyResult.code || 1); - } - } - - const commandResult = await runCommand(connection, { - title: chosenAction.name, - environment, - command: chosenAction.command, - cwd: remoteCwd, - env: variables, - }, writeEmitter); - - const useLocalEvfevent = - fromWorkspace && chosenAction.postDownload && - (chosenAction.postDownload.includes(`.evfevent`) || chosenAction.postDownload.includes(`.evfevent/`)); - - if (commandResult) { - hasRun = true; - const isIleCommand = environment === `ile`; - - const possibleObject = getObjectFromCommand(commandResult.command); - if (isIleCommand && possibleObject) { - Object.assign(evfeventInfo, possibleObject); - } - - actionName = (isIleCommand && possibleObject ? `${chosenAction.name} for ${evfeventInfo.library}/${evfeventInfo.object}` : actionName); - successful = (commandResult.code === 0 || commandResult.code === null); - - writeEmitter.fire(NEWLINE); - - if (useLocalEvfevent) { - writeEmitter.fire(`Fetching errors from .evfevent.${NEWLINE}`); - - } - else if (evfeventInfo.object && evfeventInfo.library) { - if (chosenAction.command.includes(`*EVENTF`)) { - writeEmitter.fire(`Fetching errors for ${evfeventInfo.library}/${evfeventInfo.object}.` + NEWLINE); - refreshDiagnosticsFromServer(instance, evfeventInfo); - problemsFetched = true; - } else { - writeEmitter.fire(`*EVENTF not found in command string. Not fetching errors for ${evfeventInfo.library}/${evfeventInfo.object}.` + NEWLINE); - } - } - } - - if (chosenAction.type === `file` && chosenAction.postDownload?.length) { - if (fromWorkspace) { - const remoteDir = remoteCwd; - const localDir = fromWorkspace.uri; - - const postDownloads: { type: vscode.FileType, localPath: string, remotePath: string }[] = []; - const downloadDirectories = new Set(); - for (const download of chosenAction.postDownload) { - const remotePath = path.posix.join(remoteDir, download); - const localPath = vscode.Uri.joinPath(localDir, download).path; - - let type: vscode.FileType; - if (await content.isDirectory(remotePath)) { - downloadDirectories.add(vscode.Uri.joinPath(localDir, download)); - type = vscode.FileType.Directory; - } - else { - const directory = path.parse(download).dir; - if (directory) { - downloadDirectories.add(vscode.Uri.joinPath(localDir, directory)); - } - type = vscode.FileType.File; - } - - postDownloads.push({ remotePath, localPath, type }) - } - - //Clear and create every local download directories - for (const downloadPath of downloadDirectories) { - try { - const stat = await vscode.workspace.fs.stat(downloadPath); //Check if target exists - if (stat.type !== vscode.FileType.Directory) { - if (await vscode.window.showWarningMessage(`${downloadPath} exists but is a file.`, "Delete and create directory")) { - await vscode.workspace.fs.delete(downloadPath); - throw new Error("Create directory"); - } - } - else if (stat.type === vscode.FileType.Directory) { - await vscode.workspace.fs.delete(downloadPath, { recursive: true }); - throw new Error("Create directory"); - } - } - catch (e) { - //Either fs.stat did not find the folder or it wasn't a folder and it's been deleted above - try { - await vscode.workspace.fs.createDirectory(downloadPath) - } - catch (error) { - vscode.window.showWarningMessage(`Failed to create download path ${downloadPath}: ${error}`); - console.log(error); - closeEmitter.fire(1); - } - } - } - - // Then we download the files that is specified. - const downloads = postDownloads.map( - async (postDownload) => { - const content = connection.getContent(); - if (postDownload.type === vscode.FileType.Directory) { - return content.downloadDirectory(postDownload.localPath, postDownload.remotePath, { recursive: true, concurrency: 5 }); - } else { - return content.downloadFile(postDownload.localPath, postDownload.remotePath); - } - } - ); - - await Promise.all(downloads) - .then(async result => { - // Done! - writeEmitter.fire(`Downloaded files as part of Action: ${chosenAction.postDownload!.join(`, `)}\n`); - - // Process locally downloaded evfevent files: - if (useLocalEvfevent) { - refreshDiagnosticsFromLocal(instance, evfeventInfo); - problemsFetched = true; - } - }) - .catch(error => { - vscode.window.showErrorMessage(`Failed to download files as part of Action.`); - writeEmitter.fire(`Failed to download a file after Action: ${error.message}\n`); - closeEmitter.fire(1); - }); - } - } - - if (problemsFetched && viewControl === `problems`) { - commands.executeCommand(`workbench.action.problems.focus`); - } - - } catch (e) { - writeEmitter.fire(`${e}\n`); - vscode.window.showErrorMessage(`Action ${chosenAction} for ${evfeventInfo.library}/${evfeventInfo.object} failed. (internal error).`); - closeEmitter.fire(1); - } - - closeEmitter.fire(successful ? 0 : 1); - }, - close: function (): void { } - }; - - return term; - }) - }) - ); - - const executionOK = (exitCode === 0); - if (hasRun) { - if (executionOK && browserItem) { - switch (chosenAction.refresh) { - case 'browser': - if (chosenAction.type === 'streamfile') { - vscode.commands.executeCommand("code-for-ibmi.refreshIFSBrowser"); - } - else if (chosenAction.type !== 'file') { - vscode.commands.executeCommand("code-for-ibmi.refreshObjectBrowser"); - } - break; - - case 'filter': - //Filter is a top level item so it has no parent (like Batman) - let filter: BrowserItem = browserItem; - while (filter.parent) { - filter = filter.parent; - } - filter.refresh?.(); - break; - - case 'parent': - browserItem.parent?.refresh?.(); - break; - - default: - //No refresh - } - } - - const openOutputAction = "Open output"; //TODO: will be translated in the future - const uiPromise = executionOK ? - vscode.window.showInformationMessage(`Action ${actionName} was successful.`, openOutputAction) : - vscode.window.showErrorMessage(`Action ${actionName} was not successful.`, openOutputAction); - - uiPromise.then(openOutput => { - if (openOutput) { - const now = new Date(); - new CustomUI() - .addParagraph(`
${outputBuffer.join("")}
`) - .setOptions({ fullWidth: true }) - .loadPage(`${chosenAction.name} [${now.toLocaleString()}]`); - } - }) - } - - return executionOK; - } - else { - return false; - } - } else if (isProtected) { - //when a member is protected(read only) - vscode.window.showErrorMessage(`Action cannot be applied on a read only member.`); - return false; - } else { - //No compile commands - vscode.window.showErrorMessage(`No compile commands found for ${uri.scheme}-${extension}.`); - return false; - } - } - else { - throw new Error("Please connect to an IBM i first") - } - } - /** * Execute a command */ - export async function runCommand(connection: IBMi, options: RemoteCommand, writeEvent?: EventEmitter): Promise { + export async function runCommand(connection: IBMi, options: RemoteCommand, writeEvent?: (content: string) => void): Promise { const config = connection.getConfig(); if (config && connection) { const cwd = options.cwd; @@ -605,41 +75,26 @@ export namespace CompileTools { variables ); - if (commandString) { - const commands = commandString.split(`\n`).filter(command => command.trim().length > 0); - const promptedCommands = []; - for (let command of commands) { - if (command.startsWith(`?`)) { - command = await vscode.window.showInputBox({ prompt: `Run Command`, value: command.substring(1) }) || ''; - } else { - command = await showCustomInputs(`Run Command`, command, options.title || `Command`); - } - promptedCommands.push(command); - if (!command) break; - } - commandString = !promptedCommands.includes(``) ? promptedCommands.join(`\n`) : ``; - } - if (commandString) { const commands = commandString.split(`\n`).filter(command => command.trim().length > 0); if (writeEvent) { if (options.environment === `ile` && !options.noLibList) { - writeEvent.fire(`Current library: ` + ileSetup.currentLibrary + NEWLINE); - writeEvent.fire(`Library list: ` + ileSetup.libraryList.join(` `) + NEWLINE); + writeEvent(`Current library: ` + ileSetup.currentLibrary + NEWLINE); + writeEvent(`Library list: ` + ileSetup.libraryList.join(` `) + NEWLINE); } if (options.cwd) { - writeEvent.fire(`Working directory: ` + options.cwd + NEWLINE); + writeEvent(`Working directory: ` + options.cwd + NEWLINE); } - writeEvent.fire(`Commands:\n${commands.map(command => `\t${command}\n`).join(``)}` + NEWLINE); + writeEvent(`Commands:\n${commands.map(command => `\t${command}\n`).join(``)}` + NEWLINE); } const callbacks: StandardIO = writeEvent ? { onStdout: (data) => { - writeEvent.fire(data.toString().replaceAll(`\n`, NEWLINE)); + writeEvent(data.toString().replaceAll(`\n`, NEWLINE)); }, onStderr: (data) => { - writeEvent.fire(data.toString().replaceAll(`\n`, NEWLINE)); + writeEvent(data.toString().replaceAll(`\n`, NEWLINE)); } } : {}; @@ -707,107 +162,6 @@ export namespace CompileTools { }; } - /** - * @param name action's name - * @param command action's command string - * @return the new command - */ - async function showCustomInputs(name: string, command: string, title?: string): Promise { - const components = []; - let loop = true; - - let end = 0; - while (loop) { - const idx = command.indexOf(`\${`, end); - - if (idx >= 0) { - const start = idx; - end = command.indexOf(`}`, start); - - if (end >= 0) { - let currentInput = command.substring(start + 2, end); - - const [name, label, initialValue] = currentInput.split(`|`); - components.push({ - name, - label, - initialValue: initialValue || ``, - start, - end: end + 1 - }); - } else { - loop = false; - } - } else { - loop = false; - } - } - - if (components.length) { - const commandUI = new CustomUI(); - - if (title) { - commandUI.addHeading(title, 2); - } - - for (const component of components) { - if (component.initialValue.includes(`,`)) { - //Select box - commandUI.addSelect(component.name, component.label, component.initialValue.split(`,`).map((value, index) => ( - { - selected: index === 0, - value, - description: value, - text: `Select ${value}`, - } - ))); - } else { - //Input box - commandUI.addInput(component.name, component.label, '', { default: component.initialValue }); - } - } - - commandUI.addButtons({ id: `execute`, label: `Execute` }, { id: `cancel`, label: `Cancel` }); - - const page = await commandUI.loadPage(name); - if (page) { - page.panel.dispose(); - if (page.data && page.data.buttons !== `cancel`) { - const dataEntries = Object.entries(page.data); - for (const component of components.reverse()) { - const value = dataEntries.find(([key]) => key === component.name)?.[1]; - command = command.substring(0, component.start) + value + command.substring(component.end); - } - } else { - command = ''; - } - } - } - - return command; - } - - function getObjectFromCommand(baseCommand?: string): CommandObject | undefined { - if (baseCommand) { - const regex = PARM_REGEX.exec(baseCommand.toUpperCase()); - if (regex) { - const object = regex.groups?.object.split(`/`); - if (object) { - if (object.length === 2) { - return { - library: object[0], - object: object[1] - }; - } else { - return { - object: object[0] - }; - } - } - } - } - } - function buildLibraryList(config: ILELibrarySettings): string[] { //We have to reverse it because `liblist -a` adds the next item to the top always return config.libraryList.slice(0).reverse(); diff --git a/src/api/Instance.ts b/src/api/Instance.ts index fb2509766..2005cb211 100644 --- a/src/api/Instance.ts +++ b/src/api/Instance.ts @@ -3,7 +3,7 @@ import { ConnectionData, IBMiEvent } from "../typings"; import { ConnectionConfiguration } from "./Configuration"; import IBMi, { ConnectionResult } from "./IBMi"; import { ConnectionStorage, GlobalStorage } from "./Storage"; -import { Tools } from "./Tools"; +import { withContext } from "../views/tools"; type IBMiEventSubscription = { func: Function, @@ -62,7 +62,7 @@ export default class Instance { } }; - return Tools.withContext("code-for-ibmi:connecting", async () => { + return withContext("code-for-ibmi:connecting", async () => { while (true) { try { result = await connection.connect(options.data, options.reconnecting, options.reloadServerSettings, options.onConnectedOperations || [], timeoutHandler); diff --git a/src/api/debug/certificates.ts b/src/api/debug/certificates.ts index 9872c98ff..a1256bae4 100644 --- a/src/api/debug/certificates.ts +++ b/src/api/debug/certificates.ts @@ -9,6 +9,7 @@ import IBMi from "../IBMi"; import IBMiContent from '../IBMiContent'; import { Tools } from '../Tools'; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, getJavaHome } from './config'; +import { fileToPath } from '../../views/tools'; type HostInfo = { ip: string @@ -109,7 +110,7 @@ export async function setup(connection: IBMi, imported?: ImportedCertificate) { password = imported.password; if (imported.localFile) { setProgress("importing local certificate"); - await connection.getContent().uploadFiles([{ local: imported.localFile, remote: debugConfig.getRemoteServiceCertificatePath() }]); + await connection.getContent().uploadFiles([{ local: fileToPath(imported.localFile), remote: debugConfig.getRemoteServiceCertificatePath() }]); } else if (imported.remoteFile) { setProgress("importing remote certificate"); diff --git a/src/api/debug/index.ts b/src/api/debug/index.ts index 69a190b9c..0845bcd1b 100644 --- a/src/api/debug/index.ts +++ b/src/api/debug/index.ts @@ -8,11 +8,11 @@ import { instance } from "../../instantiate"; import { ObjectItem } from "../../typings"; import { ILELibrarySettings } from "../CompileTools"; import { ConnectionManager } from "../Configuration"; -import { Tools } from "../Tools"; import { Env, getEnvConfig } from "../local/env"; import * as certificates from "./certificates"; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, resetDebugServiceDetails } from "./config"; import * as server from "./server"; +import { withContext } from "../../views/tools"; const debugExtensionId = `IBM.ibmidebug`; @@ -257,7 +257,7 @@ export async function initialize(context: ExtensionContext) { if (connection) { const doSetup = await vscode.window.showWarningMessage(`Do you confirm you want to generate or import a new certificate for the Debug Service?`, { modal: true }, 'Generate', 'Import'); if (doSetup) { - Tools.withContext("code-for-ibmi:debugWorking", async () => { + withContext("code-for-ibmi:debugWorking", async () => { if (!(await server.getDebugServiceJob()) || await server.stopService(connection)) { const debugConfig = await new DebugConfiguration(connection).load(); const clearResult = await connection.sendCommand({ command: `rm -f ${debugConfig.getRemoteServiceCertificatePath()} ${debugConfig.getRemoteClientCertificatePath()}` }); @@ -276,7 +276,7 @@ export async function initialize(context: ExtensionContext) { } }), vscode.commands.registerCommand(`code-for-ibmi.debug.setup.remote`, (doSetup?: 'Generate' | 'Import') => - Tools.withContext("code-for-ibmi:debugWorking", async () => { + withContext("code-for-ibmi:debugWorking", async () => { const connection = instance.getConnection(); if (connection) { const ptfInstalled = server.debugPTFInstalled(); @@ -336,7 +336,7 @@ export async function initialize(context: ExtensionContext) { vscode.commands.registerCommand(`code-for-ibmi.debug.setup.local`, () => vscode.window.withProgress({ title: "Downloading Debug Service Certificate", location: vscode.ProgressLocation.Window }, async () => - await Tools.withContext("code-for-ibmi:debugWorking", async () => { + await withContext("code-for-ibmi:debugWorking", async () => { const connection = instance.getConnection(); if (connection) { const ptfInstalled = server.debugPTFInstalled(); diff --git a/src/api/local/deployTools.ts b/src/api/local/deployTools.ts index 3eaacee73..befd59d15 100644 --- a/src/api/local/deployTools.ts +++ b/src/api/local/deployTools.ts @@ -3,9 +3,9 @@ import path, { basename } from 'path'; import vscode, { Uri, WorkspaceFolder } from 'vscode'; import { instance } from '../../instantiate'; import { DeploymentMethod, DeploymentParameters } from '../../typings'; -import { Tools } from '../Tools'; import { LocalLanguageActions } from './LocalLanguageActions'; import { Deployment } from './deployment'; +import { getGitAPI, md5Hash } from '../../views/tools'; type ServerFileChanges = { uploads: Uri[], relativeRemoteDeletes: string[] }; @@ -67,7 +67,7 @@ export namespace DeployTools { const changes = Deployment.workspaceChanges.get(folder)?.size || 0; methods.push({ method: "changed" as DeploymentMethod, label: `Changes`, description: `${changes} change${changes > 1 ? `s` : ``} detected since last upload. ${!changes ? `Will skip deploy step.` : ``}` }); - if (Tools.getGitAPI()) { + if (getGitAPI()) { methods.push( { method: "unstaged" as DeploymentMethod, label: `Working Changes`, description: `Unstaged changes in git` }, { method: "staged" as DeploymentMethod, label: `Staged Changes`, description: `` } @@ -215,7 +215,7 @@ export namespace DeployTools { export async function getDeployGitFiles(parameters: DeploymentParameters, changeType: 'staged' | 'working'): Promise { const useStagedChanges = (changeType == 'staged'); - const gitApi = Tools.getGitAPI(); + const gitApi = getGitAPI(); if (gitApi && gitApi.repositories.length > 0) { const repository = gitApi.repositories.find(r => r.rootUri.fsPath === parameters.workspaceFolder.uri.fsPath); @@ -273,7 +273,7 @@ export namespace DeployTools { const uploads: vscode.Uri[] = []; for await (const file of localFiles) { const remote = remoteMD5.find(e => e.path === file.path); - const md5 = Tools.md5Hash(file.uri); + const md5 = md5Hash(file.uri); if (!remote || remote.md5 !== md5) { uploads.push(file.uri); } diff --git a/src/api/local/git.ts b/src/api/local/git.ts index 01aabe314..38a3a047a 100644 --- a/src/api/local/git.ts +++ b/src/api/local/git.ts @@ -1,15 +1,15 @@ import { ExtensionContext, WorkspaceFolder, commands, window } from "vscode"; -import { Tools } from "../Tools"; import { getBranchLibraryName } from "./env"; import { instance } from "../../instantiate"; import { ConnectionConfiguration, GlobalConfiguration } from "../Configuration"; import IBMi from "../IBMi"; import IBMiContent from "../IBMiContent"; +import { getGitAPI } from "../../views/tools"; const lastBranch: { [workspaceUri: string]: string } = {}; export function getGitBranch(workspaceFolder: WorkspaceFolder) { - const gitApi = Tools.getGitAPI(); + const gitApi = getGitAPI(); if (gitApi) { const repo = gitApi.getRepository(workspaceFolder.uri); if (repo) { @@ -19,7 +19,7 @@ export function getGitBranch(workspaceFolder: WorkspaceFolder) { } export function setupGitEventHandler(context: ExtensionContext) { - const gitApi = Tools.getGitAPI(); + const gitApi = getGitAPI(); if (gitApi) { gitApi.onDidOpenRepository((repo) => { diff --git a/src/commands/actions.ts b/src/commands/actions.ts index 92d2e737c..1874d547c 100644 --- a/src/commands/actions.ts +++ b/src/commands/actions.ts @@ -1,10 +1,10 @@ import path from "path"; import { commands, TreeItem, Uri, WorkspaceFolder, window, Disposable } from "vscode"; -import { CompileTools } from "../api/CompileTools"; import { ConnectionConfiguration } from "../api/Configuration"; -import { refreshDiagnosticsFromServer } from "../api/errors/diagnostics"; +import { refreshDiagnosticsFromServer } from "../views/diagnostics"; import Instance from "../api/Instance"; import { BrowserItem, Action, DeploymentMethod } from "../typings"; +import { runAction } from "../views/actions"; export function registerActionsCommands(instance: Instance): Disposable[] { return [ @@ -55,7 +55,7 @@ export function registerActionsCommands(instance: Instance): Disposable[] { } if (canRun && [`member`, `streamfile`, `file`, 'object'].includes(uri.scheme)) { - return await CompileTools.runAction(instance, uri, action, method, browserItem, workspaceFolder); + return await runAction(instance, uri, action, method, browserItem, workspaceFolder); } } else { diff --git a/src/commands/open.ts b/src/commands/open.ts index f1b03eb31..22dce7202 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -1,12 +1,11 @@ import { commands, Disposable, l10n, QuickInputButton, QuickPickItem, QuickPickItemButtonEvent, QuickPickItemKind, Range, TextDocument, TextDocumentShowOptions, ThemeIcon, Uri, window } from "vscode"; -import IBMi from "../api/IBMi"; import { MemberItem, OpenEditableOptions, WithPath } from "../typings"; import Instance from "../api/Instance"; import { Tools } from "../api/Tools"; import { getUriFromPath, parseFSOptions } from "../filesystems/qsys/QSysFs"; import { DefaultOpenMode, GlobalConfiguration } from "../api/Configuration"; import path from "path"; -import { GetMemberInfo } from "../components/getMemberInfo"; +import { findExistingDocument, findExistingDocumentUri } from "../views/tools"; const CLEAR_RECENT = `$(trash) Clear recently opened`; const CLEAR_CACHED = `$(trash) Clear cached`; @@ -34,7 +33,7 @@ export function registerOpenCommands(instance: Instance): Disposable[] { const uri = getUriFromPath(path, options); - const existingUri = Tools.findExistingDocumentUri(uri); + const existingUri = findExistingDocumentUri(uri); if (existingUri) { const existingOptions = parseFSOptions(existingUri); @@ -87,7 +86,7 @@ export function registerOpenCommands(instance: Instance): Disposable[] { commands.registerCommand("code-for-ibmi.refreshFile", async (uri?: Uri) => { let doc: TextDocument | undefined; if (uri) { - doc = Tools.findExistingDocument(uri); + doc = findExistingDocument(uri); } else { const editor = window.activeTextEditor; doc = editor?.document; diff --git a/src/extension.ts b/src/extension.ts index 68612dc8b..2b21f7765 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,10 +6,7 @@ import { ExtensionContext, commands, languages, window, workspace } from "vscode import { CustomUI } from "./api/CustomUI"; import { instance, loadAllofExtension } from './instantiate'; - -import { CompileTools } from "./api/CompileTools"; import { ConnectionConfiguration, ConnectionManager, onCodeForIBMiConfigurationChange } from "./api/Configuration"; -import IBMi from "./api/IBMi"; import { GlobalStorage } from "./api/Storage"; import { Tools } from "./api/Tools"; import * as Debug from './api/debug'; @@ -35,6 +32,7 @@ import { initializeIFSBrowser } from "./views/ifsBrowser"; import { initializeObjectBrowser } from "./views/objectBrowser"; import { initializeSearchView } from "./views/searchView"; import { SettingsUI } from "./webviews/settings"; +import { registerActionTools } from "./views/actions"; export async function activate(context: ExtensionContext): Promise { // Use the console to output diagnostic information (console.log) and errors (console.error) @@ -87,7 +85,7 @@ export async function activate(context: ExtensionContext): Promise languages.registerCompletionItemProvider({ language: 'json', pattern: "**/.vscode/actions.json" }, new LocalActionCompletionItemProvider(), "&") ); - CompileTools.register(context); + registerActionTools(context); GlobalStorage.initialize(context); Debug.initialize(context); Deployment.initialize(context); diff --git a/src/filesystems/qsys/FSUtils.ts b/src/filesystems/qsys/FSUtils.ts index 6de89f0cf..edaf6cc36 100644 --- a/src/filesystems/qsys/FSUtils.ts +++ b/src/filesystems/qsys/FSUtils.ts @@ -2,7 +2,7 @@ import path from "path"; import vscode, { l10n } from "vscode"; import { GlobalConfiguration, ReconnectMode } from "../../api/Configuration"; import { GlobalStorage } from "../../api/Storage"; -import { Tools } from "../../api/Tools"; +import { findUriTabs } from "../../views/tools"; /** * Called when a member/streamfile is left open when VS Code is closed and re-opened to reconnect (or not) to the previous IBM i, based on the `autoReconnect` global configuration value. @@ -36,7 +36,7 @@ export async function reconnectFS(uri: vscode.Uri) { return true; } else { - for (const tab of Tools.findUriTabs(uri)) { + for (const tab of findUriTabs(uri)) { await vscode.window.tabGroups.close(tab); } return false; diff --git a/src/sandbox.ts b/src/sandbox.ts index 818760f29..f0cf54e5d 100644 --- a/src/sandbox.ts +++ b/src/sandbox.ts @@ -2,9 +2,9 @@ import { env } from "process"; import querystring from "querystring"; import { commands, ExtensionContext, l10n, Uri, window } from "vscode"; import { ConnectionConfiguration, ConnectionManager } from "./api/Configuration"; -import { Tools } from "./api/Tools"; import { instance } from "./instantiate"; import { ConnectionData } from "./typings"; +import { getGitAPI } from "./views/tools"; export async function registerUriHandler(context: ExtensionContext) { context.subscriptions.push( @@ -107,7 +107,7 @@ export async function handleStartup() { // If Sandbox mode is enabled, then the server and username can be inherited from the branch name if (env.VSCODE_IBMI_SANDBOX) { try { - const gitAPI = Tools.getGitAPI(); + const gitAPI = getGitAPI(); if (gitAPI && gitAPI.repositories && gitAPI.repositories.length > 0) { const repo = gitAPI.repositories[0]; const branchName = repo.state.HEAD?.name; diff --git a/src/testing/action.ts b/src/testing/action.ts index 37108c01c..109465281 100644 --- a/src/testing/action.ts +++ b/src/testing/action.ts @@ -11,6 +11,7 @@ import { getMemberUri, getUriFromPath } from "../filesystems/qsys/QSysFs"; import { instance } from "../instantiate"; import { Action, IBMiObject } from "../typings"; import { File, Folder, createFolder } from "./deployTools"; +import { runAction } from "../views/actions"; export const helloWorldProject: Folder = { name: `DeleteMe_${Tools.makeid()}`, @@ -92,7 +93,7 @@ export const ActionSuite: TestSuite = { name: `Create Display File (CRTDSPF)`, }; - const success = await CompileTools.runAction(instance, uri, action, `all`); + const success = await runAction(instance, uri, action, `all`); console.log(success); assert.ok(success); } @@ -157,7 +158,7 @@ export const ActionSuite: TestSuite = { ], }; const uri = getMemberUri({ library: tempLib, file: 'QRPGLESRC', name: 'THEBADONE', extension: 'RPGLE' }) - const success = await CompileTools.runAction(instance, uri, action, `all`); + const success = await runAction(instance, uri, action, `all`); assert.strictEqual(success, false); } } @@ -165,7 +166,7 @@ export const ActionSuite: TestSuite = { }; async function testHelloWorldProgram(uri: vscode.Uri, action: Action, library: string) { - const actionRan = await CompileTools.runAction(instance, uri, action, `all`); + const actionRan = await runAction(instance, uri, action, `all`); assert.ok(actionRan); const keysToCompare = [`library`, `name`, `type`, `text`, `attribute`, `sourceFile`, `memberCount`]; diff --git a/src/testing/deployTools.ts b/src/testing/deployTools.ts index 1fe76c6ad..84092ab09 100644 --- a/src/testing/deployTools.ts +++ b/src/testing/deployTools.ts @@ -6,11 +6,12 @@ import { EOL } from "os"; import { basename, posix } from "path"; import vscode from "vscode"; import { TestSuite } from "."; -import { CompileTools } from "../api/CompileTools"; import { Tools } from "../api/Tools"; import { DeployTools } from "../api/local/deployTools"; import { instance } from "../instantiate"; import { Action, DeploymentMethod } from "../typings"; +import { md5Hash } from "../views/tools"; +import { runAction } from "../views/actions"; type FileInfo = { md5: string @@ -162,7 +163,7 @@ export const DeployToolsSuite: TestSuite = { ] }; - await CompileTools.runAction(instance, vscode.Uri.joinPath(fakeProject.localPath!, "hello.txt"), action); + await runAction(instance, vscode.Uri.joinPath(fakeProject.localPath!, "hello.txt"), action); const localRoot = vscode.workspace.getWorkspaceFolder(fakeProject.localPath!)?.uri; assert.ok(localRoot, "No workspace folder"); @@ -259,7 +260,7 @@ async function getLocalFilesInfo() { const localFiles: FilesInfo = new Map; for await (const file of await vscode.workspace.findFiles(new vscode.RelativePattern(fakeProject.localPath!, "**/*"))) { const path = posix.join(basename(fakeProject.localPath!.path), posix.relative(fakeProject.localPath!.path, file.path)); - localFiles.set(path, { date: "unused", md5: Tools.md5Hash(file) }); + localFiles.set(path, { date: "unused", md5: md5Hash(file) }); } return localFiles; } diff --git a/src/typings.ts b/src/typings.ts index 210b6215a..0fbb10503 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -37,6 +37,7 @@ export interface StandardIO { export type ActionType = "member" | "streamfile" | "object" | "file"; export type ActionRefresh = "no" | "parent" | "filter" | "browser"; export type ActionEnvironment = "ile" | "qsh" | "pase"; +export type Variable = Record; export enum CcsidOrigin { User = "user", diff --git a/src/views/actions.ts b/src/views/actions.ts new file mode 100644 index 000000000..526d6470c --- /dev/null +++ b/src/views/actions.ts @@ -0,0 +1,650 @@ + +import path from 'path'; +import { EvfEventInfo, refreshDiagnosticsFromLocal, refreshDiagnosticsFromServer, registerDiagnostics } from './diagnostics'; +import { getLocalActions } from '../api/local/actions'; +import { DeployTools } from '../api/local/deployTools'; +import { getBranchLibraryName, getEnvConfig } from '../api/local/env'; +import { getGitBranch } from '../api/local/git'; +import Instance from '../api/Instance'; +import { parseFSOptions } from '../filesystems/qsys/QSysFs'; +import { Action, BrowserItem, DeploymentMethod, Variable } from '../typings'; +import { GlobalConfiguration } from '../api/Configuration'; + +import vscode, { CustomExecution, Pseudoterminal, TaskGroup, TaskRevealKind, WorkspaceFolder, commands, tasks } from 'vscode'; +import { CustomUI } from '../api/CustomUI'; +import { Tools } from '../api/Tools'; +import { CompileTools } from '../api/CompileTools'; + +interface CommandObject { + object: string + library?: string +} + +const actionUsed: Map = new Map; +const PARM_REGEX = /(PNLGRP|OBJ|PGM|MODULE)\((?.+?)\)/; + +export function registerActionTools(context: vscode.ExtensionContext) { + context.subscriptions.push( + ...registerDiagnostics() + ); +} + +export async function runAction(instance: Instance, uri: vscode.Uri, customAction?: Action, method?: DeploymentMethod, browserItem?: BrowserItem, workspaceFolder?: WorkspaceFolder): Promise { + const connection = instance.getConnection(); + + const uriOptions = parseFSOptions(uri); + if (connection) { + const config = connection.getConfig(); + const content = connection.getContent(); + + const extension = uri.path.substring(uri.path.lastIndexOf(`.`) + 1).toUpperCase(); + const fragment = uri.fragment.toUpperCase(); + + const isProtected = uriOptions.readonly || config?.readOnlyMode; + + if (!workspaceFolder) { + workspaceFolder = vscode.workspace.getWorkspaceFolder(uri); + } + let remoteCwd = config?.homeDirectory || `.`; + + let availableActions: { label: string; action: Action; }[] = []; + if (!customAction) { + // First we grab a copy the predefined Actions in the VS Code settings + const allActions = [...GlobalConfiguration.get(`actions`) || []]; + + // Then, if we're being called from a local file + // we fetch the Actions defined from the workspace. + if (workspaceFolder && uri.scheme === `file`) { + const localActions = await getLocalActions(workspaceFolder); + allActions.push(...localActions); + } + + // We make sure all extensions are uppercase + allActions.forEach(action => { + if (action.extensions) { + action.extensions = action.extensions.map(ext => ext.toUpperCase()); + }; + }); + + // Then we get all the available Actions for the current context + availableActions = allActions.filter(action => action.type === uri.scheme && (!action.extensions || action.extensions.includes(extension) || action.extensions.includes(fragment) || action.extensions.includes(`GLOBAL`)) && (!isProtected || action.runOnProtected)) + .sort((a, b) => (actionUsed.get(b.name) || 0) - (actionUsed.get(a.name) || 0)) + .map(action => ({ + label: action.name, + action + })); + } + + if (customAction || availableActions.length) { + const chosenAction = customAction || ((availableActions.length === 1) ? availableActions[0] : await vscode.window.showQuickPick(availableActions))?.action; + if (chosenAction) { + actionUsed.set(chosenAction.name, Date.now()); + const environment = chosenAction.environment || `ile`; + + let workspaceId: number | undefined = undefined; + + // If we are running an Action for a local file, we need a deploy directory even if they are not + // deploying the file. This is because we need to know the relative path of the file to the deploy directory. + if (workspaceFolder && chosenAction.type === `file`) { + if (chosenAction.deployFirst) { + const deployResult = await DeployTools.launchDeploy(workspaceFolder.index, method); + if (deployResult !== undefined) { + workspaceId = deployResult.workspaceId; + remoteCwd = deployResult.remoteDirectory; + } else { + vscode.window.showWarningMessage(`Action "${chosenAction.name}" was cancelled.`); + return false; + } + } else { + workspaceId = workspaceFolder.index; + const deployPath = DeployTools.getRemoteDeployDirectory(workspaceFolder); + if (deployPath) { + remoteCwd = deployPath; + } else { + vscode.window.showWarningMessage(`No deploy directory setup for this workspace. Cancelling Action.`); + return false; + } + } + } + + let fromWorkspace: WorkspaceFolder | undefined; + + if (chosenAction.type === `file` && vscode.workspace.workspaceFolders) { + fromWorkspace = vscode.workspace.workspaceFolders[workspaceId || 0]; + } + + const variables: Variable = {}; + const evfeventInfo: EvfEventInfo = { + object: '', + library: '', + extension, + workspace: fromWorkspace + }; + + if (workspaceFolder) { + const envFileVars = await getEnvConfig(workspaceFolder); + Object.entries(envFileVars).forEach(([key, value]) => variables[`&${key}`] = value); + } + + switch (chosenAction.type) { + case `member`: + const memberDetail = connection.parserMemberPath(uri.path); + evfeventInfo.library = memberDetail.library; + evfeventInfo.object = memberDetail.name; + evfeventInfo.extension = memberDetail.extension; + evfeventInfo.asp = memberDetail.asp; + + variables[`&OPENLIBL`] = memberDetail.library.toLowerCase(); + variables[`&OPENLIB`] = memberDetail.library; + + variables[`&OPENSPFL`] = memberDetail.file.toLowerCase(); + variables[`&OPENSPF`] = memberDetail.file; + + variables[`&OPENMBRL`] = memberDetail.name.toLowerCase(); + variables[`&OPENMBR`] = memberDetail.name; + + variables[`&EXTL`] = memberDetail.extension.toLowerCase(); + variables[`&EXT`] = memberDetail.extension; + break; + + case `file`: + case `streamfile`: + const pathData = path.parse(uri.path); + const basename = pathData.base; + const ext = pathData.ext ? (pathData.ext.startsWith(`.`) ? pathData.ext.substring(1) : pathData.ext) : ``; + const parent = path.parse(pathData.dir).base; + let name = pathData.name; + + // Logic to handle second extension, caused by bob. + const bobTypes = [`.PGM`, `.SRVPGM`]; + const secondName = path.parse(name); + if (secondName.ext && bobTypes.includes(secondName.ext.toUpperCase())) { + name = secondName.name; + } + + // Remove bob text convention + if (name.includes(`-`)) { + name = name.substring(0, name.indexOf(`-`)); + } + + if (variables[`&CURLIB`]) { + evfeventInfo.library = variables[`&CURLIB`]; + + } else { + evfeventInfo.library = config.currentLibrary; + } + + evfeventInfo.library = evfeventInfo.library.toUpperCase(); + evfeventInfo.object = name.toUpperCase(); + evfeventInfo.extension = ext; + + if (chosenAction.command.includes(`&SRCFILE`)) { + variables[`&SRCLIB`] = evfeventInfo.library; + variables[`&SRCPF`] = `QTMPSRC`; + variables[`&SRCFILE`] = `${evfeventInfo.library}/QTMPSRC`; + } + + switch (chosenAction.type) { + case `file`: + variables[`&LOCALPATH`] = uri.fsPath; + if (fromWorkspace) { + const relativePath = path.relative(fromWorkspace.uri.path, uri.path).split(path.sep).join(path.posix.sep); + variables[`&RELATIVEPATH`] = relativePath; + + // We need to make sure the remote path is posix + const fullPath = path.posix.join(remoteCwd, relativePath); + variables[`&FULLPATH`] = fullPath; + variables[`{path}`] = fullPath; + variables[`&WORKDIR`] = remoteCwd; + variables[`&FILEDIR`] = path.posix.parse(fullPath).dir; + + const branch = getGitBranch(fromWorkspace); + if (branch) { + variables[`&BRANCHLIB`] = getBranchLibraryName(branch); + variables[`&BRANCH`] = branch; + variables[`{branch}`] = branch; + } + } + break; + + case `streamfile`: + const relativePath = path.posix.relative(remoteCwd, uri.path); + variables[`&RELATIVEPATH`] = relativePath; + + const fullName = uri.path; + variables[`&FULLPATH`] = fullName; + variables[`&FILEDIR`] = path.parse(fullName).dir; + break; + } + + variables[`&PARENT`] = parent; + + variables[`&BASENAME`] = basename; + variables[`{filename}`] = basename; + + variables[`&NAMEL`] = name.toLowerCase(); + variables[`&NAME`] = name; + + variables[`&EXTL`] = extension.toLowerCase(); + variables[`&EXT`] = extension; + break; + + case `object`: + const [_, library, fullName] = uri.path.toUpperCase().split(`/`); + const object = fullName.substring(0, fullName.lastIndexOf(`.`)); + + evfeventInfo.library = library; + evfeventInfo.object = object; + + variables[`&LIBRARYL`] = library.toLowerCase(); + variables[`&LIBRARY`] = library; + + variables[`&NAMEL`] = object.toLowerCase(); + variables[`&NAME`] = object; + + variables[`&TYPEL`] = extension.toLowerCase(); + variables[`&TYPE`] = extension; + + variables[`&EXTL`] = extension.toLowerCase(); + variables[`&EXT`] = extension; + break; + } + + const viewControl = GlobalConfiguration.get(`postActionView`) || "none"; + const outputBuffer: string[] = []; + let actionName = chosenAction.name; + let hasRun = false; + + let commandString = chosenAction.command; + if (commandString) { + const commands = commandString.split(`\n`).filter(command => command.trim().length > 0); + const promptedCommands = []; + for (let command of commands) { + if (command.startsWith(`?`)) { + command = await vscode.window.showInputBox({ prompt: `Run Command`, value: command.substring(1) }) || ''; + } else { + command = await showCustomInputs(`Run Command`, command, chosenAction.name || `Command`); + } + promptedCommands.push(command); + if (!command) break; + } + commandString = !promptedCommands.includes(``) ? promptedCommands.join(`\n`) : ``; + } + + const exitCode = await new Promise(resolve => + tasks.executeTask({ + isBackground: true, + name: chosenAction.name, + definition: { type: `ibmi` }, + scope: workspaceFolder, + source: 'IBM i', + presentationOptions: { + showReuseMessage: true, + clear: GlobalConfiguration.get(`clearOutputEveryTime`), + focus: false, + reveal: (viewControl === `task` ? TaskRevealKind.Always : TaskRevealKind.Never), + }, + problemMatchers: [], + runOptions: {}, + group: TaskGroup.Build, + execution: new CustomExecution(async (e) => { + const writeEmitter = new vscode.EventEmitter(); + const closeEmitter = new vscode.EventEmitter(); + + writeEmitter.event(s => outputBuffer.push(s)); + closeEmitter.event(resolve); + + const term: Pseudoterminal = { + onDidWrite: writeEmitter.event, + onDidClose: closeEmitter.event, + open: async (initialDimensions: vscode.TerminalDimensions | undefined) => { + let successful = false; + let problemsFetched = false; + + try { + writeEmitter.fire(`Running Action: ${chosenAction.name} (${new Date().toLocaleTimeString()})` + CompileTools.NEWLINE); + + // If &SRCFILE is set, we need to copy the file to a temporary source file from the IFS + if (variables[`&FULLPATH`] && variables[`&SRCFILE`] && evfeventInfo.object) { + const [lib, srcpf] = variables[`&SRCFILE`].split(`/`); + + const createSourceFile = content.toCl(`CRTSRCPF`, { + rcdlen: 112, //NICE: this configurable in a VS Code setting? + file: `${lib}/${srcpf}`, + }); + + const copyFromStreamfile = content.toCl(`CPYFRMSTMF`, { + fromstmf: variables[`&FULLPATH`], + tombr: `'${Tools.qualifyPath(lib, srcpf, evfeventInfo.object)}'`, + mbropt: `*REPLACE`, + dbfccsid: `*FILE`, + stmfccsid: 1208, + }); + + // We don't care if this fails. Usually it's because the source file already exists. + await CompileTools.runCommand(connection, { command: createSourceFile, environment: `ile`, noLibList: true }); + + // Attempt to copy to member + const copyResult = await CompileTools.runCommand(connection, { command: copyFromStreamfile, environment: `ile`, noLibList: true }); + + if (copyResult.code !== 0) { + writeEmitter.fire(`Failed to copy file to a temporary member.\n\t${copyResult.stderr}\n\n`); + closeEmitter.fire(copyResult.code || 1); + } + } + + const commandResult = await CompileTools.runCommand(connection, { + title: chosenAction.name, + environment, + command: chosenAction.command, + cwd: remoteCwd, + env: variables, + }, (content) => writeEmitter.fire(content)); + + const useLocalEvfevent = + fromWorkspace && chosenAction.postDownload && + (chosenAction.postDownload.includes(`.evfevent`) || chosenAction.postDownload.includes(`.evfevent/`)); + + if (commandResult) { + hasRun = true; + const isIleCommand = environment === `ile`; + + const possibleObject = getObjectFromCommand(commandResult.command); + if (isIleCommand && possibleObject) { + Object.assign(evfeventInfo, possibleObject); + } + + actionName = (isIleCommand && possibleObject ? `${chosenAction.name} for ${evfeventInfo.library}/${evfeventInfo.object}` : actionName); + successful = (commandResult.code === 0 || commandResult.code === null); + + writeEmitter.fire(CompileTools.NEWLINE); + + if (useLocalEvfevent) { + writeEmitter.fire(`Fetching errors from .evfevent.${CompileTools.NEWLINE}`); + + } + else if (evfeventInfo.object && evfeventInfo.library) { + if (chosenAction.command.includes(`*EVENTF`)) { + writeEmitter.fire(`Fetching errors for ${evfeventInfo.library}/${evfeventInfo.object}.` + CompileTools.NEWLINE); + refreshDiagnosticsFromServer(instance, evfeventInfo); + problemsFetched = true; + } else { + writeEmitter.fire(`*EVENTF not found in command string. Not fetching errors for ${evfeventInfo.library}/${evfeventInfo.object}.` + CompileTools.NEWLINE); + } + } + } + + if (chosenAction.type === `file` && chosenAction.postDownload?.length) { + if (fromWorkspace) { + const remoteDir = remoteCwd; + const localDir = fromWorkspace.uri; + + const postDownloads: { type: vscode.FileType, localPath: string, remotePath: string }[] = []; + const downloadDirectories = new Set(); + for (const download of chosenAction.postDownload) { + const remotePath = path.posix.join(remoteDir, download); + const localPath = vscode.Uri.joinPath(localDir, download).path; + + let type: vscode.FileType; + if (await content.isDirectory(remotePath)) { + downloadDirectories.add(vscode.Uri.joinPath(localDir, download)); + type = vscode.FileType.Directory; + } + else { + const directory = path.parse(download).dir; + if (directory) { + downloadDirectories.add(vscode.Uri.joinPath(localDir, directory)); + } + type = vscode.FileType.File; + } + + postDownloads.push({ remotePath, localPath, type }) + } + + //Clear and create every local download directories + for (const downloadPath of downloadDirectories) { + try { + const stat = await vscode.workspace.fs.stat(downloadPath); //Check if target exists + if (stat.type !== vscode.FileType.Directory) { + if (await vscode.window.showWarningMessage(`${downloadPath} exists but is a file.`, "Delete and create directory")) { + await vscode.workspace.fs.delete(downloadPath); + throw new Error("Create directory"); + } + } + else if (stat.type === vscode.FileType.Directory) { + await vscode.workspace.fs.delete(downloadPath, { recursive: true }); + throw new Error("Create directory"); + } + } + catch (e) { + //Either fs.stat did not find the folder or it wasn't a folder and it's been deleted above + try { + await vscode.workspace.fs.createDirectory(downloadPath) + } + catch (error) { + vscode.window.showWarningMessage(`Failed to create download path ${downloadPath}: ${error}`); + console.log(error); + closeEmitter.fire(1); + } + } + } + + // Then we download the files that is specified. + const downloads = postDownloads.map( + async (postDownload) => { + const content = connection.getContent(); + if (postDownload.type === vscode.FileType.Directory) { + return content.downloadDirectory(postDownload.localPath, postDownload.remotePath, { recursive: true, concurrency: 5 }); + } else { + return content.downloadFile(postDownload.localPath, postDownload.remotePath); + } + } + ); + + await Promise.all(downloads) + .then(async result => { + // Done! + writeEmitter.fire(`Downloaded files as part of Action: ${chosenAction.postDownload!.join(`, `)}\n`); + + // Process locally downloaded evfevent files: + if (useLocalEvfevent) { + refreshDiagnosticsFromLocal(instance, evfeventInfo); + problemsFetched = true; + } + }) + .catch(error => { + vscode.window.showErrorMessage(`Failed to download files as part of Action.`); + writeEmitter.fire(`Failed to download a file after Action: ${error.message}\n`); + closeEmitter.fire(1); + }); + } + } + + if (problemsFetched && viewControl === `problems`) { + commands.executeCommand(`workbench.action.problems.focus`); + } + + } catch (e) { + writeEmitter.fire(`${e}\n`); + vscode.window.showErrorMessage(`Action ${chosenAction} for ${evfeventInfo.library}/${evfeventInfo.object} failed. (internal error).`); + closeEmitter.fire(1); + } + + closeEmitter.fire(successful ? 0 : 1); + }, + close: function (): void { } + }; + + return term; + }) + }) + ); + + const executionOK = (exitCode === 0); + if (hasRun) { + if (executionOK && browserItem) { + switch (chosenAction.refresh) { + case 'browser': + if (chosenAction.type === 'streamfile') { + vscode.commands.executeCommand("code-for-ibmi.refreshIFSBrowser"); + } + else if (chosenAction.type !== 'file') { + vscode.commands.executeCommand("code-for-ibmi.refreshObjectBrowser"); + } + break; + + case 'filter': + //Filter is a top level item so it has no parent (like Batman) + let filter: BrowserItem = browserItem; + while (filter.parent) { + filter = filter.parent; + } + filter.refresh?.(); + break; + + case 'parent': + browserItem.parent?.refresh?.(); + break; + + default: + //No refresh + } + } + + const openOutputAction = "Open output"; //TODO: will be translated in the future + const uiPromise = executionOK ? + vscode.window.showInformationMessage(`Action ${actionName} was successful.`, openOutputAction) : + vscode.window.showErrorMessage(`Action ${actionName} was not successful.`, openOutputAction); + + uiPromise.then(openOutput => { + if (openOutput) { + const now = new Date(); + new CustomUI() + .addParagraph(`
${outputBuffer.join("")}
`) + .setOptions({ fullWidth: true }) + .loadPage(`${chosenAction.name} [${now.toLocaleString()}]`); + } + }) + } + + return executionOK; + } + else { + return false; + } + } else if (isProtected) { + //when a member is protected(read only) + vscode.window.showErrorMessage(`Action cannot be applied on a read only member.`); + return false; + } else { + //No compile commands + vscode.window.showErrorMessage(`No compile commands found for ${uri.scheme}-${extension}.`); + return false; + } + } + else { + throw new Error("Please connect to an IBM i first") + } +} + +function getObjectFromCommand(baseCommand?: string): CommandObject | undefined { + if (baseCommand) { + const regex = PARM_REGEX.exec(baseCommand.toUpperCase()); + if (regex) { + const object = regex.groups?.object.split(`/`); + if (object) { + if (object.length === 2) { + return { + library: object[0], + object: object[1] + }; + } else { + return { + object: object[0] + }; + } + } + } + } +} + + + /** + * @param name action's name + * @param command action's command string + * @return the new command + */ + async function showCustomInputs(name: string, command: string, title?: string): Promise { + const components = []; + let loop = true; + + let end = 0; + while (loop) { + const idx = command.indexOf(`\${`, end); + + if (idx >= 0) { + const start = idx; + end = command.indexOf(`}`, start); + + if (end >= 0) { + let currentInput = command.substring(start + 2, end); + + const [name, label, initialValue] = currentInput.split(`|`); + components.push({ + name, + label, + initialValue: initialValue || ``, + start, + end: end + 1 + }); + } else { + loop = false; + } + } else { + loop = false; + } + } + + if (components.length) { + const commandUI = new CustomUI(); + + if (title) { + commandUI.addHeading(title, 2); + } + + for (const component of components) { + if (component.initialValue.includes(`,`)) { + //Select box + commandUI.addSelect(component.name, component.label, component.initialValue.split(`,`).map((value, index) => ( + { + selected: index === 0, + value, + description: value, + text: `Select ${value}`, + } + ))); + } else { + //Input box + commandUI.addInput(component.name, component.label, '', { default: component.initialValue }); + } + } + + commandUI.addButtons({ id: `execute`, label: `Execute` }, { id: `cancel`, label: `Cancel` }); + + const page = await commandUI.loadPage(name); + if (page) { + page.panel.dispose(); + if (page.data && page.data.buttons !== `cancel`) { + const dataEntries = Object.entries(page.data); + for (const component of components.reverse()) { + const value = dataEntries.find(([key]) => key === component.name)?.[1]; + command = command.substring(0, component.start) + value + command.substring(component.end); + } + } else { + command = ''; + } + } + } + + return command; + } \ No newline at end of file diff --git a/src/api/errors/diagnostics.ts b/src/views/diagnostics.ts similarity index 89% rename from src/api/errors/diagnostics.ts rename to src/views/diagnostics.ts index b029a18a1..2ced60a4b 100644 --- a/src/api/errors/diagnostics.ts +++ b/src/views/diagnostics.ts @@ -1,11 +1,11 @@ import * as vscode from "vscode"; -import { FileError } from "../../typings"; -import { GlobalConfiguration } from "../Configuration"; -import Instance from "../Instance"; -import { Tools } from "../Tools"; -import { getEvfeventFiles } from "../local/actions"; -import { parseErrors } from "./parser"; +import { FileError } from "../typings"; +import { GlobalConfiguration } from "../api/Configuration"; +import Instance from "../api/Instance"; +import { getEvfeventFiles } from "../api/local/actions"; +import { parseErrors } from "../api/errors/parser"; +import { findExistingDocumentByName, findExistingDocumentUri } from "./tools"; const ileDiagnostics = vscode.languages.createDiagnosticCollection(`ILE`); @@ -175,7 +175,7 @@ export function handleEvfeventLines(lines: string[], instance: Instance, evfeven // tabs like we do below. if (evfeventInfo.extension) { const baseName = file.split(`/`).pop(); - const openFile = Tools.findExistingDocumentByName(`${baseName}.${evfeventInfo.extension}`); + const openFile = findExistingDocumentByName(`${baseName}.${evfeventInfo.extension}`); if (openFile) { ileDiagnostics.set(openFile, diagnostics); continue; @@ -185,10 +185,10 @@ export function handleEvfeventLines(lines: string[], instance: Instance, evfeven } if (file.startsWith(`/`)) { - ileDiagnostics.set(Tools.findExistingDocumentUri(vscode.Uri.from({ scheme: `streamfile`, path: file })), diagnostics); + ileDiagnostics.set(findExistingDocumentUri(vscode.Uri.from({ scheme: `streamfile`, path: file })), diagnostics); } else { - const memberUri = Tools.findExistingDocumentUri(vscode.Uri.from({ scheme: `member`, path: `/${asp}${file}${evfeventInfo.extension ? `.` + evfeventInfo.extension : ``}` })); + const memberUri = findExistingDocumentUri(vscode.Uri.from({ scheme: `member`, path: `/${asp}${file}${evfeventInfo.extension ? `.` + evfeventInfo.extension : ``}` })); ileDiagnostics.set(memberUri, diagnostics); } } diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 7df552708..97b928121 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -10,6 +10,7 @@ import { isSEPSupported } from "../../api/debug/server"; import { extensionComponentRegistry } from "../../components/manager"; import { instance } from "../../instantiate"; import { ConnectionData, Server } from '../../typings'; +import { withContext } from "../../views/tools"; const EDITING_CONTEXT = `code-for-ibmi:editingConnection`; @@ -260,7 +261,7 @@ export class SettingsUI { .addHorizontalRule() .addButtons({ id: `save`, label: `Save settings`, requiresValidation: true }); - await Tools.withContext(EDITING_CONTEXT, async () => { + await withContext(EDITING_CONTEXT, async () => { const page = await ui.loadPage(`Settings: ${config.name}`); if (page) { page.panel.dispose(); @@ -373,7 +374,7 @@ export class SettingsUI { { id: `removeAuth`, label: vscode.l10n.t(`Remove auth methods`) } ); - await Tools.withContext(EDITING_CONTEXT, async () => { + await withContext(EDITING_CONTEXT, async () => { const page = await ui.loadPage(vscode.l10n.t(`Login Settings: "{0}"`, name)); if (page && page.data) { page.panel.dispose(); From ca5c86bd8d3c0a70f7c68d33c2f85c1fba4226e4 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 14:34:36 -0500 Subject: [PATCH 03/46] Remove vscode namespace from ibmi class Signed-off-by: worksofliam --- src/{api => }/Instance.ts | 58 +- src/api/IBMi.ts | 1418 +++++++++++++++-------------------- src/api/IBMiContent.ts | 4 +- src/api/Search.ts | 2 +- src/api/debug/index.ts | 2 +- src/commands/actions.ts | 2 +- src/commands/compare.ts | 2 +- src/commands/connection.ts | 2 +- src/commands/open.ts | 2 +- src/commands/password.ts | 2 +- src/instantiate.ts | 2 +- src/typings.ts | 2 +- src/views/actions.ts | 2 +- src/views/connection.ts | 200 +++++ src/views/diagnostics.ts | 2 +- src/views/helpView.ts | 20 +- src/webviews/login/index.ts | 4 +- 17 files changed, 877 insertions(+), 849 deletions(-) rename src/{api => }/Instance.ts (76%) create mode 100644 src/views/connection.ts diff --git a/src/api/Instance.ts b/src/Instance.ts similarity index 76% rename from src/api/Instance.ts rename to src/Instance.ts index 2005cb211..1373d075c 100644 --- a/src/api/Instance.ts +++ b/src/Instance.ts @@ -1,9 +1,10 @@ import * as vscode from "vscode"; -import { ConnectionData, IBMiEvent } from "../typings"; -import { ConnectionConfiguration } from "./Configuration"; -import IBMi, { ConnectionResult } from "./IBMi"; -import { ConnectionStorage, GlobalStorage } from "./Storage"; -import { withContext } from "../views/tools"; +import { ConnectionData, IBMiEvent } from "./typings"; +import { ConnectionConfiguration } from "./api/Configuration"; +import IBMi, { ConnectionResult } from "./api/IBMi"; +import { ConnectionStorage, GlobalStorage } from "./api/Storage"; +import { withContext } from "./views/tools"; +import { handleConnectionResults, messageCallback } from "./views/connection"; type IBMiEventSubscription = { func: Function, @@ -21,6 +22,7 @@ export interface ConnectionOptions { export default class Instance { private connection: IBMi | undefined; + private outputChannel: vscode.OutputChannel = vscode.window.createOutputChannel(`Code for IBM i`); private storage: ConnectionStorage; private emitter: vscode.EventEmitter = new vscode.EventEmitter(); private subscribers: Map = new Map; @@ -35,6 +37,11 @@ export default class Instance { connect(options: ConnectionOptions): Promise { const connection = new IBMi(); + this.outputChannel.clear(); + connection.appendOutput = (message) => { + this.outputChannel.append(message); + } + let result: ConnectionResult; const timeoutHandler = async (conn: IBMi) => { @@ -47,12 +54,13 @@ export default class Instance { let reconnect = choice === `Yes`; let collectLogs = choice === `No, get logs`; - if (collectLogs) { - const logs = conn.getOutputChannelContent(); - vscode.workspace.openTextDocument({ content: logs, language: `plaintext` }).then(doc => { - vscode.window.showTextDocument(doc); - }); - } + // TODO: how to get output channel stuff? + // if (collectLogs) { + // const logs = conn.getOutputChannelContent(); + // vscode.workspace.openTextDocument({ content: logs, language: `plaintext` }).then(doc => { + // vscode.window.showTextDocument(doc); + // }); + // } this.disconnect(); @@ -64,11 +72,27 @@ export default class Instance { return withContext("code-for-ibmi:connecting", async () => { while (true) { - try { - result = await connection.connect(options.data, options.reconnecting, options.reloadServerSettings, options.onConnectedOperations || [], timeoutHandler); - } catch (e: any) { - result = { success: false, error: e.message }; - } + let customError: string|undefined; + await vscode.window.withProgress({location: vscode.ProgressLocation.Notification, title: `Code for IBM i`}, async (p) => { + try { + result = await connection.connect( + options.data, + { + timeoutCallback: timeoutHandler, + onConnectedOperations: options.onConnectedOperations || [], + uiErrorHandler: handleConnectionResults, + progress: (message) => {p.report(message)}, + message: messageCallback, + }, + options.reconnecting, + options.reloadServerSettings, + + ); + } catch (e: any) { + customError = e.message; + result = { success: false }; + } + }); if (result.success) { await this.setConnection(connection); @@ -78,7 +102,7 @@ export default class Instance { await this.disconnect(); if (options.reconnecting && await vscode.window.showWarningMessage(`Could not reconnect`, { modal: true, - detail: `Reconnection has failed. Would you like to try again?\n\n${result.error || `No error provided.`}` + detail: `Reconnection has failed. Would you like to try again?\n\n${customError || `No error provided.`}` }, `Yes`)) { options.reconnecting = true; diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 358f34e6e..395884ddb 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -3,7 +3,6 @@ import { existsSync } from "fs"; import * as node_ssh from "node-ssh"; import os from "os"; import path, { parse as parsePath } from 'path'; -import * as vscode from "vscode"; import { IBMiComponent } from "../components/component"; import { CopyToImport } from "../components/copyToImport"; import { CustomQSh } from '../components/cqsh'; @@ -22,9 +21,12 @@ export interface MemberParts extends IBMiMember { basename: string } +export type ConnectionMessageType = 'info' | 'warning' | 'error'; +export type ConnectionErrorCode = `shell_config`|`home_directory_creation`|`QCPTOIMPF_exists`|`QCPFRMIMPF_exists`|`default_not_bash`|`invalid_bashrc`|`invalid_temp_lib`|`no_auto_conv_ebcdic`|`not_loaded_debug_config`|`no_sql_runner`|`ccsid_warning`; + export interface ConnectionResult { success: boolean, - error?: string + errorCodes?: ConnectionErrorCode[], } const remoteApps = [ // All names MUST also be defined as key in 'remoteFeatures' below!! @@ -52,6 +54,13 @@ const remoteApps = [ // All names MUST also be defined as key in 'remoteFeatures ]; type DisconnectCallback = (conn: IBMi) => Promise; +interface ConnectionCallbacks{ + onConnectedOperations?: Function[], + timeoutCallback?: (conn: IBMi) => Promise, + uiErrorHandler: (connection: IBMi, error: ConnectionErrorCode, data?: any) => Promise, + progress: (detail: {message: string}) => void, + message: (type: ConnectionMessageType, message: string) => void +} export default class IBMi { static readonly CCSID_NOCONVERSION = 65535; @@ -83,8 +92,6 @@ export default class IBMi { currentConnectionName: string = ``; private tempRemoteFiles: { [name: string]: string } = {}; defaultUserLibraries: string[] = []; - private outputChannel?: vscode.OutputChannel; - private outputChannelContent?: string; /** * Used to store ASP numbers and their names * Their names usually maps up to a directory in @@ -101,11 +108,13 @@ export default class IBMi { shell?: string; - private commandsExecuted = 0; - //Maximum admited length for command's argument - any command whose arguments are longer than this won't be executed by the shell maximumArgsLength = 0; + public appendOutput: (text: string) => void = (text) => { + process.stdout.write(text); + }; + private disconnectedCallback: (DisconnectCallback) | undefined; /** @@ -163,10 +172,6 @@ export default class IBMi { this.config = newConfig; } - getOutputChannelContent() { - return this.outputChannelContent; - } - constructor() { this.remoteFeatures = { git: undefined, @@ -203,906 +208,741 @@ export default class IBMi { /** * @returns {Promise<{success: boolean, error?: any}>} Was succesful at connecting or not. */ - async connect(connectionObject: ConnectionData, reconnecting?: boolean, reloadServerSettings: boolean = false, onConnectedOperations: Function[] = [], timeoutCallback?: (conn: IBMi) => Promise): Promise { + async connect(connectionObject: ConnectionData, callbacks: ConnectionCallbacks, reconnecting?: boolean, reloadServerSettings: boolean = false): Promise { const currentExtensionVersion = process.env.VSCODEIBMI_VERSION; try { connectionObject.keepaliveInterval = 35000; configVars.replaceAll(connectionObject); - return await vscode.window.withProgress({ - location: vscode.ProgressLocation.Notification, - title: `Connecting`, - cancellable: true - }, async (progress, cancelToken) => { - progress.report({ - message: `Connecting via SSH.` - }); - const delayedOperations: Function[] = [...onConnectedOperations]; + callbacks.progress({ + message: `Connecting via SSH.` + }); - this.client = new node_ssh.NodeSSH; - await this.client.connect({ - ...connectionObject, - privateKeyPath: connectionObject.privateKeyPath ? Tools.resolvePath(connectionObject.privateKeyPath) : undefined - } as node_ssh.Config); + const delayedOperations: Function[] = callbacks.onConnectedOperations ? [...callbacks.onConnectedOperations] : []; - cancelToken.onCancellationRequested(() => { - this.dispose(); - }); + this.client = new node_ssh.NodeSSH; + await this.client.connect({ + ...connectionObject, + privateKeyPath: connectionObject.privateKeyPath ? Tools.resolvePath(connectionObject.privateKeyPath) : undefined + } as node_ssh.Config); - this.currentConnectionName = connectionObject.name; - this.currentHost = connectionObject.host; - this.currentPort = connectionObject.port; - this.currentUser = connectionObject.username; + // cancelToken.onCancellationRequested(() => { + // this.dispose(); + // }); - if (this.outputChannel) { - this.appendOutput(`\n\nReconnecting to ${this.currentConnectionName}...\n\n`); + this.currentConnectionName = connectionObject.name; + this.currentHost = connectionObject.host; + this.currentPort = connectionObject.port; + this.currentUser = connectionObject.username; - } else { - this.outputChannel = vscode.window.createOutputChannel(`Code for IBM i: ${this.currentConnectionName}`); - } - - this.outputChannelContent = ''; - this.appendOutput(`Code for IBM i, version ${currentExtensionVersion}\n\n`); + this.appendOutput(`Code for IBM i, version ${currentExtensionVersion}\n\n`); - let tempLibrarySet = false; + let tempLibrarySet = false; - progress.report({ - message: `Loading configuration.` - }); + callbacks.progress({ + message: `Loading configuration.` + }); - //Load existing config - this.config = await ConnectionConfiguration.load(this.currentConnectionName); + //Load existing config + this.config = await ConnectionConfiguration.load(this.currentConnectionName); - // Load cached server settings. - const cachedServerSettings: CachedServerSettings = GlobalStorage.get().getServerSettingsCache(this.currentConnectionName); + // Load cached server settings. + const cachedServerSettings: CachedServerSettings = GlobalStorage.get().getServerSettingsCache(this.currentConnectionName); - // Reload server settings? - const quickConnect = () => { - return (this.config!.quickConnect === true && reloadServerSettings === false); - } + // Reload server settings? + const quickConnect = () => { + return (this.config!.quickConnect === true && reloadServerSettings === false); + } - // Check shell output for additional user text - this will confuse Code... - progress.report({ - message: `Checking shell output.` - }); + // Check shell output for additional user text - this will confuse Code... + callbacks.progress({ + message: `Checking shell output.` + }); - const checkShellText = `This should be the only text!`; - const checkShellResult = await this.sendCommand({ - command: `echo "${checkShellText}"`, - directory: `.` - }); - if (checkShellResult.stdout.split(`\n`)[0] !== checkShellText) { - const chosen = await vscode.window.showErrorMessage(`Error in shell configuration!`, { - detail: [ - `This extension can not work with the shell configured on ${this.currentConnectionName},`, - `since the output from shell commands have additional content.`, - `This can be caused by running commands like "echo" or other`, - `commands creating output in your shell start script.`, ``, - `The connection to ${this.currentConnectionName} will be aborted.` - ].join(`\n`), - modal: true - }, `Read more`); - - if (chosen === `Read more`) { - vscode.commands.executeCommand(`vscode.open`, `https://codefori.github.io/docs/#/pages/tips/setup`); - } + const checkShellText = `This should be the only text!`; + const checkShellResult = await this.sendCommand({ + command: `echo "${checkShellText}"`, + directory: `.` + }); + if (checkShellResult.stdout.split(`\n`)[0] !== checkShellText) { + callbacks.uiErrorHandler(this, `shell_config`); + return { + success: false + }; + } - throw (`Shell config error, connection aborted.`); + if (callbacks.timeoutCallback) { + const timeoutCallbackWrapper = () => { + // Don't call the callback function if it was based on a user cancellation request. + // if (!cancelToken.isCancellationRequested) { + // callbacks.timeoutCallback!(this); + // } } - if (timeoutCallback) { - const timeoutCallbackWrapper = () => { - // Don't call the callback function if it was based on a user cancellation request. - if (!cancelToken.isCancellationRequested) { - timeoutCallback(this); - } - } - - // Register handlers after we might have to abort due to bad configuration. - this.client.connection!.once(`timeout`, timeoutCallbackWrapper); - this.client.connection!.once(`end`, timeoutCallbackWrapper); - this.client.connection!.once(`error`, timeoutCallbackWrapper); - } + // Register handlers after we might have to abort due to bad configuration. + this.client.connection!.once(`timeout`, timeoutCallbackWrapper); + this.client.connection!.once(`end`, timeoutCallbackWrapper); + this.client.connection!.once(`error`, timeoutCallbackWrapper); + } - progress.report({ - message: `Checking home directory.` - }); + callbacks.progress({ + message: `Checking home directory.` + }); - let defaultHomeDir; + let defaultHomeDir; - const echoHomeResult = await this.sendCommand({ - command: `echo $HOME && cd && test -w $HOME`, - directory: `.` - }); - // Note: if the home directory does not exist, the behavior of the echo/cd/test command combo is as follows: - // - stderr contains 'Could not chdir to home directory /home/________: No such file or directory' - // (The output contains 'chdir' regardless of locale and shell, so maybe we could use that - // if we iterate on this code again in the future) - // - stdout contains the name of the home directory (even if it does not exist) - // - The 'cd' command causes an error if the home directory does not exist or otherwise can't be cd'ed into - // - The 'test' command causes an error if the home directory is not writable (one can cd into a non-writable directory) - let isHomeUsable = (0 == echoHomeResult.code); - if (isHomeUsable) { - defaultHomeDir = echoHomeResult.stdout.trim(); - } else { - // Let's try to provide more valuable information to the user about why their home directory - // is bad and maybe even provide the opportunity to create the home directory - - let actualHomeDir = echoHomeResult.stdout.trim(); - - // we _could_ just assume the home directory doesn't exist but maybe there's something more going on, namely mucked-up permissions - let doesHomeExist = (0 === (await this.sendCommand({ command: `test -e ${actualHomeDir}` })).code); - if (doesHomeExist) { - // Note: this logic might look backward because we fall into this (failure) leg on what looks like success (home dir exists). - // But, remember, but we only got here if 'cd $HOME' failed. - // Let's try to figure out why.... - if (0 !== (await this.sendCommand({ command: `test -d ${actualHomeDir}` })).code) { - await vscode.window.showWarningMessage(`Your home directory (${actualHomeDir}) is not a directory! Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: !reconnecting }); - } - else if (0 !== (await this.sendCommand({ command: `test -w ${actualHomeDir}` })).code) { - await vscode.window.showWarningMessage(`Your home directory (${actualHomeDir}) is not writable! Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: !reconnecting }); - } - else if (0 !== (await this.sendCommand({ command: `test -x ${actualHomeDir}` })).code) { - await vscode.window.showWarningMessage(`Your home directory (${actualHomeDir}) is not usable due to permissions! Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: !reconnecting }); - } - else { - // not sure, but get your sys admin involved - await vscode.window.showWarningMessage(`Your home directory (${actualHomeDir}) exists but is unusable. Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: !reconnecting }); - } + const echoHomeResult = await this.sendCommand({ + command: `echo $HOME && cd && test -w $HOME`, + directory: `.` + }); + // Note: if the home directory does not exist, the behavior of the echo/cd/test command combo is as follows: + // - stderr contains 'Could not chdir to home directory /home/________: No such file or directory' + // (The output contains 'chdir' regardless of locale and shell, so maybe we could use that + // if we iterate on this code again in the future) + // - stdout contains the name of the home directory (even if it does not exist) + // - The 'cd' command causes an error if the home directory does not exist or otherwise can't be cd'ed into + // - The 'test' command causes an error if the home directory is not writable (one can cd into a non-writable directory) + let isHomeUsable = (0 == echoHomeResult.code); + if (isHomeUsable) { + defaultHomeDir = echoHomeResult.stdout.trim(); + } else { + // Let's try to provide more valuable information to the user about why their home directory + // is bad and maybe even provide the opportunity to create the home directory + + let actualHomeDir = echoHomeResult.stdout.trim(); + + // we _could_ just assume the home directory doesn't exist but maybe there's something more going on, namely mucked-up permissions + let doesHomeExist = (0 === (await this.sendCommand({ command: `test -e ${actualHomeDir}` })).code); + if (doesHomeExist) { + // Note: this logic might look backward because we fall into this (failure) leg on what looks like success (home dir exists). + // But, remember, but we only got here if 'cd $HOME' failed. + // Let's try to figure out why.... + if (0 !== (await this.sendCommand({ command: `test -d ${actualHomeDir}` })).code) { + await callbacks.message(`warning`, `Your home directory (${actualHomeDir}) is not a directory! Code for IBM i may not function correctly. Please contact your system administrator.`); } - else if (reconnecting) { - vscode.window.showWarningMessage(`Your home directory (${actualHomeDir}) does not exist. Code for IBM i may not function correctly.`, { modal: false }); + else if (0 !== (await this.sendCommand({ command: `test -w ${actualHomeDir}` })).code) { + await callbacks.message(`warning`, `Your home directory (${actualHomeDir}) is not writable! Code for IBM i may not function correctly. Please contact your system administrator.`); } - else if (await vscode.window.showWarningMessage(`Home directory does not exist`, { - modal: true, - detail: `Your home directory (${actualHomeDir}) does not exist, so Code for IBM i may not function correctly. Would you like to create this directory now?`, - }, `Yes`)) { - this.appendOutput(`creating home directory ${actualHomeDir}`); - let mkHomeCmd = `mkdir -p ${actualHomeDir} && chown ${connectionObject.username.toLowerCase()} ${actualHomeDir} && chmod 0755 ${actualHomeDir}`; - let mkHomeResult = await this.sendCommand({ command: mkHomeCmd, directory: `.` }); - if (0 === mkHomeResult.code) { - defaultHomeDir = actualHomeDir; - } else { - let mkHomeErrs = mkHomeResult.stderr; - // We still get 'Could not chdir to home directory' in stderr so we need to hackily gut that out, as well as the bashisms that are a side effect of our API - mkHomeErrs = mkHomeErrs.substring(1 + mkHomeErrs.indexOf(`\n`)).replace(`bash: line 1: `, ``); - await vscode.window.showWarningMessage(`Error creating home directory (${actualHomeDir}):\n${mkHomeErrs}.\n\n Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: true }); - } + else if (0 !== (await this.sendCommand({ command: `test -x ${actualHomeDir}` })).code) { + await callbacks.message(`warning`, `Your home directory (${actualHomeDir}) is not usable due to permissions! Code for IBM i may not function correctly. Please contact your system administrator.`); } - } - - // Check to see if we need to store a new value for the home directory - if (defaultHomeDir) { - if (this.config.homeDirectory !== defaultHomeDir) { - this.config.homeDirectory = defaultHomeDir; - vscode.window.showInformationMessage(`Configured home directory reset to ${defaultHomeDir}.`); + else { + // not sure, but get your sys admin involved + await callbacks.message(`warning`, `Your home directory (${actualHomeDir}) exists but is unusable. Code for IBM i may not function correctly. Please contact your system administrator.`); } - } else { - // New connections always have `.` as the initial value. - // If we can't find a usable home directory, just reset it to - // the initial default. - this.config.homeDirectory = `.`; } - - //Set a default IFS listing - if (this.config.ifsShortcuts.length === 0) { - if (defaultHomeDir) { - this.config.ifsShortcuts = [this.config.homeDirectory]; - } else { - this.config.ifsShortcuts = [`/`]; + else if (reconnecting) { + callbacks.message(`warning`, `Your home directory (${actualHomeDir}) does not exist. Code for IBM i may not function correctly.`); + } + else { + const homedirCreated = await callbacks.uiErrorHandler(this, `home_directory_creation`, actualHomeDir); + if (homedirCreated) { + defaultHomeDir = actualHomeDir; } } + } - // If the version has changed (by update for example), then fetch everything again - if (cachedServerSettings?.lastCheckedOnVersion !== currentExtensionVersion) { - reloadServerSettings = true; + // Check to see if we need to store a new value for the home directory + if (defaultHomeDir) { + if (this.config.homeDirectory !== defaultHomeDir) { + this.config.homeDirectory = defaultHomeDir; + callbacks.message(`info`, `Configured home directory reset to ${defaultHomeDir}.`); } + } else { + // New connections always have `.` as the initial value. + // If we can't find a usable home directory, just reset it to + // the initial default. + this.config.homeDirectory = `.`; + } - // Check for installed components? - // For Quick Connect to work here, 'remoteFeatures' MUST have all features defined and no new properties may be added! - if (quickConnect() && cachedServerSettings?.remoteFeaturesKeys && cachedServerSettings.remoteFeaturesKeys === Object.keys(this.remoteFeatures).sort().toString()) { - Object.assign(this.remoteFeatures, cachedServerSettings.remoteFeatures); + //Set a default IFS listing + if (this.config.ifsShortcuts.length === 0) { + if (defaultHomeDir) { + this.config.ifsShortcuts = [this.config.homeDirectory]; } else { - progress.report({ - message: `Checking installed components on host IBM i.` - }); + this.config.ifsShortcuts = [`/`]; + } + } - // We need to check if our remote programs are installed. - remoteApps.push( - { - path: `/QSYS.lib/${this.upperCaseName(this.config.tempLibrary)}.lib/`, - names: [`GETNEWLIBL.PGM`], - specific: `GE*.PGM` - } - ); + // If the version has changed (by update for example), then fetch everything again + if (cachedServerSettings?.lastCheckedOnVersion !== currentExtensionVersion) { + reloadServerSettings = true; + } - //Next, we see what pase features are available (installed via yum) - //This may enable certain features in the future. - for (const feature of remoteApps) { - try { - progress.report({ - message: `Checking installed components on host IBM i: ${feature.path}` - }); + // Check for installed components? + // For Quick Connect to work here, 'remoteFeatures' MUST have all features defined and no new properties may be added! + if (quickConnect() && cachedServerSettings?.remoteFeaturesKeys && cachedServerSettings.remoteFeaturesKeys === Object.keys(this.remoteFeatures).sort().toString()) { + Object.assign(this.remoteFeatures, cachedServerSettings.remoteFeatures); + } else { + callbacks.progress({ + message: `Checking installed components on host IBM i.` + }); - const call = await this.sendCommand({ command: `ls -p ${feature.path}${feature.specific || ``}` }); - if (call.stdout) { - const files = call.stdout.split(`\n`); - - if (feature.specific) { - for (const name of feature.names) - this.remoteFeatures[name] = files.find(file => file.includes(name)); - } else { - for (const name of feature.names) - if (files.includes(name)) - this.remoteFeatures[name] = feature.path + name; - } - } - } catch (e) { - console.log(e); - } + // We need to check if our remote programs are installed. + remoteApps.push( + { + path: `/QSYS.lib/${this.upperCaseName(this.config.tempLibrary)}.lib/`, + names: [`GETNEWLIBL.PGM`], + specific: `GE*.PGM` } + ); - //Specific Java installations check - progress.report({ - message: `Checking installed components on host IBM i: Java` - }); - const javaCheck = async (root: string) => await this.content.testStreamFile(`${root}/bin/java`, 'x') ? root : undefined; - this.remoteFeatures.jdk80 = await javaCheck(`/QOpenSys/QIBM/ProdData/JavaVM/jdk80/64bit`); - this.remoteFeatures.jdk11 = await javaCheck(`/QOpenSys/QIBM/ProdData/JavaVM/jdk11/64bit`); - this.remoteFeatures.openjdk11 = await javaCheck(`/QOpensys/pkgs/lib/jvm/openjdk-11`); - this.remoteFeatures.jdk17 = await javaCheck(`/QOpenSys/QIBM/ProdData/JavaVM/jdk17/64bit`); - } + //Next, we see what pase features are available (installed via yum) + //This may enable certain features in the future. + for (const feature of remoteApps) { + try { + callbacks.progress({ + message: `Checking installed components on host IBM i: ${feature.path}` + }); - if (this.remoteFeatures.uname) { - progress.report({ - message: `Checking OS version.` - }); - const systemVersionResult = await this.sendCommand({ command: `${this.remoteFeatures.uname} -rv` }); + const call = await this.sendCommand({ command: `ls -p ${feature.path}${feature.specific || ``}` }); + if (call.stdout) { + const files = call.stdout.split(`\n`); - if (systemVersionResult.code === 0) { - const version = systemVersionResult.stdout.trim().split(` `); - this.systemVersion = Number(`${version[1]}.${version[0]}`); + if (feature.specific) { + for (const name of feature.names) + this.remoteFeatures[name] = files.find(file => file.includes(name)); + } else { + for (const name of feature.names) + if (files.includes(name)) + this.remoteFeatures[name] = feature.path + name; + } + } + } catch (e) { + console.log(e); } } - if (!this.systemVersion) { - vscode.window.showWarningMessage(`Unable to determine system version. Code for IBM i only supports 7.3 and above. Some features may not work correctly.`); - } else if (this.systemVersion < 7.3) { - vscode.window.showWarningMessage(`IBM i ${this.systemVersion} is not supported. Code for IBM i only supports 7.3 and above. Some features may not work correctly.`); - } + //Specific Java installations check + callbacks.progress({ + message: `Checking installed components on host IBM i: Java` + }); + const javaCheck = async (root: string) => await this.content.testStreamFile(`${root}/bin/java`, 'x') ? root : undefined; + this.remoteFeatures.jdk80 = await javaCheck(`/QOpenSys/QIBM/ProdData/JavaVM/jdk80/64bit`); + this.remoteFeatures.jdk11 = await javaCheck(`/QOpenSys/QIBM/ProdData/JavaVM/jdk11/64bit`); + this.remoteFeatures.openjdk11 = await javaCheck(`/QOpensys/pkgs/lib/jvm/openjdk-11`); + this.remoteFeatures.jdk17 = await javaCheck(`/QOpenSys/QIBM/ProdData/JavaVM/jdk17/64bit`); + } - progress.report({ message: `Checking Code for IBM i components.` }); - await this.componentManager.startup(); + if (this.remoteFeatures.uname) { + callbacks.progress({ + message: `Checking OS version.` + }); + const systemVersionResult = await this.sendCommand({ command: `${this.remoteFeatures.uname} -rv` }); - const componentStates = await this.componentManager.getState(); - this.appendOutput(`\nCode for IBM i components:\n`); - for (const state of componentStates) { - this.appendOutput(`\t${state.id.name} (${state.id.version}): ${state.state}\n`); + if (systemVersionResult.code === 0) { + const version = systemVersionResult.stdout.trim().split(` `); + this.systemVersion = Number(`${version[1]}.${version[0]}`); } - this.appendOutput(`\n`); + } - progress.report({ - message: `Checking library list configuration.` - }); + if (!this.systemVersion) { + callbacks.message(`warning`, `Unable to determine system version. Code for IBM i only supports 7.3 and above. Some features may not work correctly.`); + } else if (this.systemVersion < 7.3) { + callbacks.message(`warning`, `IBM i ${this.systemVersion} is not supported. Code for IBM i only supports 7.3 and above. Some features may not work correctly.`); + } - //Since the compiles are stateless, then we have to set the library list each time we use the `SYSTEM` command - //We setup the defaultUserLibraries here so we can remove them later on so the user can setup their own library list - let currentLibrary = `QGPL`; - this.defaultUserLibraries = []; + callbacks.progress({ message: `Checking Code for IBM i components.` }); + await this.componentManager.startup(); - const liblResult = await this.sendQsh({ - command: `liblist` - }); - if (liblResult.code === 0) { - const libraryListString = liblResult.stdout; - if (libraryListString !== ``) { - const libraryList = libraryListString.split(`\n`); - - let lib, type; - for (const line of libraryList) { - lib = line.substring(0, 10).trim(); - type = line.substring(12); - - switch (type) { - case `USR`: - this.defaultUserLibraries.push(lib); - break; + const componentStates = await this.componentManager.getState(); + this.appendOutput(`\nCode for IBM i components:\n`); + for (const state of componentStates) { + this.appendOutput(`\t${state.id.name} (${state.id.version}): ${state.state}\n`); + } + this.appendOutput(`\n`); - case `CUR`: - currentLibrary = lib; - break; - } - } + callbacks.progress({ + message: `Checking library list configuration.` + }); - //If this is the first time the config is made, then these arrays will be empty - if (this.config.currentLibrary.length === 0) { - this.config.currentLibrary = currentLibrary; - } - if (this.config.libraryList.length === 0) { - this.config.libraryList = this.defaultUserLibraries; + //Since the compiles are stateless, then we have to set the library list each time we use the `SYSTEM` command + //We setup the defaultUserLibraries here so we can remove them later on so the user can setup their own library list + let currentLibrary = `QGPL`; + this.defaultUserLibraries = []; + + const liblResult = await this.sendQsh({ + command: `liblist` + }); + if (liblResult.code === 0) { + const libraryListString = liblResult.stdout; + if (libraryListString !== ``) { + const libraryList = libraryListString.split(`\n`); + + let lib, type; + for (const line of libraryList) { + lib = line.substring(0, 10).trim(); + type = line.substring(12); + + switch (type) { + case `USR`: + this.defaultUserLibraries.push(lib); + break; + + case `CUR`: + currentLibrary = lib; + break; } } + + //If this is the first time the config is made, then these arrays will be empty + if (this.config.currentLibrary.length === 0) { + this.config.currentLibrary = currentLibrary; + } + if (this.config.libraryList.length === 0) { + this.config.libraryList = this.defaultUserLibraries; + } } + } - progress.report({ - message: `Checking temporary library configuration.` - }); + callbacks.progress({ + message: `Checking temporary library configuration.` + }); - //Next, we need to check the temp lib (where temp outfile data lives) exists - const createdTempLib = await this.runCommand({ - command: `CRTLIB LIB(${this.config.tempLibrary}) TEXT('Code for i temporary objects. May be cleared.')`, - noLibList: true - }); + //Next, we need to check the temp lib (where temp outfile data lives) exists + const createdTempLib = await this.runCommand({ + command: `CRTLIB LIB(${this.config.tempLibrary}) TEXT('Code for i temporary objects. May be cleared.')`, + noLibList: true + }); - if (createdTempLib.code === 0) { + if (createdTempLib.code === 0) { + tempLibrarySet = true; + } else { + const messages = Tools.parseMessages(createdTempLib.stderr); + if (messages.findId(`CPF2158`) || messages.findId(`CPF2111`)) { //Already exists, hopefully ok :) tempLibrarySet = true; - } else { - const messages = Tools.parseMessages(createdTempLib.stderr); - if (messages.findId(`CPF2158`) || messages.findId(`CPF2111`)) { //Already exists, hopefully ok :) - tempLibrarySet = true; - } - else if (messages.findId(`CPD0032`)) { //Can't use CRTLIB - const tempLibExists = await this.runCommand({ - command: `CHKOBJ OBJ(QSYS/${this.config.tempLibrary}) OBJTYPE(*LIB)`, - noLibList: true - }); + } + else if (messages.findId(`CPD0032`)) { //Can't use CRTLIB + const tempLibExists = await this.runCommand({ + command: `CHKOBJ OBJ(QSYS/${this.config.tempLibrary}) OBJTYPE(*LIB)`, + noLibList: true + }); - if (tempLibExists.code === 0) { - //We're all good if no errors - tempLibrarySet = true; - } else if (currentLibrary && !currentLibrary.startsWith(`Q`)) { - //Using ${currentLibrary} as the temporary library for temporary data. - this.config.tempLibrary = currentLibrary; - tempLibrarySet = true; - } + if (tempLibExists.code === 0) { + //We're all good if no errors + tempLibrarySet = true; + } else if (currentLibrary && !currentLibrary.startsWith(`Q`)) { + //Using ${currentLibrary} as the temporary library for temporary data. + this.config.tempLibrary = currentLibrary; + tempLibrarySet = true; } } + } - progress.report({ - message: `Checking temporary directory configuration.` - }); + callbacks.progress({ + message: `Checking temporary directory configuration.` + }); - let tempDirSet = false; - // Next, we need to check if the temp directory exists + let tempDirSet = false; + // Next, we need to check if the temp directory exists + let result = await this.sendCommand({ + command: `[ -d "${this.config.tempDir}" ]` + }); + + if (result.code === 0) { + // Directory exists + tempDirSet = true; + } else { + // Directory does not exist, try to create it let result = await this.sendCommand({ - command: `[ -d "${this.config.tempDir}" ]` + command: `mkdir -p ${this.config.tempDir}` }); - if (result.code === 0) { - // Directory exists + // Directory created tempDirSet = true; } else { - // Directory does not exist, try to create it - let result = await this.sendCommand({ - command: `mkdir -p ${this.config.tempDir}` - }); - if (result.code === 0) { - // Directory created - tempDirSet = true; - } else { - // Directory not created - } + // Directory not created } + } - if (!tempDirSet) { - this.config.tempDir = `/tmp`; - } + if (!tempDirSet) { + this.config.tempDir = `/tmp`; + } - if (tempLibrarySet && this.config.autoClearTempData) { - progress.report({ - message: `Clearing temporary data.` - }); + if (tempLibrarySet && this.config.autoClearTempData) { + callbacks.progress({ + message: `Clearing temporary data.` + }); - this.runCommand({ - command: `DLTOBJ OBJ(${this.config.tempLibrary}/O_*) OBJTYPE(*FILE)`, - noLibList: true, - }) - .then(result => { - // All good! - if (result && result.stderr) { - const messages = Tools.parseMessages(result.stderr); - if (!messages.findId(`CPF2125`)) { - // @ts-ignore We know the config exists. - vscode.window.showErrorMessage(`Temporary data not cleared from ${this.config.tempLibrary}.`, `View log`).then(async choice => { - if (choice === `View log`) { - this.outputChannel!.show(); - } - }); - } + this.runCommand({ + command: `DLTOBJ OBJ(${this.config.tempLibrary}/O_*) OBJTYPE(*FILE)`, + noLibList: true, + }) + .then(result => { + // All good! + if (result && result.stderr) { + const messages = Tools.parseMessages(result.stderr); + if (!messages.findId(`CPF2125`)) { + // @ts-ignore We know the config exists. + callbacks.message(`errror`, `Temporary data not cleared from ${this.config.tempLibrary}.`); } - }) + } + }) - this.sendCommand({ - command: `rm -rf ${path.posix.join(this.config.tempDir, `vscodetemp*`)}` + this.sendCommand({ + command: `rm -rf ${path.posix.join(this.config.tempDir, `vscodetemp*`)}` + }) + .then(result => { + // All good! }) - .then(result => { - // All good! - }) - .catch(e => { - // CPF2125: No objects deleted. - // @ts-ignore We know the config exists. - vscode.window.showErrorMessage(`Temporary data not cleared from ${this.config.tempDir}.`, `View log`).then(async choice => { - if (choice === `View log`) { - this.outputChannel!.show(); - } - }); - }); - } + .catch(e => { + // CPF2125: No objects deleted. + // @ts-ignore We know the config exists. + callbacks.message(`errror`, `Temporary data not cleared from ${this.config.tempDir}.`); + }); + } - const commandShellResult = await this.sendCommand({ - command: `echo $SHELL` - }); + const commandShellResult = await this.sendCommand({ + command: `echo $SHELL` + }); - if (commandShellResult.code === 0) { - this.shell = commandShellResult.stdout.trim(); - } + if (commandShellResult.code === 0) { + this.shell = commandShellResult.stdout.trim(); + } - // Check for bad data areas? - if (quickConnect() && cachedServerSettings?.badDataAreasChecked === true) { - // Do nothing, bad data areas are already checked. - } else { - progress.report({ - message: `Checking for bad data areas.` - }); + // Check for bad data areas? + if (quickConnect() && cachedServerSettings?.badDataAreasChecked === true) { + // Do nothing, bad data areas are already checked. + } else { + callbacks.progress({ + message: `Checking for bad data areas.` + }); - const QCPTOIMPF = await this.runCommand({ - command: `CHKOBJ OBJ(QSYS/QCPTOIMPF) OBJTYPE(*DTAARA)`, - noLibList: true - }); + const QCPTOIMPF = await this.runCommand({ + command: `CHKOBJ OBJ(QSYS/QCPTOIMPF) OBJTYPE(*DTAARA)`, + noLibList: true + }); - if (QCPTOIMPF?.code === 0) { - vscode.window.showWarningMessage(`The data area QSYS/QCPTOIMPF exists on this system and may impact Code for IBM i functionality.`, { - detail: `For V5R3, the code for the command CPYTOIMPF had a major design change to increase functionality and performance. The QSYS/QCPTOIMPF data area lets developers keep the pre-V5R2 version of CPYTOIMPF. Code for IBM i cannot function correctly while this data area exists.`, - modal: true, - }, `Delete`, `Read more`).then(choice => { - switch (choice) { - case `Delete`: - this.runCommand({ - command: `DLTOBJ OBJ(QSYS/QCPTOIMPF) OBJTYPE(*DTAARA)`, - noLibList: true - }) - .then((result) => { - if (result?.code === 0) { - vscode.window.showInformationMessage(`The data area QSYS/QCPTOIMPF has been deleted.`); - } else { - vscode.window.showInformationMessage(`Failed to delete the data area QSYS/QCPTOIMPF. Code for IBM i may not work as intended.`); - } - }) - break; - case `Read more`: - vscode.env.openExternal(vscode.Uri.parse(`https://github.com/codefori/vscode-ibmi/issues/476#issuecomment-1018908018`)); - break; - } - }); - } + if (QCPTOIMPF?.code === 0) { + callbacks.uiErrorHandler(this, `QCPTOIMPF_exists`); + } - const QCPFRMIMPF = await this.runCommand({ - command: `CHKOBJ OBJ(QSYS/QCPFRMIMPF) OBJTYPE(*DTAARA)`, - noLibList: true - }); + const QCPFRMIMPF = await this.runCommand({ + command: `CHKOBJ OBJ(QSYS/QCPFRMIMPF) OBJTYPE(*DTAARA)`, + noLibList: true + }); - if (QCPFRMIMPF?.code === 0) { - vscode.window.showWarningMessage(`The data area QSYS/QCPFRMIMPF exists on this system and may impact Code for IBM i functionality.`, { - modal: false, - }, `Delete`, `Read more`).then(choice => { - switch (choice) { - case `Delete`: - this.runCommand({ - command: `DLTOBJ OBJ(QSYS/QCPFRMIMPF) OBJTYPE(*DTAARA)`, - noLibList: true - }) - .then((result) => { - if (result?.code === 0) { - vscode.window.showInformationMessage(`The data area QSYS/QCPFRMIMPF has been deleted.`); - } else { - vscode.window.showInformationMessage(`Failed to delete the data area QSYS/QCPFRMIMPF. Code for IBM i may not work as intended.`); - } - }) - break; - case `Read more`: - vscode.env.openExternal(vscode.Uri.parse(`https://github.com/codefori/vscode-ibmi/issues/476#issuecomment-1018908018`)); - break; - } - }); - } + if (QCPFRMIMPF?.code === 0) { + callbacks.uiErrorHandler(this, `QCPFRMIMPF_exists`); } + } - // give user option to set bash as default shell. - if (this.remoteFeatures[`bash`]) { - try { - //check users default shell - - if (!commandShellResult.stderr) { - let usesBash = this.shell === IBMi.bashShellPath; - if (!usesBash) { - // make sure chsh is installed - if (this.remoteFeatures[`chsh`]) { - vscode.window.showInformationMessage(`IBM recommends using bash as your default shell.`, `Set shell to bash`, `Read More`,).then(async choice => { - switch (choice) { - case `Set shell to bash`: - const commandSetBashResult = await this.sendCommand({ - command: `/QOpenSys/pkgs/bin/chsh -s /QOpenSys/pkgs/bin/bash` - }); - - if (!commandSetBashResult.stderr) { - vscode.window.showInformationMessage(`Shell is now bash! Reconnect for change to take effect.`); - usesBash = true; - } else { - vscode.window.showInformationMessage(`Default shell WAS NOT changed to bash.`); - } - break; - - case `Read More`: - vscode.env.openExternal(vscode.Uri.parse(`https://ibmi-oss-docs.readthedocs.io/en/latest/user_setup/README.html#step-4-change-your-default-shell-to-bash`)); - break; - } - }); - } + // give user option to set bash as default shell. + if (this.remoteFeatures[`bash`]) { + try { + //check users default shell + + if (!commandShellResult.stderr) { + let usesBash = this.shell === IBMi.bashShellPath; + if (!usesBash) { + // make sure chsh is installed + if (this.remoteFeatures[`chsh`]) { + callbacks.uiErrorHandler(this, `default_not_bash`); } + } - if (usesBash) { - //Ensure /QOpenSys/pkgs/bin is found in $PATH - progress.report({ - message: `Checking /QOpenSys/pkgs/bin in $PATH.` - }); - - if ((!quickConnect || !cachedServerSettings?.pathChecked)) { - const currentPaths = (await this.sendCommand({ command: "echo $PATH" })).stdout.split(":"); - const bashrcFile = `${defaultHomeDir}/.bashrc`; - let bashrcExists = (await this.sendCommand({ command: `test -e ${bashrcFile}` })).code === 0; - let reason; - const requiredPaths = ["/QOpenSys/pkgs/bin", "/usr/bin", "/QOpenSys/usr/bin"] - let missingPath; - for (const requiredPath of requiredPaths) { - if (!currentPaths.includes(requiredPath)) { - reason = `Your $PATH shell environment variable does not include ${requiredPath}`; - missingPath = requiredPath - break; - } - } - // If reason is still undefined, then we know the user has all the required paths. Then we don't - // need to check for their existence before checking the order of the required paths. - if (!reason && - (currentPaths.indexOf("/QOpenSys/pkgs/bin") > currentPaths.indexOf("/usr/bin") - || (currentPaths.indexOf("/QOpenSys/pkgs/bin") > currentPaths.indexOf("/QOpenSys/usr/bin")))) { - reason = "/QOpenSys/pkgs/bin is not in the right position in your $PATH shell environment variable"; - missingPath = "/QOpenSys/pkgs/bin" - } - if (reason && await vscode.window.showWarningMessage(`${missingPath} not found in $PATH`, { - modal: true, - detail: `${reason}, so Code for IBM i may not function correctly. Would you like to ${bashrcExists ? "update" : "create"} ${bashrcFile} to fix this now?`, - }, `Yes`)) { - delayedOperations.push(async () => { - this.appendOutput(`${bashrcExists ? "update" : "create"} ${bashrcFile}`); - if (!bashrcExists) { - // Add "/usr/bin" and "/QOpenSys/usr/bin" to the end of the path. This way we know that the user has - // all the required paths, but we don't overwrite the priority of other items on their path. - const createBashrc = await this.sendCommand({ command: `echo "# Generated by Code for IBM i\nexport PATH=/QOpenSys/pkgs/bin:\\$PATH:/QOpenSys/usr/bin:/usr/bin" >> ${bashrcFile} && chown ${connectionObject.username.toLowerCase()} ${bashrcFile} && chmod 755 ${bashrcFile}` }); - if (createBashrc.code !== 0) { - vscode.window.showWarningMessage(`Error creating ${bashrcFile}):\n${createBashrc.stderr}.\n\n Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: true }); - } - } - else { - try { - const content = this.content; - if (content) { - const bashrcContent = (await content.downloadStreamfile(bashrcFile)).split("\n"); - let replaced = false; - bashrcContent.forEach((line, index) => { - if (!replaced) { - const pathRegex = /^((?:export )?PATH=)(.*)(?:)$/.exec(line); - if (pathRegex) { - bashrcContent[index] = `${pathRegex[1]}/QOpenSys/pkgs/bin:${pathRegex[2] - .replace("/QOpenSys/pkgs/bin", "") //Removes /QOpenSys/pkgs/bin wherever it is - .replace("::", ":")}:/QOpenSys/usr/bin:/usr/bin`; //Removes double : in case /QOpenSys/pkgs/bin wasn't at the end - replaced = true; - } - } - }); - - if (!replaced) { - bashrcContent.push( - "", - "# Generated by Code for IBM i", - "export PATH=/QOpenSys/pkgs/bin:$PATH:/QOpenSys/usr/bin:/usr/bin" - ); - } - - await content.writeStreamfile(bashrcFile, bashrcContent.join("\n")); - } - } - catch (error) { - vscode.window.showWarningMessage(`Error modifying PATH in ${bashrcFile}):\n${error}.\n\n Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: true }); - } - } - }); + if (usesBash) { + //Ensure /QOpenSys/pkgs/bin is found in $PATH + callbacks.progress({ + message: `Checking /QOpenSys/pkgs/bin in $PATH.` + }); + + if ((!quickConnect || !cachedServerSettings?.pathChecked)) { + const currentPaths = (await this.sendCommand({ command: "echo $PATH" })).stdout.split(":"); + const bashrcFile = `${defaultHomeDir}/.bashrc`; + let bashrcExists = (await this.sendCommand({ command: `test -e ${bashrcFile}` })).code === 0; + let reason; + const requiredPaths = ["/QOpenSys/pkgs/bin", "/usr/bin", "/QOpenSys/usr/bin"] + let missingPath; + for (const requiredPath of requiredPaths) { + if (!currentPaths.includes(requiredPath)) { + reason = `Your $PATH shell environment variable does not include ${requiredPath}`; + missingPath = requiredPath + break; } } + // If reason is still undefined, then we know the user has all the required paths. Then we don't + // need to check for their existence before checking the order of the required paths. + if (!reason && + (currentPaths.indexOf("/QOpenSys/pkgs/bin") > currentPaths.indexOf("/usr/bin") + || (currentPaths.indexOf("/QOpenSys/pkgs/bin") > currentPaths.indexOf("/QOpenSys/usr/bin")))) { + reason = "/QOpenSys/pkgs/bin is not in the right position in your $PATH shell environment variable"; + missingPath = "/QOpenSys/pkgs/bin" + } + + if (reason) { + callbacks.uiErrorHandler(this, `invalid_bashrc`, { missingPath, bashrcFile, bashrcExists, reason }); + } } } - } catch (e) { - // Oh well...trying to set default shell is not worth stopping for. - console.log(e); } + } catch (e) { + // Oh well...trying to set default shell is not worth stopping for. + console.log(e); } + } - if (this.config.autoConvertIFSccsid) { - if (this.remoteFeatures.attr === undefined || this.remoteFeatures.iconv === undefined) { - this.config.autoConvertIFSccsid = false; - vscode.window.showWarningMessage(`EBCDIC streamfiles will not be rendered correctly since \`attr\` or \`iconv\` is not installed on the host. They should both exist in \`\\usr\\bin\`.`); - } + if (this.config.autoConvertIFSccsid) { + if (this.remoteFeatures.attr === undefined || this.remoteFeatures.iconv === undefined) { + this.config.autoConvertIFSccsid = false; + callbacks.message(`warning`, `EBCDIC streamfiles will not be rendered correctly since \`attr\` or \`iconv\` is not installed on the host. They should both exist in \`\\usr\\bin\`.`); } + } - if (defaultHomeDir) { - if (!tempLibrarySet) { - vscode.window.showWarningMessage(`Code for IBM i will not function correctly until the temporary library has been corrected in the settings.`, `Open Settings`) - .then(result => { - switch (result) { - case `Open Settings`: - vscode.commands.executeCommand(`code-for-ibmi.showAdditionalSettings`); - break; - } - }); - } - } else { - vscode.window.showWarningMessage(`Code for IBM i may not function correctly until your user has a home directory.`); + if (defaultHomeDir) { + if (!tempLibrarySet) { + callbacks.uiErrorHandler(this, `invalid_temp_lib`); } + } else { + callbacks.message(`warning`, `Code for IBM i may not function correctly until your user has a home directory.`); + } - // Validate configured library list. - if (quickConnect() && cachedServerSettings?.libraryListValidated === true) { - // Do nothing, library list is already checked. - } else { - if (this.config.libraryList) { - progress.report({ - message: `Validate configured library list` - }); - let validLibs: string[] = []; - let badLibs: string[] = []; - - const result = await this.sendQsh({ - command: [ - `liblist -d ` + IBMi.escapeForShell(this.defaultUserLibraries.join(` `)), - ...this.config.libraryList.map(lib => `liblist -a ` + IBMi.escapeForShell(lib)) - ].join(`; `) - }); + // Validate configured library list. + if (quickConnect() && cachedServerSettings?.libraryListValidated === true) { + // Do nothing, library list is already checked. + } else { + if (this.config.libraryList) { + callbacks.progress({ + message: `Validate configured library list` + }); + let validLibs: string[] = []; + let badLibs: string[] = []; + + const result = await this.sendQsh({ + command: [ + `liblist -d ` + IBMi.escapeForShell(this.defaultUserLibraries.join(` `)), + ...this.config.libraryList.map(lib => `liblist -a ` + IBMi.escapeForShell(lib)) + ].join(`; `) + }); - if (result.stderr) { - const lines = result.stderr.split(`\n`); + if (result.stderr) { + const lines = result.stderr.split(`\n`); - lines.forEach(line => { - const badLib = this.config?.libraryList.find(lib => line.includes(`ibrary ${lib} `)); + lines.forEach(line => { + const badLib = this.config?.libraryList.find(lib => line.includes(`ibrary ${lib} `)); - // If there is an error about the library, store it - if (badLib) badLibs.push(badLib); - }); - } + // If there is an error about the library, store it + if (badLib) badLibs.push(badLib); + }); + } - if (result && badLibs.length > 0) { - validLibs = this.config.libraryList.filter(lib => !badLibs.includes(lib)); - const chosen = await vscode.window.showWarningMessage(`The following ${badLibs.length > 1 ? `libraries` : `library`} does not exist: ${badLibs.join(`,`)}. Remove ${badLibs.length > 1 ? `them` : `it`} from the library list?`, `Yes`, `No`); - if (chosen === `Yes`) { - this.config!.libraryList = validLibs; - } else { - vscode.window.showWarningMessage(`The following libraries does not exist: ${badLibs.join(`,`)}.`); - } - } + if (result && badLibs.length > 0) { + validLibs = this.config.libraryList.filter(lib => !badLibs.includes(lib)); + // Automatically cleanup bad libraries + this.config!.libraryList = validLibs; } } + } - let debugConfigLoaded = false - if ((!quickConnect || !cachedServerSettings?.debugConfigLoaded)) { - if (debugPTFInstalled()) { - try { - const debugServiceConfig = await new DebugConfiguration(this).load(); - delete this.config.debugCertDirectory; - this.config.debugPort = debugServiceConfig.getOrDefault("DBGSRV_SECURED_PORT", "8005"); - this.config.debugSepPort = debugServiceConfig.getOrDefault("DBGSRV_SEP_DAEMON_PORT", "8008"); - debugConfigLoaded = true; - } - catch (error) { - vscode.window.showWarningMessage(`Could not load debug service configuration: ${error}`); - } + let debugConfigLoaded = false + if ((!quickConnect || !cachedServerSettings?.debugConfigLoaded)) { + if (debugPTFInstalled()) { + try { + const debugServiceConfig = await new DebugConfiguration(this).load(); + delete this.config.debugCertDirectory; + this.config.debugPort = debugServiceConfig.getOrDefault("DBGSRV_SECURED_PORT", "8005"); + this.config.debugSepPort = debugServiceConfig.getOrDefault("DBGSRV_SEP_DAEMON_PORT", "8008"); + debugConfigLoaded = true; + } + catch (error) { + callbacks.message(`error`, `Could not load debug service configuration: ${error}`); } } + } - if ((!quickConnect || !cachedServerSettings?.maximumArgsLength)) { - //Compute the maximum admited length of a command's arguments. Source: Googling and https://www.in-ulm.de/~mascheck/various/argmax/#effectively_usable - this.maximumArgsLength = Number((await this.sendCommand({ command: "/QOpenSys/usr/bin/expr `/QOpenSys/usr/bin/getconf ARG_MAX` - `env|wc -c` - `env|wc -l` \\* 4 - 2048" })).stdout); - } - else { - this.maximumArgsLength = cachedServerSettings.maximumArgsLength; - } + if ((!quickConnect || !cachedServerSettings?.maximumArgsLength)) { + //Compute the maximum admited length of a command's arguments. Source: Googling and https://www.in-ulm.de/~mascheck/various/argmax/#effectively_usable + this.maximumArgsLength = Number((await this.sendCommand({ command: "/QOpenSys/usr/bin/expr `/QOpenSys/usr/bin/getconf ARG_MAX` - `env|wc -c` - `env|wc -l` \\* 4 - 2048" })).stdout); + } + else { + this.maximumArgsLength = cachedServerSettings.maximumArgsLength; + } - if (this.sqlRunnerAvailable()) { - // Check for ASP information? - if (quickConnect() && cachedServerSettings?.aspInfo) { - this.aspInfo = cachedServerSettings.aspInfo; - } else { - progress.report({ - message: `Checking for ASP information.` - }); + if (this.sqlRunnerAvailable()) { + // Check for ASP information? + if (quickConnect() && cachedServerSettings?.aspInfo) { + this.aspInfo = cachedServerSettings.aspInfo; + } else { + callbacks.progress({ + message: `Checking for ASP information.` + }); - //This is mostly a nice to have. We grab the ASP info so user's do - //not have to provide the ASP in the settings. - try { - const resultSet = await this.runSQL(`SELECT * FROM QSYS2.ASP_INFO`); - resultSet.forEach(row => { - if (row.DEVICE_DESCRIPTION_NAME && row.DEVICE_DESCRIPTION_NAME && row.DEVICE_DESCRIPTION_NAME !== `null`) { - this.aspInfo[Number(row.ASP_NUMBER)] = String(row.DEVICE_DESCRIPTION_NAME); - } - }); - } catch (e) { - //Oh well - progress.report({ - message: `Failed to get ASP information.` - }); - } + //This is mostly a nice to have. We grab the ASP info so user's do + //not have to provide the ASP in the settings. + try { + const resultSet = await this.runSQL(`SELECT * FROM QSYS2.ASP_INFO`); + resultSet.forEach(row => { + if (row.DEVICE_DESCRIPTION_NAME && row.DEVICE_DESCRIPTION_NAME && row.DEVICE_DESCRIPTION_NAME !== `null`) { + this.aspInfo[Number(row.ASP_NUMBER)] = String(row.DEVICE_DESCRIPTION_NAME); + } + }); + } catch (e) { + //Oh well + callbacks.progress({ + message: `Failed to get ASP information.` + }); } + } - // Fetch conversion values? - if (quickConnect() && cachedServerSettings?.jobCcsid !== null && cachedServerSettings?.userDefaultCCSID && cachedServerSettings?.qccsid) { - this.qccsid = cachedServerSettings.qccsid; - this.userJobCcsid = cachedServerSettings.jobCcsid; - this.userDefaultCCSID = cachedServerSettings.userDefaultCCSID; - } else { - progress.report({ - message: `Fetching conversion values.` - }); + // Fetch conversion values? + if (quickConnect() && cachedServerSettings?.jobCcsid !== null && cachedServerSettings?.userDefaultCCSID && cachedServerSettings?.qccsid) { + this.qccsid = cachedServerSettings.qccsid; + this.userJobCcsid = cachedServerSettings.jobCcsid; + this.userDefaultCCSID = cachedServerSettings.userDefaultCCSID; + } else { + callbacks.progress({ + message: `Fetching conversion values.` + }); - // Next, we're going to see if we can get the CCSID from the user or the system. - // Some things don't work without it!!! - try { + // Next, we're going to see if we can get the CCSID from the user or the system. + // Some things don't work without it!!! + try { - // we need to grab the system CCSID (QCCSID) - const [systemCCSID] = await this.runSQL(`select SYSTEM_VALUE_NAME, CURRENT_NUMERIC_VALUE from QSYS2.SYSTEM_VALUE_INFO where SYSTEM_VALUE_NAME = 'QCCSID'`); - if (typeof systemCCSID.CURRENT_NUMERIC_VALUE === 'number') { - this.qccsid = systemCCSID.CURRENT_NUMERIC_VALUE; - } + // we need to grab the system CCSID (QCCSID) + const [systemCCSID] = await this.runSQL(`select SYSTEM_VALUE_NAME, CURRENT_NUMERIC_VALUE from QSYS2.SYSTEM_VALUE_INFO where SYSTEM_VALUE_NAME = 'QCCSID'`); + if (typeof systemCCSID.CURRENT_NUMERIC_VALUE === 'number') { + this.qccsid = systemCCSID.CURRENT_NUMERIC_VALUE; + } - // we grab the users default CCSID - const [userInfo] = await this.runSQL(`select CHARACTER_CODE_SET_ID from table( QSYS2.QSYUSRINFO( USERNAME => upper('${this.currentUser}') ) )`); - if (userInfo.CHARACTER_CODE_SET_ID !== `null` && typeof userInfo.CHARACTER_CODE_SET_ID === 'number') { - this.userJobCcsid = userInfo.CHARACTER_CODE_SET_ID; - } + // we grab the users default CCSID + const [userInfo] = await this.runSQL(`select CHARACTER_CODE_SET_ID from table( QSYS2.QSYUSRINFO( USERNAME => upper('${this.currentUser}') ) )`); + if (userInfo.CHARACTER_CODE_SET_ID !== `null` && typeof userInfo.CHARACTER_CODE_SET_ID === 'number') { + this.userJobCcsid = userInfo.CHARACTER_CODE_SET_ID; + } - // if the job ccsid is *SYSVAL, then assign it to sysval - if (this.userJobCcsid === IBMi.CCSID_SYSVAL) { - this.userJobCcsid = this.qccsid; - } + // if the job ccsid is *SYSVAL, then assign it to sysval + if (this.userJobCcsid === IBMi.CCSID_SYSVAL) { + this.userJobCcsid = this.qccsid; + } - // Let's also get the user's default CCSID - try { - const [activeJob] = await this.runSQL(`Select DEFAULT_CCSID From Table(QSYS2.ACTIVE_JOB_INFO( JOB_NAME_FILTER => '*', DETAILED_INFO => 'ALL' ))`); - this.userDefaultCCSID = Number(activeJob.DEFAULT_CCSID); - } - catch (error) { - const [defaultCCSID] = (await this.runCommand({ command: "DSPJOB OPTION(*DFNA)" })) - .stdout - .split("\n") - .filter(line => line.includes("DFTCCSID")); - - const defaultCCSCID = Number(defaultCCSID.split("DFTCCSID").at(1)?.trim()); - if (defaultCCSCID && !isNaN(defaultCCSCID)) { - this.userDefaultCCSID = defaultCCSCID; - } + // Let's also get the user's default CCSID + try { + const [activeJob] = await this.runSQL(`Select DEFAULT_CCSID From Table(QSYS2.ACTIVE_JOB_INFO( JOB_NAME_FILTER => '*', DETAILED_INFO => 'ALL' ))`); + this.userDefaultCCSID = Number(activeJob.DEFAULT_CCSID); + } + catch (error) { + const [defaultCCSID] = (await this.runCommand({ command: "DSPJOB OPTION(*DFNA)" })) + .stdout + .split("\n") + .filter(line => line.includes("DFTCCSID")); + + const defaultCCSCID = Number(defaultCCSID.split("DFTCCSID").at(1)?.trim()); + if (defaultCCSCID && !isNaN(defaultCCSCID)) { + this.userDefaultCCSID = defaultCCSCID; } - - } catch (e) { - // Oh well! - console.log(e); } + + } catch (e) { + // Oh well! + console.log(e); } + } - let userCcsidNeedsFixing = false; - let sshdCcsidMismatch = false; + let userCcsidNeedsFixing = false; + let sshdCcsidMismatch = false; - const showCcsidWarning = (message: string) => { - vscode.window.showWarningMessage(message, `Show documentation`).then(choice => { - if (choice === `Show documentation`) { - vscode.commands.executeCommand(`vscode.open`, `https://codefori.github.io/docs/tips/ccsid/`); - } - }); - } + const showCcsidWarning = (message: string) => { + callbacks.uiErrorHandler(this, `ccsid_warning`, message); + } - if (this.canUseCqsh) { - // If cqsh is available, but the user profile CCSID is bad, then cqsh won't work - if (this.getCcsid() === IBMi.CCSID_NOCONVERSION) { - userCcsidNeedsFixing = true; - } + if (this.canUseCqsh) { + // If cqsh is available, but the user profile CCSID is bad, then cqsh won't work + if (this.getCcsid() === IBMi.CCSID_NOCONVERSION) { + userCcsidNeedsFixing = true; } + } - else { - // If cqsh is not available, then we need to check the SSHD CCSID - this.sshdCcsid = await this.content.getSshCcsid(); - if (this.sshdCcsid === this.getCcsid()) { - // If the SSHD CCSID matches the job CCSID (not the user profile!), then we're good. - // This means we can use regular qsh without worrying about translation because the SSHD and job CCSID match. - userCcsidNeedsFixing = false; - } else { - // If the SSHD CCSID does not match the job CCSID, then we need to warn the user - sshdCcsidMismatch = true; - } + else { + // If cqsh is not available, then we need to check the SSHD CCSID + this.sshdCcsid = await this.content.getSshCcsid(); + if (this.sshdCcsid === this.getCcsid()) { + // If the SSHD CCSID matches the job CCSID (not the user profile!), then we're good. + // This means we can use regular qsh without worrying about translation because the SSHD and job CCSID match. + userCcsidNeedsFixing = false; + } else { + // If the SSHD CCSID does not match the job CCSID, then we need to warn the user + sshdCcsidMismatch = true; } + } - if (userCcsidNeedsFixing) { - showCcsidWarning(`The job CCSID is set to ${IBMi.CCSID_NOCONVERSION}. This may cause issues with objects with variant characters. Please use CHGUSRPRF USER(${this.currentUser.toUpperCase()}) CCSID(${this.userDefaultCCSID}) to set your profile to the current default CCSID.`); - } else if (sshdCcsidMismatch) { - showCcsidWarning(`The CCSID of the SSH connection (${this.sshdCcsid}) does not match the job CCSID (${this.getCcsid()}). This may cause issues with objects with variant characters.`); - } + if (userCcsidNeedsFixing) { + showCcsidWarning(`The job CCSID is set to ${IBMi.CCSID_NOCONVERSION}. This may cause issues with objects with variant characters. Please use CHGUSRPRF USER(${this.currentUser.toUpperCase()}) CCSID(${this.userDefaultCCSID}) to set your profile to the current default CCSID.`); + } else if (sshdCcsidMismatch) { + showCcsidWarning(`The CCSID of the SSH connection (${this.sshdCcsid}) does not match the job CCSID (${this.getCcsid()}). This may cause issues with objects with variant characters.`); + } - this.appendOutput(`\nCCSID information:\n`); - this.appendOutput(`\tQCCSID: ${this.qccsid}\n`); - this.appendOutput(`\tUser Job CCSID: ${this.userJobCcsid}\n`); - this.appendOutput(`\tUser Default CCSID: ${this.userDefaultCCSID}\n`); - if (this.sshdCcsid) { - this.appendOutput(`\tSSHD CCSID: ${this.sshdCcsid}\n`); - } + this.appendOutput(`\nCCSID information:\n`); + this.appendOutput(`\tQCCSID: ${this.qccsid}\n`); + this.appendOutput(`\tUser Job CCSID: ${this.userJobCcsid}\n`); + this.appendOutput(`\tUser Default CCSID: ${this.userDefaultCCSID}\n`); + if (this.sshdCcsid) { + this.appendOutput(`\tSSHD CCSID: ${this.sshdCcsid}\n`); + } - // We only do this check if we're on 7.3 or below. - if (this.systemVersion && this.systemVersion <= 7.3) { - progress.report({ - message: `Checking PASE locale environment variables.` - }); + // We only do this check if we're on 7.3 or below. + if (this.systemVersion && this.systemVersion <= 7.3) { + callbacks.progress({ + message: `Checking PASE locale environment variables.` + }); - const systemEnvVars = await this.content.getSysEnvVars(); + const systemEnvVars = await this.content.getSysEnvVars(); - const paseLang = systemEnvVars.PASE_LANG; - const paseCcsid = systemEnvVars.QIBM_PASE_CCSID; + const paseLang = systemEnvVars.PASE_LANG; + const paseCcsid = systemEnvVars.QIBM_PASE_CCSID; - if (paseLang === undefined || paseCcsid === undefined) { - showCcsidWarning(`The PASE environment variables PASE_LANG and QIBM_PASE_CCSID are not set correctly and is required for this OS version (${this.systemVersion}). This may cause issues with objects with variant characters.`); - } else if (paseCcsid !== `1208`) { - showCcsidWarning(`The PASE environment variable QIBM_PASE_CCSID is not set to 1208 and is required for this OS version (${this.systemVersion}). This may cause issues with objects with variant characters.`); - } + if (paseLang === undefined || paseCcsid === undefined) { + showCcsidWarning(`The PASE environment variables PASE_LANG and QIBM_PASE_CCSID are not set correctly and is required for this OS version (${this.systemVersion}). This may cause issues with objects with variant characters.`); + } else if (paseCcsid !== `1208`) { + showCcsidWarning(`The PASE environment variable QIBM_PASE_CCSID is not set to 1208 and is required for this OS version (${this.systemVersion}). This may cause issues with objects with variant characters.`); } + } - // We always need to fetch the local variants because - // now we pickup CCSID changes faster due to cqsh - progress.report({ - message: `Fetching local encoding values.` - }); + // We always need to fetch the local variants because + // now we pickup CCSID changes faster due to cqsh + callbacks.progress({ + message: `Fetching local encoding values.` + }); - const [variants] = await this.runSQL(`With VARIANTS ( HASH, AT, DOLLARSIGN ) as (` - + ` values ( cast( x'7B' as varchar(1) )` - + ` , cast( x'7C' as varchar(1) )` - + ` , cast( x'5B' as varchar(1) ) )` - + `)` - + `Select HASH concat AT concat DOLLARSIGN as LOCAL from VARIANTS`); + const [variants] = await this.runSQL(`With VARIANTS ( HASH, AT, DOLLARSIGN ) as (` + + ` values ( cast( x'7B' as varchar(1) )` + + ` , cast( x'7C' as varchar(1) )` + + ` , cast( x'5B' as varchar(1) ) )` + + `)` + + `Select HASH concat AT concat DOLLARSIGN as LOCAL from VARIANTS`); - if (typeof variants.LOCAL === 'string' && variants.LOCAL !== `null`) { - this.variantChars.local = variants.LOCAL; - } - } else { - vscode.window.showWarningMessage(`The SQL runner is not available. This could mean that VS Code will not work for this connection. See our documentation for more information.`) + if (typeof variants.LOCAL === 'string' && variants.LOCAL !== `null`) { + this.variantChars.local = variants.LOCAL; } + } else { + callbacks.message(`warning`, `The SQL runner is not available. This could mean that VS Code will not work for this connection. See our documentation for more information.`) + } - if (!reconnecting) { - for (const operation of delayedOperations) { - await operation(); - } + if (!reconnecting) { + for (const operation of delayedOperations) { + await operation(); } + } - GlobalStorage.get().setServerSettingsCache(this.currentConnectionName, { - lastCheckedOnVersion: currentExtensionVersion, - aspInfo: this.aspInfo, - qccsid: this.qccsid, - jobCcsid: this.userJobCcsid, - remoteFeatures: this.remoteFeatures, - remoteFeaturesKeys: Object.keys(this.remoteFeatures).sort().toString(), - badDataAreasChecked: true, - libraryListValidated: true, - pathChecked: true, - userDefaultCCSID: this.userDefaultCCSID, - debugConfigLoaded, - maximumArgsLength: this.maximumArgsLength - }); - - return { - success: true - }; + GlobalStorage.get().setServerSettingsCache(this.currentConnectionName, { + lastCheckedOnVersion: currentExtensionVersion, + aspInfo: this.aspInfo, + qccsid: this.qccsid, + jobCcsid: this.userJobCcsid, + remoteFeatures: this.remoteFeatures, + remoteFeaturesKeys: Object.keys(this.remoteFeatures).sort().toString(), + badDataAreasChecked: true, + libraryListValidated: true, + pathChecked: true, + userDefaultCCSID: this.userDefaultCCSID, + debugConfigLoaded, + maximumArgsLength: this.maximumArgsLength }); + return { + success: true + }; + } catch (e: any) { this.disconnect(true); @@ -1118,8 +958,7 @@ export default class IBMi { } return { - success: false, - error + success: false }; } finally { @@ -1194,13 +1033,10 @@ export default class IBMi { const command = commands.join(` && `); const directory = options.directory || this.config?.homeDirectory; - this.determineClear() - if (this.outputChannel) { - this.appendOutput(`${directory}: ${command}\n`); - if (options && options.stdin) { - this.appendOutput(`${options.stdin}\n`); - } + this.appendOutput(`${directory}: ${command}\n`); + if (options && options.stdin) { + this.appendOutput(`${options.stdin}\n`); } const result = await this.client!.execCommand(command, { @@ -1221,29 +1057,6 @@ export default class IBMi { }; } - private appendOutput(content: string) { - if (this.outputChannel) { - this.outputChannel.append(content); - } - if (this.outputChannelContent !== undefined) { - this.outputChannelContent += content; - } - } - - private determineClear() { - if (this.commandsExecuted > 150) { - if (this.outputChannel) { - this.outputChannel.clear(); - } - if (this.outputChannelContent !== undefined) { - this.outputChannelContent = ''; - } - this.commandsExecuted = 0; - } - - this.commandsExecuted += 1; - } - private disconnect(failedToConnect = false) { if (this.client) { this.client = undefined; @@ -1256,15 +1069,6 @@ export default class IBMi { async dispose() { this.disconnect(); - - if (this.outputChannel) { - this.outputChannel.hide(); - this.outputChannel.dispose(); - } - - if (this.outputChannelContent !== undefined) { - this.outputChannelContent = undefined; - } } /** diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index b01b9d136..4a0d503c8 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -4,7 +4,6 @@ import path from 'path'; import tmp from 'tmp'; import util from 'util'; import * as node_ssh from "node-ssh"; -import { MarkdownString, Uri, window } from 'vscode'; import { GetMemberInfo } from '../components/getMemberInfo'; import { ObjectTypes } from '../filesystems/qsys/Objects'; import { AttrOperands, CommandResult, IBMiError, IBMiMember, IBMiObject, IFSFile, QsysPath, SpecialAuthorities } from '../typings'; @@ -247,7 +246,8 @@ export default class IBMiContent { if (copyResult.code === 0) { const messages = Tools.parseMessages(copyResult.stderr); if (messages.findId("CPIA083")) { - window.showWarningMessage(`${library}/${sourceFile}(${member}) was saved with truncated records!`); + // TODO: what do we do about this, really? + // window.showWarningMessage(`${library}/${sourceFile}(${member}) was saved with truncated records!`); } return true; } else { diff --git a/src/api/Search.ts b/src/api/Search.ts index 57b153085..92f3b0512 100644 --- a/src/api/Search.ts +++ b/src/api/Search.ts @@ -2,7 +2,7 @@ import * as path from 'path'; import { GetMemberInfo } from '../components/getMemberInfo'; import { IBMiMember, SearchHit, SearchResults } from '../typings'; import { GlobalConfiguration } from './Configuration'; -import Instance from './Instance'; +import Instance from '../Instance'; import { Tools } from './Tools'; export namespace Search { diff --git a/src/api/debug/index.ts b/src/api/debug/index.ts index 0845bcd1b..fd9ccabaa 100644 --- a/src/api/debug/index.ts +++ b/src/api/debug/index.ts @@ -1,5 +1,5 @@ import { ExtensionContext, Uri } from "vscode"; -import Instance from "../Instance"; +import Instance from "../../Instance"; import path from "path"; import * as vscode from 'vscode'; diff --git a/src/commands/actions.ts b/src/commands/actions.ts index 1874d547c..ca2ed7cf7 100644 --- a/src/commands/actions.ts +++ b/src/commands/actions.ts @@ -2,7 +2,7 @@ import path from "path"; import { commands, TreeItem, Uri, WorkspaceFolder, window, Disposable } from "vscode"; import { ConnectionConfiguration } from "../api/Configuration"; import { refreshDiagnosticsFromServer } from "../views/diagnostics"; -import Instance from "../api/Instance"; +import Instance from "../Instance"; import { BrowserItem, Action, DeploymentMethod } from "../typings"; import { runAction } from "../views/actions"; diff --git a/src/commands/compare.ts b/src/commands/compare.ts index ded0df5a5..edc50de6e 100644 --- a/src/commands/compare.ts +++ b/src/commands/compare.ts @@ -1,5 +1,5 @@ import { commands, window, Uri, l10n, Disposable } from "vscode"; -import Instance from "../api/Instance"; +import Instance from "../Instance"; let selectedForCompare: Uri; diff --git a/src/commands/connection.ts b/src/commands/connection.ts index 2bdbb9ae7..cdc06f80f 100644 --- a/src/commands/connection.ts +++ b/src/commands/connection.ts @@ -1,6 +1,6 @@ import { commands, Disposable, ExtensionContext, window } from "vscode"; import { ConnectionManager } from "../api/Configuration"; -import Instance from "../api/Instance"; +import Instance from "../Instance"; import { ConnectionData } from "../typings"; import { safeDisconnect } from "../instantiate"; diff --git a/src/commands/open.ts b/src/commands/open.ts index 22dce7202..88cd07356 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -1,6 +1,6 @@ import { commands, Disposable, l10n, QuickInputButton, QuickPickItem, QuickPickItemButtonEvent, QuickPickItemKind, Range, TextDocument, TextDocumentShowOptions, ThemeIcon, Uri, window } from "vscode"; import { MemberItem, OpenEditableOptions, WithPath } from "../typings"; -import Instance from "../api/Instance"; +import Instance from "../Instance"; import { Tools } from "../api/Tools"; import { getUriFromPath, parseFSOptions } from "../filesystems/qsys/QSysFs"; import { DefaultOpenMode, GlobalConfiguration } from "../api/Configuration"; diff --git a/src/commands/password.ts b/src/commands/password.ts index ba32a2a89..86e45f9f2 100644 --- a/src/commands/password.ts +++ b/src/commands/password.ts @@ -1,6 +1,6 @@ import { commands, extensions, window, Disposable, ExtensionContext } from "vscode"; import { ConnectionManager } from "../api/Configuration"; -import Instance from "../api/Instance"; +import Instance from "../Instance"; const passwordAttempts: { [extensionId: string]: number } = {} diff --git a/src/instantiate.ts b/src/instantiate.ts index eccf42c7d..a25ff7615 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -1,7 +1,7 @@ import * as vscode from "vscode"; import { GlobalConfiguration, onCodeForIBMiConfigurationChange } from "./api/Configuration"; -import Instance from "./api/Instance"; +import Instance from "./Instance"; import { Terminal } from './api/Terminal'; import { getDebugServiceDetails } from './api/debug/config'; import { debugPTFInstalled, isDebugEngineRunning } from './api/debug/server'; diff --git a/src/typings.ts b/src/typings.ts index 0fbb10503..e5a4c9b12 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -2,7 +2,7 @@ import { Ignore } from 'ignore'; import { MarkdownString, ProviderResult, Range, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode"; import { ConnectionConfiguration } from './api/Configuration'; import { CustomUI } from "./api/CustomUI"; -import Instance from "./api/Instance"; +import Instance from "./Instance"; import { Tools } from "./api/Tools"; import { DeployTools } from "./api/local/deployTools"; import { ComponentRegistry } from './components/manager'; diff --git a/src/views/actions.ts b/src/views/actions.ts index 526d6470c..391350dab 100644 --- a/src/views/actions.ts +++ b/src/views/actions.ts @@ -5,7 +5,7 @@ import { getLocalActions } from '../api/local/actions'; import { DeployTools } from '../api/local/deployTools'; import { getBranchLibraryName, getEnvConfig } from '../api/local/env'; import { getGitBranch } from '../api/local/git'; -import Instance from '../api/Instance'; +import Instance from '../Instance'; import { parseFSOptions } from '../filesystems/qsys/QSysFs'; import { Action, BrowserItem, DeploymentMethod, Variable } from '../typings'; import { GlobalConfiguration } from '../api/Configuration'; diff --git a/src/views/connection.ts b/src/views/connection.ts new file mode 100644 index 000000000..eec04e692 --- /dev/null +++ b/src/views/connection.ts @@ -0,0 +1,200 @@ +import { commands, env, Uri, window } from "vscode"; +import IBMi, { ConnectionErrorCode, ConnectionMessageType } from "../api/IBMi"; + +export function messageCallback(type: ConnectionMessageType, message: string) { + switch (type) { + case `info`: + window.showInformationMessage(message); + break; + case `warning`: + window.showWarningMessage(message); + break; + case `error`: + window.showErrorMessage(message); + break; + } +} + +export async function handleConnectionResults(connection: IBMi, error: ConnectionErrorCode, data: any) { + switch (error as ConnectionErrorCode) { + case `shell_config`: + const chosen = await window.showInformationMessage(`Error in shell configuration!`, { + detail: [ + `This extension can not work with the shell configured on ${connection.currentConnectionName},`, + `since the output from shell commands have additional content.`, + `This can be caused by running commands like "echo" or other`, + `commands creating output in your shell start script.`, ``, + `The connection to ${connection.currentConnectionName} will be aborted.` + ].join(`\n`), + modal: true + }, `Read more`); + + if (chosen === `Read more`) { + commands.executeCommand(`open`, `https://codefori.github.io/docs/#/pages/tips/setup`); + } + break; + + case `home_directory_creation`: + if (await window.showWarningMessage(`Home directory does not exist`, { + modal: true, + detail: `Your home directory (${data}) does not exist, so Code for IBM i may not function correctly. Would you like to create this directory now?`, + }, `Yes`)) { + let mkHomeCmd = `mkdir -p ${data} && chown ${connection.currentUser.toLowerCase()} ${data} && chmod 0755 ${data}`; + let mkHomeResult = await connection.sendCommand({ command: mkHomeCmd, directory: `.` }); + if (0 === mkHomeResult.code) { + return true; + } else { + let mkHomeErrs = mkHomeResult.stderr; + // We still get 'Could not chdir to home directory' in stderr so we need to hackily gut that out, as well as the bashisms that are a side effect of our API + mkHomeErrs = mkHomeErrs.substring(1 + mkHomeErrs.indexOf(`\n`)).replace(`bash: line 1: `, ``); + await window.showWarningMessage(`Error creating home directory (${data}):\n${mkHomeErrs}.\n\n Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: true }); + return false; + } + } + break; + + case `QCPTOIMPF_exists`: + window.showWarningMessage(`The data area QSYS/QCPTOIMPF exists on this system and may impact Code for IBM i functionality.`, { + detail: `For V5R3, the code for the command CPYTOIMPF had a major design change to increase functionality and performance. The QSYS/QCPTOIMPF data area lets developers keep the pre-V5R2 version of CPYTOIMPF. Code for IBM i cannot function correctly while this data area exists.`, + modal: true, + }, `Delete`, `Read more`).then(choice => { + switch (choice) { + case `Delete`: + connection.runCommand({ + command: `DLTOBJ OBJ(QSYS/QCPTOIMPF) OBJTYPE(*DTAARA)`, + noLibList: true + }) + .then((result) => { + if (result?.code === 0) { + window.showInformationMessage(`The data area QSYS/QCPTOIMPF has been deleted.`); + } else { + window.showInformationMessage(`Failed to delete the data area QSYS/QCPTOIMPF. Code for IBM i may not work as intended.`); + } + }) + break; + case `Read more`: + env.openExternal(Uri.parse(`https://github.com/codefori/vscode-ibmi/issues/476#issuecomment-1018908018`)); + break; + } + }); + break; + + case `QCPFRMIMPF_exists`: + window.showWarningMessage(`The data area QSYS/QCPFRMIMPF exists on this system and may impact Code for IBM i functionality.`, { + modal: false, + }, `Delete`, `Read more`).then(choice => { + switch (choice) { + case `Delete`: + connection.runCommand({ + command: `DLTOBJ OBJ(QSYS/QCPFRMIMPF) OBJTYPE(*DTAARA)`, + noLibList: true + }) + .then((result) => { + if (result?.code === 0) { + window.showInformationMessage(`The data area QSYS/QCPFRMIMPF has been deleted.`); + } else { + window.showInformationMessage(`Failed to delete the data area QSYS/QCPFRMIMPF. Code for IBM i may not work as intended.`); + } + }) + break; + case `Read more`: + env.openExternal(Uri.parse(`https://github.com/codefori/vscode-ibmi/issues/476#issuecomment-1018908018`)); + break; + } + }); + break; + + case `default_not_bash`: + window.showInformationMessage(`IBM recommends using bash as your default shell.`, `Set shell to bash`, `Read More`,).then(async choice => { + switch (choice) { + case `Set shell to bash`: + const commandSetBashResult = await connection.sendCommand({ + command: `/QOpenSys/pkgs/bin/chsh -s /QOpenSys/pkgs/bin/bash` + }); + + if (!commandSetBashResult.stderr) { + window.showInformationMessage(`Shell is now bash! Reconnect for change to take effect.`); + } else { + window.showInformationMessage(`Default shell WAS NOT changed to bash.`); + } + break; + + case `Read More`: + env.openExternal(Uri.parse(`https://ibmi-oss-docs.readthedocs.io/en/latest/user_setup/README.html#step-4-change-your-default-shell-to-bash`)); + break; + } + }); + break; + + case `invalid_bashrc`: + const { bashrcFile, bashrcExists, missingPath, reason } = data; + if (await window.showWarningMessage(`${missingPath} not found in $PATH`, { + modal: true, + detail: `${reason}, so Code for IBM i may not function correctly. Would you like to ${bashrcExists ? "update" : "create"} ${bashrcFile} to fix this now?`, + }, `Yes`)) { + if (!bashrcExists) { + // Add "/usr/bin" and "/QOpenSys/usr/bin" to the end of the path. This way we know that the user has + // all the required paths, but we don't overwrite the priority of other items on their path. + const createBashrc = await connection.sendCommand({ command: `echo "# Generated by Code for IBM i\nexport PATH=/QOpenSys/pkgs/bin:\\$PATH:/QOpenSys/usr/bin:/usr/bin" >> ${bashrcFile} && chown ${connection.currentUser.toLowerCase()} ${bashrcFile} && chmod 755 ${bashrcFile}` }); + if (createBashrc.code !== 0) { + window.showWarningMessage(`Error creating ${bashrcFile}):\n${createBashrc.stderr}.\n\n Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: true }); + } + } + else { + try { + const content = connection.content; + if (content) { + const bashrcContent = (await content.downloadStreamfile(bashrcFile)).split("\n"); + let replaced = false; + bashrcContent.forEach((line, index) => { + if (!replaced) { + const pathRegex = /^((?:export )?PATH=)(.*)(?:)$/.exec(line); + if (pathRegex) { + bashrcContent[index] = `${pathRegex[1]}/QOpenSys/pkgs/bin:${pathRegex[2] + .replace("/QOpenSys/pkgs/bin", "") //Removes /QOpenSys/pkgs/bin wherever it is + .replace("::", ":")}:/QOpenSys/usr/bin:/usr/bin`; //Removes double : in case /QOpenSys/pkgs/bin wasn't at the end + replaced = true; + } + } + }); + + if (!replaced) { + bashrcContent.push( + "", + "# Generated by Code for IBM i", + "export PATH=/QOpenSys/pkgs/bin:$PATH:/QOpenSys/usr/bin:/usr/bin" + ); + } + + await content.writeStreamfile(bashrcFile, bashrcContent.join("\n")); + } + } + catch (error) { + window.showWarningMessage(`Error modifying PATH in ${bashrcFile}):\n${error}.\n\n Code for IBM i may not function correctly. Please contact your system administrator.`, { modal: true }); + } + } + } + break; + + case `invalid_temp_lib`: + window.showWarningMessage(`Code for IBM i will not function correctly until the temporary library has been corrected in the settings.`, `Open Settings`) + .then(result => { + switch (result) { + case `Open Settings`: + commands.executeCommand(`code-for-ibmi.showAdditionalSettings`); + break; + } + }); + break; + + case `ccsid_warning`: + window.showWarningMessage(data, `Show documentation`).then(choice => { + if (choice === `Show documentation`) { + commands.executeCommand(`open`, `https://codefori.github.io/docs/tips/ccsid/`); + } + }); + break; + } + + return false; +} \ No newline at end of file diff --git a/src/views/diagnostics.ts b/src/views/diagnostics.ts index 2ced60a4b..762b64a31 100644 --- a/src/views/diagnostics.ts +++ b/src/views/diagnostics.ts @@ -2,7 +2,7 @@ import * as vscode from "vscode"; import { FileError } from "../typings"; import { GlobalConfiguration } from "../api/Configuration"; -import Instance from "../api/Instance"; +import Instance from "../Instance"; import { getEvfeventFiles } from "../api/local/actions"; import { parseErrors } from "../api/errors/parser"; import { findExistingDocumentByName, findExistingDocumentUri } from "./tools"; diff --git a/src/views/helpView.ts b/src/views/helpView.ts index 8d25bbaed..6b6e00b67 100644 --- a/src/views/helpView.ts +++ b/src/views/helpView.ts @@ -133,16 +133,16 @@ async function downloadLogs() { location: vscode.ProgressLocation.Notification, title: vscode.l10n.t(`Gathering logs...`), }, async () => { - const codeForIBMiLog = connection.getOutputChannelContent(); - if (codeForIBMiLog !== undefined) { - logs.push({ - label: vscode.l10n.t(`Code for IBM i Log`), - detail: `${connection?.currentUser}@${connection?.currentHost}`, - picked: true, - fileName: 'CodeForIBMi.txt', - fileContent: Buffer.from(codeForIBMiLog, 'utf8') - }); - } + // const codeForIBMiLog = connection.getOutputChannelContent(); + // if (codeForIBMiLog !== undefined) { + // logs.push({ + // label: vscode.l10n.t(`Code for IBM i Log`), + // detail: `${connection?.currentUser}@${connection?.currentHost}`, + // picked: true, + // fileName: 'CodeForIBMi.txt', + // fileContent: Buffer.from(codeForIBMiLog, 'utf8') + // }); + // } const debugConfig = await new DebugConfiguration(connection).load(); try { diff --git a/src/webviews/login/index.ts b/src/webviews/login/index.ts index ea61b7d46..05818de1f 100644 --- a/src/webviews/login/index.ts +++ b/src/webviews/login/index.ts @@ -119,7 +119,7 @@ export class Login { } } else { - vscode.window.showErrorMessage(`Not connected to ${data.host}! ${connected.error}`); + vscode.window.showErrorMessage(`Not connected to ${data.host}!`); } } catch (e) { vscode.window.showErrorMessage(`Error connecting to ${data.host}! ${e}`); @@ -179,7 +179,7 @@ export class Login { if (connected.success) { vscode.window.showInformationMessage(`Connected to ${connectionConfig.host}!`); } else { - vscode.window.showErrorMessage(`Not connected to ${connectionConfig.host}! ${connected.error}`); + vscode.window.showErrorMessage(`Not connected to ${connectionConfig.host}!`); } return true; From f81122a54349bedc7460a891791c12c5ac6fbaa0 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 14:35:27 -0500 Subject: [PATCH 04/46] Move Terminal module outside of API directory Signed-off-by: worksofliam --- src/instantiate.ts | 2 +- src/{api => views}/Terminal.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/{api => views}/Terminal.ts (97%) diff --git a/src/instantiate.ts b/src/instantiate.ts index a25ff7615..ebdd61461 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -2,7 +2,7 @@ import * as vscode from "vscode"; import { GlobalConfiguration, onCodeForIBMiConfigurationChange } from "./api/Configuration"; import Instance from "./Instance"; -import { Terminal } from './api/Terminal'; +import { Terminal } from './views/Terminal'; import { getDebugServiceDetails } from './api/debug/config'; import { debugPTFInstalled, isDebugEngineRunning } from './api/debug/server'; import { setupGitEventHandler } from './api/local/git'; diff --git a/src/api/Terminal.ts b/src/views/Terminal.ts similarity index 97% rename from src/api/Terminal.ts rename to src/views/Terminal.ts index 389e4839b..f6e4ded95 100644 --- a/src/api/Terminal.ts +++ b/src/views/Terminal.ts @@ -2,9 +2,9 @@ import path from 'path'; import vscode, { commands } from 'vscode'; import { instance } from '../instantiate'; -import { GlobalConfiguration } from './Configuration'; -import IBMi from './IBMi'; -import { Tools } from './Tools'; +import { GlobalConfiguration } from '../api/Configuration'; +import IBMi from '../api/IBMi'; +import { Tools } from '../api/Tools'; const PASE_INIT_FLAG = '#C4IINIT'; const PASE_INIT_FLAG_REGEX = /#+C+4+I+I+N+I+T+$/ @@ -120,7 +120,7 @@ export namespace Terminal { async function createTerminal(context: vscode.ExtensionContext, connection: IBMi, terminalSettings: TerminalSettings) { let ready = terminalSettings.type === TerminalType._5250; const writeEmitter = new vscode.EventEmitter(); - const channel = await connection.client.requestShell({ term: "xterm" }); + const channel = await connection.client!.requestShell({ term: "xterm" }); channel.on(`data`, (data: Buffer) => { const dataString = data.toString(); if (ready) { From a64fa5dcd7804ba7ed76a57c37611253100b45ea Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 14:36:39 -0500 Subject: [PATCH 05/46] Move customui to webview directory Signed-off-by: worksofliam --- src/api/debug/server.ts | 2 +- src/extension.ts | 2 +- src/typings.ts | 2 +- src/views/actions.ts | 2 +- src/{api => webviews}/CustomUI.ts | 0 src/webviews/actions/index.ts | 2 +- src/webviews/commandProfile/index.ts | 2 +- src/webviews/filters/index.ts | 2 +- src/webviews/login/index.ts | 2 +- src/webviews/settings/index.ts | 2 +- src/webviews/variables/index.ts | 2 +- 11 files changed, 10 insertions(+), 10 deletions(-) rename src/{api => webviews}/CustomUI.ts (100%) diff --git a/src/api/debug/server.ts b/src/api/debug/server.ts index 898060537..cf4e186ed 100644 --- a/src/api/debug/server.ts +++ b/src/api/debug/server.ts @@ -1,7 +1,7 @@ import path from "path"; import { commands, l10n, window } from "vscode"; import { instance } from "../../instantiate"; -import { CustomUI } from "../CustomUI"; +import { CustomUI } from "../../webviews/CustomUI"; import IBMi from "../IBMi"; import { Tools } from "../Tools"; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, ORIGINAL_DEBUG_CONFIG_FILE } from "./config"; diff --git a/src/extension.ts b/src/extension.ts index 2b21f7765..1983a6c93 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -4,7 +4,7 @@ import { ExtensionContext, commands, languages, window, workspace } from "vscode // this method is called when your extension is activated // your extension is activated the very first time the command is executed -import { CustomUI } from "./api/CustomUI"; +import { CustomUI } from "./webviews/CustomUI"; import { instance, loadAllofExtension } from './instantiate'; import { ConnectionConfiguration, ConnectionManager, onCodeForIBMiConfigurationChange } from "./api/Configuration"; import { GlobalStorage } from "./api/Storage"; diff --git a/src/typings.ts b/src/typings.ts index e5a4c9b12..d4f5657e1 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -1,7 +1,7 @@ import { Ignore } from 'ignore'; import { MarkdownString, ProviderResult, Range, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode"; import { ConnectionConfiguration } from './api/Configuration'; -import { CustomUI } from "./api/CustomUI"; +import { CustomUI } from "./webviews/CustomUI"; import Instance from "./Instance"; import { Tools } from "./api/Tools"; import { DeployTools } from "./api/local/deployTools"; diff --git a/src/views/actions.ts b/src/views/actions.ts index 391350dab..5ac113d6f 100644 --- a/src/views/actions.ts +++ b/src/views/actions.ts @@ -11,7 +11,7 @@ import { Action, BrowserItem, DeploymentMethod, Variable } from '../typings'; import { GlobalConfiguration } from '../api/Configuration'; import vscode, { CustomExecution, Pseudoterminal, TaskGroup, TaskRevealKind, WorkspaceFolder, commands, tasks } from 'vscode'; -import { CustomUI } from '../api/CustomUI'; +import { CustomUI } from '../webviews/CustomUI'; import { Tools } from '../api/Tools'; import { CompileTools } from '../api/CompileTools'; diff --git a/src/api/CustomUI.ts b/src/webviews/CustomUI.ts similarity index 100% rename from src/api/CustomUI.ts rename to src/webviews/CustomUI.ts diff --git a/src/webviews/actions/index.ts b/src/webviews/actions/index.ts index f99138f0a..ce6d930ad 100644 --- a/src/webviews/actions/index.ts +++ b/src/webviews/actions/index.ts @@ -1,6 +1,6 @@ import vscode from "vscode"; -import { CustomUI, Tab } from "../../api/CustomUI"; +import { CustomUI, Tab } from "../CustomUI"; import { GlobalConfiguration } from "../../api/Configuration"; import { Tools } from "../../api/Tools"; diff --git a/src/webviews/commandProfile/index.ts b/src/webviews/commandProfile/index.ts index 42fc1af5c..eb4c5470a 100644 --- a/src/webviews/commandProfile/index.ts +++ b/src/webviews/commandProfile/index.ts @@ -1,6 +1,6 @@ import { commands, window } from "vscode"; import { ConnectionConfiguration, GlobalConfiguration } from "../../api/Configuration"; -import { CustomUI } from "../../api/CustomUI"; +import { CustomUI } from "../CustomUI"; import { instance } from "../../instantiate"; export class CommandProfile { diff --git a/src/webviews/filters/index.ts b/src/webviews/filters/index.ts index 3565f8f4e..54492a715 100644 --- a/src/webviews/filters/index.ts +++ b/src/webviews/filters/index.ts @@ -1,5 +1,5 @@ import { ConnectionConfiguration } from "../../api/Configuration"; -import { CustomUI } from "../../api/CustomUI"; +import { CustomUI } from "../CustomUI"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; diff --git a/src/webviews/login/index.ts b/src/webviews/login/index.ts index 05818de1f..b91a479c0 100644 --- a/src/webviews/login/index.ts +++ b/src/webviews/login/index.ts @@ -1,6 +1,6 @@ import vscode, { l10n, ThemeIcon } from "vscode"; import { ConnectionConfiguration, ConnectionManager } from "../../api/Configuration"; -import { CustomUI, Section } from "../../api/CustomUI"; +import { CustomUI, Section } from "../CustomUI"; import { Tools } from "../../api/Tools"; import { instance, safeDisconnect } from "../../instantiate"; import { ConnectionData } from '../../typings'; diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 97b928121..e96cb7047 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -1,7 +1,7 @@ import { existsSync } from "fs"; import vscode from "vscode"; import { ConnectionConfiguration, ConnectionManager, GlobalConfiguration } from "../../api/Configuration"; -import { ComplexTab, CustomUI, Section } from "../../api/CustomUI"; +import { ComplexTab, CustomUI, Section } from "../CustomUI"; import { GlobalStorage } from '../../api/Storage'; import { Tools } from "../../api/Tools"; import { isManaged } from "../../api/debug"; diff --git a/src/webviews/variables/index.ts b/src/webviews/variables/index.ts index 58c8b5af7..bbbf0d015 100644 --- a/src/webviews/variables/index.ts +++ b/src/webviews/variables/index.ts @@ -1,6 +1,6 @@ import vscode from "vscode"; import { ConnectionConfiguration } from "../../api/Configuration"; -import { CustomUI } from "../../api/CustomUI"; +import { CustomUI } from "../CustomUI"; import { instance } from "../../instantiate"; export class VariablesUI { From 6006a080fa42286d37540a28b1e09b6e8e24b6f9 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 14:37:31 -0500 Subject: [PATCH 06/46] Move git to filesystems Signed-off-by: worksofliam --- src/{api/local => filesystems}/git.ts | 12 ++++++------ src/instantiate.ts | 2 +- src/views/actions.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) rename src/{api/local => filesystems}/git.ts (94%) diff --git a/src/api/local/git.ts b/src/filesystems/git.ts similarity index 94% rename from src/api/local/git.ts rename to src/filesystems/git.ts index 38a3a047a..4b5b4bcde 100644 --- a/src/api/local/git.ts +++ b/src/filesystems/git.ts @@ -1,10 +1,10 @@ import { ExtensionContext, WorkspaceFolder, commands, window } from "vscode"; -import { getBranchLibraryName } from "./env"; -import { instance } from "../../instantiate"; -import { ConnectionConfiguration, GlobalConfiguration } from "../Configuration"; -import IBMi from "../IBMi"; -import IBMiContent from "../IBMiContent"; -import { getGitAPI } from "../../views/tools"; +import { getBranchLibraryName } from "../api/local/env"; +import { instance } from "../instantiate"; +import { ConnectionConfiguration, GlobalConfiguration } from "../api/Configuration"; +import IBMi from "../api/IBMi"; +import IBMiContent from "../api/IBMiContent"; +import { getGitAPI } from "../views/tools"; const lastBranch: { [workspaceUri: string]: string } = {}; diff --git a/src/instantiate.ts b/src/instantiate.ts index ebdd61461..632c6a58a 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -5,7 +5,7 @@ import Instance from "./Instance"; import { Terminal } from './views/Terminal'; import { getDebugServiceDetails } from './api/debug/config'; import { debugPTFInstalled, isDebugEngineRunning } from './api/debug/server'; -import { setupGitEventHandler } from './api/local/git'; +import { setupGitEventHandler } from './filesystems/git'; import { registerActionsCommands } from './commands/actions'; import { registerCompareCommands } from './commands/compare'; import { registerConnectionCommands } from './commands/connection'; diff --git a/src/views/actions.ts b/src/views/actions.ts index 5ac113d6f..014d9a3ba 100644 --- a/src/views/actions.ts +++ b/src/views/actions.ts @@ -4,7 +4,7 @@ import { EvfEventInfo, refreshDiagnosticsFromLocal, refreshDiagnosticsFromServer import { getLocalActions } from '../api/local/actions'; import { DeployTools } from '../api/local/deployTools'; import { getBranchLibraryName, getEnvConfig } from '../api/local/env'; -import { getGitBranch } from '../api/local/git'; +import { getGitBranch } from '../filesystems/git'; import Instance from '../Instance'; import { parseFSOptions } from '../filesystems/qsys/QSysFs'; import { Action, BrowserItem, DeploymentMethod, Variable } from '../typings'; From 7251aabb24f902f025f643ff053f1fa976cde81f Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 14:38:02 -0500 Subject: [PATCH 07/46] Move deploy tools to filesystems Signed-off-by: worksofliam --- src/api/local/deployment.ts | 2 +- src/extension.ts | 2 +- src/{api/local => filesystems}/deployTools.ts | 10 +++++----- src/testing/action.ts | 2 +- src/testing/deployTools.ts | 2 +- src/typings.ts | 2 +- src/views/actions.ts | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) rename src/{api/local => filesystems}/deployTools.ts (98%) diff --git a/src/api/local/deployment.ts b/src/api/local/deployment.ts index 26ff45939..c3fd02a19 100644 --- a/src/api/local/deployment.ts +++ b/src/api/local/deployment.ts @@ -8,7 +8,7 @@ import { DeploymentParameters } from '../../typings'; import IBMi from '../IBMi'; import { Tools } from '../Tools'; import { getLocalActions } from './actions'; -import { DeployTools } from './deployTools'; +import { DeployTools } from '../../filesystems/deployTools'; export namespace Deployment { export interface MD5Entry { diff --git a/src/extension.ts b/src/extension.ts index 1983a6c93..8d3b13a99 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -11,7 +11,7 @@ import { GlobalStorage } from "./api/Storage"; import { Tools } from "./api/Tools"; import * as Debug from './api/debug'; import { parseErrors } from "./api/errors/parser"; -import { DeployTools } from "./api/local/deployTools"; +import { DeployTools } from "./filesystems/deployTools"; import { Deployment } from "./api/local/deployment"; import { CopyToImport } from "./components/copyToImport"; import { CustomQSh } from "./components/cqsh"; diff --git a/src/api/local/deployTools.ts b/src/filesystems/deployTools.ts similarity index 98% rename from src/api/local/deployTools.ts rename to src/filesystems/deployTools.ts index befd59d15..005cf4b2a 100644 --- a/src/api/local/deployTools.ts +++ b/src/filesystems/deployTools.ts @@ -1,11 +1,11 @@ import createIgnore, { Ignore } from 'ignore'; import path, { basename } from 'path'; import vscode, { Uri, WorkspaceFolder } from 'vscode'; -import { instance } from '../../instantiate'; -import { DeploymentMethod, DeploymentParameters } from '../../typings'; -import { LocalLanguageActions } from './LocalLanguageActions'; -import { Deployment } from './deployment'; -import { getGitAPI, md5Hash } from '../../views/tools'; +import { instance } from '../instantiate'; +import { DeploymentMethod, DeploymentParameters } from '../typings'; +import { LocalLanguageActions } from '../api/local/LocalLanguageActions'; +import { Deployment } from '../api/local/deployment'; +import { getGitAPI, md5Hash } from '../views/tools'; type ServerFileChanges = { uploads: Uri[], relativeRemoteDeletes: string[] }; diff --git a/src/testing/action.ts b/src/testing/action.ts index 109465281..4b36c8b31 100644 --- a/src/testing/action.ts +++ b/src/testing/action.ts @@ -5,7 +5,7 @@ import { TestSuite } from "."; import { CompileTools } from "../api/CompileTools"; import { Tools } from "../api/Tools"; import { LocalLanguageActions } from "../api/local/LocalLanguageActions"; -import { DeployTools } from "../api/local/deployTools"; +import { DeployTools } from "../filesystems/deployTools"; import { getEnvConfig } from "../api/local/env"; import { getMemberUri, getUriFromPath } from "../filesystems/qsys/QSysFs"; import { instance } from "../instantiate"; diff --git a/src/testing/deployTools.ts b/src/testing/deployTools.ts index 84092ab09..42872aa06 100644 --- a/src/testing/deployTools.ts +++ b/src/testing/deployTools.ts @@ -7,7 +7,7 @@ import { basename, posix } from "path"; import vscode from "vscode"; import { TestSuite } from "."; import { Tools } from "../api/Tools"; -import { DeployTools } from "../api/local/deployTools"; +import { DeployTools } from "../filesystems/deployTools"; import { instance } from "../instantiate"; import { Action, DeploymentMethod } from "../typings"; import { md5Hash } from "../views/tools"; diff --git a/src/typings.ts b/src/typings.ts index d4f5657e1..7f80eccc6 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -4,7 +4,7 @@ import { ConnectionConfiguration } from './api/Configuration'; import { CustomUI } from "./webviews/CustomUI"; import Instance from "./Instance"; import { Tools } from "./api/Tools"; -import { DeployTools } from "./api/local/deployTools"; +import { DeployTools } from "./filesystems/deployTools"; import { ComponentRegistry } from './components/manager'; export interface CodeForIBMi { diff --git a/src/views/actions.ts b/src/views/actions.ts index 014d9a3ba..2313eb670 100644 --- a/src/views/actions.ts +++ b/src/views/actions.ts @@ -2,7 +2,7 @@ import path from 'path'; import { EvfEventInfo, refreshDiagnosticsFromLocal, refreshDiagnosticsFromServer, registerDiagnostics } from './diagnostics'; import { getLocalActions } from '../api/local/actions'; -import { DeployTools } from '../api/local/deployTools'; +import { DeployTools } from '../filesystems/deployTools'; import { getBranchLibraryName, getEnvConfig } from '../api/local/env'; import { getGitBranch } from '../filesystems/git'; import Instance from '../Instance'; From 9469d740e079b575ff2d03c3d060e523b7976762 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 14:39:04 -0500 Subject: [PATCH 08/46] Move deployment to file systems Signed-off-by: worksofliam --- src/extension.ts | 2 +- src/filesystems/deployTools.ts | 2 +- src/{api/local => filesystems}/deployment.ts | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) rename src/{api/local => filesystems}/deployment.ts (96%) diff --git a/src/extension.ts b/src/extension.ts index 8d3b13a99..640a1c084 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -12,7 +12,7 @@ import { Tools } from "./api/Tools"; import * as Debug from './api/debug'; import { parseErrors } from "./api/errors/parser"; import { DeployTools } from "./filesystems/deployTools"; -import { Deployment } from "./api/local/deployment"; +import { Deployment } from "./filesystems/deployment"; import { CopyToImport } from "./components/copyToImport"; import { CustomQSh } from "./components/cqsh"; import { GetMemberInfo } from "./components/getMemberInfo"; diff --git a/src/filesystems/deployTools.ts b/src/filesystems/deployTools.ts index 005cf4b2a..ce9bc4c99 100644 --- a/src/filesystems/deployTools.ts +++ b/src/filesystems/deployTools.ts @@ -4,7 +4,7 @@ import vscode, { Uri, WorkspaceFolder } from 'vscode'; import { instance } from '../instantiate'; import { DeploymentMethod, DeploymentParameters } from '../typings'; import { LocalLanguageActions } from '../api/local/LocalLanguageActions'; -import { Deployment } from '../api/local/deployment'; +import { Deployment } from './deployment'; import { getGitAPI, md5Hash } from '../views/tools'; type ServerFileChanges = { uploads: Uri[], relativeRemoteDeletes: string[] }; diff --git a/src/api/local/deployment.ts b/src/filesystems/deployment.ts similarity index 96% rename from src/api/local/deployment.ts rename to src/filesystems/deployment.ts index c3fd02a19..6f83fbe6b 100644 --- a/src/api/local/deployment.ts +++ b/src/filesystems/deployment.ts @@ -3,12 +3,12 @@ import path from 'path'; import tar from 'tar'; import tmp from 'tmp'; import vscode from 'vscode'; -import { instance } from '../../instantiate'; -import { DeploymentParameters } from '../../typings'; -import IBMi from '../IBMi'; -import { Tools } from '../Tools'; -import { getLocalActions } from './actions'; -import { DeployTools } from '../../filesystems/deployTools'; +import { instance } from '../instantiate'; +import { DeploymentParameters } from '../typings'; +import IBMi from '../api/IBMi'; +import { Tools } from '../api/Tools'; +import { getLocalActions } from '../api/local/actions'; +import { DeployTools } from './deployTools'; export namespace Deployment { export interface MD5Entry { @@ -232,7 +232,7 @@ export namespace Deployment { deploymentLog.appendLine(`Created deployment tarball ${localTarball.name}`); progress?.report({ message: `sending deployment tarball...` }); - await connection.client.putFile(localTarball.name, remoteTarball); + await connection.client!.putFile(localTarball.name, remoteTarball); deploymentLog.appendLine(`Uploaded deployment tarball as ${remoteTarball}`); progress?.report({ message: `extracting deployment tarball to ${parameters.remotePath}...` }); From 0455f148583c00279b65e827f8bb6ae2b13fffb5 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 14:40:16 -0500 Subject: [PATCH 09/46] Move all local to filesystems Signed-off-by: worksofliam --- src/api/debug/index.ts | 2 +- src/extension.ts | 4 ++-- .../local/LocalLanguageActions.ts | 0 src/{api => filesystems}/local/actions.ts | 0 src/filesystems/{ => local}/deployTools.ts | 8 ++++---- src/filesystems/{ => local}/deployment.ts | 10 +++++----- src/{api => filesystems}/local/env.ts | 0 src/filesystems/{ => local}/git.ts | 12 ++++++------ src/instantiate.ts | 2 +- src/testing/action.ts | 6 +++--- src/testing/deployTools.ts | 2 +- src/typings.ts | 2 +- src/views/actions.ts | 8 ++++---- src/views/diagnostics.ts | 2 +- 14 files changed, 29 insertions(+), 29 deletions(-) rename src/{api => filesystems}/local/LocalLanguageActions.ts (100%) rename src/{api => filesystems}/local/actions.ts (100%) rename src/filesystems/{ => local}/deployTools.ts (98%) rename src/filesystems/{ => local}/deployment.ts (97%) rename src/{api => filesystems}/local/env.ts (100%) rename src/filesystems/{ => local}/git.ts (94%) diff --git a/src/api/debug/index.ts b/src/api/debug/index.ts index fd9ccabaa..c8c6158c4 100644 --- a/src/api/debug/index.ts +++ b/src/api/debug/index.ts @@ -8,7 +8,7 @@ import { instance } from "../../instantiate"; import { ObjectItem } from "../../typings"; import { ILELibrarySettings } from "../CompileTools"; import { ConnectionManager } from "../Configuration"; -import { Env, getEnvConfig } from "../local/env"; +import { Env, getEnvConfig } from "../../filesystems/local/env"; import * as certificates from "./certificates"; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, resetDebugServiceDetails } from "./config"; import * as server from "./server"; diff --git a/src/extension.ts b/src/extension.ts index 640a1c084..29c4a596b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -11,8 +11,8 @@ import { GlobalStorage } from "./api/Storage"; import { Tools } from "./api/Tools"; import * as Debug from './api/debug'; import { parseErrors } from "./api/errors/parser"; -import { DeployTools } from "./filesystems/deployTools"; -import { Deployment } from "./filesystems/deployment"; +import { DeployTools } from "./filesystems/local/deployTools"; +import { Deployment } from "./filesystems/local/deployment"; import { CopyToImport } from "./components/copyToImport"; import { CustomQSh } from "./components/cqsh"; import { GetMemberInfo } from "./components/getMemberInfo"; diff --git a/src/api/local/LocalLanguageActions.ts b/src/filesystems/local/LocalLanguageActions.ts similarity index 100% rename from src/api/local/LocalLanguageActions.ts rename to src/filesystems/local/LocalLanguageActions.ts diff --git a/src/api/local/actions.ts b/src/filesystems/local/actions.ts similarity index 100% rename from src/api/local/actions.ts rename to src/filesystems/local/actions.ts diff --git a/src/filesystems/deployTools.ts b/src/filesystems/local/deployTools.ts similarity index 98% rename from src/filesystems/deployTools.ts rename to src/filesystems/local/deployTools.ts index ce9bc4c99..befd59d15 100644 --- a/src/filesystems/deployTools.ts +++ b/src/filesystems/local/deployTools.ts @@ -1,11 +1,11 @@ import createIgnore, { Ignore } from 'ignore'; import path, { basename } from 'path'; import vscode, { Uri, WorkspaceFolder } from 'vscode'; -import { instance } from '../instantiate'; -import { DeploymentMethod, DeploymentParameters } from '../typings'; -import { LocalLanguageActions } from '../api/local/LocalLanguageActions'; +import { instance } from '../../instantiate'; +import { DeploymentMethod, DeploymentParameters } from '../../typings'; +import { LocalLanguageActions } from './LocalLanguageActions'; import { Deployment } from './deployment'; -import { getGitAPI, md5Hash } from '../views/tools'; +import { getGitAPI, md5Hash } from '../../views/tools'; type ServerFileChanges = { uploads: Uri[], relativeRemoteDeletes: string[] }; diff --git a/src/filesystems/deployment.ts b/src/filesystems/local/deployment.ts similarity index 97% rename from src/filesystems/deployment.ts rename to src/filesystems/local/deployment.ts index 6f83fbe6b..b74972316 100644 --- a/src/filesystems/deployment.ts +++ b/src/filesystems/local/deployment.ts @@ -3,11 +3,11 @@ import path from 'path'; import tar from 'tar'; import tmp from 'tmp'; import vscode from 'vscode'; -import { instance } from '../instantiate'; -import { DeploymentParameters } from '../typings'; -import IBMi from '../api/IBMi'; -import { Tools } from '../api/Tools'; -import { getLocalActions } from '../api/local/actions'; +import { instance } from '../../instantiate'; +import { DeploymentParameters } from '../../typings'; +import IBMi from '../../api/IBMi'; +import { Tools } from '../../api/Tools'; +import { getLocalActions } from './actions'; import { DeployTools } from './deployTools'; export namespace Deployment { diff --git a/src/api/local/env.ts b/src/filesystems/local/env.ts similarity index 100% rename from src/api/local/env.ts rename to src/filesystems/local/env.ts diff --git a/src/filesystems/git.ts b/src/filesystems/local/git.ts similarity index 94% rename from src/filesystems/git.ts rename to src/filesystems/local/git.ts index 4b5b4bcde..237256048 100644 --- a/src/filesystems/git.ts +++ b/src/filesystems/local/git.ts @@ -1,10 +1,10 @@ import { ExtensionContext, WorkspaceFolder, commands, window } from "vscode"; -import { getBranchLibraryName } from "../api/local/env"; -import { instance } from "../instantiate"; -import { ConnectionConfiguration, GlobalConfiguration } from "../api/Configuration"; -import IBMi from "../api/IBMi"; -import IBMiContent from "../api/IBMiContent"; -import { getGitAPI } from "../views/tools"; +import { getBranchLibraryName } from "./env"; +import { instance } from "../../instantiate"; +import { ConnectionConfiguration, GlobalConfiguration } from "../../api/Configuration"; +import IBMi from "../../api/IBMi"; +import IBMiContent from "../../api/IBMiContent"; +import { getGitAPI } from "../../views/tools"; const lastBranch: { [workspaceUri: string]: string } = {}; diff --git a/src/instantiate.ts b/src/instantiate.ts index 632c6a58a..e9246e0fb 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -5,7 +5,7 @@ import Instance from "./Instance"; import { Terminal } from './views/Terminal'; import { getDebugServiceDetails } from './api/debug/config'; import { debugPTFInstalled, isDebugEngineRunning } from './api/debug/server'; -import { setupGitEventHandler } from './filesystems/git'; +import { setupGitEventHandler } from './filesystems/local/git'; import { registerActionsCommands } from './commands/actions'; import { registerCompareCommands } from './commands/compare'; import { registerConnectionCommands } from './commands/connection'; diff --git a/src/testing/action.ts b/src/testing/action.ts index 4b36c8b31..ed16dba93 100644 --- a/src/testing/action.ts +++ b/src/testing/action.ts @@ -4,9 +4,9 @@ import vscode from "vscode"; import { TestSuite } from "."; import { CompileTools } from "../api/CompileTools"; import { Tools } from "../api/Tools"; -import { LocalLanguageActions } from "../api/local/LocalLanguageActions"; -import { DeployTools } from "../filesystems/deployTools"; -import { getEnvConfig } from "../api/local/env"; +import { LocalLanguageActions } from "../filesystems/local/LocalLanguageActions"; +import { DeployTools } from "../filesystems/local/deployTools"; +import { getEnvConfig } from "../filesystems/local/env"; import { getMemberUri, getUriFromPath } from "../filesystems/qsys/QSysFs"; import { instance } from "../instantiate"; import { Action, IBMiObject } from "../typings"; diff --git a/src/testing/deployTools.ts b/src/testing/deployTools.ts index 42872aa06..4f6a13bf1 100644 --- a/src/testing/deployTools.ts +++ b/src/testing/deployTools.ts @@ -7,7 +7,7 @@ import { basename, posix } from "path"; import vscode from "vscode"; import { TestSuite } from "."; import { Tools } from "../api/Tools"; -import { DeployTools } from "../filesystems/deployTools"; +import { DeployTools } from "../filesystems/local/deployTools"; import { instance } from "../instantiate"; import { Action, DeploymentMethod } from "../typings"; import { md5Hash } from "../views/tools"; diff --git a/src/typings.ts b/src/typings.ts index 7f80eccc6..3ea47c980 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -4,7 +4,7 @@ import { ConnectionConfiguration } from './api/Configuration'; import { CustomUI } from "./webviews/CustomUI"; import Instance from "./Instance"; import { Tools } from "./api/Tools"; -import { DeployTools } from "./filesystems/deployTools"; +import { DeployTools } from "./filesystems/local/deployTools"; import { ComponentRegistry } from './components/manager'; export interface CodeForIBMi { diff --git a/src/views/actions.ts b/src/views/actions.ts index 2313eb670..7da4f0346 100644 --- a/src/views/actions.ts +++ b/src/views/actions.ts @@ -1,10 +1,10 @@ import path from 'path'; import { EvfEventInfo, refreshDiagnosticsFromLocal, refreshDiagnosticsFromServer, registerDiagnostics } from './diagnostics'; -import { getLocalActions } from '../api/local/actions'; -import { DeployTools } from '../filesystems/deployTools'; -import { getBranchLibraryName, getEnvConfig } from '../api/local/env'; -import { getGitBranch } from '../filesystems/git'; +import { getLocalActions } from '../filesystems/local/actions'; +import { DeployTools } from '../filesystems/local/deployTools'; +import { getBranchLibraryName, getEnvConfig } from '../filesystems/local/env'; +import { getGitBranch } from '../filesystems/local/git'; import Instance from '../Instance'; import { parseFSOptions } from '../filesystems/qsys/QSysFs'; import { Action, BrowserItem, DeploymentMethod, Variable } from '../typings'; diff --git a/src/views/diagnostics.ts b/src/views/diagnostics.ts index 762b64a31..c85e6b1f8 100644 --- a/src/views/diagnostics.ts +++ b/src/views/diagnostics.ts @@ -3,7 +3,7 @@ import * as vscode from "vscode"; import { FileError } from "../typings"; import { GlobalConfiguration } from "../api/Configuration"; import Instance from "../Instance"; -import { getEvfeventFiles } from "../api/local/actions"; +import { getEvfeventFiles } from "../filesystems/local/actions"; import { parseErrors } from "../api/errors/parser"; import { findExistingDocumentByName, findExistingDocumentUri } from "./tools"; From fc5ae3b6a6e3283ee9a99b37db82008dd5d4e154 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 14:42:06 -0500 Subject: [PATCH 10/46] Move debug out of api Signed-off-by: worksofliam --- src/api/IBMi.ts | 4 ++-- src/{api => }/debug/certificates.ts | 10 +++++----- src/{api => }/debug/config.ts | 4 ++-- src/{api => }/debug/index.ts | 14 +++++++------- src/{api => }/debug/server.ts | 8 ++++---- src/extension.ts | 2 +- src/instantiate.ts | 4 ++-- src/testing/debug.ts | 2 +- src/views/debugView.ts | 6 +++--- src/views/helpView.ts | 2 +- src/webviews/settings/index.ts | 6 +++--- 11 files changed, 31 insertions(+), 31 deletions(-) rename src/{api => }/debug/certificates.ts (98%) rename src/{api => }/debug/config.ts (98%) rename src/{api => }/debug/index.ts (98%) rename src/{api => }/debug/server.ts (98%) diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 395884ddb..38ae5d80c 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -14,8 +14,8 @@ import IBMiContent from "./IBMiContent"; import { CachedServerSettings, GlobalStorage } from './Storage'; import { Tools } from './Tools'; import * as configVars from './configVars'; -import { DebugConfiguration } from "./debug/config"; -import { debugPTFInstalled } from "./debug/server"; +import { DebugConfiguration } from "../debug/config"; +import { debugPTFInstalled } from "../debug/server"; export interface MemberParts extends IBMiMember { basename: string diff --git a/src/api/debug/certificates.ts b/src/debug/certificates.ts similarity index 98% rename from src/api/debug/certificates.ts rename to src/debug/certificates.ts index a1256bae4..69c9f76e8 100644 --- a/src/api/debug/certificates.ts +++ b/src/debug/certificates.ts @@ -4,12 +4,12 @@ import * as os from "os"; import path, { dirname, posix } from "path"; import { promisify } from 'util'; import vscode from "vscode"; -import { instance } from '../../instantiate'; -import IBMi from "../IBMi"; -import IBMiContent from '../IBMiContent'; -import { Tools } from '../Tools'; +import { instance } from '../instantiate'; +import IBMi from "../api/IBMi"; +import IBMiContent from '../api/IBMiContent'; +import { Tools } from '../api/Tools'; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, getJavaHome } from './config'; -import { fileToPath } from '../../views/tools'; +import { fileToPath } from '../views/tools'; type HostInfo = { ip: string diff --git a/src/api/debug/config.ts b/src/debug/config.ts similarity index 98% rename from src/api/debug/config.ts rename to src/debug/config.ts index fba52e307..de3b18659 100644 --- a/src/api/debug/config.ts +++ b/src/debug/config.ts @@ -1,7 +1,7 @@ import path from "path"; import vscode from "vscode"; -import { instance } from "../../instantiate"; -import IBMi from "../IBMi"; +import { instance } from "../instantiate"; +import IBMi from "../api/IBMi"; import { SERVICE_CERTIFICATE } from "./certificates"; type ConfigLine = { diff --git a/src/api/debug/index.ts b/src/debug/index.ts similarity index 98% rename from src/api/debug/index.ts rename to src/debug/index.ts index c8c6158c4..4c4323059 100644 --- a/src/api/debug/index.ts +++ b/src/debug/index.ts @@ -1,18 +1,18 @@ import { ExtensionContext, Uri } from "vscode"; -import Instance from "../../Instance"; +import Instance from "../Instance"; import path from "path"; import * as vscode from 'vscode'; -import { instance } from "../../instantiate"; -import { ObjectItem } from "../../typings"; -import { ILELibrarySettings } from "../CompileTools"; -import { ConnectionManager } from "../Configuration"; -import { Env, getEnvConfig } from "../../filesystems/local/env"; +import { instance } from "../instantiate"; +import { ObjectItem } from "../typings"; +import { ILELibrarySettings } from "../api/CompileTools"; +import { ConnectionManager } from "../api/Configuration"; +import { Env, getEnvConfig } from "../filesystems/local/env"; import * as certificates from "./certificates"; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, resetDebugServiceDetails } from "./config"; import * as server from "./server"; -import { withContext } from "../../views/tools"; +import { withContext } from "../views/tools"; const debugExtensionId = `IBM.ibmidebug`; diff --git a/src/api/debug/server.ts b/src/debug/server.ts similarity index 98% rename from src/api/debug/server.ts rename to src/debug/server.ts index cf4e186ed..761631d7c 100644 --- a/src/api/debug/server.ts +++ b/src/debug/server.ts @@ -1,9 +1,9 @@ import path from "path"; import { commands, l10n, window } from "vscode"; -import { instance } from "../../instantiate"; -import { CustomUI } from "../../webviews/CustomUI"; -import IBMi from "../IBMi"; -import { Tools } from "../Tools"; +import { instance } from "../instantiate"; +import { CustomUI } from "../webviews/CustomUI"; +import IBMi from "../api/IBMi"; +import { Tools } from "../api/Tools"; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, ORIGINAL_DEBUG_CONFIG_FILE } from "./config"; export type DebugJob = { diff --git a/src/extension.ts b/src/extension.ts index 29c4a596b..15ddd836a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -9,7 +9,7 @@ import { instance, loadAllofExtension } from './instantiate'; import { ConnectionConfiguration, ConnectionManager, onCodeForIBMiConfigurationChange } from "./api/Configuration"; import { GlobalStorage } from "./api/Storage"; import { Tools } from "./api/Tools"; -import * as Debug from './api/debug'; +import * as Debug from './debug'; import { parseErrors } from "./api/errors/parser"; import { DeployTools } from "./filesystems/local/deployTools"; import { Deployment } from "./filesystems/local/deployment"; diff --git a/src/instantiate.ts b/src/instantiate.ts index e9246e0fb..e8fc9043b 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -3,8 +3,8 @@ import * as vscode from "vscode"; import { GlobalConfiguration, onCodeForIBMiConfigurationChange } from "./api/Configuration"; import Instance from "./Instance"; import { Terminal } from './views/Terminal'; -import { getDebugServiceDetails } from './api/debug/config'; -import { debugPTFInstalled, isDebugEngineRunning } from './api/debug/server'; +import { getDebugServiceDetails } from './debug/config'; +import { debugPTFInstalled, isDebugEngineRunning } from './debug/server'; import { setupGitEventHandler } from './filesystems/local/git'; import { registerActionsCommands } from './commands/actions'; import { registerCompareCommands } from './commands/compare'; diff --git a/src/testing/debug.ts b/src/testing/debug.ts index 44aa2e89d..2e6249be1 100644 --- a/src/testing/debug.ts +++ b/src/testing/debug.ts @@ -1,6 +1,6 @@ import assert from "assert"; import { TestSuite } from "."; -import { getJavaHome } from "../api/debug/config"; +import { getJavaHome } from "../debug/config"; import { instance } from "../instantiate"; export const DebugSuite: TestSuite = { diff --git a/src/views/debugView.ts b/src/views/debugView.ts index 9a931f77f..f4cd9e2f5 100644 --- a/src/views/debugView.ts +++ b/src/views/debugView.ts @@ -1,8 +1,8 @@ import vscode from "vscode"; import { Tools } from "../api/Tools"; -import { checkClientCertificate, debugKeyFileExists, remoteCertificatesExists, SERVICE_CERTIFICATE } from "../api/debug/certificates"; -import { DebugConfiguration, getDebugServiceDetails } from "../api/debug/config"; -import { DebugJob, getDebugServerJob, getDebugServiceJob, isDebugEngineRunning, readActiveJob, readJVMInfo, startServer, startService, stopServer, stopService } from "../api/debug/server"; +import { checkClientCertificate, debugKeyFileExists, remoteCertificatesExists, SERVICE_CERTIFICATE } from "../debug/certificates"; +import { DebugConfiguration, getDebugServiceDetails } from "../debug/config"; +import { DebugJob, getDebugServerJob, getDebugServiceJob, isDebugEngineRunning, readActiveJob, readJVMInfo, startServer, startService, stopServer, stopService } from "../debug/server"; import { instance } from "../instantiate"; import { BrowserItem } from "../typings"; import { withContext } from "./tools"; diff --git a/src/views/helpView.ts b/src/views/helpView.ts index 6b6e00b67..13fd80e7a 100644 --- a/src/views/helpView.ts +++ b/src/views/helpView.ts @@ -2,7 +2,7 @@ import AdmZip from 'adm-zip'; import path, { parse } from 'path'; import vscode from 'vscode'; -import { DebugConfiguration } from '../api/debug/config'; +import { DebugConfiguration } from '../debug/config'; import IBMi from '../api/IBMi'; import { instance } from '../instantiate'; diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index e96cb7047..045d07cc4 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -4,9 +4,9 @@ import { ConnectionConfiguration, ConnectionManager, GlobalConfiguration } from import { ComplexTab, CustomUI, Section } from "../CustomUI"; import { GlobalStorage } from '../../api/Storage'; import { Tools } from "../../api/Tools"; -import { isManaged } from "../../api/debug"; -import * as certificates from "../../api/debug/certificates"; -import { isSEPSupported } from "../../api/debug/server"; +import { isManaged } from "../../debug"; +import * as certificates from "../../debug/certificates"; +import { isSEPSupported } from "../../debug/server"; import { extensionComponentRegistry } from "../../components/manager"; import { instance } from "../../instantiate"; import { ConnectionData, Server } from '../../typings'; From 9d0f564650963cce1b48a90129e06edf66d42b3a Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 14:47:10 -0500 Subject: [PATCH 11/46] Move components Signed-off-by: worksofliam --- src/api/IBMi.ts | 8 ++++---- src/api/IBMiContent.ts | 2 +- src/api/Search.ts | 2 +- src/{ => api}/components/component.ts | 2 +- src/{ => api}/components/copyToImport.ts | 6 +++--- src/{ => api}/components/cqsh/cqsh | Bin src/{ => api}/components/cqsh/cqsh.c | 0 src/{ => api}/components/cqsh/index.ts | 2 +- src/{ => api}/components/getMemberInfo.ts | 8 ++++---- src/{ => api}/components/getNewLibl.ts | 4 ++-- src/{ => api}/components/manager.ts | 2 +- src/extension.ts | 10 +++++----- src/testing/components.ts | 4 ++-- src/typings.ts | 2 +- src/views/ProfilesView.ts | 2 +- src/webviews/settings/index.ts | 2 +- 16 files changed, 28 insertions(+), 28 deletions(-) rename src/{ => api}/components/component.ts (98%) rename src/{ => api}/components/copyToImport.ts (95%) rename src/{ => api}/components/cqsh/cqsh (100%) rename src/{ => api}/components/cqsh/cqsh.c (100%) rename src/{ => api}/components/cqsh/index.ts (98%) rename src/{ => api}/components/getMemberInfo.ts (97%) rename src/{ => api}/components/getNewLibl.ts (96%) rename src/{ => api}/components/manager.ts (98%) diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 38ae5d80c..216cc6337 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -3,10 +3,10 @@ import { existsSync } from "fs"; import * as node_ssh from "node-ssh"; import os from "os"; import path, { parse as parsePath } from 'path'; -import { IBMiComponent } from "../components/component"; -import { CopyToImport } from "../components/copyToImport"; -import { CustomQSh } from '../components/cqsh'; -import { ComponentManager } from "../components/manager"; +import { IBMiComponent } from "./components/component"; +import { CopyToImport } from "./components/copyToImport"; +import { CustomQSh } from './components/cqsh'; +import { ComponentManager } from "./components/manager"; import { CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, WrapResult } from "../typings"; import { CompileTools } from "./CompileTools"; import { ConnectionConfiguration } from "./Configuration"; diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index 4a0d503c8..ad70a4d33 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -4,7 +4,7 @@ import path from 'path'; import tmp from 'tmp'; import util from 'util'; import * as node_ssh from "node-ssh"; -import { GetMemberInfo } from '../components/getMemberInfo'; +import { GetMemberInfo } from './components/getMemberInfo'; import { ObjectTypes } from '../filesystems/qsys/Objects'; import { AttrOperands, CommandResult, IBMiError, IBMiMember, IBMiObject, IFSFile, QsysPath, SpecialAuthorities } from '../typings'; import { ConnectionConfiguration } from './Configuration'; diff --git a/src/api/Search.ts b/src/api/Search.ts index 92f3b0512..eafa9412c 100644 --- a/src/api/Search.ts +++ b/src/api/Search.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { GetMemberInfo } from '../components/getMemberInfo'; +import { GetMemberInfo } from './components/getMemberInfo'; import { IBMiMember, SearchHit, SearchResults } from '../typings'; import { GlobalConfiguration } from './Configuration'; import Instance from '../Instance'; diff --git a/src/components/component.ts b/src/api/components/component.ts similarity index 98% rename from src/components/component.ts rename to src/api/components/component.ts index e5cc604ee..4b67952b8 100644 --- a/src/components/component.ts +++ b/src/api/components/component.ts @@ -1,4 +1,4 @@ -import IBMi from "../api/IBMi"; +import IBMi from "../IBMi"; export type ComponentState = `NotChecked` | `NotInstalled` | `Installed` | `NeedsUpdate` | `Error`; diff --git a/src/components/copyToImport.ts b/src/api/components/copyToImport.ts similarity index 95% rename from src/components/copyToImport.ts rename to src/api/components/copyToImport.ts index b1fe61420..bc2849160 100644 --- a/src/components/copyToImport.ts +++ b/src/api/components/copyToImport.ts @@ -1,6 +1,6 @@ -import IBMi from "../api/IBMi"; -import { Tools } from "../api/Tools"; -import { WrapResult } from "../typings"; +import IBMi from "../IBMi"; +import { Tools } from "../Tools"; +import { WrapResult } from "../../typings"; import { ComponentState, IBMiComponent } from "./component"; export class CopyToImport implements IBMiComponent { diff --git a/src/components/cqsh/cqsh b/src/api/components/cqsh/cqsh similarity index 100% rename from src/components/cqsh/cqsh rename to src/api/components/cqsh/cqsh diff --git a/src/components/cqsh/cqsh.c b/src/api/components/cqsh/cqsh.c similarity index 100% rename from src/components/cqsh/cqsh.c rename to src/api/components/cqsh/cqsh.c diff --git a/src/components/cqsh/index.ts b/src/api/components/cqsh/index.ts similarity index 98% rename from src/components/cqsh/index.ts rename to src/api/components/cqsh/index.ts index 1de8bedf8..490087d54 100644 --- a/src/components/cqsh/index.ts +++ b/src/api/components/cqsh/index.ts @@ -2,7 +2,7 @@ import { stat } from "fs/promises"; import path from "path"; import { extensions } from "vscode"; -import IBMi from "../../api/IBMi"; +import IBMi from "../../IBMi"; import { ComponentState, IBMiComponent } from "../component"; export class CustomQSh implements IBMiComponent { diff --git a/src/components/getMemberInfo.ts b/src/api/components/getMemberInfo.ts similarity index 97% rename from src/components/getMemberInfo.ts rename to src/api/components/getMemberInfo.ts index c1ee97c01..c63cf438c 100644 --- a/src/components/getMemberInfo.ts +++ b/src/api/components/getMemberInfo.ts @@ -1,8 +1,8 @@ import { posix } from "path"; -import IBMi from "../api/IBMi"; -import { Tools } from "../api/Tools"; -import { IBMiMember } from "../typings"; -import { ComponentState, IBMiComponent } from "./component"; +import IBMi from "../IBMi"; +import { Tools } from "../Tools"; +import { IBMiMember } from "../../typings"; +import { ComponentState, IBMiComponent } from "../components/component"; export class GetMemberInfo implements IBMiComponent { static ID = 'GetMemberInfo'; diff --git a/src/components/getNewLibl.ts b/src/api/components/getNewLibl.ts similarity index 96% rename from src/components/getNewLibl.ts rename to src/api/components/getNewLibl.ts index 4082b8524..718d51e32 100644 --- a/src/components/getNewLibl.ts +++ b/src/api/components/getNewLibl.ts @@ -1,6 +1,6 @@ import { posix } from "path"; -import IBMi from "../api/IBMi"; -import { instance } from "../instantiate"; +import IBMi from "../IBMi"; +import { instance } from "../../instantiate"; import { ComponentState, IBMiComponent } from "./component"; export class GetNewLibl implements IBMiComponent { diff --git a/src/components/manager.ts b/src/api/components/manager.ts similarity index 98% rename from src/components/manager.ts rename to src/api/components/manager.ts index aec03a0e3..0b8ebd56a 100644 --- a/src/components/manager.ts +++ b/src/api/components/manager.ts @@ -1,5 +1,5 @@ import vscode from "vscode"; -import IBMi from "../api/IBMi"; +import IBMi from "../IBMi"; import { ComponentState, IBMiComponent } from "./component"; export class ComponentRegistry { diff --git a/src/extension.ts b/src/extension.ts index 15ddd836a..3736fd09f 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -13,11 +13,11 @@ import * as Debug from './debug'; import { parseErrors } from "./api/errors/parser"; import { DeployTools } from "./filesystems/local/deployTools"; import { Deployment } from "./filesystems/local/deployment"; -import { CopyToImport } from "./components/copyToImport"; -import { CustomQSh } from "./components/cqsh"; -import { GetMemberInfo } from "./components/getMemberInfo"; -import { GetNewLibl } from "./components/getNewLibl"; -import { extensionComponentRegistry } from "./components/manager"; +import { CopyToImport } from "./api/components/copyToImport"; +import { CustomQSh } from "./api/components/cqsh"; +import { GetMemberInfo } from "./api/components/getMemberInfo"; +import { GetNewLibl } from "./api/components/getNewLibl"; +import { extensionComponentRegistry } from "./api/components/manager"; import { IFSFS } from "./filesystems/ifsFs"; import { LocalActionCompletionItemProvider } from "./languages/actions/completion"; import * as Sandbox from "./sandbox"; diff --git a/src/testing/components.ts b/src/testing/components.ts index 80b0cd8a5..85ec96879 100644 --- a/src/testing/components.ts +++ b/src/testing/components.ts @@ -1,8 +1,8 @@ import assert from "assert"; import { TestSuite } from "."; import { Tools } from "../api/Tools"; -import { GetMemberInfo } from "../components/getMemberInfo"; -import { GetNewLibl } from "../components/getNewLibl"; +import { GetMemberInfo } from "../api/components/getMemberInfo"; +import { GetNewLibl } from "../api/components/getNewLibl"; import { instance } from "../instantiate"; export const ComponentSuite: TestSuite = { diff --git a/src/typings.ts b/src/typings.ts index 3ea47c980..3abe4c410 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -5,7 +5,7 @@ import { CustomUI } from "./webviews/CustomUI"; import Instance from "./Instance"; import { Tools } from "./api/Tools"; import { DeployTools } from "./filesystems/local/deployTools"; -import { ComponentRegistry } from './components/manager'; +import { ComponentRegistry } from './api/components/manager'; export interface CodeForIBMi { instance: Instance, diff --git a/src/views/ProfilesView.ts b/src/views/ProfilesView.ts index 8734a386a..d74ed91e1 100644 --- a/src/views/ProfilesView.ts +++ b/src/views/ProfilesView.ts @@ -1,7 +1,7 @@ import vscode, { l10n, window } from 'vscode'; import { ConnectionConfiguration } from '../api/Configuration'; -import { GetNewLibl } from '../components/getNewLibl'; +import { GetNewLibl } from '../api/components/getNewLibl'; import { instance } from '../instantiate'; import { Profile } from '../typings'; import { CommandProfile } from '../webviews/commandProfile'; diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 045d07cc4..8c4a6e6bc 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -7,7 +7,7 @@ import { Tools } from "../../api/Tools"; import { isManaged } from "../../debug"; import * as certificates from "../../debug/certificates"; import { isSEPSupported } from "../../debug/server"; -import { extensionComponentRegistry } from "../../components/manager"; +import { extensionComponentRegistry } from "../../api/components/manager"; import { instance } from "../../instantiate"; import { ConnectionData, Server } from '../../typings'; import { withContext } from "../../views/tools"; From 0345ba697d2b2b3adf70b54ab9c68c8df810fa06 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 14:47:44 -0500 Subject: [PATCH 12/46] Move cqsh out of components Signed-off-by: worksofliam --- src/api/IBMi.ts | 2 +- src/{api => }/components/cqsh/cqsh | Bin src/{api => }/components/cqsh/cqsh.c | 0 src/{api => }/components/cqsh/index.ts | 4 ++-- src/extension.ts | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename src/{api => }/components/cqsh/cqsh (100%) rename src/{api => }/components/cqsh/cqsh.c (100%) rename src/{api => }/components/cqsh/index.ts (94%) diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 216cc6337..ee826236c 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -5,7 +5,7 @@ import os from "os"; import path, { parse as parsePath } from 'path'; import { IBMiComponent } from "./components/component"; import { CopyToImport } from "./components/copyToImport"; -import { CustomQSh } from './components/cqsh'; +import { CustomQSh } from '../components/cqsh'; import { ComponentManager } from "./components/manager"; import { CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, WrapResult } from "../typings"; import { CompileTools } from "./CompileTools"; diff --git a/src/api/components/cqsh/cqsh b/src/components/cqsh/cqsh similarity index 100% rename from src/api/components/cqsh/cqsh rename to src/components/cqsh/cqsh diff --git a/src/api/components/cqsh/cqsh.c b/src/components/cqsh/cqsh.c similarity index 100% rename from src/api/components/cqsh/cqsh.c rename to src/components/cqsh/cqsh.c diff --git a/src/api/components/cqsh/index.ts b/src/components/cqsh/index.ts similarity index 94% rename from src/api/components/cqsh/index.ts rename to src/components/cqsh/index.ts index 490087d54..7adf0f735 100644 --- a/src/api/components/cqsh/index.ts +++ b/src/components/cqsh/index.ts @@ -2,8 +2,8 @@ import { stat } from "fs/promises"; import path from "path"; import { extensions } from "vscode"; -import IBMi from "../../IBMi"; -import { ComponentState, IBMiComponent } from "../component"; +import IBMi from "../../api/IBMi"; +import { ComponentState, IBMiComponent } from "../../api/components/component"; export class CustomQSh implements IBMiComponent { static ID = "cqsh"; diff --git a/src/extension.ts b/src/extension.ts index 3736fd09f..8f82a5952 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -14,7 +14,7 @@ import { parseErrors } from "./api/errors/parser"; import { DeployTools } from "./filesystems/local/deployTools"; import { Deployment } from "./filesystems/local/deployment"; import { CopyToImport } from "./api/components/copyToImport"; -import { CustomQSh } from "./api/components/cqsh"; +import { CustomQSh } from "./components/cqsh"; import { GetMemberInfo } from "./api/components/getMemberInfo"; import { GetNewLibl } from "./api/components/getNewLibl"; import { extensionComponentRegistry } from "./api/components/manager"; From c864293efa538d436557002f99f4276dd6dfecce Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 14:51:21 -0500 Subject: [PATCH 13/46] Remove use of instance from Search Signed-off-by: worksofliam --- src/api/Search.ts | 15 ++++++--------- src/testing/search.ts | 6 +++--- src/views/ifsBrowser.ts | 4 ++-- src/views/objectBrowser.ts | 2 +- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/api/Search.ts b/src/api/Search.ts index eafa9412c..22034ac58 100644 --- a/src/api/Search.ts +++ b/src/api/Search.ts @@ -2,14 +2,13 @@ import * as path from 'path'; import { GetMemberInfo } from './components/getMemberInfo'; import { IBMiMember, SearchHit, SearchResults } from '../typings'; import { GlobalConfiguration } from './Configuration'; -import Instance from '../Instance'; import { Tools } from './Tools'; +import IBMi from './IBMi'; export namespace Search { - export async function searchMembers(instance: Instance, library: string, sourceFile: string, searchTerm: string, members: string|IBMiMember[], readOnly?: boolean,): Promise { - const connection = instance.getConnection(); - const config = instance.getConfig(); - const content = instance.getContent(); + export async function searchMembers(connection: IBMi, library: string, sourceFile: string, searchTerm: string, members: string|IBMiMember[], readOnly?: boolean,): Promise { + const config = connection.getConfig(); + const content = connection.getContent(); if (connection && config && content) { let detailedMembers: IBMiMember[]|undefined; @@ -105,8 +104,7 @@ export namespace Search { } } - export async function searchIFS(instance: Instance, path: string, searchTerm: string): Promise { - const connection = instance.getConnection(); + export async function searchIFS(connection: IBMi, path: string, searchTerm: string): Promise { if (connection) { const grep = connection.remoteFeatures.grep; @@ -138,8 +136,7 @@ export namespace Search { } } - export async function findIFS(instance: Instance, path: string, findTerm: string): Promise { - const connection = instance.getConnection(); + export async function findIFS(connection: IBMi, path: string, findTerm: string): Promise { if (connection) { const find = connection.remoteFeatures.find; diff --git a/src/testing/search.ts b/src/testing/search.ts index b2a732b97..4bf0f35d6 100644 --- a/src/testing/search.ts +++ b/src/testing/search.ts @@ -9,7 +9,7 @@ export const SearchSuite: TestSuite = { tests: [ { name: "Single member search", test: async () => { - const result = await Search.searchMembers(instance, "QSYSINC", "QRPGLESRC", "IBM", "CMRPG"); + const result = await Search.searchMembers(instance.getConnection()!, "QSYSINC", "QRPGLESRC", "IBM", "CMRPG"); assert.strictEqual(result.term, "IBM"); assert.strictEqual(result.hits.length, 1); const [hit] = result.hits; @@ -29,7 +29,7 @@ export const SearchSuite: TestSuite = { name: "Generic name search", test: async () => { const memberFilter = "E*"; const filter = parseFilter(memberFilter); - const result = await Search.searchMembers(instance, "QSYSINC", "QRPGLESRC", "IBM", memberFilter); + const result = await Search.searchMembers(instance.getConnection()!, "QSYSINC", "QRPGLESRC", "IBM", memberFilter); assert.ok(result.hits.every(hit => filter.test(hit.path.split("/").at(-1)!))); assert.ok(result.hits.every(hit => !hit.path.endsWith(`MBR`))); } @@ -45,7 +45,7 @@ export const SearchSuite: TestSuite = { const members = await getConnection().content.getMemberList({ library, sourceFile, members: memberFilter }); assert.ok(checkNames(members.map(member => member.name))); - const result = await Search.searchMembers(instance, "QSYSINC", "QRPGLESRC", "SQL", members); + const result = await Search.searchMembers(instance.getConnection()!, "QSYSINC", "QRPGLESRC", "SQL", members); assert.strictEqual(result.hits.length, 6); assert.ok(checkNames(result.hits.map(hit => hit.path.split("/").at(-1)!))); assert.ok(result.hits.every(hit => !hit.path.endsWith(`MBR`))); diff --git a/src/views/ifsBrowser.ts b/src/views/ifsBrowser.ts index 6438f7f6f..978556c87 100644 --- a/src/views/ifsBrowser.ts +++ b/src/views/ifsBrowser.ts @@ -945,7 +945,7 @@ async function doSearchInStreamfiles(searchTerm: string, searchPath: string) { progress.report({ message: l10n.t(`"{0}" in {1}.`, searchTerm, searchPath) }); - const results = await Search.searchIFS(instance, searchPath, searchTerm); + const results = await Search.searchIFS(instance.getConnection()!, searchPath, searchTerm); if (results?.hits.length) { openIFSSearchResults(searchPath, results); } else { @@ -967,7 +967,7 @@ async function doFindStreamfiles(findTerm: string, findPath: string) { progress.report({ message: l10n.t(`Finding filenames with "{0}" in {1}.`, findTerm, findPath) }); - const results = (await Search.findIFS(instance, findPath, findTerm)); + const results = (await Search.findIFS(instance.getConnection()!, findPath, findTerm)); if (results?.hits.length) { openIFSSearchResults(findPath, results); } else { diff --git a/src/views/objectBrowser.ts b/src/views/objectBrowser.ts index 8d2c7c3e9..aae0b3dff 100644 --- a/src/views/objectBrowser.ts +++ b/src/views/objectBrowser.ts @@ -1392,7 +1392,7 @@ async function doSearchInSourceFile(searchTerm: string, path: string, filter?: C memberFilter = filter?.member; } - const results = await Search.searchMembers(instance, library, sourceFile, searchTerm, memberFilter, filter?.protected); + const results = await Search.searchMembers(instance.getConnection()!, library, sourceFile, searchTerm, memberFilter, filter?.protected); clearInterval(messageTimeout) if (results.hits.length) { const objectNamesLower = GlobalConfiguration.get(`ObjectBrowser.showNamesInLowercase`); From e654e0ce661070d2dd9764c838f96522f8a09e11 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 15:51:33 -0500 Subject: [PATCH 14/46] Support for virtual configuration Signed-off-by: worksofliam --- src/Instance.ts | 9 +- src/Storage.ts | 28 +++++ src/api/Configuration.ts | 20 ++-- src/api/IBMi.ts | 7 +- src/api/Search.ts | 6 +- src/api/Storage.ts | 132 +++++++++++----------- src/commands/open.ts | 8 +- src/extension.ts | 9 +- src/filesystems/local/git.ts | 4 +- src/filesystems/qsys/FSUtils.ts | 8 +- src/filesystems/qsys/extendedContent.ts | 6 +- src/filesystems/qsys/sourceDateHandler.ts | 4 +- src/instantiate.ts | 4 +- src/views/ConnectionBrowser.ts | 32 +++--- src/views/LibraryListView.ts | 4 +- src/views/Terminal.ts | 4 +- src/views/actions.ts | 8 +- src/views/diagnostics.ts | 8 +- src/views/ifsBrowser.ts | 40 +++---- src/views/objectBrowser.ts | 23 ++-- src/webviews/actions/index.ts | 6 +- src/webviews/commandProfile/index.ts | 2 +- src/webviews/settings/index.ts | 10 +- 23 files changed, 205 insertions(+), 177 deletions(-) create mode 100644 src/Storage.ts diff --git a/src/Instance.ts b/src/Instance.ts index 1373d075c..94327239c 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -2,9 +2,10 @@ import * as vscode from "vscode"; import { ConnectionData, IBMiEvent } from "./typings"; import { ConnectionConfiguration } from "./api/Configuration"; import IBMi, { ConnectionResult } from "./api/IBMi"; -import { ConnectionStorage, GlobalStorage } from "./api/Storage"; +import { CodeForIStorage, ConnectionStorage } from "./api/Storage"; import { withContext } from "./views/tools"; import { handleConnectionResults, messageCallback } from "./views/connection"; +import { VsStorage } from "./Storage"; type IBMiEventSubscription = { func: Function, @@ -30,7 +31,9 @@ export default class Instance { private deprecationCount = 0; //TODO: remove in v3.0.0 constructor(context: vscode.ExtensionContext) { - this.storage = new ConnectionStorage(context); + const vscodeStorage = new VsStorage(context); + this.storage = new ConnectionStorage(vscodeStorage); + IBMi.GlobalStorage = new CodeForIStorage(vscodeStorage); this.emitter.event(e => this.processEvent(e)); } @@ -145,7 +148,7 @@ export default class Instance { this.connection = connection; this.storage.setConnectionName(connection.currentConnectionName); - await GlobalStorage.get().setLastConnection(connection.currentConnectionName); + await IBMi.GlobalStorage.setLastConnection(connection.currentConnectionName); this.fire(`connected`); } else { diff --git a/src/Storage.ts b/src/Storage.ts new file mode 100644 index 000000000..d8a788372 --- /dev/null +++ b/src/Storage.ts @@ -0,0 +1,28 @@ +import * as vscode from 'vscode'; +import { Storage } from './api/Storage'; + +export class VsStorage extends Storage { + declare protected readonly globalState; + private connectionName: string = ""; + + constructor(context: vscode.ExtensionContext) { + super(); + this.globalState = context.globalState; + } + + setConnectionName(connectionName: string) { + this.connectionName = connectionName; + } + + public keys(): readonly string[] { + return this.globalState.keys(); + } + + get(key: string): T | undefined { + return this.globalState.get(this.getStorageKey(key)) as T | undefined; + } + + async set(key: string, value: any) { + await this.globalState.update(this.getStorageKey(key), value); + } +} \ No newline at end of file diff --git a/src/api/Configuration.ts b/src/api/Configuration.ts index 4a551f247..55cb1b341 100644 --- a/src/api/Configuration.ts +++ b/src/api/Configuration.ts @@ -7,7 +7,7 @@ export type SourceDateMode = "edit" | "diff"; export type DefaultOpenMode = "browse" | "edit"; export type ReconnectMode = "always" | "never" | "ask"; -const getConfiguration = (): vscode.WorkspaceConfiguration => { +const getExtensionConfig = (): vscode.WorkspaceConfiguration => { return vscode.workspace.getConfiguration(`code-for-ibmi`); } @@ -20,13 +20,13 @@ export function onCodeForIBMiConfigurationChange(props: string | string[], to }) } -export namespace GlobalConfiguration { +export namespace GlobalVSCodeConfiguration { export function get(key: string): T | undefined { - return getConfiguration().get(key); + return getExtensionConfig().get(key); } export function set(key: string, value: any) { - return getConfiguration().update(key, value, vscode.ConfigurationTarget.Global); + return getExtensionConfig().update(key, value, vscode.ConfigurationTarget.Global); } } @@ -49,15 +49,15 @@ export namespace ConnectionManager { export function sort() { const connections = getAll(); connections.sort((a, b) => a.name.localeCompare(b.name)); - return GlobalConfiguration.set(`connections`, connections); + return GlobalVSCodeConfiguration.set(`connections`, connections); } export function getAll(): ConnectionData[] { - return GlobalConfiguration.get(`connections`) || []; + return GlobalVSCodeConfiguration.get(`connections`) || []; } function setAll(connections: ConnectionData[]) { - return GlobalConfiguration.set(`connections`, connections); + return GlobalVSCodeConfiguration.set(`connections`, connections); } export async function storeNew(data: ConnectionData): Promise { @@ -84,7 +84,7 @@ export namespace ConnectionManager { // Remove possible password from any connection connections.forEach(conn => delete conn.password); - return GlobalConfiguration.set(`connections`, connections); + return GlobalVSCodeConfiguration.set(`connections`, connections); } export function getStoredPassword(context: vscode.ExtensionContext, connectionName: string) { @@ -170,7 +170,7 @@ export namespace ConnectionConfiguration { } function getConnectionSettings(): Parameters[] { - return getConfiguration().get(`connectionSettings`) || []; + return getExtensionConfig().get(`connectionSettings`) || []; } function initialize(parameters: Partial): Parameters { @@ -219,7 +219,7 @@ export namespace ConnectionConfiguration { } async function updateAll(connections: Parameters[]) { - await getConfiguration().update(`connectionSettings`, connections, vscode.ConfigurationTarget.Global); + await getExtensionConfig().update(`connectionSettings`, connections, vscode.ConfigurationTarget.Global); } export async function update(parameters: Parameters) { diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index ee826236c..f15f7d35d 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -11,7 +11,7 @@ import { CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, import { CompileTools } from "./CompileTools"; import { ConnectionConfiguration } from "./Configuration"; import IBMiContent from "./IBMiContent"; -import { CachedServerSettings, GlobalStorage } from './Storage'; +import { CachedServerSettings, CodeForIStorage } from './Storage'; import { Tools } from './Tools'; import * as configVars from './configVars'; import { DebugConfiguration } from "../debug/config"; @@ -63,6 +63,7 @@ interface ConnectionCallbacks{ } export default class IBMi { + public static GlobalStorage: CodeForIStorage; static readonly CCSID_NOCONVERSION = 65535; static readonly CCSID_SYSVAL = -2; static readonly bashShellPath = '/QOpenSys/pkgs/bin/bash'; @@ -248,7 +249,7 @@ export default class IBMi { this.config = await ConnectionConfiguration.load(this.currentConnectionName); // Load cached server settings. - const cachedServerSettings: CachedServerSettings = GlobalStorage.get().getServerSettingsCache(this.currentConnectionName); + const cachedServerSettings: CachedServerSettings = IBMi.GlobalStorage.getServerSettingsCache(this.currentConnectionName); // Reload server settings? const quickConnect = () => { @@ -924,7 +925,7 @@ export default class IBMi { } } - GlobalStorage.get().setServerSettingsCache(this.currentConnectionName, { + IBMi.GlobalStorage.setServerSettingsCache(this.currentConnectionName, { lastCheckedOnVersion: currentExtensionVersion, aspInfo: this.aspInfo, qccsid: this.qccsid, diff --git a/src/api/Search.ts b/src/api/Search.ts index 22034ac58..6cfcbfb39 100644 --- a/src/api/Search.ts +++ b/src/api/Search.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import { GetMemberInfo } from './components/getMemberInfo'; import { IBMiMember, SearchHit, SearchResults } from '../typings'; -import { GlobalConfiguration } from './Configuration'; +import { GlobalVSCodeConfiguration } from './Configuration'; import { Tools } from './Tools'; import IBMi from './IBMi'; @@ -109,7 +109,7 @@ export namespace Search { const grep = connection.remoteFeatures.grep; if (grep) { - const dirsToIgnore = GlobalConfiguration.get(`grepIgnoreDirs`) || []; + const dirsToIgnore = GlobalVSCodeConfiguration.get(`grepIgnoreDirs`) || []; let ignoreString = ``; if (dirsToIgnore.length > 0) { @@ -141,7 +141,7 @@ export namespace Search { const find = connection.remoteFeatures.find; if (find) { - const dirsToIgnore = GlobalConfiguration.get(`grepIgnoreDirs`) || []; + const dirsToIgnore = GlobalVSCodeConfiguration.get(`grepIgnoreDirs`) || []; let ignoreString = ``; if (dirsToIgnore.length > 0) { diff --git a/src/api/Storage.ts b/src/api/Storage.ts index 869a28c2e..f23d8ca70 100644 --- a/src/api/Storage.ts +++ b/src/api/Storage.ts @@ -24,28 +24,6 @@ type AuthorisedExtension = { lastAccess: number } -abstract class Storage { - protected readonly globalState; - - constructor(context: vscode.ExtensionContext) { - this.globalState = context.globalState; - } - - protected keys(): readonly string[] { - return this.globalState.keys(); - } - - protected get(key: string): T | undefined { - return this.globalState.get(this.getStorageKey(key)) as T | undefined; - } - - protected async set(key: string, value: any) { - await this.globalState.update(this.getStorageKey(key), value); - } - - protected abstract getStorageKey(key: string): string; -} - export type LastConnection = { name: string timestamp: number @@ -66,29 +44,51 @@ export type CachedServerSettings = { maximumArgsLength: number } | undefined; -export class GlobalStorage extends Storage { - private static instance: GlobalStorage; +export abstract class Storage { + protected readonly globalState: any; - static initialize(context: vscode.ExtensionContext) { - if (!this.instance) { - this.instance = new GlobalStorage(context); - } + constructor() { + this.globalState = new Map(); } - static get() { - return this.instance; + keys(): readonly string[] { + return Array.from(this.globalState.keys()); } - private constructor(context: vscode.ExtensionContext) { - super(context); + get(key: string): T | undefined { + return this.globalState.get(this.getStorageKey(key)) as T | undefined; + } + + async set(key: string, value: any) { + await this.globalState.set(this.getStorageKey(key), value); + } + + getStorageKey(key: string): string { + return key; } +} + +export class CodeForIStorage { + // private static instance: GlobalStorage; + + // static initialize(context: vscode.ExtensionContext) { + // if (!this.instance) { + // this.instance = new GlobalStorage(context); + // } + // } + + // static get() { + // return this.instance; + // } + + constructor(private internalStorage: Storage) {} protected getStorageKey(key: string): string { return key; } getLastConnections() { - return this.get("lastConnections"); + return this.internalStorage.get("lastConnections"); } async setLastConnection(name: string) { @@ -104,67 +104,65 @@ export class GlobalStorage extends Storage { } async setLastConnections(lastConnections: LastConnection[]) { - await this.set("lastConnections", lastConnections.sort((c1, c2) => c2.timestamp - c1.timestamp)); + await this.internalStorage.set("lastConnections", lastConnections.sort((c1, c2) => c2.timestamp - c1.timestamp)); } getServerSettingsCache(name: string) { - return this.get(SERVER_SETTINGS_CACHE_KEY(name)); + return this.internalStorage.get(SERVER_SETTINGS_CACHE_KEY(name)); } async setServerSettingsCache(name: string, serverSettings: CachedServerSettings) { - await this.set(SERVER_SETTINGS_CACHE_KEY(name), serverSettings); + await this.internalStorage.set(SERVER_SETTINGS_CACHE_KEY(name), serverSettings); } async setServerSettingsCacheSpecific(name: string, newSettings: Partial) { - await this.set(SERVER_SETTINGS_CACHE_KEY(name), { + await this.internalStorage.set(SERVER_SETTINGS_CACHE_KEY(name), { ...this.getServerSettingsCache(name), ...newSettings }); } async deleteServerSettingsCache(name: string) { - await this.set(SERVER_SETTINGS_CACHE_KEY(name), undefined); + await this.internalStorage.set(SERVER_SETTINGS_CACHE_KEY(name), undefined); } async deleteStaleServerSettingsCache(connections: ConnectionData[]) { const validKeys = connections.map(connection => SERVER_SETTINGS_CACHE_KEY(connection.name)); - const currentKeys = this.keys(); + const currentKeys = this.internalStorage.keys(); const keysToDelete = currentKeys.filter(key => key.startsWith(SERVER_SETTINGS_CACHE_PREFIX) && !validKeys.includes(key)); for await (const key of keysToDelete) { - await this.set(key, undefined); + await this.internalStorage.set(key, undefined); } } getPreviousSearchTerms() { - return this.get(PREVIOUS_SEARCH_TERMS_KEY) || []; + return this.internalStorage.get(PREVIOUS_SEARCH_TERMS_KEY) || []; } async addPreviousSearchTerm(term: string) { - await this.set(PREVIOUS_SEARCH_TERMS_KEY, [term].concat(this.getPreviousSearchTerms().filter(t => t !== term))); + await this.internalStorage.set(PREVIOUS_SEARCH_TERMS_KEY, [term].concat(this.getPreviousSearchTerms().filter(t => t !== term))); } async clearPreviousSearchTerms(){ - await this.set(PREVIOUS_SEARCH_TERMS_KEY, undefined); + await this.internalStorage.set(PREVIOUS_SEARCH_TERMS_KEY, undefined); } getPreviousFindTerms() { - return this.get(PREVIOUS_FIND_TERMS_KEY) || []; + return this.internalStorage.get(PREVIOUS_FIND_TERMS_KEY) || []; } async addPreviousFindTerm(term: string) { - await this.set(PREVIOUS_FIND_TERMS_KEY, [term].concat(this.getPreviousFindTerms().filter(t => t !== term))); + await this.internalStorage.set(PREVIOUS_FIND_TERMS_KEY, [term].concat(this.getPreviousFindTerms().filter(t => t !== term))); } async clearPreviousFindTerms(){ - await this.set(PREVIOUS_FIND_TERMS_KEY, undefined); + await this.internalStorage.set(PREVIOUS_FIND_TERMS_KEY, undefined); } } -export class ConnectionStorage extends Storage { +export class ConnectionStorage { private connectionName: string = ""; - constructor(context: vscode.ExtensionContext) { - super(context); - } + constructor(private internalStorage: Storage) {} get ready(): boolean { if (this.connectionName) { @@ -184,60 +182,60 @@ export class ConnectionStorage extends Storage { } getSourceList() { - return this.get(SOURCE_LIST_KEY) || {}; + return this.internalStorage.get(SOURCE_LIST_KEY) || {}; } async setSourceList(sourceList: PathContent) { - await this.set(SOURCE_LIST_KEY, sourceList); + await this.internalStorage.set(SOURCE_LIST_KEY, sourceList); } getLastProfile() { - return this.get(LAST_PROFILE_KEY); + return this.internalStorage.get(LAST_PROFILE_KEY); } async setLastProfile(lastProfile: string) { - await this.set(LAST_PROFILE_KEY, lastProfile); + await this.internalStorage.set(LAST_PROFILE_KEY, lastProfile); } getPreviousCurLibs() { - return this.get(PREVIOUS_CUR_LIBS_KEY) || []; + return this.internalStorage.get(PREVIOUS_CUR_LIBS_KEY) || []; } async setPreviousCurLibs(previousCurLibs: string[]) { - await this.set(PREVIOUS_CUR_LIBS_KEY, previousCurLibs); + await this.internalStorage.set(PREVIOUS_CUR_LIBS_KEY, previousCurLibs); } getDeployment() { - return this.get(DEPLOYMENT_KEY) || {}; + return this.internalStorage.get(DEPLOYMENT_KEY) || {}; } async setDeployment(existingPaths: DeploymentPath) { - await this.set(DEPLOYMENT_KEY, existingPaths); + await this.internalStorage.set(DEPLOYMENT_KEY, existingPaths); } getDebugCommands() { - return this.get(DEBUG_KEY) || {}; + return this.internalStorage.get(DEBUG_KEY) || {}; } setDebugCommands(existingCommands: DebugCommands) { - return this.set(DEBUG_KEY, existingCommands); + return this.internalStorage.set(DEBUG_KEY, existingCommands); } getWorkspaceDeployPath(workspaceFolder: vscode.WorkspaceFolder) { - const deployDirs = this.get(DEPLOYMENT_KEY) || {}; + const deployDirs = this.internalStorage.get(DEPLOYMENT_KEY) || {}; return deployDirs[workspaceFolder.uri.fsPath].toLowerCase(); } getRecentlyOpenedFiles() { - return this.get(RECENTLY_OPENED_FILES_KEY) || []; + return this.internalStorage.get(RECENTLY_OPENED_FILES_KEY) || []; } async setRecentlyOpenedFiles(recentlyOpenedFiles: string[]) { - await this.set(RECENTLY_OPENED_FILES_KEY, recentlyOpenedFiles); + await this.internalStorage.set(RECENTLY_OPENED_FILES_KEY, recentlyOpenedFiles); } async clearRecentlyOpenedFiles() { - await this.set(RECENTLY_OPENED_FILES_KEY, undefined); + await this.internalStorage.set(RECENTLY_OPENED_FILES_KEY, undefined); } async grantExtensionAuthorisation(extension: vscode.Extension) { @@ -249,7 +247,7 @@ export class ConnectionStorage extends Storage { since: new Date().getTime(), lastAccess: new Date().getTime() }); - await this.set(AUTHORISED_EXTENSIONS_KEY, extensions); + await this.internalStorage.set(AUTHORISED_EXTENSIONS_KEY, extensions); } } @@ -262,7 +260,7 @@ export class ConnectionStorage extends Storage { } getAuthorisedExtensions(): AuthorisedExtension[] { - return this.get(AUTHORISED_EXTENSIONS_KEY) || []; + return this.internalStorage.get(AUTHORISED_EXTENSIONS_KEY) || []; } revokeAllExtensionAuthorisations() { @@ -271,6 +269,6 @@ export class ConnectionStorage extends Storage { revokeExtensionAuthorisation(...extensions: AuthorisedExtension[]) { const newExtensions = this.getAuthorisedExtensions().filter(ext => !extensions.includes(ext)); - return this.set(AUTHORISED_EXTENSIONS_KEY, newExtensions); + return this.internalStorage.set(AUTHORISED_EXTENSIONS_KEY, newExtensions); } } diff --git a/src/commands/open.ts b/src/commands/open.ts index 88cd07356..da7b436b3 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -3,7 +3,7 @@ import { MemberItem, OpenEditableOptions, WithPath } from "../typings"; import Instance from "../Instance"; import { Tools } from "../api/Tools"; import { getUriFromPath, parseFSOptions } from "../filesystems/qsys/QSysFs"; -import { DefaultOpenMode, GlobalConfiguration } from "../api/Configuration"; +import { DefaultOpenMode, GlobalVSCodeConfiguration } from "../api/Configuration"; import path from "path"; import { findExistingDocument, findExistingDocumentUri } from "../views/tools"; @@ -53,7 +53,7 @@ export function registerOpenCommands(instance: Instance): Disposable[] { } // Add file to front of recently opened files list. - const recentLimit = GlobalConfiguration.get(`recentlyOpenedFilesLimit`); + const recentLimit = GlobalVSCodeConfiguration.get(`recentlyOpenedFilesLimit`); const storage = instance.getStorage(); if (recentLimit) { const recent = storage!.getRecentlyOpenedFiles(); @@ -78,7 +78,7 @@ export function registerOpenCommands(instance: Instance): Disposable[] { }), commands.registerCommand("code-for-ibmi.openWithDefaultMode", (item: WithPath, overrideMode?: DefaultOpenMode, position?: Range) => { - const readonly = (overrideMode || GlobalConfiguration.get("defaultOpenMode")) === "browse"; + const readonly = (overrideMode || GlobalVSCodeConfiguration.get("defaultOpenMode")) === "browse"; commands.executeCommand(`code-for-ibmi.openEditable`, item.path, { readonly, position } as OpenEditableOptions); }), @@ -128,7 +128,7 @@ export function registerOpenCommands(instance: Instance): Disposable[] { let list: string[] = []; // Get recently opened files - cut if limit has been reduced. - const recentLimit = GlobalConfiguration.get(`recentlyOpenedFilesLimit`) as number; + const recentLimit = GlobalVSCodeConfiguration.get(`recentlyOpenedFilesLimit`) as number; const recent = storage!.getRecentlyOpenedFiles(); if (recent.length > recentLimit) { recent.splice(recentLimit); diff --git a/src/extension.ts b/src/extension.ts index 8f82a5952..80803d7f2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -7,7 +7,6 @@ import { ExtensionContext, commands, languages, window, workspace } from "vscode import { CustomUI } from "./webviews/CustomUI"; import { instance, loadAllofExtension } from './instantiate'; import { ConnectionConfiguration, ConnectionManager, onCodeForIBMiConfigurationChange } from "./api/Configuration"; -import { GlobalStorage } from "./api/Storage"; import { Tools } from "./api/Tools"; import * as Debug from './debug'; import { parseErrors } from "./api/errors/parser"; @@ -33,6 +32,7 @@ import { initializeObjectBrowser } from "./views/objectBrowser"; import { initializeSearchView } from "./views/searchView"; import { SettingsUI } from "./webviews/settings"; import { registerActionTools } from "./views/actions"; +import IBMi from "./api/IBMi"; export async function activate(context: ExtensionContext): Promise { // Use the console to output diagnostic information (console.log) and errors (console.error) @@ -42,10 +42,10 @@ export async function activate(context: ExtensionContext): Promise await loadAllofExtension(context); const updateLastConnectionAndServerCache = () => { const connections = ConnectionManager.getAll(); - const lastConnections = (GlobalStorage.get().getLastConnections() || []).filter(lc => connections.find(c => c.name === lc.name)); - GlobalStorage.get().setLastConnections(lastConnections); + const lastConnections = (IBMi.GlobalStorage.getLastConnections() || []).filter(lc => connections.find(c => c.name === lc.name)); + IBMi.GlobalStorage.setLastConnections(lastConnections); commands.executeCommand(`setContext`, `code-for-ibmi:hasPreviousConnection`, lastConnections.length > 0); - GlobalStorage.get().deleteStaleServerSettingsCache(connections); + IBMi.GlobalStorage.deleteStaleServerSettingsCache(connections); commands.executeCommand(`code-for-ibmi.refreshConnections`); }; @@ -86,7 +86,6 @@ export async function activate(context: ExtensionContext): Promise ); registerActionTools(context); - GlobalStorage.initialize(context); Debug.initialize(context); Deployment.initialize(context); updateLastConnectionAndServerCache(); diff --git a/src/filesystems/local/git.ts b/src/filesystems/local/git.ts index 237256048..33ea192a6 100644 --- a/src/filesystems/local/git.ts +++ b/src/filesystems/local/git.ts @@ -1,7 +1,7 @@ import { ExtensionContext, WorkspaceFolder, commands, window } from "vscode"; import { getBranchLibraryName } from "./env"; import { instance } from "../../instantiate"; -import { ConnectionConfiguration, GlobalConfiguration } from "../../api/Configuration"; +import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../../api/Configuration"; import IBMi from "../../api/IBMi"; import IBMiContent from "../../api/IBMiContent"; import { getGitAPI } from "../../views/tools"; @@ -26,7 +26,7 @@ export function setupGitEventHandler(context: ExtensionContext) { const workspaceUri = repo.rootUri.toString(); const changeEvent = repo.state.onDidChange((_e) => { - if (GlobalConfiguration.get(`createLibraryOnBranchChange`)) { + if (GlobalVSCodeConfiguration.get(`createLibraryOnBranchChange`)) { if (repo) { const head = repo.state.HEAD; const connection = instance.getConnection(); diff --git a/src/filesystems/qsys/FSUtils.ts b/src/filesystems/qsys/FSUtils.ts index edaf6cc36..67a23be8f 100644 --- a/src/filesystems/qsys/FSUtils.ts +++ b/src/filesystems/qsys/FSUtils.ts @@ -1,8 +1,8 @@ import path from "path"; import vscode, { l10n } from "vscode"; -import { GlobalConfiguration, ReconnectMode } from "../../api/Configuration"; -import { GlobalStorage } from "../../api/Storage"; +import { GlobalVSCodeConfiguration, ReconnectMode } from "../../api/Configuration"; import { findUriTabs } from "../../views/tools"; +import IBMi from "../../api/IBMi"; /** * Called when a member/streamfile is left open when VS Code is closed and re-opened to reconnect (or not) to the previous IBM i, based on the `autoReconnect` global configuration value. @@ -12,7 +12,7 @@ import { findUriTabs } from "../../views/tools"; * @returns `true` if the user choses to reconnect, `false` otherwise. */ export async function reconnectFS(uri: vscode.Uri) { - const reconnect = GlobalConfiguration.get("autoReconnect") || "ask"; + const reconnect = GlobalVSCodeConfiguration.get("autoReconnect") || "ask"; let doReconnect = false; switch (reconnect) { case "always": @@ -20,7 +20,7 @@ export async function reconnectFS(uri: vscode.Uri) { break; case "ask": - const lastConnection = GlobalStorage.get().getLastConnections()?.at(0)?.name; + const lastConnection = IBMi.GlobalStorage.getLastConnections()?.at(0)?.name; if (lastConnection) { if (await vscode.window.showInformationMessage(l10n.t("Do you want to reconnect to {0} and open {1}?", lastConnection, path.basename(uri.path)), l10n.t("Reconnect"))) { doReconnect = true; diff --git a/src/filesystems/qsys/extendedContent.ts b/src/filesystems/qsys/extendedContent.ts index f7a13fc56..a803faa63 100644 --- a/src/filesystems/qsys/extendedContent.ts +++ b/src/filesystems/qsys/extendedContent.ts @@ -2,7 +2,7 @@ import fs from "fs"; import tmp from "tmp"; import util from "util"; import vscode from "vscode"; -import { GlobalConfiguration } from "../../api/Configuration"; +import { GlobalVSCodeConfiguration } from "../../api/Configuration"; import { instance } from "../../instantiate"; import { getAliasName, SourceDateHandler } from "./sourceDateHandler"; @@ -33,7 +33,7 @@ export class ExtendedIBMiContent { const config = instance.getConfig(); const connection = instance.getConnection(); if (connection && config && content) { - const sourceColourSupport = GlobalConfiguration.get(`showSeuColors`); + const sourceColourSupport = GlobalVSCodeConfiguration.get(`showSeuColors`); const tempLib = config.tempLibrary; const alias = getAliasName(uri); const aliasPath = `${tempLib}.${alias}`; @@ -133,7 +133,7 @@ export class ExtendedIBMiContent { const { library, file, name } = connection.parserMemberPath(uri.path); const tempRmt = connection.getTempRemote(library + file + name); if (tempRmt) { - const sourceColourSupport = GlobalConfiguration.get(`showSeuColors`); + const sourceColourSupport = GlobalVSCodeConfiguration.get(`showSeuColors`); const tmpobj = await tmpFile(); const sourceData = body.split(`\n`); diff --git a/src/filesystems/qsys/sourceDateHandler.ts b/src/filesystems/qsys/sourceDateHandler.ts index dac930acb..0e1730554 100644 --- a/src/filesystems/qsys/sourceDateHandler.ts +++ b/src/filesystems/qsys/sourceDateHandler.ts @@ -2,7 +2,7 @@ import Crypto from "crypto"; import vscode from "vscode"; import { DiffComputer } from "vscode-diff"; -import { GlobalConfiguration, SourceDateMode } from "../../api/Configuration"; +import { GlobalVSCodeConfiguration, SourceDateMode } from "../../api/Configuration"; import { instance } from "../../instantiate"; const editedTodayColor = new vscode.ThemeColor(`gitDecoration.modifiedResourceForeground`); @@ -100,7 +100,7 @@ export class SourceDateHandler { changeSourceDateMode(sourceDateMode: SourceDateMode) { this.sourceDateMode = sourceDateMode; - const dateSearchButtonEnabled = GlobalConfiguration.get(`showDateSearchButton`); + const dateSearchButtonEnabled = GlobalVSCodeConfiguration.get(`showDateSearchButton`); if (this.sourceDateMode === "diff" && dateSearchButtonEnabled) { this.sourceDateSearchBarItem.show(); diff --git a/src/instantiate.ts b/src/instantiate.ts index e8fc9043b..788219b4e 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode"; -import { GlobalConfiguration, onCodeForIBMiConfigurationChange } from "./api/Configuration"; +import { GlobalVSCodeConfiguration, onCodeForIBMiConfigurationChange } from "./api/Configuration"; import Instance from "./Instance"; import { Terminal } from './views/Terminal'; import { getDebugServiceDetails } from './debug/config'; @@ -97,7 +97,7 @@ export async function loadAllofExtension(context: vscode.ExtensionContext) { ); // Color provider - if (GlobalConfiguration.get(`showSeuColors`)) { + if (GlobalVSCodeConfiguration.get(`showSeuColors`)) { SEUColorProvider.intitialize(context); } diff --git a/src/views/ConnectionBrowser.ts b/src/views/ConnectionBrowser.ts index 6240c8fe4..6ede3245f 100644 --- a/src/views/ConnectionBrowser.ts +++ b/src/views/ConnectionBrowser.ts @@ -1,10 +1,10 @@ import vscode from 'vscode'; import { ConnectionData, Server } from '../typings'; -import { ConnectionConfiguration, ConnectionManager, GlobalConfiguration } from '../api/Configuration'; -import { GlobalStorage } from '../api/Storage'; +import { ConnectionConfiguration, ConnectionManager, GlobalVSCodeConfiguration } from '../api/Configuration'; import { instance } from '../instantiate'; import { Login } from '../webviews/login'; +import IBMi from '../api/IBMi'; type CopyOperationItem = { label: string @@ -30,7 +30,7 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { }), vscode.commands.registerCommand(`code-for-ibmi.connectToPrevious`, async () => { - const lastConnection = GlobalStorage.get().getLastConnections()?.[0]; + const lastConnection = IBMi.GlobalStorage.getLastConnections()?.[0]; if (lastConnection) { return await vscode.commands.executeCommand(`code-for-ibmi.connectTo`, lastConnection.name); } @@ -41,7 +41,7 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { connectionBrowser.attemptingConnection = true; if (!name) { - const lastConnections = GlobalStorage.get().getLastConnections() || []; + const lastConnections = IBMi.GlobalStorage.getLastConnections() || []; if (lastConnections && lastConnections.length) { name = (await vscode.window.showQuickPick([{ kind: vscode.QuickPickItemKind.Separator, label: vscode.l10n.t(`Last connection`) }, ...lastConnections.map(lc => ({ label: lc.name, description: vscode.l10n.t(`Last used: {0}`, new Date(lc.timestamp).toLocaleString()) }))], @@ -101,22 +101,22 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { await ConnectionManager.updateByIndex(index, data); // Then rename the connection settings - const connectionSettings = GlobalConfiguration.get(`connectionSettings`) || []; + const connectionSettings = GlobalVSCodeConfiguration.get(`connectionSettings`) || []; index = connectionSettings.findIndex(connection => connection.name === server.name); if (index === -1) throw (vscode.l10n.t(`No parameters for connection "{0}" was found`, server.name)); connectionSettings[index].name = newName; // Then get the cached connection settings - const cachedConnectionSettings = GlobalStorage.get().getServerSettingsCache(server.name); + const cachedConnectionSettings = IBMi.GlobalStorage.getServerSettingsCache(server.name); // Then get the password key const secret = await ConnectionManager.getStoredPassword(context, server.name); // No errors - update the settings. - await GlobalConfiguration.set(`connectionSettings`, connectionSettings); + await GlobalVSCodeConfiguration.set(`connectionSettings`, connectionSettings); if (cachedConnectionSettings) { - GlobalStorage.get().setServerSettingsCache(newName, cachedConnectionSettings); - GlobalStorage.get().deleteServerSettingsCache(server.name); + IBMi.GlobalStorage.setServerSettingsCache(newName, cachedConnectionSettings); + IBMi.GlobalStorage.deleteServerSettingsCache(server.name); } if (secret) { await ConnectionManager.setStoredPassword(context, newName, secret); @@ -158,12 +158,12 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { await ConnectionManager.deleteByName(server.name); // Also remove the connection settings - const connectionSettings = GlobalConfiguration.get(`connectionSettings`) || []; + const connectionSettings = GlobalVSCodeConfiguration.get(`connectionSettings`) || []; const newConnectionSettings = connectionSettings.filter(connection => connection.name !== server.name); - await GlobalConfiguration.set(`connectionSettings`, newConnectionSettings); + await GlobalVSCodeConfiguration.set(`connectionSettings`, newConnectionSettings); // Also remove the cached connection settings - GlobalStorage.get().deleteServerSettingsCache(server.name); + IBMi.GlobalStorage.deleteServerSettingsCache(server.name); // Then remove the password await ConnectionManager.deleteStoredPassword(context, server.name); @@ -174,7 +174,7 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { } }), vscode.commands.registerCommand(`code-for-ibmi.copyConnection`, async (server: Server) => { - const connectionSettings = GlobalConfiguration.get(`connectionSettings`) || []; + const connectionSettings = GlobalVSCodeConfiguration.get(`connectionSettings`) || []; const connection = ConnectionManager.getByName(server.name); const connectionSetting = connectionSettings.find(connection => server.name === connection.name); @@ -226,7 +226,7 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { newConnectionSetting.connectionProfiles = []; copyOperations.forEach(operation => operation(connectionSetting, newConnectionSetting)); connectionSettings.push(newConnectionSetting); - await GlobalConfiguration.set(`connectionSettings`, connectionSettings); + await GlobalVSCodeConfiguration.set(`connectionSettings`, connectionSettings); const password = await ConnectionManager.getStoredPassword(context, server.name); if (password) { @@ -258,7 +258,7 @@ class ConnectionBrowser implements vscode.TreeDataProvider { } async getChildren(): Promise { - const lastConnection = GlobalStorage.get().getLastConnections()?.[0]; + const lastConnection = IBMi.GlobalStorage.getLastConnections()?.[0]; return ConnectionManager.getAll() .map(connection => new ServerItem(connection, connection.name === lastConnection?.name)); } @@ -267,7 +267,7 @@ class ConnectionBrowser implements vscode.TreeDataProvider { class ServerItem extends vscode.TreeItem implements Server { constructor(readonly connection: ConnectionData, lastConnected?: boolean) { super(connection.name, vscode.TreeItemCollapsibleState.None); - const readOnly = (GlobalConfiguration.get(`connectionSettings`) || []) + const readOnly = (GlobalVSCodeConfiguration.get(`connectionSettings`) || []) .find(settings => connection.name === settings.name) ?.readOnlyMode diff --git a/src/views/LibraryListView.ts b/src/views/LibraryListView.ts index 0cb6c32f5..560b04d50 100644 --- a/src/views/LibraryListView.ts +++ b/src/views/LibraryListView.ts @@ -1,5 +1,5 @@ import vscode, { commands, l10n } from "vscode"; -import { ConnectionConfiguration, GlobalConfiguration } from "../api/Configuration"; +import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../api/Configuration"; import { instance } from "../instantiate"; import { IBMiObject, WithLibrary } from "../typings"; import { objectToToolTip } from "./tools"; @@ -258,7 +258,7 @@ export class LibraryListProvider implements vscode.TreeDataProvider(`terminals.${type.toLowerCase()}.openInEditorArea`) ? vscode.TerminalLocation.Editor : vscode.TerminalLocation.Panel, + location: GlobalVSCodeConfiguration.get(`terminals.${type.toLowerCase()}.openInEditorArea`) ? vscode.TerminalLocation.Editor : vscode.TerminalLocation.Panel, connectionString: configuration.connectringStringFor5250, currentDirectory: options?.currentDirectory }; diff --git a/src/views/actions.ts b/src/views/actions.ts index 7da4f0346..0f54c505a 100644 --- a/src/views/actions.ts +++ b/src/views/actions.ts @@ -8,7 +8,7 @@ import { getGitBranch } from '../filesystems/local/git'; import Instance from '../Instance'; import { parseFSOptions } from '../filesystems/qsys/QSysFs'; import { Action, BrowserItem, DeploymentMethod, Variable } from '../typings'; -import { GlobalConfiguration } from '../api/Configuration'; +import { GlobalVSCodeConfiguration } from '../api/Configuration'; import vscode, { CustomExecution, Pseudoterminal, TaskGroup, TaskRevealKind, WorkspaceFolder, commands, tasks } from 'vscode'; import { CustomUI } from '../webviews/CustomUI'; @@ -50,7 +50,7 @@ export async function runAction(instance: Instance, uri: vscode.Uri, customActio let availableActions: { label: string; action: Action; }[] = []; if (!customAction) { // First we grab a copy the predefined Actions in the VS Code settings - const allActions = [...GlobalConfiguration.get(`actions`) || []]; + const allActions = [...GlobalVSCodeConfiguration.get(`actions`) || []]; // Then, if we're being called from a local file // we fetch the Actions defined from the workspace. @@ -250,7 +250,7 @@ export async function runAction(instance: Instance, uri: vscode.Uri, customActio break; } - const viewControl = GlobalConfiguration.get(`postActionView`) || "none"; + const viewControl = GlobalVSCodeConfiguration.get(`postActionView`) || "none"; const outputBuffer: string[] = []; let actionName = chosenAction.name; let hasRun = false; @@ -280,7 +280,7 @@ export async function runAction(instance: Instance, uri: vscode.Uri, customActio source: 'IBM i', presentationOptions: { showReuseMessage: true, - clear: GlobalConfiguration.get(`clearOutputEveryTime`), + clear: GlobalVSCodeConfiguration.get(`clearOutputEveryTime`), focus: false, reveal: (viewControl === `task` ? TaskRevealKind.Always : TaskRevealKind.Never), }, diff --git a/src/views/diagnostics.ts b/src/views/diagnostics.ts index c85e6b1f8..25c120b10 100644 --- a/src/views/diagnostics.ts +++ b/src/views/diagnostics.ts @@ -1,7 +1,7 @@ import * as vscode from "vscode"; import { FileError } from "../typings"; -import { GlobalConfiguration } from "../api/Configuration"; +import { GlobalVSCodeConfiguration } from "../api/Configuration"; import Instance from "../Instance"; import { getEvfeventFiles } from "../filesystems/local/actions"; import { parseErrors } from "../api/errors/parser"; @@ -26,7 +26,7 @@ export function registerDiagnostics(): vscode.Disposable[] { }), ]; - if (GlobalConfiguration.get(`clearDiagnosticOnEdit`)) { + if (GlobalVSCodeConfiguration.get(`clearDiagnosticOnEdit`)) { disposables.push( vscode.workspace.onDidChangeTextDocument(e => { if (ileDiagnostics.has(e.document.uri)) { @@ -64,7 +64,7 @@ export async function refreshDiagnosticsFromServer(instance: Instance, evfeventI const tableData = await content.getTable(evfeventInfo.library, `EVFEVENT`, evfeventInfo.object); const lines = tableData.map(row => String(row.EVFEVENT)); - if (GlobalConfiguration.get(`clearErrorsBeforeBuild`)) { + if (GlobalVSCodeConfiguration.get(`clearErrorsBeforeBuild`)) { // Clear all errors if the user has this setting enabled clearDiagnostics(); } @@ -81,7 +81,7 @@ export async function refreshDiagnosticsFromLocal(instance: Instance, evfeventIn if (evfeventFiles) { const filesContent = await Promise.all(evfeventFiles.map(uri => vscode.workspace.fs.readFile(uri))); - if (GlobalConfiguration.get(`clearErrorsBeforeBuild`)) { + if (GlobalVSCodeConfiguration.get(`clearErrorsBeforeBuild`)) { // Clear all errors if the user has this setting enabled clearDiagnostics(); } diff --git a/src/views/ifsBrowser.ts b/src/views/ifsBrowser.ts index 978556c87..db2eeea49 100644 --- a/src/views/ifsBrowser.ts +++ b/src/views/ifsBrowser.ts @@ -3,14 +3,14 @@ import path, { dirname, extname } from "path"; import vscode, { FileType, l10n, window } from "vscode"; import { existsSync, mkdirSync, rmdirSync } from "fs"; -import { ConnectionConfiguration, GlobalConfiguration } from "../api/Configuration"; +import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../api/Configuration"; import { SortOptions } from "../api/IBMiContent"; import { Search } from "../api/Search"; -import { GlobalStorage } from "../api/Storage"; import { Tools } from "../api/Tools"; import { instance } from "../instantiate"; import { BrowserItem, BrowserItemParameters, FocusOptions, IFSFile, IFS_BROWSER_MIMETYPE, OBJECT_BROWSER_MIMETYPE, SearchHit, SearchResults, WithPath } from "../typings"; import { fileToPath, findUriTabs, ifsFileToToolTip } from "./tools"; +import IBMi from "../api/IBMi"; const URI_LIST_MIMETYPE = "text/uri-list"; const URI_LIST_SEPARATOR = "\r\n"; @@ -18,7 +18,7 @@ const PROTECTED_DIRS = /^(\/|\/QOpenSys|\/QSYS\.LIB|\/QDLS|\/QOPT|\/QNTC|\/QFile const ALWAYS_SHOW_FILES = /^(\.gitignore|\.vscode|\.deployignore)$/i; type DragNDropAction = "move" | "copy"; type DragNDropBehavior = DragNDropAction | "ask"; -const getDragDropBehavior = () => GlobalConfiguration.get(`IfsBrowser.DragAndDropDefaultBehavior`) || "ask"; +const getDragDropBehavior = () => GlobalVSCodeConfiguration.get(`IfsBrowser.DragAndDropDefaultBehavior`) || "ask"; function isProtected(path: string) { return PROTECTED_DIRS.test(path) || instance.getContent()?.isProtectedPath(path); @@ -82,7 +82,7 @@ class IFSBrowser implements vscode.TreeDataProvider { shortcuts.splice(newPosition, 0, moveDir); config.ifsShortcuts = shortcuts; await ConnectionConfiguration.update(config); - if (GlobalConfiguration.get(`autoRefresh`)) { + if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { this.refresh(); } } @@ -364,7 +364,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { if (config.autoSortIFSShortcuts) { vscode.commands.executeCommand(`code-for-ibmi.sortIFSShortcuts`); } - if (GlobalConfiguration.get(`autoRefresh`)) { + if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { ifsBrowser.refresh(); } } @@ -390,7 +390,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { shortcuts.splice(inx, 1); config.ifsShortcuts = shortcuts; await ConnectionConfiguration.update(config); - if (GlobalConfiguration.get(`autoRefresh`)) { + if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { ifsBrowser.refresh(); } } @@ -408,7 +408,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { try { config.ifsShortcuts.sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase())); await ConnectionConfiguration.update(config); - if (GlobalConfiguration.get(`autoRefresh`)) { + if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { ifsBrowser.refresh(); } } catch (e) { @@ -438,7 +438,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { try { await connection.sendCommand({ command: `mkdir ${Tools.escapePath(fullName)}` }); - if (GlobalConfiguration.get(`autoRefresh`)) { + if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { ifsBrowser.refresh(node); } @@ -466,7 +466,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { vscode.window.showInformationMessage(l10n.t(`Creating streamfile {0}.`, fullName)); await content.createStreamFile(fullName); vscode.commands.executeCommand(`code-for-ibmi.openEditable`, fullName); - if (GlobalConfiguration.get(`autoRefresh`)) { + if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { ifsBrowser.refresh(node); } else { @@ -524,7 +524,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { } } - if (GlobalConfiguration.get(`autoRefresh`)) { + if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { ifsBrowser.refresh(node); } vscode.window.showInformationMessage(l10n.t(`Upload completed.`)); @@ -558,7 +558,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { if (await vscode.window.showWarningMessage(message, { modal: true, detail }, l10n.t(`Yes`))) { const toBeDeleted: string[] = []; for (const item of items) { - if ((GlobalConfiguration.get(`safeDeleteMode`)) && item.file.type === `directory`) { //Check if path is directory + if ((GlobalVSCodeConfiguration.get(`safeDeleteMode`)) && item.file.type === `directory`) { //Check if path is directory const dirName = path.basename(item.path) //Get the name of the directory to be deleted const deletionPrompt = l10n.t(`Once you delete the directory, it cannot be restored. @@ -591,7 +591,7 @@ Please type "{0}" to confirm deletion.`, dirName); if (removeResult.code !== 0) { throw removeResult.stderr; } - if (GlobalConfiguration.get(`autoRefresh`)) { + if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { items.map(item => item.parent) .filter(Tools.distinct) .forEach(async parent => parent?.refresh?.()); @@ -653,7 +653,7 @@ Please type "{0}" to confirm deletion.`, dirName); throw moveResult.stderr; } - if (GlobalConfiguration.get(`autoRefresh`)) { + if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { ifsBrowser.refresh(); } let label; @@ -699,7 +699,7 @@ Please type "{0}" to confirm deletion.`, dirName); const targetPath = target.startsWith(`/`) ? target : homeDirectory + `/` + target; try { await connection.sendCommand({ command: `cp -r ${Tools.escapePath(node.path)} ${Tools.escapePath(targetPath)}` }); - if (GlobalConfiguration.get(`autoRefresh`)) { + if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { ifsBrowser.refresh(); } vscode.window.showInformationMessage(l10n.t(`{0} was copied to {1}.`, Tools.escapePath(node.path), Tools.escapePath(targetPath))); @@ -724,7 +724,7 @@ Please type "{0}" to confirm deletion.`, dirName); }); if (searchPath) { - const list = GlobalStorage.get().getPreviousSearchTerms(); + const list = IBMi.GlobalStorage.getPreviousSearchTerms(); const items: vscode.QuickPickItem[] = list.map(term => ({ label: term })); const listHeader = [ { label: l10n.t(`Previous search terms`), kind: vscode.QuickPickItemKind.Separator } @@ -751,14 +751,14 @@ Please type "{0}" to confirm deletion.`, dirName); const searchTerm = quickPick.activeItems[0].label; if (searchTerm) { if (searchTerm === clearList) { - GlobalStorage.get().clearPreviousSearchTerms(); + IBMi.GlobalStorage.clearPreviousSearchTerms(); quickPick.items = []; quickPick.placeholder = l10n.t(`Enter search term.`); vscode.window.showInformationMessage(l10n.t(`Cleared list.`)); quickPick.show(); } else { quickPick.hide(); - GlobalStorage.get().addPreviousSearchTerm(searchTerm); + IBMi.GlobalStorage.addPreviousSearchTerm(searchTerm); await doSearchInStreamfiles(searchTerm, searchPath); } } @@ -784,7 +784,7 @@ Please type "{0}" to confirm deletion.`, dirName); }); if (findPath) { - const list = GlobalStorage.get().getPreviousFindTerms(); + const list = IBMi.GlobalStorage.getPreviousFindTerms(); const items: vscode.QuickPickItem[] = list.map(term => ({ label: term })); const listHeader = [ { label: l10n.t("Previous find terms"), kind: vscode.QuickPickItemKind.Separator } @@ -811,14 +811,14 @@ Please type "{0}" to confirm deletion.`, dirName); const findTerm = quickPick.activeItems[0].label; if (findTerm) { if (findTerm === clearList) { - GlobalStorage.get().clearPreviousFindTerms(); + IBMi.GlobalStorage.clearPreviousFindTerms(); quickPick.items = []; quickPick.placeholder = l10n.t(`Enter find term.`); vscode.window.showInformationMessage(l10n.t(`Cleared list.`)); quickPick.show(); } else { quickPick.hide(); - GlobalStorage.get().addPreviousFindTerm(findTerm); + IBMi.GlobalStorage.addPreviousFindTerm(findTerm); await doFindStreamfiles(findTerm, findPath); } } diff --git a/src/views/objectBrowser.ts b/src/views/objectBrowser.ts index aae0b3dff..b83f88a2a 100644 --- a/src/views/objectBrowser.ts +++ b/src/views/objectBrowser.ts @@ -2,12 +2,11 @@ import fs, { existsSync } from "fs"; import os from "os"; import path, { basename, dirname } from "path"; import vscode from "vscode"; -import { ConnectionConfiguration, DefaultOpenMode, GlobalConfiguration } from "../api/Configuration"; +import { ConnectionConfiguration, DefaultOpenMode, GlobalVSCodeConfiguration } from "../api/Configuration"; import { parseFilter, singleGenericName } from "../api/Filter"; -import { MemberParts } from "../api/IBMi"; +import IBMi, { MemberParts } from "../api/IBMi"; import { SortOptions, SortOrder } from "../api/IBMiContent"; import { Search } from "../api/Search"; -import { GlobalStorage } from '../api/Storage'; import { Tools } from "../api/Tools"; import { getMemberUri } from "../filesystems/qsys/QSysFs"; import { instance } from "../instantiate"; @@ -17,8 +16,8 @@ import { findUriTabs, memberToToolTip, objectToToolTip, sourcePhysicalFileToTool const URI_LIST_SEPARATOR = "\r\n"; -const objectNamesLower = () => GlobalConfiguration.get(`ObjectBrowser.showNamesInLowercase`); -const objectSortOrder = () => GlobalConfiguration.get(`ObjectBrowser.sortObjectsByName`) ? `name` : `type`; +const objectNamesLower = () => GlobalVSCodeConfiguration.get(`ObjectBrowser.showNamesInLowercase`); +const objectSortOrder = () => GlobalVSCodeConfiguration.get(`ObjectBrowser.sortObjectsByName`) ? `name` : `type`; const correctCase = (value: string) => { ; @@ -111,7 +110,7 @@ class ObjectBrowser implements vscode.TreeDataProvider { } autoRefresh(message?: string) { - const autoRefresh = GlobalConfiguration.get(`autoRefresh`); + const autoRefresh = GlobalVSCodeConfiguration.get(`autoRefresh`); if (autoRefresh) { if (message) { vscode.window.showInformationMessage(message); @@ -567,7 +566,7 @@ export function initializeObjectBrowser(context: vscode.ExtensionContext) { }) if (addResult.code === 0) { - if (GlobalConfiguration.get(`autoOpenFile`)) { + if (GlobalVSCodeConfiguration.get(`autoOpenFile`)) { vscode.commands.executeCommand(`code-for-ibmi.openEditable`, fullPath); } @@ -644,7 +643,7 @@ export function initializeObjectBrowser(context: vscode.ExtensionContext) { }); } - if (GlobalConfiguration.get(`autoOpenFile`)) { + if (GlobalVSCodeConfiguration.get(`autoOpenFile`)) { vscode.commands.executeCommand(`code-for-ibmi.openEditable`, fullPath); } @@ -966,7 +965,7 @@ Do you want to replace it?`, item.name), skipAllLabel, overwriteLabel, overwrite if (pathParts[1] !== `*ALL`) { const aspText = ((config.sourceASP && config.sourceASP.length > 0) ? vscode.l10n.t(`(in ASP {0})`, config.sourceASP) : ``); - const list = GlobalStorage.get().getPreviousSearchTerms(); + const list = IBMi.GlobalStorage.getPreviousSearchTerms(); const listHeader: vscode.QuickPickItem[] = [ { label: vscode.l10n.t(`Previous search terms`), kind: vscode.QuickPickItemKind.Separator } ]; @@ -991,14 +990,14 @@ Do you want to replace it?`, item.name), skipAllLabel, overwriteLabel, overwrite const searchTerm = quickPick.activeItems[0].label; if (searchTerm) { if (searchTerm === clearList) { - GlobalStorage.get().clearPreviousSearchTerms(); + IBMi.GlobalStorage.clearPreviousSearchTerms(); quickPick.items = []; quickPick.placeholder = vscode.l10n.t(`Enter search term.`); vscode.window.showInformationMessage(vscode.l10n.t(`Cleared list.`)); quickPick.show(); } else { quickPick.hide(); - GlobalStorage.get().addPreviousSearchTerm(searchTerm); + IBMi.GlobalStorage.addPreviousSearchTerm(searchTerm); await doSearchInSourceFile(searchTerm, parameters.path, parameters.filter); } } @@ -1395,7 +1394,7 @@ async function doSearchInSourceFile(searchTerm: string, path: string, filter?: C const results = await Search.searchMembers(instance.getConnection()!, library, sourceFile, searchTerm, memberFilter, filter?.protected); clearInterval(messageTimeout) if (results.hits.length) { - const objectNamesLower = GlobalConfiguration.get(`ObjectBrowser.showNamesInLowercase`); + const objectNamesLower = GlobalVSCodeConfiguration.get(`ObjectBrowser.showNamesInLowercase`); // Format result to be lowercase if the setting is enabled results.hits.forEach(result => { diff --git a/src/webviews/actions/index.ts b/src/webviews/actions/index.ts index ce6d930ad..19348cf80 100644 --- a/src/webviews/actions/index.ts +++ b/src/webviews/actions/index.ts @@ -2,7 +2,7 @@ import vscode from "vscode"; import { CustomUI, Tab } from "../CustomUI"; -import { GlobalConfiguration } from "../../api/Configuration"; +import { GlobalVSCodeConfiguration } from "../../api/Configuration"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; import { Action, ActionEnvironment, ActionRefresh, ActionType } from "../../typings"; @@ -302,11 +302,11 @@ export namespace ActionsUI { } async function saveActions(actions: Action[]) { - return GlobalConfiguration.set(`actions`, actions); + return GlobalVSCodeConfiguration.set(`actions`, actions); } function loadActions(): Action[] { - return GlobalConfiguration.get(`actions`) || []; + return GlobalVSCodeConfiguration.get(`actions`) || []; } function getDefaultTabIndex(type?: ActionType) { diff --git a/src/webviews/commandProfile/index.ts b/src/webviews/commandProfile/index.ts index eb4c5470a..0feb41d72 100644 --- a/src/webviews/commandProfile/index.ts +++ b/src/webviews/commandProfile/index.ts @@ -1,5 +1,5 @@ import { commands, window } from "vscode"; -import { ConnectionConfiguration, GlobalConfiguration } from "../../api/Configuration"; +import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../../api/Configuration"; import { CustomUI } from "../CustomUI"; import { instance } from "../../instantiate"; diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 8c4a6e6bc..2b11d9e6a 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -1,8 +1,7 @@ import { existsSync } from "fs"; import vscode from "vscode"; -import { ConnectionConfiguration, ConnectionManager, GlobalConfiguration } from "../../api/Configuration"; +import { ConnectionConfiguration, ConnectionManager, GlobalVSCodeConfiguration } from "../../api/Configuration"; import { ComplexTab, CustomUI, Section } from "../CustomUI"; -import { GlobalStorage } from '../../api/Storage'; import { Tools } from "../../api/Tools"; import { isManaged } from "../../debug"; import * as certificates from "../../debug/certificates"; @@ -11,6 +10,7 @@ import { extensionComponentRegistry } from "../../api/components/manager"; import { instance } from "../../instantiate"; import { ConnectionData, Server } from '../../typings'; import { withContext } from "../../views/tools"; +import IBMi from "../../api/IBMi"; const EDITING_CONTEXT = `code-for-ibmi:editingConnection`; @@ -36,7 +36,7 @@ export class SettingsUI { context.subscriptions.push( vscode.commands.registerCommand(`code-for-ibmi.showAdditionalSettings`, async (server?: Server, tab?: string) => { - const connectionSettings = GlobalConfiguration.get(`connectionSettings`); + const connectionSettings = GlobalVSCodeConfiguration.get(`connectionSettings`); const connection = instance.getConnection(); const passwordAuthorisedExtensions = instance.getStorage()?.getAuthorisedExtensions() || []; @@ -321,7 +321,7 @@ export class SettingsUI { Object.assign(config, data); await instance.setConfig(config); if (removeCachedSettings) - GlobalStorage.get().deleteServerSettingsCache(config.name); + IBMi.GlobalStorage.deleteServerSettingsCache(config.name); if (connection) { if (restart) { @@ -420,7 +420,7 @@ export class SettingsUI { stored = Object.assign(stored, data); await ConnectionManager.updateByIndex(index, stored); - GlobalStorage.get().deleteServerSettingsCache(server.name); + IBMi.GlobalStorage.deleteServerSettingsCache(server.name); vscode.commands.executeCommand(`code-for-ibmi.refreshConnections`); } }); From 76dd3b541d31583f7268ef96a64cd442de2ff24b Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 15:53:06 -0500 Subject: [PATCH 15/46] Move configuration out of API Signed-off-by: worksofliam --- src/{api => }/Configuration.ts | 4 ++-- src/Instance.ts | 2 +- src/api/IBMi.ts | 2 +- src/api/IBMiContent.ts | 2 +- src/api/Search.ts | 2 +- src/commands/actions.ts | 2 +- src/commands/connection.ts | 2 +- src/commands/open.ts | 2 +- src/commands/password.ts | 2 +- src/debug/index.ts | 2 +- src/extension.ts | 2 +- src/filesystems/local/git.ts | 2 +- src/filesystems/qsys/FSUtils.ts | 2 +- src/filesystems/qsys/QSysFs.ts | 2 +- src/filesystems/qsys/extendedContent.ts | 2 +- src/filesystems/qsys/sourceDateHandler.ts | 2 +- src/instantiate.ts | 2 +- src/sandbox.ts | 2 +- src/typings.ts | 2 +- src/views/ConnectionBrowser.ts | 2 +- src/views/LibraryListView.ts | 2 +- src/views/ProfilesView.ts | 2 +- src/views/Terminal.ts | 2 +- src/views/actions.ts | 2 +- src/views/diagnostics.ts | 2 +- src/views/ifsBrowser.ts | 2 +- src/views/objectBrowser.ts | 2 +- src/views/searchView.ts | 2 +- src/webviews/actions/index.ts | 2 +- src/webviews/commandProfile/index.ts | 2 +- src/webviews/filters/index.ts | 2 +- src/webviews/login/index.ts | 2 +- src/webviews/settings/index.ts | 2 +- src/webviews/variables/index.ts | 2 +- 34 files changed, 35 insertions(+), 35 deletions(-) rename src/{api => }/Configuration.ts (98%) diff --git a/src/api/Configuration.ts b/src/Configuration.ts similarity index 98% rename from src/api/Configuration.ts rename to src/Configuration.ts index 55cb1b341..c0248aa99 100644 --- a/src/api/Configuration.ts +++ b/src/Configuration.ts @@ -1,7 +1,7 @@ import os from "os"; import * as vscode from 'vscode'; -import { ConnectionData, DeploymentMethod } from '../typings'; -import { FilterType } from './Filter'; +import { ConnectionData, DeploymentMethod } from './typings'; +import { FilterType } from './api/Filter'; export type SourceDateMode = "edit" | "diff"; export type DefaultOpenMode = "browse" | "edit"; diff --git a/src/Instance.ts b/src/Instance.ts index 94327239c..984f9f970 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode"; import { ConnectionData, IBMiEvent } from "./typings"; -import { ConnectionConfiguration } from "./api/Configuration"; +import { ConnectionConfiguration } from "./Configuration"; import IBMi, { ConnectionResult } from "./api/IBMi"; import { CodeForIStorage, ConnectionStorage } from "./api/Storage"; import { withContext } from "./views/tools"; diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index f15f7d35d..4498002a8 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -9,7 +9,7 @@ import { CustomQSh } from '../components/cqsh'; import { ComponentManager } from "./components/manager"; import { CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, WrapResult } from "../typings"; import { CompileTools } from "./CompileTools"; -import { ConnectionConfiguration } from "./Configuration"; +import { ConnectionConfiguration } from "../Configuration"; import IBMiContent from "./IBMiContent"; import { CachedServerSettings, CodeForIStorage } from './Storage'; import { Tools } from './Tools'; diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index ad70a4d33..1e8b11dc1 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -7,7 +7,7 @@ import * as node_ssh from "node-ssh"; import { GetMemberInfo } from './components/getMemberInfo'; import { ObjectTypes } from '../filesystems/qsys/Objects'; import { AttrOperands, CommandResult, IBMiError, IBMiMember, IBMiObject, IFSFile, QsysPath, SpecialAuthorities } from '../typings'; -import { ConnectionConfiguration } from './Configuration'; +import { ConnectionConfiguration } from '../Configuration'; import { FilterType, parseFilter, singleGenericName } from './Filter'; import { default as IBMi } from './IBMi'; import { Tools } from './Tools'; diff --git a/src/api/Search.ts b/src/api/Search.ts index 6cfcbfb39..13177a240 100644 --- a/src/api/Search.ts +++ b/src/api/Search.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import { GetMemberInfo } from './components/getMemberInfo'; import { IBMiMember, SearchHit, SearchResults } from '../typings'; -import { GlobalVSCodeConfiguration } from './Configuration'; +import { GlobalVSCodeConfiguration } from '../Configuration'; import { Tools } from './Tools'; import IBMi from './IBMi'; diff --git a/src/commands/actions.ts b/src/commands/actions.ts index ca2ed7cf7..d125beda6 100644 --- a/src/commands/actions.ts +++ b/src/commands/actions.ts @@ -1,6 +1,6 @@ import path from "path"; import { commands, TreeItem, Uri, WorkspaceFolder, window, Disposable } from "vscode"; -import { ConnectionConfiguration } from "../api/Configuration"; +import { ConnectionConfiguration } from "../Configuration"; import { refreshDiagnosticsFromServer } from "../views/diagnostics"; import Instance from "../Instance"; import { BrowserItem, Action, DeploymentMethod } from "../typings"; diff --git a/src/commands/connection.ts b/src/commands/connection.ts index cdc06f80f..dde1c73bd 100644 --- a/src/commands/connection.ts +++ b/src/commands/connection.ts @@ -1,5 +1,5 @@ import { commands, Disposable, ExtensionContext, window } from "vscode"; -import { ConnectionManager } from "../api/Configuration"; +import { ConnectionManager } from "../Configuration"; import Instance from "../Instance"; import { ConnectionData } from "../typings"; import { safeDisconnect } from "../instantiate"; diff --git a/src/commands/open.ts b/src/commands/open.ts index da7b436b3..245650ec9 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -3,7 +3,7 @@ import { MemberItem, OpenEditableOptions, WithPath } from "../typings"; import Instance from "../Instance"; import { Tools } from "../api/Tools"; import { getUriFromPath, parseFSOptions } from "../filesystems/qsys/QSysFs"; -import { DefaultOpenMode, GlobalVSCodeConfiguration } from "../api/Configuration"; +import { DefaultOpenMode, GlobalVSCodeConfiguration } from "../Configuration"; import path from "path"; import { findExistingDocument, findExistingDocumentUri } from "../views/tools"; diff --git a/src/commands/password.ts b/src/commands/password.ts index 86e45f9f2..97d897f79 100644 --- a/src/commands/password.ts +++ b/src/commands/password.ts @@ -1,5 +1,5 @@ import { commands, extensions, window, Disposable, ExtensionContext } from "vscode"; -import { ConnectionManager } from "../api/Configuration"; +import { ConnectionManager } from "../Configuration"; import Instance from "../Instance"; diff --git a/src/debug/index.ts b/src/debug/index.ts index 4c4323059..6f8167749 100644 --- a/src/debug/index.ts +++ b/src/debug/index.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import { instance } from "../instantiate"; import { ObjectItem } from "../typings"; import { ILELibrarySettings } from "../api/CompileTools"; -import { ConnectionManager } from "../api/Configuration"; +import { ConnectionManager } from "../Configuration"; import { Env, getEnvConfig } from "../filesystems/local/env"; import * as certificates from "./certificates"; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, resetDebugServiceDetails } from "./config"; diff --git a/src/extension.ts b/src/extension.ts index 80803d7f2..65beceb10 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,7 +6,7 @@ import { ExtensionContext, commands, languages, window, workspace } from "vscode import { CustomUI } from "./webviews/CustomUI"; import { instance, loadAllofExtension } from './instantiate'; -import { ConnectionConfiguration, ConnectionManager, onCodeForIBMiConfigurationChange } from "./api/Configuration"; +import { ConnectionConfiguration, ConnectionManager, onCodeForIBMiConfigurationChange } from "./Configuration"; import { Tools } from "./api/Tools"; import * as Debug from './debug'; import { parseErrors } from "./api/errors/parser"; diff --git a/src/filesystems/local/git.ts b/src/filesystems/local/git.ts index 33ea192a6..9320c5782 100644 --- a/src/filesystems/local/git.ts +++ b/src/filesystems/local/git.ts @@ -1,7 +1,7 @@ import { ExtensionContext, WorkspaceFolder, commands, window } from "vscode"; import { getBranchLibraryName } from "./env"; import { instance } from "../../instantiate"; -import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../../api/Configuration"; +import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../../Configuration"; import IBMi from "../../api/IBMi"; import IBMiContent from "../../api/IBMiContent"; import { getGitAPI } from "../../views/tools"; diff --git a/src/filesystems/qsys/FSUtils.ts b/src/filesystems/qsys/FSUtils.ts index 67a23be8f..3b5268b97 100644 --- a/src/filesystems/qsys/FSUtils.ts +++ b/src/filesystems/qsys/FSUtils.ts @@ -1,6 +1,6 @@ import path from "path"; import vscode, { l10n } from "vscode"; -import { GlobalVSCodeConfiguration, ReconnectMode } from "../../api/Configuration"; +import { GlobalVSCodeConfiguration, ReconnectMode } from "../../Configuration"; import { findUriTabs } from "../../views/tools"; import IBMi from "../../api/IBMi"; diff --git a/src/filesystems/qsys/QSysFs.ts b/src/filesystems/qsys/QSysFs.ts index 39d649f97..bee5826b9 100644 --- a/src/filesystems/qsys/QSysFs.ts +++ b/src/filesystems/qsys/QSysFs.ts @@ -1,7 +1,7 @@ import { parse as parsePath } from "path"; import { parse, ParsedUrlQueryInput, stringify } from "querystring"; import vscode, { FilePermission, FileSystemError } from "vscode"; -import { onCodeForIBMiConfigurationChange } from "../../api/Configuration"; +import { onCodeForIBMiConfigurationChange } from "../../Configuration"; import IBMi from "../../api/IBMi"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; diff --git a/src/filesystems/qsys/extendedContent.ts b/src/filesystems/qsys/extendedContent.ts index a803faa63..605aeef14 100644 --- a/src/filesystems/qsys/extendedContent.ts +++ b/src/filesystems/qsys/extendedContent.ts @@ -2,7 +2,7 @@ import fs from "fs"; import tmp from "tmp"; import util from "util"; import vscode from "vscode"; -import { GlobalVSCodeConfiguration } from "../../api/Configuration"; +import { GlobalVSCodeConfiguration } from "../../Configuration"; import { instance } from "../../instantiate"; import { getAliasName, SourceDateHandler } from "./sourceDateHandler"; diff --git a/src/filesystems/qsys/sourceDateHandler.ts b/src/filesystems/qsys/sourceDateHandler.ts index 0e1730554..e29c6d216 100644 --- a/src/filesystems/qsys/sourceDateHandler.ts +++ b/src/filesystems/qsys/sourceDateHandler.ts @@ -2,7 +2,7 @@ import Crypto from "crypto"; import vscode from "vscode"; import { DiffComputer } from "vscode-diff"; -import { GlobalVSCodeConfiguration, SourceDateMode } from "../../api/Configuration"; +import { GlobalVSCodeConfiguration, SourceDateMode } from "../../Configuration"; import { instance } from "../../instantiate"; const editedTodayColor = new vscode.ThemeColor(`gitDecoration.modifiedResourceForeground`); diff --git a/src/instantiate.ts b/src/instantiate.ts index 788219b4e..80da32543 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode"; -import { GlobalVSCodeConfiguration, onCodeForIBMiConfigurationChange } from "./api/Configuration"; +import { GlobalVSCodeConfiguration, onCodeForIBMiConfigurationChange } from "./Configuration"; import Instance from "./Instance"; import { Terminal } from './views/Terminal'; import { getDebugServiceDetails } from './debug/config'; diff --git a/src/sandbox.ts b/src/sandbox.ts index f0cf54e5d..997a4f5e7 100644 --- a/src/sandbox.ts +++ b/src/sandbox.ts @@ -1,7 +1,7 @@ import { env } from "process"; import querystring from "querystring"; import { commands, ExtensionContext, l10n, Uri, window } from "vscode"; -import { ConnectionConfiguration, ConnectionManager } from "./api/Configuration"; +import { ConnectionConfiguration, ConnectionManager } from "./Configuration"; import { instance } from "./instantiate"; import { ConnectionData } from "./typings"; import { getGitAPI } from "./views/tools"; diff --git a/src/typings.ts b/src/typings.ts index 3abe4c410..2bf2b2f40 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -1,6 +1,6 @@ import { Ignore } from 'ignore'; import { MarkdownString, ProviderResult, Range, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode"; -import { ConnectionConfiguration } from './api/Configuration'; +import { ConnectionConfiguration } from './Configuration'; import { CustomUI } from "./webviews/CustomUI"; import Instance from "./Instance"; import { Tools } from "./api/Tools"; diff --git a/src/views/ConnectionBrowser.ts b/src/views/ConnectionBrowser.ts index 6ede3245f..a4d6f9be6 100644 --- a/src/views/ConnectionBrowser.ts +++ b/src/views/ConnectionBrowser.ts @@ -1,7 +1,7 @@ import vscode from 'vscode'; import { ConnectionData, Server } from '../typings'; -import { ConnectionConfiguration, ConnectionManager, GlobalVSCodeConfiguration } from '../api/Configuration'; +import { ConnectionConfiguration, ConnectionManager, GlobalVSCodeConfiguration } from '../Configuration'; import { instance } from '../instantiate'; import { Login } from '../webviews/login'; import IBMi from '../api/IBMi'; diff --git a/src/views/LibraryListView.ts b/src/views/LibraryListView.ts index 560b04d50..83e1ac12e 100644 --- a/src/views/LibraryListView.ts +++ b/src/views/LibraryListView.ts @@ -1,5 +1,5 @@ import vscode, { commands, l10n } from "vscode"; -import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../api/Configuration"; +import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../Configuration"; import { instance } from "../instantiate"; import { IBMiObject, WithLibrary } from "../typings"; import { objectToToolTip } from "./tools"; diff --git a/src/views/ProfilesView.ts b/src/views/ProfilesView.ts index d74ed91e1..6ca711a1c 100644 --- a/src/views/ProfilesView.ts +++ b/src/views/ProfilesView.ts @@ -1,6 +1,6 @@ import vscode, { l10n, window } from 'vscode'; -import { ConnectionConfiguration } from '../api/Configuration'; +import { ConnectionConfiguration } from '../Configuration'; import { GetNewLibl } from '../api/components/getNewLibl'; import { instance } from '../instantiate'; import { Profile } from '../typings'; diff --git a/src/views/Terminal.ts b/src/views/Terminal.ts index 2e5367857..9c891fd72 100644 --- a/src/views/Terminal.ts +++ b/src/views/Terminal.ts @@ -2,7 +2,7 @@ import path from 'path'; import vscode, { commands } from 'vscode'; import { instance } from '../instantiate'; -import { GlobalVSCodeConfiguration } from '../api/Configuration'; +import { GlobalVSCodeConfiguration } from '../Configuration'; import IBMi from '../api/IBMi'; import { Tools } from '../api/Tools'; diff --git a/src/views/actions.ts b/src/views/actions.ts index 0f54c505a..e409b9404 100644 --- a/src/views/actions.ts +++ b/src/views/actions.ts @@ -8,7 +8,7 @@ import { getGitBranch } from '../filesystems/local/git'; import Instance from '../Instance'; import { parseFSOptions } from '../filesystems/qsys/QSysFs'; import { Action, BrowserItem, DeploymentMethod, Variable } from '../typings'; -import { GlobalVSCodeConfiguration } from '../api/Configuration'; +import { GlobalVSCodeConfiguration } from '../Configuration'; import vscode, { CustomExecution, Pseudoterminal, TaskGroup, TaskRevealKind, WorkspaceFolder, commands, tasks } from 'vscode'; import { CustomUI } from '../webviews/CustomUI'; diff --git a/src/views/diagnostics.ts b/src/views/diagnostics.ts index 25c120b10..66dd2cd00 100644 --- a/src/views/diagnostics.ts +++ b/src/views/diagnostics.ts @@ -1,7 +1,7 @@ import * as vscode from "vscode"; import { FileError } from "../typings"; -import { GlobalVSCodeConfiguration } from "../api/Configuration"; +import { GlobalVSCodeConfiguration } from "../Configuration"; import Instance from "../Instance"; import { getEvfeventFiles } from "../filesystems/local/actions"; import { parseErrors } from "../api/errors/parser"; diff --git a/src/views/ifsBrowser.ts b/src/views/ifsBrowser.ts index db2eeea49..eb436bd48 100644 --- a/src/views/ifsBrowser.ts +++ b/src/views/ifsBrowser.ts @@ -3,7 +3,7 @@ import path, { dirname, extname } from "path"; import vscode, { FileType, l10n, window } from "vscode"; import { existsSync, mkdirSync, rmdirSync } from "fs"; -import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../api/Configuration"; +import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../Configuration"; import { SortOptions } from "../api/IBMiContent"; import { Search } from "../api/Search"; import { Tools } from "../api/Tools"; diff --git a/src/views/objectBrowser.ts b/src/views/objectBrowser.ts index b83f88a2a..b5fc0186a 100644 --- a/src/views/objectBrowser.ts +++ b/src/views/objectBrowser.ts @@ -2,7 +2,7 @@ import fs, { existsSync } from "fs"; import os from "os"; import path, { basename, dirname } from "path"; import vscode from "vscode"; -import { ConnectionConfiguration, DefaultOpenMode, GlobalVSCodeConfiguration } from "../api/Configuration"; +import { ConnectionConfiguration, DefaultOpenMode, GlobalVSCodeConfiguration } from "../Configuration"; import { parseFilter, singleGenericName } from "../api/Filter"; import IBMi, { MemberParts } from "../api/IBMi"; import { SortOptions, SortOrder } from "../api/IBMiContent"; diff --git a/src/views/searchView.ts b/src/views/searchView.ts index 420c257f9..4aa6be70d 100644 --- a/src/views/searchView.ts +++ b/src/views/searchView.ts @@ -1,6 +1,6 @@ import path from 'path'; import vscode from "vscode"; -import { DefaultOpenMode } from "../api/Configuration"; +import { DefaultOpenMode } from "../Configuration"; import { SearchHit, SearchHitLine, SearchResults, WithPath } from "../typings"; export function initializeSearchView(context: vscode.ExtensionContext) { diff --git a/src/webviews/actions/index.ts b/src/webviews/actions/index.ts index 19348cf80..b04b0073b 100644 --- a/src/webviews/actions/index.ts +++ b/src/webviews/actions/index.ts @@ -2,7 +2,7 @@ import vscode from "vscode"; import { CustomUI, Tab } from "../CustomUI"; -import { GlobalVSCodeConfiguration } from "../../api/Configuration"; +import { GlobalVSCodeConfiguration } from "../../Configuration"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; import { Action, ActionEnvironment, ActionRefresh, ActionType } from "../../typings"; diff --git a/src/webviews/commandProfile/index.ts b/src/webviews/commandProfile/index.ts index 0feb41d72..0cbb51615 100644 --- a/src/webviews/commandProfile/index.ts +++ b/src/webviews/commandProfile/index.ts @@ -1,5 +1,5 @@ import { commands, window } from "vscode"; -import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../../api/Configuration"; +import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../../Configuration"; import { CustomUI } from "../CustomUI"; import { instance } from "../../instantiate"; diff --git a/src/webviews/filters/index.ts b/src/webviews/filters/index.ts index 54492a715..2f501f16b 100644 --- a/src/webviews/filters/index.ts +++ b/src/webviews/filters/index.ts @@ -1,4 +1,4 @@ -import { ConnectionConfiguration } from "../../api/Configuration"; +import { ConnectionConfiguration } from "../../Configuration"; import { CustomUI } from "../CustomUI"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; diff --git a/src/webviews/login/index.ts b/src/webviews/login/index.ts index b91a479c0..33f3b3092 100644 --- a/src/webviews/login/index.ts +++ b/src/webviews/login/index.ts @@ -1,5 +1,5 @@ import vscode, { l10n, ThemeIcon } from "vscode"; -import { ConnectionConfiguration, ConnectionManager } from "../../api/Configuration"; +import { ConnectionConfiguration, ConnectionManager } from "../../Configuration"; import { CustomUI, Section } from "../CustomUI"; import { Tools } from "../../api/Tools"; import { instance, safeDisconnect } from "../../instantiate"; diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 2b11d9e6a..7ff9567e5 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -1,6 +1,6 @@ import { existsSync } from "fs"; import vscode from "vscode"; -import { ConnectionConfiguration, ConnectionManager, GlobalVSCodeConfiguration } from "../../api/Configuration"; +import { ConnectionConfiguration, ConnectionManager, GlobalVSCodeConfiguration } from "../../Configuration"; import { ComplexTab, CustomUI, Section } from "../CustomUI"; import { Tools } from "../../api/Tools"; import { isManaged } from "../../debug"; diff --git a/src/webviews/variables/index.ts b/src/webviews/variables/index.ts index bbbf0d015..d5fc8feda 100644 --- a/src/webviews/variables/index.ts +++ b/src/webviews/variables/index.ts @@ -1,5 +1,5 @@ import vscode from "vscode"; -import { ConnectionConfiguration } from "../../api/Configuration"; +import { ConnectionConfiguration } from "../../Configuration"; import { CustomUI } from "../CustomUI"; import { instance } from "../../instantiate"; From c8a568ec699d37db0c1523b405e1273217fd164e Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 15:54:44 -0500 Subject: [PATCH 16/46] create config directory Signed-off-by: worksofliam --- src/Instance.ts | 4 ++-- src/api/IBMi.ts | 2 +- src/api/IBMiContent.ts | 2 +- src/api/Search.ts | 2 +- src/commands/actions.ts | 2 +- src/commands/connection.ts | 2 +- src/commands/open.ts | 2 +- src/commands/password.ts | 2 +- src/{ => config}/Configuration.ts | 4 ++-- src/{ => config}/Storage.ts | 2 +- src/debug/index.ts | 2 +- src/extension.ts | 2 +- src/filesystems/local/git.ts | 2 +- src/filesystems/qsys/FSUtils.ts | 2 +- src/filesystems/qsys/QSysFs.ts | 2 +- src/filesystems/qsys/extendedContent.ts | 2 +- src/filesystems/qsys/sourceDateHandler.ts | 2 +- src/instantiate.ts | 2 +- src/sandbox.ts | 2 +- src/typings.ts | 2 +- src/views/ConnectionBrowser.ts | 2 +- src/views/LibraryListView.ts | 2 +- src/views/ProfilesView.ts | 2 +- src/views/Terminal.ts | 2 +- src/views/actions.ts | 2 +- src/views/diagnostics.ts | 2 +- src/views/ifsBrowser.ts | 2 +- src/views/objectBrowser.ts | 2 +- src/views/searchView.ts | 2 +- src/webviews/actions/index.ts | 2 +- src/webviews/commandProfile/index.ts | 2 +- src/webviews/filters/index.ts | 2 +- src/webviews/login/index.ts | 2 +- src/webviews/settings/index.ts | 2 +- src/webviews/variables/index.ts | 2 +- 35 files changed, 37 insertions(+), 37 deletions(-) rename src/{ => config}/Configuration.ts (98%) rename src/{ => config}/Storage.ts (94%) diff --git a/src/Instance.ts b/src/Instance.ts index 984f9f970..ddfba4dec 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -1,11 +1,11 @@ import * as vscode from "vscode"; import { ConnectionData, IBMiEvent } from "./typings"; -import { ConnectionConfiguration } from "./Configuration"; +import { ConnectionConfiguration } from "./config/Configuration"; import IBMi, { ConnectionResult } from "./api/IBMi"; import { CodeForIStorage, ConnectionStorage } from "./api/Storage"; import { withContext } from "./views/tools"; import { handleConnectionResults, messageCallback } from "./views/connection"; -import { VsStorage } from "./Storage"; +import { VsStorage } from "./config/Storage"; type IBMiEventSubscription = { func: Function, diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 4498002a8..b48b06ea1 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -9,7 +9,7 @@ import { CustomQSh } from '../components/cqsh'; import { ComponentManager } from "./components/manager"; import { CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, WrapResult } from "../typings"; import { CompileTools } from "./CompileTools"; -import { ConnectionConfiguration } from "../Configuration"; +import { ConnectionConfiguration } from "../config/Configuration"; import IBMiContent from "./IBMiContent"; import { CachedServerSettings, CodeForIStorage } from './Storage'; import { Tools } from './Tools'; diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index 1e8b11dc1..5d3b2763f 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -7,7 +7,7 @@ import * as node_ssh from "node-ssh"; import { GetMemberInfo } from './components/getMemberInfo'; import { ObjectTypes } from '../filesystems/qsys/Objects'; import { AttrOperands, CommandResult, IBMiError, IBMiMember, IBMiObject, IFSFile, QsysPath, SpecialAuthorities } from '../typings'; -import { ConnectionConfiguration } from '../Configuration'; +import { ConnectionConfiguration } from '../config/Configuration'; import { FilterType, parseFilter, singleGenericName } from './Filter'; import { default as IBMi } from './IBMi'; import { Tools } from './Tools'; diff --git a/src/api/Search.ts b/src/api/Search.ts index 13177a240..6dc7fe82b 100644 --- a/src/api/Search.ts +++ b/src/api/Search.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import { GetMemberInfo } from './components/getMemberInfo'; import { IBMiMember, SearchHit, SearchResults } from '../typings'; -import { GlobalVSCodeConfiguration } from '../Configuration'; +import { GlobalVSCodeConfiguration } from '../config/Configuration'; import { Tools } from './Tools'; import IBMi from './IBMi'; diff --git a/src/commands/actions.ts b/src/commands/actions.ts index d125beda6..a1d8b79ce 100644 --- a/src/commands/actions.ts +++ b/src/commands/actions.ts @@ -1,6 +1,6 @@ import path from "path"; import { commands, TreeItem, Uri, WorkspaceFolder, window, Disposable } from "vscode"; -import { ConnectionConfiguration } from "../Configuration"; +import { ConnectionConfiguration } from "../config/Configuration"; import { refreshDiagnosticsFromServer } from "../views/diagnostics"; import Instance from "../Instance"; import { BrowserItem, Action, DeploymentMethod } from "../typings"; diff --git a/src/commands/connection.ts b/src/commands/connection.ts index dde1c73bd..7e7be6b70 100644 --- a/src/commands/connection.ts +++ b/src/commands/connection.ts @@ -1,5 +1,5 @@ import { commands, Disposable, ExtensionContext, window } from "vscode"; -import { ConnectionManager } from "../Configuration"; +import { ConnectionManager } from "../config/Configuration"; import Instance from "../Instance"; import { ConnectionData } from "../typings"; import { safeDisconnect } from "../instantiate"; diff --git a/src/commands/open.ts b/src/commands/open.ts index 245650ec9..08193114b 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -3,7 +3,7 @@ import { MemberItem, OpenEditableOptions, WithPath } from "../typings"; import Instance from "../Instance"; import { Tools } from "../api/Tools"; import { getUriFromPath, parseFSOptions } from "../filesystems/qsys/QSysFs"; -import { DefaultOpenMode, GlobalVSCodeConfiguration } from "../Configuration"; +import { DefaultOpenMode, GlobalVSCodeConfiguration } from "../config/Configuration"; import path from "path"; import { findExistingDocument, findExistingDocumentUri } from "../views/tools"; diff --git a/src/commands/password.ts b/src/commands/password.ts index 97d897f79..5c081a511 100644 --- a/src/commands/password.ts +++ b/src/commands/password.ts @@ -1,5 +1,5 @@ import { commands, extensions, window, Disposable, ExtensionContext } from "vscode"; -import { ConnectionManager } from "../Configuration"; +import { ConnectionManager } from "../config/Configuration"; import Instance from "../Instance"; diff --git a/src/Configuration.ts b/src/config/Configuration.ts similarity index 98% rename from src/Configuration.ts rename to src/config/Configuration.ts index c0248aa99..2e4f39f17 100644 --- a/src/Configuration.ts +++ b/src/config/Configuration.ts @@ -1,7 +1,7 @@ import os from "os"; import * as vscode from 'vscode'; -import { ConnectionData, DeploymentMethod } from './typings'; -import { FilterType } from './api/Filter'; +import { ConnectionData, DeploymentMethod } from '../typings'; +import { FilterType } from '../api/Filter'; export type SourceDateMode = "edit" | "diff"; export type DefaultOpenMode = "browse" | "edit"; diff --git a/src/Storage.ts b/src/config/Storage.ts similarity index 94% rename from src/Storage.ts rename to src/config/Storage.ts index d8a788372..1e99ac191 100644 --- a/src/Storage.ts +++ b/src/config/Storage.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import { Storage } from './api/Storage'; +import { Storage } from '../api/Storage'; export class VsStorage extends Storage { declare protected readonly globalState; diff --git a/src/debug/index.ts b/src/debug/index.ts index 6f8167749..5cc96b5e5 100644 --- a/src/debug/index.ts +++ b/src/debug/index.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import { instance } from "../instantiate"; import { ObjectItem } from "../typings"; import { ILELibrarySettings } from "../api/CompileTools"; -import { ConnectionManager } from "../Configuration"; +import { ConnectionManager } from "../config/Configuration"; import { Env, getEnvConfig } from "../filesystems/local/env"; import * as certificates from "./certificates"; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, resetDebugServiceDetails } from "./config"; diff --git a/src/extension.ts b/src/extension.ts index 65beceb10..a41580a77 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,7 +6,7 @@ import { ExtensionContext, commands, languages, window, workspace } from "vscode import { CustomUI } from "./webviews/CustomUI"; import { instance, loadAllofExtension } from './instantiate'; -import { ConnectionConfiguration, ConnectionManager, onCodeForIBMiConfigurationChange } from "./Configuration"; +import { ConnectionConfiguration, ConnectionManager, onCodeForIBMiConfigurationChange } from "./config/Configuration"; import { Tools } from "./api/Tools"; import * as Debug from './debug'; import { parseErrors } from "./api/errors/parser"; diff --git a/src/filesystems/local/git.ts b/src/filesystems/local/git.ts index 9320c5782..acfb3b93f 100644 --- a/src/filesystems/local/git.ts +++ b/src/filesystems/local/git.ts @@ -1,7 +1,7 @@ import { ExtensionContext, WorkspaceFolder, commands, window } from "vscode"; import { getBranchLibraryName } from "./env"; import { instance } from "../../instantiate"; -import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../../Configuration"; +import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../../config/Configuration"; import IBMi from "../../api/IBMi"; import IBMiContent from "../../api/IBMiContent"; import { getGitAPI } from "../../views/tools"; diff --git a/src/filesystems/qsys/FSUtils.ts b/src/filesystems/qsys/FSUtils.ts index 3b5268b97..1ed3fc429 100644 --- a/src/filesystems/qsys/FSUtils.ts +++ b/src/filesystems/qsys/FSUtils.ts @@ -1,6 +1,6 @@ import path from "path"; import vscode, { l10n } from "vscode"; -import { GlobalVSCodeConfiguration, ReconnectMode } from "../../Configuration"; +import { GlobalVSCodeConfiguration, ReconnectMode } from "../../config/Configuration"; import { findUriTabs } from "../../views/tools"; import IBMi from "../../api/IBMi"; diff --git a/src/filesystems/qsys/QSysFs.ts b/src/filesystems/qsys/QSysFs.ts index bee5826b9..0fe78913f 100644 --- a/src/filesystems/qsys/QSysFs.ts +++ b/src/filesystems/qsys/QSysFs.ts @@ -1,7 +1,7 @@ import { parse as parsePath } from "path"; import { parse, ParsedUrlQueryInput, stringify } from "querystring"; import vscode, { FilePermission, FileSystemError } from "vscode"; -import { onCodeForIBMiConfigurationChange } from "../../Configuration"; +import { onCodeForIBMiConfigurationChange } from "../../config/Configuration"; import IBMi from "../../api/IBMi"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; diff --git a/src/filesystems/qsys/extendedContent.ts b/src/filesystems/qsys/extendedContent.ts index 605aeef14..fbc3661d1 100644 --- a/src/filesystems/qsys/extendedContent.ts +++ b/src/filesystems/qsys/extendedContent.ts @@ -2,7 +2,7 @@ import fs from "fs"; import tmp from "tmp"; import util from "util"; import vscode from "vscode"; -import { GlobalVSCodeConfiguration } from "../../Configuration"; +import { GlobalVSCodeConfiguration } from "../../config/Configuration"; import { instance } from "../../instantiate"; import { getAliasName, SourceDateHandler } from "./sourceDateHandler"; diff --git a/src/filesystems/qsys/sourceDateHandler.ts b/src/filesystems/qsys/sourceDateHandler.ts index e29c6d216..11fd3968e 100644 --- a/src/filesystems/qsys/sourceDateHandler.ts +++ b/src/filesystems/qsys/sourceDateHandler.ts @@ -2,7 +2,7 @@ import Crypto from "crypto"; import vscode from "vscode"; import { DiffComputer } from "vscode-diff"; -import { GlobalVSCodeConfiguration, SourceDateMode } from "../../Configuration"; +import { GlobalVSCodeConfiguration, SourceDateMode } from "../../config/Configuration"; import { instance } from "../../instantiate"; const editedTodayColor = new vscode.ThemeColor(`gitDecoration.modifiedResourceForeground`); diff --git a/src/instantiate.ts b/src/instantiate.ts index 80da32543..cfd04f139 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode"; -import { GlobalVSCodeConfiguration, onCodeForIBMiConfigurationChange } from "./Configuration"; +import { GlobalVSCodeConfiguration, onCodeForIBMiConfigurationChange } from "./config/Configuration"; import Instance from "./Instance"; import { Terminal } from './views/Terminal'; import { getDebugServiceDetails } from './debug/config'; diff --git a/src/sandbox.ts b/src/sandbox.ts index 997a4f5e7..e8da3cd0c 100644 --- a/src/sandbox.ts +++ b/src/sandbox.ts @@ -1,7 +1,7 @@ import { env } from "process"; import querystring from "querystring"; import { commands, ExtensionContext, l10n, Uri, window } from "vscode"; -import { ConnectionConfiguration, ConnectionManager } from "./Configuration"; +import { ConnectionConfiguration, ConnectionManager } from "./config/Configuration"; import { instance } from "./instantiate"; import { ConnectionData } from "./typings"; import { getGitAPI } from "./views/tools"; diff --git a/src/typings.ts b/src/typings.ts index 2bf2b2f40..79f1c9218 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -1,6 +1,6 @@ import { Ignore } from 'ignore'; import { MarkdownString, ProviderResult, Range, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode"; -import { ConnectionConfiguration } from './Configuration'; +import { ConnectionConfiguration } from './config/Configuration'; import { CustomUI } from "./webviews/CustomUI"; import Instance from "./Instance"; import { Tools } from "./api/Tools"; diff --git a/src/views/ConnectionBrowser.ts b/src/views/ConnectionBrowser.ts index a4d6f9be6..deda8abfc 100644 --- a/src/views/ConnectionBrowser.ts +++ b/src/views/ConnectionBrowser.ts @@ -1,7 +1,7 @@ import vscode from 'vscode'; import { ConnectionData, Server } from '../typings'; -import { ConnectionConfiguration, ConnectionManager, GlobalVSCodeConfiguration } from '../Configuration'; +import { ConnectionConfiguration, ConnectionManager, GlobalVSCodeConfiguration } from '../config/Configuration'; import { instance } from '../instantiate'; import { Login } from '../webviews/login'; import IBMi from '../api/IBMi'; diff --git a/src/views/LibraryListView.ts b/src/views/LibraryListView.ts index 83e1ac12e..0367fd4bd 100644 --- a/src/views/LibraryListView.ts +++ b/src/views/LibraryListView.ts @@ -1,5 +1,5 @@ import vscode, { commands, l10n } from "vscode"; -import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../Configuration"; +import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../config/Configuration"; import { instance } from "../instantiate"; import { IBMiObject, WithLibrary } from "../typings"; import { objectToToolTip } from "./tools"; diff --git a/src/views/ProfilesView.ts b/src/views/ProfilesView.ts index 6ca711a1c..68c8e8173 100644 --- a/src/views/ProfilesView.ts +++ b/src/views/ProfilesView.ts @@ -1,6 +1,6 @@ import vscode, { l10n, window } from 'vscode'; -import { ConnectionConfiguration } from '../Configuration'; +import { ConnectionConfiguration } from '../config/Configuration'; import { GetNewLibl } from '../api/components/getNewLibl'; import { instance } from '../instantiate'; import { Profile } from '../typings'; diff --git a/src/views/Terminal.ts b/src/views/Terminal.ts index 9c891fd72..60f52feee 100644 --- a/src/views/Terminal.ts +++ b/src/views/Terminal.ts @@ -2,7 +2,7 @@ import path from 'path'; import vscode, { commands } from 'vscode'; import { instance } from '../instantiate'; -import { GlobalVSCodeConfiguration } from '../Configuration'; +import { GlobalVSCodeConfiguration } from '../config/Configuration'; import IBMi from '../api/IBMi'; import { Tools } from '../api/Tools'; diff --git a/src/views/actions.ts b/src/views/actions.ts index e409b9404..7cec34076 100644 --- a/src/views/actions.ts +++ b/src/views/actions.ts @@ -8,7 +8,7 @@ import { getGitBranch } from '../filesystems/local/git'; import Instance from '../Instance'; import { parseFSOptions } from '../filesystems/qsys/QSysFs'; import { Action, BrowserItem, DeploymentMethod, Variable } from '../typings'; -import { GlobalVSCodeConfiguration } from '../Configuration'; +import { GlobalVSCodeConfiguration } from '../config/Configuration'; import vscode, { CustomExecution, Pseudoterminal, TaskGroup, TaskRevealKind, WorkspaceFolder, commands, tasks } from 'vscode'; import { CustomUI } from '../webviews/CustomUI'; diff --git a/src/views/diagnostics.ts b/src/views/diagnostics.ts index 66dd2cd00..20b734e74 100644 --- a/src/views/diagnostics.ts +++ b/src/views/diagnostics.ts @@ -1,7 +1,7 @@ import * as vscode from "vscode"; import { FileError } from "../typings"; -import { GlobalVSCodeConfiguration } from "../Configuration"; +import { GlobalVSCodeConfiguration } from "../config/Configuration"; import Instance from "../Instance"; import { getEvfeventFiles } from "../filesystems/local/actions"; import { parseErrors } from "../api/errors/parser"; diff --git a/src/views/ifsBrowser.ts b/src/views/ifsBrowser.ts index eb436bd48..1ef3d2f44 100644 --- a/src/views/ifsBrowser.ts +++ b/src/views/ifsBrowser.ts @@ -3,7 +3,7 @@ import path, { dirname, extname } from "path"; import vscode, { FileType, l10n, window } from "vscode"; import { existsSync, mkdirSync, rmdirSync } from "fs"; -import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../Configuration"; +import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../config/Configuration"; import { SortOptions } from "../api/IBMiContent"; import { Search } from "../api/Search"; import { Tools } from "../api/Tools"; diff --git a/src/views/objectBrowser.ts b/src/views/objectBrowser.ts index b5fc0186a..583536cd6 100644 --- a/src/views/objectBrowser.ts +++ b/src/views/objectBrowser.ts @@ -2,7 +2,7 @@ import fs, { existsSync } from "fs"; import os from "os"; import path, { basename, dirname } from "path"; import vscode from "vscode"; -import { ConnectionConfiguration, DefaultOpenMode, GlobalVSCodeConfiguration } from "../Configuration"; +import { ConnectionConfiguration, DefaultOpenMode, GlobalVSCodeConfiguration } from "../config/Configuration"; import { parseFilter, singleGenericName } from "../api/Filter"; import IBMi, { MemberParts } from "../api/IBMi"; import { SortOptions, SortOrder } from "../api/IBMiContent"; diff --git a/src/views/searchView.ts b/src/views/searchView.ts index 4aa6be70d..57d5fd5e2 100644 --- a/src/views/searchView.ts +++ b/src/views/searchView.ts @@ -1,6 +1,6 @@ import path from 'path'; import vscode from "vscode"; -import { DefaultOpenMode } from "../Configuration"; +import { DefaultOpenMode } from "../config/Configuration"; import { SearchHit, SearchHitLine, SearchResults, WithPath } from "../typings"; export function initializeSearchView(context: vscode.ExtensionContext) { diff --git a/src/webviews/actions/index.ts b/src/webviews/actions/index.ts index b04b0073b..dcddf6988 100644 --- a/src/webviews/actions/index.ts +++ b/src/webviews/actions/index.ts @@ -2,7 +2,7 @@ import vscode from "vscode"; import { CustomUI, Tab } from "../CustomUI"; -import { GlobalVSCodeConfiguration } from "../../Configuration"; +import { GlobalVSCodeConfiguration } from "../../config/Configuration"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; import { Action, ActionEnvironment, ActionRefresh, ActionType } from "../../typings"; diff --git a/src/webviews/commandProfile/index.ts b/src/webviews/commandProfile/index.ts index 0cbb51615..c1b873203 100644 --- a/src/webviews/commandProfile/index.ts +++ b/src/webviews/commandProfile/index.ts @@ -1,5 +1,5 @@ import { commands, window } from "vscode"; -import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../../Configuration"; +import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../../config/Configuration"; import { CustomUI } from "../CustomUI"; import { instance } from "../../instantiate"; diff --git a/src/webviews/filters/index.ts b/src/webviews/filters/index.ts index 2f501f16b..2e79dea7e 100644 --- a/src/webviews/filters/index.ts +++ b/src/webviews/filters/index.ts @@ -1,4 +1,4 @@ -import { ConnectionConfiguration } from "../../Configuration"; +import { ConnectionConfiguration } from "../../config/Configuration"; import { CustomUI } from "../CustomUI"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; diff --git a/src/webviews/login/index.ts b/src/webviews/login/index.ts index 33f3b3092..90073447f 100644 --- a/src/webviews/login/index.ts +++ b/src/webviews/login/index.ts @@ -1,5 +1,5 @@ import vscode, { l10n, ThemeIcon } from "vscode"; -import { ConnectionConfiguration, ConnectionManager } from "../../Configuration"; +import { ConnectionConfiguration, ConnectionManager } from "../../config/Configuration"; import { CustomUI, Section } from "../CustomUI"; import { Tools } from "../../api/Tools"; import { instance, safeDisconnect } from "../../instantiate"; diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 7ff9567e5..fe383142a 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -1,6 +1,6 @@ import { existsSync } from "fs"; import vscode from "vscode"; -import { ConnectionConfiguration, ConnectionManager, GlobalVSCodeConfiguration } from "../../Configuration"; +import { ConnectionConfiguration, ConnectionManager, GlobalVSCodeConfiguration } from "../../config/Configuration"; import { ComplexTab, CustomUI, Section } from "../CustomUI"; import { Tools } from "../../api/Tools"; import { isManaged } from "../../debug"; diff --git a/src/webviews/variables/index.ts b/src/webviews/variables/index.ts index d5fc8feda..7f5db47a5 100644 --- a/src/webviews/variables/index.ts +++ b/src/webviews/variables/index.ts @@ -1,5 +1,5 @@ import vscode from "vscode"; -import { ConnectionConfiguration } from "../../Configuration"; +import { ConnectionConfiguration } from "../../config/Configuration"; import { CustomUI } from "../CustomUI"; import { instance } from "../../instantiate"; From c688135daf188ef3dbcea557e51b48a35ee1a137 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 16:01:19 -0500 Subject: [PATCH 17/46] Remove vscode from Storage API Signed-off-by: worksofliam --- src/api/Storage.ts | 18 +++++++++--------- src/commands/password.ts | 4 ++-- src/testing/storage.ts | 10 +++++----- src/views/diagnostics.ts | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/api/Storage.ts b/src/api/Storage.ts index f23d8ca70..dd1d04b99 100644 --- a/src/api/Storage.ts +++ b/src/api/Storage.ts @@ -1,4 +1,4 @@ -import vscode from 'vscode'; + import { ConnectionData } from '../typings'; const PREVIOUS_CUR_LIBS_KEY = `prevCurLibs`; @@ -221,9 +221,9 @@ export class ConnectionStorage { return this.internalStorage.set(DEBUG_KEY, existingCommands); } - getWorkspaceDeployPath(workspaceFolder: vscode.WorkspaceFolder) { + getWorkspaceDeployPath(workspaceFolderFsPath: string) { const deployDirs = this.internalStorage.get(DEPLOYMENT_KEY) || {}; - return deployDirs[workspaceFolder.uri.fsPath].toLowerCase(); + return deployDirs[workspaceFolderFsPath].toLowerCase(); } getRecentlyOpenedFiles() { @@ -238,12 +238,12 @@ export class ConnectionStorage { await this.internalStorage.set(RECENTLY_OPENED_FILES_KEY, undefined); } - async grantExtensionAuthorisation(extension: vscode.Extension) { + async grantExtensionAuthorisation(extensionId: string, displayName: string) { const extensions = this.getAuthorisedExtensions(); - if (!this.getExtensionAuthorisation(extension)) { + if (!this.getExtensionAuthorisation(extensionId)) { extensions.push({ - id: extension.id, - displayName: extension.packageJSON.displayName, + id: extensionId, + displayName: displayName, since: new Date().getTime(), lastAccess: new Date().getTime() }); @@ -251,8 +251,8 @@ export class ConnectionStorage { } } - getExtensionAuthorisation(extension: vscode.Extension) { - const authorisedExtension = this.getAuthorisedExtensions().find(authorisedExtension => authorisedExtension.id === extension.id); + getExtensionAuthorisation(extensionId: string) { + const authorisedExtension = this.getAuthorisedExtensions().find(authorisedExtension => authorisedExtension.id === extensionId); if (authorisedExtension) { authorisedExtension.lastAccess = new Date().getTime(); } diff --git a/src/commands/password.ts b/src/commands/password.ts index 5c081a511..2083dddb6 100644 --- a/src/commands/password.ts +++ b/src/commands/password.ts @@ -26,7 +26,7 @@ export function registerPasswordCommands(context: ExtensionContext, instance: In const storedPassword = await ConnectionManager.getStoredPassword(context, instance.getConnection()!.currentConnectionName); if (storedPassword) { - let isAuthed = storage.getExtensionAuthorisation(extension) !== undefined; + let isAuthed = storage.getExtensionAuthorisation(extension.id) !== undefined; if (!isAuthed) { const detail = `The ${displayName} extension is requesting access to your password for this connection. ${reason ? `\n\nReason: ${reason}` : `The extension did not provide a reason for password access.`}`; @@ -53,7 +53,7 @@ export function registerPasswordCommands(context: ExtensionContext, instance: In switch (result) { case `Allow`: - await storage.grantExtensionAuthorisation(extension); + await storage.grantExtensionAuthorisation(extension.id, displayName); isAuthed = true; done = true; break; diff --git a/src/testing/storage.ts b/src/testing/storage.ts index 3288dbf7a..fba3f14c3 100644 --- a/src/testing/storage.ts +++ b/src/testing/storage.ts @@ -12,22 +12,22 @@ export const StorageSuite: TestSuite = { if(storage){ const extension = vscode.extensions.getExtension("halcyontechltd.code-for-ibmi")!; try{ - let auth = storage.getExtensionAuthorisation(extension); + let auth = storage.getExtensionAuthorisation(extension.id); assert.strictEqual(undefined, auth, "Extension is already authorized"); - storage.grantExtensionAuthorisation(extension); + storage.grantExtensionAuthorisation(extension.id, extension.packageJSON.displayName || extension.id); - auth = storage.getExtensionAuthorisation(extension); + auth = storage.getExtensionAuthorisation(extension.id); assert.ok(auth, "Authorisation not found"); assert.strictEqual(new Date(auth.since).toDateString(), new Date().toDateString(), "Access date must be today"); const lastAccess = auth.lastAccess; await new Promise(r => setTimeout(r, 100)); //Wait a bit - auth = storage.getExtensionAuthorisation(extension); + auth = storage.getExtensionAuthorisation(extension.id); assert.ok(auth, "Authorisation not found"); assert.notStrictEqual(lastAccess, auth.lastAccess, "Last access did not change") } finally{ - const auth = storage.getExtensionAuthorisation(extension); + const auth = storage.getExtensionAuthorisation(extension.id); if(auth){ storage.revokeExtensionAuthorisation(auth); } diff --git a/src/views/diagnostics.ts b/src/views/diagnostics.ts index 20b734e74..595da18cc 100644 --- a/src/views/diagnostics.ts +++ b/src/views/diagnostics.ts @@ -143,7 +143,7 @@ export function handleEvfeventLines(lines: string[], instance: Instance, evfeven const storage = instance.getStorage(); if (workspaceFolder && storage) { - const workspaceDeployPath = storage.getWorkspaceDeployPath(workspaceFolder); + const workspaceDeployPath = storage.getWorkspaceDeployPath(workspaceFolder.uri.fsPath); const deployPathIndex = file.toLowerCase().indexOf(workspaceDeployPath.toLowerCase()); let relativeCompilePath = (deployPathIndex !== -1 ? file.substring(0, deployPathIndex) + file.substring(deployPathIndex + workspaceDeployPath.length) : undefined); From 33c1a2b22b28142353e3d5ca5b9328668cb6e9f9 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 16:49:28 -0500 Subject: [PATCH 18/46] Refactor hardcoded VS Code configuration Signed-off-by: worksofliam --- src/Instance.ts | 12 +- src/api/IBMi.ts | 15 +- src/api/IBMiContent.ts | 3 +- src/api/Search.ts | 5 +- src/api/configuration/Config.ts | 17 ++ src/api/configuration/ConnectionManager.ts | 219 +++++++++++++++++++ src/api/{ => configuration}/Storage.ts | 2 +- src/commands/actions.ts | 4 +- src/commands/connection.ts | 4 +- src/commands/open.ts | 9 +- src/commands/password.ts | 4 +- src/config/Configuration.ts | 241 +-------------------- src/config/Storage.ts | 2 +- src/config/passwords.ts | 18 ++ src/debug/index.ts | 4 +- src/extension.ts | 8 +- src/filesystems/local/git.ts | 10 +- src/filesystems/qsys/FSUtils.ts | 4 +- src/filesystems/qsys/extendedContent.ts | 8 +- src/filesystems/qsys/sourceDateHandler.ts | 5 +- src/instantiate.ts | 5 +- src/sandbox.ts | 8 +- src/typings.ts | 4 +- src/views/ConnectionBrowser.ts | 49 +++-- src/views/LibraryListView.ts | 11 +- src/views/ProfilesView.ts | 25 ++- src/views/Terminal.ts | 3 +- src/views/actions.ts | 8 +- src/views/diagnostics.ts | 8 +- src/views/ifsBrowser.ts | 37 ++-- src/views/objectBrowser.ts | 37 ++-- src/webviews/actions/index.ts | 8 +- src/webviews/commandProfile/index.ts | 10 +- src/webviews/filters/index.ts | 7 +- src/webviews/login/index.ts | 23 +- src/webviews/settings/index.ts | 23 +- src/webviews/variables/index.ts | 6 +- 37 files changed, 459 insertions(+), 407 deletions(-) create mode 100644 src/api/configuration/Config.ts create mode 100644 src/api/configuration/ConnectionManager.ts rename src/api/{ => configuration}/Storage.ts (99%) create mode 100644 src/config/passwords.ts diff --git a/src/Instance.ts b/src/Instance.ts index ddfba4dec..d212a4946 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -1,11 +1,12 @@ import * as vscode from "vscode"; import { ConnectionData, IBMiEvent } from "./typings"; -import { ConnectionConfiguration } from "./config/Configuration"; import IBMi, { ConnectionResult } from "./api/IBMi"; -import { CodeForIStorage, ConnectionStorage } from "./api/Storage"; +import { CodeForIStorage, ConnectionStorage } from "./api/configuration/Storage"; import { withContext } from "./views/tools"; import { handleConnectionResults, messageCallback } from "./views/connection"; import { VsStorage } from "./config/Storage"; +import { VsCodeConfig } from "./config/Configuration"; +import { ConnectionConfig } from "./api/configuration/ConnectionManager"; type IBMiEventSubscription = { func: Function, @@ -33,7 +34,10 @@ export default class Instance { constructor(context: vscode.ExtensionContext) { const vscodeStorage = new VsStorage(context); this.storage = new ConnectionStorage(vscodeStorage); + IBMi.GlobalStorage = new CodeForIStorage(vscodeStorage); + IBMi.connectionManager.configMethod = new VsCodeConfig(); + this.emitter.event(e => this.processEvent(e)); } @@ -163,11 +167,11 @@ export default class Instance { return this.connection; } - async setConfig(newConfig: ConnectionConfiguration.Parameters) { + async setConfig(newConfig: ConnectionConfig) { if (this.connection) { this.connection.setConfig(newConfig); } - await ConnectionConfiguration.update(newConfig); + await IBMi.connectionManager.update(newConfig); } /** diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index b48b06ea1..81fa850cd 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -9,13 +9,13 @@ import { CustomQSh } from '../components/cqsh'; import { ComponentManager } from "./components/manager"; import { CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, WrapResult } from "../typings"; import { CompileTools } from "./CompileTools"; -import { ConnectionConfiguration } from "../config/Configuration"; import IBMiContent from "./IBMiContent"; -import { CachedServerSettings, CodeForIStorage } from './Storage'; +import { CachedServerSettings, CodeForIStorage } from './configuration/Storage'; import { Tools } from './Tools'; import * as configVars from './configVars'; import { DebugConfiguration } from "../debug/config"; import { debugPTFInstalled } from "../debug/server"; +import { ConnectionManager, ConnectionConfig } from './configuration/ConnectionManager'; export interface MemberParts extends IBMiMember { basename: string @@ -64,6 +64,7 @@ interface ConnectionCallbacks{ export default class IBMi { public static GlobalStorage: CodeForIStorage; + public static connectionManager: ConnectionManager = new ConnectionManager(); static readonly CCSID_NOCONVERSION = 65535; static readonly CCSID_SYSVAL = -2; static readonly bashShellPath = '/QOpenSys/pkgs/bin/bash'; @@ -80,7 +81,7 @@ export default class IBMi { /** * @deprecated Will become private in v3.0.0 - use {@link IBMi.getConfig} instead. */ - config?: ConnectionConfiguration.Parameters; + config?: ConnectionConfig; /** * @deprecated Will become private in v3.0.0 - use {@link IBMi.getContent} instead. */ @@ -169,7 +170,7 @@ export default class IBMi { } } - setConfig(newConfig: ConnectionConfiguration.Parameters) { + setConfig(newConfig: ConnectionConfig) { this.config = newConfig; } @@ -246,7 +247,7 @@ export default class IBMi { }); //Load existing config - this.config = await ConnectionConfiguration.load(this.currentConnectionName); + this.config = await IBMi.connectionManager.load(this.currentConnectionName); // Load cached server settings. const cachedServerSettings: CachedServerSettings = IBMi.GlobalStorage.getServerSettingsCache(this.currentConnectionName); @@ -963,7 +964,7 @@ export default class IBMi { }; } finally { - ConnectionConfiguration.update(this.config!); + IBMi.connectionManager.update(this.config!); } } @@ -1199,7 +1200,7 @@ export default class IBMi { async setLastDownloadLocation(location: string) { if (this.config && location && location !== this.config.lastDownloadLocation) { this.config.lastDownloadLocation = location; - await ConnectionConfiguration.update(this.config); + await IBMi.connectionManager.update(this.config); } } diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index 5d3b2763f..cd63ab9e8 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -7,7 +7,6 @@ import * as node_ssh from "node-ssh"; import { GetMemberInfo } from './components/getMemberInfo'; import { ObjectTypes } from '../filesystems/qsys/Objects'; import { AttrOperands, CommandResult, IBMiError, IBMiMember, IBMiObject, IFSFile, QsysPath, SpecialAuthorities } from '../typings'; -import { ConnectionConfiguration } from '../config/Configuration'; import { FilterType, parseFilter, singleGenericName } from './Filter'; import { default as IBMi } from './IBMi'; import { Tools } from './Tools'; @@ -28,7 +27,7 @@ export type SortOptions = { export default class IBMiContent { constructor(readonly ibmi: IBMi) { } - private get config(): ConnectionConfiguration.Parameters { + private get config() { return this.ibmi.getConfig(); } diff --git a/src/api/Search.ts b/src/api/Search.ts index 6dc7fe82b..830a614a2 100644 --- a/src/api/Search.ts +++ b/src/api/Search.ts @@ -1,7 +1,6 @@ import * as path from 'path'; import { GetMemberInfo } from './components/getMemberInfo'; import { IBMiMember, SearchHit, SearchResults } from '../typings'; -import { GlobalVSCodeConfiguration } from '../config/Configuration'; import { Tools } from './Tools'; import IBMi from './IBMi'; @@ -109,7 +108,7 @@ export namespace Search { const grep = connection.remoteFeatures.grep; if (grep) { - const dirsToIgnore = GlobalVSCodeConfiguration.get(`grepIgnoreDirs`) || []; + const dirsToIgnore = IBMi.connectionManager.get(`grepIgnoreDirs`) || []; let ignoreString = ``; if (dirsToIgnore.length > 0) { @@ -141,7 +140,7 @@ export namespace Search { const find = connection.remoteFeatures.find; if (find) { - const dirsToIgnore = GlobalVSCodeConfiguration.get(`grepIgnoreDirs`) || []; + const dirsToIgnore = IBMi.connectionManager.get(`grepIgnoreDirs`) || []; let ignoreString = ``; if (dirsToIgnore.length > 0) { diff --git a/src/api/configuration/Config.ts b/src/api/configuration/Config.ts new file mode 100644 index 000000000..433858435 --- /dev/null +++ b/src/api/configuration/Config.ts @@ -0,0 +1,17 @@ +export abstract class Config { + abstract get(key: string): T | undefined; + + abstract set(key: string, value: any): Promise; +} + +export class VirtualConfig extends Config { + private readonly config: Map = new Map(); + + get(key: string): T | undefined { + return this.config.get(key) as T | undefined; + } + + async set(key: string, value: any): Promise { + this.config.set(key, value); + } +} \ No newline at end of file diff --git a/src/api/configuration/ConnectionManager.ts b/src/api/configuration/ConnectionManager.ts new file mode 100644 index 000000000..a2de4eb06 --- /dev/null +++ b/src/api/configuration/ConnectionManager.ts @@ -0,0 +1,219 @@ + +import os from "os"; +import { SourceDateMode } from "../../config/Configuration"; +import { ConnectionData, DeploymentMethod } from "../../typings"; +import { FilterType } from "../Filter"; +import { Config, VirtualConfig } from "./Config"; + +export interface ConnectionConfig extends ConnectionProfile { + host: string; + autoClearTempData: boolean; + connectionProfiles: ConnectionProfile[]; + commandProfiles: CommandProfile[]; + autoSortIFSShortcuts: boolean; + tempLibrary: string; + tempDir: string; + sourceASP: string; + sourceFileCCSID: string; + autoConvertIFSccsid: boolean; + hideCompileErrors: string[]; + enableSourceDates: boolean; + sourceDateMode: SourceDateMode; + sourceDateGutter: boolean; + encodingFor5250: string; + terminalFor5250: string; + setDeviceNameFor5250: boolean; + connectringStringFor5250: string; + autoSaveBeforeAction: boolean; + showDescInLibList: boolean; + debugPort: string; + debugSepPort: string; + debugUpdateProductionFiles: boolean; + debugEnableDebugTracing: boolean; + readOnlyMode: boolean; + quickConnect: boolean; + defaultDeploymentMethod: DeploymentMethod | ''; + protectedPaths: string[]; + showHiddenFiles: boolean; + lastDownloadLocation: string; + [name: string]: any; +} + +export interface ObjectFilters { + name: string + filterType: FilterType + library: string + object: string + types: string[] + member: string + memberType: string + protected: boolean +} + +export interface CustomVariable { + name: string + value: string +} + +export interface ConnectionProfile { + name: string + homeDirectory: string + currentLibrary: string + libraryList: string[] + objectFilters: ObjectFilters[] + ifsShortcuts: string[] + customVariables: CustomVariable[] +} + +export interface CommandProfile { + name: string; + command: string; +} + +export interface StoredConnection { + index: number, + data: ConnectionData +}; + +function initialize(parameters: Partial): ConnectionConfig { + return { + ...parameters, + name: parameters.name!, + host: parameters.host || '', + objectFilters: parameters.objectFilters || [], + libraryList: parameters.libraryList || [], + autoClearTempData: parameters.autoClearTempData || false, + customVariables: parameters.customVariables || [], + connectionProfiles: parameters.connectionProfiles || [], + commandProfiles: parameters.commandProfiles || [], + ifsShortcuts: parameters.ifsShortcuts || [], + /** Default auto sorting of shortcuts to off */ + autoSortIFSShortcuts: parameters.autoSortIFSShortcuts || false, + homeDirectory: parameters.homeDirectory || `.`, + /** Undefined means not created, so default to on */ + tempLibrary: parameters.tempLibrary || `ILEDITOR`, + tempDir: parameters.tempDir || `/tmp`, + currentLibrary: parameters.currentLibrary || ``, + sourceASP: parameters.sourceASP || ``, + sourceFileCCSID: parameters.sourceFileCCSID || `*FILE`, + autoConvertIFSccsid: (parameters.autoConvertIFSccsid === true), + hideCompileErrors: parameters.hideCompileErrors || [], + enableSourceDates: parameters.enableSourceDates === true, + sourceDateMode: parameters.sourceDateMode || "diff", + sourceDateGutter: parameters.sourceDateGutter === true, + encodingFor5250: parameters.encodingFor5250 || `default`, + terminalFor5250: parameters.terminalFor5250 || `default`, + setDeviceNameFor5250: (parameters.setDeviceNameFor5250 === true), + connectringStringFor5250: parameters.connectringStringFor5250 || `localhost`, + autoSaveBeforeAction: (parameters.autoSaveBeforeAction === true), + showDescInLibList: (parameters.showDescInLibList === true), + debugPort: (parameters.debugPort || "8005"), + debugSepPort: (parameters.debugSepPort || "8008"), + debugUpdateProductionFiles: (parameters.debugUpdateProductionFiles === true), + debugEnableDebugTracing: (parameters.debugEnableDebugTracing === true), + readOnlyMode: (parameters.readOnlyMode === true), + quickConnect: (parameters.quickConnect === true || parameters.quickConnect === undefined), + defaultDeploymentMethod: parameters.defaultDeploymentMethod || ``, + protectedPaths: (parameters.protectedPaths || []), + showHiddenFiles: (parameters.showHiddenFiles === true || parameters.showHiddenFiles === undefined), + lastDownloadLocation: (parameters.lastDownloadLocation || os.homedir()) + } +} + +export class ConnectionManager { + configMethod: Config = new VirtualConfig(); + + /** + * A bit of a hack to access any piece of configuration. (like actions) + */ + get(key: string) { + return this.configMethod.get(key); + } + + /** + * Same hack as get. + */ + set(key: string, value: any) { + return this.configMethod.set(key, value); + } + + getByName(name: string) { + const connections = this.getAll(); + const index = connections.findIndex(conn => conn.name === name); + if (index !== -1) { + return { index, data: connections[index] }; + } + } + + async sort() { + const connections = await this.getAll(); + connections.sort((a, b) => a.name.localeCompare(b.name)); + return this.configMethod.set(`connections`, connections); + } + + getAll() { + return this.configMethod.get(`connections`) || []; + } + + async setAll(connections: ConnectionData[]) { + return this.configMethod.set(`connections`, connections); + } + + async storeNew(data: ConnectionData) { + const connections = await this.getAll(); + const newId = connections.length; + connections.push(data); + await this.setAll(connections); + return { index: newId, data }; + } + + async deleteByName(name: string) { + const connections = await this.getAll(); + const index = connections.findIndex(conn => conn.name === name); + if (index !== -1) { + connections.splice(index, 1); + return this.setAll(connections); + } + } + + async updateByIndex(index: number, data: ConnectionData) { + const connections = await this.getAll(); + connections[index] = data; + + // Remove possible password from any connection + connections.forEach(conn => delete conn.password); + + return this.configMethod.set(`connections`, connections); + } + + getConnectionSettings(): ConnectionConfig[] { + return this.configMethod.get(`connectionSettings`) || []; + } + + async updateAll(connections: ConnectionConfig[]) { + await this.configMethod.set(`connectionSettings`, connections); + } + + async update(parameters: ConnectionConfig) { + if (parameters?.name) { + const connections = this.getConnectionSettings(); + connections.filter(conn => conn.name === parameters.name).forEach(conn => Object.assign(conn, parameters)); + await this.updateAll(connections); + } + } + + async load(name: string): Promise { + let connections = this.getConnectionSettings(); + let existingConfig = connections.find(conn => conn.name === name); + let config: ConnectionConfig; + if (existingConfig) { + config = initialize(existingConfig); + } else { + config = initialize({ name: name }); + connections.push(config); + await this.updateAll(connections); + } + + return config; + } +} \ No newline at end of file diff --git a/src/api/Storage.ts b/src/api/configuration/Storage.ts similarity index 99% rename from src/api/Storage.ts rename to src/api/configuration/Storage.ts index dd1d04b99..22711fd3b 100644 --- a/src/api/Storage.ts +++ b/src/api/configuration/Storage.ts @@ -1,5 +1,5 @@ -import { ConnectionData } from '../typings'; +import { ConnectionData } from '../../typings'; const PREVIOUS_CUR_LIBS_KEY = `prevCurLibs`; const LAST_PROFILE_KEY = `currentProfile`; diff --git a/src/commands/actions.ts b/src/commands/actions.ts index a1d8b79ce..2bdc233ef 100644 --- a/src/commands/actions.ts +++ b/src/commands/actions.ts @@ -1,10 +1,10 @@ import path from "path"; import { commands, TreeItem, Uri, WorkspaceFolder, window, Disposable } from "vscode"; -import { ConnectionConfiguration } from "../config/Configuration"; import { refreshDiagnosticsFromServer } from "../views/diagnostics"; import Instance from "../Instance"; import { BrowserItem, Action, DeploymentMethod } from "../typings"; import { runAction } from "../views/actions"; +import IBMi from "../api/IBMi"; export function registerActionsCommands(instance: Instance): Disposable[] { return [ @@ -43,7 +43,7 @@ export function registerActionsCommands(instance: Instance): Disposable[] { break; case `Save automatically`: config.autoSaveBeforeAction = true; - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); await editor.document.save(); canRun = true; break; diff --git a/src/commands/connection.ts b/src/commands/connection.ts index 7e7be6b70..5bbca140b 100644 --- a/src/commands/connection.ts +++ b/src/commands/connection.ts @@ -1,8 +1,8 @@ import { commands, Disposable, ExtensionContext, window } from "vscode"; -import { ConnectionManager } from "../config/Configuration"; import Instance from "../Instance"; import { ConnectionData } from "../typings"; import { safeDisconnect } from "../instantiate"; +import { setStoredPassword } from "../config/passwords"; export function registerConnectionCommands(context: ExtensionContext, instance: Instance): Disposable[] { @@ -16,7 +16,7 @@ export function registerConnectionCommands(context: ExtensionContext, instance: } if (savePassword && connectionData.password) { - await ConnectionManager.setStoredPassword(context, connectionData.name, connectionData.password); + await setStoredPassword(context, connectionData.name, connectionData.password); } return (await instance.connect({data: connectionData, reloadServerSettings: reloadSettings})).success; diff --git a/src/commands/open.ts b/src/commands/open.ts index 08193114b..b417cba12 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -3,9 +3,10 @@ import { MemberItem, OpenEditableOptions, WithPath } from "../typings"; import Instance from "../Instance"; import { Tools } from "../api/Tools"; import { getUriFromPath, parseFSOptions } from "../filesystems/qsys/QSysFs"; -import { DefaultOpenMode, GlobalVSCodeConfiguration } from "../config/Configuration"; +import { DefaultOpenMode } from "../config/Configuration"; import path from "path"; import { findExistingDocument, findExistingDocumentUri } from "../views/tools"; +import IBMi from "../api/IBMi"; const CLEAR_RECENT = `$(trash) Clear recently opened`; const CLEAR_CACHED = `$(trash) Clear cached`; @@ -53,7 +54,7 @@ export function registerOpenCommands(instance: Instance): Disposable[] { } // Add file to front of recently opened files list. - const recentLimit = GlobalVSCodeConfiguration.get(`recentlyOpenedFilesLimit`); + const recentLimit = IBMi.connectionManager.get(`recentlyOpenedFilesLimit`); const storage = instance.getStorage(); if (recentLimit) { const recent = storage!.getRecentlyOpenedFiles(); @@ -78,7 +79,7 @@ export function registerOpenCommands(instance: Instance): Disposable[] { }), commands.registerCommand("code-for-ibmi.openWithDefaultMode", (item: WithPath, overrideMode?: DefaultOpenMode, position?: Range) => { - const readonly = (overrideMode || GlobalVSCodeConfiguration.get("defaultOpenMode")) === "browse"; + const readonly = (overrideMode || IBMi.connectionManager.get("defaultOpenMode")) === "browse"; commands.executeCommand(`code-for-ibmi.openEditable`, item.path, { readonly, position } as OpenEditableOptions); }), @@ -128,7 +129,7 @@ export function registerOpenCommands(instance: Instance): Disposable[] { let list: string[] = []; // Get recently opened files - cut if limit has been reduced. - const recentLimit = GlobalVSCodeConfiguration.get(`recentlyOpenedFilesLimit`) as number; + const recentLimit = IBMi.connectionManager.get(`recentlyOpenedFilesLimit`) as number; const recent = storage!.getRecentlyOpenedFiles(); if (recent.length > recentLimit) { recent.splice(recentLimit); diff --git a/src/commands/password.ts b/src/commands/password.ts index 2083dddb6..312e15eb4 100644 --- a/src/commands/password.ts +++ b/src/commands/password.ts @@ -1,6 +1,6 @@ import { commands, extensions, window, Disposable, ExtensionContext } from "vscode"; -import { ConnectionManager } from "../config/Configuration"; import Instance from "../Instance"; +import { getStoredPassword } from "../config/passwords"; const passwordAttempts: { [extensionId: string]: number } = {} @@ -23,7 +23,7 @@ export function registerPasswordCommands(context: ExtensionContext, instance: In throw new Error(`Password request denied for extension ${displayName}.`); } - const storedPassword = await ConnectionManager.getStoredPassword(context, instance.getConnection()!.currentConnectionName); + const storedPassword = await getStoredPassword(context, instance.getConnection()!.currentConnectionName); if (storedPassword) { let isAuthed = storage.getExtensionAuthorisation(extension.id) !== undefined; diff --git a/src/config/Configuration.ts b/src/config/Configuration.ts index 2e4f39f17..c5caec943 100644 --- a/src/config/Configuration.ts +++ b/src/config/Configuration.ts @@ -1,16 +1,13 @@ -import os from "os"; + import * as vscode from 'vscode'; import { ConnectionData, DeploymentMethod } from '../typings'; import { FilterType } from '../api/Filter'; +import { Config } from "../api/configuration/Config"; export type SourceDateMode = "edit" | "diff"; export type DefaultOpenMode = "browse" | "edit"; export type ReconnectMode = "always" | "never" | "ask"; -const getExtensionConfig = (): vscode.WorkspaceConfiguration => { - return vscode.workspace.getConfiguration(`code-for-ibmi`); -} - export function onCodeForIBMiConfigurationChange(props: string | string[], todo: (value: vscode.ConfigurationChangeEvent) => void) { const keys = (Array.isArray(props) ? props : Array.of(props)).map(key => `code-for-ibmi.${key}`); return vscode.workspace.onDidChangeConfiguration(async event => { @@ -20,233 +17,19 @@ export function onCodeForIBMiConfigurationChange(props: string | string[], to }) } -export namespace GlobalVSCodeConfiguration { - export function get(key: string): T | undefined { - return getExtensionConfig().get(key); - } - - export function set(key: string, value: any) { - return getExtensionConfig().update(key, value, vscode.ConfigurationTarget.Global); - } -} - -export interface StoredConnection { - index: number, - data: ConnectionData -}; - -const getPasswordKey = (connectionName: string) => `${connectionName}_password`; - -export namespace ConnectionManager { - export function getByName(name: string): StoredConnection | undefined { - const connections = getAll(); - const index = connections.findIndex(conn => conn.name === name); - if (index !== -1) { - return { index, data: connections[index] }; - } +export class VsCodeConfig extends Config { + constructor() { + super(); } - - export function sort() { - const connections = getAll(); - connections.sort((a, b) => a.name.localeCompare(b.name)); - return GlobalVSCodeConfiguration.set(`connections`, connections); + private getWorkspaceConfig() { + return vscode.workspace.getConfiguration(`code-for-ibmi`); } - export function getAll(): ConnectionData[] { - return GlobalVSCodeConfiguration.get(`connections`) || []; + get(key: string): T | undefined { + return this.getWorkspaceConfig().get(key); } - - function setAll(connections: ConnectionData[]) { - return GlobalVSCodeConfiguration.set(`connections`, connections); + async set(key: string, value: any): Promise { + await this.getWorkspaceConfig().update(key, value, vscode.ConfigurationTarget.Global); } - export async function storeNew(data: ConnectionData): Promise { - const connections = getAll(); - const newId = connections.length; - connections.push(data); - await setAll(connections); - return { index: newId, data }; - } - - export function deleteByName(name: string) { - const connections = getAll(); - const index = connections.findIndex(conn => conn.name === name); - if (index !== -1) { - connections.splice(index, 1); - return setAll(connections); - } - } - - export function updateByIndex(index: number, data: ConnectionData) { - const connections = getAll(); - connections[index] = data; - - // Remove possible password from any connection - connections.forEach(conn => delete conn.password); - - return GlobalVSCodeConfiguration.set(`connections`, connections); - } - - export function getStoredPassword(context: vscode.ExtensionContext, connectionName: string) { - const connectionKey = getPasswordKey(connectionName); - return context.secrets.get(connectionKey); - } - - export function setStoredPassword(context: vscode.ExtensionContext, connectionName: string, password: string) { - const connectionKey = getPasswordKey(connectionName); - return context.secrets.store(connectionKey, password); - } - - export function deleteStoredPassword(context: vscode.ExtensionContext, connectionName: string) { - const connectionKey = getPasswordKey(connectionName); - return context.secrets.delete(connectionKey); - } -} - -export namespace ConnectionConfiguration { - export interface Parameters extends ConnectionProfile { - host: string; - autoClearTempData: boolean; - connectionProfiles: ConnectionProfile[]; - commandProfiles: CommandProfile[]; - autoSortIFSShortcuts: boolean; - tempLibrary: string; - tempDir: string; - sourceASP: string; - sourceFileCCSID: string; - autoConvertIFSccsid: boolean; - hideCompileErrors: string[]; - enableSourceDates: boolean; - sourceDateMode: SourceDateMode; - sourceDateGutter: boolean; - encodingFor5250: string; - terminalFor5250: string; - setDeviceNameFor5250: boolean; - connectringStringFor5250: string; - autoSaveBeforeAction: boolean; - showDescInLibList: boolean; - debugPort: string; - debugSepPort: string; - debugUpdateProductionFiles: boolean; - debugEnableDebugTracing: boolean; - readOnlyMode: boolean; - quickConnect: boolean; - defaultDeploymentMethod: DeploymentMethod | ''; - protectedPaths: string[]; - showHiddenFiles: boolean; - lastDownloadLocation: string; - [name: string]: any; - } - - export interface ObjectFilters { - name: string - filterType: FilterType - library: string - object: string - types: string[] - member: string - memberType: string - protected: boolean - } - - export interface CustomVariable { - name: string - value: string - } - - export interface ConnectionProfile { - name: string - homeDirectory: string - currentLibrary: string - libraryList: string[] - objectFilters: ObjectFilters[] - ifsShortcuts: string[] - customVariables: CustomVariable[] - } - - export interface CommandProfile { - name: string; - command: string; - } - - function getConnectionSettings(): Parameters[] { - return getExtensionConfig().get(`connectionSettings`) || []; - } - - function initialize(parameters: Partial): Parameters { - return { - ...parameters, - name: parameters.name!, - host: parameters.host || '', - objectFilters: parameters.objectFilters || [], - libraryList: parameters.libraryList || [], - autoClearTempData: parameters.autoClearTempData || false, - customVariables: parameters.customVariables || [], - connectionProfiles: parameters.connectionProfiles || [], - commandProfiles: parameters.commandProfiles || [], - ifsShortcuts: parameters.ifsShortcuts || [], - /** Default auto sorting of shortcuts to off */ - autoSortIFSShortcuts: parameters.autoSortIFSShortcuts || false, - homeDirectory: parameters.homeDirectory || `.`, - /** Undefined means not created, so default to on */ - tempLibrary: parameters.tempLibrary || `ILEDITOR`, - tempDir: parameters.tempDir || `/tmp`, - currentLibrary: parameters.currentLibrary || ``, - sourceASP: parameters.sourceASP || ``, - sourceFileCCSID: parameters.sourceFileCCSID || `*FILE`, - autoConvertIFSccsid: (parameters.autoConvertIFSccsid === true), - hideCompileErrors: parameters.hideCompileErrors || [], - enableSourceDates: parameters.enableSourceDates === true, - sourceDateMode: parameters.sourceDateMode || "diff", - sourceDateGutter: parameters.sourceDateGutter === true, - encodingFor5250: parameters.encodingFor5250 || `default`, - terminalFor5250: parameters.terminalFor5250 || `default`, - setDeviceNameFor5250: (parameters.setDeviceNameFor5250 === true), - connectringStringFor5250: parameters.connectringStringFor5250 || `localhost`, - autoSaveBeforeAction: (parameters.autoSaveBeforeAction === true), - showDescInLibList: (parameters.showDescInLibList === true), - debugPort: (parameters.debugPort || "8005"), - debugSepPort: (parameters.debugSepPort || "8008"), - debugUpdateProductionFiles: (parameters.debugUpdateProductionFiles === true), - debugEnableDebugTracing: (parameters.debugEnableDebugTracing === true), - readOnlyMode: (parameters.readOnlyMode === true), - quickConnect: (parameters.quickConnect === true || parameters.quickConnect === undefined), - defaultDeploymentMethod: parameters.defaultDeploymentMethod || ``, - protectedPaths: (parameters.protectedPaths || []), - showHiddenFiles: (parameters.showHiddenFiles === true || parameters.showHiddenFiles === undefined), - lastDownloadLocation: (parameters.lastDownloadLocation || os.homedir()) - } - } - - async function updateAll(connections: Parameters[]) { - await getExtensionConfig().update(`connectionSettings`, connections, vscode.ConfigurationTarget.Global); - } - - export async function update(parameters: Parameters) { - if (parameters?.name) { - const connections = getConnectionSettings(); - connections.filter(conn => conn.name === parameters.name).forEach(conn => Object.assign(conn, parameters)); - await updateAll(connections); - } - } - - /** - * Will load an existing config if it exists, otherwise will create it with default values. - * @param name Connection name string for configuration - * @returns the parameters - */ - export async function load(name: string): Promise { - let connections = getConnectionSettings(); - let existingConfig = connections.find(conn => conn.name === name); - let config: Parameters; - if (existingConfig) { - config = initialize(existingConfig); - } else { - config = initialize({ name: name }); - connections.push(config); - await updateAll(connections); - } - - return config; - } -} +} \ No newline at end of file diff --git a/src/config/Storage.ts b/src/config/Storage.ts index 1e99ac191..e547a6f33 100644 --- a/src/config/Storage.ts +++ b/src/config/Storage.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import { Storage } from '../api/Storage'; +import { Storage } from '../api/configuration/Storage'; export class VsStorage extends Storage { declare protected readonly globalState; diff --git a/src/config/passwords.ts b/src/config/passwords.ts new file mode 100644 index 000000000..ee84d776b --- /dev/null +++ b/src/config/passwords.ts @@ -0,0 +1,18 @@ +import { ExtensionContext } from "vscode"; + +const getPasswordKey = (connectionName: string) => `${connectionName}_password`; + +export function getStoredPassword(context: ExtensionContext, connectionName: string) { + const connectionKey = getPasswordKey(connectionName); + return context.secrets.get(connectionKey); +} + +export function setStoredPassword(context: ExtensionContext, connectionName: string, password: string) { + const connectionKey = getPasswordKey(connectionName); + return context.secrets.store(connectionKey, password); +} + +export function deleteStoredPassword(context: ExtensionContext, connectionName: string) { + const connectionKey = getPasswordKey(connectionName); + return context.secrets.delete(connectionKey); +} \ No newline at end of file diff --git a/src/debug/index.ts b/src/debug/index.ts index 5cc96b5e5..809e8fece 100644 --- a/src/debug/index.ts +++ b/src/debug/index.ts @@ -7,12 +7,12 @@ import * as vscode from 'vscode'; import { instance } from "../instantiate"; import { ObjectItem } from "../typings"; import { ILELibrarySettings } from "../api/CompileTools"; -import { ConnectionManager } from "../config/Configuration"; import { Env, getEnvConfig } from "../filesystems/local/env"; import * as certificates from "./certificates"; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, resetDebugServiceDetails } from "./config"; import * as server from "./server"; import { withContext } from "../views/tools"; +import { getStoredPassword } from "../config/passwords"; const debugExtensionId = `IBM.ibmidebug`; @@ -174,7 +174,7 @@ export async function initialize(context: ExtensionContext) { const getPassword = async () => { const connection = instance.getConnection(); - let password = await ConnectionManager.getStoredPassword(context, connection!.currentConnectionName); + let password = await getStoredPassword(context, connection!.currentConnectionName); if (!password) { password = temporaryPassword; diff --git a/src/extension.ts b/src/extension.ts index a41580a77..1fea4c7a7 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,7 +6,7 @@ import { ExtensionContext, commands, languages, window, workspace } from "vscode import { CustomUI } from "./webviews/CustomUI"; import { instance, loadAllofExtension } from './instantiate'; -import { ConnectionConfiguration, ConnectionManager, onCodeForIBMiConfigurationChange } from "./config/Configuration"; +import { onCodeForIBMiConfigurationChange } from "./config/Configuration"; import { Tools } from "./api/Tools"; import * as Debug from './debug'; import { parseErrors } from "./api/errors/parser"; @@ -40,8 +40,9 @@ export async function activate(context: ExtensionContext): Promise console.log(`Congratulations, your extension "code-for-ibmi" is now active!`); await loadAllofExtension(context); + const updateLastConnectionAndServerCache = () => { - const connections = ConnectionManager.getAll(); + const connections = IBMi.connectionManager.getAll(); const lastConnections = (IBMi.GlobalStorage.getLastConnections() || []).filter(lc => connections.find(c => c.name === lc.name)); IBMi.GlobalStorage.setLastConnections(lastConnections); commands.executeCommand(`setContext`, `code-for-ibmi:hasPreviousConnection`, lastConnections.length > 0); @@ -69,13 +70,14 @@ export async function activate(context: ExtensionContext): Promise `profilesView`, new ProfilesView(context) ), + onCodeForIBMiConfigurationChange("connections", updateLastConnectionAndServerCache), onCodeForIBMiConfigurationChange("connectionSettings", async () => { const connection = instance.getConnection(); if (connection) { const config = instance.getConfig(); if (config) { - Object.assign(config, (await ConnectionConfiguration.load(config.name))); + Object.assign(config, (await IBMi.connectionManager.load(config.name))); } } }), diff --git a/src/filesystems/local/git.ts b/src/filesystems/local/git.ts index acfb3b93f..42daf817a 100644 --- a/src/filesystems/local/git.ts +++ b/src/filesystems/local/git.ts @@ -1,10 +1,10 @@ import { ExtensionContext, WorkspaceFolder, commands, window } from "vscode"; import { getBranchLibraryName } from "./env"; import { instance } from "../../instantiate"; -import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../../config/Configuration"; import IBMi from "../../api/IBMi"; import IBMiContent from "../../api/IBMiContent"; import { getGitAPI } from "../../views/tools"; +import { ConnectionConfig } from "../../api/configuration/ConnectionManager"; const lastBranch: { [workspaceUri: string]: string } = {}; @@ -26,7 +26,7 @@ export function setupGitEventHandler(context: ExtensionContext) { const workspaceUri = repo.rootUri.toString(); const changeEvent = repo.state.onDidChange((_e) => { - if (GlobalVSCodeConfiguration.get(`createLibraryOnBranchChange`)) { + if (IBMi.connectionManager.get(`createLibraryOnBranchChange`)) { if (repo) { const head = repo.state.HEAD; const connection = instance.getConnection(); @@ -55,7 +55,7 @@ export function setupGitEventHandler(context: ExtensionContext) { } } -function setupBranchLibrary(currentBranch: string, content: IBMiContent, connection: IBMi, config: ConnectionConfiguration.Parameters) { +function setupBranchLibrary(currentBranch: string, content: IBMiContent, connection: IBMi, config: ConnectionConfig) { const filters = config.objectFilters; const newBranchLib = getBranchLibraryName(currentBranch); content.checkObject({ library: `QSYS`, name: newBranchLib, type: `*LIB` }).then(exists => { @@ -75,7 +75,7 @@ function setupBranchLibrary(currentBranch: string, content: IBMiContent, connect }); config.objectFilters = filters; - ConnectionConfiguration.update(config).then(() => { + IBMi.connectionManager.update(config).then(() => { commands.executeCommand(`code-for-ibmi.refreshObjectBrowser`); }); } @@ -102,7 +102,7 @@ function setupBranchLibrary(currentBranch: string, content: IBMiContent, connect }); config.objectFilters = filters; - ConnectionConfiguration.update(config).then(() => { + IBMi.connectionManager.update(config).then(() => { commands.executeCommand(`code-for-ibmi.refreshObjectBrowser`); }); } diff --git a/src/filesystems/qsys/FSUtils.ts b/src/filesystems/qsys/FSUtils.ts index 1ed3fc429..87f0dee72 100644 --- a/src/filesystems/qsys/FSUtils.ts +++ b/src/filesystems/qsys/FSUtils.ts @@ -1,6 +1,6 @@ import path from "path"; import vscode, { l10n } from "vscode"; -import { GlobalVSCodeConfiguration, ReconnectMode } from "../../config/Configuration"; +import { ReconnectMode } from "../../config/Configuration"; import { findUriTabs } from "../../views/tools"; import IBMi from "../../api/IBMi"; @@ -12,7 +12,7 @@ import IBMi from "../../api/IBMi"; * @returns `true` if the user choses to reconnect, `false` otherwise. */ export async function reconnectFS(uri: vscode.Uri) { - const reconnect = GlobalVSCodeConfiguration.get("autoReconnect") || "ask"; + const reconnect = IBMi.connectionManager.get("autoReconnect") || "ask"; let doReconnect = false; switch (reconnect) { case "always": diff --git a/src/filesystems/qsys/extendedContent.ts b/src/filesystems/qsys/extendedContent.ts index fbc3661d1..42a55e996 100644 --- a/src/filesystems/qsys/extendedContent.ts +++ b/src/filesystems/qsys/extendedContent.ts @@ -2,9 +2,9 @@ import fs from "fs"; import tmp from "tmp"; import util from "util"; import vscode from "vscode"; -import { GlobalVSCodeConfiguration } from "../../config/Configuration"; import { instance } from "../../instantiate"; import { getAliasName, SourceDateHandler } from "./sourceDateHandler"; +import IBMi from "../../api/IBMi"; const tmpFile = util.promisify(tmp.file); const writeFileAsync = util.promisify(fs.writeFile); @@ -33,7 +33,7 @@ export class ExtendedIBMiContent { const config = instance.getConfig(); const connection = instance.getConnection(); if (connection && config && content) { - const sourceColourSupport = GlobalVSCodeConfiguration.get(`showSeuColors`); + const sourceColourSupport = IBMi.connectionManager.get(`showSeuColors`); const tempLib = config.tempLibrary; const alias = getAliasName(uri); const aliasPath = `${tempLib}.${alias}`; @@ -128,12 +128,12 @@ export class ExtendedIBMiContent { const sourceDates = this.sourceDateHandler.sourceDateMode === `edit` ? this.sourceDateHandler.baseDates.get(alias) || [] : this.sourceDateHandler.calcNewSourceDates(alias, body); - const client = connection.client; + const client = connection.client!; const { library, file, name } = connection.parserMemberPath(uri.path); const tempRmt = connection.getTempRemote(library + file + name); if (tempRmt) { - const sourceColourSupport = GlobalVSCodeConfiguration.get(`showSeuColors`); + const sourceColourSupport = IBMi.connectionManager.get(`showSeuColors`); const tmpobj = await tmpFile(); const sourceData = body.split(`\n`); diff --git a/src/filesystems/qsys/sourceDateHandler.ts b/src/filesystems/qsys/sourceDateHandler.ts index 11fd3968e..263667ab9 100644 --- a/src/filesystems/qsys/sourceDateHandler.ts +++ b/src/filesystems/qsys/sourceDateHandler.ts @@ -2,8 +2,9 @@ import Crypto from "crypto"; import vscode from "vscode"; import { DiffComputer } from "vscode-diff"; -import { GlobalVSCodeConfiguration, SourceDateMode } from "../../config/Configuration"; +import { SourceDateMode } from "../../config/Configuration"; import { instance } from "../../instantiate"; +import IBMi from "../../api/IBMi"; const editedTodayColor = new vscode.ThemeColor(`gitDecoration.modifiedResourceForeground`); const seachGutterColor = new vscode.ThemeColor(`gitDecoration.addedResourceForeground`); @@ -100,7 +101,7 @@ export class SourceDateHandler { changeSourceDateMode(sourceDateMode: SourceDateMode) { this.sourceDateMode = sourceDateMode; - const dateSearchButtonEnabled = GlobalVSCodeConfiguration.get(`showDateSearchButton`); + const dateSearchButtonEnabled = IBMi.connectionManager.get(`showDateSearchButton`); if (this.sourceDateMode === "diff" && dateSearchButtonEnabled) { this.sourceDateSearchBarItem.show(); diff --git a/src/instantiate.ts b/src/instantiate.ts index cfd04f139..3d1bf91b4 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode"; -import { GlobalVSCodeConfiguration, onCodeForIBMiConfigurationChange } from "./config/Configuration"; +import { onCodeForIBMiConfigurationChange } from "./config/Configuration"; import Instance from "./Instance"; import { Terminal } from './views/Terminal'; import { getDebugServiceDetails } from './debug/config'; @@ -15,6 +15,7 @@ import { QSysFS } from "./filesystems/qsys/QSysFs"; import { SEUColorProvider } from "./languages/general/SEUColorProvider"; import { ActionsUI } from './webviews/actions'; import { VariablesUI } from "./webviews/variables"; +import IBMi from "./api/IBMi"; export let instance: Instance; @@ -97,7 +98,7 @@ export async function loadAllofExtension(context: vscode.ExtensionContext) { ); // Color provider - if (GlobalVSCodeConfiguration.get(`showSeuColors`)) { + if (IBMi.connectionManager.get(`showSeuColors`)) { SEUColorProvider.intitialize(context); } diff --git a/src/sandbox.ts b/src/sandbox.ts index e8da3cd0c..d8bb0722e 100644 --- a/src/sandbox.ts +++ b/src/sandbox.ts @@ -1,10 +1,10 @@ import { env } from "process"; import querystring from "querystring"; import { commands, ExtensionContext, l10n, Uri, window } from "vscode"; -import { ConnectionConfiguration, ConnectionManager } from "./config/Configuration"; import { instance } from "./instantiate"; import { ConnectionData } from "./typings"; import { getGitAPI } from "./views/tools"; +import IBMi from "./api/IBMi"; export async function registerUriHandler(context: ExtensionContext) { context.subscriptions.push( @@ -64,11 +64,11 @@ export async function registerUriHandler(context: ExtensionContext) { await initialSetup(connectionData.username); if (save) { - const existingConnection = ConnectionManager.getByName(connectionData.name); + const existingConnection = IBMi.connectionManager.getByName(connectionData.name); if (!existingConnection) { // New connection! - await ConnectionManager.storeNew(connectionData); + await IBMi.connectionManager.storeNew(connectionData); } } @@ -203,7 +203,7 @@ async function initialSetup(username: string) { }, ); - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); commands.executeCommand(`code-for-ibmi.refreshLibraryListView`); commands.executeCommand(`code-for-ibmi.refreshObjectBrowser`); } diff --git a/src/typings.ts b/src/typings.ts index 79f1c9218..32814891d 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -1,11 +1,11 @@ import { Ignore } from 'ignore'; import { MarkdownString, ProviderResult, Range, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode"; -import { ConnectionConfiguration } from './config/Configuration'; import { CustomUI } from "./webviews/CustomUI"; import Instance from "./Instance"; import { Tools } from "./api/Tools"; import { DeployTools } from "./filesystems/local/deployTools"; import { ComponentRegistry } from './api/components/manager'; +import { ObjectFilters } from './api/configuration/ConnectionManager'; export interface CodeForIBMi { instance: Instance, @@ -193,7 +193,7 @@ export class BrowserItem extends TreeItem { } export interface FilteredItem { - filter: ConnectionConfiguration.ObjectFilters + filter: ObjectFilters } export interface ObjectItem extends FilteredItem, WithPath { diff --git a/src/views/ConnectionBrowser.ts b/src/views/ConnectionBrowser.ts index deda8abfc..20f897196 100644 --- a/src/views/ConnectionBrowser.ts +++ b/src/views/ConnectionBrowser.ts @@ -1,15 +1,16 @@ import vscode from 'vscode'; import { ConnectionData, Server } from '../typings'; -import { ConnectionConfiguration, ConnectionManager, GlobalVSCodeConfiguration } from '../config/Configuration'; import { instance } from '../instantiate'; import { Login } from '../webviews/login'; import IBMi from '../api/IBMi'; +import { ConnectionConfig, ConnectionManager } from '../api/configuration/ConnectionManager'; +import { deleteStoredPassword, getStoredPassword, setStoredPassword } from '../config/passwords'; type CopyOperationItem = { label: string picked: true - copy: (from: ConnectionConfiguration.Parameters, to: ConnectionConfiguration.Parameters) => void + copy: (from: ConnectionConfig, to: ConnectionConfig) => void } export function initializeConnectionBrowser(context: vscode.ExtensionContext) { @@ -79,7 +80,7 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { vscode.commands.registerCommand(`code-for-ibmi.renameConnection`, async (server: Server) => { if (!connectionBrowser.attemptingConnection && server) { - const existingConnections = ConnectionManager.getAll(); + const existingConnections = await IBMi.connectionManager.getAll(); const newName = await vscode.window.showInputBox({ prompt: vscode.l10n.t(`Rename connection "{0}"`, server.name), value: server.name, @@ -95,13 +96,13 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { if (newName) { try { // First rename the connection details - let { index, data } = ConnectionManager.getByName(server.name)! + let { index, data } = (await IBMi.connectionManager.getByName(server.name))! if (index === -1) throw (vscode.l10n.t(`No connection named "{0}" was found`, server.name)); data.name = newName; - await ConnectionManager.updateByIndex(index, data); + await IBMi.connectionManager.updateByIndex(index, data); // Then rename the connection settings - const connectionSettings = GlobalVSCodeConfiguration.get(`connectionSettings`) || []; + const connectionSettings = IBMi.connectionManager.get(`connectionSettings`) || []; index = connectionSettings.findIndex(connection => connection.name === server.name); if (index === -1) throw (vscode.l10n.t(`No parameters for connection "{0}" was found`, server.name)); connectionSettings[index].name = newName; @@ -110,17 +111,17 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { const cachedConnectionSettings = IBMi.GlobalStorage.getServerSettingsCache(server.name); // Then get the password key - const secret = await ConnectionManager.getStoredPassword(context, server.name); + const secret = await getStoredPassword(context, server.name); // No errors - update the settings. - await GlobalVSCodeConfiguration.set(`connectionSettings`, connectionSettings); + await IBMi.connectionManager.set(`connectionSettings`, connectionSettings); if (cachedConnectionSettings) { IBMi.GlobalStorage.setServerSettingsCache(newName, cachedConnectionSettings); IBMi.GlobalStorage.deleteServerSettingsCache(server.name); } if (secret) { - await ConnectionManager.setStoredPassword(context, newName, secret); - await ConnectionManager.deleteStoredPassword(context, server.name); + await setStoredPassword(context, newName, secret); + await deleteStoredPassword(context, server.name); } connectionBrowser.refresh(); @@ -133,7 +134,7 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { }), vscode.commands.registerCommand(`code-for-ibmi.sortConnections`, async () => { - await ConnectionManager.sort(); + await IBMi.connectionManager.sort(); connectionBrowser.refresh(); }), @@ -155,18 +156,18 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { if (await vscode.window.showWarningMessage(message, { modal: true, detail }, vscode.l10n.t(`Yes`))) { for (const server of toBeDeleted) { // First remove the connection details - await ConnectionManager.deleteByName(server.name); + await IBMi.connectionManager.deleteByName(server.name); // Also remove the connection settings - const connectionSettings = GlobalVSCodeConfiguration.get(`connectionSettings`) || []; + const connectionSettings = IBMi.connectionManager.get(`connectionSettings`) || []; const newConnectionSettings = connectionSettings.filter(connection => connection.name !== server.name); - await GlobalVSCodeConfiguration.set(`connectionSettings`, newConnectionSettings); + await IBMi.connectionManager.set(`connectionSettings`, newConnectionSettings); // Also remove the cached connection settings IBMi.GlobalStorage.deleteServerSettingsCache(server.name); // Then remove the password - await ConnectionManager.deleteStoredPassword(context, server.name); + await deleteStoredPassword(context, server.name); } connectionBrowser.refresh(); @@ -174,9 +175,9 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { } }), vscode.commands.registerCommand(`code-for-ibmi.copyConnection`, async (server: Server) => { - const connectionSettings = GlobalVSCodeConfiguration.get(`connectionSettings`) || []; + const connectionSettings = IBMi.connectionManager.get(`connectionSettings`) || []; - const connection = ConnectionManager.getByName(server.name); + const connection = IBMi.connectionManager.getByName(server.name); const connectionSetting = connectionSettings.find(connection => server.name === connection.name); if (connection && connectionSetting) { @@ -187,7 +188,7 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { prompt: vscode.l10n.t(`Copy connection "{0}"`, server.name), placeHolder: vscode.l10n.t(`New connection name`), value: newConnectionName, - validateInput: value => ConnectionManager.getByName(value) ? + validateInput: async value => await IBMi.connectionManager.getByName(value) ? vscode.l10n.t(`Connection "{0}" already exists`, value) : undefined }); @@ -212,7 +213,7 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { if (newConnectionName && copyOperations) { const newConnection = Object.assign({}, connection.data); newConnection.name = newConnectionName; - await ConnectionManager.storeNew(newConnection); + await IBMi.connectionManager.storeNew(newConnection); const newConnectionSetting = Object.assign({}, connectionSetting); newConnectionSetting.name = newConnectionName; @@ -226,11 +227,11 @@ export function initializeConnectionBrowser(context: vscode.ExtensionContext) { newConnectionSetting.connectionProfiles = []; copyOperations.forEach(operation => operation(connectionSetting, newConnectionSetting)); connectionSettings.push(newConnectionSetting); - await GlobalVSCodeConfiguration.set(`connectionSettings`, connectionSettings); + await IBMi.connectionManager.set(`connectionSettings`, connectionSettings); - const password = await ConnectionManager.getStoredPassword(context, server.name); + const password = await getStoredPassword(context, server.name); if (password) { - await ConnectionManager.setStoredPassword(context, newConnectionName, password); + await setStoredPassword(context, newConnectionName, password); } connectionBrowser.refresh(); @@ -259,7 +260,7 @@ class ConnectionBrowser implements vscode.TreeDataProvider { async getChildren(): Promise { const lastConnection = IBMi.GlobalStorage.getLastConnections()?.[0]; - return ConnectionManager.getAll() + return IBMi.connectionManager.getAll() .map(connection => new ServerItem(connection, connection.name === lastConnection?.name)); } } @@ -267,7 +268,7 @@ class ConnectionBrowser implements vscode.TreeDataProvider { class ServerItem extends vscode.TreeItem implements Server { constructor(readonly connection: ConnectionData, lastConnected?: boolean) { super(connection.name, vscode.TreeItemCollapsibleState.None); - const readOnly = (GlobalVSCodeConfiguration.get(`connectionSettings`) || []) + const readOnly = (IBMi.connectionManager.get(`connectionSettings`) || []) .find(settings => connection.name === settings.name) ?.readOnlyMode diff --git a/src/views/LibraryListView.ts b/src/views/LibraryListView.ts index 0367fd4bd..f44c406bb 100644 --- a/src/views/LibraryListView.ts +++ b/src/views/LibraryListView.ts @@ -1,8 +1,9 @@ import vscode, { commands, l10n } from "vscode"; -import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../config/Configuration"; import { instance } from "../instantiate"; import { IBMiObject, WithLibrary } from "../typings"; import { objectToToolTip } from "./tools"; +import { ConnectionConfig } from "../api/configuration/ConnectionManager"; +import IBMi from "../api/IBMi"; export class LibraryListProvider implements vscode.TreeDataProvider { private readonly _emitter: vscode.EventEmitter = new vscode.EventEmitter(); @@ -256,9 +257,9 @@ export class LibraryListProvider implements vscode.TreeDataProvider lib !== library); previousCurLibs.splice(0, 0, currentLibrary); await storage.setPreviousCurLibs(previousCurLibs); - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); return true; } else { vscode.window.showErrorMessage(l10n.t(`Failed to set {0} as current library: {1}`, library, commandResult.stderr)); diff --git a/src/views/ProfilesView.ts b/src/views/ProfilesView.ts index 68c8e8173..2c90559d9 100644 --- a/src/views/ProfilesView.ts +++ b/src/views/ProfilesView.ts @@ -1,10 +1,11 @@ import vscode, { l10n, window } from 'vscode'; -import { ConnectionConfiguration } from '../config/Configuration'; import { GetNewLibl } from '../api/components/getNewLibl'; import { instance } from '../instantiate'; import { Profile } from '../typings'; -import { CommandProfile } from '../webviews/commandProfile'; +import { CommandProfileUi } from '../webviews/commandProfile'; +import IBMi from '../api/IBMi'; +import { ConnectionProfile } from '../api/configuration/ConnectionManager'; export class ProfilesView { private _onDidChangeTreeData = new vscode.EventEmitter(); @@ -43,7 +44,7 @@ export class ProfilesView { } await Promise.all([ - ConnectionConfiguration.update(config), + IBMi.connectionManager.update(config), storage.setLastProfile(savedProfileName) ]); this.refresh(); @@ -63,7 +64,7 @@ export class ProfilesView { if (result === l10n.t(`Yes`)) { currentProfiles.splice(currentProfiles.findIndex(profile => profile === chosenProfile), 1); config.connectionProfiles = currentProfiles; - await ConnectionConfiguration.update(config) + await IBMi.connectionManager.update(config) this.refresh(); // TODO: Add message about deleted profile! } @@ -79,7 +80,7 @@ export class ProfilesView { const chosenProfile = await getOrPickAvailableProfile(config.connectionProfiles, profileNode); if (chosenProfile) { assignProfile(chosenProfile, config); - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); await Promise.all([ vscode.commands.executeCommand(`code-for-ibmi.refreshLibraryListView`), @@ -95,7 +96,7 @@ export class ProfilesView { }), vscode.commands.registerCommand(`code-for-ibmi.manageCommandProfile`, async (commandProfile?: CommandProfileItem) => { - CommandProfile.show(commandProfile ? commandProfile.profile : undefined); + CommandProfileUi.show(commandProfile ? commandProfile.profile : undefined); }), vscode.commands.registerCommand(`code-for-ibmi.deleteCommandProfile`, async (commandProfile?: CommandProfileItem) => { @@ -104,7 +105,7 @@ export class ProfilesView { const storedProfile = config.commandProfiles.findIndex(profile => profile.name === commandProfile.profile); if (storedProfile !== undefined) { config.commandProfiles.splice(storedProfile, 1); - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); // TODO: Add message about deleting! this.refresh(); } @@ -126,7 +127,7 @@ export class ProfilesView { if (newSettings) { config.libraryList = newSettings.libraryList; config.currentLibrary = newSettings.currentLibrary; - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); await Promise.all([ storage.setLastProfile(storedProfile.name), @@ -169,7 +170,7 @@ export class ProfilesView { objectFilters: config.objectFilters, }, config); - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); await Promise.all([ vscode.commands.executeCommand(`code-for-ibmi.refreshLibraryListView`), @@ -221,7 +222,7 @@ export class ProfilesView { } } -async function getOrPickAvailableProfile(availableProfiles: ConnectionConfiguration.ConnectionProfile[], profileNode?: Profile): Promise { +async function getOrPickAvailableProfile(availableProfiles: ConnectionProfile[], profileNode?: Profile): Promise { if (availableProfiles.length > 0) { if (profileNode) { return availableProfiles.find(profile => profile.name === profileNode.profile); @@ -241,7 +242,7 @@ async function getOrPickAvailableProfile(availableProfiles: ConnectionConfigurat } } -function assignProfile(fromProfile: ConnectionConfiguration.ConnectionProfile, toProfile: ConnectionConfiguration.ConnectionProfile) { +function assignProfile(fromProfile: ConnectionProfile, toProfile: ConnectionProfile) { toProfile.homeDirectory = fromProfile.homeDirectory; toProfile.currentLibrary = fromProfile.currentLibrary; toProfile.libraryList = fromProfile.libraryList; @@ -250,7 +251,7 @@ function assignProfile(fromProfile: ConnectionConfiguration.ConnectionProfile, t toProfile.customVariables = fromProfile.customVariables; } -function cloneProfile(fromProfile: ConnectionConfiguration.ConnectionProfile, newName: string): ConnectionConfiguration.ConnectionProfile { +function cloneProfile(fromProfile: ConnectionProfile, newName: string): ConnectionProfile { return { name: newName, homeDirectory: fromProfile.homeDirectory, diff --git a/src/views/Terminal.ts b/src/views/Terminal.ts index 60f52feee..6f1f235b2 100644 --- a/src/views/Terminal.ts +++ b/src/views/Terminal.ts @@ -2,7 +2,6 @@ import path from 'path'; import vscode, { commands } from 'vscode'; import { instance } from '../instantiate'; -import { GlobalVSCodeConfiguration } from '../config/Configuration'; import IBMi from '../api/IBMi'; import { Tools } from '../api/Tools'; @@ -84,7 +83,7 @@ export namespace Terminal { if (type) { const terminalSettings: TerminalSettings = { type, - location: GlobalVSCodeConfiguration.get(`terminals.${type.toLowerCase()}.openInEditorArea`) ? vscode.TerminalLocation.Editor : vscode.TerminalLocation.Panel, + location: IBMi.connectionManager.get(`terminals.${type.toLowerCase()}.openInEditorArea`) ? vscode.TerminalLocation.Editor : vscode.TerminalLocation.Panel, connectionString: configuration.connectringStringFor5250, currentDirectory: options?.currentDirectory }; diff --git a/src/views/actions.ts b/src/views/actions.ts index 7cec34076..27399e7f5 100644 --- a/src/views/actions.ts +++ b/src/views/actions.ts @@ -8,12 +8,12 @@ import { getGitBranch } from '../filesystems/local/git'; import Instance from '../Instance'; import { parseFSOptions } from '../filesystems/qsys/QSysFs'; import { Action, BrowserItem, DeploymentMethod, Variable } from '../typings'; -import { GlobalVSCodeConfiguration } from '../config/Configuration'; import vscode, { CustomExecution, Pseudoterminal, TaskGroup, TaskRevealKind, WorkspaceFolder, commands, tasks } from 'vscode'; import { CustomUI } from '../webviews/CustomUI'; import { Tools } from '../api/Tools'; import { CompileTools } from '../api/CompileTools'; +import IBMi from '../api/IBMi'; interface CommandObject { object: string @@ -50,7 +50,7 @@ export async function runAction(instance: Instance, uri: vscode.Uri, customActio let availableActions: { label: string; action: Action; }[] = []; if (!customAction) { // First we grab a copy the predefined Actions in the VS Code settings - const allActions = [...GlobalVSCodeConfiguration.get(`actions`) || []]; + const allActions = [...IBMi.connectionManager.get(`actions`) || []]; // Then, if we're being called from a local file // we fetch the Actions defined from the workspace. @@ -250,7 +250,7 @@ export async function runAction(instance: Instance, uri: vscode.Uri, customActio break; } - const viewControl = GlobalVSCodeConfiguration.get(`postActionView`) || "none"; + const viewControl = IBMi.connectionManager.get(`postActionView`) || "none"; const outputBuffer: string[] = []; let actionName = chosenAction.name; let hasRun = false; @@ -280,7 +280,7 @@ export async function runAction(instance: Instance, uri: vscode.Uri, customActio source: 'IBM i', presentationOptions: { showReuseMessage: true, - clear: GlobalVSCodeConfiguration.get(`clearOutputEveryTime`), + clear: IBMi.connectionManager.get(`clearOutputEveryTime`), focus: false, reveal: (viewControl === `task` ? TaskRevealKind.Always : TaskRevealKind.Never), }, diff --git a/src/views/diagnostics.ts b/src/views/diagnostics.ts index 595da18cc..26eb5f388 100644 --- a/src/views/diagnostics.ts +++ b/src/views/diagnostics.ts @@ -1,11 +1,11 @@ import * as vscode from "vscode"; import { FileError } from "../typings"; -import { GlobalVSCodeConfiguration } from "../config/Configuration"; import Instance from "../Instance"; import { getEvfeventFiles } from "../filesystems/local/actions"; import { parseErrors } from "../api/errors/parser"; import { findExistingDocumentByName, findExistingDocumentUri } from "./tools"; +import IBMi from "../api/IBMi"; const ileDiagnostics = vscode.languages.createDiagnosticCollection(`ILE`); @@ -26,7 +26,7 @@ export function registerDiagnostics(): vscode.Disposable[] { }), ]; - if (GlobalVSCodeConfiguration.get(`clearDiagnosticOnEdit`)) { + if (IBMi.connectionManager.get(`clearDiagnosticOnEdit`)) { disposables.push( vscode.workspace.onDidChangeTextDocument(e => { if (ileDiagnostics.has(e.document.uri)) { @@ -64,7 +64,7 @@ export async function refreshDiagnosticsFromServer(instance: Instance, evfeventI const tableData = await content.getTable(evfeventInfo.library, `EVFEVENT`, evfeventInfo.object); const lines = tableData.map(row => String(row.EVFEVENT)); - if (GlobalVSCodeConfiguration.get(`clearErrorsBeforeBuild`)) { + if (IBMi.connectionManager.get(`clearErrorsBeforeBuild`)) { // Clear all errors if the user has this setting enabled clearDiagnostics(); } @@ -81,7 +81,7 @@ export async function refreshDiagnosticsFromLocal(instance: Instance, evfeventIn if (evfeventFiles) { const filesContent = await Promise.all(evfeventFiles.map(uri => vscode.workspace.fs.readFile(uri))); - if (GlobalVSCodeConfiguration.get(`clearErrorsBeforeBuild`)) { + if (IBMi.connectionManager.get(`clearErrorsBeforeBuild`)) { // Clear all errors if the user has this setting enabled clearDiagnostics(); } diff --git a/src/views/ifsBrowser.ts b/src/views/ifsBrowser.ts index 1ef3d2f44..f4a6b9fd8 100644 --- a/src/views/ifsBrowser.ts +++ b/src/views/ifsBrowser.ts @@ -3,7 +3,6 @@ import path, { dirname, extname } from "path"; import vscode, { FileType, l10n, window } from "vscode"; import { existsSync, mkdirSync, rmdirSync } from "fs"; -import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../config/Configuration"; import { SortOptions } from "../api/IBMiContent"; import { Search } from "../api/Search"; import { Tools } from "../api/Tools"; @@ -18,7 +17,7 @@ const PROTECTED_DIRS = /^(\/|\/QOpenSys|\/QSYS\.LIB|\/QDLS|\/QOPT|\/QNTC|\/QFile const ALWAYS_SHOW_FILES = /^(\.gitignore|\.vscode|\.deployignore)$/i; type DragNDropAction = "move" | "copy"; type DragNDropBehavior = DragNDropAction | "ask"; -const getDragDropBehavior = () => GlobalVSCodeConfiguration.get(`IfsBrowser.DragAndDropDefaultBehavior`) || "ask"; +const getDragDropBehavior = () => IBMi.connectionManager.get(`IfsBrowser.DragAndDropDefaultBehavior`) || "ask"; function isProtected(path: string) { return PROTECTED_DIRS.test(path) || instance.getContent()?.isProtectedPath(path); @@ -81,8 +80,8 @@ class IFSBrowser implements vscode.TreeDataProvider { } shortcuts.splice(newPosition, 0, moveDir); config.ifsShortcuts = shortcuts; - await ConnectionConfiguration.update(config); - if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { + await IBMi.connectionManager.update(config); + if (IBMi.connectionManager.get(`autoRefresh`)) { this.refresh(); } } @@ -334,7 +333,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { try { if (newDirectory && newDirectory !== homeDirectory) { config.homeDirectory = newDirectory; - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); vscode.window.showInformationMessage(l10n.t(`Working directory changed to {0}.`, newDirectory)); } } catch (e) { @@ -360,11 +359,11 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { } else if (!shortcuts.includes(newDirectory)) { shortcuts.push(newDirectory); config.ifsShortcuts = shortcuts; - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); if (config.autoSortIFSShortcuts) { vscode.commands.executeCommand(`code-for-ibmi.sortIFSShortcuts`); } - if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { + if (IBMi.connectionManager.get(`autoRefresh`)) { ifsBrowser.refresh(); } } @@ -389,8 +388,8 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { if (inx >= 0) { shortcuts.splice(inx, 1); config.ifsShortcuts = shortcuts; - await ConnectionConfiguration.update(config); - if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { + await IBMi.connectionManager.update(config); + if (IBMi.connectionManager.get(`autoRefresh`)) { ifsBrowser.refresh(); } } @@ -407,8 +406,8 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { if (config) { try { config.ifsShortcuts.sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase())); - await ConnectionConfiguration.update(config); - if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { + await IBMi.connectionManager.update(config); + if (IBMi.connectionManager.get(`autoRefresh`)) { ifsBrowser.refresh(); } } catch (e) { @@ -438,7 +437,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { try { await connection.sendCommand({ command: `mkdir ${Tools.escapePath(fullName)}` }); - if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { + if (IBMi.connectionManager.get(`autoRefresh`)) { ifsBrowser.refresh(node); } @@ -466,7 +465,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { vscode.window.showInformationMessage(l10n.t(`Creating streamfile {0}.`, fullName)); await content.createStreamFile(fullName); vscode.commands.executeCommand(`code-for-ibmi.openEditable`, fullName); - if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { + if (IBMi.connectionManager.get(`autoRefresh`)) { ifsBrowser.refresh(node); } else { @@ -524,7 +523,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { } } - if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { + if (IBMi.connectionManager.get(`autoRefresh`)) { ifsBrowser.refresh(node); } vscode.window.showInformationMessage(l10n.t(`Upload completed.`)); @@ -558,7 +557,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { if (await vscode.window.showWarningMessage(message, { modal: true, detail }, l10n.t(`Yes`))) { const toBeDeleted: string[] = []; for (const item of items) { - if ((GlobalVSCodeConfiguration.get(`safeDeleteMode`)) && item.file.type === `directory`) { //Check if path is directory + if ((IBMi.connectionManager.get(`safeDeleteMode`)) && item.file.type === `directory`) { //Check if path is directory const dirName = path.basename(item.path) //Get the name of the directory to be deleted const deletionPrompt = l10n.t(`Once you delete the directory, it cannot be restored. @@ -591,7 +590,7 @@ Please type "{0}" to confirm deletion.`, dirName); if (removeResult.code !== 0) { throw removeResult.stderr; } - if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { + if (IBMi.connectionManager.get(`autoRefresh`)) { items.map(item => item.parent) .filter(Tools.distinct) .forEach(async parent => parent?.refresh?.()); @@ -653,7 +652,7 @@ Please type "{0}" to confirm deletion.`, dirName); throw moveResult.stderr; } - if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { + if (IBMi.connectionManager.get(`autoRefresh`)) { ifsBrowser.refresh(); } let label; @@ -699,7 +698,7 @@ Please type "{0}" to confirm deletion.`, dirName); const targetPath = target.startsWith(`/`) ? target : homeDirectory + `/` + target; try { await connection.sendCommand({ command: `cp -r ${Tools.escapePath(node.path)} ${Tools.escapePath(targetPath)}` }); - if (GlobalVSCodeConfiguration.get(`autoRefresh`)) { + if (IBMi.connectionManager.get(`autoRefresh`)) { ifsBrowser.refresh(); } vscode.window.showInformationMessage(l10n.t(`{0} was copied to {1}.`, Tools.escapePath(node.path), Tools.escapePath(targetPath))); @@ -917,7 +916,7 @@ vscode.commands.registerCommand(`code-for-ibmi.ifs.toggleShowHiddenFiles`, async const config = instance.getConfig(); if (config) { config.showHiddenFiles = !config.showHiddenFiles; - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); vscode.commands.executeCommand("code-for-ibmi.refreshIFSBrowser"); } }); diff --git a/src/views/objectBrowser.ts b/src/views/objectBrowser.ts index 583536cd6..e6356b270 100644 --- a/src/views/objectBrowser.ts +++ b/src/views/objectBrowser.ts @@ -2,7 +2,7 @@ import fs, { existsSync } from "fs"; import os from "os"; import path, { basename, dirname } from "path"; import vscode from "vscode"; -import { ConnectionConfiguration, DefaultOpenMode, GlobalVSCodeConfiguration } from "../config/Configuration"; +import { DefaultOpenMode } from "../config/Configuration"; import { parseFilter, singleGenericName } from "../api/Filter"; import IBMi, { MemberParts } from "../api/IBMi"; import { SortOptions, SortOrder } from "../api/IBMiContent"; @@ -13,11 +13,12 @@ import { instance } from "../instantiate"; import { BrowserItem, BrowserItemParameters, CommandResult, FilteredItem, FocusOptions, IBMiMember, IBMiObject, MemberItem, OBJECT_BROWSER_MIMETYPE, ObjectItem, WithLibrary } from "../typings"; import { editFilter } from "../webviews/filters"; import { findUriTabs, memberToToolTip, objectToToolTip, sourcePhysicalFileToToolTip } from "./tools"; +import { ObjectFilters } from "../api/configuration/ConnectionManager"; const URI_LIST_SEPARATOR = "\r\n"; -const objectNamesLower = () => GlobalVSCodeConfiguration.get(`ObjectBrowser.showNamesInLowercase`); -const objectSortOrder = () => GlobalVSCodeConfiguration.get(`ObjectBrowser.sortObjectsByName`) ? `name` : `type`; +const objectNamesLower = () => IBMi.connectionManager.get(`ObjectBrowser.showNamesInLowercase`); +const objectSortOrder = () => IBMi.connectionManager.get(`ObjectBrowser.sortObjectsByName`) ? `name` : `type`; const correctCase = (value: string) => { ; @@ -48,7 +49,7 @@ const objectIcons = { } abstract class ObjectBrowserItem extends BrowserItem { - constructor(readonly filter: ConnectionConfiguration.ObjectFilters, label: string, params?: BrowserItemParameters) { + constructor(readonly filter: ObjectFilters, label: string, params?: BrowserItemParameters) { super(label, params); } @@ -100,7 +101,7 @@ class ObjectBrowser implements vscode.TreeDataProvider { objectFilters.splice(from, 1); objectFilters.splice(to, 0, filter); config.objectFilters = objectFilters; - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); this.autoRefresh(); } } @@ -110,7 +111,7 @@ class ObjectBrowser implements vscode.TreeDataProvider { } autoRefresh(message?: string) { - const autoRefresh = GlobalVSCodeConfiguration.get(`autoRefresh`); + const autoRefresh = IBMi.connectionManager.get(`autoRefresh`); if (autoRefresh) { if (message) { vscode.window.showInformationMessage(message); @@ -169,7 +170,7 @@ class CreateFilterItem extends BrowserItem { class ObjectBrowserFilterItem extends ObjectBrowserItem implements WithLibrary { readonly library: string; - constructor(filter: ConnectionConfiguration.ObjectFilters) { + constructor(filter: ObjectFilters) { super(filter, filter.name, { icon: filter.protected ? `lock-small` : '', state: vscode.TreeItemCollapsibleState.Collapsed }); this.library = parseFilter(filter.library, filter.filterType).noFilter ? filter.library : ''; this.contextValue = `filter${this.library ? "_library" : ''}${this.isProtected() ? `_readonly` : ``}`; @@ -205,7 +206,7 @@ class ObjectBrowserFilterItem extends ObjectBrowserItem implements WithLibrary { if (index > -1) { config.objectFilters.splice(index, 1); - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); } @@ -483,7 +484,7 @@ export function initializeObjectBrowser(context: vscode.ExtensionContext) { member: `*`, memberType: `*`, protected: false - } as ConnectionConfiguration.ObjectFilters; + } as ObjectFilters; objectFilters.push(filter); } else { regex = FILTER_REGEX.exec(connection.upperCaseName(newFilter)); @@ -498,13 +499,13 @@ export function initializeObjectBrowser(context: vscode.ExtensionContext) { member: parsedFilter.mbr || `*`, memberType: parsedFilter.mbrType || `*`, protected: false - } as ConnectionConfiguration.ObjectFilters; + } as ObjectFilters; objectFilters.push(filter); } } config.objectFilters = objectFilters; - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); objectBrowser.refresh(); } }), @@ -527,7 +528,7 @@ export function initializeObjectBrowser(context: vscode.ExtensionContext) { vscode.commands.registerCommand(`code-for-ibmi.sortFilters`, async () => { const config = getConfig(); config.objectFilters.sort((filter1, filter2) => filter1.name.toLowerCase().localeCompare(filter2.name.toLowerCase())); - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); objectBrowser.autoRefresh(); }), @@ -566,7 +567,7 @@ export function initializeObjectBrowser(context: vscode.ExtensionContext) { }) if (addResult.code === 0) { - if (GlobalVSCodeConfiguration.get(`autoOpenFile`)) { + if (IBMi.connectionManager.get(`autoOpenFile`)) { vscode.commands.executeCommand(`code-for-ibmi.openEditable`, fullPath); } @@ -643,7 +644,7 @@ export function initializeObjectBrowser(context: vscode.ExtensionContext) { }); } - if (GlobalVSCodeConfiguration.get(`autoOpenFile`)) { + if (IBMi.connectionManager.get(`autoOpenFile`)) { vscode.commands.executeCommand(`code-for-ibmi.openEditable`, fullPath); } @@ -1046,7 +1047,7 @@ Do you want to replace it?`, item.name), skipAllLabel, overwriteLabel, overwrite }); config.objectFilters = filters; - ConnectionConfiguration.update(config); + IBMi.connectionManager.update(config); const autoRefresh = objectBrowser.autoRefresh(); // Add to library list ? @@ -1347,7 +1348,7 @@ function storeMemberList(path: string, list: string[]) { } } -async function doSearchInSourceFile(searchTerm: string, path: string, filter?: ConnectionConfiguration.ObjectFilters) { +async function doSearchInSourceFile(searchTerm: string, path: string, filter?: ObjectFilters) { const content = getContent(); const [library, sourceFile] = path.split(`/`); try { @@ -1394,7 +1395,7 @@ async function doSearchInSourceFile(searchTerm: string, path: string, filter?: C const results = await Search.searchMembers(instance.getConnection()!, library, sourceFile, searchTerm, memberFilter, filter?.protected); clearInterval(messageTimeout) if (results.hits.length) { - const objectNamesLower = GlobalVSCodeConfiguration.get(`ObjectBrowser.showNamesInLowercase`); + const objectNamesLower = IBMi.connectionManager.get(`ObjectBrowser.showNamesInLowercase`); // Format result to be lowercase if the setting is enabled results.hits.forEach(result => { @@ -1419,7 +1420,7 @@ async function doSearchInSourceFile(searchTerm: string, path: string, filter?: C } } -async function listObjects(item: ObjectBrowserFilterItem, filter?: ConnectionConfiguration.ObjectFilters) { +async function listObjects(item: ObjectBrowserFilterItem, filter?: ObjectFilters) { return (await getContent().getObjectList(filter || item.filter, objectSortOrder())) .map(object => { return object.sourceFile ? new ObjectBrowserSourcePhysicalFileItem(item, object) : new ObjectBrowserObjectItem(item, object); diff --git a/src/webviews/actions/index.ts b/src/webviews/actions/index.ts index dcddf6988..0729b31f7 100644 --- a/src/webviews/actions/index.ts +++ b/src/webviews/actions/index.ts @@ -2,11 +2,11 @@ import vscode from "vscode"; import { CustomUI, Tab } from "../CustomUI"; -import { GlobalVSCodeConfiguration } from "../../config/Configuration"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; import { Action, ActionEnvironment, ActionRefresh, ActionType } from "../../typings"; import { getVariablesInfo } from "./varinfo"; +import IBMi from "../../api/IBMi"; type MainMenuPage = { buttons?: 'newAction' | 'duplicateAction' @@ -301,12 +301,12 @@ export namespace ActionsUI { } } -async function saveActions(actions: Action[]) { - return GlobalVSCodeConfiguration.set(`actions`, actions); +function saveActions(actions: Action[]) { + return IBMi.connectionManager.set(`actions`, actions); } function loadActions(): Action[] { - return GlobalVSCodeConfiguration.get(`actions`) || []; + return IBMi.connectionManager.get(`actions`) || []; } function getDefaultTabIndex(type?: ActionType) { diff --git a/src/webviews/commandProfile/index.ts b/src/webviews/commandProfile/index.ts index c1b873203..85ca589c2 100644 --- a/src/webviews/commandProfile/index.ts +++ b/src/webviews/commandProfile/index.ts @@ -1,14 +1,16 @@ import { commands, window } from "vscode"; -import { ConnectionConfiguration, GlobalVSCodeConfiguration } from "../../config/Configuration"; + import { CustomUI } from "../CustomUI"; import { instance } from "../../instantiate"; +import IBMi from "../../api/IBMi"; +import { CommandProfile } from "../../api/configuration/ConnectionManager"; -export class CommandProfile { +export class CommandProfileUi { static async show(currentName?: string) { let config = instance.getConfig(); const connection = instance.getConnection(); - let currentSettings: ConnectionConfiguration.CommandProfile = { + let currentSettings: CommandProfile = { name: ``, command: `` }; @@ -45,7 +47,7 @@ export class CommandProfile { config!.commandProfiles.push(page.data); } - await ConnectionConfiguration.update(config!); + await IBMi.connectionManager.update(config!); commands.executeCommand(`code-for-ibmi.refreshProfileView`); } else { diff --git a/src/webviews/filters/index.ts b/src/webviews/filters/index.ts index 2e79dea7e..95cac6540 100644 --- a/src/webviews/filters/index.ts +++ b/src/webviews/filters/index.ts @@ -1,9 +1,10 @@ -import { ConnectionConfiguration } from "../../config/Configuration"; import { CustomUI } from "../CustomUI"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; +import { ObjectFilters } from "../../api/configuration/ConnectionManager"; +import IBMi from "../../api/IBMi"; -export async function editFilter(filter?: ConnectionConfiguration.ObjectFilters, copy = false) { +export async function editFilter(filter?: ObjectFilters, copy = false) { const connection = instance.getConnection(); const config = instance.getConfig(); if (config) { @@ -103,7 +104,7 @@ export async function editFilter(filter?: ConnectionConfiguration.ObjectFilters, objectFilters[filterIndex] = Object.assign(filter, data); } - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); } } } \ No newline at end of file diff --git a/src/webviews/login/index.ts b/src/webviews/login/index.ts index 90073447f..3e39b721b 100644 --- a/src/webviews/login/index.ts +++ b/src/webviews/login/index.ts @@ -1,9 +1,10 @@ import vscode, { l10n, ThemeIcon } from "vscode"; -import { ConnectionConfiguration, ConnectionManager } from "../../config/Configuration"; import { CustomUI, Section } from "../CustomUI"; import { Tools } from "../../api/Tools"; import { instance, safeDisconnect } from "../../instantiate"; import { ConnectionData } from '../../typings'; +import IBMi from "../../api/IBMi"; +import { deleteStoredPassword, getStoredPassword, setStoredPassword } from "../../config/passwords"; type NewLoginSettings = ConnectionData & { savePassword: boolean @@ -60,7 +61,7 @@ export class Login { data.readyTimeout = Number(data.readyTimeout); data.privateKeyPath = data.privateKeyPath?.trim() ? Tools.normalizePath(data.privateKeyPath) : undefined; if (data.name) { - const existingConnection = ConnectionManager.getByName(data.name); + const existingConnection = await IBMi.connectionManager.getByName(data.name); if (existingConnection) { vscode.window.showErrorMessage(`Connection with name ${data.name} already exists.`); @@ -75,15 +76,15 @@ export class Login { }; if (data.savePassword && data.password) { - await ConnectionManager.setStoredPassword(context, data.name, data.password); + await setStoredPassword(context, data.name, data.password); } - await ConnectionManager.storeNew(newConnection); + await IBMi.connectionManager.storeNew(newConnection); - const config = await ConnectionConfiguration.load(data.name) + const config = await IBMi.connectionManager.load(data.name) config.tempLibrary = data.tempLibrary; config.tempDir = data.tempDir; - ConnectionConfiguration.update(config); + IBMi.connectionManager.update(config); vscode.commands.executeCommand(`code-for-ibmi.refreshConnections`); switch (data.buttons) { @@ -94,7 +95,7 @@ export class Login { vscode.window.showInformationMessage(`Connecting to ${data.host}.`); const toDoOnConnected: Function[] = []; if (!data.password && !data.privateKeyPath && await promptPassword(context, data)) { - toDoOnConnected.push(() => ConnectionManager.setStoredPassword(context, data.name, data.password!)); + toDoOnConnected.push(() => setStoredPassword(context, data.name, data.password!)); } if (data.password || data.privateKeyPath) { @@ -153,19 +154,19 @@ export class Login { } } - const connection = ConnectionManager.getByName(name); + const connection = await IBMi.connectionManager.getByName(name); if (connection) { const toDoOnConnected: Function[] = []; const connectionConfig = connection.data; if (connectionConfig.privateKeyPath) { // If connecting with a private key, remove the password - await ConnectionManager.deleteStoredPassword(context, connectionConfig.name); + await deleteStoredPassword(context, connectionConfig.name); } else { // Assume connection with a password, but prompt if we don't have one - connectionConfig.password = await ConnectionManager.getStoredPassword(context, connectionConfig.name); + connectionConfig.password = await getStoredPassword(context, connectionConfig.name); if (!connectionConfig.password) { if (await promptPassword(context, connectionConfig)) { - toDoOnConnected.push(() => ConnectionManager.setStoredPassword(context, connectionConfig.name, connectionConfig.password!)); + toDoOnConnected.push(() => setStoredPassword(context, connectionConfig.name, connectionConfig.password!)); } } diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index fe383142a..6ece37d77 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -1,6 +1,5 @@ import { existsSync } from "fs"; import vscode from "vscode"; -import { ConnectionConfiguration, ConnectionManager, GlobalVSCodeConfiguration } from "../../config/Configuration"; import { ComplexTab, CustomUI, Section } from "../CustomUI"; import { Tools } from "../../api/Tools"; import { isManaged } from "../../debug"; @@ -11,6 +10,8 @@ import { instance } from "../../instantiate"; import { ConnectionData, Server } from '../../typings'; import { withContext } from "../../views/tools"; import IBMi from "../../api/IBMi"; +import { ConnectionConfig, ConnectionManager } from "../../api/configuration/ConnectionManager"; +import { deleteStoredPassword, getStoredPassword, setStoredPassword } from "../../config/passwords"; const EDITING_CONTEXT = `code-for-ibmi:editingConnection`; @@ -36,20 +37,20 @@ export class SettingsUI { context.subscriptions.push( vscode.commands.registerCommand(`code-for-ibmi.showAdditionalSettings`, async (server?: Server, tab?: string) => { - const connectionSettings = GlobalVSCodeConfiguration.get(`connectionSettings`); + const connectionSettings = await IBMi.connectionManager.getAll(); const connection = instance.getConnection(); const passwordAuthorisedExtensions = instance.getStorage()?.getAuthorisedExtensions() || []; - let config: ConnectionConfiguration.Parameters; + let config: ConnectionConfig; if (connectionSettings && server) { - config = await ConnectionConfiguration.load(server.name); + config = await IBMi.connectionManager.load(server.name); } else { config = instance.getConfig()!; if (connection && config) { // Reload config to initialize any new config parameters. - config = await ConnectionConfiguration.load(config.name); + config = await IBMi.connectionManager.load(config.name); } else { vscode.window.showErrorMessage(`No connection is active.`); return; @@ -353,9 +354,9 @@ export class SettingsUI { if (server) { const name = server.name; - const connection = ConnectionManager.getByName(name); + const connection = await IBMi.connectionManager.getByName(name); if (connection) { - const storedPassword = await ConnectionManager.getStoredPassword(context, name); + const storedPassword = await getStoredPassword(context, name); let { data: stored, index } = connection; const privateKeyPath = stored.privateKeyPath ? Tools.resolvePath(stored.privateKeyPath) : undefined; const privateKeyWarning = !privateKeyPath || existsSync(privateKeyPath) ? "" : "⚠️ This private key doesn't exist on this system! ⚠️

"; @@ -384,7 +385,7 @@ export class SettingsUI { switch (chosenButton) { case `removeAuth`: - await ConnectionManager.deleteStoredPassword(context, name); + await deleteStoredPassword(context, name); data.privateKeyPath = undefined; vscode.window.showInformationMessage(vscode.l10n.t(`Authentication methods removed for "{0}".`, name)); break; @@ -395,7 +396,7 @@ export class SettingsUI { if (data.password !== storedPassword) { // New password was entered, so store the password // and remove the private key path from the data - await ConnectionManager.setStoredPassword(context, name, data.password); + await setStoredPassword(context, name, data.password); vscode.window.showInformationMessage(vscode.l10n.t(`Password updated and will be used for "{0}".`, name)); } } else if (data.privateKeyPath?.trim()) { @@ -403,7 +404,7 @@ export class SettingsUI { // then remove the password from the data and // use the keypath instead data.privateKeyPath = Tools.normalizePath(data.privateKeyPath); - await ConnectionManager.deleteStoredPassword(context, name); + await deleteStoredPassword(context, name); vscode.window.showInformationMessage(vscode.l10n.t(`Private key updated and will be used for "{0}".`, name)); } else { @@ -419,7 +420,7 @@ export class SettingsUI { delete data.buttons; stored = Object.assign(stored, data); - await ConnectionManager.updateByIndex(index, stored); + await IBMi.connectionManager.updateByIndex(index, stored); IBMi.GlobalStorage.deleteServerSettingsCache(server.name); vscode.commands.executeCommand(`code-for-ibmi.refreshConnections`); } diff --git a/src/webviews/variables/index.ts b/src/webviews/variables/index.ts index 7f5db47a5..b49bed67a 100644 --- a/src/webviews/variables/index.ts +++ b/src/webviews/variables/index.ts @@ -1,7 +1,7 @@ import vscode from "vscode"; -import { ConnectionConfiguration } from "../../config/Configuration"; import { CustomUI } from "../CustomUI"; import { instance } from "../../instantiate"; +import IBMi from "../../api/IBMi"; export class VariablesUI { @@ -85,7 +85,7 @@ export class VariablesUI { if (id >= 0) { allVariables.splice(id, 1); config.customVariables = allVariables; - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); } break; @@ -104,7 +104,7 @@ export class VariablesUI { } config.customVariables = allVariables; - await ConnectionConfiguration.update(config); + await IBMi.connectionManager.update(config); break; } From 2eb088f41bc44269d08db8d3423d8dc79ff404f0 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 17:03:37 -0500 Subject: [PATCH 19/46] Move debug configuration to API Signed-off-by: worksofliam --- src/api/IBMi.ts | 9 ++-- .../configuration/DebugConfiguration.ts} | 42 ++++++++----------- src/debug/certificates.ts | 17 ++++---- src/debug/index.ts | 2 +- src/debug/server.ts | 4 +- src/instantiate.ts | 2 +- src/testing/debug.ts | 2 +- src/views/debugView.ts | 4 +- src/views/helpView.ts | 2 +- 9 files changed, 41 insertions(+), 43 deletions(-) rename src/{debug/config.ts => api/configuration/DebugConfiguration.ts} (82%) diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 81fa850cd..8000f2340 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -13,8 +13,7 @@ import IBMiContent from "./IBMiContent"; import { CachedServerSettings, CodeForIStorage } from './configuration/Storage'; import { Tools } from './Tools'; import * as configVars from './configVars'; -import { DebugConfiguration } from "../debug/config"; -import { debugPTFInstalled } from "../debug/server"; +import { DebugConfiguration } from "./configuration/DebugConfiguration"; import { ConnectionManager, ConnectionConfig } from './configuration/ConnectionManager'; export interface MemberParts extends IBMiMember { @@ -739,7 +738,7 @@ export default class IBMi { let debugConfigLoaded = false if ((!quickConnect || !cachedServerSettings?.debugConfigLoaded)) { - if (debugPTFInstalled()) { + if (this.debugPTFInstalled()) { try { const debugServiceConfig = await new DebugConfiguration(this).load(); delete this.config.debugCertDirectory; @@ -1395,4 +1394,8 @@ export default class IBMi { sshdCcsid: this.sshdCcsid }; } + + debugPTFInstalled() { + return this.remoteFeatures[`startDebugService.sh`] !== undefined; + } } \ No newline at end of file diff --git a/src/debug/config.ts b/src/api/configuration/DebugConfiguration.ts similarity index 82% rename from src/debug/config.ts rename to src/api/configuration/DebugConfiguration.ts index de3b18659..107b5e3f3 100644 --- a/src/debug/config.ts +++ b/src/api/configuration/DebugConfiguration.ts @@ -1,8 +1,10 @@ import path from "path"; -import vscode from "vscode"; -import { instance } from "../instantiate"; -import IBMi from "../api/IBMi"; -import { SERVICE_CERTIFICATE } from "./certificates"; +import { instance } from "../../instantiate"; +import IBMi from "../IBMi"; + +export const SERVICE_CERTIFICATE = `debug_service.pfx`; +export const CLIENT_CERTIFICATE = `debug_service.crt`; +export const LEGACY_CERT_DIRECTORY = `/QIBM/ProdData/IBMiDebugService/bin/certs`; type ConfigLine = { key: string @@ -149,24 +151,18 @@ export async function getDebugServiceDetails(): Promise { const detailFilePath = path.posix.join((await new DebugConfiguration(connection).load()).getRemoteServiceRoot(), `package.json`); const detailExists = await content.testStreamFile(detailFilePath, "r"); if (detailExists) { - try { - const fileContents = (await content.downloadStreamfileRaw(detailFilePath)).toString("utf-8"); - const parsed = JSON.parse(fileContents); - details = { - ...parsed as DebugServiceDetails, - semanticVersion: () => { - const parts = (parsed.version ? String(parsed.version).split('.') : []).map(Number); - return { - major: parts[0], - minor: parts[1], - patch: parts[2] - }; - } + const fileContents = (await content.downloadStreamfileRaw(detailFilePath)).toString("utf-8"); + const parsed = JSON.parse(fileContents); + details = { + ...parsed as DebugServiceDetails, + semanticVersion: () => { + const parts = (parsed.version ? String(parsed.version).split('.') : []).map(Number); + return { + major: parts[0], + minor: parts[1], + patch: parts[2] + }; } - } catch (e: any) { - // Something very very bad has happened - vscode.window.showErrorMessage(vscode.l10n.t(`Failed to read debug service detail file {0}: {1}`, detailFilePath, e)); - console.log(e); } } else { @@ -191,9 +187,5 @@ export async function getDebugServiceDetails(): Promise { export function getJavaHome(connection: IBMi, version: string) { version = version.padEnd(2, '0'); const javaHome = connection.remoteFeatures[`jdk${version}`]; - if (!javaHome) { - throw new Error(vscode.l10n.t(`Java version {0} is not installed.`, version)); - } - return javaHome; } \ No newline at end of file diff --git a/src/debug/certificates.ts b/src/debug/certificates.ts index 69c9f76e8..cbf87215e 100644 --- a/src/debug/certificates.ts +++ b/src/debug/certificates.ts @@ -8,8 +8,8 @@ import { instance } from '../instantiate'; import IBMi from "../api/IBMi"; import IBMiContent from '../api/IBMiContent'; import { Tools } from '../api/Tools'; -import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, getJavaHome } from './config'; import { fileToPath } from '../views/tools'; +import { DebugConfiguration, SERVICE_CERTIFICATE, CLIENT_CERTIFICATE, getDebugServiceDetails, getJavaHome, DEBUG_CONFIG_FILE, LEGACY_CERT_DIRECTORY } from '../api/configuration/DebugConfiguration'; type HostInfo = { ip: string @@ -25,10 +25,6 @@ export type ImportedCertificate = { const ENCRYPTION_KEY = ".code4i.debug"; const IP_REGEX = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/gi; const dnsLookup = promisify(dns.lookup); -export const SERVICE_CERTIFICATE = `debug_service.pfx`; -export const CLIENT_CERTIFICATE = `debug_service.crt`; - -export const LEGACY_CERT_DIRECTORY = `/QIBM/ProdData/IBMiDebugService/bin/certs`; async function getHostInfo(connection: IBMi): Promise { const hostNames = [ @@ -170,7 +166,14 @@ export async function setup(connection: IBMi, imported?: ImportedCertificate) { debugConfig.delete("DEBUG_SERVICE_KEYSTORE_PASSWORD"); await debugConfig.save(); } - const javaHome = getJavaHome(connection, (await getDebugServiceDetails()).java); + + const javaVersion = (await getDebugServiceDetails()).java; + const javaHome = getJavaHome(connection, javaVersion); + + if (!javaHome) { + throw new Error(vscode.l10n.t(`Java version {0} is not installed.`, javaVersion)); + } + const encryptResult = await connection.sendCommand({ command: `${path.posix.join(debugConfig.getRemoteServiceBin(), `encryptKeystorePassword.sh`)} | /usr/bin/tail -n 1`, env: { @@ -265,7 +268,7 @@ export async function sanityCheck(connection: IBMi, content: IBMiContent) { //Check if java home needs to be updated if the service got updated (e.g: v1 uses Java 8 and v2 uses Java 11) const javaHome = debugConfig.get("JAVA_HOME"); const expectedJavaHome = getJavaHome(connection, (await getDebugServiceDetails()).java); - if (javaHome && javaHome !== expectedJavaHome) { + if (javaHome && expectedJavaHome && javaHome !== expectedJavaHome) { if (await content.testStreamFile(DEBUG_CONFIG_FILE, "w")) { //Automatically make the change if possible debugConfig.set("JAVA_HOME", expectedJavaHome); diff --git a/src/debug/index.ts b/src/debug/index.ts index 809e8fece..0d7e507fd 100644 --- a/src/debug/index.ts +++ b/src/debug/index.ts @@ -9,7 +9,7 @@ import { ObjectItem } from "../typings"; import { ILELibrarySettings } from "../api/CompileTools"; import { Env, getEnvConfig } from "../filesystems/local/env"; import * as certificates from "./certificates"; -import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, resetDebugServiceDetails } from "./config"; +import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, resetDebugServiceDetails } from "../api/configuration/DebugConfiguration"; import * as server from "./server"; import { withContext } from "../views/tools"; import { getStoredPassword } from "../config/passwords"; diff --git a/src/debug/server.ts b/src/debug/server.ts index 761631d7c..103c3b0be 100644 --- a/src/debug/server.ts +++ b/src/debug/server.ts @@ -4,7 +4,7 @@ import { instance } from "../instantiate"; import { CustomUI } from "../webviews/CustomUI"; import IBMi from "../api/IBMi"; import { Tools } from "../api/Tools"; -import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, ORIGINAL_DEBUG_CONFIG_FILE } from "./config"; +import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, ORIGINAL_DEBUG_CONFIG_FILE } from "../api/configuration/DebugConfiguration"; export type DebugJob = { name: string @@ -12,7 +12,7 @@ export type DebugJob = { } export function debugPTFInstalled() { - return instance.getConnection()?.remoteFeatures[`startDebugService.sh`] !== undefined; + return instance.getConnection()?.debugPTFInstalled() } export async function isSEPSupported() { diff --git a/src/instantiate.ts b/src/instantiate.ts index 3d1bf91b4..1b59a088e 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -3,7 +3,7 @@ import * as vscode from "vscode"; import { onCodeForIBMiConfigurationChange } from "./config/Configuration"; import Instance from "./Instance"; import { Terminal } from './views/Terminal'; -import { getDebugServiceDetails } from './debug/config'; +import { getDebugServiceDetails } from './api/configuration/DebugConfiguration'; import { debugPTFInstalled, isDebugEngineRunning } from './debug/server'; import { setupGitEventHandler } from './filesystems/local/git'; import { registerActionsCommands } from './commands/actions'; diff --git a/src/testing/debug.ts b/src/testing/debug.ts index 2e6249be1..c71074662 100644 --- a/src/testing/debug.ts +++ b/src/testing/debug.ts @@ -1,6 +1,6 @@ import assert from "assert"; import { TestSuite } from "."; -import { getJavaHome } from "../debug/config"; +import { getJavaHome } from "../api/configuration/DebugConfiguration"; import { instance } from "../instantiate"; export const DebugSuite: TestSuite = { diff --git a/src/views/debugView.ts b/src/views/debugView.ts index f4cd9e2f5..8af5f1336 100644 --- a/src/views/debugView.ts +++ b/src/views/debugView.ts @@ -1,7 +1,7 @@ import vscode from "vscode"; import { Tools } from "../api/Tools"; -import { checkClientCertificate, debugKeyFileExists, remoteCertificatesExists, SERVICE_CERTIFICATE } from "../debug/certificates"; -import { DebugConfiguration, getDebugServiceDetails } from "../debug/config"; +import { checkClientCertificate, debugKeyFileExists, remoteCertificatesExists } from "../debug/certificates"; +import { DebugConfiguration, getDebugServiceDetails, SERVICE_CERTIFICATE } from "../api/configuration/DebugConfiguration"; import { DebugJob, getDebugServerJob, getDebugServiceJob, isDebugEngineRunning, readActiveJob, readJVMInfo, startServer, startService, stopServer, stopService } from "../debug/server"; import { instance } from "../instantiate"; import { BrowserItem } from "../typings"; diff --git a/src/views/helpView.ts b/src/views/helpView.ts index 13fd80e7a..1d6527243 100644 --- a/src/views/helpView.ts +++ b/src/views/helpView.ts @@ -2,7 +2,7 @@ import AdmZip from 'adm-zip'; import path, { parse } from 'path'; import vscode from 'vscode'; -import { DebugConfiguration } from '../debug/config'; +import { DebugConfiguration } from '../api/configuration/DebugConfiguration'; import IBMi from '../api/IBMi'; import { instance } from '../instantiate'; From a6008454d4be758ce707a9b113f93bcb1d1937c2 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 14 Jan 2025 21:39:40 -0500 Subject: [PATCH 20/46] Move more types around Signed-off-by: worksofliam --- .env | 9 + package-lock.json | 1992 ++++++++++++++++- package.json | 2 + src/api/CompileTools.ts | 2 +- src/api/IBMi.ts | 2 +- src/api/IBMiContent.ts | 4 +- src/api/Search.ts | 2 +- src/api/Tools.ts | 2 +- src/api/components/copyToImport.ts | 2 +- src/api/components/getMemberInfo.ts | 2 +- src/api/components/getNewLibl.ts | 3 +- src/api/configVars.ts | 2 +- src/api/configuration/ConnectionManager.ts | 7 +- src/api/configuration/Storage.ts | 3 +- src/api/errors/parser.ts | 2 +- .../qsys => api/import}/Objects.ts | 0 src/api/tests.tsconfig.json | 5 + src/api/tests/a.test.ts | 6 + src/api/tests/env.ts | 11 + src/api/tests/globalSetup.ts | 39 + src/api/tests/state.ts | 11 + src/api/types.ts | 196 ++ src/commands/actions.ts | 3 +- src/commands/open.ts | 6 +- src/config/Configuration.ts | 4 - src/filesystems/local/actions.ts | 2 +- src/filesystems/local/deployTools.ts | 3 +- src/filesystems/local/deployment.ts | 2 +- .../local/gitApi.d.ts} | 0 src/filesystems/local/types.ts | 3 + src/filesystems/qsys/FSUtils.ts | 2 +- src/filesystems/qsys/sourceDateHandler.ts | 2 +- src/typings.ts | 224 +- src/views/actions.ts | 3 +- src/views/debugView.ts | 2 +- src/views/ifsBrowser.ts | 3 +- src/views/objectBrowser.ts | 6 +- src/views/searchView.ts | 2 +- src/views/tools.ts | 2 +- src/views/types.ts | 25 + vitest.config.ts | 13 + 41 files changed, 2297 insertions(+), 314 deletions(-) create mode 100644 .env rename src/{filesystems/qsys => api/import}/Objects.ts (100%) create mode 100644 src/api/tests.tsconfig.json create mode 100644 src/api/tests/a.test.ts create mode 100644 src/api/tests/env.ts create mode 100644 src/api/tests/globalSetup.ts create mode 100644 src/api/tests/state.ts create mode 100644 src/api/types.ts rename src/{api/import/git.d.ts => filesystems/local/gitApi.d.ts} (100%) create mode 100644 src/filesystems/local/types.ts create mode 100644 src/views/types.ts create mode 100644 vitest.config.ts diff --git a/.env b/.env new file mode 100644 index 000000000..087785656 --- /dev/null +++ b/.env @@ -0,0 +1,9 @@ +# defaults to localhost +#VITE_SERVER=UT201P18.RCH.STGLABS.IBM.COM +VITE_SERVER=iopen.iinthecloud.com + +# defaults to 8076 +VITE_PORT=22 + +VITE_DB_USER=SNDBX3 +VITE_DB_PASS=SNDBX3 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6feb5a0d8..25b91a1ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,7 @@ "ssh2-streams": "^0.4.10", "ts-loader": "^9.3.1", "typescript": "^4.8.2", + "vitest": "^2.1.8", "webpack": "^5.94.0", "webpack-cli": "^4.5.0" }, @@ -145,6 +146,262 @@ "node": ">=10.0.0" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/linux-x64": { "version": "0.19.2", "cpu": [ @@ -160,6 +417,102 @@ "node": ">=12" } }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", "dev": true, @@ -266,21 +619,269 @@ "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.1.tgz", "integrity": "sha512-wx4aBmgeGvFmOKucFKY+8VFJSYZxs9poN3SDNQFF6lT6NrQUnHiPB2PWz2sc4ieEcAaYYzN+1uWahEeTq2aRIQ==" }, - "node_modules/@types/adm-zip": { - "version": "0.5.5", + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", + "integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@types/estree": { - "version": "1.0.5", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", + "integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@types/glob": { - "version": "7.2.0", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", + "integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", + "integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", + "integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", + "integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", + "integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", + "integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", + "integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", + "integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", + "integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", + "integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", + "integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", + "integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", + "integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", + "integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", + "integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", + "integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", + "integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/adm-zip": { + "version": "0.5.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "node_modules/@types/glob": { + "version": "7.2.0", "dev": true, "license": "MIT", "dependencies": { @@ -345,6 +946,112 @@ "dev": true, "license": "MIT" }, + "node_modules/@vitest/expect": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.8.tgz", + "integrity": "sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==", + "dev": true, + "dependencies": { + "@vitest/spy": "2.1.8", + "@vitest/utils": "2.1.8", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.8.tgz", + "integrity": "sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==", + "dev": true, + "dependencies": { + "@vitest/spy": "2.1.8", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.8.tgz", + "integrity": "sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==", + "dev": true, + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.8.tgz", + "integrity": "sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==", + "dev": true, + "dependencies": { + "@vitest/utils": "2.1.8", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.8.tgz", + "integrity": "sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==", + "dev": true, + "dependencies": { + "@vitest/pretty-format": "2.1.8", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.8.tgz", + "integrity": "sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==", + "dev": true, + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz", + "integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==", + "dev": true, + "dependencies": { + "@vitest/pretty-format": "2.1.8", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@vscode-elements/elements": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@vscode-elements/elements/-/elements-1.9.1.tgz", @@ -658,6 +1365,15 @@ "safer-buffer": "~2.1.0" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/astral-regex": { "version": "2.0.0", "dev": true, @@ -747,6 +1463,15 @@ "node": ">=10.0.0" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/callsites": { "version": "3.1.0", "dev": true, @@ -774,6 +1499,22 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chai": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", + "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", + "dev": true, + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/chalk": { "version": "4.1.2", "dev": true, @@ -789,6 +1530,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "engines": { + "node": ">= 16" + } + }, "node_modules/chownr": { "version": "2.0.0", "license": "ISC", @@ -912,11 +1662,12 @@ "license": "MIT" }, "node_modules/debug": { - "version": "4.3.4", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, - "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -927,6 +1678,15 @@ } } }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/deep-is": { "version": "0.1.4", "dev": true, @@ -1053,64 +1813,736 @@ "webpack": "^4.40.0 || ^5.0.0" } }, - "node_modules/esbuild-loader/node_modules/@esbuild/linux-x64": { - "version": "0.17.19", + "node_modules/esbuild-loader/node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-loader/node_modules/esbuild": { + "version": "0.17.19", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "node_modules/esbuild-loader/node_modules/webpack-sources": { + "version": "1.4.3", + "dev": true, + "license": "MIT", + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-arm": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.2.tgz", + "integrity": "sha512-tM8yLeYVe7pRyAu9VMi/Q7aunpLwD139EY1S99xbQkT4/q2qa6eA4ige/WJQYdJ8GBL1K33pPFhPfPdJ/WzT8Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.2.tgz", + "integrity": "sha512-lsB65vAbe90I/Qe10OjkmrdxSX4UJDjosDgb8sZUKcg3oefEuW2OT2Vozz8ef7wrJbMcmhvCC+hciF8jY/uAkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.2.tgz", + "integrity": "sha512-qK/TpmHt2M/Hg82WXHRc/W/2SGo/l1thtDHZWqFq7oi24AjZ4O/CpPSu6ZuYKFkEgmZlFoa7CooAyYmuvnaG8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/darwin-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.2.tgz", + "integrity": "sha512-Ora8JokrvrzEPEpZO18ZYXkH4asCdc1DLdcVy8TGf5eWtPO1Ie4WroEJzwI52ZGtpODy3+m0a2yEX9l+KUn0tA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/darwin-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.2.tgz", + "integrity": "sha512-tP+B5UuIbbFMj2hQaUr6EALlHOIOmlLM2FK7jeFBobPy2ERdohI4Ka6ZFjZ1ZYsrHE/hZimGuU90jusRE0pwDw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.2.tgz", + "integrity": "sha512-YbPY2kc0acfzL1VPVK6EnAlig4f+l8xmq36OZkU0jzBVHcOTyQDhnKQaLzZudNJQyymd9OqQezeaBgkTGdTGeQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/freebsd-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.2.tgz", + "integrity": "sha512-nSO5uZT2clM6hosjWHAsS15hLrwCvIWx+b2e3lZ3MwbYSaXwvfO528OF+dLjas1g3bZonciivI8qKR/Hm7IWGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-arm": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.2.tgz", + "integrity": "sha512-Odalh8hICg7SOD7XCj0YLpYCEc+6mkoq63UnExDCiRA2wXEmGlK5JVrW50vZR9Qz4qkvqnHcpH+OFEggO3PgTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.2.tgz", + "integrity": "sha512-ig2P7GeG//zWlU0AggA3pV1h5gdix0MA3wgB+NsnBXViwiGgY77fuN9Wr5uoCrs2YzaYfogXgsWZbm+HGr09xg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-ia32": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.2.tgz", + "integrity": "sha512-mLfp0ziRPOLSTek0Gd9T5B8AtzKAkoZE70fneiiyPlSnUKKI4lp+mGEnQXcQEHLJAcIYDPSyBvsUbKUG2ri/XQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-loong64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.2.tgz", + "integrity": "sha512-hn28+JNDTxxCpnYjdDYVMNTR3SKavyLlCHHkufHV91fkewpIyQchS1d8wSbmXhs1fiYDpNww8KTFlJ1dHsxeSw==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-mips64el": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.2.tgz", + "integrity": "sha512-KbXaC0Sejt7vD2fEgPoIKb6nxkfYW9OmFUK9XQE4//PvGIxNIfPk1NmlHmMg6f25x57rpmEFrn1OotASYIAaTg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-ppc64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.2.tgz", + "integrity": "sha512-dJ0kE8KTqbiHtA3Fc/zn7lCd7pqVr4JcT0JqOnbj4LLzYnp+7h8Qi4yjfq42ZlHfhOCM42rBh0EwHYLL6LEzcw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-riscv64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.2.tgz", + "integrity": "sha512-7Z/jKNFufZ/bbu4INqqCN6DDlrmOTmdw6D0gH+6Y7auok2r02Ur661qPuXidPOJ+FSgbEeQnnAGgsVynfLuOEw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-s390x": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.2.tgz", + "integrity": "sha512-U+RinR6aXXABFCcAY4gSlv4CL1oOVvSSCdseQmGO66H+XyuQGZIUdhG56SZaDJQcLmrSfRmx5XZOWyCJPRqS7g==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/netbsd-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.2.tgz", + "integrity": "sha512-WNa5zZk1XpTTwMDompZmvQLHszDDDN7lYjEHCUmAGB83Bgs20EMs7ICD+oKeT6xt4phV4NDdSi/8OfjPbSbZfQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/openbsd-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.2.tgz", + "integrity": "sha512-S6kI1aT3S++Dedb7vxIuUOb3oAxqxk2Rh5rOXOTYnzN8JzW1VzBd+IqPiSpgitu45042SYD3HCoEyhLKQcDFDw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/sunos-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.2.tgz", + "integrity": "sha512-VXSSMsmb+Z8LbsQGcBMiM+fYObDNRm8p7tkUDMPG/g4fhFX5DEFmjxIEa3N8Zr96SjsJ1woAhF0DUnS3MF3ARw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.2.tgz", + "integrity": "sha512-5NayUlSAyb5PQYFAU9x3bHdsqB88RC3aM9lKDAz4X1mo/EchMIT1Q+pSeBXNgkfNmRecLXA0O8xP+x8V+g/LKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/win32-ia32": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.2.tgz", + "integrity": "sha512-47gL/ek1v36iN0wL9L4Q2MFdujR0poLZMJwhO2/N3gA89jgHp4MR8DKCmwYtGNksbfJb9JoTtbkoe6sDhg2QTA==", "cpu": [ - "x64" + "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ], "engines": { "node": ">=12" } }, - "node_modules/esbuild-loader/node_modules/esbuild": { - "version": "0.17.19", + "node_modules/esbuild/node_modules/@esbuild/win32-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.2.tgz", + "integrity": "sha512-tcuhV7ncXBqbt/Ybf0IyrMcwVOAPDckMK9rXNHtF17UTK18OKLpg08glminN06pt2WCoALhXdLfSPbVvK/6fxw==", + "cpu": [ + "x64" + ], "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" - } - }, - "node_modules/esbuild-loader/node_modules/webpack-sources": { - "version": "1.4.3", - "dev": true, - "license": "MIT", - "dependencies": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" } }, "node_modules/escalade": { @@ -1327,6 +2759,15 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "dev": true, @@ -1343,6 +2784,15 @@ "node": ">=0.8.x" } }, + "node_modules/expect-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz", + "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "dev": true, @@ -1441,6 +2891,20 @@ "version": "1.0.0", "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.1", "dev": true, @@ -1811,6 +3275,12 @@ "dev": true, "license": "MIT" }, + "node_modules/loupe": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", + "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", + "dev": true + }, "node_modules/lru-cache": { "version": "6.0.0", "dev": true, @@ -1822,6 +3292,15 @@ "node": ">=10" } }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, "node_modules/make-dir": { "version": "3.1.0", "license": "MIT", @@ -1920,15 +3399,34 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "dev": true, - "license": "MIT" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true }, "node_modules/nan": { "version": "2.17.0", "license": "MIT", "optional": true }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "dev": true, @@ -2055,10 +3553,26 @@ "dev": true, "license": "MIT" }, - "node_modules/picocolors": { - "version": "1.0.1", + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, - "license": "ISC" + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", @@ -2082,6 +3596,34 @@ "node": ">=8" } }, + "node_modules/postcss": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", + "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "dev": true, @@ -2200,6 +3742,44 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rollup": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz", + "integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.30.1", + "@rollup/rollup-android-arm64": "4.30.1", + "@rollup/rollup-darwin-arm64": "4.30.1", + "@rollup/rollup-darwin-x64": "4.30.1", + "@rollup/rollup-freebsd-arm64": "4.30.1", + "@rollup/rollup-freebsd-x64": "4.30.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.30.1", + "@rollup/rollup-linux-arm-musleabihf": "4.30.1", + "@rollup/rollup-linux-arm64-gnu": "4.30.1", + "@rollup/rollup-linux-arm64-musl": "4.30.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.30.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", + "@rollup/rollup-linux-riscv64-gnu": "4.30.1", + "@rollup/rollup-linux-s390x-gnu": "4.30.1", + "@rollup/rollup-linux-x64-gnu": "4.30.1", + "@rollup/rollup-linux-x64-musl": "4.30.1", + "@rollup/rollup-win32-arm64-msvc": "4.30.1", + "@rollup/rollup-win32-ia32-msvc": "4.30.1", + "@rollup/rollup-win32-x64-msvc": "4.30.1", + "fsevents": "~2.3.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "dev": true, @@ -2313,6 +3893,12 @@ "version": "0.2.0", "license": "MIT" }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, "node_modules/slice-ansi": { "version": "4.0.0", "dev": true, @@ -2342,6 +3928,15 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-support": { "version": "0.5.21", "dev": true, @@ -2383,6 +3978,18 @@ "node": ">=5.2.0" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "node_modules/std-env": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", + "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", + "dev": true + }, "node_modules/stream-transform": { "version": "3.2.0", "license": "MIT" @@ -2592,6 +4199,45 @@ "dev": true, "license": "MIT" }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true + }, + "node_modules/tinypool": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", + "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", + "dev": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tmp": { "version": "0.2.1", "license": "MIT", @@ -2717,6 +4363,206 @@ "dev": true, "license": "MIT" }, + "node_modules/vite": { + "version": "5.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", + "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "dev": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.8.tgz", + "integrity": "sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitest": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.8.tgz", + "integrity": "sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==", + "dev": true, + "dependencies": { + "@vitest/expect": "2.1.8", + "@vitest/mocker": "2.1.8", + "@vitest/pretty-format": "^2.1.8", + "@vitest/runner": "2.1.8", + "@vitest/snapshot": "2.1.8", + "@vitest/spy": "2.1.8", + "@vitest/utils": "2.1.8", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.8", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.8", + "@vitest/ui": "2.1.8", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, "node_modules/vscode-diff": { "version": "2.0.2", "license": "MIT" @@ -2885,6 +4731,22 @@ "node": ">= 8" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wildcard": { "version": "2.0.0", "dev": true, diff --git a/package.json b/package.json index 9258f6199..829283e2c 100644 --- a/package.json +++ b/package.json @@ -2955,6 +2955,7 @@ "scripts": { "lint": "eslint src/**/*.js --no-error-on-unmatched-pattern", "pretest": "npm run lint", + "test": "vitest", "package": "vsce package", "build": "rm -rf dist && tsc", "vscode:prepublish": "webpack --mode production", @@ -2978,6 +2979,7 @@ "ssh2-streams": "^0.4.10", "ts-loader": "^9.3.1", "typescript": "^4.8.2", + "vitest": "^2.1.8", "webpack": "^5.94.0", "webpack-cli": "^4.5.0" }, diff --git a/src/api/CompileTools.ts b/src/api/CompileTools.ts index 8df6a8fb7..8706704a9 100644 --- a/src/api/CompileTools.ts +++ b/src/api/CompileTools.ts @@ -1,7 +1,7 @@ -import { Variable, RemoteCommand, CommandResult, StandardIO } from '../typings'; import IBMi from './IBMi'; import { Tools } from './Tools'; +import { Variable, RemoteCommand, CommandResult, StandardIO } from './types'; export interface ILELibrarySettings { currentLibrary: string; diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 8000f2340..f7b6534bc 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -7,7 +7,6 @@ import { IBMiComponent } from "./components/component"; import { CopyToImport } from "./components/copyToImport"; import { CustomQSh } from '../components/cqsh'; import { ComponentManager } from "./components/manager"; -import { CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, WrapResult } from "../typings"; import { CompileTools } from "./CompileTools"; import IBMiContent from "./IBMiContent"; import { CachedServerSettings, CodeForIStorage } from './configuration/Storage'; @@ -15,6 +14,7 @@ import { Tools } from './Tools'; import * as configVars from './configVars'; import { DebugConfiguration } from "./configuration/DebugConfiguration"; import { ConnectionManager, ConnectionConfig } from './configuration/ConnectionManager'; +import { CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, WrapResult } from './types'; export interface MemberParts extends IBMiMember { basename: string diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index cd63ab9e8..86eb0376f 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -5,11 +5,11 @@ import tmp from 'tmp'; import util from 'util'; import * as node_ssh from "node-ssh"; import { GetMemberInfo } from './components/getMemberInfo'; -import { ObjectTypes } from '../filesystems/qsys/Objects'; -import { AttrOperands, CommandResult, IBMiError, IBMiMember, IBMiObject, IFSFile, QsysPath, SpecialAuthorities } from '../typings'; +import { AttrOperands, CommandResult, IBMiError, IBMiMember, IBMiObject, IFSFile, QsysPath, SpecialAuthorities } from './types'; import { FilterType, parseFilter, singleGenericName } from './Filter'; import { default as IBMi } from './IBMi'; import { Tools } from './Tools'; +import { ObjectTypes } from './import/Objects'; const tmpFile = util.promisify(tmp.file); const readFileAsync = util.promisify(fs.readFile); const writeFileAsync = util.promisify(fs.writeFile); diff --git a/src/api/Search.ts b/src/api/Search.ts index 830a614a2..4a87cd31c 100644 --- a/src/api/Search.ts +++ b/src/api/Search.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import { GetMemberInfo } from './components/getMemberInfo'; -import { IBMiMember, SearchHit, SearchResults } from '../typings'; +import { IBMiMember, SearchHit, SearchResults } from './types'; import { Tools } from './Tools'; import IBMi from './IBMi'; diff --git a/src/api/Tools.ts b/src/api/Tools.ts index 8f9e286af..3ccd11471 100644 --- a/src/api/Tools.ts +++ b/src/api/Tools.ts @@ -1,7 +1,7 @@ import os from "os"; import path from "path"; -import { IBMiMessage, IBMiMessages, QsysPath } from '../typings'; +import { IBMiMessage, IBMiMessages, QsysPath } from './types'; export namespace Tools { export class SqlError extends Error { diff --git a/src/api/components/copyToImport.ts b/src/api/components/copyToImport.ts index bc2849160..f46ae4f60 100644 --- a/src/api/components/copyToImport.ts +++ b/src/api/components/copyToImport.ts @@ -1,6 +1,6 @@ import IBMi from "../IBMi"; import { Tools } from "../Tools"; -import { WrapResult } from "../../typings"; +import { WrapResult } from "../types"; import { ComponentState, IBMiComponent } from "./component"; export class CopyToImport implements IBMiComponent { diff --git a/src/api/components/getMemberInfo.ts b/src/api/components/getMemberInfo.ts index c63cf438c..2808fc689 100644 --- a/src/api/components/getMemberInfo.ts +++ b/src/api/components/getMemberInfo.ts @@ -1,8 +1,8 @@ import { posix } from "path"; import IBMi from "../IBMi"; import { Tools } from "../Tools"; -import { IBMiMember } from "../../typings"; import { ComponentState, IBMiComponent } from "../components/component"; +import { IBMiMember } from "../types"; export class GetMemberInfo implements IBMiComponent { static ID = 'GetMemberInfo'; diff --git a/src/api/components/getNewLibl.ts b/src/api/components/getNewLibl.ts index 718d51e32..8f9cad20a 100644 --- a/src/api/components/getNewLibl.ts +++ b/src/api/components/getNewLibl.ts @@ -1,6 +1,5 @@ import { posix } from "path"; import IBMi from "../IBMi"; -import { instance } from "../../instantiate"; import { ComponentState, IBMiComponent } from "./component"; export class GetNewLibl implements IBMiComponent { @@ -15,7 +14,7 @@ export class GetNewLibl implements IBMiComponent { update(connection: IBMi): Promise { const config = connection.config! - const content = instance.getContent(); + const content = connection.getContent(); return connection.withTempDirectory(async (tempDir): Promise => { const tempSourcePath = posix.join(tempDir, `getnewlibl.sql`); diff --git a/src/api/configVars.ts b/src/api/configVars.ts index 592b7073a..c453f2477 100644 --- a/src/api/configVars.ts +++ b/src/api/configVars.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import * as os from 'os'; -import { ConnectionData } from "../typings"; +import { ConnectionData } from './types'; function hasOwnProperty( obj: O, diff --git a/src/api/configuration/ConnectionManager.ts b/src/api/configuration/ConnectionManager.ts index a2de4eb06..0267cb1c5 100644 --- a/src/api/configuration/ConnectionManager.ts +++ b/src/api/configuration/ConnectionManager.ts @@ -1,9 +1,12 @@ import os from "os"; -import { SourceDateMode } from "../../config/Configuration"; -import { ConnectionData, DeploymentMethod } from "../../typings"; import { FilterType } from "../Filter"; import { Config, VirtualConfig } from "./Config"; +import { DeploymentMethod, ConnectionData } from "../types"; + +export type SourceDateMode = "edit" | "diff"; +export type DefaultOpenMode = "browse" | "edit"; +export type ReconnectMode = "always" | "never" | "ask"; export interface ConnectionConfig extends ConnectionProfile { host: string; diff --git a/src/api/configuration/Storage.ts b/src/api/configuration/Storage.ts index 22711fd3b..e44c88879 100644 --- a/src/api/configuration/Storage.ts +++ b/src/api/configuration/Storage.ts @@ -1,5 +1,4 @@ - -import { ConnectionData } from '../../typings'; +import { ConnectionData } from "../types"; const PREVIOUS_CUR_LIBS_KEY = `prevCurLibs`; const LAST_PROFILE_KEY = `currentProfile`; diff --git a/src/api/errors/parser.ts b/src/api/errors/parser.ts index 907b6fee8..1179b8761 100644 --- a/src/api/errors/parser.ts +++ b/src/api/errors/parser.ts @@ -1,5 +1,5 @@ import { Parser, ISequentialFileReader } from "@ibm/ibmi-eventf-parser"; -import { FileError } from "../../typings"; +import { FileError } from "../types"; class EvfEventFileReader implements ISequentialFileReader { lines: string[]; diff --git a/src/filesystems/qsys/Objects.ts b/src/api/import/Objects.ts similarity index 100% rename from src/filesystems/qsys/Objects.ts rename to src/api/import/Objects.ts diff --git a/src/api/tests.tsconfig.json b/src/api/tests.tsconfig.json new file mode 100644 index 000000000..cb2bea875 --- /dev/null +++ b/src/api/tests.tsconfig.json @@ -0,0 +1,5 @@ +{ + "include": [ + "." + ] +} \ No newline at end of file diff --git a/src/api/tests/a.test.ts b/src/api/tests/a.test.ts new file mode 100644 index 000000000..06126003b --- /dev/null +++ b/src/api/tests/a.test.ts @@ -0,0 +1,6 @@ +// sum.test.js +import { expect, test } from 'vitest' + +test('adds 1 + 2 to equal 3', () => { + expect(1+2).toBe(3) +}) \ No newline at end of file diff --git a/src/api/tests/env.ts b/src/api/tests/env.ts new file mode 100644 index 000000000..1e5129459 --- /dev/null +++ b/src/api/tests/env.ts @@ -0,0 +1,11 @@ + +/** + * Default credentials for connecting to the daemon server, + * loaded from environment variables. + */ +export const ENV_CREDS = { + host: process.env.VITE_SERVER || `localhost`, + user: process.env.VITE_DB_USER, + password: process.env.VITE_DB_PASS, + port: parseInt(process.env.VITE_DB_PORT || `22`) +} \ No newline at end of file diff --git a/src/api/tests/globalSetup.ts b/src/api/tests/globalSetup.ts new file mode 100644 index 000000000..81c9264d7 --- /dev/null +++ b/src/api/tests/globalSetup.ts @@ -0,0 +1,39 @@ +import assert from "assert"; +import IBMi from "../IBMi"; +import { ENV_CREDS } from "./env"; +import { setConnection } from "./state"; +import { vi } from "vitest"; + +export default async function setup() { + // vi.mock(import(`vscode`), async (importOriginal) => { + // return {} + // }); + + const conn = new IBMi(); + + const result = await conn.connect( + { + host: ENV_CREDS.host!, + name: `testsystem`, + username: ENV_CREDS.user!, + password: ENV_CREDS.password!, + port: ENV_CREDS.port + }, + { + message: (type: string, message: string) => { + console.log(`${type.padEnd(10)} ${message}`); + }, + progress: ({message}) => { + console.log(`PROGRESS: ${message}`); + }, + uiErrorHandler: async (connection, code, data) => { + console.log(`UI ERROR: ${code}: ${data}`); + return false; + }, + } + ); + + assert.ok(result.success); + + setConnection(conn); +} diff --git a/src/api/tests/state.ts b/src/api/tests/state.ts new file mode 100644 index 000000000..6ed5f0439 --- /dev/null +++ b/src/api/tests/state.ts @@ -0,0 +1,11 @@ +import IBMi from "../IBMi"; + +let connection: IBMi; + +export function setConnection(conn: IBMi) { + connection = conn; +} + +export function getConnection() { + return connection!; +} \ No newline at end of file diff --git a/src/api/types.ts b/src/api/types.ts new file mode 100644 index 000000000..876eda3d5 --- /dev/null +++ b/src/api/types.ts @@ -0,0 +1,196 @@ +import { ObjectFilters } from "./configuration/ConnectionManager"; + +export type DeploymentMethod = "all" | "staged" | "unstaged" | "changed" | "compare"; + +export interface StandardIO { + onStdout?: (data: Buffer) => void; + onStderr?: (data: Buffer) => void; + stdin?: string; +} + +/** + * External interface for extensions to call `code-for-ibmi.runCommand` + */ +export type ActionType = "member" | "streamfile" | "object" | "file"; +export type ActionRefresh = "no" | "parent" | "filter" | "browser"; +export type ActionEnvironment = "ile" | "qsh" | "pase"; +export type Variable = Record; + +export enum CcsidOrigin { + User = "user", + System = "system", +}; + +export interface RemoteCommand { + title?: string; + command: string; + environment?: ActionEnvironment; + cwd?: string; + env?: Record; + noLibList?: boolean +} + +export interface CommandData extends StandardIO { + command: string; + directory?: string; + env?: Record; +} + +export interface CommandResult { + code: number; + stdout: string; + stderr: string; + command?: string; +} + +export interface Action { + name: string; + command: string; + type?: ActionType; + environment: ActionEnvironment; + extensions?: string[]; + deployFirst?: boolean; + postDownload?: string[]; + refresh?: ActionRefresh; + runOnProtected?: boolean; +} + +export interface ConnectionData { + name: string; + host: string; + port: number; + username: string; + password?: string; + privateKeyPath?: string; + keepaliveInterval?: number; + readyTimeout?: number; +} + +export interface Server { + name: string +} + +export interface Profile { + profile: string +} + +export interface QsysPath { + asp?: string, + library: string, + name: string, +} + +export interface IBMiObject extends QsysPath { + type: string, + text: string, + sourceFile?: boolean + attribute?: string, + sourceLength?: number + size?: number + created?: Date + changed?: Date + created_by?: string + owner?: string +} + +export interface IBMiMember { + library: string + file: string + name: string + extension: string + recordLength?: number + text?: string + asp?: string + lines?: number + created?: Date + changed?: Date +} + +export interface IFSFile { + type: "directory" | "streamfile" + name: string + path: string + size?: number + modified?: Date + owner?: string +} + +export interface IBMiError { + code: string + text: string +} + +export interface FileError { + sev: number + lineNum: number + toLineNum: number + column: number + toColumn: number + text: string + code: string +} + +export interface QsysFsOptions { + readonly?: boolean +} + +export type IBMiEvent = "connected" | "disconnected" | "deployLocation" | "deploy" + +export interface WithPath { + path: string +} + +export interface WithLibrary { + library: string +} + +export type FocusOptions = { select?: boolean; focus?: boolean; expand?: boolean | number } + +export interface FilteredItem { + filter: ObjectFilters +} + +export interface ObjectItem extends FilteredItem, WithPath { + object: IBMiObject +} + +export interface MemberItem extends FilteredItem, WithPath { + member: IBMiMember +} + +export type IBMiMessage = { + id: string + text: string +} + +export type IBMiMessages = { + messages: IBMiMessage[] + findId(id: string): IBMiMessage | undefined +} +export const OBJECT_BROWSER_MIMETYPE = "application/vnd.code.tree.objectbrowser"; +export const IFS_BROWSER_MIMETYPE = "application/vnd.code.tree.ifsbrowser"; + +export interface WrapResult { + newStatements: string[]; + outStmf: string; +} + +export type SpecialAuthorities = "*ALLOBJ" | "*AUDIT" | "*IOSYSCFG" | "*JOBCTL" | "*SAVSYS" | "*SECADM" | "*SERVICE" | "*SPLCTL"; +export type AttrOperands = 'ACCESS_TIME' | 'ALLOC_SIZE' | 'ALLOC_SIZE_64' | 'ALWCKPWR' | 'ALWSAV' | 'ASP' | 'AUDIT' | 'AUTH_GROUP' | 'AUTH_LIST_NAME' | 'AUTH_OWNER' | 'AUTH_USERS' | 'CCSID' | 'CHANGE_TIME' | 'CHECKED_OUT' | 'CHECKED_OUT_USER' | 'CHECKED_OUT_TIME' | 'CODEPAGE' | 'CREATE_TIME' | 'CRTOBJAUD' | 'CRTOBJSCAN' | 'DATA_SIZE' | 'DATA_SIZE_64' | 'DIR_FORMAT' | 'DISK_STG_OPT' | 'EXTENDED_ATTR_SIZE' | 'FILE_FORMAT' | 'FILE_ID' | 'JOURNAL_APPLY_CHANGES' | 'JOURNAL_ID' | 'JOURNAL_LIBRARY' | 'JOURNAL_NAME' | 'JOURNAL_OPTIONS' | 'JOURNAL_RCVR_ASP' | 'JOURNAL_RCVR_LIBRARY' | 'JOURNAL_RCVR_NAME' | 'JOURNAL_ROLLBACK_ENDED' | 'JOURNAL_START_TIME' | 'JOURNAL_STATUS' | 'LOCAL_REMOTE' | 'MAIN_STG_OPT' | 'MODIFY_TIME' | 'MULT_SIGS' | 'OBJTYPE' | 'PC_ARCHIVE' | 'PC_HIDDEN' | 'PC_READ_ONLY' | 'PC_SYSTEM' | 'RSTDRNMUNL' | 'SCAN' | 'SCAN_BINARY' | 'SCAN_CCSID1' | 'SCAN_CCSID2' | 'SCAN_SIGS_DIFF' | 'SCAN_STATUS' | 'SGID' | 'SIGNED' | 'STG_FREE' | 'SUID' | 'SYSTEM_ARCHIVE' | 'SYSTEM_USE' | 'SYS_SIGNED' | 'UDFS_DEFAULT_FORMAT' | 'USAGE_DAYS_USED' | 'USAGE_LAST_USED_TIME' | 'USAGE_RESET_TIME'; + +export type SearchResults = { + term: string, + hits: SearchHit[] +} + +export type SearchHit = { + path: string + lines: SearchHitLine[] + readonly?: boolean + label?: string +} + +export type SearchHitLine = { + number: number + content: string +} \ No newline at end of file diff --git a/src/commands/actions.ts b/src/commands/actions.ts index 2bdc233ef..48001d1f3 100644 --- a/src/commands/actions.ts +++ b/src/commands/actions.ts @@ -2,9 +2,10 @@ import path from "path"; import { commands, TreeItem, Uri, WorkspaceFolder, window, Disposable } from "vscode"; import { refreshDiagnosticsFromServer } from "../views/diagnostics"; import Instance from "../Instance"; -import { BrowserItem, Action, DeploymentMethod } from "../typings"; +import { Action, DeploymentMethod } from "../typings"; import { runAction } from "../views/actions"; import IBMi from "../api/IBMi"; +import { BrowserItem } from "../views/types"; export function registerActionsCommands(instance: Instance): Disposable[] { return [ diff --git a/src/commands/open.ts b/src/commands/open.ts index b417cba12..03a15c7ca 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -1,16 +1,18 @@ import { commands, Disposable, l10n, QuickInputButton, QuickPickItem, QuickPickItemButtonEvent, QuickPickItemKind, Range, TextDocument, TextDocumentShowOptions, ThemeIcon, Uri, window } from "vscode"; -import { MemberItem, OpenEditableOptions, WithPath } from "../typings"; +import { MemberItem, QsysFsOptions, WithPath } from "../typings"; import Instance from "../Instance"; import { Tools } from "../api/Tools"; import { getUriFromPath, parseFSOptions } from "../filesystems/qsys/QSysFs"; -import { DefaultOpenMode } from "../config/Configuration"; import path from "path"; import { findExistingDocument, findExistingDocumentUri } from "../views/tools"; import IBMi from "../api/IBMi"; +import { DefaultOpenMode } from "../api/configuration/ConnectionManager"; const CLEAR_RECENT = `$(trash) Clear recently opened`; const CLEAR_CACHED = `$(trash) Clear cached`; +export type OpenEditableOptions = QsysFsOptions & { position?: Range }; + export function registerOpenCommands(instance: Instance): Disposable[] { return [ diff --git a/src/config/Configuration.ts b/src/config/Configuration.ts index c5caec943..893d5d3fd 100644 --- a/src/config/Configuration.ts +++ b/src/config/Configuration.ts @@ -4,10 +4,6 @@ import { ConnectionData, DeploymentMethod } from '../typings'; import { FilterType } from '../api/Filter'; import { Config } from "../api/configuration/Config"; -export type SourceDateMode = "edit" | "diff"; -export type DefaultOpenMode = "browse" | "edit"; -export type ReconnectMode = "always" | "never" | "ask"; - export function onCodeForIBMiConfigurationChange(props: string | string[], todo: (value: vscode.ConfigurationChangeEvent) => void) { const keys = (Array.isArray(props) ? props : Array.of(props)).map(key => `code-for-ibmi.${key}`); return vscode.workspace.onDidChangeConfiguration(async event => { diff --git a/src/filesystems/local/actions.ts b/src/filesystems/local/actions.ts index a95c0776e..512139d8d 100644 --- a/src/filesystems/local/actions.ts +++ b/src/filesystems/local/actions.ts @@ -1,5 +1,5 @@ import { RelativePattern, window, workspace, WorkspaceFolder } from "vscode"; -import { Action } from "../../typings"; +import { Action } from "../../api/types"; export async function getLocalActions(currentWorkspace: WorkspaceFolder) { const actions: Action[] = []; diff --git a/src/filesystems/local/deployTools.ts b/src/filesystems/local/deployTools.ts index befd59d15..edf352972 100644 --- a/src/filesystems/local/deployTools.ts +++ b/src/filesystems/local/deployTools.ts @@ -2,10 +2,11 @@ import createIgnore, { Ignore } from 'ignore'; import path, { basename } from 'path'; import vscode, { Uri, WorkspaceFolder } from 'vscode'; import { instance } from '../../instantiate'; -import { DeploymentMethod, DeploymentParameters } from '../../typings'; import { LocalLanguageActions } from './LocalLanguageActions'; import { Deployment } from './deployment'; import { getGitAPI, md5Hash } from '../../views/tools'; +import { DeploymentMethod } from '../../api/types'; +import { DeploymentParameters } from '../../typings'; type ServerFileChanges = { uploads: Uri[], relativeRemoteDeletes: string[] }; diff --git a/src/filesystems/local/deployment.ts b/src/filesystems/local/deployment.ts index b74972316..6cdabb5d1 100644 --- a/src/filesystems/local/deployment.ts +++ b/src/filesystems/local/deployment.ts @@ -4,11 +4,11 @@ import tar from 'tar'; import tmp from 'tmp'; import vscode from 'vscode'; import { instance } from '../../instantiate'; -import { DeploymentParameters } from '../../typings'; import IBMi from '../../api/IBMi'; import { Tools } from '../../api/Tools'; import { getLocalActions } from './actions'; import { DeployTools } from './deployTools'; +import { DeploymentParameters } from '../../typings'; export namespace Deployment { export interface MD5Entry { diff --git a/src/api/import/git.d.ts b/src/filesystems/local/gitApi.d.ts similarity index 100% rename from src/api/import/git.d.ts rename to src/filesystems/local/gitApi.d.ts diff --git a/src/filesystems/local/types.ts b/src/filesystems/local/types.ts new file mode 100644 index 000000000..70c5d39f0 --- /dev/null +++ b/src/filesystems/local/types.ts @@ -0,0 +1,3 @@ +import { Ignore } from "ignore" +import { WorkspaceFolder } from "vscode" +import { DeploymentMethod } from "../../api/types" \ No newline at end of file diff --git a/src/filesystems/qsys/FSUtils.ts b/src/filesystems/qsys/FSUtils.ts index 87f0dee72..6d3e40089 100644 --- a/src/filesystems/qsys/FSUtils.ts +++ b/src/filesystems/qsys/FSUtils.ts @@ -1,8 +1,8 @@ import path from "path"; import vscode, { l10n } from "vscode"; -import { ReconnectMode } from "../../config/Configuration"; import { findUriTabs } from "../../views/tools"; import IBMi from "../../api/IBMi"; +import { ReconnectMode } from "../../api/configuration/ConnectionManager"; /** * Called when a member/streamfile is left open when VS Code is closed and re-opened to reconnect (or not) to the previous IBM i, based on the `autoReconnect` global configuration value. diff --git a/src/filesystems/qsys/sourceDateHandler.ts b/src/filesystems/qsys/sourceDateHandler.ts index 263667ab9..a4f0a9aaa 100644 --- a/src/filesystems/qsys/sourceDateHandler.ts +++ b/src/filesystems/qsys/sourceDateHandler.ts @@ -2,9 +2,9 @@ import Crypto from "crypto"; import vscode from "vscode"; import { DiffComputer } from "vscode-diff"; -import { SourceDateMode } from "../../config/Configuration"; import { instance } from "../../instantiate"; import IBMi from "../../api/IBMi"; +import { SourceDateMode } from "../../api/configuration/ConnectionManager"; const editedTodayColor = new vscode.ThemeColor(`gitDecoration.modifiedResourceForeground`); const seachGutterColor = new vscode.ThemeColor(`gitDecoration.addedResourceForeground`); diff --git a/src/typings.ts b/src/typings.ts index 32814891d..5cec6d7d1 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -1,11 +1,12 @@ -import { Ignore } from 'ignore'; -import { MarkdownString, ProviderResult, Range, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder } from "vscode"; import { CustomUI } from "./webviews/CustomUI"; import Instance from "./Instance"; import { Tools } from "./api/Tools"; import { DeployTools } from "./filesystems/local/deployTools"; import { ComponentRegistry } from './api/components/manager'; import { ObjectFilters } from './api/configuration/ConnectionManager'; +import { DeploymentMethod, FileError, IBMiMember, IBMiObject, WithPath } from "./api/types"; +import { Ignore } from "ignore"; +import { WorkspaceFolder } from "vscode"; export interface CodeForIBMi { instance: Instance, @@ -16,181 +17,6 @@ export interface CodeForIBMi { componentRegistry: ComponentRegistry } -export type DeploymentMethod = "all" | "staged" | "unstaged" | "changed" | "compare"; - -export interface DeploymentParameters { - method: DeploymentMethod - workspaceFolder: WorkspaceFolder - remotePath: string - ignoreRules?: Ignore -} - -export interface StandardIO { - onStdout?: (data: Buffer) => void; - onStderr?: (data: Buffer) => void; - stdin?: string; -} - -/** - * External interface for extensions to call `code-for-ibmi.runCommand` - */ -export type ActionType = "member" | "streamfile" | "object" | "file"; -export type ActionRefresh = "no" | "parent" | "filter" | "browser"; -export type ActionEnvironment = "ile" | "qsh" | "pase"; -export type Variable = Record; - -export enum CcsidOrigin { - User = "user", - System = "system", -}; - -export interface RemoteCommand { - title?: string; - command: string; - environment?: ActionEnvironment; - cwd?: string; - env?: Record; - noLibList?: boolean -} - -export interface CommandData extends StandardIO { - command: string; - directory?: string; - env?: Record; -} - -export interface CommandResult { - code: number; - stdout: string; - stderr: string; - command?: string; -} - -export interface Action { - name: string; - command: string; - type?: ActionType; - environment: ActionEnvironment; - extensions?: string[]; - deployFirst?: boolean; - postDownload?: string[]; - refresh?: ActionRefresh; - runOnProtected?: boolean; -} - -export interface ConnectionData { - name: string; - host: string; - port: number; - username: string; - password?: string; - privateKeyPath?: string; - keepaliveInterval?: number; - readyTimeout?: number; -} - -export interface Server { - name: string -} - -export interface Profile { - profile: string -} - -export interface QsysPath { - asp?: string, - library: string, - name: string, -} - -export interface IBMiObject extends QsysPath { - type: string, - text: string, - sourceFile?: boolean - attribute?: string, - sourceLength?: number - size?: number - created?: Date - changed?: Date - created_by?: string - owner?: string -} - -export interface IBMiMember { - library: string - file: string - name: string - extension: string - recordLength?: number - text?: string - asp?: string - lines?: number - created?: Date - changed?: Date -} - -export interface IFSFile { - type: "directory" | "streamfile" - name: string - path: string - size?: number - modified?: Date - owner?: string -} - -export interface IBMiError { - code: string - text: string -} - -export interface FileError { - sev: number - lineNum: number - toLineNum: number - column: number - toColumn: number - text: string - code: string -} - -export interface QsysFsOptions { - readonly?: boolean -} - -export type IBMiEvent = "connected" | "disconnected" | "deployLocation" | "deploy" - -export interface WithPath { - path: string -} - -export interface WithLibrary { - library: string -} - -export type FocusOptions = { select?: boolean; focus?: boolean; expand?: boolean | number } - -export type BrowserItemParameters = { - icon?: string - color?: string - state?: TreeItemCollapsibleState - parent?: BrowserItem -} - -export class BrowserItem extends TreeItem { - constructor(label: string, readonly params?: BrowserItemParameters) { - super(label, params?.state); - this.iconPath = params?.icon ? new ThemeIcon(params.icon, params.color ? new ThemeColor(params.color) : undefined) : undefined; - } - - get parent() { - return this.params?.parent; - } - - getChildren?(): ProviderResult; - refresh?(): void; - reveal?(options?: FocusOptions): Thenable; - getToolTip?(): Promise; -} export interface FilteredItem { filter: ObjectFilters @@ -204,41 +30,13 @@ export interface MemberItem extends FilteredItem, WithPath { member: IBMiMember } -export type IBMiMessage = { - id: string - text: string -} - -export type IBMiMessages = { - messages: IBMiMessage[] - findId(id: string): IBMiMessage | undefined -} -export const OBJECT_BROWSER_MIMETYPE = "application/vnd.code.tree.objectbrowser"; -export const IFS_BROWSER_MIMETYPE = "application/vnd.code.tree.ifsbrowser"; - -export type OpenEditableOptions = QsysFsOptions & { position?: Range }; - -export interface WrapResult { - newStatements: string[]; - outStmf: string; -} - -export type SpecialAuthorities = "*ALLOBJ" | "*AUDIT" | "*IOSYSCFG" | "*JOBCTL" | "*SAVSYS" | "*SECADM" | "*SERVICE" | "*SPLCTL"; -export type AttrOperands = 'ACCESS_TIME' | 'ALLOC_SIZE' | 'ALLOC_SIZE_64' | 'ALWCKPWR' | 'ALWSAV' | 'ASP' | 'AUDIT' | 'AUTH_GROUP' | 'AUTH_LIST_NAME' | 'AUTH_OWNER' | 'AUTH_USERS' | 'CCSID' | 'CHANGE_TIME' | 'CHECKED_OUT' | 'CHECKED_OUT_USER' | 'CHECKED_OUT_TIME' | 'CODEPAGE' | 'CREATE_TIME' | 'CRTOBJAUD' | 'CRTOBJSCAN' | 'DATA_SIZE' | 'DATA_SIZE_64' | 'DIR_FORMAT' | 'DISK_STG_OPT' | 'EXTENDED_ATTR_SIZE' | 'FILE_FORMAT' | 'FILE_ID' | 'JOURNAL_APPLY_CHANGES' | 'JOURNAL_ID' | 'JOURNAL_LIBRARY' | 'JOURNAL_NAME' | 'JOURNAL_OPTIONS' | 'JOURNAL_RCVR_ASP' | 'JOURNAL_RCVR_LIBRARY' | 'JOURNAL_RCVR_NAME' | 'JOURNAL_ROLLBACK_ENDED' | 'JOURNAL_START_TIME' | 'JOURNAL_STATUS' | 'LOCAL_REMOTE' | 'MAIN_STG_OPT' | 'MODIFY_TIME' | 'MULT_SIGS' | 'OBJTYPE' | 'PC_ARCHIVE' | 'PC_HIDDEN' | 'PC_READ_ONLY' | 'PC_SYSTEM' | 'RSTDRNMUNL' | 'SCAN' | 'SCAN_BINARY' | 'SCAN_CCSID1' | 'SCAN_CCSID2' | 'SCAN_SIGS_DIFF' | 'SCAN_STATUS' | 'SGID' | 'SIGNED' | 'STG_FREE' | 'SUID' | 'SYSTEM_ARCHIVE' | 'SYSTEM_USE' | 'SYS_SIGNED' | 'UDFS_DEFAULT_FORMAT' | 'USAGE_DAYS_USED' | 'USAGE_LAST_USED_TIME' | 'USAGE_RESET_TIME'; - -export type SearchResults = { - term: string, - hits: SearchHit[] -} - -export type SearchHit = { - path: string - lines: SearchHitLine[] - readonly?: boolean - label?: string +export interface DeploymentParameters { + method: DeploymentMethod + workspaceFolder: WorkspaceFolder + remotePath: string + ignoreRules?: Ignore } -export type SearchHitLine = { - number: number - content: string -} \ No newline at end of file +export * from "./api/types"; +export * from "./views/types"; +export * from "./filesystems/local/types"; \ No newline at end of file diff --git a/src/views/actions.ts b/src/views/actions.ts index 27399e7f5..f8656a87f 100644 --- a/src/views/actions.ts +++ b/src/views/actions.ts @@ -7,13 +7,14 @@ import { getBranchLibraryName, getEnvConfig } from '../filesystems/local/env'; import { getGitBranch } from '../filesystems/local/git'; import Instance from '../Instance'; import { parseFSOptions } from '../filesystems/qsys/QSysFs'; -import { Action, BrowserItem, DeploymentMethod, Variable } from '../typings'; +import { Action, DeploymentMethod, Variable } from '../typings'; import vscode, { CustomExecution, Pseudoterminal, TaskGroup, TaskRevealKind, WorkspaceFolder, commands, tasks } from 'vscode'; import { CustomUI } from '../webviews/CustomUI'; import { Tools } from '../api/Tools'; import { CompileTools } from '../api/CompileTools'; import IBMi from '../api/IBMi'; +import { BrowserItem } from './types'; interface CommandObject { object: string diff --git a/src/views/debugView.ts b/src/views/debugView.ts index 8af5f1336..faf6945a1 100644 --- a/src/views/debugView.ts +++ b/src/views/debugView.ts @@ -4,8 +4,8 @@ import { checkClientCertificate, debugKeyFileExists, remoteCertificatesExists } import { DebugConfiguration, getDebugServiceDetails, SERVICE_CERTIFICATE } from "../api/configuration/DebugConfiguration"; import { DebugJob, getDebugServerJob, getDebugServiceJob, isDebugEngineRunning, readActiveJob, readJVMInfo, startServer, startService, stopServer, stopService } from "../debug/server"; import { instance } from "../instantiate"; -import { BrowserItem } from "../typings"; import { withContext } from "./tools"; +import { BrowserItem } from "./types"; const title = "IBM i debugger"; type Certificates = { diff --git a/src/views/ifsBrowser.ts b/src/views/ifsBrowser.ts index f4a6b9fd8..efc8a163a 100644 --- a/src/views/ifsBrowser.ts +++ b/src/views/ifsBrowser.ts @@ -7,9 +7,10 @@ import { SortOptions } from "../api/IBMiContent"; import { Search } from "../api/Search"; import { Tools } from "../api/Tools"; import { instance } from "../instantiate"; -import { BrowserItem, BrowserItemParameters, FocusOptions, IFSFile, IFS_BROWSER_MIMETYPE, OBJECT_BROWSER_MIMETYPE, SearchHit, SearchResults, WithPath } from "../typings"; +import { FocusOptions, IFSFile, IFS_BROWSER_MIMETYPE, OBJECT_BROWSER_MIMETYPE, SearchHit, SearchResults, WithPath } from "../typings"; import { fileToPath, findUriTabs, ifsFileToToolTip } from "./tools"; import IBMi from "../api/IBMi"; +import { BrowserItem, BrowserItemParameters } from "./types"; const URI_LIST_MIMETYPE = "text/uri-list"; const URI_LIST_SEPARATOR = "\r\n"; diff --git a/src/views/objectBrowser.ts b/src/views/objectBrowser.ts index e6356b270..58f95065b 100644 --- a/src/views/objectBrowser.ts +++ b/src/views/objectBrowser.ts @@ -2,7 +2,6 @@ import fs, { existsSync } from "fs"; import os from "os"; import path, { basename, dirname } from "path"; import vscode from "vscode"; -import { DefaultOpenMode } from "../config/Configuration"; import { parseFilter, singleGenericName } from "../api/Filter"; import IBMi, { MemberParts } from "../api/IBMi"; import { SortOptions, SortOrder } from "../api/IBMiContent"; @@ -10,10 +9,11 @@ import { Search } from "../api/Search"; import { Tools } from "../api/Tools"; import { getMemberUri } from "../filesystems/qsys/QSysFs"; import { instance } from "../instantiate"; -import { BrowserItem, BrowserItemParameters, CommandResult, FilteredItem, FocusOptions, IBMiMember, IBMiObject, MemberItem, OBJECT_BROWSER_MIMETYPE, ObjectItem, WithLibrary } from "../typings"; +import { CommandResult, FilteredItem, FocusOptions, IBMiMember, IBMiObject, MemberItem, OBJECT_BROWSER_MIMETYPE, ObjectItem, WithLibrary } from "../typings"; import { editFilter } from "../webviews/filters"; import { findUriTabs, memberToToolTip, objectToToolTip, sourcePhysicalFileToToolTip } from "./tools"; -import { ObjectFilters } from "../api/configuration/ConnectionManager"; +import { DefaultOpenMode, ObjectFilters } from "../api/configuration/ConnectionManager"; +import { BrowserItem, BrowserItemParameters } from "./types"; const URI_LIST_SEPARATOR = "\r\n"; diff --git a/src/views/searchView.ts b/src/views/searchView.ts index 57d5fd5e2..6ac3aa9af 100644 --- a/src/views/searchView.ts +++ b/src/views/searchView.ts @@ -1,7 +1,7 @@ import path from 'path'; import vscode from "vscode"; -import { DefaultOpenMode } from "../config/Configuration"; import { SearchHit, SearchHitLine, SearchResults, WithPath } from "../typings"; +import { DefaultOpenMode } from '../api/configuration/ConnectionManager'; export function initializeSearchView(context: vscode.ExtensionContext) { const searchView = new SearchView(); diff --git a/src/views/tools.ts b/src/views/tools.ts index 363f13516..5556ace54 100644 --- a/src/views/tools.ts +++ b/src/views/tools.ts @@ -2,7 +2,7 @@ import Crypto from 'crypto'; import { readFileSync } from "fs"; import vscode, { MarkdownString } from "vscode"; -import { API, GitExtension } from "../api/import/git"; +import { API, GitExtension } from "../filesystems/local/gitApi"; import { Tools } from '../api/Tools'; import { IBMiObject, IBMiMember, IFSFile } from '../typings'; import IBMi from '../api/IBMi'; diff --git a/src/views/types.ts b/src/views/types.ts new file mode 100644 index 000000000..c68d18b44 --- /dev/null +++ b/src/views/types.ts @@ -0,0 +1,25 @@ +import { TreeItemCollapsibleState, TreeItem, ThemeIcon, ThemeColor, ProviderResult, MarkdownString } from "vscode" +import { FocusOptions } from "../api/types" + +export type BrowserItemParameters = { + icon?: string + color?: string + state?: TreeItemCollapsibleState + parent?: BrowserItem +} + +export class BrowserItem extends TreeItem { + constructor(label: string, readonly params?: BrowserItemParameters) { + super(label, params?.state); + this.iconPath = params?.icon ? new ThemeIcon(params.icon, params.color ? new ThemeColor(params.color) : undefined) : undefined; + } + + get parent() { + return this.params?.parent; + } + + getChildren?(): ProviderResult; + refresh?(): void; + reveal?(options?: FocusOptions): Thenable; + getToolTip?(): Promise; +} \ No newline at end of file diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 000000000..c22fd1b0c --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,13 @@ +/// +import { defineConfig } from 'vite' + +export default defineConfig({ + test: { + // ... Specify options here. + fileParallelism: false, + root: './src/api', + setupFiles: [ + 'tests/globalSetup.ts', + ], + }, +}) \ No newline at end of file From 89249fc34b62ea5caa27f1df9d2203208c066c59 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Wed, 15 Jan 2025 09:43:11 -0500 Subject: [PATCH 21/46] Remove last entanglements Signed-off-by: worksofliam --- src/api/IBMi.ts | 2 +- src/{ => api}/components/cqsh/cqsh | Bin src/{ => api}/components/cqsh/cqsh.c | 0 src/{ => api}/components/cqsh/index.ts | 20 ++++--- src/api/configuration/DebugConfiguration.ts | 62 +++++++++----------- src/debug/certificates.ts | 4 +- src/debug/index.ts | 12 ++-- src/debug/server.ts | 6 +- src/extension.ts | 10 +++- src/instantiate.ts | 29 ++++----- src/views/debugView.ts | 5 +- src/webviews/settings/index.ts | 2 +- 12 files changed, 80 insertions(+), 72 deletions(-) rename src/{ => api}/components/cqsh/cqsh (100%) rename src/{ => api}/components/cqsh/cqsh.c (100%) rename src/{ => api}/components/cqsh/index.ts (76%) diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index f7b6534bc..9c6c21f95 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -5,7 +5,7 @@ import os from "os"; import path, { parse as parsePath } from 'path'; import { IBMiComponent } from "./components/component"; import { CopyToImport } from "./components/copyToImport"; -import { CustomQSh } from '../components/cqsh'; +import { CustomQSh } from './components/cqsh'; import { ComponentManager } from "./components/manager"; import { CompileTools } from "./CompileTools"; import IBMiContent from "./IBMiContent"; diff --git a/src/components/cqsh/cqsh b/src/api/components/cqsh/cqsh similarity index 100% rename from src/components/cqsh/cqsh rename to src/api/components/cqsh/cqsh diff --git a/src/components/cqsh/cqsh.c b/src/api/components/cqsh/cqsh.c similarity index 100% rename from src/components/cqsh/cqsh.c rename to src/api/components/cqsh/cqsh.c diff --git a/src/components/cqsh/index.ts b/src/api/components/cqsh/index.ts similarity index 76% rename from src/components/cqsh/index.ts rename to src/api/components/cqsh/index.ts index 7adf0f735..5c70143ca 100644 --- a/src/components/cqsh/index.ts +++ b/src/api/components/cqsh/index.ts @@ -1,12 +1,17 @@ import { stat } from "fs/promises"; import path from "path"; -import { extensions } from "vscode"; -import IBMi from "../../api/IBMi"; -import { ComponentState, IBMiComponent } from "../../api/components/component"; +import IBMi from "../../IBMi"; +import { ComponentState, IBMiComponent } from "../component"; export class CustomQSh implements IBMiComponent { static ID = "cqsh"; + private localAssetPath: string|undefined; + + setLocalAssetPath(newPath: string) { + this.localAssetPath = newPath; + } + installPath = ""; getIdentification() { @@ -36,16 +41,17 @@ export class CustomQSh implements IBMiComponent { } async update(connection: IBMi): Promise { - const extensionPath = extensions.getExtension(`halcyontechltd.code-for-ibmi`)!.extensionPath; + if (!this.localAssetPath) { + return `Error`; + } - const assetPath = path.join(extensionPath, `dist`, this.getFileName()); - const assetExistsLocally = await exists(assetPath); + const assetExistsLocally = await exists(this.localAssetPath); if (!assetExistsLocally) { return `Error`; } - await connection.getContent().uploadFiles([{ local: assetPath, remote: this.installPath }]); + await connection.getContent().uploadFiles([{ local: this.localAssetPath, remote: this.installPath }]); await connection.sendCommand({ command: `chmod +x ${this.installPath}`, diff --git a/src/api/configuration/DebugConfiguration.ts b/src/api/configuration/DebugConfiguration.ts index 107b5e3f3..5aa2352bb 100644 --- a/src/api/configuration/DebugConfiguration.ts +++ b/src/api/configuration/DebugConfiguration.ts @@ -1,5 +1,4 @@ import path from "path"; -import { instance } from "../../instantiate"; import IBMi from "../IBMi"; export const SERVICE_CERTIFICATE = `debug_service.pfx`; @@ -133,7 +132,7 @@ export function resetDebugServiceDetails() { debugServiceDetails = undefined; } -export async function getDebugServiceDetails(): Promise { +export async function getDebugServiceDetails(connection: IBMi): Promise { if (!debugServiceDetails) { let details = { version: `1.0.0`, @@ -145,40 +144,37 @@ export async function getDebugServiceDetails(): Promise { }) }; - const connection = instance.getConnection(); - if (connection) { - const content = connection.getContent(); - const detailFilePath = path.posix.join((await new DebugConfiguration(connection).load()).getRemoteServiceRoot(), `package.json`); - const detailExists = await content.testStreamFile(detailFilePath, "r"); - if (detailExists) { - const fileContents = (await content.downloadStreamfileRaw(detailFilePath)).toString("utf-8"); - const parsed = JSON.parse(fileContents); - details = { - ...parsed as DebugServiceDetails, - semanticVersion: () => { - const parts = (parsed.version ? String(parsed.version).split('.') : []).map(Number); - return { - major: parts[0], - minor: parts[1], - patch: parts[2] - }; - } + const content = connection.getContent(); + const detailFilePath = path.posix.join((await new DebugConfiguration(connection).load()).getRemoteServiceRoot(), `package.json`); + const detailExists = await content.testStreamFile(detailFilePath, "r"); + if (detailExists) { + const fileContents = (await content.downloadStreamfileRaw(detailFilePath)).toString("utf-8"); + const parsed = JSON.parse(fileContents); + details = { + ...parsed as DebugServiceDetails, + semanticVersion: () => { + const parts = (parsed.version ? String(parsed.version).split('.') : []).map(Number); + return { + major: parts[0], + minor: parts[1], + patch: parts[2] + }; } } - else { - details = { - version: `1.0.0`, - java: `8`, - semanticVersion: () => ({ - major: 1, - minor: 0, - patch: 0 - }) - }; - } - - debugServiceDetails = details; } + else { + details = { + version: `1.0.0`, + java: `8`, + semanticVersion: () => ({ + major: 1, + minor: 0, + patch: 0 + }) + }; + } + + debugServiceDetails = details; } return debugServiceDetails!; diff --git a/src/debug/certificates.ts b/src/debug/certificates.ts index cbf87215e..5f5ce7f49 100644 --- a/src/debug/certificates.ts +++ b/src/debug/certificates.ts @@ -167,7 +167,7 @@ export async function setup(connection: IBMi, imported?: ImportedCertificate) { await debugConfig.save(); } - const javaVersion = (await getDebugServiceDetails()).java; + const javaVersion = (await getDebugServiceDetails(connection)).java; const javaHome = getJavaHome(connection, javaVersion); if (!javaHome) { @@ -267,7 +267,7 @@ export async function sanityCheck(connection: IBMi, content: IBMiContent) { //Check if java home needs to be updated if the service got updated (e.g: v1 uses Java 8 and v2 uses Java 11) const javaHome = debugConfig.get("JAVA_HOME"); - const expectedJavaHome = getJavaHome(connection, (await getDebugServiceDetails()).java); + const expectedJavaHome = getJavaHome(connection, (await getDebugServiceDetails(connection)).java); if (javaHome && expectedJavaHome && javaHome !== expectedJavaHome) { if (await content.testStreamFile(DEBUG_CONFIG_FILE, "w")) { //Automatically make the change if possible diff --git a/src/debug/index.ts b/src/debug/index.ts index 0d7e507fd..db3f6a9e6 100644 --- a/src/debug/index.ts +++ b/src/debug/index.ts @@ -378,15 +378,15 @@ export async function initialize(context: ExtensionContext) { async () => { activateDebugExtension(); const connection = instance.getConnection(); - const content = instance.getContent(); - if (connection && content && server.debugPTFInstalled()) { + if (connection && server.debugPTFInstalled()) { + const content = connection.getContent(); vscode.commands.executeCommand(`setContext`, ptfContext, true); //Enable debug related commands vscode.commands.executeCommand(`setContext`, debugContext, true); //Enable service entry points related commands - vscode.commands.executeCommand(`setContext`, debugSEPContext, await server.isSEPSupported()); + vscode.commands.executeCommand(`setContext`, debugSEPContext, await server.isSEPSupported(connection)); const isDebugManaged = isManaged(); vscode.commands.executeCommand(`setContext`, `code-for-ibmi:debugManaged`, isDebugManaged); @@ -434,11 +434,11 @@ type DebugType = "batch" | "sep"; type DebugObjectType = "*PGM" | "*SRVPGM"; export async function startDebug(instance: Instance, options: DebugOptions) { - const connection = instance.getConnection(); - const config = instance.getConfig(); + const connection = instance.getConnection()!; + const config = connection.getConfig(); const storage = instance.getStorage(); - const serviceDetails = await getDebugServiceDetails(); + const serviceDetails = await getDebugServiceDetails(connection); const port = config?.debugPort; const updateProductionFiles = config?.debugUpdateProductionFiles; diff --git a/src/debug/server.ts b/src/debug/server.ts index 103c3b0be..2098939c8 100644 --- a/src/debug/server.ts +++ b/src/debug/server.ts @@ -15,8 +15,8 @@ export function debugPTFInstalled() { return instance.getConnection()?.debugPTFInstalled() } -export async function isSEPSupported() { - return (await getDebugServiceDetails()).semanticVersion().major > 1; +export async function isSEPSupported(connection: IBMi) { + return (await getDebugServiceDetails(connection)).semanticVersion().major > 1; } export async function startService(connection: IBMi) { @@ -28,7 +28,7 @@ export async function startService(connection: IBMi) { try { await checkAuthority(); - const debugServiceVersion = (await getDebugServiceDetails()).semanticVersion(); + const debugServiceVersion = (await getDebugServiceDetails(connection)).semanticVersion(); const prestartCommand = (debugServiceVersion.major >= 2 && debugServiceVersion.patch >= 1) ? `export DEBUG_SERVICE_EXTERNAL_CONFIG_FILE=${DEBUG_CONFIG_FILE}` : `cp ${DEBUG_CONFIG_FILE} ${ORIGINAL_DEBUG_CONFIG_FILE}` diff --git a/src/extension.ts b/src/extension.ts index 1fea4c7a7..ae42e1667 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,5 +1,5 @@ // The module 'vscode' contains the VS Code extensibility API -import { ExtensionContext, commands, languages, window, workspace } from "vscode"; +import { ExtensionContext, commands, extensions, languages, window, workspace } from "vscode"; // this method is called when your extension is activated // your extension is activated the very first time the command is executed @@ -13,7 +13,7 @@ import { parseErrors } from "./api/errors/parser"; import { DeployTools } from "./filesystems/local/deployTools"; import { Deployment } from "./filesystems/local/deployment"; import { CopyToImport } from "./api/components/copyToImport"; -import { CustomQSh } from "./components/cqsh"; +import { CustomQSh } from "./api/components/cqsh"; import { GetMemberInfo } from "./api/components/getMemberInfo"; import { GetNewLibl } from "./api/components/getNewLibl"; import { extensionComponentRegistry } from "./api/components/manager"; @@ -33,6 +33,7 @@ import { initializeSearchView } from "./views/searchView"; import { SettingsUI } from "./webviews/settings"; import { registerActionTools } from "./views/actions"; import IBMi from "./api/IBMi"; +import path from "path"; export async function activate(context: ExtensionContext): Promise { // Use the console to output diagnostic information (console.log) and errors (console.error) @@ -112,7 +113,10 @@ export async function activate(context: ExtensionContext): Promise commands.executeCommand("code-for-ibmi.refreshProfileView"); }); - extensionComponentRegistry.registerComponent(context, new CustomQSh()); + const customQsh = new CustomQSh(); + customQsh.setLocalAssetPath(path.join(context.extensionPath, `dist`, customQsh.getFileName())); + + extensionComponentRegistry.registerComponent(context, customQsh); extensionComponentRegistry.registerComponent(context, new GetNewLibl); extensionComponentRegistry.registerComponent(context, new GetMemberInfo()); extensionComponentRegistry.registerComponent(context, new CopyToImport()); diff --git a/src/instantiate.ts b/src/instantiate.ts index 1b59a088e..ec69883ea 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -109,22 +109,23 @@ export async function loadAllofExtension(context: vscode.ExtensionContext) { } async function updateConnectedBar() { - const config = instance.getConnection()?.getConfig(); - if (config) { + const connection = instance.getConnection(); + if (connection) { + const config = connection.getConfig(); connectedBarItem.text = `$(${config.readOnlyMode ? "lock" : "settings-gear"}) ${config.name}`; - } - const debugRunning = await isDebugEngineRunning(); - connectedBarItem.tooltip = new vscode.MarkdownString([ - `[$(settings-gear) Settings](command:code-for-ibmi.showAdditionalSettings)`, - `[$(file-binary) Actions](command:code-for-ibmi.showActionsMaintenance)`, - `[$(terminal) Terminals](command:code-for-ibmi.launchTerminalPicker)`, - debugPTFInstalled() ? - `[$(${debugRunning ? "bug" : "debug"}) Debugger ${((await getDebugServiceDetails()).version)} (${debugRunning ? "on" : "off"})](command:ibmiDebugBrowser.focus)` - : - `[$(debug) No debug PTF](https://codefori.github.io/docs/developing/debug/#required-ptfs)` - ].join(`\n\n---\n\n`), true); - connectedBarItem.tooltip.isTrusted = true; + const debugRunning = await isDebugEngineRunning(); + connectedBarItem.tooltip = new vscode.MarkdownString([ + `[$(settings-gear) Settings](command:code-for-ibmi.showAdditionalSettings)`, + `[$(file-binary) Actions](command:code-for-ibmi.showActionsMaintenance)`, + `[$(terminal) Terminals](command:code-for-ibmi.launchTerminalPicker)`, + debugPTFInstalled() ? + `[$(${debugRunning ? "bug" : "debug"}) Debugger ${((await getDebugServiceDetails(connection)).version)} (${debugRunning ? "on" : "off"})](command:ibmiDebugBrowser.focus)` + : + `[$(debug) No debug PTF](https://codefori.github.io/docs/developing/debug/#required-ptfs)` + ].join(`\n\n---\n\n`), true); + connectedBarItem.tooltip.isTrusted = true; + } } async function onConnected() { diff --git a/src/views/debugView.ts b/src/views/debugView.ts index faf6945a1..68e94305d 100644 --- a/src/views/debugView.ts +++ b/src/views/debugView.ts @@ -29,8 +29,9 @@ export function initializeDebugBrowser(context: vscode.ExtensionContext) { }); const updateDebugBrowser = async () => { - if (instance.getConnection()) { - debugTreeViewer.title = `${title} ${(await getDebugServiceDetails()).version}` + const connection = instance.getConnection(); + if (connection) { + debugTreeViewer.title = `${title} ${(await getDebugServiceDetails(connection)).version}` debugTreeViewer.description = await isDebugEngineRunning() ? vscode.l10n.t(`Online`) : vscode.l10n.t(`Offline`); } else { diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 6ece37d77..1c99e5a07 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -183,7 +183,7 @@ export class SettingsUI { const debugServiceConfig: Map = new Map() .set("Debug port", config.debugPort); - if (await isSEPSupported()) { + if (await isSEPSupported(connection)) { debugServiceConfig.set("SEP debug port", config.debugSepPort) } debuggerTab.addParagraph(`
    ${Array.from(debugServiceConfig.entries()).map(([label, value]) => `
  • ${label}: ${value}
  • `).join("")}
`); From 01b8f52f8751ca8dd0ca5997e634c1b2255d5a6a Mon Sep 17 00:00:00 2001 From: worksofliam Date: Wed, 15 Jan 2025 09:56:50 -0500 Subject: [PATCH 22/46] Working connection test! Signed-off-by: worksofliam --- .env | 9 ------ .gitignore | 3 +- src/api/configuration/Storage.ts | 14 +++++++-- src/api/tests/globalSetup.ts | 50 ++++++++++++++++++++++---------- src/config/Storage.ts | 4 +-- 5 files changed, 50 insertions(+), 30 deletions(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index 087785656..000000000 --- a/.env +++ /dev/null @@ -1,9 +0,0 @@ -# defaults to localhost -#VITE_SERVER=UT201P18.RCH.STGLABS.IBM.COM -VITE_SERVER=iopen.iinthecloud.com - -# defaults to 8076 -VITE_PORT=22 - -VITE_DB_USER=SNDBX3 -VITE_DB_PASS=SNDBX3 \ No newline at end of file diff --git a/.gitignore b/.gitignore index ee00f7354..4efa68684 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules .vscode-test/ *.vsix dist -.DS_Store \ No newline at end of file +.DS_Store +.env \ No newline at end of file diff --git a/src/api/configuration/Storage.ts b/src/api/configuration/Storage.ts index e44c88879..d7d38a42e 100644 --- a/src/api/configuration/Storage.ts +++ b/src/api/configuration/Storage.ts @@ -43,7 +43,7 @@ export type CachedServerSettings = { maximumArgsLength: number } | undefined; -export abstract class Storage { +export abstract class BaseStorage { protected readonly globalState: any; constructor() { @@ -67,6 +67,14 @@ export abstract class Storage { } } +export class VirtualStorage extends BaseStorage { + protected readonly globalState: Map = new Map(); + + constructor() { + super(); + } +} + export class CodeForIStorage { // private static instance: GlobalStorage; @@ -80,7 +88,7 @@ export class CodeForIStorage { // return this.instance; // } - constructor(private internalStorage: Storage) {} + constructor(private internalStorage: BaseStorage) {} protected getStorageKey(key: string): string { return key; @@ -161,7 +169,7 @@ export class CodeForIStorage { export class ConnectionStorage { private connectionName: string = ""; - constructor(private internalStorage: Storage) {} + constructor(private internalStorage: BaseStorage) {} get ready(): boolean { if (this.connectionName) { diff --git a/src/api/tests/globalSetup.ts b/src/api/tests/globalSetup.ts index 81c9264d7..a47580ab3 100644 --- a/src/api/tests/globalSetup.ts +++ b/src/api/tests/globalSetup.ts @@ -1,24 +1,31 @@ import assert from "assert"; import IBMi from "../IBMi"; import { ENV_CREDS } from "./env"; -import { setConnection } from "./state"; -import { vi } from "vitest"; +import { getConnection, setConnection } from "./state"; +import { afterAll, beforeAll, expect } from "vitest"; +import { CodeForIStorage, ConnectionStorage, VirtualStorage } from "../configuration/Storage"; +import { VirtualConfig } from "../configuration/Config"; -export default async function setup() { - // vi.mock(import(`vscode`), async (importOriginal) => { - // return {} - // }); +beforeAll(async () => { + const virtualStorage = new VirtualStorage(); + + IBMi.GlobalStorage = new CodeForIStorage(virtualStorage); + IBMi.connectionManager.configMethod = new VirtualConfig(); const conn = new IBMi(); + const creds = { + host: ENV_CREDS.host!, + name: `testsystem`, + username: ENV_CREDS.user!, + password: ENV_CREDS.password!, + port: ENV_CREDS.port + }; + + console.log(creds); + const result = await conn.connect( - { - host: ENV_CREDS.host!, - name: `testsystem`, - username: ENV_CREDS.user!, - password: ENV_CREDS.password!, - port: ENV_CREDS.port - }, + creds, { message: (type: string, message: string) => { console.log(`${type.padEnd(10)} ${message}`); @@ -33,7 +40,20 @@ export default async function setup() { } ); - assert.ok(result.success); + console.log(result); + expect(result).toBeDefined(); setConnection(conn); -} + + console.log('hi'); +}, 25000); + +afterAll(async () => { + const conn = getConnection(); + + if (conn) { + await conn.dispose(); + } else { + assert.fail(`Connection was not set`); + } +}) \ No newline at end of file diff --git a/src/config/Storage.ts b/src/config/Storage.ts index e547a6f33..c6ef17704 100644 --- a/src/config/Storage.ts +++ b/src/config/Storage.ts @@ -1,7 +1,7 @@ import * as vscode from 'vscode'; -import { Storage } from '../api/configuration/Storage'; +import { BaseStorage } from '../api/configuration/Storage'; -export class VsStorage extends Storage { +export class VsStorage extends BaseStorage { declare protected readonly globalState; private connectionName: string = ""; From 78c1cbba0ac262286d4cca11c7376c4119708be9 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Wed, 15 Jan 2025 10:02:32 -0500 Subject: [PATCH 23/46] Update test script to run vitest and suppress console output in global setup Signed-off-by: worksofliam --- package.json | 2 +- src/api/tests/globalSetup.ts | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 829283e2c..eb0432b66 100644 --- a/package.json +++ b/package.json @@ -2955,7 +2955,7 @@ "scripts": { "lint": "eslint src/**/*.js --no-error-on-unmatched-pattern", "pretest": "npm run lint", - "test": "vitest", + "test": "vitest run", "package": "vsce package", "build": "rm -rf dist && tsc", "vscode:prepublish": "webpack --mode production", diff --git a/src/api/tests/globalSetup.ts b/src/api/tests/globalSetup.ts index a47580ab3..5707afcd2 100644 --- a/src/api/tests/globalSetup.ts +++ b/src/api/tests/globalSetup.ts @@ -22,16 +22,17 @@ beforeAll(async () => { port: ENV_CREDS.port }; - console.log(creds); + // Override this so not to spam the console. + conn.appendOutput = (data) => {}; const result = await conn.connect( creds, { message: (type: string, message: string) => { - console.log(`${type.padEnd(10)} ${message}`); + // console.log(`${type.padEnd(10)} ${message}`); }, progress: ({message}) => { - console.log(`PROGRESS: ${message}`); + // console.log(`PROGRESS: ${message}`); }, uiErrorHandler: async (connection, code, data) => { console.log(`UI ERROR: ${code}: ${data}`); @@ -40,12 +41,9 @@ beforeAll(async () => { } ); - console.log(result); expect(result).toBeDefined(); + expect(result.success).toBeTruthy(); - setConnection(conn); - - console.log('hi'); }, 25000); afterAll(async () => { From c792c8d09d1d040223e71341a9ca778fa5942575 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Wed, 15 Jan 2025 10:06:19 -0500 Subject: [PATCH 24/46] Remove unused TypeScript configuration and set connection in global setup Signed-off-by: worksofliam --- src/api/tests.tsconfig.json | 5 ----- src/api/tests/globalSetup.ts | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) delete mode 100644 src/api/tests.tsconfig.json diff --git a/src/api/tests.tsconfig.json b/src/api/tests.tsconfig.json deleted file mode 100644 index cb2bea875..000000000 --- a/src/api/tests.tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "include": [ - "." - ] -} \ No newline at end of file diff --git a/src/api/tests/globalSetup.ts b/src/api/tests/globalSetup.ts index 5707afcd2..c981ff6d6 100644 --- a/src/api/tests/globalSetup.ts +++ b/src/api/tests/globalSetup.ts @@ -44,6 +44,7 @@ beforeAll(async () => { expect(result).toBeDefined(); expect(result.success).toBeTruthy(); + setConnection(conn); }, 25000); afterAll(async () => { From 10c1de7088317fab8e1cd3981848af6a84430ca4 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Wed, 15 Jan 2025 10:12:00 -0500 Subject: [PATCH 25/46] Add cancellation support to connection progress with EventEmitter Signed-off-by: worksofliam --- src/Instance.ts | 13 ++++++++++--- src/api/IBMi.ts | 21 ++++++++++++++------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/Instance.ts b/src/Instance.ts index d212a4946..41bfabd40 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -7,6 +7,7 @@ import { handleConnectionResults, messageCallback } from "./views/connection"; import { VsStorage } from "./config/Storage"; import { VsCodeConfig } from "./config/Configuration"; import { ConnectionConfig } from "./api/configuration/ConnectionManager"; +import { EventEmitter } from "stream"; type IBMiEventSubscription = { func: Function, @@ -80,8 +81,14 @@ export default class Instance { return withContext("code-for-ibmi:connecting", async () => { while (true) { let customError: string|undefined; - await vscode.window.withProgress({location: vscode.ProgressLocation.Notification, title: `Code for IBM i`}, async (p) => { + await vscode.window.withProgress({location: vscode.ProgressLocation.Notification, title: `Code for IBM i`, cancellable: true}, async (p, cancelToken) => { try { + const cancelEmitter = new EventEmitter(); + + cancelToken.onCancellationRequested(() => { + cancelEmitter.emit(`cancel`); + }); + result = await connection.connect( options.data, { @@ -90,10 +97,10 @@ export default class Instance { uiErrorHandler: handleConnectionResults, progress: (message) => {p.report(message)}, message: messageCallback, + cancelEmitter }, options.reconnecting, - options.reloadServerSettings, - + options.reloadServerSettings, ); } catch (e: any) { customError = e.message; diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 9c6c21f95..3ee226e73 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -15,6 +15,7 @@ import * as configVars from './configVars'; import { DebugConfiguration } from "./configuration/DebugConfiguration"; import { ConnectionManager, ConnectionConfig } from './configuration/ConnectionManager'; import { CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, WrapResult } from './types'; +import { EventEmitter } from 'stream'; export interface MemberParts extends IBMiMember { basename: string @@ -58,7 +59,8 @@ interface ConnectionCallbacks{ timeoutCallback?: (conn: IBMi) => Promise, uiErrorHandler: (connection: IBMi, error: ConnectionErrorCode, data?: any) => Promise, progress: (detail: {message: string}) => void, - message: (type: ConnectionMessageType, message: string) => void + message: (type: ConnectionMessageType, message: string) => void, + cancelEmitter?: EventEmitter, } export default class IBMi { @@ -228,9 +230,14 @@ export default class IBMi { privateKeyPath: connectionObject.privateKeyPath ? Tools.resolvePath(connectionObject.privateKeyPath) : undefined } as node_ssh.Config); - // cancelToken.onCancellationRequested(() => { - // this.dispose(); - // }); + let wasCancelled = false; + + if (callbacks.cancelEmitter) { + callbacks.cancelEmitter.once('cancel', () => { + wasCancelled = true; + this.dispose(); + }); + } this.currentConnectionName = connectionObject.name; this.currentHost = connectionObject.host; @@ -276,9 +283,9 @@ export default class IBMi { if (callbacks.timeoutCallback) { const timeoutCallbackWrapper = () => { // Don't call the callback function if it was based on a user cancellation request. - // if (!cancelToken.isCancellationRequested) { - // callbacks.timeoutCallback!(this); - // } + if (!wasCancelled) { + callbacks.timeoutCallback!(this); + } } // Register handlers after we might have to abort due to bad configuration. From e582b1eb8e2e87b7afe9c93a86118e966074ec1d Mon Sep 17 00:00:00 2001 From: worksofliam Date: Wed, 15 Jan 2025 10:23:49 -0500 Subject: [PATCH 26/46] Rename views to ui Signed-off-by: worksofliam --- src/Instance.ts | 4 ++-- src/commands/actions.ts | 6 +++--- src/commands/open.ts | 2 +- src/debug/certificates.ts | 2 +- src/debug/index.ts | 2 +- src/extension.ts | 18 +++++++++--------- src/filesystems/local/deployTools.ts | 2 +- src/filesystems/local/git.ts | 2 +- src/filesystems/qsys/FSUtils.ts | 2 +- src/instantiate.ts | 2 +- src/sandbox.ts | 2 +- src/testing/action.ts | 2 +- src/testing/deployTools.ts | 4 ++-- src/typings.ts | 2 +- src/{views => ui}/Terminal.ts | 0 src/{views => ui}/actions.ts | 0 src/{views => ui}/connection.ts | 0 src/{views => ui}/diagnostics.ts | 0 src/{views => ui}/tools.ts | 0 src/{views => ui}/types.ts | 0 src/{ => ui}/views/ConnectionBrowser.ts | 12 ++++++------ src/{ => ui}/views/LibraryListView.ts | 10 +++++----- src/{ => ui}/views/ProfilesView.ts | 12 ++++++------ src/{ => ui}/views/debugView.ts | 14 +++++++------- src/{ => ui}/views/helpView.ts | 6 +++--- src/{ => ui}/views/ifsBrowser.ts | 16 ++++++++-------- src/{ => ui}/views/objectBrowser.ts | 24 ++++++++++++------------ src/{ => ui}/views/searchView.ts | 4 ++-- src/webviews/settings/index.ts | 2 +- 29 files changed, 76 insertions(+), 76 deletions(-) rename src/{views => ui}/Terminal.ts (100%) rename src/{views => ui}/actions.ts (100%) rename src/{views => ui}/connection.ts (100%) rename src/{views => ui}/diagnostics.ts (100%) rename src/{views => ui}/tools.ts (100%) rename src/{views => ui}/types.ts (100%) rename src/{ => ui}/views/ConnectionBrowser.ts (97%) rename src/{ => ui}/views/LibraryListView.ts (98%) rename src/{ => ui}/views/ProfilesView.ts (97%) rename src/{ => ui}/views/debugView.ts (96%) rename src/{ => ui}/views/helpView.ts (98%) rename src/{ => ui}/views/ifsBrowser.ts (99%) rename src/{ => ui}/views/objectBrowser.ts (98%) rename src/{ => ui}/views/searchView.ts (98%) diff --git a/src/Instance.ts b/src/Instance.ts index 41bfabd40..ee74f5542 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -2,8 +2,8 @@ import * as vscode from "vscode"; import { ConnectionData, IBMiEvent } from "./typings"; import IBMi, { ConnectionResult } from "./api/IBMi"; import { CodeForIStorage, ConnectionStorage } from "./api/configuration/Storage"; -import { withContext } from "./views/tools"; -import { handleConnectionResults, messageCallback } from "./views/connection"; +import { withContext } from "./ui/tools"; +import { handleConnectionResults, messageCallback } from "./ui/connection"; import { VsStorage } from "./config/Storage"; import { VsCodeConfig } from "./config/Configuration"; import { ConnectionConfig } from "./api/configuration/ConnectionManager"; diff --git a/src/commands/actions.ts b/src/commands/actions.ts index 48001d1f3..f816dc1d0 100644 --- a/src/commands/actions.ts +++ b/src/commands/actions.ts @@ -1,11 +1,11 @@ import path from "path"; import { commands, TreeItem, Uri, WorkspaceFolder, window, Disposable } from "vscode"; -import { refreshDiagnosticsFromServer } from "../views/diagnostics"; +import { refreshDiagnosticsFromServer } from "../ui/diagnostics"; import Instance from "../Instance"; import { Action, DeploymentMethod } from "../typings"; -import { runAction } from "../views/actions"; +import { runAction } from "../ui/actions"; import IBMi from "../api/IBMi"; -import { BrowserItem } from "../views/types"; +import { BrowserItem } from "../ui/types"; export function registerActionsCommands(instance: Instance): Disposable[] { return [ diff --git a/src/commands/open.ts b/src/commands/open.ts index 03a15c7ca..38f05dd6c 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -4,7 +4,7 @@ import Instance from "../Instance"; import { Tools } from "../api/Tools"; import { getUriFromPath, parseFSOptions } from "../filesystems/qsys/QSysFs"; import path from "path"; -import { findExistingDocument, findExistingDocumentUri } from "../views/tools"; +import { findExistingDocument, findExistingDocumentUri } from "../ui/tools"; import IBMi from "../api/IBMi"; import { DefaultOpenMode } from "../api/configuration/ConnectionManager"; diff --git a/src/debug/certificates.ts b/src/debug/certificates.ts index 5f5ce7f49..dd333b63c 100644 --- a/src/debug/certificates.ts +++ b/src/debug/certificates.ts @@ -8,7 +8,7 @@ import { instance } from '../instantiate'; import IBMi from "../api/IBMi"; import IBMiContent from '../api/IBMiContent'; import { Tools } from '../api/Tools'; -import { fileToPath } from '../views/tools'; +import { fileToPath } from '../ui/tools'; import { DebugConfiguration, SERVICE_CERTIFICATE, CLIENT_CERTIFICATE, getDebugServiceDetails, getJavaHome, DEBUG_CONFIG_FILE, LEGACY_CERT_DIRECTORY } from '../api/configuration/DebugConfiguration'; type HostInfo = { diff --git a/src/debug/index.ts b/src/debug/index.ts index db3f6a9e6..a2ef1e518 100644 --- a/src/debug/index.ts +++ b/src/debug/index.ts @@ -11,7 +11,7 @@ import { Env, getEnvConfig } from "../filesystems/local/env"; import * as certificates from "./certificates"; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, resetDebugServiceDetails } from "../api/configuration/DebugConfiguration"; import * as server from "./server"; -import { withContext } from "../views/tools"; +import { withContext } from "../ui/tools"; import { getStoredPassword } from "../config/passwords"; const debugExtensionId = `IBM.ibmidebug`; diff --git a/src/extension.ts b/src/extension.ts index ae42e1667..115309c41 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -22,16 +22,16 @@ import { LocalActionCompletionItemProvider } from "./languages/actions/completio import * as Sandbox from "./sandbox"; import { initialise } from "./testing"; import { CodeForIBMi, ConnectionData } from "./typings"; -import { initializeConnectionBrowser } from "./views/ConnectionBrowser"; -import { LibraryListProvider } from "./views/LibraryListView"; -import { ProfilesView } from "./views/ProfilesView"; -import { initializeDebugBrowser } from "./views/debugView"; -import { HelpView } from "./views/helpView"; -import { initializeIFSBrowser } from "./views/ifsBrowser"; -import { initializeObjectBrowser } from "./views/objectBrowser"; -import { initializeSearchView } from "./views/searchView"; +import { initializeConnectionBrowser } from "./ui/views/ConnectionBrowser"; +import { LibraryListProvider } from "./ui/views/LibraryListView"; +import { ProfilesView } from "./ui/views/ProfilesView"; +import { initializeDebugBrowser } from "./ui/views/debugView"; +import { HelpView } from "./ui/views/helpView"; +import { initializeIFSBrowser } from "./ui/views/ifsBrowser"; +import { initializeObjectBrowser } from "./ui/views/objectBrowser"; +import { initializeSearchView } from "./ui/views/searchView"; import { SettingsUI } from "./webviews/settings"; -import { registerActionTools } from "./views/actions"; +import { registerActionTools } from "./ui/actions"; import IBMi from "./api/IBMi"; import path from "path"; diff --git a/src/filesystems/local/deployTools.ts b/src/filesystems/local/deployTools.ts index edf352972..3c08c51cd 100644 --- a/src/filesystems/local/deployTools.ts +++ b/src/filesystems/local/deployTools.ts @@ -4,7 +4,7 @@ import vscode, { Uri, WorkspaceFolder } from 'vscode'; import { instance } from '../../instantiate'; import { LocalLanguageActions } from './LocalLanguageActions'; import { Deployment } from './deployment'; -import { getGitAPI, md5Hash } from '../../views/tools'; +import { getGitAPI, md5Hash } from '../../ui/tools'; import { DeploymentMethod } from '../../api/types'; import { DeploymentParameters } from '../../typings'; diff --git a/src/filesystems/local/git.ts b/src/filesystems/local/git.ts index 42daf817a..5cb5fcf73 100644 --- a/src/filesystems/local/git.ts +++ b/src/filesystems/local/git.ts @@ -3,7 +3,7 @@ import { getBranchLibraryName } from "./env"; import { instance } from "../../instantiate"; import IBMi from "../../api/IBMi"; import IBMiContent from "../../api/IBMiContent"; -import { getGitAPI } from "../../views/tools"; +import { getGitAPI } from "../../ui/tools"; import { ConnectionConfig } from "../../api/configuration/ConnectionManager"; const lastBranch: { [workspaceUri: string]: string } = {}; diff --git a/src/filesystems/qsys/FSUtils.ts b/src/filesystems/qsys/FSUtils.ts index 6d3e40089..e0d5eb769 100644 --- a/src/filesystems/qsys/FSUtils.ts +++ b/src/filesystems/qsys/FSUtils.ts @@ -1,6 +1,6 @@ import path from "path"; import vscode, { l10n } from "vscode"; -import { findUriTabs } from "../../views/tools"; +import { findUriTabs } from "../../ui/tools"; import IBMi from "../../api/IBMi"; import { ReconnectMode } from "../../api/configuration/ConnectionManager"; diff --git a/src/instantiate.ts b/src/instantiate.ts index ec69883ea..2944b6b13 100644 --- a/src/instantiate.ts +++ b/src/instantiate.ts @@ -2,7 +2,7 @@ import * as vscode from "vscode"; import { onCodeForIBMiConfigurationChange } from "./config/Configuration"; import Instance from "./Instance"; -import { Terminal } from './views/Terminal'; +import { Terminal } from './ui/Terminal'; import { getDebugServiceDetails } from './api/configuration/DebugConfiguration'; import { debugPTFInstalled, isDebugEngineRunning } from './debug/server'; import { setupGitEventHandler } from './filesystems/local/git'; diff --git a/src/sandbox.ts b/src/sandbox.ts index d8bb0722e..81291d2d4 100644 --- a/src/sandbox.ts +++ b/src/sandbox.ts @@ -3,7 +3,7 @@ import querystring from "querystring"; import { commands, ExtensionContext, l10n, Uri, window } from "vscode"; import { instance } from "./instantiate"; import { ConnectionData } from "./typings"; -import { getGitAPI } from "./views/tools"; +import { getGitAPI } from "./ui/tools"; import IBMi from "./api/IBMi"; export async function registerUriHandler(context: ExtensionContext) { diff --git a/src/testing/action.ts b/src/testing/action.ts index ed16dba93..bdb708b8d 100644 --- a/src/testing/action.ts +++ b/src/testing/action.ts @@ -11,7 +11,7 @@ import { getMemberUri, getUriFromPath } from "../filesystems/qsys/QSysFs"; import { instance } from "../instantiate"; import { Action, IBMiObject } from "../typings"; import { File, Folder, createFolder } from "./deployTools"; -import { runAction } from "../views/actions"; +import { runAction } from "../ui/actions"; export const helloWorldProject: Folder = { name: `DeleteMe_${Tools.makeid()}`, diff --git a/src/testing/deployTools.ts b/src/testing/deployTools.ts index 4f6a13bf1..d1b687b5d 100644 --- a/src/testing/deployTools.ts +++ b/src/testing/deployTools.ts @@ -10,8 +10,8 @@ import { Tools } from "../api/Tools"; import { DeployTools } from "../filesystems/local/deployTools"; import { instance } from "../instantiate"; import { Action, DeploymentMethod } from "../typings"; -import { md5Hash } from "../views/tools"; -import { runAction } from "../views/actions"; +import { md5Hash } from "../ui/tools"; +import { runAction } from "../ui/actions"; type FileInfo = { md5: string diff --git a/src/typings.ts b/src/typings.ts index 5cec6d7d1..17c9dce00 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -38,5 +38,5 @@ export interface DeploymentParameters { } export * from "./api/types"; -export * from "./views/types"; +export * from "./ui/types"; export * from "./filesystems/local/types"; \ No newline at end of file diff --git a/src/views/Terminal.ts b/src/ui/Terminal.ts similarity index 100% rename from src/views/Terminal.ts rename to src/ui/Terminal.ts diff --git a/src/views/actions.ts b/src/ui/actions.ts similarity index 100% rename from src/views/actions.ts rename to src/ui/actions.ts diff --git a/src/views/connection.ts b/src/ui/connection.ts similarity index 100% rename from src/views/connection.ts rename to src/ui/connection.ts diff --git a/src/views/diagnostics.ts b/src/ui/diagnostics.ts similarity index 100% rename from src/views/diagnostics.ts rename to src/ui/diagnostics.ts diff --git a/src/views/tools.ts b/src/ui/tools.ts similarity index 100% rename from src/views/tools.ts rename to src/ui/tools.ts diff --git a/src/views/types.ts b/src/ui/types.ts similarity index 100% rename from src/views/types.ts rename to src/ui/types.ts diff --git a/src/views/ConnectionBrowser.ts b/src/ui/views/ConnectionBrowser.ts similarity index 97% rename from src/views/ConnectionBrowser.ts rename to src/ui/views/ConnectionBrowser.ts index 20f897196..f213bf6ab 100644 --- a/src/views/ConnectionBrowser.ts +++ b/src/ui/views/ConnectionBrowser.ts @@ -1,11 +1,11 @@ import vscode from 'vscode'; -import { ConnectionData, Server } from '../typings'; +import { ConnectionData, Server } from '../../typings'; -import { instance } from '../instantiate'; -import { Login } from '../webviews/login'; -import IBMi from '../api/IBMi'; -import { ConnectionConfig, ConnectionManager } from '../api/configuration/ConnectionManager'; -import { deleteStoredPassword, getStoredPassword, setStoredPassword } from '../config/passwords'; +import { instance } from '../../instantiate'; +import { Login } from '../../webviews/login'; +import IBMi from '../../api/IBMi'; +import { ConnectionConfig, ConnectionManager } from '../../api/configuration/ConnectionManager'; +import { deleteStoredPassword, getStoredPassword, setStoredPassword } from '../../config/passwords'; type CopyOperationItem = { label: string diff --git a/src/views/LibraryListView.ts b/src/ui/views/LibraryListView.ts similarity index 98% rename from src/views/LibraryListView.ts rename to src/ui/views/LibraryListView.ts index f44c406bb..6e654c089 100644 --- a/src/views/LibraryListView.ts +++ b/src/ui/views/LibraryListView.ts @@ -1,9 +1,9 @@ import vscode, { commands, l10n } from "vscode"; -import { instance } from "../instantiate"; -import { IBMiObject, WithLibrary } from "../typings"; -import { objectToToolTip } from "./tools"; -import { ConnectionConfig } from "../api/configuration/ConnectionManager"; -import IBMi from "../api/IBMi"; +import { instance } from "../../instantiate"; +import { IBMiObject, WithLibrary } from "../../typings"; +import { objectToToolTip } from "../tools"; +import { ConnectionConfig } from "../../api/configuration/ConnectionManager"; +import IBMi from "../../api/IBMi"; export class LibraryListProvider implements vscode.TreeDataProvider { private readonly _emitter: vscode.EventEmitter = new vscode.EventEmitter(); diff --git a/src/views/ProfilesView.ts b/src/ui/views/ProfilesView.ts similarity index 97% rename from src/views/ProfilesView.ts rename to src/ui/views/ProfilesView.ts index 2c90559d9..0727c166f 100644 --- a/src/views/ProfilesView.ts +++ b/src/ui/views/ProfilesView.ts @@ -1,11 +1,11 @@ import vscode, { l10n, window } from 'vscode'; -import { GetNewLibl } from '../api/components/getNewLibl'; -import { instance } from '../instantiate'; -import { Profile } from '../typings'; -import { CommandProfileUi } from '../webviews/commandProfile'; -import IBMi from '../api/IBMi'; -import { ConnectionProfile } from '../api/configuration/ConnectionManager'; +import { GetNewLibl } from '../../api/components/getNewLibl'; +import { instance } from '../../instantiate'; +import { Profile } from '../../typings'; +import { CommandProfileUi } from '../../webviews/commandProfile'; +import IBMi from '../../api/IBMi'; +import { ConnectionProfile } from '../../api/configuration/ConnectionManager'; export class ProfilesView { private _onDidChangeTreeData = new vscode.EventEmitter(); diff --git a/src/views/debugView.ts b/src/ui/views/debugView.ts similarity index 96% rename from src/views/debugView.ts rename to src/ui/views/debugView.ts index 68e94305d..840a0ca9a 100644 --- a/src/views/debugView.ts +++ b/src/ui/views/debugView.ts @@ -1,11 +1,11 @@ import vscode from "vscode"; -import { Tools } from "../api/Tools"; -import { checkClientCertificate, debugKeyFileExists, remoteCertificatesExists } from "../debug/certificates"; -import { DebugConfiguration, getDebugServiceDetails, SERVICE_CERTIFICATE } from "../api/configuration/DebugConfiguration"; -import { DebugJob, getDebugServerJob, getDebugServiceJob, isDebugEngineRunning, readActiveJob, readJVMInfo, startServer, startService, stopServer, stopService } from "../debug/server"; -import { instance } from "../instantiate"; -import { withContext } from "./tools"; -import { BrowserItem } from "./types"; +import { Tools } from "../../api/Tools"; +import { checkClientCertificate, debugKeyFileExists, remoteCertificatesExists } from "../../debug/certificates"; +import { DebugConfiguration, getDebugServiceDetails, SERVICE_CERTIFICATE } from "../../api/configuration/DebugConfiguration"; +import { DebugJob, getDebugServerJob, getDebugServiceJob, isDebugEngineRunning, readActiveJob, readJVMInfo, startServer, startService, stopServer, stopService } from "../../debug/server"; +import { instance } from "../../instantiate"; +import { withContext } from "../tools"; +import { BrowserItem } from "../types"; const title = "IBM i debugger"; type Certificates = { diff --git a/src/views/helpView.ts b/src/ui/views/helpView.ts similarity index 98% rename from src/views/helpView.ts rename to src/ui/views/helpView.ts index 1d6527243..691a96404 100644 --- a/src/views/helpView.ts +++ b/src/ui/views/helpView.ts @@ -2,9 +2,9 @@ import AdmZip from 'adm-zip'; import path, { parse } from 'path'; import vscode from 'vscode'; -import { DebugConfiguration } from '../api/configuration/DebugConfiguration'; -import IBMi from '../api/IBMi'; -import { instance } from '../instantiate'; +import { DebugConfiguration } from '../../api/configuration/DebugConfiguration'; +import IBMi from '../../api/IBMi'; +import { instance } from '../../instantiate'; export class HelpView implements vscode.TreeDataProvider { private _onDidChangeTreeData = new vscode.EventEmitter(); diff --git a/src/views/ifsBrowser.ts b/src/ui/views/ifsBrowser.ts similarity index 99% rename from src/views/ifsBrowser.ts rename to src/ui/views/ifsBrowser.ts index efc8a163a..c3fbd93e5 100644 --- a/src/views/ifsBrowser.ts +++ b/src/ui/views/ifsBrowser.ts @@ -3,14 +3,14 @@ import path, { dirname, extname } from "path"; import vscode, { FileType, l10n, window } from "vscode"; import { existsSync, mkdirSync, rmdirSync } from "fs"; -import { SortOptions } from "../api/IBMiContent"; -import { Search } from "../api/Search"; -import { Tools } from "../api/Tools"; -import { instance } from "../instantiate"; -import { FocusOptions, IFSFile, IFS_BROWSER_MIMETYPE, OBJECT_BROWSER_MIMETYPE, SearchHit, SearchResults, WithPath } from "../typings"; -import { fileToPath, findUriTabs, ifsFileToToolTip } from "./tools"; -import IBMi from "../api/IBMi"; -import { BrowserItem, BrowserItemParameters } from "./types"; +import { SortOptions } from "../../api/IBMiContent"; +import { Search } from "../../api/Search"; +import { Tools } from "../../api/Tools"; +import { instance } from "../../instantiate"; +import { FocusOptions, IFSFile, IFS_BROWSER_MIMETYPE, OBJECT_BROWSER_MIMETYPE, SearchHit, SearchResults, WithPath } from "../../typings"; +import { fileToPath, findUriTabs, ifsFileToToolTip } from "../tools"; +import IBMi from "../../api/IBMi"; +import { BrowserItem, BrowserItemParameters } from "../types"; const URI_LIST_MIMETYPE = "text/uri-list"; const URI_LIST_SEPARATOR = "\r\n"; diff --git a/src/views/objectBrowser.ts b/src/ui/views/objectBrowser.ts similarity index 98% rename from src/views/objectBrowser.ts rename to src/ui/views/objectBrowser.ts index 58f95065b..d7c79629a 100644 --- a/src/views/objectBrowser.ts +++ b/src/ui/views/objectBrowser.ts @@ -2,18 +2,18 @@ import fs, { existsSync } from "fs"; import os from "os"; import path, { basename, dirname } from "path"; import vscode from "vscode"; -import { parseFilter, singleGenericName } from "../api/Filter"; -import IBMi, { MemberParts } from "../api/IBMi"; -import { SortOptions, SortOrder } from "../api/IBMiContent"; -import { Search } from "../api/Search"; -import { Tools } from "../api/Tools"; -import { getMemberUri } from "../filesystems/qsys/QSysFs"; -import { instance } from "../instantiate"; -import { CommandResult, FilteredItem, FocusOptions, IBMiMember, IBMiObject, MemberItem, OBJECT_BROWSER_MIMETYPE, ObjectItem, WithLibrary } from "../typings"; -import { editFilter } from "../webviews/filters"; -import { findUriTabs, memberToToolTip, objectToToolTip, sourcePhysicalFileToToolTip } from "./tools"; -import { DefaultOpenMode, ObjectFilters } from "../api/configuration/ConnectionManager"; -import { BrowserItem, BrowserItemParameters } from "./types"; +import { parseFilter, singleGenericName } from "../../api/Filter"; +import IBMi, { MemberParts } from "../../api/IBMi"; +import { SortOptions, SortOrder } from "../../api/IBMiContent"; +import { Search } from "../../api/Search"; +import { Tools } from "../../api/Tools"; +import { getMemberUri } from "../../filesystems/qsys/QSysFs"; +import { instance } from "../../instantiate"; +import { CommandResult, FilteredItem, FocusOptions, IBMiMember, IBMiObject, MemberItem, OBJECT_BROWSER_MIMETYPE, ObjectItem, WithLibrary } from "../../typings"; +import { editFilter } from "../../webviews/filters"; +import { findUriTabs, memberToToolTip, objectToToolTip, sourcePhysicalFileToToolTip } from "../tools"; +import { DefaultOpenMode, ObjectFilters } from "../../api/configuration/ConnectionManager"; +import { BrowserItem, BrowserItemParameters } from "../types"; const URI_LIST_SEPARATOR = "\r\n"; diff --git a/src/views/searchView.ts b/src/ui/views/searchView.ts similarity index 98% rename from src/views/searchView.ts rename to src/ui/views/searchView.ts index 6ac3aa9af..2ccd4bc02 100644 --- a/src/views/searchView.ts +++ b/src/ui/views/searchView.ts @@ -1,7 +1,7 @@ import path from 'path'; import vscode from "vscode"; -import { SearchHit, SearchHitLine, SearchResults, WithPath } from "../typings"; -import { DefaultOpenMode } from '../api/configuration/ConnectionManager'; +import { SearchHit, SearchHitLine, SearchResults, WithPath } from "../../typings"; +import { DefaultOpenMode } from '../../api/configuration/ConnectionManager'; export function initializeSearchView(context: vscode.ExtensionContext) { const searchView = new SearchView(); diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 1c99e5a07..97f0fd411 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -8,7 +8,7 @@ import { isSEPSupported } from "../../debug/server"; import { extensionComponentRegistry } from "../../api/components/manager"; import { instance } from "../../instantiate"; import { ConnectionData, Server } from '../../typings'; -import { withContext } from "../../views/tools"; +import { withContext } from "../../ui/tools"; import IBMi from "../../api/IBMi"; import { ConnectionConfig, ConnectionManager } from "../../api/configuration/ConnectionManager"; import { deleteStoredPassword, getStoredPassword, setStoredPassword } from "../../config/passwords"; From 99101c4b7a5beb1fdc47acf767ff7d65950375b2 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Wed, 15 Jan 2025 10:36:14 -0500 Subject: [PATCH 27/46] Refactor configuration imports to use the new directory structure and add a readme for configuration clarification Signed-off-by: worksofliam --- src/Instance.ts | 6 +- src/api/IBMi.ts | 4 +- src/api/configuration/Storage.ts | 281 ------------------ .../{ => config}/ConnectionManager.ts | 6 +- .../{Config.ts => config/VirtualConfig.ts} | 0 src/api/configuration/readme.md | 5 + src/api/configuration/storage/BaseStorage.ts | 31 ++ .../configuration/storage/CodeForIStorage.ts | 110 +++++++ .../storage/ConnectionStorage.ts | 131 ++++++++ src/api/tests/globalSetup.ts | 4 +- src/api/types.ts | 2 +- src/commands/open.ts | 2 +- src/config/Configuration.ts | 4 +- src/config/Storage.ts | 2 +- src/filesystems/local/git.ts | 2 +- src/filesystems/qsys/FSUtils.ts | 2 +- src/filesystems/qsys/sourceDateHandler.ts | 2 +- src/typings.ts | 2 +- src/ui/views/ConnectionBrowser.ts | 2 +- src/ui/views/LibraryListView.ts | 2 +- src/ui/views/ProfilesView.ts | 2 +- src/ui/views/objectBrowser.ts | 2 +- src/ui/views/searchView.ts | 2 +- src/webviews/commandProfile/index.ts | 2 +- src/webviews/filters/index.ts | 2 +- src/webviews/settings/index.ts | 2 +- 26 files changed, 303 insertions(+), 309 deletions(-) delete mode 100644 src/api/configuration/Storage.ts rename src/api/configuration/{ => config}/ConnectionManager.ts (97%) rename src/api/configuration/{Config.ts => config/VirtualConfig.ts} (100%) create mode 100644 src/api/configuration/readme.md create mode 100644 src/api/configuration/storage/BaseStorage.ts create mode 100644 src/api/configuration/storage/CodeForIStorage.ts create mode 100644 src/api/configuration/storage/ConnectionStorage.ts diff --git a/src/Instance.ts b/src/Instance.ts index ee74f5542..15e980745 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -1,13 +1,14 @@ import * as vscode from "vscode"; import { ConnectionData, IBMiEvent } from "./typings"; import IBMi, { ConnectionResult } from "./api/IBMi"; -import { CodeForIStorage, ConnectionStorage } from "./api/configuration/Storage"; +import { CodeForIStorage } from "./api/configuration/storage/CodeForIStorage"; import { withContext } from "./ui/tools"; import { handleConnectionResults, messageCallback } from "./ui/connection"; import { VsStorage } from "./config/Storage"; import { VsCodeConfig } from "./config/Configuration"; -import { ConnectionConfig } from "./api/configuration/ConnectionManager"; +import { ConnectionConfig } from "./api/configuration/config/ConnectionManager"; import { EventEmitter } from "stream"; +import { ConnectionStorage } from "./api/configuration/storage/ConnectionStorage"; type IBMiEventSubscription = { func: Function, @@ -35,7 +36,6 @@ export default class Instance { constructor(context: vscode.ExtensionContext) { const vscodeStorage = new VsStorage(context); this.storage = new ConnectionStorage(vscodeStorage); - IBMi.GlobalStorage = new CodeForIStorage(vscodeStorage); IBMi.connectionManager.configMethod = new VsCodeConfig(); diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 3ee226e73..2684e11fb 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -9,11 +9,11 @@ import { CustomQSh } from './components/cqsh'; import { ComponentManager } from "./components/manager"; import { CompileTools } from "./CompileTools"; import IBMiContent from "./IBMiContent"; -import { CachedServerSettings, CodeForIStorage } from './configuration/Storage'; +import { CachedServerSettings, CodeForIStorage } from './configuration/storage/CodeForIStorage'; import { Tools } from './Tools'; import * as configVars from './configVars'; import { DebugConfiguration } from "./configuration/DebugConfiguration"; -import { ConnectionManager, ConnectionConfig } from './configuration/ConnectionManager'; +import { ConnectionManager, ConnectionConfig } from './configuration/config/ConnectionManager'; import { CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, WrapResult } from './types'; import { EventEmitter } from 'stream'; diff --git a/src/api/configuration/Storage.ts b/src/api/configuration/Storage.ts deleted file mode 100644 index d7d38a42e..000000000 --- a/src/api/configuration/Storage.ts +++ /dev/null @@ -1,281 +0,0 @@ -import { ConnectionData } from "../types"; - -const PREVIOUS_CUR_LIBS_KEY = `prevCurLibs`; -const LAST_PROFILE_KEY = `currentProfile`; -const SOURCE_LIST_KEY = `sourceList`; -const DEPLOYMENT_KEY = `deployment`; -const DEBUG_KEY = `debug`; -const SERVER_SETTINGS_CACHE_PREFIX = `serverSettingsCache_`; -const SERVER_SETTINGS_CACHE_KEY = (name: string) => SERVER_SETTINGS_CACHE_PREFIX + name; -const PREVIOUS_SEARCH_TERMS_KEY = `prevSearchTerms`; -const PREVIOUS_FIND_TERMS_KEY = `prevFindTerms`; -const RECENTLY_OPENED_FILES_KEY = `recentlyOpenedFiles`; -const AUTHORISED_EXTENSIONS_KEY = `authorisedExtensions` - -export type PathContent = Record; -export type DeploymentPath = Record; -export type DebugCommands = Record; - -type AuthorisedExtension = { - id: string - displayName: string - since: number - lastAccess: number -} - -export type LastConnection = { - name: string - timestamp: number -}; - -export type CachedServerSettings = { - lastCheckedOnVersion: string | undefined; - aspInfo: { [id: number]: string } - qccsid: number | null; - jobCcsid: number | null - remoteFeatures: { [name: string]: string | undefined } - remoteFeaturesKeys: string | null - badDataAreasChecked: boolean | null - libraryListValidated: boolean | null - pathChecked?: boolean - userDefaultCCSID: number | null - debugConfigLoaded: boolean - maximumArgsLength: number -} | undefined; - -export abstract class BaseStorage { - protected readonly globalState: any; - - constructor() { - this.globalState = new Map(); - } - - keys(): readonly string[] { - return Array.from(this.globalState.keys()); - } - - get(key: string): T | undefined { - return this.globalState.get(this.getStorageKey(key)) as T | undefined; - } - - async set(key: string, value: any) { - await this.globalState.set(this.getStorageKey(key), value); - } - - getStorageKey(key: string): string { - return key; - } -} - -export class VirtualStorage extends BaseStorage { - protected readonly globalState: Map = new Map(); - - constructor() { - super(); - } -} - -export class CodeForIStorage { - // private static instance: GlobalStorage; - - // static initialize(context: vscode.ExtensionContext) { - // if (!this.instance) { - // this.instance = new GlobalStorage(context); - // } - // } - - // static get() { - // return this.instance; - // } - - constructor(private internalStorage: BaseStorage) {} - - protected getStorageKey(key: string): string { - return key; - } - - getLastConnections() { - return this.internalStorage.get("lastConnections"); - } - - async setLastConnection(name: string) { - const lastConnections = this.getLastConnections() || []; - const connection = lastConnections?.find(c => c.name === name); - if (connection) { - connection.timestamp = Date.now(); - } - else { - lastConnections?.push({ name, timestamp: Date.now() }); - } - await this.setLastConnections(lastConnections); - } - - async setLastConnections(lastConnections: LastConnection[]) { - await this.internalStorage.set("lastConnections", lastConnections.sort((c1, c2) => c2.timestamp - c1.timestamp)); - } - - getServerSettingsCache(name: string) { - return this.internalStorage.get(SERVER_SETTINGS_CACHE_KEY(name)); - } - - async setServerSettingsCache(name: string, serverSettings: CachedServerSettings) { - await this.internalStorage.set(SERVER_SETTINGS_CACHE_KEY(name), serverSettings); - } - - async setServerSettingsCacheSpecific(name: string, newSettings: Partial) { - await this.internalStorage.set(SERVER_SETTINGS_CACHE_KEY(name), { - ...this.getServerSettingsCache(name), - ...newSettings - }); - } - - async deleteServerSettingsCache(name: string) { - await this.internalStorage.set(SERVER_SETTINGS_CACHE_KEY(name), undefined); - } - - async deleteStaleServerSettingsCache(connections: ConnectionData[]) { - const validKeys = connections.map(connection => SERVER_SETTINGS_CACHE_KEY(connection.name)); - const currentKeys = this.internalStorage.keys(); - const keysToDelete = currentKeys.filter(key => key.startsWith(SERVER_SETTINGS_CACHE_PREFIX) && !validKeys.includes(key)); - for await (const key of keysToDelete) { - await this.internalStorage.set(key, undefined); - } - } - - getPreviousSearchTerms() { - return this.internalStorage.get(PREVIOUS_SEARCH_TERMS_KEY) || []; - } - - async addPreviousSearchTerm(term: string) { - await this.internalStorage.set(PREVIOUS_SEARCH_TERMS_KEY, [term].concat(this.getPreviousSearchTerms().filter(t => t !== term))); - } - - async clearPreviousSearchTerms(){ - await this.internalStorage.set(PREVIOUS_SEARCH_TERMS_KEY, undefined); - } - - getPreviousFindTerms() { - return this.internalStorage.get(PREVIOUS_FIND_TERMS_KEY) || []; - } - - async addPreviousFindTerm(term: string) { - await this.internalStorage.set(PREVIOUS_FIND_TERMS_KEY, [term].concat(this.getPreviousFindTerms().filter(t => t !== term))); - } - - async clearPreviousFindTerms(){ - await this.internalStorage.set(PREVIOUS_FIND_TERMS_KEY, undefined); - } -} - -export class ConnectionStorage { - private connectionName: string = ""; - constructor(private internalStorage: BaseStorage) {} - - get ready(): boolean { - if (this.connectionName) { - return true; - } - else { - return false; - } - } - - setConnectionName(connectionName: string) { - this.connectionName = connectionName; - } - - protected getStorageKey(key: string): string { - return `${this.connectionName}.${key}`; - } - - getSourceList() { - return this.internalStorage.get(SOURCE_LIST_KEY) || {}; - } - - async setSourceList(sourceList: PathContent) { - await this.internalStorage.set(SOURCE_LIST_KEY, sourceList); - } - - getLastProfile() { - return this.internalStorage.get(LAST_PROFILE_KEY); - } - - async setLastProfile(lastProfile: string) { - await this.internalStorage.set(LAST_PROFILE_KEY, lastProfile); - } - - getPreviousCurLibs() { - return this.internalStorage.get(PREVIOUS_CUR_LIBS_KEY) || []; - } - - async setPreviousCurLibs(previousCurLibs: string[]) { - await this.internalStorage.set(PREVIOUS_CUR_LIBS_KEY, previousCurLibs); - } - - getDeployment() { - return this.internalStorage.get(DEPLOYMENT_KEY) || {}; - } - - async setDeployment(existingPaths: DeploymentPath) { - await this.internalStorage.set(DEPLOYMENT_KEY, existingPaths); - } - - getDebugCommands() { - return this.internalStorage.get(DEBUG_KEY) || {}; - } - - setDebugCommands(existingCommands: DebugCommands) { - return this.internalStorage.set(DEBUG_KEY, existingCommands); - } - - getWorkspaceDeployPath(workspaceFolderFsPath: string) { - const deployDirs = this.internalStorage.get(DEPLOYMENT_KEY) || {}; - return deployDirs[workspaceFolderFsPath].toLowerCase(); - } - - getRecentlyOpenedFiles() { - return this.internalStorage.get(RECENTLY_OPENED_FILES_KEY) || []; - } - - async setRecentlyOpenedFiles(recentlyOpenedFiles: string[]) { - await this.internalStorage.set(RECENTLY_OPENED_FILES_KEY, recentlyOpenedFiles); - } - - async clearRecentlyOpenedFiles() { - await this.internalStorage.set(RECENTLY_OPENED_FILES_KEY, undefined); - } - - async grantExtensionAuthorisation(extensionId: string, displayName: string) { - const extensions = this.getAuthorisedExtensions(); - if (!this.getExtensionAuthorisation(extensionId)) { - extensions.push({ - id: extensionId, - displayName: displayName, - since: new Date().getTime(), - lastAccess: new Date().getTime() - }); - await this.internalStorage.set(AUTHORISED_EXTENSIONS_KEY, extensions); - } - } - - getExtensionAuthorisation(extensionId: string) { - const authorisedExtension = this.getAuthorisedExtensions().find(authorisedExtension => authorisedExtension.id === extensionId); - if (authorisedExtension) { - authorisedExtension.lastAccess = new Date().getTime(); - } - return authorisedExtension; - } - - getAuthorisedExtensions(): AuthorisedExtension[] { - return this.internalStorage.get(AUTHORISED_EXTENSIONS_KEY) || []; - } - - revokeAllExtensionAuthorisations() { - this.revokeExtensionAuthorisation(...this.getAuthorisedExtensions()); - } - - revokeExtensionAuthorisation(...extensions: AuthorisedExtension[]) { - const newExtensions = this.getAuthorisedExtensions().filter(ext => !extensions.includes(ext)); - return this.internalStorage.set(AUTHORISED_EXTENSIONS_KEY, newExtensions); - } -} diff --git a/src/api/configuration/ConnectionManager.ts b/src/api/configuration/config/ConnectionManager.ts similarity index 97% rename from src/api/configuration/ConnectionManager.ts rename to src/api/configuration/config/ConnectionManager.ts index 0267cb1c5..54b3d7676 100644 --- a/src/api/configuration/ConnectionManager.ts +++ b/src/api/configuration/config/ConnectionManager.ts @@ -1,8 +1,8 @@ import os from "os"; -import { FilterType } from "../Filter"; -import { Config, VirtualConfig } from "./Config"; -import { DeploymentMethod, ConnectionData } from "../types"; +import { FilterType } from "../../Filter"; +import { Config, VirtualConfig } from "./VirtualConfig"; +import { DeploymentMethod, ConnectionData } from "../../types"; export type SourceDateMode = "edit" | "diff"; export type DefaultOpenMode = "browse" | "edit"; diff --git a/src/api/configuration/Config.ts b/src/api/configuration/config/VirtualConfig.ts similarity index 100% rename from src/api/configuration/Config.ts rename to src/api/configuration/config/VirtualConfig.ts diff --git a/src/api/configuration/readme.md b/src/api/configuration/readme.md new file mode 100644 index 000000000..0357157a6 --- /dev/null +++ b/src/api/configuration/readme.md @@ -0,0 +1,5 @@ + +#### What's the difference between `config` and `storage`? + +* **config** is the idea of user configurable configuration files. This is things like connection settings, actions, and the likes. +* **storage** if for storing data that is not editable by the user. Details like history, authorisation lists, etc. \ No newline at end of file diff --git a/src/api/configuration/storage/BaseStorage.ts b/src/api/configuration/storage/BaseStorage.ts new file mode 100644 index 000000000..15b8de8bb --- /dev/null +++ b/src/api/configuration/storage/BaseStorage.ts @@ -0,0 +1,31 @@ +export abstract class BaseStorage { + protected readonly globalState: any; + + constructor() { + this.globalState = new Map(); + } + + keys(): readonly string[] { + return Array.from(this.globalState.keys()); + } + + get(key: string): T | undefined { + return this.globalState.get(this.getStorageKey(key)) as T | undefined; + } + + async set(key: string, value: any) { + await this.globalState.set(this.getStorageKey(key), value); + } + + getStorageKey(key: string): string { + return key; + } +} + +export class VirtualStorage extends BaseStorage { + protected readonly globalState: Map = new Map(); + + constructor() { + super(); + } +} \ No newline at end of file diff --git a/src/api/configuration/storage/CodeForIStorage.ts b/src/api/configuration/storage/CodeForIStorage.ts new file mode 100644 index 000000000..30e95c5bd --- /dev/null +++ b/src/api/configuration/storage/CodeForIStorage.ts @@ -0,0 +1,110 @@ +import { ConnectionData } from "../../types"; +import { BaseStorage } from "./BaseStorage"; +const SERVER_SETTINGS_CACHE_PREFIX = `serverSettingsCache_`; +const SERVER_SETTINGS_CACHE_KEY = (name: string) => SERVER_SETTINGS_CACHE_PREFIX + name; +const PREVIOUS_SEARCH_TERMS_KEY = `prevSearchTerms`; +const PREVIOUS_FIND_TERMS_KEY = `prevFindTerms`; + +export type PathContent = Record; +export type DeploymentPath = Record; +export type DebugCommands = Record; + +export type LastConnection = { + name: string + timestamp: number +}; + +export type CachedServerSettings = { + lastCheckedOnVersion: string | undefined; + aspInfo: { [id: number]: string } + qccsid: number | null; + jobCcsid: number | null + remoteFeatures: { [name: string]: string | undefined } + remoteFeaturesKeys: string | null + badDataAreasChecked: boolean | null + libraryListValidated: boolean | null + pathChecked?: boolean + userDefaultCCSID: number | null + debugConfigLoaded: boolean + maximumArgsLength: number +} | undefined; + +export class CodeForIStorage { + constructor(private internalStorage: BaseStorage) {} + + protected getStorageKey(key: string): string { + return key; + } + + getLastConnections() { + return this.internalStorage.get("lastConnections"); + } + + async setLastConnection(name: string) { + const lastConnections = this.getLastConnections() || []; + const connection = lastConnections?.find(c => c.name === name); + if (connection) { + connection.timestamp = Date.now(); + } + else { + lastConnections?.push({ name, timestamp: Date.now() }); + } + await this.setLastConnections(lastConnections); + } + + async setLastConnections(lastConnections: LastConnection[]) { + await this.internalStorage.set("lastConnections", lastConnections.sort((c1, c2) => c2.timestamp - c1.timestamp)); + } + + getServerSettingsCache(name: string) { + return this.internalStorage.get(SERVER_SETTINGS_CACHE_KEY(name)); + } + + async setServerSettingsCache(name: string, serverSettings: CachedServerSettings) { + await this.internalStorage.set(SERVER_SETTINGS_CACHE_KEY(name), serverSettings); + } + + async setServerSettingsCacheSpecific(name: string, newSettings: Partial) { + await this.internalStorage.set(SERVER_SETTINGS_CACHE_KEY(name), { + ...this.getServerSettingsCache(name), + ...newSettings + }); + } + + async deleteServerSettingsCache(name: string) { + await this.internalStorage.set(SERVER_SETTINGS_CACHE_KEY(name), undefined); + } + + async deleteStaleServerSettingsCache(connections: ConnectionData[]) { + const validKeys = connections.map(connection => SERVER_SETTINGS_CACHE_KEY(connection.name)); + const currentKeys = this.internalStorage.keys(); + const keysToDelete = currentKeys.filter(key => key.startsWith(SERVER_SETTINGS_CACHE_PREFIX) && !validKeys.includes(key)); + for await (const key of keysToDelete) { + await this.internalStorage.set(key, undefined); + } + } + + getPreviousSearchTerms() { + return this.internalStorage.get(PREVIOUS_SEARCH_TERMS_KEY) || []; + } + + async addPreviousSearchTerm(term: string) { + await this.internalStorage.set(PREVIOUS_SEARCH_TERMS_KEY, [term].concat(this.getPreviousSearchTerms().filter(t => t !== term))); + } + + async clearPreviousSearchTerms(){ + await this.internalStorage.set(PREVIOUS_SEARCH_TERMS_KEY, undefined); + } + + getPreviousFindTerms() { + return this.internalStorage.get(PREVIOUS_FIND_TERMS_KEY) || []; + } + + async addPreviousFindTerm(term: string) { + await this.internalStorage.set(PREVIOUS_FIND_TERMS_KEY, [term].concat(this.getPreviousFindTerms().filter(t => t !== term))); + } + + async clearPreviousFindTerms(){ + await this.internalStorage.set(PREVIOUS_FIND_TERMS_KEY, undefined); + } +} diff --git a/src/api/configuration/storage/ConnectionStorage.ts b/src/api/configuration/storage/ConnectionStorage.ts new file mode 100644 index 000000000..9f4f8135a --- /dev/null +++ b/src/api/configuration/storage/ConnectionStorage.ts @@ -0,0 +1,131 @@ +import { BaseStorage } from "./BaseStorage"; +import { PathContent, DeploymentPath, DebugCommands } from "./CodeForIStorage"; + +const PREVIOUS_CUR_LIBS_KEY = `prevCurLibs`; +const LAST_PROFILE_KEY = `currentProfile`; +const SOURCE_LIST_KEY = `sourceList`; +const DEPLOYMENT_KEY = `deployment`; +const DEBUG_KEY = `debug`; + +const RECENTLY_OPENED_FILES_KEY = `recentlyOpenedFiles`; +const AUTHORISED_EXTENSIONS_KEY = `authorisedExtensions` + +type AuthorisedExtension = { + id: string + displayName: string + since: number + lastAccess: number +} + +export class ConnectionStorage { + private connectionName: string = ""; + constructor(private internalStorage: BaseStorage) {} + + get ready(): boolean { + if (this.connectionName) { + return true; + } + else { + return false; + } + } + + setConnectionName(connectionName: string) { + this.connectionName = connectionName; + } + + protected getStorageKey(key: string): string { + return `${this.connectionName}.${key}`; + } + + getSourceList() { + return this.internalStorage.get(SOURCE_LIST_KEY) || {}; + } + + async setSourceList(sourceList: PathContent) { + await this.internalStorage.set(SOURCE_LIST_KEY, sourceList); + } + + getLastProfile() { + return this.internalStorage.get(LAST_PROFILE_KEY); + } + + async setLastProfile(lastProfile: string) { + await this.internalStorage.set(LAST_PROFILE_KEY, lastProfile); + } + + getPreviousCurLibs() { + return this.internalStorage.get(PREVIOUS_CUR_LIBS_KEY) || []; + } + + async setPreviousCurLibs(previousCurLibs: string[]) { + await this.internalStorage.set(PREVIOUS_CUR_LIBS_KEY, previousCurLibs); + } + + getDeployment() { + return this.internalStorage.get(DEPLOYMENT_KEY) || {}; + } + + async setDeployment(existingPaths: DeploymentPath) { + await this.internalStorage.set(DEPLOYMENT_KEY, existingPaths); + } + + getDebugCommands() { + return this.internalStorage.get(DEBUG_KEY) || {}; + } + + setDebugCommands(existingCommands: DebugCommands) { + return this.internalStorage.set(DEBUG_KEY, existingCommands); + } + + getWorkspaceDeployPath(workspaceFolderFsPath: string) { + const deployDirs = this.internalStorage.get(DEPLOYMENT_KEY) || {}; + return deployDirs[workspaceFolderFsPath].toLowerCase(); + } + + getRecentlyOpenedFiles() { + return this.internalStorage.get(RECENTLY_OPENED_FILES_KEY) || []; + } + + async setRecentlyOpenedFiles(recentlyOpenedFiles: string[]) { + await this.internalStorage.set(RECENTLY_OPENED_FILES_KEY, recentlyOpenedFiles); + } + + async clearRecentlyOpenedFiles() { + await this.internalStorage.set(RECENTLY_OPENED_FILES_KEY, undefined); + } + + async grantExtensionAuthorisation(extensionId: string, displayName: string) { + const extensions = this.getAuthorisedExtensions(); + if (!this.getExtensionAuthorisation(extensionId)) { + extensions.push({ + id: extensionId, + displayName: displayName, + since: new Date().getTime(), + lastAccess: new Date().getTime() + }); + await this.internalStorage.set(AUTHORISED_EXTENSIONS_KEY, extensions); + } + } + + getExtensionAuthorisation(extensionId: string) { + const authorisedExtension = this.getAuthorisedExtensions().find(authorisedExtension => authorisedExtension.id === extensionId); + if (authorisedExtension) { + authorisedExtension.lastAccess = new Date().getTime(); + } + return authorisedExtension; + } + + getAuthorisedExtensions(): AuthorisedExtension[] { + return this.internalStorage.get(AUTHORISED_EXTENSIONS_KEY) || []; + } + + revokeAllExtensionAuthorisations() { + this.revokeExtensionAuthorisation(...this.getAuthorisedExtensions()); + } + + revokeExtensionAuthorisation(...extensions: AuthorisedExtension[]) { + const newExtensions = this.getAuthorisedExtensions().filter(ext => !extensions.includes(ext)); + return this.internalStorage.set(AUTHORISED_EXTENSIONS_KEY, newExtensions); + } +} diff --git a/src/api/tests/globalSetup.ts b/src/api/tests/globalSetup.ts index c981ff6d6..47701134f 100644 --- a/src/api/tests/globalSetup.ts +++ b/src/api/tests/globalSetup.ts @@ -3,8 +3,8 @@ import IBMi from "../IBMi"; import { ENV_CREDS } from "./env"; import { getConnection, setConnection } from "./state"; import { afterAll, beforeAll, expect } from "vitest"; -import { CodeForIStorage, ConnectionStorage, VirtualStorage } from "../configuration/Storage"; -import { VirtualConfig } from "../configuration/Config"; +import { CodeForIStorage, ConnectionStorage, VirtualStorage } from "../configuration/storage/CodeForIStorage"; +import { VirtualConfig } from "../configuration/config/VirtualConfig"; beforeAll(async () => { const virtualStorage = new VirtualStorage(); diff --git a/src/api/types.ts b/src/api/types.ts index 876eda3d5..6b3a3e7b3 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -1,4 +1,4 @@ -import { ObjectFilters } from "./configuration/ConnectionManager"; +import { ObjectFilters } from "./configuration/config/ConnectionManager"; export type DeploymentMethod = "all" | "staged" | "unstaged" | "changed" | "compare"; diff --git a/src/commands/open.ts b/src/commands/open.ts index 38f05dd6c..7d2184496 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -6,7 +6,7 @@ import { getUriFromPath, parseFSOptions } from "../filesystems/qsys/QSysFs"; import path from "path"; import { findExistingDocument, findExistingDocumentUri } from "../ui/tools"; import IBMi from "../api/IBMi"; -import { DefaultOpenMode } from "../api/configuration/ConnectionManager"; +import { DefaultOpenMode } from "../api/configuration/config/ConnectionManager"; const CLEAR_RECENT = `$(trash) Clear recently opened`; const CLEAR_CACHED = `$(trash) Clear cached`; diff --git a/src/config/Configuration.ts b/src/config/Configuration.ts index 893d5d3fd..d72265a9c 100644 --- a/src/config/Configuration.ts +++ b/src/config/Configuration.ts @@ -1,8 +1,6 @@ import * as vscode from 'vscode'; -import { ConnectionData, DeploymentMethod } from '../typings'; -import { FilterType } from '../api/Filter'; -import { Config } from "../api/configuration/Config"; +import { Config } from "../api/configuration/config/VirtualConfig"; export function onCodeForIBMiConfigurationChange(props: string | string[], todo: (value: vscode.ConfigurationChangeEvent) => void) { const keys = (Array.isArray(props) ? props : Array.of(props)).map(key => `code-for-ibmi.${key}`); diff --git a/src/config/Storage.ts b/src/config/Storage.ts index c6ef17704..2dfe7f57f 100644 --- a/src/config/Storage.ts +++ b/src/config/Storage.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import { BaseStorage } from '../api/configuration/Storage'; +import { BaseStorage } from '../api/configuration/storage/BaseStorage'; export class VsStorage extends BaseStorage { declare protected readonly globalState; diff --git a/src/filesystems/local/git.ts b/src/filesystems/local/git.ts index 5cb5fcf73..586465dcc 100644 --- a/src/filesystems/local/git.ts +++ b/src/filesystems/local/git.ts @@ -4,7 +4,7 @@ import { instance } from "../../instantiate"; import IBMi from "../../api/IBMi"; import IBMiContent from "../../api/IBMiContent"; import { getGitAPI } from "../../ui/tools"; -import { ConnectionConfig } from "../../api/configuration/ConnectionManager"; +import { ConnectionConfig } from "../../api/configuration/config/ConnectionManager"; const lastBranch: { [workspaceUri: string]: string } = {}; diff --git a/src/filesystems/qsys/FSUtils.ts b/src/filesystems/qsys/FSUtils.ts index e0d5eb769..84c7845df 100644 --- a/src/filesystems/qsys/FSUtils.ts +++ b/src/filesystems/qsys/FSUtils.ts @@ -2,7 +2,7 @@ import path from "path"; import vscode, { l10n } from "vscode"; import { findUriTabs } from "../../ui/tools"; import IBMi from "../../api/IBMi"; -import { ReconnectMode } from "../../api/configuration/ConnectionManager"; +import { ReconnectMode } from "../../api/configuration/config/ConnectionManager"; /** * Called when a member/streamfile is left open when VS Code is closed and re-opened to reconnect (or not) to the previous IBM i, based on the `autoReconnect` global configuration value. diff --git a/src/filesystems/qsys/sourceDateHandler.ts b/src/filesystems/qsys/sourceDateHandler.ts index a4f0a9aaa..9cead2772 100644 --- a/src/filesystems/qsys/sourceDateHandler.ts +++ b/src/filesystems/qsys/sourceDateHandler.ts @@ -4,7 +4,7 @@ import { DiffComputer } from "vscode-diff"; import { instance } from "../../instantiate"; import IBMi from "../../api/IBMi"; -import { SourceDateMode } from "../../api/configuration/ConnectionManager"; +import { SourceDateMode } from "../../api/configuration/config/ConnectionManager"; const editedTodayColor = new vscode.ThemeColor(`gitDecoration.modifiedResourceForeground`); const seachGutterColor = new vscode.ThemeColor(`gitDecoration.addedResourceForeground`); diff --git a/src/typings.ts b/src/typings.ts index 17c9dce00..a9f3c78ff 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -3,7 +3,7 @@ import Instance from "./Instance"; import { Tools } from "./api/Tools"; import { DeployTools } from "./filesystems/local/deployTools"; import { ComponentRegistry } from './api/components/manager'; -import { ObjectFilters } from './api/configuration/ConnectionManager'; +import { ObjectFilters } from './api/configuration/config/ConnectionManager'; import { DeploymentMethod, FileError, IBMiMember, IBMiObject, WithPath } from "./api/types"; import { Ignore } from "ignore"; import { WorkspaceFolder } from "vscode"; diff --git a/src/ui/views/ConnectionBrowser.ts b/src/ui/views/ConnectionBrowser.ts index f213bf6ab..76b53ce25 100644 --- a/src/ui/views/ConnectionBrowser.ts +++ b/src/ui/views/ConnectionBrowser.ts @@ -4,7 +4,7 @@ import { ConnectionData, Server } from '../../typings'; import { instance } from '../../instantiate'; import { Login } from '../../webviews/login'; import IBMi from '../../api/IBMi'; -import { ConnectionConfig, ConnectionManager } from '../../api/configuration/ConnectionManager'; +import { ConnectionConfig, ConnectionManager } from '../../api/configuration/config/ConnectionManager'; import { deleteStoredPassword, getStoredPassword, setStoredPassword } from '../../config/passwords'; type CopyOperationItem = { diff --git a/src/ui/views/LibraryListView.ts b/src/ui/views/LibraryListView.ts index 6e654c089..79ef3c78c 100644 --- a/src/ui/views/LibraryListView.ts +++ b/src/ui/views/LibraryListView.ts @@ -2,7 +2,7 @@ import vscode, { commands, l10n } from "vscode"; import { instance } from "../../instantiate"; import { IBMiObject, WithLibrary } from "../../typings"; import { objectToToolTip } from "../tools"; -import { ConnectionConfig } from "../../api/configuration/ConnectionManager"; +import { ConnectionConfig } from "../../api/configuration/config/ConnectionManager"; import IBMi from "../../api/IBMi"; export class LibraryListProvider implements vscode.TreeDataProvider { diff --git a/src/ui/views/ProfilesView.ts b/src/ui/views/ProfilesView.ts index 0727c166f..bb5cebe95 100644 --- a/src/ui/views/ProfilesView.ts +++ b/src/ui/views/ProfilesView.ts @@ -5,7 +5,7 @@ import { instance } from '../../instantiate'; import { Profile } from '../../typings'; import { CommandProfileUi } from '../../webviews/commandProfile'; import IBMi from '../../api/IBMi'; -import { ConnectionProfile } from '../../api/configuration/ConnectionManager'; +import { ConnectionProfile } from '../../api/configuration/config/ConnectionManager'; export class ProfilesView { private _onDidChangeTreeData = new vscode.EventEmitter(); diff --git a/src/ui/views/objectBrowser.ts b/src/ui/views/objectBrowser.ts index d7c79629a..285c25495 100644 --- a/src/ui/views/objectBrowser.ts +++ b/src/ui/views/objectBrowser.ts @@ -12,7 +12,7 @@ import { instance } from "../../instantiate"; import { CommandResult, FilteredItem, FocusOptions, IBMiMember, IBMiObject, MemberItem, OBJECT_BROWSER_MIMETYPE, ObjectItem, WithLibrary } from "../../typings"; import { editFilter } from "../../webviews/filters"; import { findUriTabs, memberToToolTip, objectToToolTip, sourcePhysicalFileToToolTip } from "../tools"; -import { DefaultOpenMode, ObjectFilters } from "../../api/configuration/ConnectionManager"; +import { DefaultOpenMode, ObjectFilters } from "../../api/configuration/config/ConnectionManager"; import { BrowserItem, BrowserItemParameters } from "../types"; const URI_LIST_SEPARATOR = "\r\n"; diff --git a/src/ui/views/searchView.ts b/src/ui/views/searchView.ts index 2ccd4bc02..2813f833d 100644 --- a/src/ui/views/searchView.ts +++ b/src/ui/views/searchView.ts @@ -1,7 +1,7 @@ import path from 'path'; import vscode from "vscode"; import { SearchHit, SearchHitLine, SearchResults, WithPath } from "../../typings"; -import { DefaultOpenMode } from '../../api/configuration/ConnectionManager'; +import { DefaultOpenMode } from '../../api/configuration/config/ConnectionManager'; export function initializeSearchView(context: vscode.ExtensionContext) { const searchView = new SearchView(); diff --git a/src/webviews/commandProfile/index.ts b/src/webviews/commandProfile/index.ts index 85ca589c2..7b4e45c89 100644 --- a/src/webviews/commandProfile/index.ts +++ b/src/webviews/commandProfile/index.ts @@ -3,7 +3,7 @@ import { commands, window } from "vscode"; import { CustomUI } from "../CustomUI"; import { instance } from "../../instantiate"; import IBMi from "../../api/IBMi"; -import { CommandProfile } from "../../api/configuration/ConnectionManager"; +import { CommandProfile } from "../../api/configuration/config/ConnectionManager"; export class CommandProfileUi { static async show(currentName?: string) { diff --git a/src/webviews/filters/index.ts b/src/webviews/filters/index.ts index 95cac6540..7cc725441 100644 --- a/src/webviews/filters/index.ts +++ b/src/webviews/filters/index.ts @@ -1,7 +1,7 @@ import { CustomUI } from "../CustomUI"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; -import { ObjectFilters } from "../../api/configuration/ConnectionManager"; +import { ObjectFilters } from "../../api/configuration/config/ConnectionManager"; import IBMi from "../../api/IBMi"; export async function editFilter(filter?: ObjectFilters, copy = false) { diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 97f0fd411..ad486e642 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -10,7 +10,7 @@ import { instance } from "../../instantiate"; import { ConnectionData, Server } from '../../typings'; import { withContext } from "../../ui/tools"; import IBMi from "../../api/IBMi"; -import { ConnectionConfig, ConnectionManager } from "../../api/configuration/ConnectionManager"; +import { ConnectionConfig, ConnectionManager } from "../../api/configuration/config/ConnectionManager"; import { deleteStoredPassword, getStoredPassword, setStoredPassword } from "../../config/passwords"; const EDITING_CONTEXT = `code-for-ibmi:editingConnection`; From bb837340f3e180bb5376331bc1c1d7d8fc710af2 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Wed, 15 Jan 2025 11:17:39 -0500 Subject: [PATCH 28/46] Fix test for Java version check Signed-off-by: worksofliam --- src/testing/debug.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testing/debug.ts b/src/testing/debug.ts index c71074662..771fa77ca 100644 --- a/src/testing/debug.ts +++ b/src/testing/debug.ts @@ -24,7 +24,7 @@ export const DebugSuite: TestSuite = { assert.strictEqual(jdk11, connection.remoteFeatures.jdk17); } - assert.throws(() => getJavaHome(connection, '666')); + assert.strictEqual(getJavaHome(connection, '666'), undefined); } } ] From 61a54139263863e901e45334f799bfc7352b5478 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Thu, 16 Jan 2025 11:54:31 -0500 Subject: [PATCH 29/46] Update progress title in connection notification to use dynamic name from options Signed-off-by: worksofliam --- src/Instance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Instance.ts b/src/Instance.ts index 15e980745..70f9965fb 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -81,7 +81,7 @@ export default class Instance { return withContext("code-for-ibmi:connecting", async () => { while (true) { let customError: string|undefined; - await vscode.window.withProgress({location: vscode.ProgressLocation.Notification, title: `Code for IBM i`, cancellable: true}, async (p, cancelToken) => { + await vscode.window.withProgress({location: vscode.ProgressLocation.Notification, title: options.data.name, cancellable: true}, async (p, cancelToken) => { try { const cancelEmitter = new EventEmitter(); From eb79789d1e637adb18ca1528ad47023f58d0336d Mon Sep 17 00:00:00 2001 From: worksofliam Date: Thu, 16 Jan 2025 13:14:23 -0500 Subject: [PATCH 30/46] Add sample environment configuration and enhance tests with connection validation Signed-off-by: worksofliam --- src/api/.env.sample | 4 ++++ src/api/tests/a.test.ts | 6 +++++- src/api/tests/globalSetup.ts | 3 ++- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 src/api/.env.sample diff --git a/src/api/.env.sample b/src/api/.env.sample new file mode 100644 index 000000000..7ebbe314f --- /dev/null +++ b/src/api/.env.sample @@ -0,0 +1,4 @@ +VITE_SERVER= +VITE_DB_USER= +VITE_DB_PASS= +VITE_DB_PORT=22 \ No newline at end of file diff --git a/src/api/tests/a.test.ts b/src/api/tests/a.test.ts index 06126003b..2486ed7b7 100644 --- a/src/api/tests/a.test.ts +++ b/src/api/tests/a.test.ts @@ -1,6 +1,10 @@ // sum.test.js import { expect, test } from 'vitest' +import { getConnection } from './state' +import exp from 'constants'; test('adds 1 + 2 to equal 3', () => { - expect(1+2).toBe(3) + const conn = getConnection(); + expect(conn).toBeDefined(); + expect(1+2).toBe(3); }) \ No newline at end of file diff --git a/src/api/tests/globalSetup.ts b/src/api/tests/globalSetup.ts index 47701134f..9a25a96ad 100644 --- a/src/api/tests/globalSetup.ts +++ b/src/api/tests/globalSetup.ts @@ -3,8 +3,9 @@ import IBMi from "../IBMi"; import { ENV_CREDS } from "./env"; import { getConnection, setConnection } from "./state"; import { afterAll, beforeAll, expect } from "vitest"; -import { CodeForIStorage, ConnectionStorage, VirtualStorage } from "../configuration/storage/CodeForIStorage"; +import { CodeForIStorage } from "../configuration/storage/CodeForIStorage"; import { VirtualConfig } from "../configuration/config/VirtualConfig"; +import { VirtualStorage } from "../configuration/storage/BaseStorage"; beforeAll(async () => { const virtualStorage = new VirtualStorage(); From c2f157ab49317a49b7b7cd93169668de8d3ba1a6 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Thu, 16 Jan 2025 15:59:29 -0500 Subject: [PATCH 31/46] Remove last dep on vscode for component API Signed-off-by: worksofliam --- src/api/components/manager.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/api/components/manager.ts b/src/api/components/manager.ts index 0b8ebd56a..3ce8b5f20 100644 --- a/src/api/components/manager.ts +++ b/src/api/components/manager.ts @@ -1,12 +1,23 @@ -import vscode from "vscode"; + import IBMi from "../IBMi"; import { ComponentState, IBMiComponent } from "./component"; +interface ExtensionContextI { + extension: { + id: string + } +} + export class ComponentRegistry { private readonly components: Map = new Map; - public registerComponent(context: vscode.ExtensionContext, component: IBMiComponent) { - const key = context.extension.id; + public registerComponent(context: ExtensionContextI|string, component: IBMiComponent) { + const key = typeof context === `object` ? context.extension.id : context; + + if (typeof key !== `string`) { + throw new Error(`Invalid extension context.`); + } + const extensionComponents = this.components.get(key); if (extensionComponents) { extensionComponents.push(component); From 287dbc426bd6ccc623d0634c9c6882995ba39af3 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Thu, 16 Jan 2025 16:06:19 -0500 Subject: [PATCH 32/46] Refactor CustomQSh to use static localAssetPath and update related methods Signed-off-by: worksofliam --- src/api/components/cqsh/index.ts | 10 +++++----- src/extension.ts | 5 ++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/api/components/cqsh/index.ts b/src/api/components/cqsh/index.ts index 5c70143ca..b5ae05bb9 100644 --- a/src/api/components/cqsh/index.ts +++ b/src/api/components/cqsh/index.ts @@ -6,9 +6,9 @@ import { ComponentState, IBMiComponent } from "../component"; export class CustomQSh implements IBMiComponent { static ID = "cqsh"; - private localAssetPath: string|undefined; + private static localAssetPath: string|undefined; - setLocalAssetPath(newPath: string) { + static setLocalAssetPath(newPath: string) { this.localAssetPath = newPath; } @@ -41,17 +41,17 @@ export class CustomQSh implements IBMiComponent { } async update(connection: IBMi): Promise { - if (!this.localAssetPath) { + if (!CustomQSh.localAssetPath) { return `Error`; } - const assetExistsLocally = await exists(this.localAssetPath); + const assetExistsLocally = await exists(CustomQSh.localAssetPath); if (!assetExistsLocally) { return `Error`; } - await connection.getContent().uploadFiles([{ local: this.localAssetPath, remote: this.installPath }]); + await connection.getContent().uploadFiles([{ local: CustomQSh.localAssetPath, remote: this.installPath }]); await connection.sendCommand({ command: `chmod +x ${this.installPath}`, diff --git a/src/extension.ts b/src/extension.ts index 115309c41..f8225f86d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -113,10 +113,9 @@ export async function activate(context: ExtensionContext): Promise commands.executeCommand("code-for-ibmi.refreshProfileView"); }); - const customQsh = new CustomQSh(); - customQsh.setLocalAssetPath(path.join(context.extensionPath, `dist`, customQsh.getFileName())); + CustomQSh.setLocalAssetPath(path.join(context.extensionPath, `dist`, `cqsh`)); - extensionComponentRegistry.registerComponent(context, customQsh); + extensionComponentRegistry.registerComponent(context, new CustomQSh()); extensionComponentRegistry.registerComponent(context, new GetNewLibl); extensionComponentRegistry.registerComponent(context, new GetMemberInfo()); extensionComponentRegistry.registerComponent(context, new CopyToImport()); From 6772e3020b76d376fec6ad6397f82a90596dcc2b Mon Sep 17 00:00:00 2001 From: worksofliam Date: Thu, 16 Jan 2025 16:25:06 -0500 Subject: [PATCH 33/46] Fix cqsh local asset logic Signed-off-by: worksofliam --- src/api/components/cqsh/index.ts | 10 +++++----- src/extension.ts | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/api/components/cqsh/index.ts b/src/api/components/cqsh/index.ts index b5ae05bb9..5c70143ca 100644 --- a/src/api/components/cqsh/index.ts +++ b/src/api/components/cqsh/index.ts @@ -6,9 +6,9 @@ import { ComponentState, IBMiComponent } from "../component"; export class CustomQSh implements IBMiComponent { static ID = "cqsh"; - private static localAssetPath: string|undefined; + private localAssetPath: string|undefined; - static setLocalAssetPath(newPath: string) { + setLocalAssetPath(newPath: string) { this.localAssetPath = newPath; } @@ -41,17 +41,17 @@ export class CustomQSh implements IBMiComponent { } async update(connection: IBMi): Promise { - if (!CustomQSh.localAssetPath) { + if (!this.localAssetPath) { return `Error`; } - const assetExistsLocally = await exists(CustomQSh.localAssetPath); + const assetExistsLocally = await exists(this.localAssetPath); if (!assetExistsLocally) { return `Error`; } - await connection.getContent().uploadFiles([{ local: CustomQSh.localAssetPath, remote: this.installPath }]); + await connection.getContent().uploadFiles([{ local: this.localAssetPath, remote: this.installPath }]); await connection.sendCommand({ command: `chmod +x ${this.installPath}`, diff --git a/src/extension.ts b/src/extension.ts index f8225f86d..115309c41 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -113,9 +113,10 @@ export async function activate(context: ExtensionContext): Promise commands.executeCommand("code-for-ibmi.refreshProfileView"); }); - CustomQSh.setLocalAssetPath(path.join(context.extensionPath, `dist`, `cqsh`)); + const customQsh = new CustomQSh(); + customQsh.setLocalAssetPath(path.join(context.extensionPath, `dist`, customQsh.getFileName())); - extensionComponentRegistry.registerComponent(context, new CustomQSh()); + extensionComponentRegistry.registerComponent(context, customQsh); extensionComponentRegistry.registerComponent(context, new GetNewLibl); extensionComponentRegistry.registerComponent(context, new GetMemberInfo()); extensionComponentRegistry.registerComponent(context, new CopyToImport()); From 4a6d47faa0b8ecd53648983657c93bf8932caaf9 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Thu, 16 Jan 2025 21:49:39 -0500 Subject: [PATCH 34/46] Return new tools API from extension Signed-off-by: worksofliam --- src/Instance.ts | 4 +- src/api/tests/config.json | 51 ++++ src/api/tests/storage.json | 38 +++ src/commands/open.ts | 6 +- src/debug/certificates.ts | 4 +- src/debug/index.ts | 8 +- src/extension.ts | 2 + src/filesystems/local/deployTools.ts | 8 +- src/filesystems/local/git.ts | 6 +- src/filesystems/qsys/FSUtils.ts | 4 +- src/sandbox.ts | 4 +- src/testing/deployTools.ts | 4 +- src/typings.ts | 2 + src/ui/diagnostics.ts | 8 +- src/ui/tools.ts | 371 ++++++++++++++------------- src/ui/views/LibraryListView.ts | 4 +- src/ui/views/debugView.ts | 10 +- src/ui/views/ifsBrowser.ts | 10 +- src/ui/views/objectBrowser.ts | 10 +- src/webviews/settings/index.ts | 6 +- 20 files changed, 328 insertions(+), 232 deletions(-) create mode 100644 src/api/tests/config.json create mode 100644 src/api/tests/storage.json diff --git a/src/Instance.ts b/src/Instance.ts index 70f9965fb..bcc18fc80 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -2,13 +2,13 @@ import * as vscode from "vscode"; import { ConnectionData, IBMiEvent } from "./typings"; import IBMi, { ConnectionResult } from "./api/IBMi"; import { CodeForIStorage } from "./api/configuration/storage/CodeForIStorage"; -import { withContext } from "./ui/tools"; import { handleConnectionResults, messageCallback } from "./ui/connection"; import { VsStorage } from "./config/Storage"; import { VsCodeConfig } from "./config/Configuration"; import { ConnectionConfig } from "./api/configuration/config/ConnectionManager"; import { EventEmitter } from "stream"; import { ConnectionStorage } from "./api/configuration/storage/ConnectionStorage"; +import { VscodeTools } from "./ui/tools"; type IBMiEventSubscription = { func: Function, @@ -78,7 +78,7 @@ export default class Instance { } }; - return withContext("code-for-ibmi:connecting", async () => { + return VscodeTools.withContext("code-for-ibmi:connecting", async () => { while (true) { let customError: string|undefined; await vscode.window.withProgress({location: vscode.ProgressLocation.Notification, title: options.data.name, cancellable: true}, async (p, cancelToken) => { diff --git a/src/api/tests/config.json b/src/api/tests/config.json new file mode 100644 index 000000000..d9b33c0f0 --- /dev/null +++ b/src/api/tests/config.json @@ -0,0 +1,51 @@ +{ + "connectionSettings": [ + { + "name": "testsystem", + "host": "", + "objectFilters": [], + "libraryList": [ + "QGPL", + "QTEMP", + "QDEVELOP", + "QBLDSYS", + "QBLDSYSR" + ], + "autoClearTempData": false, + "customVariables": [], + "connectionProfiles": [], + "commandProfiles": [], + "ifsShortcuts": [ + "/home/LIAMA" + ], + "autoSortIFSShortcuts": false, + "homeDirectory": "/home/LIAMA", + "tempLibrary": "ILEDITOR", + "tempDir": "/tmp", + "currentLibrary": "QGPL", + "sourceASP": "", + "sourceFileCCSID": "*FILE", + "autoConvertIFSccsid": false, + "hideCompileErrors": [], + "enableSourceDates": false, + "sourceDateMode": "diff", + "sourceDateGutter": false, + "encodingFor5250": "default", + "terminalFor5250": "default", + "setDeviceNameFor5250": false, + "connectringStringFor5250": "localhost", + "autoSaveBeforeAction": false, + "showDescInLibList": false, + "debugPort": "8005", + "debugSepPort": "8008", + "debugUpdateProductionFiles": false, + "debugEnableDebugTracing": false, + "readOnlyMode": false, + "quickConnect": true, + "defaultDeploymentMethod": "", + "protectedPaths": [], + "showHiddenFiles": true, + "lastDownloadLocation": "/Users/barry" + } + ] +} \ No newline at end of file diff --git a/src/api/tests/storage.json b/src/api/tests/storage.json new file mode 100644 index 000000000..f25e0bfd8 --- /dev/null +++ b/src/api/tests/storage.json @@ -0,0 +1,38 @@ +{ + "serverSettingsCache_testsystem": { + "aspInfo": {}, + "qccsid": 65535, + "jobCcsid": 37, + "remoteFeatures": { + "git": "/QOpenSys/pkgs/bin/git", + "grep": "/QOpenSys/pkgs/bin/grep", + "tn5250": "/QOpenSys/pkgs/bin/tn5250", + "setccsid": "/usr/bin/setccsid", + "md5sum": "/QOpenSys/pkgs/bin/md5sum", + "bash": "/QOpenSys/pkgs/bin/bash", + "chsh": "/QOpenSys/pkgs/bin/chsh", + "stat": "/QOpenSys/pkgs/bin/stat", + "sort": "/QOpenSys/pkgs/bin/sort", + "GETNEWLIBL.PGM": "/QSYS.lib/ILEDITOR.lib/GETNEWLIBL.PGM", + "QZDFMDB2.PGM": "/QSYS.LIB/QZDFMDB2.PGM", + "startDebugService.sh": "/QIBM/ProdData/IBMiDebugService/bin/startDebugService.sh", + "attr": "/usr/bin/attr", + "iconv": "/usr/bin/iconv", + "tar": "/QOpenSys/pkgs/bin/tar", + "ls": "/QOpenSys/pkgs/bin/ls", + "find": "/QOpenSys/pkgs/bin/find", + "jdk80": "/QOpenSys/QIBM/ProdData/JavaVM/jdk80/64bit", + "jdk11": "/QOpenSys/QIBM/ProdData/JavaVM/jdk11/64bit", + "jdk17": "/QOpenSys/QIBM/ProdData/JavaVM/jdk17/64bit", + "openjdk11": "/QOpensys/pkgs/lib/jvm/openjdk-11", + "uname": "/usr/bin/uname" + }, + "remoteFeaturesKeys": "GETMBRINFO.SQL,GETNEWLIBL.PGM,QZDFMDB2.PGM,attr,bash,chsh,find,git,grep,iconv,jdk11,jdk17,jdk80,ls,md5sum,openjdk11,setccsid,sort,startDebugService.sh,stat,tar,tn5250,uname", + "badDataAreasChecked": true, + "libraryListValidated": true, + "pathChecked": true, + "userDefaultCCSID": 37, + "debugConfigLoaded": false, + "maximumArgsLength": 4191784 + } +} \ No newline at end of file diff --git a/src/commands/open.ts b/src/commands/open.ts index 7d2184496..47d16d57b 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -4,7 +4,7 @@ import Instance from "../Instance"; import { Tools } from "../api/Tools"; import { getUriFromPath, parseFSOptions } from "../filesystems/qsys/QSysFs"; import path from "path"; -import { findExistingDocument, findExistingDocumentUri } from "../ui/tools"; +import { VscodeTools } from "../ui/tools"; import IBMi from "../api/IBMi"; import { DefaultOpenMode } from "../api/configuration/config/ConnectionManager"; @@ -36,7 +36,7 @@ export function registerOpenCommands(instance: Instance): Disposable[] { const uri = getUriFromPath(path, options); - const existingUri = findExistingDocumentUri(uri); + const existingUri = VscodeTools.findExistingDocumentUri(uri); if (existingUri) { const existingOptions = parseFSOptions(existingUri); @@ -89,7 +89,7 @@ export function registerOpenCommands(instance: Instance): Disposable[] { commands.registerCommand("code-for-ibmi.refreshFile", async (uri?: Uri) => { let doc: TextDocument | undefined; if (uri) { - doc = findExistingDocument(uri); + doc = VscodeTools.findExistingDocument(uri); } else { const editor = window.activeTextEditor; doc = editor?.document; diff --git a/src/debug/certificates.ts b/src/debug/certificates.ts index dd333b63c..4e0943efe 100644 --- a/src/debug/certificates.ts +++ b/src/debug/certificates.ts @@ -8,7 +8,7 @@ import { instance } from '../instantiate'; import IBMi from "../api/IBMi"; import IBMiContent from '../api/IBMiContent'; import { Tools } from '../api/Tools'; -import { fileToPath } from '../ui/tools'; +import { VscodeTools } from '../ui/tools'; import { DebugConfiguration, SERVICE_CERTIFICATE, CLIENT_CERTIFICATE, getDebugServiceDetails, getJavaHome, DEBUG_CONFIG_FILE, LEGACY_CERT_DIRECTORY } from '../api/configuration/DebugConfiguration'; type HostInfo = { @@ -106,7 +106,7 @@ export async function setup(connection: IBMi, imported?: ImportedCertificate) { password = imported.password; if (imported.localFile) { setProgress("importing local certificate"); - await connection.getContent().uploadFiles([{ local: fileToPath(imported.localFile), remote: debugConfig.getRemoteServiceCertificatePath() }]); + await connection.getContent().uploadFiles([{ local: VscodeTools.fileToPath(imported.localFile), remote: debugConfig.getRemoteServiceCertificatePath() }]); } else if (imported.remoteFile) { setProgress("importing remote certificate"); diff --git a/src/debug/index.ts b/src/debug/index.ts index a2ef1e518..37a0eb9ec 100644 --- a/src/debug/index.ts +++ b/src/debug/index.ts @@ -11,7 +11,7 @@ import { Env, getEnvConfig } from "../filesystems/local/env"; import * as certificates from "./certificates"; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, resetDebugServiceDetails } from "../api/configuration/DebugConfiguration"; import * as server from "./server"; -import { withContext } from "../ui/tools"; +import { VscodeTools } from "../ui/tools"; import { getStoredPassword } from "../config/passwords"; const debugExtensionId = `IBM.ibmidebug`; @@ -257,7 +257,7 @@ export async function initialize(context: ExtensionContext) { if (connection) { const doSetup = await vscode.window.showWarningMessage(`Do you confirm you want to generate or import a new certificate for the Debug Service?`, { modal: true }, 'Generate', 'Import'); if (doSetup) { - withContext("code-for-ibmi:debugWorking", async () => { + VscodeTools.withContext("code-for-ibmi:debugWorking", async () => { if (!(await server.getDebugServiceJob()) || await server.stopService(connection)) { const debugConfig = await new DebugConfiguration(connection).load(); const clearResult = await connection.sendCommand({ command: `rm -f ${debugConfig.getRemoteServiceCertificatePath()} ${debugConfig.getRemoteClientCertificatePath()}` }); @@ -276,7 +276,7 @@ export async function initialize(context: ExtensionContext) { } }), vscode.commands.registerCommand(`code-for-ibmi.debug.setup.remote`, (doSetup?: 'Generate' | 'Import') => - withContext("code-for-ibmi:debugWorking", async () => { + VscodeTools.withContext("code-for-ibmi:debugWorking", async () => { const connection = instance.getConnection(); if (connection) { const ptfInstalled = server.debugPTFInstalled(); @@ -336,7 +336,7 @@ export async function initialize(context: ExtensionContext) { vscode.commands.registerCommand(`code-for-ibmi.debug.setup.local`, () => vscode.window.withProgress({ title: "Downloading Debug Service Certificate", location: vscode.ProgressLocation.Window }, async () => - await withContext("code-for-ibmi:debugWorking", async () => { + await VscodeTools.withContext("code-for-ibmi:debugWorking", async () => { const connection = instance.getConnection(); if (connection) { const ptfInstalled = server.debugPTFInstalled(); diff --git a/src/extension.ts b/src/extension.ts index 115309c41..4f63f23e2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -34,6 +34,7 @@ import { SettingsUI } from "./webviews/settings"; import { registerActionTools } from "./ui/actions"; import IBMi from "./api/IBMi"; import path from "path"; +import { VscodeTools } from "./ui/tools"; export async function activate(context: ExtensionContext): Promise { // Use the console to output diagnostic information (console.log) and errors (console.error) @@ -126,6 +127,7 @@ export async function activate(context: ExtensionContext): Promise deployTools: DeployTools, evfeventParser: parseErrors, tools: Tools, + vscodeTools: VscodeTools, componentRegistry: extensionComponentRegistry }; } diff --git a/src/filesystems/local/deployTools.ts b/src/filesystems/local/deployTools.ts index 3c08c51cd..0acb20c77 100644 --- a/src/filesystems/local/deployTools.ts +++ b/src/filesystems/local/deployTools.ts @@ -4,7 +4,7 @@ import vscode, { Uri, WorkspaceFolder } from 'vscode'; import { instance } from '../../instantiate'; import { LocalLanguageActions } from './LocalLanguageActions'; import { Deployment } from './deployment'; -import { getGitAPI, md5Hash } from '../../ui/tools'; +import { VscodeTools } from '../../ui/tools'; import { DeploymentMethod } from '../../api/types'; import { DeploymentParameters } from '../../typings'; @@ -68,7 +68,7 @@ export namespace DeployTools { const changes = Deployment.workspaceChanges.get(folder)?.size || 0; methods.push({ method: "changed" as DeploymentMethod, label: `Changes`, description: `${changes} change${changes > 1 ? `s` : ``} detected since last upload. ${!changes ? `Will skip deploy step.` : ``}` }); - if (getGitAPI()) { + if (VscodeTools.getGitAPI()) { methods.push( { method: "unstaged" as DeploymentMethod, label: `Working Changes`, description: `Unstaged changes in git` }, { method: "staged" as DeploymentMethod, label: `Staged Changes`, description: `` } @@ -216,7 +216,7 @@ export namespace DeployTools { export async function getDeployGitFiles(parameters: DeploymentParameters, changeType: 'staged' | 'working'): Promise { const useStagedChanges = (changeType == 'staged'); - const gitApi = getGitAPI(); + const gitApi = VscodeTools.getGitAPI(); if (gitApi && gitApi.repositories.length > 0) { const repository = gitApi.repositories.find(r => r.rootUri.fsPath === parameters.workspaceFolder.uri.fsPath); @@ -274,7 +274,7 @@ export namespace DeployTools { const uploads: vscode.Uri[] = []; for await (const file of localFiles) { const remote = remoteMD5.find(e => e.path === file.path); - const md5 = md5Hash(file.uri); + const md5 = VscodeTools.md5Hash(file.uri); if (!remote || remote.md5 !== md5) { uploads.push(file.uri); } diff --git a/src/filesystems/local/git.ts b/src/filesystems/local/git.ts index 586465dcc..2b28b658d 100644 --- a/src/filesystems/local/git.ts +++ b/src/filesystems/local/git.ts @@ -3,13 +3,13 @@ import { getBranchLibraryName } from "./env"; import { instance } from "../../instantiate"; import IBMi from "../../api/IBMi"; import IBMiContent from "../../api/IBMiContent"; -import { getGitAPI } from "../../ui/tools"; +import { VscodeTools } from "../../ui/tools"; import { ConnectionConfig } from "../../api/configuration/config/ConnectionManager"; const lastBranch: { [workspaceUri: string]: string } = {}; export function getGitBranch(workspaceFolder: WorkspaceFolder) { - const gitApi = getGitAPI(); + const gitApi = VscodeTools.getGitAPI(); if (gitApi) { const repo = gitApi.getRepository(workspaceFolder.uri); if (repo) { @@ -19,7 +19,7 @@ export function getGitBranch(workspaceFolder: WorkspaceFolder) { } export function setupGitEventHandler(context: ExtensionContext) { - const gitApi = getGitAPI(); + const gitApi = VscodeTools.getGitAPI(); if (gitApi) { gitApi.onDidOpenRepository((repo) => { diff --git a/src/filesystems/qsys/FSUtils.ts b/src/filesystems/qsys/FSUtils.ts index 84c7845df..3ff0d6e90 100644 --- a/src/filesystems/qsys/FSUtils.ts +++ b/src/filesystems/qsys/FSUtils.ts @@ -1,6 +1,6 @@ import path from "path"; import vscode, { l10n } from "vscode"; -import { findUriTabs } from "../../ui/tools"; +import { VscodeTools } from "../../ui/tools"; import IBMi from "../../api/IBMi"; import { ReconnectMode } from "../../api/configuration/config/ConnectionManager"; @@ -36,7 +36,7 @@ export async function reconnectFS(uri: vscode.Uri) { return true; } else { - for (const tab of findUriTabs(uri)) { + for (const tab of VscodeTools.findUriTabs(uri)) { await vscode.window.tabGroups.close(tab); } return false; diff --git a/src/sandbox.ts b/src/sandbox.ts index 81291d2d4..357e03b6f 100644 --- a/src/sandbox.ts +++ b/src/sandbox.ts @@ -3,7 +3,7 @@ import querystring from "querystring"; import { commands, ExtensionContext, l10n, Uri, window } from "vscode"; import { instance } from "./instantiate"; import { ConnectionData } from "./typings"; -import { getGitAPI } from "./ui/tools"; +import { VscodeTools } from "./ui/tools"; import IBMi from "./api/IBMi"; export async function registerUriHandler(context: ExtensionContext) { @@ -107,7 +107,7 @@ export async function handleStartup() { // If Sandbox mode is enabled, then the server and username can be inherited from the branch name if (env.VSCODE_IBMI_SANDBOX) { try { - const gitAPI = getGitAPI(); + const gitAPI = VscodeTools.getGitAPI(); if (gitAPI && gitAPI.repositories && gitAPI.repositories.length > 0) { const repo = gitAPI.repositories[0]; const branchName = repo.state.HEAD?.name; diff --git a/src/testing/deployTools.ts b/src/testing/deployTools.ts index d1b687b5d..c70bafa7d 100644 --- a/src/testing/deployTools.ts +++ b/src/testing/deployTools.ts @@ -10,7 +10,7 @@ import { Tools } from "../api/Tools"; import { DeployTools } from "../filesystems/local/deployTools"; import { instance } from "../instantiate"; import { Action, DeploymentMethod } from "../typings"; -import { md5Hash } from "../ui/tools"; +import { VscodeTools } from "../ui/tools"; import { runAction } from "../ui/actions"; type FileInfo = { @@ -260,7 +260,7 @@ async function getLocalFilesInfo() { const localFiles: FilesInfo = new Map; for await (const file of await vscode.workspace.findFiles(new vscode.RelativePattern(fakeProject.localPath!, "**/*"))) { const path = posix.join(basename(fakeProject.localPath!.path), posix.relative(fakeProject.localPath!.path, file.path)); - localFiles.set(path, { date: "unused", md5: md5Hash(file) }); + localFiles.set(path, { date: "unused", md5: VscodeTools.md5Hash(file) }); } return localFiles; } diff --git a/src/typings.ts b/src/typings.ts index a9f3c78ff..8a223e46a 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -7,6 +7,7 @@ import { ObjectFilters } from './api/configuration/config/ConnectionManager'; import { DeploymentMethod, FileError, IBMiMember, IBMiObject, WithPath } from "./api/types"; import { Ignore } from "ignore"; import { WorkspaceFolder } from "vscode"; +import { VscodeTools } from "./ui/tools"; export interface CodeForIBMi { instance: Instance, @@ -14,6 +15,7 @@ export interface CodeForIBMi { deployTools: typeof DeployTools, evfeventParser: (lines: string[]) => Map, tools: typeof Tools, + vscodeTools: typeof VscodeTools, componentRegistry: ComponentRegistry } diff --git a/src/ui/diagnostics.ts b/src/ui/diagnostics.ts index 26eb5f388..95703a81e 100644 --- a/src/ui/diagnostics.ts +++ b/src/ui/diagnostics.ts @@ -4,7 +4,7 @@ import { FileError } from "../typings"; import Instance from "../Instance"; import { getEvfeventFiles } from "../filesystems/local/actions"; import { parseErrors } from "../api/errors/parser"; -import { findExistingDocumentByName, findExistingDocumentUri } from "./tools"; +import { VscodeTools } from "./tools"; import IBMi from "../api/IBMi"; const ileDiagnostics = vscode.languages.createDiagnosticCollection(`ILE`); @@ -175,7 +175,7 @@ export function handleEvfeventLines(lines: string[], instance: Instance, evfeven // tabs like we do below. if (evfeventInfo.extension) { const baseName = file.split(`/`).pop(); - const openFile = findExistingDocumentByName(`${baseName}.${evfeventInfo.extension}`); + const openFile = VscodeTools.findExistingDocumentByName(`${baseName}.${evfeventInfo.extension}`); if (openFile) { ileDiagnostics.set(openFile, diagnostics); continue; @@ -185,10 +185,10 @@ export function handleEvfeventLines(lines: string[], instance: Instance, evfeven } if (file.startsWith(`/`)) { - ileDiagnostics.set(findExistingDocumentUri(vscode.Uri.from({ scheme: `streamfile`, path: file })), diagnostics); + ileDiagnostics.set(VscodeTools.findExistingDocumentUri(vscode.Uri.from({ scheme: `streamfile`, path: file })), diagnostics); } else { - const memberUri = findExistingDocumentUri(vscode.Uri.from({ scheme: `member`, path: `/${asp}${file}${evfeventInfo.extension ? `.` + evfeventInfo.extension : ``}` })); + const memberUri = VscodeTools.findExistingDocumentUri(vscode.Uri.from({ scheme: `member`, path: `/${asp}${file}${evfeventInfo.extension ? `.` + evfeventInfo.extension : ``}` })); ileDiagnostics.set(memberUri, diagnostics); } } diff --git a/src/ui/tools.ts b/src/ui/tools.ts index 5556ace54..470634533 100644 --- a/src/ui/tools.ts +++ b/src/ui/tools.ts @@ -9,199 +9,202 @@ import IBMi from '../api/IBMi'; let gitLookedUp: boolean; let gitAPI: API | undefined; -export function getGitAPI(): API | undefined { - if (!gitLookedUp) { - try { - gitAPI = vscode.extensions.getExtension(`vscode.git`)?.exports.getAPI(1); + +export namespace VscodeTools { + export function getGitAPI(): API | undefined { + if (!gitLookedUp) { + try { + gitAPI = vscode.extensions.getExtension(`vscode.git`)?.exports.getAPI(1); + } + catch (error) { + console.log(`Git extension issue.`, error); + } + finally { + gitLookedUp = true; + } } - catch (error) { - console.log(`Git extension issue.`, error); + return gitAPI; + } + + export function md5Hash(file: vscode.Uri): string { + const bytes = readFileSync(file.fsPath); + return Crypto.createHash("md5") + .update(bytes) + .digest("hex") + .toLowerCase(); + } + + /** + * Check whether two given uris point to the same file/member + */ + export function areEquivalentUris(uriA: vscode.Uri, uriB: vscode.Uri) { + return uriStringWithoutFragment(uriA) === uriStringWithoutFragment(uriB); + } + + /** + * We do this to find previously opened files with the same path, but different case OR readonly flags. + * Without this, it's possible for the same document to be opened twice simply due to the readonly flag. + */ + export function findExistingDocumentUri(uri: vscode.Uri) { + const possibleDoc = findExistingDocument(uri); + return possibleDoc?.uri || uri; + } + + export function findExistingDocument(uri: vscode.Uri) { + const baseUriString = uriStringWithoutFragment(uri); + const possibleDoc = vscode.workspace.textDocuments.find(document => uriStringWithoutFragment(document.uri) === baseUriString); + return possibleDoc; + } + + export function findExistingDocumentByName(nameAndExt: string) { + const possibleDoc = vscode.workspace.textDocuments.find(document => document.fileName.toLowerCase().endsWith(nameAndExt.toLowerCase())); + return possibleDoc ? possibleDoc.uri : undefined; + } + + /** + * We convert member to lowercase as members are case insensitive. + */ + function uriStringWithoutFragment(uri: vscode.Uri) { + // To lowercase because the URI path is case-insensitive + const baseUri = uri.scheme + `:` + uri.path; + const isCaseSensitive = (uri.scheme === `streamfile` && /^\/QOpenSys\//i.test(uri.path)); + return (isCaseSensitive ? baseUri : baseUri.toLowerCase()); + } + + /** + * Given the uri of a member or other resource, find all + * (if any) open tabs where that resource is being edited. + */ + export function findUriTabs(uriToFind: vscode.Uri | string): vscode.Tab[] { + let resourceTabs: vscode.Tab[] = []; + for (const group of vscode.window.tabGroups.all) { + group.tabs.filter(tab => + (tab.input instanceof vscode.TabInputText) + && (uriToFind instanceof vscode.Uri ? areEquivalentUris(tab.input.uri, uriToFind) : tab.input.uri.path.startsWith(`${uriToFind}/`)) + ).forEach(tab => { + resourceTabs.push(tab); + }); + } + return resourceTabs; + } + + + + export function generateTooltipHtmlTable(header: string, rows: Record) { + return `` + .concat(`${header ? `${header}` : ``}`) + .concat(`${Object.entries(rows) + .filter(([key, value]) => value !== undefined && value !== '') + .map(([key, value]) => ``) + .join(``)}` + ) + .concat(`
${vscode.l10n.t(key)}: ${value}
`); + } + + + const activeContexts: Map = new Map; + /** + * Runs a function while a context value is set to true. + * + * If multiple callers call this function with the same context, only the last one returning will unset the context value. + * + * @param context the context value that will be set to `true` during `task` execution + * @param task the function to run while the context value is `true` + */ + export async function withContext(context: string, task: () => Promise) { + try { + let stack = activeContexts.get(context); + if (stack === undefined) { + await vscode.commands.executeCommand(`setContext`, context, true); + activeContexts.set(context, 0); + } + else { + stack++; + activeContexts.set(context, stack); + } + return await task(); } finally { - gitLookedUp = true; + let stack = activeContexts.get(context); + if (stack !== undefined) { + if (stack) { + stack--; + activeContexts.set(context, stack); + } + else { + await vscode.commands.executeCommand(`setContext`, context, undefined); + activeContexts.delete(context); + } + } } } - return gitAPI; -} - -export function md5Hash(file: vscode.Uri): string { - const bytes = readFileSync(file.fsPath); - return Crypto.createHash("md5") - .update(bytes) - .digest("hex") - .toLowerCase(); -} - -/** - * Check whether two given uris point to the same file/member - */ -export function areEquivalentUris(uriA: vscode.Uri, uriB: vscode.Uri) { - return uriStringWithoutFragment(uriA) === uriStringWithoutFragment(uriB); -} - -/** - * We do this to find previously opened files with the same path, but different case OR readonly flags. - * Without this, it's possible for the same document to be opened twice simply due to the readonly flag. - */ -export function findExistingDocumentUri(uri: vscode.Uri) { - const possibleDoc = findExistingDocument(uri); - return possibleDoc?.uri || uri; -} - -export function findExistingDocument(uri: vscode.Uri) { - const baseUriString = uriStringWithoutFragment(uri); - const possibleDoc = vscode.workspace.textDocuments.find(document => uriStringWithoutFragment(document.uri) === baseUriString); - return possibleDoc; -} - -export function findExistingDocumentByName(nameAndExt: string) { - const possibleDoc = vscode.workspace.textDocuments.find(document => document.fileName.toLowerCase().endsWith(nameAndExt.toLowerCase())); - return possibleDoc ? possibleDoc.uri : undefined; -} - -/** - * We convert member to lowercase as members are case insensitive. - */ -function uriStringWithoutFragment(uri: vscode.Uri) { - // To lowercase because the URI path is case-insensitive - const baseUri = uri.scheme + `:` + uri.path; - const isCaseSensitive = (uri.scheme === `streamfile` && /^\/QOpenSys\//i.test(uri.path)); - return (isCaseSensitive ? baseUri : baseUri.toLowerCase()); -} - -/** - * Given the uri of a member or other resource, find all - * (if any) open tabs where that resource is being edited. -*/ -export function findUriTabs(uriToFind: vscode.Uri | string): vscode.Tab[] { - let resourceTabs: vscode.Tab[] = []; - for (const group of vscode.window.tabGroups.all) { - group.tabs.filter(tab => - (tab.input instanceof vscode.TabInputText) - && (uriToFind instanceof vscode.Uri ? areEquivalentUris(tab.input.uri, uriToFind) : tab.input.uri.path.startsWith(`${uriToFind}/`)) - ).forEach(tab => { - resourceTabs.push(tab); - }); - } - return resourceTabs; -} - - - -export function generateTooltipHtmlTable(header: string, rows: Record) { - return `` - .concat(`${header ? `${header}` : ``}`) - .concat(`${Object.entries(rows) - .filter(([key, value]) => value !== undefined && value !== '') - .map(([key, value]) => ``) - .join(``)}` - ) - .concat(`
${vscode.l10n.t(key)}: ${value}
`); -} - - -const activeContexts: Map = new Map; -/** - * Runs a function while a context value is set to true. - * - * If multiple callers call this function with the same context, only the last one returning will unset the context value. - * - * @param context the context value that will be set to `true` during `task` execution - * @param task the function to run while the context value is `true` - */ -export async function withContext(context: string, task: () => Promise) { - try { - let stack = activeContexts.get(context); - if (stack === undefined) { - await vscode.commands.executeCommand(`setContext`, context, true); - activeContexts.set(context, 0); + + export function fileToPath(file: string | vscode.Uri): string { + if (typeof file === "string") { + return Tools.fixWindowsPath(file); } else { - stack++; - activeContexts.set(context, stack); + return file.fsPath; } - return await task(); } - finally { - let stack = activeContexts.get(context); - if (stack !== undefined) { - if (stack) { - stack--; - activeContexts.set(context, stack); - } - else { - await vscode.commands.executeCommand(`setContext`, context, undefined); - activeContexts.delete(context); - } - } + + export function objectToToolTip(path: string, object: IBMiObject) { + const tooltip = new MarkdownString(generateTooltipHtmlTable(path, { + "Type": object.type, + "Attribute": object.attribute, + "Text": object.text, + "Size": object.size, + "Created": safeIsoValue(object.created), + "Changed": safeIsoValue(object.changed), + "Created by": object.created_by, + "Owner": object.owner, + "IASP": object.asp + })); + tooltip.supportHtml = true; + return tooltip; + } + + export async function sourcePhysicalFileToToolTip(connection: IBMi, path: string, object: IBMiObject) { + const content = connection.getContent(); + const tooltip = new MarkdownString(generateTooltipHtmlTable(path, { + "Text": object.text, + "Members": await content.countMembers(object), + "Length": object.sourceLength, + "CCSID": (await content.getAttributes(object, "CCSID"))?.CCSID || '?', + "IASP": object.asp + })); + tooltip.supportHtml = true; + return tooltip; + } + + export function memberToToolTip(path: string, member: IBMiMember) { + const tooltip = new MarkdownString(generateTooltipHtmlTable(path, { + "Text": member.text, + "Lines": member.lines, + "Created": safeIsoValue(member.created), + "Changed": safeIsoValue(member.changed) + })); + tooltip.supportHtml = true; + return tooltip; + } + + export function ifsFileToToolTip(path: string, ifsFile: IFSFile) { + const tooltip = new MarkdownString(generateTooltipHtmlTable(path, { + "Size": ifsFile.size, + "Modified": ifsFile.modified ? safeIsoValue(new Date(ifsFile.modified.getTime() - ifsFile.modified.getTimezoneOffset() * 60 * 1000)) : ``, + "Owner": ifsFile.owner ? ifsFile.owner.toUpperCase() : `` + })); + tooltip.supportHtml = true; + return tooltip; } -} - -export function fileToPath(file: string | vscode.Uri): string { - if (typeof file === "string") { - return Tools.fixWindowsPath(file); - } - else { - return file.fsPath; - } -} - -export function objectToToolTip(path: string, object: IBMiObject) { - const tooltip = new MarkdownString(generateTooltipHtmlTable(path, { - "Type": object.type, - "Attribute": object.attribute, - "Text": object.text, - "Size": object.size, - "Created": safeIsoValue(object.created), - "Changed": safeIsoValue(object.changed), - "Created by": object.created_by, - "Owner": object.owner, - "IASP": object.asp - })); - tooltip.supportHtml = true; - return tooltip; -} - -export async function sourcePhysicalFileToToolTip(connection: IBMi, path: string, object: IBMiObject) { - const content = connection.getContent(); - const tooltip = new MarkdownString(generateTooltipHtmlTable(path, { - "Text": object.text, - "Members": await content.countMembers(object), - "Length": object.sourceLength, - "CCSID": (await content.getAttributes(object, "CCSID"))?.CCSID || '?', - "IASP": object.asp - })); - tooltip.supportHtml = true; - return tooltip; -} - -export function memberToToolTip(path: string, member: IBMiMember) { - const tooltip = new MarkdownString(generateTooltipHtmlTable(path, { - "Text": member.text, - "Lines": member.lines, - "Created": safeIsoValue(member.created), - "Changed": safeIsoValue(member.changed) - })); - tooltip.supportHtml = true; - return tooltip; -} - -export function ifsFileToToolTip(path: string, ifsFile: IFSFile) { - const tooltip = new MarkdownString(generateTooltipHtmlTable(path, { - "Size": ifsFile.size, - "Modified": ifsFile.modified ? safeIsoValue(new Date(ifsFile.modified.getTime() - ifsFile.modified.getTimezoneOffset() * 60 * 1000)) : ``, - "Owner": ifsFile.owner ? ifsFile.owner.toUpperCase() : `` - })); - tooltip.supportHtml = true; - return tooltip; -} - - - -function safeIsoValue(date: Date | undefined) { - try { - return date ? date.toISOString().slice(0, 19).replace(`T`, ` `) : ``; - } catch (e) { - return `Unknown`; + + + + function safeIsoValue(date: Date | undefined) { + try { + return date ? date.toISOString().slice(0, 19).replace(`T`, ` `) : ``; + } catch (e) { + return `Unknown`; + } } } \ No newline at end of file diff --git a/src/ui/views/LibraryListView.ts b/src/ui/views/LibraryListView.ts index 79ef3c78c..ce6cf26e9 100644 --- a/src/ui/views/LibraryListView.ts +++ b/src/ui/views/LibraryListView.ts @@ -1,7 +1,7 @@ import vscode, { commands, l10n } from "vscode"; import { instance } from "../../instantiate"; import { IBMiObject, WithLibrary } from "../../typings"; -import { objectToToolTip } from "../tools"; +import { VscodeTools } from "../tools"; import { ConnectionConfig } from "../../api/configuration/config/ConnectionManager"; import IBMi from "../../api/IBMi"; @@ -302,7 +302,7 @@ class LibraryListNode extends vscode.TreeItem implements WithLibrary { ((context === `currentLibrary` ? `${l10n.t(`(current library)`)}` : ``) + (object.text !== `` && showDescInLibList ? ` ${object.text}` : ``) + (object.attribute !== `` ? ` (*${object.attribute})` : ``)).trim(); - this.tooltip = objectToToolTip([object.library, object.name].join(`/`), object); + this.tooltip = VscodeTools.objectToToolTip([object.library, object.name].join(`/`), object); } } diff --git a/src/ui/views/debugView.ts b/src/ui/views/debugView.ts index 840a0ca9a..c185b1bb8 100644 --- a/src/ui/views/debugView.ts +++ b/src/ui/views/debugView.ts @@ -4,7 +4,7 @@ import { checkClientCertificate, debugKeyFileExists, remoteCertificatesExists } import { DebugConfiguration, getDebugServiceDetails, SERVICE_CERTIFICATE } from "../../api/configuration/DebugConfiguration"; import { DebugJob, getDebugServerJob, getDebugServiceJob, isDebugEngineRunning, readActiveJob, readJVMInfo, startServer, startService, stopServer, stopService } from "../../debug/server"; import { instance } from "../../instantiate"; -import { withContext } from "../tools"; +import { VscodeTools } from "../tools"; import { BrowserItem } from "../types"; const title = "IBM i debugger"; @@ -49,9 +49,9 @@ export function initializeDebugBrowser(context: vscode.ExtensionContext) { debugTreeViewer, vscode.commands.registerCommand("code-for-ibmi.debug.refresh", updateDebugBrowser), vscode.commands.registerCommand("code-for-ibmi.debug.refresh.item", (item: DebugItem) => debugBrowser.refresh(item)), - vscode.commands.registerCommand("code-for-ibmi.debug.job.start", (item: DebugJobItem) => withContext(`code-for-ibmi:debugWorking`, () => item.start())), - vscode.commands.registerCommand("code-for-ibmi.debug.job.stop", (item: DebugJobItem) => withContext(`code-for-ibmi:debugWorking`, () => item.stop())), - vscode.commands.registerCommand("code-for-ibmi.debug.job.restart", async (item: DebugJobItem) => withContext(`code-for-ibmi:debugWorking`, async () => await item.stop() && item.start())), + vscode.commands.registerCommand("code-for-ibmi.debug.job.start", (item: DebugJobItem) => VscodeTools.withContext(`code-for-ibmi:debugWorking`, () => item.start())), + vscode.commands.registerCommand("code-for-ibmi.debug.job.stop", (item: DebugJobItem) => VscodeTools.withContext(`code-for-ibmi:debugWorking`, () => item.stop())), + vscode.commands.registerCommand("code-for-ibmi.debug.job.restart", async (item: DebugJobItem) => VscodeTools.withContext(`code-for-ibmi:debugWorking`, async () => await item.stop() && item.start())), ); } @@ -68,7 +68,7 @@ class DebugBrowser implements vscode.TreeDataProvider { } async getChildren(item?: DebugItem) { - return withContext(`code-for-ibmi:debugWorking`, async () => item?.getChildren?.() || this.getRootItems()); + return VscodeTools.withContext(`code-for-ibmi:debugWorking`, async () => item?.getChildren?.() || this.getRootItems()); } private async getRootItems() { diff --git a/src/ui/views/ifsBrowser.ts b/src/ui/views/ifsBrowser.ts index c3fbd93e5..22e4249ec 100644 --- a/src/ui/views/ifsBrowser.ts +++ b/src/ui/views/ifsBrowser.ts @@ -8,7 +8,7 @@ import { Search } from "../../api/Search"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; import { FocusOptions, IFSFile, IFS_BROWSER_MIMETYPE, OBJECT_BROWSER_MIMETYPE, SearchHit, SearchResults, WithPath } from "../../typings"; -import { fileToPath, findUriTabs, ifsFileToToolTip } from "../tools"; +import { VscodeTools } from "../tools"; import IBMi from "../../api/IBMi"; import { BrowserItem, BrowserItemParameters } from "../types"; @@ -101,7 +101,7 @@ class IFSItem extends BrowserItem implements WithPath { constructor(readonly file: IFSFile, parameters: BrowserItemParameters) { super(file.name, parameters); this.path = file.path; - this.tooltip = ifsFileToToolTip(this.path, file); + this.tooltip = VscodeTools.ifsFileToToolTip(this.path, file); } sortBy(sort: SortOptions) { @@ -520,7 +520,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { for (const directory of directoriesToUpload) { const name = path.basename(directory.fsPath); progress.report({ message: l10n.t(`sending {0} directory...`, name) }) - await connection.getContent().uploadDirectory(fileToPath(directory), path.posix.join(root, name), { concurrency: 5 }) + await connection.getContent().uploadDirectory(VscodeTools.fileToPath(directory), path.posix.join(root, name), { concurrency: 5 }) } } @@ -622,14 +622,14 @@ Please type "{0}" to confirm deletion.`, dirName); return; } // Check if the streamfile is currently open in an editor tab - oldFileTabs.push(...findUriTabs(node.resourceUri)); + oldFileTabs.push(...VscodeTools.findUriTabs(node.resourceUri)); if (oldFileTabs.find(tab => tab.isDirty)) { vscode.window.showErrorMessage(l10n.t(`Error renaming/moving {0}! {1}`, typeLabel, l10n.t("The file has unsaved changes."))); return; } } else { // Check if there are streamfiles in the directory which are currently open in an editor tab - oldFileTabs.push(...findUriTabs(node.file.path)); + oldFileTabs.push(...VscodeTools.findUriTabs(node.file.path)); if (oldFileTabs.find(tab => tab.isDirty)) { vscode.window.showErrorMessage(l10n.t(`Error renaming/moving {0}! {1}`, typeLabel, l10n.t("The directory has file(s) with unsaved changes."))); return; diff --git a/src/ui/views/objectBrowser.ts b/src/ui/views/objectBrowser.ts index 285c25495..cd026c84d 100644 --- a/src/ui/views/objectBrowser.ts +++ b/src/ui/views/objectBrowser.ts @@ -11,7 +11,7 @@ import { getMemberUri } from "../../filesystems/qsys/QSysFs"; import { instance } from "../../instantiate"; import { CommandResult, FilteredItem, FocusOptions, IBMiMember, IBMiObject, MemberItem, OBJECT_BROWSER_MIMETYPE, ObjectItem, WithLibrary } from "../../typings"; import { editFilter } from "../../webviews/filters"; -import { findUriTabs, memberToToolTip, objectToToolTip, sourcePhysicalFileToToolTip } from "../tools"; +import { VscodeTools } from "../tools"; import { DefaultOpenMode, ObjectFilters } from "../../api/configuration/config/ConnectionManager"; import { BrowserItem, BrowserItemParameters } from "../types"; @@ -307,7 +307,7 @@ class ObjectBrowserSourcePhysicalFileItem extends ObjectBrowserItem implements O } getToolTip() { - return sourcePhysicalFileToToolTip(getConnection(), this.path, this.object); + return VscodeTools.sourcePhysicalFileToToolTip(getConnection(), this.path, this.object); } } @@ -326,7 +326,7 @@ class ObjectBrowserObjectItem extends ObjectBrowserItem implements ObjectItem, W this.updateDescription(); this.contextValue = `object.${type.toLowerCase()}${object.attribute ? `.${object.attribute}` : ``}${isLibrary ? '_library' : ''}${this.isProtected() ? `_readonly` : ``}`; - this.tooltip = objectToToolTip(this.path, object); + this.tooltip = VscodeTools.objectToToolTip(this.path, object); this.resourceUri = vscode.Uri.from({ scheme: `object`, @@ -378,7 +378,7 @@ class ObjectBrowserMemberItem extends ObjectBrowserItem implements MemberItem { this.resourceUri = getMemberUri(member, { readonly }); this.path = this.resourceUri.path.substring(1); - this.tooltip = memberToToolTip(this.path, member); + this.tooltip = VscodeTools.memberToToolTip(this.path, member); this.sortBy = (sort: SortOptions) => parent.sortBy(sort); @@ -710,7 +710,7 @@ export function initializeObjectBrowser(context: vscode.ExtensionContext) { let newNameOK; // Check if the member is currently open in an editor tab. - const oldMemberTabs = findUriTabs(oldUri); + const oldMemberTabs = VscodeTools.findUriTabs(oldUri); // If the member is currently open in an editor tab, and // the member has unsaved changes, then prevent the renaming operation. diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index ad486e642..772b343ea 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -8,7 +8,7 @@ import { isSEPSupported } from "../../debug/server"; import { extensionComponentRegistry } from "../../api/components/manager"; import { instance } from "../../instantiate"; import { ConnectionData, Server } from '../../typings'; -import { withContext } from "../../ui/tools"; +import { VscodeTools } from "../../ui/tools"; import IBMi from "../../api/IBMi"; import { ConnectionConfig, ConnectionManager } from "../../api/configuration/config/ConnectionManager"; import { deleteStoredPassword, getStoredPassword, setStoredPassword } from "../../config/passwords"; @@ -262,7 +262,7 @@ export class SettingsUI { .addHorizontalRule() .addButtons({ id: `save`, label: `Save settings`, requiresValidation: true }); - await withContext(EDITING_CONTEXT, async () => { + await VscodeTools.withContext(EDITING_CONTEXT, async () => { const page = await ui.loadPage(`Settings: ${config.name}`); if (page) { page.panel.dispose(); @@ -375,7 +375,7 @@ export class SettingsUI { { id: `removeAuth`, label: vscode.l10n.t(`Remove auth methods`) } ); - await withContext(EDITING_CONTEXT, async () => { + await VscodeTools.withContext(EDITING_CONTEXT, async () => { const page = await ui.loadPage(vscode.l10n.t(`Login Settings: "{0}"`, name)); if (page && page.data) { page.panel.dispose(); From 677f18f74b0b1674fbdcd66ef0f4aba33196d665 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Thu, 16 Jan 2025 22:06:35 -0500 Subject: [PATCH 35/46] Move path normalisation back to internal tools Signed-off-by: worksofliam --- src/api/IBMiContent.ts | 17 +++++++++-------- src/api/Tools.ts | 10 ++++++++++ src/debug/certificates.ts | 2 +- src/typings.ts | 3 ++- src/ui/tools.ts | 9 --------- src/ui/views/ifsBrowser.ts | 2 +- 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/api/IBMiContent.ts b/src/api/IBMiContent.ts index 86eb0376f..9dea1ca53 100644 --- a/src/api/IBMiContent.ts +++ b/src/api/IBMiContent.ts @@ -10,6 +10,7 @@ import { FilterType, parseFilter, singleGenericName } from './Filter'; import { default as IBMi } from './IBMi'; import { Tools } from './Tools'; import { ObjectTypes } from './import/Objects'; +import { EditorPath } from '../typings'; const tmpFile = util.promisify(tmp.file); const readFileAsync = util.promisify(fs.readFile); const writeFileAsync = util.promisify(fs.writeFile); @@ -1043,19 +1044,19 @@ export default class IBMiContent { } } - async uploadFiles(files: { local: string, remote: string }[], options?: node_ssh.SSHPutFilesOptions) { - await this.ibmi.client!.putFiles(files.map(f => { return { local: f.local, remote: f.remote } }), options); + async uploadFiles(files: { local: EditorPath, remote: string }[], options?: node_ssh.SSHPutFilesOptions) { + await this.ibmi.client!.putFiles(files.map(f => { return { local: Tools.fileToPath(f.local), remote: f.remote } }), options); } - async downloadFile(localFile: string, remoteFile: string) { - await this.ibmi.client!.getFile(localFile, remoteFile); + async downloadFile(localFile: EditorPath, remoteFile: string) { + await this.ibmi.client!.getFile(Tools.fileToPath(localFile), remoteFile); } - async uploadDirectory(localDirectory: string, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { - await this.ibmi.client!.putDirectory(localDirectory, remoteDirectory, options); + async uploadDirectory(localDirectory: EditorPath, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { + await this.ibmi.client!.putDirectory(Tools.fileToPath(localDirectory), remoteDirectory, options); } - async downloadDirectory(localDirectory: string, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { - await this.ibmi.client!.getDirectory(localDirectory, remoteDirectory, options); + async downloadDirectory(localDirectory: EditorPath, remoteDirectory: string, options?: node_ssh.SSHGetPutDirectoryOptions) { + await this.ibmi.client!.getDirectory(Tools.fileToPath(localDirectory), remoteDirectory, options); } } \ No newline at end of file diff --git a/src/api/Tools.ts b/src/api/Tools.ts index fd605047f..3df788656 100644 --- a/src/api/Tools.ts +++ b/src/api/Tools.ts @@ -2,6 +2,7 @@ import os from "os"; import path from "path"; import { IBMiMessage, IBMiMessages, QsysPath } from './types'; +import { EditorPath } from "../typings"; export namespace Tools { export class SqlError extends Error { @@ -298,6 +299,15 @@ export namespace Tools { return statements; } + export function fileToPath(file: EditorPath): string { + if (typeof file === "string") { + return Tools.fixWindowsPath(file); + } + else { + return file.fsPath; + } + } + export function fixWindowsPath(path: string) { if (process.platform === `win32` && path[0] === `/`) { //Issue with getFile not working propertly on Windows diff --git a/src/debug/certificates.ts b/src/debug/certificates.ts index 4e0943efe..17779e703 100644 --- a/src/debug/certificates.ts +++ b/src/debug/certificates.ts @@ -106,7 +106,7 @@ export async function setup(connection: IBMi, imported?: ImportedCertificate) { password = imported.password; if (imported.localFile) { setProgress("importing local certificate"); - await connection.getContent().uploadFiles([{ local: VscodeTools.fileToPath(imported.localFile), remote: debugConfig.getRemoteServiceCertificatePath() }]); + await connection.getContent().uploadFiles([{ local: imported.localFile, remote: debugConfig.getRemoteServiceCertificatePath() }]); } else if (imported.remoteFile) { setProgress("importing remote certificate"); diff --git a/src/typings.ts b/src/typings.ts index 8a223e46a..f24400696 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -19,7 +19,6 @@ export interface CodeForIBMi { componentRegistry: ComponentRegistry } - export interface FilteredItem { filter: ObjectFilters } @@ -39,6 +38,8 @@ export interface DeploymentParameters { ignoreRules?: Ignore } +export type EditorPath = string | { fsPath: string }; + export * from "./api/types"; export * from "./ui/types"; export * from "./filesystems/local/types"; \ No newline at end of file diff --git a/src/ui/tools.ts b/src/ui/tools.ts index 470634533..2f91f7c45 100644 --- a/src/ui/tools.ts +++ b/src/ui/tools.ts @@ -139,15 +139,6 @@ export namespace VscodeTools { } } - export function fileToPath(file: string | vscode.Uri): string { - if (typeof file === "string") { - return Tools.fixWindowsPath(file); - } - else { - return file.fsPath; - } - } - export function objectToToolTip(path: string, object: IBMiObject) { const tooltip = new MarkdownString(generateTooltipHtmlTable(path, { "Type": object.type, diff --git a/src/ui/views/ifsBrowser.ts b/src/ui/views/ifsBrowser.ts index 22e4249ec..54c56dbbe 100644 --- a/src/ui/views/ifsBrowser.ts +++ b/src/ui/views/ifsBrowser.ts @@ -520,7 +520,7 @@ export function initializeIFSBrowser(context: vscode.ExtensionContext) { for (const directory of directoriesToUpload) { const name = path.basename(directory.fsPath); progress.report({ message: l10n.t(`sending {0} directory...`, name) }) - await connection.getContent().uploadDirectory(VscodeTools.fileToPath(directory), path.posix.join(root, name), { concurrency: 5 }) + await connection.getContent().uploadDirectory(directory, path.posix.join(root, name), { concurrency: 5 }) } } From 04caaa4e3ead2df6bb792a1f70d1d1cffe92da37 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Thu, 16 Jan 2025 22:07:03 -0500 Subject: [PATCH 36/46] Rename UI tools file Signed-off-by: worksofliam --- src/Instance.ts | 2 +- src/commands/open.ts | 2 +- src/debug/certificates.ts | 2 +- src/debug/index.ts | 2 +- src/extension.ts | 2 +- src/filesystems/local/deployTools.ts | 2 +- src/filesystems/local/git.ts | 2 +- src/filesystems/qsys/FSUtils.ts | 2 +- src/sandbox.ts | 2 +- src/testing/deployTools.ts | 2 +- src/typings.ts | 2 +- src/ui/diagnostics.ts | 2 +- src/ui/views/LibraryListView.ts | 2 +- src/ui/views/debugView.ts | 2 +- src/ui/views/ifsBrowser.ts | 2 +- src/ui/views/objectBrowser.ts | 2 +- src/ui/{tools.ts => vscodeTools.ts} | 0 src/webviews/settings/index.ts | 2 +- 18 files changed, 17 insertions(+), 17 deletions(-) rename src/ui/{tools.ts => vscodeTools.ts} (100%) diff --git a/src/Instance.ts b/src/Instance.ts index bcc18fc80..7f6069d25 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -8,7 +8,7 @@ import { VsCodeConfig } from "./config/Configuration"; import { ConnectionConfig } from "./api/configuration/config/ConnectionManager"; import { EventEmitter } from "stream"; import { ConnectionStorage } from "./api/configuration/storage/ConnectionStorage"; -import { VscodeTools } from "./ui/tools"; +import { VscodeTools } from "./ui/vscodeTools"; type IBMiEventSubscription = { func: Function, diff --git a/src/commands/open.ts b/src/commands/open.ts index 47d16d57b..e7d037b89 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -4,7 +4,7 @@ import Instance from "../Instance"; import { Tools } from "../api/Tools"; import { getUriFromPath, parseFSOptions } from "../filesystems/qsys/QSysFs"; import path from "path"; -import { VscodeTools } from "../ui/tools"; +import { VscodeTools } from "../ui/vscodeTools"; import IBMi from "../api/IBMi"; import { DefaultOpenMode } from "../api/configuration/config/ConnectionManager"; diff --git a/src/debug/certificates.ts b/src/debug/certificates.ts index 17779e703..e9fcad477 100644 --- a/src/debug/certificates.ts +++ b/src/debug/certificates.ts @@ -8,7 +8,7 @@ import { instance } from '../instantiate'; import IBMi from "../api/IBMi"; import IBMiContent from '../api/IBMiContent'; import { Tools } from '../api/Tools'; -import { VscodeTools } from '../ui/tools'; +import { VscodeTools } from '../ui/vscodeTools'; import { DebugConfiguration, SERVICE_CERTIFICATE, CLIENT_CERTIFICATE, getDebugServiceDetails, getJavaHome, DEBUG_CONFIG_FILE, LEGACY_CERT_DIRECTORY } from '../api/configuration/DebugConfiguration'; type HostInfo = { diff --git a/src/debug/index.ts b/src/debug/index.ts index 37a0eb9ec..ad9de0e3b 100644 --- a/src/debug/index.ts +++ b/src/debug/index.ts @@ -11,7 +11,7 @@ import { Env, getEnvConfig } from "../filesystems/local/env"; import * as certificates from "./certificates"; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, resetDebugServiceDetails } from "../api/configuration/DebugConfiguration"; import * as server from "./server"; -import { VscodeTools } from "../ui/tools"; +import { VscodeTools } from "../ui/vscodeTools"; import { getStoredPassword } from "../config/passwords"; const debugExtensionId = `IBM.ibmidebug`; diff --git a/src/extension.ts b/src/extension.ts index 4f63f23e2..1579832ee 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -34,7 +34,7 @@ import { SettingsUI } from "./webviews/settings"; import { registerActionTools } from "./ui/actions"; import IBMi from "./api/IBMi"; import path from "path"; -import { VscodeTools } from "./ui/tools"; +import { VscodeTools } from "./ui/vscodeTools"; export async function activate(context: ExtensionContext): Promise { // Use the console to output diagnostic information (console.log) and errors (console.error) diff --git a/src/filesystems/local/deployTools.ts b/src/filesystems/local/deployTools.ts index 0acb20c77..638cef4d5 100644 --- a/src/filesystems/local/deployTools.ts +++ b/src/filesystems/local/deployTools.ts @@ -4,7 +4,7 @@ import vscode, { Uri, WorkspaceFolder } from 'vscode'; import { instance } from '../../instantiate'; import { LocalLanguageActions } from './LocalLanguageActions'; import { Deployment } from './deployment'; -import { VscodeTools } from '../../ui/tools'; +import { VscodeTools } from '../../ui/vscodeTools'; import { DeploymentMethod } from '../../api/types'; import { DeploymentParameters } from '../../typings'; diff --git a/src/filesystems/local/git.ts b/src/filesystems/local/git.ts index 2b28b658d..194bc5dc3 100644 --- a/src/filesystems/local/git.ts +++ b/src/filesystems/local/git.ts @@ -3,7 +3,7 @@ import { getBranchLibraryName } from "./env"; import { instance } from "../../instantiate"; import IBMi from "../../api/IBMi"; import IBMiContent from "../../api/IBMiContent"; -import { VscodeTools } from "../../ui/tools"; +import { VscodeTools } from "../../ui/vscodeTools"; import { ConnectionConfig } from "../../api/configuration/config/ConnectionManager"; const lastBranch: { [workspaceUri: string]: string } = {}; diff --git a/src/filesystems/qsys/FSUtils.ts b/src/filesystems/qsys/FSUtils.ts index 3ff0d6e90..c392dfeb2 100644 --- a/src/filesystems/qsys/FSUtils.ts +++ b/src/filesystems/qsys/FSUtils.ts @@ -1,6 +1,6 @@ import path from "path"; import vscode, { l10n } from "vscode"; -import { VscodeTools } from "../../ui/tools"; +import { VscodeTools } from "../../ui/vscodeTools"; import IBMi from "../../api/IBMi"; import { ReconnectMode } from "../../api/configuration/config/ConnectionManager"; diff --git a/src/sandbox.ts b/src/sandbox.ts index 357e03b6f..92a810578 100644 --- a/src/sandbox.ts +++ b/src/sandbox.ts @@ -3,7 +3,7 @@ import querystring from "querystring"; import { commands, ExtensionContext, l10n, Uri, window } from "vscode"; import { instance } from "./instantiate"; import { ConnectionData } from "./typings"; -import { VscodeTools } from "./ui/tools"; +import { VscodeTools } from "./ui/vscodeTools"; import IBMi from "./api/IBMi"; export async function registerUriHandler(context: ExtensionContext) { diff --git a/src/testing/deployTools.ts b/src/testing/deployTools.ts index c70bafa7d..4f246074e 100644 --- a/src/testing/deployTools.ts +++ b/src/testing/deployTools.ts @@ -10,7 +10,7 @@ import { Tools } from "../api/Tools"; import { DeployTools } from "../filesystems/local/deployTools"; import { instance } from "../instantiate"; import { Action, DeploymentMethod } from "../typings"; -import { VscodeTools } from "../ui/tools"; +import { VscodeTools } from "../ui/vscodeTools"; import { runAction } from "../ui/actions"; type FileInfo = { diff --git a/src/typings.ts b/src/typings.ts index f24400696..99ebb446f 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -7,7 +7,7 @@ import { ObjectFilters } from './api/configuration/config/ConnectionManager'; import { DeploymentMethod, FileError, IBMiMember, IBMiObject, WithPath } from "./api/types"; import { Ignore } from "ignore"; import { WorkspaceFolder } from "vscode"; -import { VscodeTools } from "./ui/tools"; +import { VscodeTools } from "./ui/vscodeTools"; export interface CodeForIBMi { instance: Instance, diff --git a/src/ui/diagnostics.ts b/src/ui/diagnostics.ts index 95703a81e..598080502 100644 --- a/src/ui/diagnostics.ts +++ b/src/ui/diagnostics.ts @@ -4,7 +4,7 @@ import { FileError } from "../typings"; import Instance from "../Instance"; import { getEvfeventFiles } from "../filesystems/local/actions"; import { parseErrors } from "../api/errors/parser"; -import { VscodeTools } from "./tools"; +import { VscodeTools } from "./vscodeTools"; import IBMi from "../api/IBMi"; const ileDiagnostics = vscode.languages.createDiagnosticCollection(`ILE`); diff --git a/src/ui/views/LibraryListView.ts b/src/ui/views/LibraryListView.ts index ce6cf26e9..e29c54d38 100644 --- a/src/ui/views/LibraryListView.ts +++ b/src/ui/views/LibraryListView.ts @@ -1,7 +1,7 @@ import vscode, { commands, l10n } from "vscode"; import { instance } from "../../instantiate"; import { IBMiObject, WithLibrary } from "../../typings"; -import { VscodeTools } from "../tools"; +import { VscodeTools } from "../vscodeTools"; import { ConnectionConfig } from "../../api/configuration/config/ConnectionManager"; import IBMi from "../../api/IBMi"; diff --git a/src/ui/views/debugView.ts b/src/ui/views/debugView.ts index c185b1bb8..3033403df 100644 --- a/src/ui/views/debugView.ts +++ b/src/ui/views/debugView.ts @@ -4,7 +4,7 @@ import { checkClientCertificate, debugKeyFileExists, remoteCertificatesExists } import { DebugConfiguration, getDebugServiceDetails, SERVICE_CERTIFICATE } from "../../api/configuration/DebugConfiguration"; import { DebugJob, getDebugServerJob, getDebugServiceJob, isDebugEngineRunning, readActiveJob, readJVMInfo, startServer, startService, stopServer, stopService } from "../../debug/server"; import { instance } from "../../instantiate"; -import { VscodeTools } from "../tools"; +import { VscodeTools } from "../vscodeTools"; import { BrowserItem } from "../types"; const title = "IBM i debugger"; diff --git a/src/ui/views/ifsBrowser.ts b/src/ui/views/ifsBrowser.ts index 54c56dbbe..f9ea0dc00 100644 --- a/src/ui/views/ifsBrowser.ts +++ b/src/ui/views/ifsBrowser.ts @@ -8,7 +8,7 @@ import { Search } from "../../api/Search"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; import { FocusOptions, IFSFile, IFS_BROWSER_MIMETYPE, OBJECT_BROWSER_MIMETYPE, SearchHit, SearchResults, WithPath } from "../../typings"; -import { VscodeTools } from "../tools"; +import { VscodeTools } from "../vscodeTools"; import IBMi from "../../api/IBMi"; import { BrowserItem, BrowserItemParameters } from "../types"; diff --git a/src/ui/views/objectBrowser.ts b/src/ui/views/objectBrowser.ts index cd026c84d..3662509ab 100644 --- a/src/ui/views/objectBrowser.ts +++ b/src/ui/views/objectBrowser.ts @@ -11,7 +11,7 @@ import { getMemberUri } from "../../filesystems/qsys/QSysFs"; import { instance } from "../../instantiate"; import { CommandResult, FilteredItem, FocusOptions, IBMiMember, IBMiObject, MemberItem, OBJECT_BROWSER_MIMETYPE, ObjectItem, WithLibrary } from "../../typings"; import { editFilter } from "../../webviews/filters"; -import { VscodeTools } from "../tools"; +import { VscodeTools } from "../vscodeTools"; import { DefaultOpenMode, ObjectFilters } from "../../api/configuration/config/ConnectionManager"; import { BrowserItem, BrowserItemParameters } from "../types"; diff --git a/src/ui/tools.ts b/src/ui/vscodeTools.ts similarity index 100% rename from src/ui/tools.ts rename to src/ui/vscodeTools.ts diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 772b343ea..05845af93 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -8,7 +8,7 @@ import { isSEPSupported } from "../../debug/server"; import { extensionComponentRegistry } from "../../api/components/manager"; import { instance } from "../../instantiate"; import { ConnectionData, Server } from '../../typings'; -import { VscodeTools } from "../../ui/tools"; +import { VscodeTools } from "../../ui/vscodeTools"; import IBMi from "../../api/IBMi"; import { ConnectionConfig, ConnectionManager } from "../../api/configuration/config/ConnectionManager"; import { deleteStoredPassword, getStoredPassword, setStoredPassword } from "../../config/passwords"; From 811c59aafc3bea5bb25eae60974ab0a444c44bde Mon Sep 17 00:00:00 2001 From: worksofliam Date: Thu, 16 Jan 2025 22:11:00 -0500 Subject: [PATCH 37/46] Re-implement old channel clearing logic Signed-off-by: worksofliam --- src/Instance.ts | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/Instance.ts b/src/Instance.ts index 7f6069d25..8517637cd 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -26,7 +26,19 @@ export interface ConnectionOptions { export default class Instance { private connection: IBMi | undefined; - private outputChannel: vscode.OutputChannel = vscode.window.createOutputChannel(`Code for IBM i`); + + private output = { + channel: vscode.window.createOutputChannel(`Code for IBM i`), + content: ``, + writeCount: 0 + }; + + private resetOutput() { + this.output.channel.clear(); + this.output.content = ``; + this.output.writeCount = 0; + } + private storage: ConnectionStorage; private emitter: vscode.EventEmitter = new vscode.EventEmitter(); private subscribers: Map = new Map; @@ -45,9 +57,14 @@ export default class Instance { connect(options: ConnectionOptions): Promise { const connection = new IBMi(); - this.outputChannel.clear(); + this.resetOutput(); connection.appendOutput = (message) => { - this.outputChannel.append(message); + if (this.output.writeCount > 150) { + this.resetOutput(); + } + + this.output.channel.append(message); + this.output.writeCount++; } let result: ConnectionResult; @@ -62,13 +79,12 @@ export default class Instance { let reconnect = choice === `Yes`; let collectLogs = choice === `No, get logs`; - // TODO: how to get output channel stuff? - // if (collectLogs) { - // const logs = conn.getOutputChannelContent(); - // vscode.workspace.openTextDocument({ content: logs, language: `plaintext` }).then(doc => { - // vscode.window.showTextDocument(doc); - // }); - // } + if (collectLogs) { + const logs = this.output.content; + vscode.workspace.openTextDocument({ content: logs, language: `plaintext` }).then(doc => { + vscode.window.showTextDocument(doc); + }); + } this.disconnect(); From a4a14fee156b5bb8629604c4011e5cc5d873fd62 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Fri, 17 Jan 2025 09:31:16 -0500 Subject: [PATCH 38/46] No longer export two tools suites on extension Signed-off-by: worksofliam --- src/Instance.ts | 2 +- src/commands/open.ts | 2 +- src/debug/certificates.ts | 2 +- src/debug/index.ts | 2 +- src/extension.ts | 5 ++--- src/filesystems/local/deployTools.ts | 2 +- src/filesystems/local/git.ts | 2 +- src/filesystems/qsys/FSUtils.ts | 2 +- src/sandbox.ts | 2 +- src/testing/deployTools.ts | 2 +- src/typings.ts | 5 ++--- src/ui/{vscodeTools.ts => Tools.ts} | 16 +++++++++++++++- src/ui/diagnostics.ts | 2 +- src/ui/views/LibraryListView.ts | 2 +- src/ui/views/debugView.ts | 2 +- src/ui/views/ifsBrowser.ts | 2 +- src/ui/views/objectBrowser.ts | 2 +- src/webviews/settings/index.ts | 2 +- 18 files changed, 34 insertions(+), 22 deletions(-) rename src/ui/{vscodeTools.ts => Tools.ts} (91%) diff --git a/src/Instance.ts b/src/Instance.ts index 8517637cd..c613497bd 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -8,7 +8,7 @@ import { VsCodeConfig } from "./config/Configuration"; import { ConnectionConfig } from "./api/configuration/config/ConnectionManager"; import { EventEmitter } from "stream"; import { ConnectionStorage } from "./api/configuration/storage/ConnectionStorage"; -import { VscodeTools } from "./ui/vscodeTools"; +import { VscodeTools } from "./ui/Tools"; type IBMiEventSubscription = { func: Function, diff --git a/src/commands/open.ts b/src/commands/open.ts index e7d037b89..06685fe5b 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -4,7 +4,7 @@ import Instance from "../Instance"; import { Tools } from "../api/Tools"; import { getUriFromPath, parseFSOptions } from "../filesystems/qsys/QSysFs"; import path from "path"; -import { VscodeTools } from "../ui/vscodeTools"; +import { VscodeTools } from "../ui/Tools"; import IBMi from "../api/IBMi"; import { DefaultOpenMode } from "../api/configuration/config/ConnectionManager"; diff --git a/src/debug/certificates.ts b/src/debug/certificates.ts index e9fcad477..a568db53c 100644 --- a/src/debug/certificates.ts +++ b/src/debug/certificates.ts @@ -8,7 +8,7 @@ import { instance } from '../instantiate'; import IBMi from "../api/IBMi"; import IBMiContent from '../api/IBMiContent'; import { Tools } from '../api/Tools'; -import { VscodeTools } from '../ui/vscodeTools'; +import { VscodeTools } from '../ui/Tools'; import { DebugConfiguration, SERVICE_CERTIFICATE, CLIENT_CERTIFICATE, getDebugServiceDetails, getJavaHome, DEBUG_CONFIG_FILE, LEGACY_CERT_DIRECTORY } from '../api/configuration/DebugConfiguration'; type HostInfo = { diff --git a/src/debug/index.ts b/src/debug/index.ts index ad9de0e3b..344accbb1 100644 --- a/src/debug/index.ts +++ b/src/debug/index.ts @@ -11,7 +11,7 @@ import { Env, getEnvConfig } from "../filesystems/local/env"; import * as certificates from "./certificates"; import { DEBUG_CONFIG_FILE, DebugConfiguration, getDebugServiceDetails, resetDebugServiceDetails } from "../api/configuration/DebugConfiguration"; import * as server from "./server"; -import { VscodeTools } from "../ui/vscodeTools"; +import { VscodeTools } from "../ui/Tools"; import { getStoredPassword } from "../config/passwords"; const debugExtensionId = `IBM.ibmidebug`; diff --git a/src/extension.ts b/src/extension.ts index 1579832ee..79a06c8f0 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -34,7 +34,7 @@ import { SettingsUI } from "./webviews/settings"; import { registerActionTools } from "./ui/actions"; import IBMi from "./api/IBMi"; import path from "path"; -import { VscodeTools } from "./ui/vscodeTools"; +import { VscodeTools } from "./ui/Tools"; export async function activate(context: ExtensionContext): Promise { // Use the console to output diagnostic information (console.log) and errors (console.error) @@ -126,8 +126,7 @@ export async function activate(context: ExtensionContext): Promise instance, customUI: () => new CustomUI(), deployTools: DeployTools, evfeventParser: parseErrors, - tools: Tools, - vscodeTools: VscodeTools, + tools: VscodeTools, componentRegistry: extensionComponentRegistry }; } diff --git a/src/filesystems/local/deployTools.ts b/src/filesystems/local/deployTools.ts index 638cef4d5..070df5317 100644 --- a/src/filesystems/local/deployTools.ts +++ b/src/filesystems/local/deployTools.ts @@ -4,7 +4,7 @@ import vscode, { Uri, WorkspaceFolder } from 'vscode'; import { instance } from '../../instantiate'; import { LocalLanguageActions } from './LocalLanguageActions'; import { Deployment } from './deployment'; -import { VscodeTools } from '../../ui/vscodeTools'; +import { VscodeTools } from '../../ui/Tools'; import { DeploymentMethod } from '../../api/types'; import { DeploymentParameters } from '../../typings'; diff --git a/src/filesystems/local/git.ts b/src/filesystems/local/git.ts index 194bc5dc3..b53bcc206 100644 --- a/src/filesystems/local/git.ts +++ b/src/filesystems/local/git.ts @@ -3,7 +3,7 @@ import { getBranchLibraryName } from "./env"; import { instance } from "../../instantiate"; import IBMi from "../../api/IBMi"; import IBMiContent from "../../api/IBMiContent"; -import { VscodeTools } from "../../ui/vscodeTools"; +import { VscodeTools } from "../../ui/Tools"; import { ConnectionConfig } from "../../api/configuration/config/ConnectionManager"; const lastBranch: { [workspaceUri: string]: string } = {}; diff --git a/src/filesystems/qsys/FSUtils.ts b/src/filesystems/qsys/FSUtils.ts index c392dfeb2..0553c63de 100644 --- a/src/filesystems/qsys/FSUtils.ts +++ b/src/filesystems/qsys/FSUtils.ts @@ -1,6 +1,6 @@ import path from "path"; import vscode, { l10n } from "vscode"; -import { VscodeTools } from "../../ui/vscodeTools"; +import { VscodeTools } from "../../ui/Tools"; import IBMi from "../../api/IBMi"; import { ReconnectMode } from "../../api/configuration/config/ConnectionManager"; diff --git a/src/sandbox.ts b/src/sandbox.ts index 92a810578..32c716fa9 100644 --- a/src/sandbox.ts +++ b/src/sandbox.ts @@ -3,7 +3,7 @@ import querystring from "querystring"; import { commands, ExtensionContext, l10n, Uri, window } from "vscode"; import { instance } from "./instantiate"; import { ConnectionData } from "./typings"; -import { VscodeTools } from "./ui/vscodeTools"; +import { VscodeTools } from "./ui/Tools"; import IBMi from "./api/IBMi"; export async function registerUriHandler(context: ExtensionContext) { diff --git a/src/testing/deployTools.ts b/src/testing/deployTools.ts index 4f246074e..11307f57e 100644 --- a/src/testing/deployTools.ts +++ b/src/testing/deployTools.ts @@ -10,7 +10,7 @@ import { Tools } from "../api/Tools"; import { DeployTools } from "../filesystems/local/deployTools"; import { instance } from "../instantiate"; import { Action, DeploymentMethod } from "../typings"; -import { VscodeTools } from "../ui/vscodeTools"; +import { VscodeTools } from "../ui/Tools"; import { runAction } from "../ui/actions"; type FileInfo = { diff --git a/src/typings.ts b/src/typings.ts index 99ebb446f..ae873c008 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -7,15 +7,14 @@ import { ObjectFilters } from './api/configuration/config/ConnectionManager'; import { DeploymentMethod, FileError, IBMiMember, IBMiObject, WithPath } from "./api/types"; import { Ignore } from "ignore"; import { WorkspaceFolder } from "vscode"; -import { VscodeTools } from "./ui/vscodeTools"; +import { VscodeTools } from "./ui/Tools"; export interface CodeForIBMi { instance: Instance, customUI: () => CustomUI, deployTools: typeof DeployTools, evfeventParser: (lines: string[]) => Map, - tools: typeof Tools, - vscodeTools: typeof VscodeTools, + tools: typeof VscodeTools, componentRegistry: ComponentRegistry } diff --git a/src/ui/vscodeTools.ts b/src/ui/Tools.ts similarity index 91% rename from src/ui/vscodeTools.ts rename to src/ui/Tools.ts index 2f91f7c45..23ba4491a 100644 --- a/src/ui/vscodeTools.ts +++ b/src/ui/Tools.ts @@ -3,9 +3,9 @@ import Crypto from 'crypto'; import { readFileSync } from "fs"; import vscode, { MarkdownString } from "vscode"; import { API, GitExtension } from "../filesystems/local/gitApi"; -import { Tools } from '../api/Tools'; import { IBMiObject, IBMiMember, IFSFile } from '../typings'; import IBMi from '../api/IBMi'; +import { Tools } from '../api/Tools'; let gitLookedUp: boolean; let gitAPI: API | undefined; @@ -198,4 +198,18 @@ export namespace VscodeTools { return `Unknown`; } } + + export const qualifyPath = Tools.qualifyPath; + export const unqualifyPath = Tools.unqualifyPath; + export const escapePath = Tools.escapePath; + export const distinct = Tools.distinct; + export const capitalize = Tools.capitalize; + export const sanitizeObjNamesForPase = Tools.sanitizeObjNamesForPase; + export const parseMessages = Tools.parseMessages; + export const parseQSysPath = Tools.parseQSysPath; + export const fileToPath = Tools.fileToPath; + export const fixWindowsPath = Tools.fixWindowsPath; + export const parseAttrDate = Tools.parseAttrDate; + export const normalizePath = Tools.normalizePath; + export const resolvePath = Tools.resolvePath; } \ No newline at end of file diff --git a/src/ui/diagnostics.ts b/src/ui/diagnostics.ts index 598080502..3a08dfd82 100644 --- a/src/ui/diagnostics.ts +++ b/src/ui/diagnostics.ts @@ -4,7 +4,7 @@ import { FileError } from "../typings"; import Instance from "../Instance"; import { getEvfeventFiles } from "../filesystems/local/actions"; import { parseErrors } from "../api/errors/parser"; -import { VscodeTools } from "./vscodeTools"; +import { VscodeTools } from "./Tools"; import IBMi from "../api/IBMi"; const ileDiagnostics = vscode.languages.createDiagnosticCollection(`ILE`); diff --git a/src/ui/views/LibraryListView.ts b/src/ui/views/LibraryListView.ts index e29c54d38..8f32f3433 100644 --- a/src/ui/views/LibraryListView.ts +++ b/src/ui/views/LibraryListView.ts @@ -1,7 +1,7 @@ import vscode, { commands, l10n } from "vscode"; import { instance } from "../../instantiate"; import { IBMiObject, WithLibrary } from "../../typings"; -import { VscodeTools } from "../vscodeTools"; +import { VscodeTools } from "../Tools"; import { ConnectionConfig } from "../../api/configuration/config/ConnectionManager"; import IBMi from "../../api/IBMi"; diff --git a/src/ui/views/debugView.ts b/src/ui/views/debugView.ts index 3033403df..d062c567d 100644 --- a/src/ui/views/debugView.ts +++ b/src/ui/views/debugView.ts @@ -4,7 +4,7 @@ import { checkClientCertificate, debugKeyFileExists, remoteCertificatesExists } import { DebugConfiguration, getDebugServiceDetails, SERVICE_CERTIFICATE } from "../../api/configuration/DebugConfiguration"; import { DebugJob, getDebugServerJob, getDebugServiceJob, isDebugEngineRunning, readActiveJob, readJVMInfo, startServer, startService, stopServer, stopService } from "../../debug/server"; import { instance } from "../../instantiate"; -import { VscodeTools } from "../vscodeTools"; +import { VscodeTools } from "../Tools"; import { BrowserItem } from "../types"; const title = "IBM i debugger"; diff --git a/src/ui/views/ifsBrowser.ts b/src/ui/views/ifsBrowser.ts index f9ea0dc00..08d379bf5 100644 --- a/src/ui/views/ifsBrowser.ts +++ b/src/ui/views/ifsBrowser.ts @@ -8,7 +8,7 @@ import { Search } from "../../api/Search"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; import { FocusOptions, IFSFile, IFS_BROWSER_MIMETYPE, OBJECT_BROWSER_MIMETYPE, SearchHit, SearchResults, WithPath } from "../../typings"; -import { VscodeTools } from "../vscodeTools"; +import { VscodeTools } from "../Tools"; import IBMi from "../../api/IBMi"; import { BrowserItem, BrowserItemParameters } from "../types"; diff --git a/src/ui/views/objectBrowser.ts b/src/ui/views/objectBrowser.ts index 3662509ab..01a86017e 100644 --- a/src/ui/views/objectBrowser.ts +++ b/src/ui/views/objectBrowser.ts @@ -11,7 +11,7 @@ import { getMemberUri } from "../../filesystems/qsys/QSysFs"; import { instance } from "../../instantiate"; import { CommandResult, FilteredItem, FocusOptions, IBMiMember, IBMiObject, MemberItem, OBJECT_BROWSER_MIMETYPE, ObjectItem, WithLibrary } from "../../typings"; import { editFilter } from "../../webviews/filters"; -import { VscodeTools } from "../vscodeTools"; +import { VscodeTools } from "../Tools"; import { DefaultOpenMode, ObjectFilters } from "../../api/configuration/config/ConnectionManager"; import { BrowserItem, BrowserItemParameters } from "../types"; diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index 05845af93..dcd70b78f 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -8,7 +8,7 @@ import { isSEPSupported } from "../../debug/server"; import { extensionComponentRegistry } from "../../api/components/manager"; import { instance } from "../../instantiate"; import { ConnectionData, Server } from '../../typings'; -import { VscodeTools } from "../../ui/vscodeTools"; +import { VscodeTools } from "../../ui/Tools"; import IBMi from "../../api/IBMi"; import { ConnectionConfig, ConnectionManager } from "../../api/configuration/config/ConnectionManager"; import { deleteStoredPassword, getStoredPassword, setStoredPassword } from "../../config/passwords"; From 728e0c220c9f7121176f41d8cda5fdcc2f8425a3 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Fri, 17 Jan 2025 09:34:07 -0500 Subject: [PATCH 39/46] Export path qualification functions to maintain API compatibility after refactor Signed-off-by: worksofliam --- src/ui/Tools.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/Tools.ts b/src/ui/Tools.ts index 23ba4491a..389465cad 100644 --- a/src/ui/Tools.ts +++ b/src/ui/Tools.ts @@ -199,6 +199,7 @@ export namespace VscodeTools { } } + // These are exported to not break the API from 'the great re-write'. export const qualifyPath = Tools.qualifyPath; export const unqualifyPath = Tools.unqualifyPath; export const escapePath = Tools.escapePath; From 866b71cbfd246340b40aafc11aeb0669156376bd Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 21 Jan 2025 09:19:53 -0500 Subject: [PATCH 40/46] Fix pre-publish to not remove some types Signed-off-by: worksofliam --- types/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/package.json b/types/package.json index a02606c97..3601f25c7 100644 --- a/types/package.json +++ b/types/package.json @@ -4,7 +4,7 @@ "description": "Types for vscode-ibmi", "typings": "./typings.d.ts", "scripts": { - "prepublish": "rm -rf filesystems schemas views webviews languages testing", + "prepublish": "rm -rf schemas ui/views webviews/*/* languages testing", "deploy": "npm publish --access public" }, "repository": { From b1b728657378056de5d44d8adfc39274e77de02c Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 21 Jan 2025 09:29:39 -0500 Subject: [PATCH 41/46] Refactor output handling and improve log retrieval in help view Signed-off-by: worksofliam --- src/Instance.ts | 20 ++++++++++++++------ src/ui/views/helpView.ts | 26 +++++++++++++------------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/Instance.ts b/src/Instance.ts index c613497bd..ce50ddc12 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -33,12 +33,6 @@ export default class Instance { writeCount: 0 }; - private resetOutput() { - this.output.channel.clear(); - this.output.content = ``; - this.output.writeCount = 0; - } - private storage: ConnectionStorage; private emitter: vscode.EventEmitter = new vscode.EventEmitter(); private subscribers: Map = new Map; @@ -54,6 +48,20 @@ export default class Instance { this.emitter.event(e => this.processEvent(e)); } + focusOutput() { + this.output.channel.show(); + } + + getOutputContent() { + return this.output.content; + } + + private resetOutput() { + this.output.channel.clear(); + this.output.content = ``; + this.output.writeCount = 0; + } + connect(options: ConnectionOptions): Promise { const connection = new IBMi(); diff --git a/src/ui/views/helpView.ts b/src/ui/views/helpView.ts index 691a96404..24239bcac 100644 --- a/src/ui/views/helpView.ts +++ b/src/ui/views/helpView.ts @@ -124,25 +124,25 @@ async function openNewIssue() { async function downloadLogs() { const connection = instance.getConnection(); - const config = instance.getConfig(); - const content = instance.getContent(); const logs: any[] = []; - if (connection && config && content) { + if (connection) { + const content = connection.getContent(); await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: vscode.l10n.t(`Gathering logs...`), }, async () => { - // const codeForIBMiLog = connection.getOutputChannelContent(); - // if (codeForIBMiLog !== undefined) { - // logs.push({ - // label: vscode.l10n.t(`Code for IBM i Log`), - // detail: `${connection?.currentUser}@${connection?.currentHost}`, - // picked: true, - // fileName: 'CodeForIBMi.txt', - // fileContent: Buffer.from(codeForIBMiLog, 'utf8') - // }); - // } + + const codeForIBMiLog = instance.getOutputContent(); + if (codeForIBMiLog !== undefined) { + logs.push({ + label: vscode.l10n.t(`Code for IBM i Log`), + detail: `${connection?.currentUser}@${connection?.currentHost}`, + picked: true, + fileName: 'CodeForIBMi.txt', + fileContent: Buffer.from(codeForIBMiLog, 'utf8') + }); + } const debugConfig = await new DebugConfiguration(connection).load(); try { From 91e687e57cf9d33b392bbe6e08ab54c25c5e3795 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 21 Jan 2025 09:43:18 -0500 Subject: [PATCH 42/46] Re-org of connection types Signed-off-by: worksofliam --- src/Instance.ts | 3 +- src/api/IBMi.ts | 3 +- .../configuration/config/ConnectionManager.ts | 78 +------------------ src/api/configuration/config/types.ts | 76 ++++++++++++++++++ src/api/types.ts | 17 +--- src/commands/open.ts | 3 +- src/filesystems/local/git.ts | 2 +- src/filesystems/qsys/FSUtils.ts | 2 +- src/filesystems/qsys/sourceDateHandler.ts | 2 +- src/typings.ts | 16 +--- src/ui/types.ts | 14 +++- src/ui/views/ConnectionBrowser.ts | 3 +- src/ui/views/LibraryListView.ts | 3 +- src/ui/views/ProfilesView.ts | 3 +- src/ui/views/objectBrowser.ts | 3 +- src/ui/views/searchView.ts | 3 +- src/webviews/commandProfile/index.ts | 2 +- src/webviews/filters/index.ts | 2 +- src/webviews/settings/index.ts | 3 +- 19 files changed, 110 insertions(+), 128 deletions(-) create mode 100644 src/api/configuration/config/types.ts diff --git a/src/Instance.ts b/src/Instance.ts index ce50ddc12..413a1b844 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -1,11 +1,10 @@ import * as vscode from "vscode"; -import { ConnectionData, IBMiEvent } from "./typings"; +import { ConnectionConfig, ConnectionData, IBMiEvent } from "./typings"; import IBMi, { ConnectionResult } from "./api/IBMi"; import { CodeForIStorage } from "./api/configuration/storage/CodeForIStorage"; import { handleConnectionResults, messageCallback } from "./ui/connection"; import { VsStorage } from "./config/Storage"; import { VsCodeConfig } from "./config/Configuration"; -import { ConnectionConfig } from "./api/configuration/config/ConnectionManager"; import { EventEmitter } from "stream"; import { ConnectionStorage } from "./api/configuration/storage/ConnectionStorage"; import { VscodeTools } from "./ui/Tools"; diff --git a/src/api/IBMi.ts b/src/api/IBMi.ts index 13cce21c5..c9915f685 100644 --- a/src/api/IBMi.ts +++ b/src/api/IBMi.ts @@ -13,9 +13,10 @@ import { CachedServerSettings, CodeForIStorage } from './configuration/storage/C import { Tools } from './Tools'; import * as configVars from './configVars'; import { DebugConfiguration } from "./configuration/DebugConfiguration"; -import { ConnectionManager, ConnectionConfig } from './configuration/config/ConnectionManager'; +import { ConnectionManager } from './configuration/config/ConnectionManager'; import { CommandData, CommandResult, ConnectionData, IBMiMember, RemoteCommand, WrapResult } from './types'; import { EventEmitter } from 'stream'; +import { ConnectionConfig } from './configuration/config/types'; export interface MemberParts extends IBMiMember { basename: string diff --git a/src/api/configuration/config/ConnectionManager.ts b/src/api/configuration/config/ConnectionManager.ts index 54b3d7676..491d3f960 100644 --- a/src/api/configuration/config/ConnectionManager.ts +++ b/src/api/configuration/config/ConnectionManager.ts @@ -1,82 +1,8 @@ import os from "os"; -import { FilterType } from "../../Filter"; import { Config, VirtualConfig } from "./VirtualConfig"; -import { DeploymentMethod, ConnectionData } from "../../types"; - -export type SourceDateMode = "edit" | "diff"; -export type DefaultOpenMode = "browse" | "edit"; -export type ReconnectMode = "always" | "never" | "ask"; - -export interface ConnectionConfig extends ConnectionProfile { - host: string; - autoClearTempData: boolean; - connectionProfiles: ConnectionProfile[]; - commandProfiles: CommandProfile[]; - autoSortIFSShortcuts: boolean; - tempLibrary: string; - tempDir: string; - sourceASP: string; - sourceFileCCSID: string; - autoConvertIFSccsid: boolean; - hideCompileErrors: string[]; - enableSourceDates: boolean; - sourceDateMode: SourceDateMode; - sourceDateGutter: boolean; - encodingFor5250: string; - terminalFor5250: string; - setDeviceNameFor5250: boolean; - connectringStringFor5250: string; - autoSaveBeforeAction: boolean; - showDescInLibList: boolean; - debugPort: string; - debugSepPort: string; - debugUpdateProductionFiles: boolean; - debugEnableDebugTracing: boolean; - readOnlyMode: boolean; - quickConnect: boolean; - defaultDeploymentMethod: DeploymentMethod | ''; - protectedPaths: string[]; - showHiddenFiles: boolean; - lastDownloadLocation: string; - [name: string]: any; -} - -export interface ObjectFilters { - name: string - filterType: FilterType - library: string - object: string - types: string[] - member: string - memberType: string - protected: boolean -} - -export interface CustomVariable { - name: string - value: string -} - -export interface ConnectionProfile { - name: string - homeDirectory: string - currentLibrary: string - libraryList: string[] - objectFilters: ObjectFilters[] - ifsShortcuts: string[] - customVariables: CustomVariable[] -} - -export interface CommandProfile { - name: string; - command: string; -} - -export interface StoredConnection { - index: number, - data: ConnectionData -}; +import { ConnectionData } from "../../types"; +import { ConnectionConfig } from "./types"; function initialize(parameters: Partial): ConnectionConfig { return { diff --git a/src/api/configuration/config/types.ts b/src/api/configuration/config/types.ts new file mode 100644 index 000000000..0eed76f56 --- /dev/null +++ b/src/api/configuration/config/types.ts @@ -0,0 +1,76 @@ +import { FilterType } from "../../Filter"; +import { DeploymentMethod, ConnectionData } from "../../types"; + +export type SourceDateMode = "edit" | "diff"; +export type DefaultOpenMode = "browse" | "edit"; +export type ReconnectMode = "always" | "never" | "ask"; + +export interface ConnectionConfig extends ConnectionProfile { + host: string; + autoClearTempData: boolean; + connectionProfiles: ConnectionProfile[]; + commandProfiles: CommandProfile[]; + autoSortIFSShortcuts: boolean; + tempLibrary: string; + tempDir: string; + sourceASP: string; + sourceFileCCSID: string; + autoConvertIFSccsid: boolean; + hideCompileErrors: string[]; + enableSourceDates: boolean; + sourceDateMode: SourceDateMode; + sourceDateGutter: boolean; + encodingFor5250: string; + terminalFor5250: string; + setDeviceNameFor5250: boolean; + connectringStringFor5250: string; + autoSaveBeforeAction: boolean; + showDescInLibList: boolean; + debugPort: string; + debugSepPort: string; + debugUpdateProductionFiles: boolean; + debugEnableDebugTracing: boolean; + readOnlyMode: boolean; + quickConnect: boolean; + defaultDeploymentMethod: DeploymentMethod | ''; + protectedPaths: string[]; + showHiddenFiles: boolean; + lastDownloadLocation: string; + [name: string]: any; +} + +export interface ObjectFilters { + name: string + filterType: FilterType + library: string + object: string + types: string[] + member: string + memberType: string + protected: boolean +} + +export interface CustomVariable { + name: string + value: string +} + +export interface ConnectionProfile { + name: string + homeDirectory: string + currentLibrary: string + libraryList: string[] + objectFilters: ObjectFilters[] + ifsShortcuts: string[] + customVariables: CustomVariable[] +} + +export interface CommandProfile { + name: string; + command: string; +} + +export interface StoredConnection { + index: number, + data: ConnectionData +}; \ No newline at end of file diff --git a/src/api/types.ts b/src/api/types.ts index 6b3a3e7b3..4ea2b04f3 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -1,4 +1,3 @@ -import { ObjectFilters } from "./configuration/config/ConnectionManager"; export type DeploymentMethod = "all" | "staged" | "unstaged" | "changed" | "compare"; @@ -146,18 +145,6 @@ export interface WithLibrary { export type FocusOptions = { select?: boolean; focus?: boolean; expand?: boolean | number } -export interface FilteredItem { - filter: ObjectFilters -} - -export interface ObjectItem extends FilteredItem, WithPath { - object: IBMiObject -} - -export interface MemberItem extends FilteredItem, WithPath { - member: IBMiMember -} - export type IBMiMessage = { id: string text: string @@ -193,4 +180,6 @@ export type SearchHit = { export type SearchHitLine = { number: number content: string -} \ No newline at end of file +} + +export * from "./configuration/config/types"; \ No newline at end of file diff --git a/src/commands/open.ts b/src/commands/open.ts index 06685fe5b..604fd2aab 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -1,12 +1,11 @@ import { commands, Disposable, l10n, QuickInputButton, QuickPickItem, QuickPickItemButtonEvent, QuickPickItemKind, Range, TextDocument, TextDocumentShowOptions, ThemeIcon, Uri, window } from "vscode"; -import { MemberItem, QsysFsOptions, WithPath } from "../typings"; +import { DefaultOpenMode, MemberItem, QsysFsOptions, WithPath } from "../typings"; import Instance from "../Instance"; import { Tools } from "../api/Tools"; import { getUriFromPath, parseFSOptions } from "../filesystems/qsys/QSysFs"; import path from "path"; import { VscodeTools } from "../ui/Tools"; import IBMi from "../api/IBMi"; -import { DefaultOpenMode } from "../api/configuration/config/ConnectionManager"; const CLEAR_RECENT = `$(trash) Clear recently opened`; const CLEAR_CACHED = `$(trash) Clear cached`; diff --git a/src/filesystems/local/git.ts b/src/filesystems/local/git.ts index b53bcc206..3680ac70d 100644 --- a/src/filesystems/local/git.ts +++ b/src/filesystems/local/git.ts @@ -4,7 +4,7 @@ import { instance } from "../../instantiate"; import IBMi from "../../api/IBMi"; import IBMiContent from "../../api/IBMiContent"; import { VscodeTools } from "../../ui/Tools"; -import { ConnectionConfig } from "../../api/configuration/config/ConnectionManager"; +import { ConnectionConfig } from "../../typings"; const lastBranch: { [workspaceUri: string]: string } = {}; diff --git a/src/filesystems/qsys/FSUtils.ts b/src/filesystems/qsys/FSUtils.ts index 0553c63de..2088c634f 100644 --- a/src/filesystems/qsys/FSUtils.ts +++ b/src/filesystems/qsys/FSUtils.ts @@ -2,7 +2,7 @@ import path from "path"; import vscode, { l10n } from "vscode"; import { VscodeTools } from "../../ui/Tools"; import IBMi from "../../api/IBMi"; -import { ReconnectMode } from "../../api/configuration/config/ConnectionManager"; +import { ReconnectMode } from "../../typings"; /** * Called when a member/streamfile is left open when VS Code is closed and re-opened to reconnect (or not) to the previous IBM i, based on the `autoReconnect` global configuration value. diff --git a/src/filesystems/qsys/sourceDateHandler.ts b/src/filesystems/qsys/sourceDateHandler.ts index 9cead2772..c9ee4039d 100644 --- a/src/filesystems/qsys/sourceDateHandler.ts +++ b/src/filesystems/qsys/sourceDateHandler.ts @@ -4,7 +4,7 @@ import { DiffComputer } from "vscode-diff"; import { instance } from "../../instantiate"; import IBMi from "../../api/IBMi"; -import { SourceDateMode } from "../../api/configuration/config/ConnectionManager"; +import { SourceDateMode } from "../../typings"; const editedTodayColor = new vscode.ThemeColor(`gitDecoration.modifiedResourceForeground`); const seachGutterColor = new vscode.ThemeColor(`gitDecoration.addedResourceForeground`); diff --git a/src/typings.ts b/src/typings.ts index ae873c008..534b4948a 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -1,10 +1,8 @@ import { CustomUI } from "./webviews/CustomUI"; import Instance from "./Instance"; -import { Tools } from "./api/Tools"; import { DeployTools } from "./filesystems/local/deployTools"; import { ComponentRegistry } from './api/components/manager'; -import { ObjectFilters } from './api/configuration/config/ConnectionManager'; -import { DeploymentMethod, FileError, IBMiMember, IBMiObject, WithPath } from "./api/types"; +import { DeploymentMethod, FileError } from "./api/types"; import { Ignore } from "ignore"; import { WorkspaceFolder } from "vscode"; import { VscodeTools } from "./ui/Tools"; @@ -18,18 +16,6 @@ export interface CodeForIBMi { componentRegistry: ComponentRegistry } -export interface FilteredItem { - filter: ObjectFilters -} - -export interface ObjectItem extends FilteredItem, WithPath { - object: IBMiObject -} - -export interface MemberItem extends FilteredItem, WithPath { - member: IBMiMember -} - export interface DeploymentParameters { method: DeploymentMethod workspaceFolder: WorkspaceFolder diff --git a/src/ui/types.ts b/src/ui/types.ts index c68d18b44..6dd0a1cfe 100644 --- a/src/ui/types.ts +++ b/src/ui/types.ts @@ -1,5 +1,5 @@ import { TreeItemCollapsibleState, TreeItem, ThemeIcon, ThemeColor, ProviderResult, MarkdownString } from "vscode" -import { FocusOptions } from "../api/types" +import { FocusOptions, IBMiMember, IBMiObject, ObjectFilters, WithPath } from "../api/types" export type BrowserItemParameters = { icon?: string @@ -8,6 +8,18 @@ export type BrowserItemParameters = { parent?: BrowserItem } +export interface FilteredItem { + filter: ObjectFilters +} + +export interface ObjectItem extends FilteredItem, WithPath { + object: IBMiObject +} + +export interface MemberItem extends FilteredItem, WithPath { + member: IBMiMember +} + export class BrowserItem extends TreeItem { constructor(label: string, readonly params?: BrowserItemParameters) { super(label, params?.state); diff --git a/src/ui/views/ConnectionBrowser.ts b/src/ui/views/ConnectionBrowser.ts index 76b53ce25..8247c2110 100644 --- a/src/ui/views/ConnectionBrowser.ts +++ b/src/ui/views/ConnectionBrowser.ts @@ -1,10 +1,9 @@ import vscode from 'vscode'; -import { ConnectionData, Server } from '../../typings'; +import { ConnectionConfig, ConnectionData, Server } from '../../typings'; import { instance } from '../../instantiate'; import { Login } from '../../webviews/login'; import IBMi from '../../api/IBMi'; -import { ConnectionConfig, ConnectionManager } from '../../api/configuration/config/ConnectionManager'; import { deleteStoredPassword, getStoredPassword, setStoredPassword } from '../../config/passwords'; type CopyOperationItem = { diff --git a/src/ui/views/LibraryListView.ts b/src/ui/views/LibraryListView.ts index 8f32f3433..f37b582c5 100644 --- a/src/ui/views/LibraryListView.ts +++ b/src/ui/views/LibraryListView.ts @@ -1,8 +1,7 @@ import vscode, { commands, l10n } from "vscode"; import { instance } from "../../instantiate"; -import { IBMiObject, WithLibrary } from "../../typings"; +import { ConnectionConfig, IBMiObject, WithLibrary } from "../../typings"; import { VscodeTools } from "../Tools"; -import { ConnectionConfig } from "../../api/configuration/config/ConnectionManager"; import IBMi from "../../api/IBMi"; export class LibraryListProvider implements vscode.TreeDataProvider { diff --git a/src/ui/views/ProfilesView.ts b/src/ui/views/ProfilesView.ts index bb5cebe95..9df61bc31 100644 --- a/src/ui/views/ProfilesView.ts +++ b/src/ui/views/ProfilesView.ts @@ -2,10 +2,9 @@ import vscode, { l10n, window } from 'vscode'; import { GetNewLibl } from '../../api/components/getNewLibl'; import { instance } from '../../instantiate'; -import { Profile } from '../../typings'; +import { ConnectionProfile, Profile } from '../../typings'; import { CommandProfileUi } from '../../webviews/commandProfile'; import IBMi from '../../api/IBMi'; -import { ConnectionProfile } from '../../api/configuration/config/ConnectionManager'; export class ProfilesView { private _onDidChangeTreeData = new vscode.EventEmitter(); diff --git a/src/ui/views/objectBrowser.ts b/src/ui/views/objectBrowser.ts index 01a86017e..21fcddda8 100644 --- a/src/ui/views/objectBrowser.ts +++ b/src/ui/views/objectBrowser.ts @@ -9,10 +9,9 @@ import { Search } from "../../api/Search"; import { Tools } from "../../api/Tools"; import { getMemberUri } from "../../filesystems/qsys/QSysFs"; import { instance } from "../../instantiate"; -import { CommandResult, FilteredItem, FocusOptions, IBMiMember, IBMiObject, MemberItem, OBJECT_BROWSER_MIMETYPE, ObjectItem, WithLibrary } from "../../typings"; +import { CommandResult, DefaultOpenMode, FilteredItem, FocusOptions, IBMiMember, IBMiObject, MemberItem, OBJECT_BROWSER_MIMETYPE, ObjectFilters, ObjectItem, WithLibrary } from "../../typings"; import { editFilter } from "../../webviews/filters"; import { VscodeTools } from "../Tools"; -import { DefaultOpenMode, ObjectFilters } from "../../api/configuration/config/ConnectionManager"; import { BrowserItem, BrowserItemParameters } from "../types"; const URI_LIST_SEPARATOR = "\r\n"; diff --git a/src/ui/views/searchView.ts b/src/ui/views/searchView.ts index 2813f833d..d5cf072d3 100644 --- a/src/ui/views/searchView.ts +++ b/src/ui/views/searchView.ts @@ -1,7 +1,6 @@ import path from 'path'; import vscode from "vscode"; -import { SearchHit, SearchHitLine, SearchResults, WithPath } from "../../typings"; -import { DefaultOpenMode } from '../../api/configuration/config/ConnectionManager'; +import { DefaultOpenMode, SearchHit, SearchHitLine, SearchResults, WithPath } from "../../typings"; export function initializeSearchView(context: vscode.ExtensionContext) { const searchView = new SearchView(); diff --git a/src/webviews/commandProfile/index.ts b/src/webviews/commandProfile/index.ts index 7b4e45c89..6b20e6808 100644 --- a/src/webviews/commandProfile/index.ts +++ b/src/webviews/commandProfile/index.ts @@ -3,7 +3,7 @@ import { commands, window } from "vscode"; import { CustomUI } from "../CustomUI"; import { instance } from "../../instantiate"; import IBMi from "../../api/IBMi"; -import { CommandProfile } from "../../api/configuration/config/ConnectionManager"; +import { CommandProfile } from "../../typings"; export class CommandProfileUi { static async show(currentName?: string) { diff --git a/src/webviews/filters/index.ts b/src/webviews/filters/index.ts index 7cc725441..38059d88d 100644 --- a/src/webviews/filters/index.ts +++ b/src/webviews/filters/index.ts @@ -1,8 +1,8 @@ import { CustomUI } from "../CustomUI"; import { Tools } from "../../api/Tools"; import { instance } from "../../instantiate"; -import { ObjectFilters } from "../../api/configuration/config/ConnectionManager"; import IBMi from "../../api/IBMi"; +import { ObjectFilters } from "../../typings"; export async function editFilter(filter?: ObjectFilters, copy = false) { const connection = instance.getConnection(); diff --git a/src/webviews/settings/index.ts b/src/webviews/settings/index.ts index dcd70b78f..c83306ea4 100644 --- a/src/webviews/settings/index.ts +++ b/src/webviews/settings/index.ts @@ -7,10 +7,9 @@ import * as certificates from "../../debug/certificates"; import { isSEPSupported } from "../../debug/server"; import { extensionComponentRegistry } from "../../api/components/manager"; import { instance } from "../../instantiate"; -import { ConnectionData, Server } from '../../typings'; +import { ConnectionConfig, ConnectionData, Server } from '../../typings'; import { VscodeTools } from "../../ui/Tools"; import IBMi from "../../api/IBMi"; -import { ConnectionConfig, ConnectionManager } from "../../api/configuration/config/ConnectionManager"; import { deleteStoredPassword, getStoredPassword, setStoredPassword } from "../../config/passwords"; const EDITING_CONTEXT = `code-for-ibmi:editingConnection`; From 36047636e188428ca21cfa288219eb6f07faef4d Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 21 Jan 2025 09:44:47 -0500 Subject: [PATCH 43/46] Update error handling link in connection results Signed-off-by: worksofliam --- src/ui/connection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/connection.ts b/src/ui/connection.ts index eec04e692..b80cf0e70 100644 --- a/src/ui/connection.ts +++ b/src/ui/connection.ts @@ -30,7 +30,7 @@ export async function handleConnectionResults(connection: IBMi, error: Connectio }, `Read more`); if (chosen === `Read more`) { - commands.executeCommand(`open`, `https://codefori.github.io/docs/#/pages/tips/setup`); + commands.executeCommand(`open`, `https://codefori.github.io/docs/tips/setup/#error-in-shell-configuration`); } break; From 3c0cefb1c473e5439f2a1ac37686f6b49af5e00c Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 21 Jan 2025 09:47:38 -0500 Subject: [PATCH 44/46] Remove unused local filesystem types Signed-off-by: worksofliam --- src/filesystems/local/types.ts | 3 --- src/typings.ts | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) delete mode 100644 src/filesystems/local/types.ts diff --git a/src/filesystems/local/types.ts b/src/filesystems/local/types.ts deleted file mode 100644 index 70c5d39f0..000000000 --- a/src/filesystems/local/types.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Ignore } from "ignore" -import { WorkspaceFolder } from "vscode" -import { DeploymentMethod } from "../../api/types" \ No newline at end of file diff --git a/src/typings.ts b/src/typings.ts index 534b4948a..c278dde87 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -26,5 +26,4 @@ export interface DeploymentParameters { export type EditorPath = string | { fsPath: string }; export * from "./api/types"; -export * from "./ui/types"; -export * from "./filesystems/local/types"; \ No newline at end of file +export * from "./ui/types"; \ No newline at end of file From f65fdaa1f63a5fa11f6ed9dfb0e731023024c9f2 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 21 Jan 2025 14:37:12 -0500 Subject: [PATCH 45/46] Refactor BaseStorage and VsStorage constructors to accept globalState as a parameter Signed-off-by: worksofliam --- src/api/configuration/storage/BaseStorage.ts | 19 +++++++++---------- src/config/Storage.ts | 9 ++------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/api/configuration/storage/BaseStorage.ts b/src/api/configuration/storage/BaseStorage.ts index 15b8de8bb..7fb61130e 100644 --- a/src/api/configuration/storage/BaseStorage.ts +++ b/src/api/configuration/storage/BaseStorage.ts @@ -1,9 +1,10 @@ export abstract class BaseStorage { protected readonly globalState: any; - constructor() { - this.globalState = new Map(); - } + constructor(globalState: any) { + this.globalState = globalState; + } + keys(): readonly string[] { return Array.from(this.globalState.keys()); @@ -22,10 +23,8 @@ export abstract class BaseStorage { } } -export class VirtualStorage extends BaseStorage { - protected readonly globalState: Map = new Map(); - - constructor() { - super(); - } -} \ No newline at end of file +export class VirtualStorage extends BaseStorage { + constructor() { + super(new Map()); + } +} \ No newline at end of file diff --git a/src/config/Storage.ts b/src/config/Storage.ts index 2dfe7f57f..d6a50a604 100644 --- a/src/config/Storage.ts +++ b/src/config/Storage.ts @@ -2,18 +2,13 @@ import * as vscode from 'vscode'; import { BaseStorage } from '../api/configuration/storage/BaseStorage'; export class VsStorage extends BaseStorage { - declare protected readonly globalState; + declare protected readonly globalState: vscode.Memento; private connectionName: string = ""; constructor(context: vscode.ExtensionContext) { - super(); + super(context.globalState); this.globalState = context.globalState; } - - setConnectionName(connectionName: string) { - this.connectionName = connectionName; - } - public keys(): readonly string[] { return this.globalState.keys(); } From 89c9d086a7f09484255bfa3e62b30f9a16a0ffd1 Mon Sep 17 00:00:00 2001 From: worksofliam Date: Tue, 21 Jan 2025 14:38:14 -0500 Subject: [PATCH 46/46] Append message to output content in Instance class Signed-off-by: worksofliam --- src/Instance.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Instance.ts b/src/Instance.ts index 413a1b844..5c406fd1a 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -71,6 +71,7 @@ export default class Instance { } this.output.channel.append(message); + this.output.content += message; this.output.writeCount++; }