From ea839755e47cb347de2b56a94ac12f37da079703 Mon Sep 17 00:00:00 2001 From: Sanjula Date: Mon, 17 Jun 2024 21:27:54 -0400 Subject: [PATCH 1/3] Add Code4i tooltips for libraries, objects, members, and ifs files Signed-off-by: Sanjula --- src/views/projectExplorer/ifsDirectory.ts | 7 ++----- src/views/projectExplorer/ifsFile.ts | 8 +++----- src/views/projectExplorer/index.ts | 10 +++++++++- src/views/projectExplorer/library.ts | 9 +++------ src/views/projectExplorer/memberFile.ts | 14 ++++---------- src/views/projectExplorer/objectFile.ts | 17 +++++++++++------ .../projectExplorer/projectExplorerTreeItem.ts | 9 +++++++-- 7 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/views/projectExplorer/ifsDirectory.ts b/src/views/projectExplorer/ifsDirectory.ts index 6bce2b42..6c75fd33 100644 --- a/src/views/projectExplorer/ifsDirectory.ts +++ b/src/views/projectExplorer/ifsDirectory.ts @@ -22,11 +22,8 @@ export default class IFSDirectory extends TreeItem implements ProjectExplorerTre this.contextValue = IFSDirectory.contextValue; this.iconPath = new ThemeIcon(`symbol-folder`); - this.tooltip = l10n.t('Name: {0}\n', ifsDirectoryInfo.name) + - l10n.t('Path: {0}\n', ifsDirectoryInfo.path) + - (ifsDirectoryInfo.size ? l10n.t('Size: {0}\n', ifsDirectoryInfo.size) : ``) + - (ifsDirectoryInfo.owner ? l10n.t('Owner: {0}\n', ifsDirectoryInfo.owner) : ``) + - (ifsDirectoryInfo.modified ? l10n.t('Modified: {0}', ifsDirectoryInfo.modified.toLocaleString()) : ``); + const ibmi = getInstance(); + this.tooltip = ibmi?.getContent().ifsFileToToolTip(ifsDirectoryInfo.path, ifsDirectoryInfo); this.description = (custom && custom.description ? custom.description : undefined); } diff --git a/src/views/projectExplorer/ifsFile.ts b/src/views/projectExplorer/ifsFile.ts index 3bad5016..499c57fc 100644 --- a/src/views/projectExplorer/ifsFile.ts +++ b/src/views/projectExplorer/ifsFile.ts @@ -6,6 +6,7 @@ import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri, WorkspaceFolder, l1 import { ProjectExplorerTreeItem } from "./projectExplorerTreeItem"; import { ContextValue } from "../../ibmiProjectExplorer"; import * as vscodeIbmiTypes from "@halcyontech/vscode-ibmi-types"; +import { getInstance } from "../../ibmi"; /** * Tree item for an IFS file. @@ -20,11 +21,8 @@ export default class IFSFile extends TreeItem implements ProjectExplorerTreeItem this.ifsFileInfo = ifsFileInfo; this.contextValue = IFSFile.contextValue; this.iconPath = new ThemeIcon(`file`); - this.tooltip = l10n.t('Name: {0}\n', ifsFileInfo.name) + - l10n.t('Path: {0}\n', ifsFileInfo.path) + - (ifsFileInfo.size ? l10n.t('Size: {0}\n', ifsFileInfo.size) : ``) + - (ifsFileInfo.owner ? l10n.t('Owner: {0}\n', ifsFileInfo.owner) : ``) + - (ifsFileInfo.modified ? l10n.t('Modified: {0}', ifsFileInfo.modified.toLocaleString()) : ``); + const ibmi = getInstance(); + this.tooltip = ibmi?.getContent().ifsFileToToolTip(ifsFileInfo.path, ifsFileInfo); this.resourceUri = this.getIFSFileResourceUri(); this.command = { command: `vscode.open`, diff --git a/src/views/projectExplorer/index.ts b/src/views/projectExplorer/index.ts index 0bd5ca76..0f100769 100644 --- a/src/views/projectExplorer/index.ts +++ b/src/views/projectExplorer/index.ts @@ -5,7 +5,7 @@ import { ConnectionData, DeploymentMethod, ObjectItem } from "@halcyontech/vscode-ibmi-types"; import { DeploymentPath } from "@halcyontech/vscode-ibmi-types/api/Storage"; import * as path from "path"; -import { ConfigurationTarget, EventEmitter, ExtensionContext, ProgressLocation, QuickPickItem, TreeDataProvider, Uri, WorkspaceFolder, commands, env, l10n, window, workspace } from "vscode"; +import { CancellationToken, ConfigurationTarget, EventEmitter, ExtensionContext, ProgressLocation, QuickPickItem, TreeDataProvider, TreeItem, Uri, WorkspaceFolder, commands, env, l10n, window, workspace } from "vscode"; import { EnvironmentManager } from "../../environmentManager"; import { IProjectT } from "../../iProjectT"; import { getDeployTools, getInstance, getTools } from "../../ibmi"; @@ -1348,6 +1348,14 @@ export default class ProjectExplorer implements TreeDataProvider { + if (element.getToolTip) { + element.tooltip = await element.getToolTip(); + } + + return element; + } + /** * Get the project tree item associated with an IBM i project. * diff --git a/src/views/projectExplorer/library.ts b/src/views/projectExplorer/library.ts index 12a558b3..cdb4ef88 100644 --- a/src/views/projectExplorer/library.ts +++ b/src/views/projectExplorer/library.ts @@ -2,7 +2,7 @@ * (c) Copyright IBM Corp. 2023 */ -import { ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder, l10n, window } from "vscode"; +import { MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, WorkspaceFolder, l10n, window } from "vscode"; import { ProjectExplorerTreeItem } from "./projectExplorerTreeItem"; import { getInstance } from "../../ibmi"; import ObjectFile from "./objectFile"; @@ -47,11 +47,8 @@ export default class Library extends TreeItem implements ProjectExplorerTreeItem this.description = (variable ? `${variable} - ` : ``) + (libraryInfo.text.trim() !== '' ? `${libraryInfo.text} ` : ``) + (libraryInfo.attribute?.trim() !== '' ? `(${libraryInfo.attribute})` : ``); - this.tooltip = l10n.t('Name: {0}\n', libraryInfo.name) + - l10n.t('Path: {0}\n', this.path) + - (libraryInfo.text.trim() !== '' ? l10n.t('Text: {0}\n', libraryInfo.text) : ``) + - (libraryInfo.attribute ? l10n.t('Attribute: {0}\n', libraryInfo.attribute) : ``) + - l10n.t('Type: {0}', libraryInfo.type); + const ibmi = getInstance(); + this.tooltip = ibmi?.getContent().objectToToolTip([libraryInfo.library, libraryInfo.name].join(`/`), libraryInfo); let iconColor: ThemeColor | undefined; switch (this.libraryType) { case LibraryType.systemLibrary: diff --git a/src/views/projectExplorer/memberFile.ts b/src/views/projectExplorer/memberFile.ts index b9c5269f..5653764a 100644 --- a/src/views/projectExplorer/memberFile.ts +++ b/src/views/projectExplorer/memberFile.ts @@ -2,10 +2,11 @@ * (c) Copyright IBM Corp. 2023 */ -import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri, WorkspaceFolder, l10n } from "vscode"; +import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri, WorkspaceFolder, l10n } from "vscode"; import { IBMiMember } from "@halcyontech/vscode-ibmi-types"; import { ProjectExplorerTreeItem } from "./projectExplorerTreeItem"; import { ContextValue } from "../../ibmiProjectExplorer"; +import { getInstance } from "../../ibmi"; /** * Tree item for a member file. @@ -23,16 +24,9 @@ export default class MemberFile extends TreeItem implements ProjectExplorerTreeI this.contextValue = MemberFile.contextValue; this.iconPath = new ThemeIcon(`file`); this.description = memberFileInfo.text; - this.tooltip = l10n.t('Name: {0}\n', memberFileInfo.name) + - l10n.t('Path: {0}\n', this.path) + - (memberFileInfo.text && memberFileInfo.text.trim() !== '' ? l10n.t('Text: {0}\n', memberFileInfo.text) : ``) + - l10n.t('Extension: {0}\n', extension) + - (memberFileInfo.asp ? l10n.t('ASP: {0}\n', memberFileInfo.asp) : ``) + - (memberFileInfo.recordLength ? l10n.t('Record Length: {0}\n', memberFileInfo.recordLength) : ``) + - (memberFileInfo.lines ? l10n.t('Lines: {0}\n', memberFileInfo.lines) : ``) + - (memberFileInfo.created ? l10n.t('Created: {0}\n', memberFileInfo.created.toLocaleString()) : ``) + - (memberFileInfo.changed ? l10n.t('Changed: {0}', memberFileInfo.changed.toLocaleString()) : ``); this.resourceUri = this.getMemberResourceUri(); + const ibmi = getInstance(); + this.tooltip = ibmi?.getContent().memberToToolTip([memberFileInfo.library, memberFileInfo.file, `${memberFileInfo.name}.${extension}`].join(`/`), memberFileInfo); this.command = { command: `vscode.open`, title: `Open Member`, diff --git a/src/views/projectExplorer/objectFile.ts b/src/views/projectExplorer/objectFile.ts index 7fa47b3a..d0c96f7a 100644 --- a/src/views/projectExplorer/objectFile.ts +++ b/src/views/projectExplorer/objectFile.ts @@ -2,7 +2,7 @@ * (c) Copyright IBM Corp. 2023 */ -import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri, WorkspaceFolder, l10n, window } from "vscode"; +import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri, WorkspaceFolder, l10n, window } from "vscode"; import { ProjectExplorerTreeItem } from "./projectExplorerTreeItem"; import MemberFile from "./memberFile"; import { getInstance } from "../../ibmi"; @@ -31,11 +31,6 @@ export default class ObjectFile extends TreeItem implements ProjectExplorerTreeI this.iconPath = new ThemeIcon(icon); this.description = (objectFileInfo.text.trim() !== '' ? `${objectFileInfo.text} ` : ``) + (objectFileInfo.attribute?.trim() !== '' ? `(${objectFileInfo.attribute})` : ''); - this.tooltip = l10n.t('Name: {0}\n', objectFileInfo.name) + - l10n.t('Path: {0}\n', this.path) + - (objectFileInfo.text.trim() !== '' ? l10n.t('Text: {0}\n', objectFileInfo.text) : ``) + - (objectFileInfo.attribute ? l10n.t('Attribute: {0}\n', objectFileInfo.attribute) : ``) + - l10n.t('Type: {0}', objectFileInfo.type); this.resourceUri = this.getObjectResourceUri(); } @@ -57,6 +52,16 @@ export default class ObjectFile extends TreeItem implements ProjectExplorerTreeI return items; } + async getToolTip() { + const ibmi = getInstance(); + const path = [this.objectFileInfo.library, this.objectFileInfo.name].join(`/`); + if (this.objectFileInfo.sourceFile) { + return await ibmi?.getContent().sourcePhysicalFileToToolTip(path, this.objectFileInfo); + } else { + return ibmi?.getContent().objectToToolTip(path, this.objectFileInfo); + } + } + getObjectResourceUri() { const type = this.objectFileInfo.type.startsWith(`*`) ? this.objectFileInfo.type.substring(1) : this.objectFileInfo.type; const path = `${this.objectFileInfo.library}/${this.objectFileInfo.name}.${type}`; diff --git a/src/views/projectExplorer/projectExplorerTreeItem.ts b/src/views/projectExplorer/projectExplorerTreeItem.ts index 2ea60960..93f8ca80 100644 --- a/src/views/projectExplorer/projectExplorerTreeItem.ts +++ b/src/views/projectExplorer/projectExplorerTreeItem.ts @@ -2,7 +2,7 @@ * (c) Copyright IBM Corp. 2023 */ -import { TreeItem, WorkspaceFolder } from "vscode"; +import { MarkdownString, TreeItem, WorkspaceFolder } from "vscode"; /** * Represents a tree item in the Project Explorer view. @@ -19,5 +19,10 @@ export interface ProjectExplorerTreeItem extends TreeItem { * * @return Children of this tree item. */ - getChildren(): ProjectExplorerTreeItem[] | Promise; + getChildren: () => ProjectExplorerTreeItem[] | Promise; + + /** + * Get the markdown tooltip of this tree item. + */ + getToolTip?: () => Promise; } \ No newline at end of file From d82350a5194fff6fbcdcc97ed634c1f2ee143fea Mon Sep 17 00:00:00 2001 From: Sanjula Date: Mon, 17 Jun 2024 21:28:03 -0400 Subject: [PATCH 2/3] update nls Signed-off-by: Sanjula --- l10n/bundle.l10n.json | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json index 22f15801..c188806a 100644 --- a/l10n/bundle.l10n.json +++ b/l10n/bundle.l10n.json @@ -63,9 +63,6 @@ "Object Libraries": "Object Libraries", "Work with the set of libraries defined in the curlib, objlib, preUsrlibl, and postUsrlibl entries of the iproj.json": "Work with the set of libraries defined in the curlib, objlib, preUsrlibl, and postUsrlibl entries of the iproj.json", "Please connect to an IBM i": "Please connect to an IBM i", - "Text: {0}\n": "Text: {0}\n", - "Attribute: {0}\n": "Attribute: {0}\n", - "Type: {0}": "Type: {0}", "Migrating Source": "Migrating Source", "Verifying makei is installed...": "Verifying makei is installed...", "Required component ({0}) to migrate source not installed on host IBM i. Run {1} to get it.": "Required component ({0}) to migrate source not installed on host IBM i. Run {1} to get it.", @@ -108,12 +105,6 @@ "{0} does not contain any source files": "{0} does not contain any source files", "Workspace folder not specified": "Workspace folder not specified", "No source files selected to be migrated": "No source files selected to be migrated", - "Extension: {0}\n": "Extension: {0}\n", - "ASP: {0}\n": "ASP: {0}\n", - "Record Length: {0}\n": "Record Length: {0}\n", - "Lines: {0}\n": "Lines: {0}\n", - "Created: {0}\n": "Created: {0}\n", - "Changed: {0}": "Changed: {0}", "Reveal in Explorer": "Reveal in Explorer", "Failed to retrieve project": "Failed to retrieve project", "Enter build command ({0} resolves to the base file name being edited. {1} resolves to the full IFS path corresponding to the source in the editor. {2} resolves to the IBM i hostname. {3} resolves to the user profile that the command will be executed under. {4} resolves to the name of the current git branch if this project is managed by git.)": "Enter build command ({0} resolves to the base file name being edited. {1} resolves to the full IFS path corresponding to the source in the editor. {2} resolves to the IBM i hostname. {3} resolves to the user profile that the command will be executed under. {4} resolves to the name of the current git branch if this project is managed by git.)", @@ -185,9 +176,6 @@ "Deleted {0}": "Deleted {0}", "Error deleting member! {0}": "Error deleting member! {0}", "Include Paths": "Include Paths", - "Size: {0}\n": "Size: {0}\n", - "Owner: {0}\n": "Owner: {0}\n", - "Modified: {0}": "Modified: {0}", "Open Stream File": "Open Stream File", "Add Folder to Workspace": "Add Folder to Workspace", "Please configure project metadata": "Please configure project metadata", From 8565d21c916dc12944a6b0cdaa83b3f01816e372 Mon Sep 17 00:00:00 2001 From: Sanjula Date: Thu, 4 Jul 2024 16:50:53 -0400 Subject: [PATCH 3/3] fix tooltips for remote include paths and improve error checking Signed-off-by: Sanjula --- l10n/bundle.l10n.json | 3 ++- src/views/projectExplorer/errorItem.ts | 4 ++-- src/views/projectExplorer/includePaths.ts | 26 ++++++++++++++++++----- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json index a0b09720..91f966c5 100644 --- a/l10n/bundle.l10n.json +++ b/l10n/bundle.l10n.json @@ -179,6 +179,8 @@ "Deleted {0}": "Deleted {0}", "Error deleting member! {0}": "Error deleting member! {0}", "Include Paths": "Include Paths", + "Not specified": "Not specified", + "Not found": "Not found", "Open Stream File": "Open Stream File", "Add Folder to Workspace": "Add Folder to Workspace", "Please configure project metadata": "Please configure project metadata", @@ -192,7 +194,6 @@ "Please configure environment file": "Please configure environment file", "Create .env": "Create .env", "Unable to retrieve environment variables": "Unable to retrieve environment variables", - "Not specified": "Not specified", "Delete Upon Deploy\n": "Delete Upon Deploy\n", "License: {0}": "License: {0}", "No job log found": "No job log found", diff --git a/src/views/projectExplorer/errorItem.ts b/src/views/projectExplorer/errorItem.ts index 834e6db5..e652ee84 100644 --- a/src/views/projectExplorer/errorItem.ts +++ b/src/views/projectExplorer/errorItem.ts @@ -151,12 +151,12 @@ export default class ErrorItem extends TreeItem implements ProjectExplorerTreeIt ); } - static createIncludePathNotSpecifiedError(workspaceFolder: WorkspaceFolder, includePath: string, position: Position | undefined): ErrorItem { + static createIncludePathError(workspaceFolder: WorkspaceFolder, includePath: string, position: Position | undefined, description: string): ErrorItem { return new ErrorItem( workspaceFolder, includePath, { - description: l10n.t('Not specified'), + description: description, contextValue: ContextValue.includePath + (position === 'first' ? ContextValue.first : '') + (position === 'last' ? ContextValue.last : '') + diff --git a/src/views/projectExplorer/includePaths.ts b/src/views/projectExplorer/includePaths.ts index 26df510d..bc981f94 100644 --- a/src/views/projectExplorer/includePaths.ts +++ b/src/views/projectExplorer/includePaths.ts @@ -11,6 +11,7 @@ import RemoteIncludePath from "./remoteIncludePath"; import * as path from "path"; import ErrorItem from "./errorItem"; import { Position } from "../../iproject"; +import { getInstance } from "../../ibmi"; /** * Tree item for Include Paths heading. @@ -46,7 +47,7 @@ export default class IncludePaths extends TreeItem implements ProjectExplorerTre } if (includePath.startsWith('&')) { - items.push(ErrorItem.createIncludePathNotSpecifiedError(this.workspaceFolder, includePath, position)); + items.push(ErrorItem.createIncludePathError(this.workspaceFolder, includePath, position, l10n.t('Not specified'))); continue; } @@ -65,14 +66,29 @@ export default class IncludePaths extends TreeItem implements ProjectExplorerTre // Relative local include path items.push(new LocalIncludePath(this.workspaceFolder, includePath, includePathUri, position, variable)); } catch (e) { + const ibmi = getInstance(); + const connection = ibmi!.getConnection(); const deployLocation = iProject!.getDeployLocation(); + if (includePath.startsWith('/') || !deployLocation) { - // Absolute remote include path - items.push(new RemoteIncludePath(this.workspaceFolder, includePath, position, variable)); + const directoryExists = (await connection?.sendCommand({ command: `test -d ${includePath}` })); + + if (directoryExists && directoryExists.code === 0) { + // Absolute remote include path + items.push(new RemoteIncludePath(this.workspaceFolder, includePath, position, variable)); + } else { + items.push(ErrorItem.createIncludePathError(this.workspaceFolder, includePath, position, l10n.t('Not found'))); + } } else { - // Relative remote include path const absoluteIncludePath = path.posix.join(deployLocation, includePath); - items.push(new RemoteIncludePath(this.workspaceFolder, absoluteIncludePath, position, variable, { label: includePath })); + const directoryExists = (await connection?.sendCommand({ command: `test -d ${absoluteIncludePath}` })); + + if (directoryExists && directoryExists.code === 0) { + // Relative remote include path + items.push(new RemoteIncludePath(this.workspaceFolder, absoluteIncludePath, position, variable, { label: includePath })); + } else { + items.push(ErrorItem.createIncludePathError(this.workspaceFolder, includePath, position, l10n.t('Not found'))); + } } } }