Skip to content

Commit

Permalink
Added definition provider and hover provider for GSC paths
Browse files Browse the repository at this point in the history
  • Loading branch information
eyza-cod2 committed Oct 30, 2024
1 parent 2b3c26e commit 815a59f
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 37 deletions.
69 changes: 49 additions & 20 deletions src/GscDefinitionProvider.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as vscode from 'vscode';
import { GscFiles } from './GscFiles';
import { GscFile } from './GscFile';
import { GroupType } from './GscFileParser';
import { GroupType, GscGroup } from './GscFileParser';
import { GscFunctions } from './GscFunctions';
import { Issues } from './Issues';
import { LoggerOutput } from './LoggerOutput';
Expand All @@ -24,7 +24,7 @@ export class GscDefinitionProvider implements vscode.DefinitionProvider {
// Get parsed file
const gscFile = await GscFiles.getFileData(document.uri, false, "provide definition");

const locations = await GscDefinitionProvider.getFunctionDefinitionLocations(gscFile, position);
const locations = await GscDefinitionProvider.getDefinitionLocations(gscFile, position);

return locations;
} catch (error) {
Expand All @@ -34,16 +34,8 @@ export class GscDefinitionProvider implements vscode.DefinitionProvider {
}


/**
* This function finds definitions of function names in current file, included files and in external files
* @example
* function(1, 2);
* function_included();
* _tests\definition_file::function_file();
* @returns
*/
public static async getFunctionDefinitionLocations(gscFile: GscFile, position: vscode.Position): Promise<vscode.Location[]> {
const locations: vscode.Location[] = [];
public static async getDefinitionLocations(gscFile: GscFile, position: vscode.Position): Promise<vscode.Location[]> {
var locations: vscode.Location[] = [];

const gscData = gscFile.data;

Expand All @@ -53,14 +45,14 @@ export class GscDefinitionProvider implements vscode.DefinitionProvider {
return locations;
}

if (groupAtCursor.type === GroupType.FunctionName) {
const funcInfo = groupAtCursor.getFunctionReferenceInfo();
if (funcInfo !== undefined) {
const funcDefs = GscFunctions.getFunctionDefinitions(gscFile, funcInfo);
if (funcDefs !== undefined && funcDefs.length > 0) {
locations.push(new vscode.Location(funcDefs[0].uri, funcDefs[0].func.rangeFunctionName));
}
}
switch (groupAtCursor.type) {
case GroupType.FunctionName:
locations = await this.getFunctionDefinitionLocations(gscFile, groupAtCursor);
break;

case GroupType.Path:
locations = await this.getPathDefinitionLocations(gscFile, groupAtCursor);
break;
}

//console.log(groupAtCursor.toString());
Expand All @@ -70,4 +62,41 @@ export class GscDefinitionProvider implements vscode.DefinitionProvider {
return locations;
}


/**
* This function finds definitions of function names in current file, included files and in external files
* @example
* function(1, 2);
* function_included();
* _tests\definition_file::function_file();
* @returns
*/
private static async getFunctionDefinitionLocations(gscFile: GscFile, groupAtCursor: GscGroup): Promise<vscode.Location[]> {
const locations: vscode.Location[] = [];

const funcInfo = groupAtCursor.getFunctionReferenceInfo();
if (funcInfo !== undefined) {
const funcDefs = GscFunctions.getFunctionDefinitions(gscFile, funcInfo);
if (funcDefs !== undefined && funcDefs.length > 0) {
locations.push(new vscode.Location(funcDefs[0].uri, funcDefs[0].func.rangeFunctionName));
}
}

return locations;
}


/** This function finds referenced files by game path */
private static async getPathDefinitionLocations(gscFile: GscFile, groupAtCursor: GscGroup): Promise<vscode.Location[]> {
const locations: vscode.Location[] = [];

const path = groupAtCursor.getTokensAsString();
const fileReference = GscFiles.getReferencedFileForFile(gscFile, path);
if (fileReference !== undefined && fileReference.gscFile !== undefined) {
locations.push(new vscode.Location(fileReference.gscFile.uri, fileReference.gscFile.data.root.getRange()));
}

return locations;
}

}
23 changes: 19 additions & 4 deletions src/GscHoverProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,14 @@ export class GscHoverProvider implements vscode.HoverProvider {


public static async getHover(gscFile: GscFile, position: vscode.Position): Promise<vscode.Hover | undefined> {
let hoverRange: vscode.Range | undefined = undefined;
let markdown = new vscode.MarkdownString();
markdown.isTrusted = true; // enable HTML tags

const gscData = gscFile.data;
const uri = gscFile.uri;
const isUniversalGame = GscConfig.isUniversalGame(gscFile.config.currentGame);
const errorDiagnosticsDisabled = gscFile.config.errorDiagnostics === ConfigErrorDiagnostics.Disable;

// Get group before cursor
var groupAtCursor = gscData.root.findGroupOnLeftAtPosition(position);
Expand All @@ -52,9 +55,6 @@ export class GscHoverProvider implements vscode.HoverProvider {
const funcInfo = groupAtCursor.getFunctionReferenceInfo();
if (funcInfo !== undefined) {

const isUniversalGame = GscConfig.isUniversalGame(gscFile.config.currentGame);
const errorDiagnosticsDisabled = gscFile.config.errorDiagnostics === ConfigErrorDiagnostics.Disable;

const res = GscFunctions.getFunctionReferenceState({name: funcInfo.name, path: funcInfo.path}, gscFile);

switch (res.state as GscFunctionState) {
Expand Down Expand Up @@ -155,12 +155,27 @@ 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) + "`");
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`);
}
}

}

if (markdown.value === "") {
return undefined;
} else {
return new vscode.Hover(markdown);
return new vscode.Hover(markdown, hoverRange);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/test/Tests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export function checkDefinition(locations: vscode.Location[], expectedFileEnd: s
}

export async function checkDefinitionFunc(gscFile: GscFile, pos: vscode.Position, pathUri: string) {
const locations = await GscDefinitionProvider.getFunctionDefinitionLocations(gscFile, pos);
const locations = await GscDefinitionProvider.getDefinitionLocations(gscFile, pos);
checkDefinition(locations, pathUri);
}

Expand Down
2 changes: 1 addition & 1 deletion src/test/workspace/GscAll_CoD2MP.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ suite('GscAll.CoD2MP', () => {
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);

const locations1 = await GscDefinitionProvider.getFunctionDefinitionLocations(gsc, new vscode.Position(3, 6));
const locations1 = await GscDefinitionProvider.getDefinitionLocations(gsc, new vscode.Position(3, 6));
tests.checkDefinition(locations1, "GscAll.CoD2MP/scripts/ItselfInclude.gsc");


Expand Down
2 changes: 1 addition & 1 deletion src/test/workspace/GscAll_UniversalGame.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ suite('GscAll.UniversalGame', () => {
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);

const locations1 = await GscDefinitionProvider.getFunctionDefinitionLocations(gsc, new vscode.Position(3, 6));
const locations1 = await GscDefinitionProvider.getDefinitionLocations(gsc, new vscode.Position(3, 6));
tests.checkDefinition(locations1, "GscAll.UniversalGame/scripts/ItselfInclude.gsc");


Expand Down
31 changes: 21 additions & 10 deletions src/test/workspace/GscFileReferences.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,45 +25,56 @@ suite('GscFileReferences', () => {
// There should be no error - everything is case insensitive
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) + "`");

// 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);
//checkHover(hover1, "\n```\nfuncName()\n```\nFile: ```GscFileReferences.1/LowerUpperCaseFolder/FunctionReferencesFile.gsc```");
const locations1 = await GscDefinitionProvider.getFunctionDefinitionLocations(gsc, new vscode.Position(5, 57));
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) + "`");
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);
const locations2 = await GscDefinitionProvider.getFunctionDefinitionLocations(gsc, new vscode.Position(8, 57));
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) + "`");
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);
const locations3 = await GscDefinitionProvider.getFunctionDefinitionLocations(gsc, new vscode.Position(11, 57));
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) + "`");
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);
const locations4 = await GscDefinitionProvider.getFunctionDefinitionLocations(gsc, new vscode.Position(14, 57));
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) + "`");
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);
const locations5 = await GscDefinitionProvider.getFunctionDefinitionLocations(gsc, new vscode.Position(17, 8));
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);
const locations6 = await GscDefinitionProvider.getFunctionDefinitionLocations(gsc, new vscode.Position(20, 8));
const locations6 = await GscDefinitionProvider.getDefinitionLocations(gsc, new vscode.Position(20, 8));
tests.checkDefinition(locations6, "GscFileReferences.1/LowerUpperCase.gsc");

Issues.checkForNewError();
Expand Down Expand Up @@ -99,7 +110,7 @@ suite('GscFileReferences', () => {
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.getFunctionDefinitionLocations(gsc, position);
var locations = await GscDefinitionProvider.getDefinitionLocations(gsc, position);
tests.checkDefinition(locations, "GscFileReferences.1/scripts/file1.gsc");


Expand Down Expand Up @@ -171,7 +182,7 @@ suite('GscFileReferences', () => {
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.getFunctionDefinitionLocations(gsc, position);
var locations = await GscDefinitionProvider.getDefinitionLocations(gsc, position);
tests.checkDefinition(locations, "GscFileReferences.2/scripts/file2.gsc");


Expand Down Expand Up @@ -238,7 +249,7 @@ suite('GscFileReferences', () => {
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.getFunctionDefinitionLocations(gsc, position);
var locations = await GscDefinitionProvider.getDefinitionLocations(gsc, position);
tests.checkDefinition(locations, "GscFileReferences.3/scripts/file3.gsc");


Expand Down

0 comments on commit 815a59f

Please sign in to comment.