diff --git a/src/GscDiagnosticsCollection.ts b/src/GscDiagnosticsCollection.ts index c8efb95..c342f5d 100644 --- a/src/GscDiagnosticsCollection.ts +++ b/src/GscDiagnosticsCollection.ts @@ -374,7 +374,7 @@ export class GscDiagnosticsCollection { const referenceData = GscFiles.getReferencedFileForFile(gscFile, path); - if (!gscFile.config.gameConfig.includeFileItself && referenceData.gscFile?.uri.toString() === gscFile.uri.toString()) { + if (!gscFile.config.gameConfig.includeFileItself && referenceData?.gscFile.uri.toString() === gscFile.uri.toString()) { return new vscode.Diagnostic(group.getRange(), "File is including itself", vscode.DiagnosticSeverity.Error); } @@ -390,7 +390,7 @@ export class GscDiagnosticsCollection { } // Check for duplicated function definitions - if (gscFile.config.gameConfig.duplicateFunctionDefinitions === false && referenceData.gscFile) { + if (gscFile.config.gameConfig.duplicateFunctionDefinitions === false && referenceData) { // Get all function definitions from included file const funcDefsInIncludedFile = GscFunctions.getLocalFunctionDefinitions(referenceData.gscFile); @@ -402,7 +402,7 @@ export class GscDiagnosticsCollection { for (let j = 0; j < index; j++) { const otherPath = allIncludedPaths[j]; const otherReferenceData = GscFiles.getReferencedFileForFile(gscFile, otherPath); - if (!otherReferenceData.gscFile) { + if (!otherReferenceData) { continue; } const otherFuncDefs = GscFunctions.getLocalFunctionDefinitions(otherReferenceData.gscFile); @@ -420,10 +420,10 @@ export class GscDiagnosticsCollection { } } - if (referenceData.gscFile === undefined) { + if (referenceData === undefined) { // This file path is ignored by configuration - if (gscFile.config.ignoredFilePaths.some(ignoredPath => path.toLowerCase().startsWith(ignoredPath.toLowerCase()))) { + if (GscFiles.isFileIgnoredBySettings(gscFile, path)) { return; } const d = new vscode.Diagnostic( @@ -519,7 +519,7 @@ export class GscDiagnosticsCollection { case GscFunctionState.NotFoundFile: // This file path is ignored by configuration - if (gscFile.config.ignoredFilePaths.some(ignoredPath => funcInfo.path.toLowerCase().startsWith(ignoredPath.toLowerCase()))) { + if (GscFiles.isFileIgnoredBySettings(gscFile, funcInfo.path)) { return; } var r = (funcInfo.pathGroup) ? funcInfo.pathGroup.getRange() : group.getRange(); diff --git a/src/GscFile.ts b/src/GscFile.ts index 904f22b..fea23bb 100644 --- a/src/GscFile.ts +++ b/src/GscFile.ts @@ -47,9 +47,7 @@ export class GscFile { } else { this.config = { referenceableGameRootFolders: [], - referenceableGameRootFoldersAll: [], referenceableWorkspaceFolders: [], - referenceableWorkspaceFoldersAll: [], rootFolder: undefined, currentGame: GscGame.UniversalGame, ignoredFunctionNames: [], diff --git a/src/GscFileCache.ts b/src/GscFileCache.ts index 3f08762..4749d33 100644 --- a/src/GscFileCache.ts +++ b/src/GscFileCache.ts @@ -10,15 +10,10 @@ import { LoggerOutput } from './LoggerOutput'; // Configuration of workspace that applies to all files within the workspace export type GscFilesConfig = { - /** All possible game root folders where GSC files can be found and referenced. */ - referenceableGameRootFolders: GscGameRootFolder[]; /** All possible game root folders where GSC files can be found and referenced, including reverse references */ - referenceableGameRootFoldersAll: GscGameRootFolder[]; - - /** All possible workspace folders where GSC files can be found and referenced */ - referenceableWorkspaceFolders: vscode.WorkspaceFolder[]; + referenceableGameRootFolders: GscGameRootFolder[]; /** All possible workspace folders where GSC files can be found and referenced, including reverse references */ - referenceableWorkspaceFoldersAll: vscode.WorkspaceFolder[]; + referenceableWorkspaceFolders: vscode.WorkspaceFolder[]; /** Game root folder */ rootFolder: GscGameRootFolder | undefined; @@ -235,10 +230,8 @@ export class GscWorkspaceFileData { const currentGame = GscConfig.getSelectedGame(workspaceFolder.uri); return { - referenceableGameRootFolders: GscFiles.loadReferenceableGameRootFolders(workspaceFolder, false), - referenceableGameRootFoldersAll: GscFiles.loadReferenceableGameRootFolders(workspaceFolder, true), - referenceableWorkspaceFolders: GscFiles.loadReferenceableWorkspaceFolders(workspaceFolder, false), - referenceableWorkspaceFoldersAll: GscFiles.loadReferenceableWorkspaceFolders(workspaceFolder, true), + referenceableGameRootFolders: GscFiles.loadReferenceableGameRootFolders(workspaceFolder), + referenceableWorkspaceFolders: GscFiles.loadReferenceableWorkspaceFolders(workspaceFolder), rootFolder: GscConfig.getGameRootFolder(workspaceFolder.uri), currentGame: currentGame, ignoredFunctionNames: GscConfig.getIgnoredFunctionNames(workspaceFolder.uri), diff --git a/src/GscFiles.ts b/src/GscFiles.ts index c835686..2ec8c4e 100644 --- a/src/GscFiles.ts +++ b/src/GscFiles.ts @@ -320,10 +320,9 @@ export class GscFiles { * It includes current workspace and included workspace folders via settings. * The workspace folders are sorted by their indexes (first being the last workspace folder in editor). * @param workspaceFolder Workspace folder from which the reference is made. - * @param includeReversedReferences If true, also workspace folders that include the current workspace folder are included. * @returns Array of workspace folders where the file can be found. */ - public static loadReferenceableWorkspaceFolders(workspaceFolder: vscode.WorkspaceFolder, includeReversedReferences: boolean): vscode.WorkspaceFolder[] { + public static loadReferenceableWorkspaceFolders(workspaceFolder: vscode.WorkspaceFolder): vscode.WorkspaceFolder[] { /* Define all possible locations where the file can be found @@ -348,13 +347,11 @@ export class GscFiles { includedWorkspaceFolders.push(workspaceFolder); // Find workspace folders that includes this workspace folder - if (includeReversedReferences) { - for (const workspaceFolder2 of vscode.workspace.workspaceFolders ?? []) { - const cfgIncludedWorkspaceFolderNames = GscConfig.getIncludedWorkspaceFolders(workspaceFolder2.uri); - // This workspace folder includes the referenced workspace folder - if (cfgIncludedWorkspaceFolderNames.includes(workspaceFolder.name)) { - includedWorkspaceFolders.push(workspaceFolder2); - } + for (const workspaceFolder2 of vscode.workspace.workspaceFolders ?? []) { + const cfgIncludedWorkspaceFolderNames = GscConfig.getIncludedWorkspaceFolders(workspaceFolder2.uri); + // This workspace folder includes the referenced workspace folder + if (cfgIncludedWorkspaceFolderNames.includes(workspaceFolder.name)) { + includedWorkspaceFolders.push(workspaceFolder2); } } @@ -409,13 +406,12 @@ export class GscFiles { * Get all possible game root folders where GSC files can be found and referenced. * It includes game root folder from current workspace and game root folders from included workspace folders via settings. * @param workspaceFolder Workspace folder from which the game root folders are referenced. - * @param includeReversedReferences If true, also workspace folders that include the current workspace folder are included. * @returns Array of game root folders where the file can be found. The first item is the game root folder from the workspace where the file is located. Other items are game root folders from included workspace folders sorted by their indexes. */ - public static loadReferenceableGameRootFolders(workspaceFolder: vscode.WorkspaceFolder, includeReversedReferences: boolean): GscGameRootFolder[] { + public static loadReferenceableGameRootFolders(workspaceFolder: vscode.WorkspaceFolder): GscGameRootFolder[] { // Define all possible locations where the file can be found (globally included workspace folders) - const includedWorkspaceFolders = GscFiles.loadReferenceableWorkspaceFolders(workspaceFolder, includeReversedReferences); + const includedWorkspaceFolders = GscFiles.loadReferenceableWorkspaceFolders(workspaceFolder); // Convert workspace folders to URIs taking game root folder into account const uris = includedWorkspaceFolders.map(f => GscConfig.getGameRootFolder(f.uri)!); @@ -426,48 +422,65 @@ export class GscFiles { /** * Get referenced file in specified file. It tries to find the file in all possible locations where it can be found (workspace folder and included workspace folders). + * File must be part of workspace to be found. * @param gscFile GSC file where the reference is located. * @param referencedFilePath Path in GSC file format (e.g. scripts\scriptName) - * @param includeReversedReferences If true, it also checks if the file is replaced by another file in another workspace folder. * @returns The reference status and the parsed file data if found */ - public static getReferencedFileForFile(gscFile: GscFile, referencedFilePath: string, includeReversedReferences: boolean = false): GscFileAndReferenceState { + public static getReferencedFileForFile(gscFile: GscFile, referencedFilePath: string): GscFileAndReferenceState | undefined { - const gameRootFolders = includeReversedReferences ? gscFile.config.referenceableGameRootFoldersAll : gscFile.config.referenceableGameRootFolders; + const file = this.getReferencedFilesForFile(gscFile, referencedFilePath, true); + + if (file.length > 0) { + return file[0]; + } + + return undefined; + } + - for (const referenceableGameRoot of gameRootFolders) { + /** + * Get the referenced file in specified file from all included workspaces. + * The first item in the array is the file that should be used. Other items are files that are replaced by the first file. + * File must be part of workspace to be found. + * @param gscFile GSC file where the reference is located. + * @param referencedFilePath Path in GSC file format (e.g. scripts\scriptName) + * @returns Array of reference status and the parsed file data if found + */ + public static getReferencedFilesForFile(gscFile: GscFile, referencedFilePath: string, exitOnFirst: boolean = false): GscFileAndReferenceState[] { + const referencedFiles: GscFileAndReferenceState[] = []; + + if (!gscFile.workspaceFolder) { + return referencedFiles; + } + + for (const referenceableGameRoot of gscFile.config.referenceableGameRootFolders) { const gscFilePathUri = vscode.Uri.joinPath(referenceableGameRoot.uri, referencedFilePath.replace(/\\/g, '/') + ".gsc"); const gsc = GscFiles.getCachedFile(gscFilePathUri, referenceableGameRoot.workspaceFolder.uri); - if (gsc === undefined) { - continue; // not found, try next workspace folder - } - - // File found, check if it is replaced by another file in another workspace folder - if (includeReversedReferences === false) { - const fileWithReverseReferences = this.getReferencedFileForFile(gscFile, referencedFilePath, true); - - if (gsc !== fileWithReverseReferences.gscFile && fileWithReverseReferences.referenceState !== GscFileReferenceState.NotFound) { - // File is replaced by another file in another workspace folder - if (fileWithReverseReferences.referenceState === GscFileReferenceState.IncludedWorkspaceFolder) { - fileWithReverseReferences.referenceState = GscFileReferenceState.IncludedWorkspaceFolderReversed; - } else if (fileWithReverseReferences.referenceState === GscFileReferenceState.LocalFile) { - // This should not happen - throw new Error("File is replaced by another file in another workspace folder, but it is not included workspace folder"); - } - return fileWithReverseReferences; - } + if (gsc === undefined || !gsc.workspaceFolder) { + continue; // not found or not part of workspace, try next workspace folder } var state = GscFileReferenceState.LocalFile; + var workspace = gsc.workspaceFolder; if (referenceableGameRoot.workspaceFolder !== gscFile.workspaceFolder) { - state = GscFileReferenceState.IncludedWorkspaceFolder; + if (gsc.workspaceFolder.index > gscFile.workspaceFolder.index) { + state = GscFileReferenceState.IncludedWorkspaceFolderOverwritten; + } else { + state = GscFileReferenceState.IncludedWorkspaceFolder; + } + workspace = referenceableGameRoot.workspaceFolder; } + + referencedFiles.push({gscFile: gsc, referenceState: state, referenceWorkspace: workspace}); - return {gscFile: gsc, referenceState: state}; + if (exitOnFirst) { + break; + } } - return {gscFile: undefined, referenceState: GscFileReferenceState.NotFound}; + return referencedFiles; } @@ -495,9 +508,20 @@ export class GscFiles { */ public static isFileReplacedByAnotherFile(gscFile: GscFile): boolean { - const referencedFiles = this.getReferencedFileForFile(gscFile, gscFile.gamePath, true); + const referencedFiles = this.getReferencedFileForFile(gscFile, gscFile.gamePath); + + if (referencedFiles && referencedFiles.gscFile !== gscFile) { + return true; + } + return false; + } - if (referencedFiles.gscFile !== gscFile) { + + /** + * Check if the GSC file is ignored by settings. + */ + public static isFileIgnoredBySettings(gscFile: GscFile, gamePath: string): boolean { + if (gscFile.config.ignoredFilePaths.some(ignoredPath => gamePath.toLowerCase().startsWith(ignoredPath.toLowerCase()))) { return true; } return false; @@ -1098,13 +1122,13 @@ export class GscFiles { export enum GscFileReferenceState { - NotFound, LocalFile, IncludedWorkspaceFolder, - IncludedWorkspaceFolderReversed + IncludedWorkspaceFolderOverwritten } export type GscFileAndReferenceState = { - gscFile: GscFile | undefined, + gscFile: GscFile, referenceState: GscFileReferenceState + referenceWorkspace: vscode.WorkspaceFolder }; \ No newline at end of file diff --git a/src/GscFunctions.ts b/src/GscFunctions.ts index 0a51076..0c0b019 100644 --- a/src/GscFunctions.ts +++ b/src/GscFunctions.ts @@ -3,6 +3,7 @@ import { GroupType, GscGroup, GscToken, GscVariableDefinitionType } from './GscF import { GscFiles, GscFileReferenceState } from './GscFiles'; import { GscFile } from './GscFile'; import { CodFunctions } from './CodFunctions'; +import { GscMarkdownGenerator } from './GscMarkdownGenerator'; export class GscFunction { @@ -25,53 +26,8 @@ export class GscFunction { public rangeScope: vscode.Range, ) {} - public static generateMarkdownDescription( - func: GscFunction | {name: string, parameters: {name: string, commentBefore?: string}[]}, - isLocalFunction: boolean, - uri: string | undefined, - reason: string = "") - : vscode.MarkdownString - { - const md = new vscode.MarkdownString(); - md.isTrusted = true; - var text = ""; - - // Declaration - text += func.name + "("; - text += func.parameters.map(p => p.name).join(", "); - text += ")"; - md.appendCodeblock(text); - - // Description - //md.appendMarkdown("" + func.desc + "\n\n"); - - // Parameters - func.parameters.forEach(p => { - text = "@param ```" + p.name + "```"; - if (p.commentBefore !== undefined && p.commentBefore !== "") { - text += " ā€” " + p.commentBefore; - } - text += " \n"; - md.appendMarkdown(text); - }); - - if (!isLocalFunction && uri !== undefined) { - const uri2 = vscode.Uri.parse(uri); - const relativePath = vscode.workspace.asRelativePath(uri2); - md.appendMarkdown("\nFile: `" + relativePath + "`"); - } else if (isLocalFunction) { - md.appendMarkdown("\n`Local function`"); - } - - if (reason !== "") { - md.appendMarkdown("\n\n" + reason); - } - - return md; - } - public generateMarkdownDescription(isLocalFunction: boolean, uri: string | undefined, reason: string): vscode.MarkdownString { - return GscFunction.generateMarkdownDescription(this, isLocalFunction, uri, reason); + return GscMarkdownGenerator.generateFunctionDescription(this, isLocalFunction, uri, reason); } }; @@ -145,7 +101,7 @@ export class GscFunctions { // File not found if (definitions === undefined) { // This file path is ignored by configuration - if (funcInfo && gscFile.config.ignoredFilePaths.some(ignoredPath => funcInfo.path.toLowerCase().startsWith(ignoredPath.toLowerCase()))) { + if (funcInfo && GscFiles.isFileIgnoredBySettings(gscFile, funcInfo.path)) { return ret(GscFunctionState.NotFoundFileButIgnored, []); } return ret(GscFunctionState.NotFoundFile, []); @@ -217,20 +173,20 @@ export class GscFunctions { if (funcInfo && funcInfo.path.length > 0) { const referenceData = GscFiles.getReferencedFileForFile(gscFile, funcInfo.path); - const referencedGscFile = referenceData.gscFile; - if (referencedGscFile === undefined) { + if (referenceData === undefined) { return undefined; } + const referencedGscFile = referenceData.gscFile; let reason = ""; - switch (referenceData.referenceState) { + /*switch (referenceData.referenceState) { case GscFileReferenceState.IncludedWorkspaceFolder: reason = "Included via workspace folder settings"; break; - case GscFileReferenceState.IncludedWorkspaceFolderReversed: + case GscFileReferenceState.IncludedWorkspaceFolderOverwritten: reason = "Included via other workspace folder settings. \nFile in current workspace is being overwritten."; break; - } + }*/ for (const f of referencedGscFile.data.functions) { if (!funcInfo || f.nameId === funcNameId) { @@ -264,10 +220,11 @@ export class GscFunctions { // Loop through all included files for (const includedPath of gscFile.data.includes) { - const referencedFile = GscFiles.getReferencedFileForFile(gscFile, includedPath).gscFile; - if (referencedFile === undefined) { + const referenceData = GscFiles.getReferencedFileForFile(gscFile, includedPath); + if (referenceData === undefined) { continue; // File not found } + const referencedFile = referenceData.gscFile; if (referencedFile.uri.toString() === gscFile.uri.toString()) { continue; // This includes itself, functions are already added } @@ -310,7 +267,7 @@ export class GscFunctions { funcReferences.push(...funcDefs.map(f => {return {func: f.func.groupFunctionName, uri: f.uri};})); // Find all function references in all files - const allFiles = gscFile.workspaceFolder ? GscFiles.getReferenceableCachedFiles(gscFile.workspaceFolder.uri, false) : [gscFile]; + const allFiles = gscFile.workspaceFolder ? GscFiles.getReferenceableCachedFiles(gscFile.workspaceFolder.uri, true) : [gscFile]; for (const gscFile2 of allFiles) { gscFile2.data.root.walk((group) => { diff --git a/src/GscHoverProvider.ts b/src/GscHoverProvider.ts index de4b3a0..1060e5b 100644 --- a/src/GscHoverProvider.ts +++ b/src/GscHoverProvider.ts @@ -7,6 +7,7 @@ import { ConfigErrorDiagnostics, GscConfig } from './GscConfig'; import { GscFunctions, GscFunctionState } from './GscFunctions'; import { Issues } from './Issues'; import { LoggerOutput } from './LoggerOutput'; +import { GscMarkdownGenerator } from './GscMarkdownGenerator'; export class GscHoverProvider implements vscode.HoverProvider { @@ -158,18 +159,13 @@ export class GscHoverProvider implements vscode.HoverProvider { } else if (groupAtCursor?.type === GroupType.Path) { const path = groupAtCursor.getTokensAsString(); - const fileReference = GscFiles.getReferencedFileForFile(gscFile, path); - if (fileReference !== undefined && fileReference.gscFile !== undefined) { - markdown.appendMarkdown("File: `" + vscode.workspace.asRelativePath(fileReference.gscFile.uri, true) + "`"); + const fileReferences = GscFiles.getReferencedFilesForFile(gscFile, path); + + if (fileReferences.length > 0) { hoverRange = groupAtCursor.getRange(); - } else { - // There would be error by diagnostics, unless disabled - if (errorDiagnosticsDisabled) { - markdown.appendText(`āš ļø Path '${path}' is not valid!`); - markdown.appendText(`\n\nšŸ›ˆ Error diagnostics disabled via workspace settings`); - } } + markdown = GscMarkdownGenerator.generateFilePathDescription(fileReferences, gscFile, path); } if (markdown.value === "") { @@ -179,6 +175,8 @@ export class GscHoverProvider implements vscode.HoverProvider { } } + + public static markdownAppendFileWasNotFound(md: vscode.MarkdownString, funcName: string, path: string) { md.appendText(`āš ļø File '${path}.gsc' was not found!`); } diff --git a/src/GscMarkdownGenerator.ts b/src/GscMarkdownGenerator.ts new file mode 100644 index 0000000..32414de --- /dev/null +++ b/src/GscMarkdownGenerator.ts @@ -0,0 +1,111 @@ +import * as vscode from 'vscode'; +import { GscFileAndReferenceState, GscFileReferenceState, GscFiles } from './GscFiles'; +import { GscFile } from './GscFile'; +import { ConfigErrorDiagnostics } from './GscConfig'; +import { GscFunction } from './GscFunctions'; + +export class GscMarkdownGenerator { + + /** + * Generates markdown string for function + * @param func Function data + * @param isLocalFunction If true it shows "Local function" + * @param uri If defined and isLocalFunction is false, it shows the file path + * @param extraDescription + * @returns Markdown string + */ + public static generateFunctionDescription( + func: GscFunction | {name: string, parameters: {name: string, commentBefore?: string}[]}, + isLocalFunction: boolean, + uri: string | undefined, + extraDescription: string = "") + : vscode.MarkdownString + { + const md = new vscode.MarkdownString(); + var text = ""; + + // Declaration + text += func.name + "("; + text += func.parameters.map(p => p.name).join(", "); + text += ")"; + md.appendCodeblock(text); + + // Description + //md.appendMarkdown("" + func.desc + "\n\n"); + + // Parameters + func.parameters.forEach(p => { + text = "@param ```" + p.name + "```"; + if (p.commentBefore !== undefined && p.commentBefore !== "") { + text += " ā€” " + p.commentBefore; + } + text += " \n"; + md.appendMarkdown(text); + }); + + if (!isLocalFunction && uri !== undefined) { + const uri2 = vscode.Uri.parse(uri); + const relativePath = vscode.workspace.asRelativePath(uri2); + md.appendMarkdown("\nFile: `" + relativePath + "`"); + } else if (isLocalFunction) { + md.appendMarkdown("\n`Local function`"); + } + + if (extraDescription !== "") { + md.appendMarkdown("\n\n" + extraDescription); + } + + return md; + } + + + public static generateFilePathDescription(fileReferences: GscFileAndReferenceState[], gscFile: GscFile, path: string): vscode.MarkdownString { + const markdown = new vscode.MarkdownString(); + + if (fileReferences.length === 0) { + // Path is ignored + if (GscFiles.isFileIgnoredBySettings(gscFile, path)) { + markdown.appendText(`šŸ›ˆ File '${path}.gsc' was not found, but its ignored by workspace settings!`); + } + + // There would be error by diagnostics, unless disabled + else if (gscFile.config.errorDiagnostics === ConfigErrorDiagnostics.Disable) { + markdown.appendText(`āš ļø Path '${path}' is not valid!`); + markdown.appendText(`\n\nšŸ›ˆ Error diagnostics disabled via workspace settings`); + } + } else { + + // Loop files in reverse and print the path + for (let i = fileReferences.length - 1; i >= 0; i--) { + const ref = fileReferences[i]; + + let status = ""; + // āœ”ļøāœ“āœ”ļøāŒāœ…šŸ”„šŸš«ā›” āœ–āœ–āŒāŒāœ–āœ—āœ˜ā˜“Ć—āØÆāŽā˜’āœ…āœ”āœ“ā˜‘ + let icon = ""; + if (fileReferences.length > 1) { + if (i === 0) { + icon = 'āœ… '; + } else { + icon = " āœ–  "; + } + status = i === 0 ? "**used**" : "replaced"; + } + let cross = i === 0 ? "" : "~~"; + + if (ref.referenceState === GscFileReferenceState.IncludedWorkspaceFolderOverwritten) { + //status += " (`" + ref.referenceWorkspace.name + "` includes `" + gscFile.workspaceFolder?.name + "` via settings)"; + status += "  (reversely included via settings)"; + } else if (ref.referenceState === GscFileReferenceState.IncludedWorkspaceFolder) { + //status += " (`" + gscFile.workspaceFolder?.name + "` includes `" + ref.referenceWorkspace.name + "` via settings)"; + status += "  (included via settings)"; + } else if (ref.referenceState === GscFileReferenceState.LocalFile) { + status += "  (local file)"; + } + + markdown.appendMarkdown("" + icon + " File: "+cross+"`" + vscode.workspace.asRelativePath(ref.gscFile.uri, true) + "`"+cross+"  " + status + " \n"); + } + + } + return markdown; + } +} \ No newline at end of file diff --git a/src/test/Tests.test.ts b/src/test/Tests.test.ts index 778575e..6e838f8 100644 --- a/src/test/Tests.test.ts +++ b/src/test/Tests.test.ts @@ -7,13 +7,14 @@ import { GscVariableDefinitionType } from '../GscFileParser'; import { GscHoverProvider } from '../GscHoverProvider'; import { GscDefinitionProvider } from '../GscDefinitionProvider'; import { EXTENSION_ID } from '../extension'; -import { GscFiles } from '../GscFiles'; +import { GscFileAndReferenceState, GscFiles } from '../GscFiles'; import { GscFile } from '../GscFile'; import { GscCompletionItemProvider } from '../GscCompletionItemProvider'; import { GscCodeActionProvider } from '../GscCodeActionProvider'; import { GscFunction } from '../GscFunctions'; import { LoggerOutput } from '../LoggerOutput'; import { Events } from '../Events'; +import { GscMarkdownGenerator } from '../GscMarkdownGenerator'; export const testWorkspaceDir = path.join(os.tmpdir(), 'vscode-test-workspace'); @@ -122,13 +123,21 @@ export function checkHover(hover: vscode.Hover | undefined, expected: string) { assert.deepStrictEqual(hover.contents[0].value, expected, "Not equal:\n\nCurrent:\n'" + hover.contents[0].value + "'\n\nExpected:\n'" + expected + "'\n\n"); } -export async function checkHoverExternalFunc(gscFile: GscFile, pos: vscode.Position, name: string, parameters: {name: string, commentBefore?: string}[], pathUri: string, reason: string) { +export async function checkHoverFunction(gscFile: GscFile, pos: vscode.Position, name: string, parameters: {name: string, commentBefore?: string}[], relativePath: string, reason: string) { const hover = await GscHoverProvider.getHover(gscFile, pos); - checkHover(hover, GscFunction.generateMarkdownDescription({name: name, parameters: parameters}, false, filePathToUri(pathUri).toString(), reason).value); + const pathUri = filePathToUri(relativePath).toString(); + checkHover(hover, GscMarkdownGenerator.generateFunctionDescription({name: name, parameters: parameters}, gscFile.uri.toString() === pathUri, pathUri, reason).value); } -export function getFunctionDescription(name: string, parameters: {name: string, commentBefore?: string}[], isLocal: boolean, pathUri: string, reason: string = "") { - return GscFunction.generateMarkdownDescription({name: name, parameters: parameters}, isLocal, filePathToUri(pathUri).toString(), reason).value; +export async function checkHoverPath(gscFile: GscFile, pos: vscode.Position, fileReferences: GscFileAndReferenceState[], path: string) { + const hover = await GscHoverProvider.getHover(gscFile, pos); + const md = GscMarkdownGenerator.generateFilePathDescription(fileReferences, gscFile, path).value; + checkHover(hover, md); +} + +export function getFunctionDescription(name: string, parameters: {name: string, commentBefore?: string}[], isLocal: boolean, relativePath: string, reason: string = "") { + const pathUri = filePathToUri(relativePath).toString(); + return GscMarkdownGenerator.generateFunctionDescription({name: name, parameters: parameters}, isLocal, pathUri, reason).value; } @@ -139,7 +148,7 @@ export function checkDefinition(locations: vscode.Location[], expectedFileEnd: s assert.deepStrictEqual(locations[0].uri.path.slice(-expectedFileEnd.length), expectedFileEnd, "Expected file end: " + expectedFileEnd + ". Actual: " + locations[0].uri.path); } -export async function checkDefinitionFunc(gscFile: GscFile, pos: vscode.Position, pathUri: string) { +export async function checkDefinitionLocation(gscFile: GscFile, pos: vscode.Position, pathUri: string) { const locations = await GscDefinitionProvider.getDefinitionLocations(gscFile, pos); checkDefinition(locations, pathUri); } diff --git a/src/test/workspace/GscAll_CoD2MP.test.ts b/src/test/workspace/GscAll_CoD2MP.test.ts index da1851f..c737d89 100644 --- a/src/test/workspace/GscAll_CoD2MP.test.ts +++ b/src/test/workspace/GscAll_CoD2MP.test.ts @@ -4,6 +4,7 @@ import * as tests from '../Tests.test'; import { GscHoverProvider } from '../../GscHoverProvider'; import { GscFunction } from '../../GscFunctions'; import { GscDefinitionProvider } from '../../GscDefinitionProvider'; +import { GscMarkdownGenerator } from '../../GscMarkdownGenerator'; /* @@ -90,12 +91,10 @@ suite('GscAll.CoD2MP', () => { assert.strictEqual(gsc.diagnostics.length, 1); // Correct path - // FunctionReferencesFolder\FunctionReferencesFile::funcName(); - const hover1 = await GscHoverProvider.getHover(gsc, new vscode.Position(3, 6)); - tests.checkHover(hover1, GscFunction.generateMarkdownDescription({name: "func1", parameters: []}, true, tests.filePathToUri("GscAll.CoD2MP/scripts/ItselfInclude.gsc").toString()).value); + // FunctionReferencesFolder\FunctionReferencesFile::funcName(); + await tests.checkHoverFunction(gsc, new vscode.Position(3, 6), "func1", [], "GscAll.CoD2MP/scripts/ItselfInclude.gsc", ""); - const locations1 = await GscDefinitionProvider.getDefinitionLocations(gsc, new vscode.Position(3, 6)); - tests.checkDefinition(locations1, "GscAll.CoD2MP/scripts/ItselfInclude.gsc"); + await tests.checkDefinitionLocation(gsc, new vscode.Position(3, 6), "GscAll.CoD2MP/scripts/ItselfInclude.gsc"); } catch (error) { @@ -124,20 +123,20 @@ suite('GscAll.CoD2MP', () => { assert.strictEqual(gsc.diagnostics.length, 8); var hover = await GscHoverProvider.getHover(gsc, new vscode.Position(10, 7)); - var md = GscFunction.generateMarkdownDescription({name: "func2", parameters: []}, true, undefined, undefined); + var md = GscMarkdownGenerator.generateFunctionDescription({name: "func2", parameters: []}, true, undefined, undefined); md.appendMarkdown('\n\r'); md.appendMarkdown('-------------------------------------------------------------------------- \n\r'); - md.appendMarkdown(GscFunction.generateMarkdownDescription({name: "func2", parameters: []}, false, tests.filePathToUri("GscAll.CoD2MP/scripts/file2.gsc").toString(), "Included via '#include'").value); + md.appendMarkdown(GscMarkdownGenerator.generateFunctionDescription({name: "func2", parameters: []}, false, tests.filePathToUri("GscAll.CoD2MP/scripts/file2.gsc").toString(), "Included via '#include'").value); tests.checkHover(hover, md.value); var hover = await GscHoverProvider.getHover(gsc, new vscode.Position(17, 3)); - var md = GscFunction.generateMarkdownDescription({name: "func5", parameters: []}, true, undefined, undefined); + var md = GscMarkdownGenerator.generateFunctionDescription({name: "func5", parameters: []}, true, undefined, undefined); md.appendMarkdown('\n\r'); md.appendMarkdown('-------------------------------------------------------------------------- \n\r'); - md.appendMarkdown(GscFunction.generateMarkdownDescription({name: "func5", parameters: []}, false, tests.filePathToUri("GscAll.CoD2MP/scripts/file5.gsc").toString(), "Included via '#include'").value); + md.appendMarkdown(GscMarkdownGenerator.generateFunctionDescription({name: "func5", parameters: []}, false, tests.filePathToUri("GscAll.CoD2MP/scripts/file5.gsc").toString(), "Included via '#include'").value); md.appendMarkdown('\n\r'); md.appendMarkdown('-------------------------------------------------------------------------- \n\r'); - md.appendMarkdown(GscFunction.generateMarkdownDescription({name: "func5", parameters: []}, false, tests.filePathToUri("GscAll.CoD2MP/scripts/file6.gsc").toString(), "Included via '#include'").value); + md.appendMarkdown(GscMarkdownGenerator.generateFunctionDescription({name: "func5", parameters: []}, false, tests.filePathToUri("GscAll.CoD2MP/scripts/file6.gsc").toString(), "Included via '#include'").value); tests.checkHover(hover, md.value); } catch (error) { diff --git a/src/test/workspace/GscAll_UniversalGame.test.ts b/src/test/workspace/GscAll_UniversalGame.test.ts index 4e4564a..426055d 100644 --- a/src/test/workspace/GscAll_UniversalGame.test.ts +++ b/src/test/workspace/GscAll_UniversalGame.test.ts @@ -4,6 +4,7 @@ import * as tests from '../Tests.test'; import { GscHoverProvider } from '../../GscHoverProvider'; import { GscFunction } from '../../GscFunctions'; import { GscDefinitionProvider } from '../../GscDefinitionProvider'; +import { GscMarkdownGenerator } from '../../GscMarkdownGenerator'; /* @@ -73,7 +74,7 @@ suite('GscAll.UniversalGame', () => { // Correct path // FunctionReferencesFolder\FunctionReferencesFile::funcName(); const hover1 = await GscHoverProvider.getHover(gsc, new vscode.Position(3, 6)); - tests.checkHover(hover1, GscFunction.generateMarkdownDescription({name: "func1", parameters: []}, true, tests.filePathToUri("GscAll.UniversalGame/scripts/ItselfInclude.gsc").toString()).value); + tests.checkHover(hover1, GscMarkdownGenerator.generateFunctionDescription({name: "func1", parameters: []}, true, tests.filePathToUri("GscAll.UniversalGame/scripts/ItselfInclude.gsc").toString()).value); const locations1 = await GscDefinitionProvider.getDefinitionLocations(gsc, new vscode.Position(3, 6)); tests.checkDefinition(locations1, "GscAll.UniversalGame/scripts/ItselfInclude.gsc"); @@ -100,7 +101,7 @@ suite('GscAll.UniversalGame', () => { assert.strictEqual(gsc.diagnostics.length, 4); var hover1 = await GscHoverProvider.getHover(gsc, new vscode.Position(10, 7)); - var md = GscFunction.generateMarkdownDescription({name: "func2", parameters: []}, true, undefined, undefined); + var md = GscMarkdownGenerator.generateFunctionDescription({name: "func2", parameters: []}, true, undefined, undefined); md.appendMarkdown('\n\r'); md.appendMarkdown('-------------------------------------------------------------------------- \n\r'); md.appendMarkdown(`Function 'func2' is also defined in this file: \n\r`); @@ -108,7 +109,7 @@ suite('GscAll.UniversalGame', () => { tests.checkHover(hover1, md.value); var hover = await GscHoverProvider.getHover(gsc, new vscode.Position(17, 3)); - var md = GscFunction.generateMarkdownDescription({name: "func5", parameters: []}, true, undefined, undefined); + var md = GscMarkdownGenerator.generateFunctionDescription({name: "func5", parameters: []}, true, undefined, undefined); md.appendMarkdown('\n\r'); md.appendMarkdown('-------------------------------------------------------------------------- \n\r'); md.appendMarkdown(`Function 'func5' is also defined in these files: \n\r`); diff --git a/src/test/workspace/GscFileReferences.test.ts b/src/test/workspace/GscFileReferences.test.ts index cff470f..e5e1300 100644 --- a/src/test/workspace/GscFileReferences.test.ts +++ b/src/test/workspace/GscFileReferences.test.ts @@ -8,6 +8,8 @@ import { GscCompletionItemProvider } from '../../GscCompletionItemProvider'; import { GscVariableDefinitionType } from '../../GscFileParser'; import { GscReferenceProvider } from '../../GscReferenceProvider'; import { Issues } from '../../Issues'; +import { GscFileAndReferenceState, GscFileReferenceState } from '../../GscFiles'; +import { GscMarkdownGenerator } from '../../GscMarkdownGenerator'; suite('GscFileReferences', () => { @@ -26,54 +28,54 @@ suite('GscFileReferences', () => { assert.ok(gsc.diagnostics.length === 0); const hover1_include = await GscHoverProvider.getHover(gsc, new vscode.Position(0, 40)); - tests.checkHover(hover1_include, "File: `" + vscode.workspace.asRelativePath(tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"), true) + "`"); + tests.checkHover(hover1_include, " File: `" + vscode.workspace.asRelativePath(tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"), true) + "`    (local file) \n"); // Correct path // FunctionReferencesFolder\FunctionReferencesFile::funcName(); const hover1 = await GscHoverProvider.getHover(gsc, new vscode.Position(5, 57)); - tests.checkHover(hover1, GscFunction.generateMarkdownDescription({name: "funcName", parameters: []}, false, tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc").toString()).value); + tests.checkHover(hover1, GscMarkdownGenerator.generateFunctionDescription({name: "funcName", parameters: []}, false, tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc").toString()).value); const hover1_file = await GscHoverProvider.getHover(gsc, new vscode.Position(5, 40)); - tests.checkHover(hover1_file, "File: `" + vscode.workspace.asRelativePath(tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"), true) + "`"); + tests.checkHover(hover1_file, " File: `" + vscode.workspace.asRelativePath(tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"), true) + "`    (local file) \n"); const locations1 = await GscDefinitionProvider.getDefinitionLocations(gsc, new vscode.Position(5, 57)); tests.checkDefinition(locations1, "GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"); // Lowercase path // functionreferencesfolder\FunctionReferencesFile::funcName(); const hover2 = await GscHoverProvider.getHover(gsc, new vscode.Position(8, 57)); - tests.checkHover(hover2, GscFunction.generateMarkdownDescription({name: "funcName", parameters: []}, false, tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc").toString()).value); + tests.checkHover(hover2, GscMarkdownGenerator.generateFunctionDescription({name: "funcName", parameters: []}, false, tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc").toString()).value); const hover2_file = await GscHoverProvider.getHover(gsc, new vscode.Position(8, 40)); - tests.checkHover(hover2_file, "File: `" + vscode.workspace.asRelativePath(tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"), true) + "`"); + tests.checkHover(hover2_file, " File: `" + vscode.workspace.asRelativePath(tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"), true) + "`    (local file) \n"); const locations2 = await GscDefinitionProvider.getDefinitionLocations(gsc, new vscode.Position(8, 57)); tests.checkDefinition(locations2, "GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"); // Lowercase path + file // functionreferencesfolder\functionreferencesfile::funcName(); const hover3 = await GscHoverProvider.getHover(gsc, new vscode.Position(11, 57)); - tests.checkHover(hover3, GscFunction.generateMarkdownDescription({name: "funcName", parameters: []}, false, tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc").toString()).value); + tests.checkHover(hover3, GscMarkdownGenerator.generateFunctionDescription({name: "funcName", parameters: []}, false, tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc").toString()).value); const hover3_file = await GscHoverProvider.getHover(gsc, new vscode.Position(11, 40)); - tests.checkHover(hover3_file, "File: `" + vscode.workspace.asRelativePath(tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"), true) + "`"); + tests.checkHover(hover3_file, " File: `" + vscode.workspace.asRelativePath(tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"), true) + "`    (local file) \n"); const locations3 = await GscDefinitionProvider.getDefinitionLocations(gsc, new vscode.Position(11, 57)); tests.checkDefinition(locations3, "GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"); // Lowercase path + file + func name // functionreferencesfolder\functionreferencesfile::funcname(); const hover4 = await GscHoverProvider.getHover(gsc, new vscode.Position(14, 57)); - tests.checkHover(hover4, GscFunction.generateMarkdownDescription({name: "funcName", parameters: []}, false, tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc").toString()).value); + tests.checkHover(hover4, GscMarkdownGenerator.generateFunctionDescription({name: "funcName", parameters: []}, false, tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc").toString()).value); const hover4_file = await GscHoverProvider.getHover(gsc, new vscode.Position(14, 40)); - tests.checkHover(hover4_file, "File: `" + vscode.workspace.asRelativePath(tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"), true) + "`"); + tests.checkHover(hover4_file, " File: `" + vscode.workspace.asRelativePath(tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"), true) + "`    (local file) \n"); const locations4 = await GscDefinitionProvider.getDefinitionLocations(gsc, new vscode.Position(14, 57)); tests.checkDefinition(locations4, "GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"); // Hover over "includedFuncName();" - its case insensitive, external file should be found const hover5 = await GscHoverProvider.getHover(gsc, new vscode.Position(17, 8)); - tests.checkHover(hover5, GscFunction.generateMarkdownDescription({name: "includedFuncName", parameters: []}, false, tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc").toString(), "Included via '#include'").value); + tests.checkHover(hover5, GscMarkdownGenerator.generateFunctionDescription({name: "includedFuncName", parameters: []}, false, tests.filePathToUri("GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc").toString(), "Included via '#include'").value); const locations5 = await GscDefinitionProvider.getDefinitionLocations(gsc, new vscode.Position(17, 8)); tests.checkDefinition(locations5, "GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc"); // Hover over "localFunc();" - its case insensitive, local func should be found const hover6 = await GscHoverProvider.getHover(gsc, new vscode.Position(20, 8)); - tests.checkHover(hover6, GscFunction.generateMarkdownDescription({name: "LOCALFUNC", parameters: []}, true, undefined, undefined).value); + tests.checkHover(hover6, GscMarkdownGenerator.generateFunctionDescription({name: "LOCALFUNC", parameters: []}, true, undefined, undefined).value); const locations6 = await GscDefinitionProvider.getDefinitionLocations(gsc, new vscode.Position(20, 8)); tests.checkDefinition(locations6, "GscFileReferences.1/LowerUpperCase.gsc"); @@ -87,54 +89,129 @@ suite('GscFileReferences', () => { // Check case insensitivity of function calls (file paths, function names) test('GscFileReferences - included workspace folders 1', async () => { try { - var gsc = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file1.gsc']); + var gsc_1 = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file1.gsc']); + var gsc_2 = await tests.loadGscFile(['GscFileReferences.2', 'scripts', 'file2.gsc']); + var gsc_3 = await tests.loadGscFile(['GscFileReferences.3', 'scripts', 'file3.gsc']); + var gsc_rep_all_1 = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file_replaced_all.gsc']); + var gsc_rep_all_2 = await tests.loadGscFile(['GscFileReferences.2', 'scripts', 'file_replaced_all.gsc']); + var gsc_rep_all_3 = await tests.loadGscFile(['GscFileReferences.3', 'scripts', 'file_replaced_all.gsc']); + + var gsc_rep_1a2_1 = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file_replaced_1_2.gsc']); + var gsc_rep_1a2_2 = await tests.loadGscFile(['GscFileReferences.2', 'scripts', 'file_replaced_1_2.gsc']); + + var gsc_rep_1 = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file_replaced_1.gsc']); + + + assert.ok(gsc_1.diagnostics.length === 0); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + var position = new vscode.Position(1, 20); // file_replaced_all + var pathReferences: GscFileAndReferenceState[] = [ // First is the used file + {gscFile: gsc_rep_all_3, referenceState: GscFileReferenceState.IncludedWorkspaceFolderOverwritten, referenceWorkspace: gsc_rep_all_3.workspaceFolder!}, + {gscFile: gsc_rep_all_2, referenceState: GscFileReferenceState.IncludedWorkspaceFolderOverwritten, referenceWorkspace: gsc_rep_all_2.workspaceFolder!}, + {gscFile: gsc_rep_all_1, referenceState: GscFileReferenceState.LocalFile, referenceWorkspace: gsc_rep_all_1.workspaceFolder!} + ]; + await tests.checkHoverPath(gsc_1, position, pathReferences, "scripts\\file_replaced_all"); + await tests.checkDefinitionLocation(gsc_1, position, "GscFileReferences.3/scripts/file_replaced_all.gsc"); + + var position = new vscode.Position(1, 34); // main() + await tests.checkHoverFunction(gsc_1, position, "main", [], "GscFileReferences.3/scripts/file_replaced_all.gsc", ""); + await tests.checkDefinitionLocation(gsc_1, position, "GscFileReferences.3/scripts/file_replaced_all.gsc"); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + var position = new vscode.Position(3, 20); // file_replaced_1_2 + var pathReferences: GscFileAndReferenceState[] = [ // First is the used file + {gscFile: gsc_rep_1a2_2, referenceState: GscFileReferenceState.IncludedWorkspaceFolderOverwritten, referenceWorkspace: gsc_rep_1a2_2.workspaceFolder!}, + {gscFile: gsc_rep_1a2_1, referenceState: GscFileReferenceState.LocalFile, referenceWorkspace: gsc_rep_1a2_1.workspaceFolder!} + ]; + await tests.checkHoverPath(gsc_1, position, pathReferences, "scripts\\file_replaced_1_2"); + await tests.checkDefinitionLocation(gsc_1, position, "GscFileReferences.2/scripts/file_replaced_1_2.gsc"); + + var position = new vscode.Position(3, 34); // main() + await tests.checkHoverFunction(gsc_1, position, "main", [], "GscFileReferences.2/scripts/file_replaced_1_2.gsc", ""); + await tests.checkDefinitionLocation(gsc_1, position, "GscFileReferences.2/scripts/file_replaced_1_2.gsc"); + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + var position = new vscode.Position(5, 20); // file_replaced_1 + var pathReferences: GscFileAndReferenceState[] = [ // First is the used file + {gscFile: gsc_rep_1, referenceState: GscFileReferenceState.LocalFile, referenceWorkspace: gsc_rep_1.workspaceFolder!} + ]; + await tests.checkHoverPath(gsc_1, position, pathReferences, "scripts\\file_replaced_1"); + await tests.checkDefinitionLocation(gsc_1, position, "GscFileReferences.1/scripts/file_replaced_1.gsc"); + + var position = new vscode.Position(5, 32); // main() + await tests.checkHoverFunction(gsc_1, position, "main", [], "GscFileReferences.1/scripts/file_replaced_1.gsc", ""); + await tests.checkDefinitionLocation(gsc_1, position, "GscFileReferences.1/scripts/file_replaced_1.gsc"); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // scripts\file1::main(); + var position = new vscode.Position(8, 10); // scripts\file1 + await tests.checkHoverPath(gsc_1, position, [{gscFile: gsc_1, referenceState: GscFileReferenceState.LocalFile, referenceWorkspace: gsc_1.workspaceFolder!}], "scripts\\file1"); + await tests.checkDefinitionLocation(gsc_1, position, "GscFileReferences.1/scripts/file1.gsc"); + + var position = new vscode.Position(8, 22); // main() + await tests.checkHoverFunction(gsc_1, position, "main", [], "GscFileReferences.1/scripts/file1.gsc", ""); + await tests.checkDefinitionLocation(gsc_1, position, "GscFileReferences.1/scripts/file1.gsc"); - tests.checkDiagnostic(gsc.diagnostics, 0, "File 'scripts\\file2.gsc' was not found in workspace folder 'GscFileReferences.1'", vscode.DiagnosticSeverity.Error); - tests.checkDiagnostic(gsc.diagnostics, 1, "File 'scripts\\file3.gsc' was not found in workspace folder 'GscFileReferences.1'", vscode.DiagnosticSeverity.Error); - assert.ok(gsc.diagnostics.length === 2); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // scripts\file2::main(); + var position = new vscode.Position(9, 10); // scripts\file2 + await tests.checkHoverPath(gsc_1, position, [{gscFile: gsc_2, referenceState: GscFileReferenceState.IncludedWorkspaceFolderOverwritten, referenceWorkspace: gsc_2.workspaceFolder!}], "scripts\\file2"); + await tests.checkDefinitionLocation(gsc_1, position, "GscFileReferences.2/scripts/file2.gsc"); - var position = new vscode.Position(1, 34); - await tests.checkHoverExternalFunc(gsc, position, "main", [], "GscFileReferences.3/scripts/file_replaced_all.gsc", "Included via other workspace folder settings. \nFile in current workspace is being overwritten."); - await tests.checkDefinitionFunc(gsc, position, "GscFileReferences.3/scripts/file_replaced_all.gsc"); + var position = new vscode.Position(9, 22); // main() + await tests.checkHoverFunction(gsc_1, position, "main", [], "GscFileReferences.2/scripts/file2.gsc", ""); + await tests.checkDefinitionLocation(gsc_1, position, "GscFileReferences.2/scripts/file2.gsc"); - var position = new vscode.Position(3, 34); - await tests.checkHoverExternalFunc(gsc, position, "main", [], "GscFileReferences.2/scripts/file_replaced_1_2.gsc", "Included via other workspace folder settings. \nFile in current workspace is being overwritten."); - await tests.checkDefinitionFunc(gsc, position, "GscFileReferences.2/scripts/file_replaced_1_2.gsc"); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - var position = new vscode.Position(5, 32); - await tests.checkHoverExternalFunc(gsc, position, "main", [], "GscFileReferences.1/scripts/file_replaced_1.gsc", ""); - await tests.checkDefinitionFunc(gsc, position, "GscFileReferences.1/scripts/file_replaced_1.gsc"); + // scripts\file3::main(); + var position = new vscode.Position(10, 10); // scripts\file3 + await tests.checkHoverPath(gsc_1, position, [{gscFile: gsc_3, referenceState: GscFileReferenceState.IncludedWorkspaceFolderOverwritten, referenceWorkspace: gsc_3.workspaceFolder!}], "scripts\\file3"); + await tests.checkDefinitionLocation(gsc_1, position, "GscFileReferences.3/scripts/file3.gsc"); - var position = new vscode.Position(8, 22); - var hover = await GscHoverProvider.getHover(gsc, position); - tests.checkHover(hover, GscFunction.generateMarkdownDescription({name: "main", parameters: []}, true, undefined, undefined).value); - var locations = await GscDefinitionProvider.getDefinitionLocations(gsc, position); - tests.checkDefinition(locations, "GscFileReferences.1/scripts/file1.gsc"); + var position = new vscode.Position(10, 22); // main() + await tests.checkHoverFunction(gsc_1, position, "main", [], "GscFileReferences.3/scripts/file3.gsc", ""); + await tests.checkDefinitionLocation(gsc_1, position, "GscFileReferences.3/scripts/file3.gsc"); + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Write text into document - const document = await vscode.window.showTextDocument(gsc.uri); + const document = await vscode.window.showTextDocument(gsc_1.uri); await document.edit(editBuilder => { editBuilder.insert(new vscode.Position(14, 4), "level."); }); - await tests.waitForDiagnosticsChange(gsc.uri); + await tests.waitForDiagnosticsChange(gsc_1.uri); - var gsc = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file1.gsc']); + var gsc_1 = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file1.gsc']); - const completions = await GscCompletionItemProvider.getCompletionItems(gsc, new vscode.Position(14, 10), gsc.config.currentGame, undefined); + const completions = await GscCompletionItemProvider.getCompletionItems(gsc_1, new vscode.Position(14, 10), gsc_1.config.currentGame, undefined); - tests.checkCompletions(gsc, completions, 0, "file1", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); - assert.ok(completions.length === 1); + tests.checkCompletions(gsc_1, completions, 0, "file3", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); + tests.checkCompletions(gsc_1, completions, 1, "file2", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); + tests.checkCompletions(gsc_1, completions, 2, "file1", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); + assert.ok(completions.length === 3); // Check references of "main" function - const refLocs = await GscReferenceProvider.getFunctionReferenceLocations(gsc, new vscode.Position(0, 2)); - tests.checkReferenceLocation(refLocs, 0, gsc.uri, 0, 0, 4); - tests.checkReferenceLocation(refLocs, 1, gsc.uri, 8, 19, 23); - assert.strictEqual(refLocs.length, 2); + const refLocs = await GscReferenceProvider.getFunctionReferenceLocations(gsc_1, new vscode.Position(0, 2)); + tests.checkReferenceLocation(refLocs, 0, gsc_1.uri, 0, 0, 4); + tests.checkReferenceLocation(refLocs, 1, tests.filePathToUri("GscFileReferences.3/scripts/file3.gsc"), 8, 19, 23); + tests.checkReferenceLocation(refLocs, 2, tests.filePathToUri("GscFileReferences.2/scripts/file2.gsc"), 8, 19, 23); + tests.checkReferenceLocation(refLocs, 3, gsc_1.uri, 8, 19, 23); + assert.strictEqual(refLocs.length, 4); // Close text editor @@ -155,51 +232,129 @@ suite('GscFileReferences', () => { // Check case insensitivity of function calls (file paths, function names) test('GscFileReferences - included workspace folders 2', async () => { try { - var gsc = await tests.loadGscFile(['GscFileReferences.2', 'scripts', 'file2.gsc']); + var gsc_1 = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file1.gsc']); + var gsc_2 = await tests.loadGscFile(['GscFileReferences.2', 'scripts', 'file2.gsc']); + var gsc_3 = await tests.loadGscFile(['GscFileReferences.3', 'scripts', 'file3.gsc']); + + var gsc_rep_all_1 = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file_replaced_all.gsc']); + var gsc_rep_all_2 = await tests.loadGscFile(['GscFileReferences.2', 'scripts', 'file_replaced_all.gsc']); + var gsc_rep_all_3 = await tests.loadGscFile(['GscFileReferences.3', 'scripts', 'file_replaced_all.gsc']); + var gsc_rep_1a2_1 = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file_replaced_1_2.gsc']); + var gsc_rep_1a2_2 = await tests.loadGscFile(['GscFileReferences.2', 'scripts', 'file_replaced_1_2.gsc']); + + var gsc_rep_1 = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file_replaced_1.gsc']); + + + assert.ok(gsc_2.diagnostics.length === 0); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + var position = new vscode.Position(1, 20); // file_replaced_all + var pathReferences: GscFileAndReferenceState[] = [ // First is the used file + {gscFile: gsc_rep_all_3, referenceState: GscFileReferenceState.IncludedWorkspaceFolderOverwritten, referenceWorkspace: gsc_rep_all_3.workspaceFolder!}, + {gscFile: gsc_rep_all_2, referenceState: GscFileReferenceState.LocalFile, referenceWorkspace: gsc_rep_all_2.workspaceFolder!}, + {gscFile: gsc_rep_all_1, referenceState: GscFileReferenceState.IncludedWorkspaceFolder, referenceWorkspace: gsc_rep_all_1.workspaceFolder!} + ]; + await tests.checkHoverPath(gsc_2, position, pathReferences, "scripts\\file_replaced_all"); + await tests.checkDefinitionLocation(gsc_2, position, "GscFileReferences.3/scripts/file_replaced_all.gsc"); + + var position = new vscode.Position(1, 34); // main() + await tests.checkHoverFunction(gsc_2, position, "main", [], "GscFileReferences.3/scripts/file_replaced_all.gsc", ""); + await tests.checkDefinitionLocation(gsc_2, position, "GscFileReferences.3/scripts/file_replaced_all.gsc"); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + var position = new vscode.Position(3, 20); // file_replaced_1_2 + var pathReferences: GscFileAndReferenceState[] = [ // First is the used file + {gscFile: gsc_rep_1a2_2, referenceState: GscFileReferenceState.LocalFile, referenceWorkspace: gsc_rep_1a2_2.workspaceFolder!}, + {gscFile: gsc_rep_1a2_1, referenceState: GscFileReferenceState.IncludedWorkspaceFolder, referenceWorkspace: gsc_rep_1a2_1.workspaceFolder!} + ]; + await tests.checkHoverPath(gsc_2, position, pathReferences, "scripts\\file_replaced_1_2"); + await tests.checkDefinitionLocation(gsc_2, position, "GscFileReferences.2/scripts/file_replaced_1_2.gsc"); + + var position = new vscode.Position(3, 34); // main() + await tests.checkHoverFunction(gsc_2, position, "main", [], "GscFileReferences.2/scripts/file_replaced_1_2.gsc", ""); + await tests.checkDefinitionLocation(gsc_2, position, "GscFileReferences.2/scripts/file_replaced_1_2.gsc"); + - tests.checkDiagnostic(gsc.diagnostics, 0, "File 'scripts\\file3.gsc' was not found in workspace folder 'GscFileReferences.2', 'GscFileReferences.1'", vscode.DiagnosticSeverity.Error); - assert.ok(gsc.diagnostics.length === 1); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + var position = new vscode.Position(5, 20); // file_replaced_1 + var pathReferences: GscFileAndReferenceState[] = [ // First is the used file + {gscFile: gsc_rep_1, referenceState: GscFileReferenceState.IncludedWorkspaceFolder, referenceWorkspace: gsc_rep_1.workspaceFolder!} + ]; + await tests.checkHoverPath(gsc_2, position, pathReferences, "scripts\\file_replaced_1"); + await tests.checkDefinitionLocation(gsc_2, position, "GscFileReferences.1/scripts/file_replaced_1.gsc"); - var position = new vscode.Position(1, 34); - await tests.checkHoverExternalFunc(gsc, position, "main", [], "GscFileReferences.3/scripts/file_replaced_all.gsc", "Included via other workspace folder settings. \nFile in current workspace is being overwritten."); - await tests.checkDefinitionFunc(gsc, position, "GscFileReferences.3/scripts/file_replaced_all.gsc"); + var position = new vscode.Position(5, 32); // main() + await tests.checkHoverFunction(gsc_2, position, "main", [], "GscFileReferences.1/scripts/file_replaced_1.gsc", ""); + await tests.checkDefinitionLocation(gsc_2, position, "GscFileReferences.1/scripts/file_replaced_1.gsc"); - var position = new vscode.Position(3, 34); - await tests.checkHoverExternalFunc(gsc, position, "main", [], "GscFileReferences.2/scripts/file_replaced_1_2.gsc", ""); - await tests.checkDefinitionFunc(gsc, position, "GscFileReferences.2/scripts/file_replaced_1_2.gsc"); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - var position = new vscode.Position(5, 32); - await tests.checkHoverExternalFunc(gsc, position, "main", [], "GscFileReferences.1/scripts/file_replaced_1.gsc", "Included via workspace folder settings"); - await tests.checkDefinitionFunc(gsc, position, "GscFileReferences.1/scripts/file_replaced_1.gsc"); + // scripts\file1::main(); + var position = new vscode.Position(8, 10); // scripts\file1 + await tests.checkHoverPath(gsc_2, position, [{gscFile: gsc_1, referenceState: GscFileReferenceState.IncludedWorkspaceFolder, referenceWorkspace: gsc_2.workspaceFolder!}], "scripts\\file1"); + await tests.checkDefinitionLocation(gsc_2, position, "GscFileReferences.1/scripts/file1.gsc"); + var position = new vscode.Position(8, 22); // main() + await tests.checkHoverFunction(gsc_2, position, "main", [], "GscFileReferences.1/scripts/file1.gsc", ""); + await tests.checkDefinitionLocation(gsc_2, position, "GscFileReferences.1/scripts/file1.gsc"); - var position = new vscode.Position(8, 22); - await tests.checkHoverExternalFunc(gsc, position, "main", [], "GscFileReferences.1/scripts/file1.gsc", "Included via workspace folder settings"); - await tests.checkDefinitionFunc(gsc, position, "GscFileReferences.1/scripts/file1.gsc"); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - var position = new vscode.Position(9, 22); - var hover = await GscHoverProvider.getHover(gsc, position); - tests.checkHover(hover, GscFunction.generateMarkdownDescription({name: "main", parameters: []}, true, undefined, undefined).value); - var locations = await GscDefinitionProvider.getDefinitionLocations(gsc, position); - tests.checkDefinition(locations, "GscFileReferences.2/scripts/file2.gsc"); + // scripts\file2::main(); + var position = new vscode.Position(9, 10); // scripts\file2 + await tests.checkHoverPath(gsc_2, position, [{gscFile: gsc_2, referenceState: GscFileReferenceState.LocalFile, referenceWorkspace: gsc_2.workspaceFolder!}], "scripts\\file2"); + await tests.checkDefinitionLocation(gsc_2, position, "GscFileReferences.2/scripts/file2.gsc"); + + var position = new vscode.Position(9, 22); // main() + await tests.checkHoverFunction(gsc_2, position, "main", [], "GscFileReferences.2/scripts/file2.gsc", ""); + await tests.checkDefinitionLocation(gsc_2, position, "GscFileReferences.2/scripts/file2.gsc"); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // scripts\file3::main(); + var position = new vscode.Position(10, 10); // scripts\file3 + await tests.checkHoverPath(gsc_2, position, [{gscFile: gsc_3, referenceState: GscFileReferenceState.IncludedWorkspaceFolderOverwritten, referenceWorkspace: gsc_3.workspaceFolder!}], "scripts\\file3"); + await tests.checkDefinitionLocation(gsc_2, position, "GscFileReferences.3/scripts/file3.gsc"); + + var position = new vscode.Position(10, 22); // main() + await tests.checkHoverFunction(gsc_2, position, "main", [], "GscFileReferences.3/scripts/file3.gsc", ""); + await tests.checkDefinitionLocation(gsc_2, position, "GscFileReferences.3/scripts/file3.gsc"); + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Write text into document - const document = await vscode.window.showTextDocument(gsc.uri); + const document = await vscode.window.showTextDocument(gsc_2.uri); await document.edit(editBuilder => { editBuilder.insert(new vscode.Position(14, 4), "level."); }); - await tests.waitForDiagnosticsChange(gsc.uri); + await tests.waitForDiagnosticsChange(gsc_2.uri); + + var gsc_2 = await tests.loadGscFile(['GscFileReferences.2', 'scripts', 'file2.gsc']); - var gsc = await tests.loadGscFile(['GscFileReferences.2', 'scripts', 'file2.gsc']); + const completions = await GscCompletionItemProvider.getCompletionItems(gsc_2, new vscode.Position(14, 10), gsc_2.config.currentGame, undefined); + + tests.checkCompletions(gsc_2, completions, 0, "file3", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); + tests.checkCompletions(gsc_2, completions, 1, "file2", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); + tests.checkCompletions(gsc_2, completions, 2, "file1", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); + assert.ok(completions.length === 3); - const completions = await GscCompletionItemProvider.getCompletionItems(gsc, new vscode.Position(14, 10), gsc.config.currentGame, undefined); - tests.checkCompletions(gsc, completions, 0, "file2", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); - tests.checkCompletions(gsc, completions, 1, "file1", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); - assert.ok(completions.length === 2); + + // Check references of "main" function + const refLocs = await GscReferenceProvider.getFunctionReferenceLocations(gsc_2, new vscode.Position(0, 2)); + tests.checkReferenceLocation(refLocs, 0, gsc_2.uri, 0, 0, 4); + tests.checkReferenceLocation(refLocs, 1, tests.filePathToUri("GscFileReferences.3/scripts/file3.gsc"), 9, 19, 23); + tests.checkReferenceLocation(refLocs, 2, tests.filePathToUri("GscFileReferences.2/scripts/file2.gsc"), 9, 19, 23); + tests.checkReferenceLocation(refLocs, 3, gsc_1.uri, 9, 19, 23); + assert.strictEqual(refLocs.length, 4); // Close text editor await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); @@ -219,56 +374,130 @@ suite('GscFileReferences', () => { // Check case insensitivity of function calls (file paths, function names) test('GscFileReferences - included workspace folders 3', async () => { try { - var gsc = await tests.loadGscFile(['GscFileReferences.3', 'scripts', 'file3.gsc']); + var gsc_1 = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file1.gsc']); + var gsc_2 = await tests.loadGscFile(['GscFileReferences.2', 'scripts', 'file2.gsc']); + var gsc_3 = await tests.loadGscFile(['GscFileReferences.3', 'scripts', 'file3.gsc']); + + var gsc_rep_all_1 = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file_replaced_all.gsc']); + var gsc_rep_all_2 = await tests.loadGscFile(['GscFileReferences.2', 'scripts', 'file_replaced_all.gsc']); + var gsc_rep_all_3 = await tests.loadGscFile(['GscFileReferences.3', 'scripts', 'file_replaced_all.gsc']); + var gsc_rep_1a2_1 = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file_replaced_1_2.gsc']); + var gsc_rep_1a2_2 = await tests.loadGscFile(['GscFileReferences.2', 'scripts', 'file_replaced_1_2.gsc']); - assert.ok(gsc.diagnostics.length === 0); + var gsc_rep_1 = await tests.loadGscFile(['GscFileReferences.1', 'scripts', 'file_replaced_1.gsc']); + + + assert.ok(gsc_3.diagnostics.length === 0); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + var position = new vscode.Position(1, 20); // file_replaced_all + var pathReferences: GscFileAndReferenceState[] = [ // First is the used file + {gscFile: gsc_rep_all_3, referenceState: GscFileReferenceState.LocalFile, referenceWorkspace: gsc_rep_all_3.workspaceFolder!}, + {gscFile: gsc_rep_all_2, referenceState: GscFileReferenceState.IncludedWorkspaceFolder, referenceWorkspace: gsc_rep_all_2.workspaceFolder!}, + {gscFile: gsc_rep_all_1, referenceState: GscFileReferenceState.IncludedWorkspaceFolder, referenceWorkspace: gsc_rep_all_1.workspaceFolder!} + ]; + await tests.checkHoverPath(gsc_3, position, pathReferences, "scripts\\file_replaced_all"); + await tests.checkDefinitionLocation(gsc_3, position, "GscFileReferences.3/scripts/file_replaced_all.gsc"); - var position = new vscode.Position(1, 34); - await tests.checkHoverExternalFunc(gsc, position, "main", [], "GscFileReferences.3/scripts/file_replaced_all.gsc", ""); - await tests.checkDefinitionFunc(gsc, position, "GscFileReferences.3/scripts/file_replaced_all.gsc"); + var position = new vscode.Position(1, 34); // main() + await tests.checkHoverFunction(gsc_3, position, "main", [], "GscFileReferences.3/scripts/file_replaced_all.gsc", ""); + await tests.checkDefinitionLocation(gsc_3, position, "GscFileReferences.3/scripts/file_replaced_all.gsc"); - var position = new vscode.Position(3, 34); - await tests.checkHoverExternalFunc(gsc, position, "main", [], "GscFileReferences.2/scripts/file_replaced_1_2.gsc", "Included via workspace folder settings"); - await tests.checkDefinitionFunc(gsc, position, "GscFileReferences.2/scripts/file_replaced_1_2.gsc"); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - var position = new vscode.Position(5, 32); - await tests.checkHoverExternalFunc(gsc, position, "main", [], "GscFileReferences.1/scripts/file_replaced_1.gsc", "Included via workspace folder settings"); - await tests.checkDefinitionFunc(gsc, position, "GscFileReferences.1/scripts/file_replaced_1.gsc"); + var position = new vscode.Position(3, 20); // file_replaced_1_2 + var pathReferences: GscFileAndReferenceState[] = [ // First is the used file + {gscFile: gsc_rep_1a2_2, referenceState: GscFileReferenceState.IncludedWorkspaceFolder, referenceWorkspace: gsc_rep_1a2_2.workspaceFolder!}, + {gscFile: gsc_rep_1a2_1, referenceState: GscFileReferenceState.IncludedWorkspaceFolder, referenceWorkspace: gsc_rep_1a2_1.workspaceFolder!} + ]; + await tests.checkHoverPath(gsc_3, position, pathReferences, "scripts\\file_replaced_1_2"); + await tests.checkDefinitionLocation(gsc_3, position, "GscFileReferences.2/scripts/file_replaced_1_2.gsc"); + var position = new vscode.Position(3, 34); // main() + await tests.checkHoverFunction(gsc_3, position, "main", [], "GscFileReferences.2/scripts/file_replaced_1_2.gsc", ""); + await tests.checkDefinitionLocation(gsc_3, position, "GscFileReferences.2/scripts/file_replaced_1_2.gsc"); - var position = new vscode.Position(8, 22); - await tests.checkHoverExternalFunc(gsc, position, "main", [], "GscFileReferences.1/scripts/file1.gsc", "Included via workspace folder settings"); - await tests.checkDefinitionFunc(gsc, position, "GscFileReferences.1/scripts/file1.gsc"); - var position = new vscode.Position(9, 22); - await tests.checkHoverExternalFunc(gsc, position, "main", [], "GscFileReferences.2/scripts/file2.gsc", "Included via workspace folder settings"); - await tests.checkDefinitionFunc(gsc, position, "GscFileReferences.2/scripts/file2.gsc"); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - var position = new vscode.Position(10, 22); - var hover = await GscHoverProvider.getHover(gsc, position); - tests.checkHover(hover, GscFunction.generateMarkdownDescription({name: "main", parameters: []}, true, undefined, undefined).value); - var locations = await GscDefinitionProvider.getDefinitionLocations(gsc, position); - tests.checkDefinition(locations, "GscFileReferences.3/scripts/file3.gsc"); + var position = new vscode.Position(5, 20); // file_replaced_1 + var pathReferences: GscFileAndReferenceState[] = [ // First is the used file + {gscFile: gsc_rep_1, referenceState: GscFileReferenceState.IncludedWorkspaceFolder, referenceWorkspace: gsc_rep_1.workspaceFolder!} + ]; + await tests.checkHoverPath(gsc_3, position, pathReferences, "scripts\\file_replaced_1"); + await tests.checkDefinitionLocation(gsc_3, position, "GscFileReferences.1/scripts/file_replaced_1.gsc"); + + var position = new vscode.Position(5, 32); // main() + await tests.checkHoverFunction(gsc_3, position, "main", [], "GscFileReferences.1/scripts/file_replaced_1.gsc", ""); + await tests.checkDefinitionLocation(gsc_3, position, "GscFileReferences.1/scripts/file_replaced_1.gsc"); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // scripts\file1::main(); + var position = new vscode.Position(8, 10); // scripts\file1 + await tests.checkHoverPath(gsc_3, position, [{gscFile: gsc_1, referenceState: GscFileReferenceState.IncludedWorkspaceFolder, referenceWorkspace: gsc_2.workspaceFolder!}], "scripts\\file1"); + await tests.checkDefinitionLocation(gsc_3, position, "GscFileReferences.1/scripts/file1.gsc"); + + var position = new vscode.Position(8, 22); // main() + await tests.checkHoverFunction(gsc_3, position, "main", [], "GscFileReferences.1/scripts/file1.gsc", ""); + await tests.checkDefinitionLocation(gsc_3, position, "GscFileReferences.1/scripts/file1.gsc"); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // scripts\file2::main(); + var position = new vscode.Position(9, 10); // scripts\file2 + await tests.checkHoverPath(gsc_3, position, [{gscFile: gsc_2, referenceState: GscFileReferenceState.IncludedWorkspaceFolder, referenceWorkspace: gsc_2.workspaceFolder!}], "scripts\\file2"); + await tests.checkDefinitionLocation(gsc_3, position, "GscFileReferences.2/scripts/file2.gsc"); + + var position = new vscode.Position(9, 22); // main() + await tests.checkHoverFunction(gsc_3, position, "main", [], "GscFileReferences.2/scripts/file2.gsc", ""); + await tests.checkDefinitionLocation(gsc_3, position, "GscFileReferences.2/scripts/file2.gsc"); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // scripts\file3::main(); + var position = new vscode.Position(10, 10); // scripts\file3 + await tests.checkHoverPath(gsc_3, position, [{gscFile: gsc_3, referenceState: GscFileReferenceState.LocalFile, referenceWorkspace: gsc_3.workspaceFolder!}], "scripts\\file3"); + await tests.checkDefinitionLocation(gsc_3, position, "GscFileReferences.3/scripts/file3.gsc"); + + var position = new vscode.Position(10, 22); // main() + await tests.checkHoverFunction(gsc_3, position, "main", [], "GscFileReferences.3/scripts/file3.gsc", ""); + await tests.checkDefinitionLocation(gsc_3, position, "GscFileReferences.3/scripts/file3.gsc"); + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Write text into document - const document = await vscode.window.showTextDocument(gsc.uri); + const document = await vscode.window.showTextDocument(gsc_3.uri); await document.edit(editBuilder => { editBuilder.insert(new vscode.Position(14, 4), "level."); }); - await tests.waitForDiagnosticsChange(gsc.uri); + await tests.waitForDiagnosticsChange(gsc_3.uri); - var gsc = await tests.loadGscFile(['GscFileReferences.3', 'scripts', 'file3.gsc']); + var gsc_2 = await tests.loadGscFile(['GscFileReferences.3', 'scripts', 'file3.gsc']); - const completions = await GscCompletionItemProvider.getCompletionItems(gsc, new vscode.Position(14, 10), gsc.config.currentGame, undefined); + const completions = await GscCompletionItemProvider.getCompletionItems(gsc_3, new vscode.Position(14, 10), gsc_2.config.currentGame, undefined); - tests.checkCompletions(gsc, completions, 0, "file3", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); - tests.checkCompletions(gsc, completions, 1, "file2", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); - tests.checkCompletions(gsc, completions, 2, "file1", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); + tests.checkCompletions(gsc_3, completions, 0, "file3", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); + tests.checkCompletions(gsc_3, completions, 1, "file2", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); + tests.checkCompletions(gsc_3, completions, 2, "file1", vscode.CompletionItemKind.Field, [GscVariableDefinitionType.Integer], undefined); assert.ok(completions.length === 3); + + + // Check references of "main" function + const refLocs = await GscReferenceProvider.getFunctionReferenceLocations(gsc_3, new vscode.Position(0, 2)); + tests.checkReferenceLocation(refLocs, 0, gsc_3.uri, 0, 0, 4); + tests.checkReferenceLocation(refLocs, 1, tests.filePathToUri("GscFileReferences.3/scripts/file3.gsc"), 10, 19, 23); + tests.checkReferenceLocation(refLocs, 2, tests.filePathToUri("GscFileReferences.2/scripts/file2.gsc"), 10, 19, 23); + tests.checkReferenceLocation(refLocs, 3, gsc_1.uri, 10, 19, 23); + assert.strictEqual(refLocs.length, 4); + // Close text editor await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); diff --git a/src/test/workspace/GscQuickFix.test.ts b/src/test/workspace/GscQuickFix.test.ts index e02d1ea..53d0e5a 100644 --- a/src/test/workspace/GscQuickFix.test.ts +++ b/src/test/workspace/GscQuickFix.test.ts @@ -15,44 +15,6 @@ suite('GscQuickFix', () => { }); - test('func references', async () => { - try { - const gsc = await tests.loadGscFile(['GscQuickFix', 'includedFolders.gsc']); - - // There should be no error - assert.ok(gsc.diagnostics.length === 0); - - // file1::func1(); - const pos1 = new vscode.Position(2, 14); - await tests.checkHoverExternalFunc(gsc, pos1, "func1", [], "GscQuickFix.1/file1.gsc", "Included via workspace folder settings"); - await tests.checkDefinitionFunc(gsc, pos1, "GscQuickFix.1/file1.gsc"); - - // file2::func2(); - const pos2 = new vscode.Position(5, 14); - await tests.checkHoverExternalFunc(gsc, pos2, "func2", [], "GscQuickFix.2/subfolder/file2.gsc", "Included via workspace folder settings"); - await tests.checkDefinitionFunc(gsc, pos2, "GscQuickFix.2/subfolder/file2.gsc"); - - // file3::func3(); - const pos3 = new vscode.Position(8, 14); - await tests.checkHoverExternalFunc(gsc, pos3, "func3", [], "GscQuickFix.3/file3.gsc", "Included via workspace folder settings"); - await tests.checkDefinitionFunc(gsc, pos3, "GscQuickFix.3/file3.gsc"); - - // fileReplaced::funcReplaced(); - const pos4 = new vscode.Position(11, 22); - await tests.checkHoverExternalFunc(gsc, pos4, "funcReplaced", [], "GscQuickFix.3/fileReplaced.gsc", "Included via workspace folder settings"); - await tests.checkDefinitionFunc(gsc, pos4, "GscQuickFix.3/fileReplaced.gsc"); - - // dummy::main(); - const pos5 = new vscode.Position(14, 14); - await tests.checkHoverExternalFunc(gsc, pos5, "main", [], "GscQuickFix/dummy.gsc", ""); - await tests.checkDefinitionFunc(gsc, pos5, "GscQuickFix/dummy.gsc"); - - } catch (error) { - tests.printDebugInfoForError(error); - } - }); - - test('command "add workspace folder" + "game root" + "ignore folder" + "ignore errors"', async () => { try { const gsc = await tests.loadGscFile(['GscQuickFix', 'includedFoldersCommand.gsc']); diff --git a/src/test/workspace/GscRename.1/.vscode/settings.json b/src/test/workspace/GscRename.1/.vscode/settings.json new file mode 100644 index 0000000..771e556 --- /dev/null +++ b/src/test/workspace/GscRename.1/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "gsc.game": "CoD2 MP" +} \ No newline at end of file diff --git a/src/test/workspace/GscRename.1/scripts/file1.gsc b/src/test/workspace/GscRename.1/scripts/file1.gsc new file mode 100644 index 0000000..e9a4368 --- /dev/null +++ b/src/test/workspace/GscRename.1/scripts/file1.gsc @@ -0,0 +1,3 @@ +f() { + scripts\file_all::func_to_be_renamed(); +} \ No newline at end of file diff --git a/src/test/workspace/GscRename.1/scripts/file_all.gsc b/src/test/workspace/GscRename.1/scripts/file_all.gsc new file mode 100644 index 0000000..c212d82 --- /dev/null +++ b/src/test/workspace/GscRename.1/scripts/file_all.gsc @@ -0,0 +1,13 @@ +func_to_be_renamed() { + +} + +f() { + func_to_be_renamed(); + + func = ::func_to_be_renamed; + + thread func_to_be_renamed(); + self thread func_to_be_renamed(); + self func_to_be_renamed(); +} \ No newline at end of file diff --git a/src/test/workspace/GscRename.2/.vscode/settings.json b/src/test/workspace/GscRename.2/.vscode/settings.json new file mode 100644 index 0000000..5d521b4 --- /dev/null +++ b/src/test/workspace/GscRename.2/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "gsc.includedWorkspaceFolders": [ + "GscRename.1" + ], + "gsc.game": "CoD2 MP" +} \ No newline at end of file diff --git a/src/test/workspace/GscRename.2/scripts/file2.gsc b/src/test/workspace/GscRename.2/scripts/file2.gsc new file mode 100644 index 0000000..e9a4368 --- /dev/null +++ b/src/test/workspace/GscRename.2/scripts/file2.gsc @@ -0,0 +1,3 @@ +f() { + scripts\file_all::func_to_be_renamed(); +} \ No newline at end of file diff --git a/src/test/workspace/GscRename.2/scripts/file_all.gsc b/src/test/workspace/GscRename.2/scripts/file_all.gsc new file mode 100644 index 0000000..c212d82 --- /dev/null +++ b/src/test/workspace/GscRename.2/scripts/file_all.gsc @@ -0,0 +1,13 @@ +func_to_be_renamed() { + +} + +f() { + func_to_be_renamed(); + + func = ::func_to_be_renamed; + + thread func_to_be_renamed(); + self thread func_to_be_renamed(); + self func_to_be_renamed(); +} \ No newline at end of file diff --git a/src/test/workspace/GscRename.3/.vscode/settings.json b/src/test/workspace/GscRename.3/.vscode/settings.json new file mode 100644 index 0000000..255ebfb --- /dev/null +++ b/src/test/workspace/GscRename.3/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "gsc.gameRootFolder": "root", + "gsc.includedWorkspaceFolders": [ + "GscRename.1", + "GscRename.2" + ], + "gsc.game": "CoD2 MP" +} \ No newline at end of file diff --git a/src/test/workspace/GscRename.3/root/scripts/file_all.gsc b/src/test/workspace/GscRename.3/root/scripts/file_all.gsc new file mode 100644 index 0000000..c212d82 --- /dev/null +++ b/src/test/workspace/GscRename.3/root/scripts/file_all.gsc @@ -0,0 +1,13 @@ +func_to_be_renamed() { + +} + +f() { + func_to_be_renamed(); + + func = ::func_to_be_renamed; + + thread func_to_be_renamed(); + self thread func_to_be_renamed(); + self func_to_be_renamed(); +} \ No newline at end of file diff --git a/src/test/workspace/GscRename.3/root/scripts/rename.gsc b/src/test/workspace/GscRename.3/root/scripts/rename.gsc new file mode 100644 index 0000000..449301a --- /dev/null +++ b/src/test/workspace/GscRename.3/root/scripts/rename.gsc @@ -0,0 +1,14 @@ +main() { + scripts\file_all::func_to_be_renamed(); +} + + +f() { + scripts\file_all::func_to_be_renamed(); + + func = scripts\file_all::func_to_be_renamed; + + thread scripts\file_all::func_to_be_renamed(); + self thread scripts\file_all::func_to_be_renamed(); + self scripts\file_all::func_to_be_renamed(); +} \ No newline at end of file diff --git a/src/test/workspace/vscode-cod-gsc-tests.code-workspace b/src/test/workspace/vscode-cod-gsc-tests.code-workspace index d99ea7b..8a99645 100644 --- a/src/test/workspace/vscode-cod-gsc-tests.code-workspace +++ b/src/test/workspace/vscode-cod-gsc-tests.code-workspace @@ -45,16 +45,32 @@ "path": "GscCompletionItemProvider.NonIncludedFolder" }, { + "name": "GscFiles", "path": "GscFiles" }, { + "name": "GscFileReferences.1", "path": "GscFileReferences.1" }, { + "name": "GscFileReferences.2", "path": "GscFileReferences.2" }, { + "name": "GscFileReferences.3", "path": "GscFileReferences.3" + }, + { + "name": "GscRename.1", + "path": "GscRename.1" + }, + { + "name": "GscRename.2", + "path": "GscRename.2" + }, + { + "name": "GscRename.3", + "path": "GscRename.3" } ] } \ No newline at end of file