Skip to content

Commit

Permalink
Fixed unnecessary file parsing, improved exceptions handling, logging…
Browse files Browse the repository at this point in the history
… data into 'Output' tab, internal notifying of GscFiles, internal storage of diagnostics for files
  • Loading branch information
eyza-cod2 committed Sep 21, 2024
1 parent f0b1233 commit 3924803
Show file tree
Hide file tree
Showing 17 changed files with 657 additions and 452 deletions.
25 changes: 15 additions & 10 deletions src/Gsc.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import * as vscode from 'vscode';
import { GscFiles } from './GscFiles';
import { GscCompletionItemProvider } from './GscCompletionItemProvider';
import { GscCompletionItemProvider } from './GscCompletionItemProvider';
import { GscSemanticTokensProvider } from './GscSemanticTokensProvider';
import { GscDiagnosticsCollection } from './GscDiagnosticsCollection';
import { GscDefinitionProvider } from './GscDefinitionProvider';
import { GscHoverProvider } from './GscHoverProvider';
import { GscStatusBar } from './GscStatusBar';
import { GscConfig } from './GscConfig';
import { GscCodeActionProvider } from './GscCodeActionProvider';
import { Issues } from './Issues';


export class Gsc {
Expand All @@ -19,15 +20,19 @@ export class Gsc {
console.log("------------------------------------------------------------");

// Register events
await GscConfig.activate(context);
await GscStatusBar.activate(context);
await GscFiles.activate(context);
await GscDiagnosticsCollection.activate(context);
await GscCodeActionProvider.activate(context);
await GscSemanticTokensProvider.activate(context);
await GscCompletionItemProvider.activate(context);
await GscDefinitionProvider.activate(context);
await GscHoverProvider.activate(context);
try {
await GscConfig.activate(context);
await GscStatusBar.activate(context);
await GscFiles.activate(context);
await GscDiagnosticsCollection.activate(context);
await GscCodeActionProvider.activate(context);
await GscSemanticTokensProvider.activate(context);
await GscCompletionItemProvider.activate(context);
await GscDefinitionProvider.activate(context);
await GscHoverProvider.activate(context);
} catch (error) {
Issues.handleError(error);
}
}

static deactivate() {
Expand Down
138 changes: 86 additions & 52 deletions src/GscCodeActionProvider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as vscode from 'vscode';
import { ConfigErrorDiagnostics, GscConfig } from './GscConfig';
import * as path from 'path';
import { Issues } from './Issues';

export class GscCodeActionProvider implements vscode.CodeActionProvider {

Expand All @@ -10,84 +11,117 @@ export class GscCodeActionProvider implements vscode.CodeActionProvider {
});

context.subscriptions.push(vscode.commands.registerCommand('gsc.addFolderForReferences', async (workspaceUri: vscode.Uri) => {
// Prompt the user to select a folder
const folderUri = await vscode.window.showOpenDialog({
canSelectFolders: true,
canSelectFiles: false,
canSelectMany: false,
openLabel: 'Add selected folder to Workspace'
});

if (folderUri && folderUri[0]) {
const uri = folderUri[0];

// Get folder name from the uri
const folderName = path.basename(uri.fsPath);
await GscConfig.addIncludedWorkspaceFolders(workspaceUri, folderName);

// Add the selected folder to the workspace
vscode.workspace.updateWorkspaceFolders(
0, //vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders.length : 0,
null,
{ uri }
);

void vscode.window.showInformationMessage(`Added folder to workspace: ${uri.fsPath}`);
try {
// Prompt the user to select a folder
const folderUri = await vscode.window.showOpenDialog({
canSelectFolders: true,
canSelectFiles: false,
canSelectMany: false,
openLabel: 'Add selected folder to Workspace'
});

if (folderUri && folderUri[0]) {
const uri = folderUri[0];

// Get folder name from the uri
const folderName = path.basename(uri.fsPath);
await GscConfig.addIncludedWorkspaceFolders(workspaceUri, folderName);

// Add the selected folder to the workspace
vscode.workspace.updateWorkspaceFolders(
0, //vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders.length : 0,
null,
{ uri }
);

void vscode.window.showInformationMessage(`Added folder to workspace: ${uri.fsPath}`);
}
} catch (error) {
Issues.handleError(error);
}
}));

context.subscriptions.push(vscode.commands.registerCommand('gsc.disableErrorDiagnostics', async (workspaceUri: vscode.Uri, workspaceFolderName: string) => {
await GscConfig.updateErrorDiagnostics(workspaceUri, ConfigErrorDiagnostics.Disable);
void vscode.window.showInformationMessage(`Disabled error diagnostic for workspace folder '${workspaceFolderName}'`);
try {
await GscConfig.updateErrorDiagnostics(workspaceUri, ConfigErrorDiagnostics.Disable);
void vscode.window.showInformationMessage(`Disabled error diagnostic for workspace folder '${workspaceFolderName}'`);
} catch (error) {
Issues.handleError(error);
}
}));

context.subscriptions.push(vscode.commands.registerCommand('gsc.addFunctionNameIntoIgnored', async (workspaceUri: vscode.Uri, functionName: string) => {
await GscConfig.addIgnoredFunctionName(workspaceUri, functionName);
void vscode.window.showInformationMessage(`Added '${functionName}' to ignored function names.`);
try {
await GscConfig.addIgnoredFunctionName(workspaceUri, functionName);
void vscode.window.showInformationMessage(`Added '${functionName}' to ignored function names.`);
} catch (error) {
Issues.handleError(error);
}
}));

context.subscriptions.push(vscode.commands.registerCommand('gsc.addFilePathIntoIgnored', async (workspaceUri: vscode.Uri, filePath: string) => {
await GscConfig.addIgnoredFilePath(workspaceUri, filePath);
void vscode.window.showInformationMessage(`Added '${filePath}' to ignored file paths.`);
try {
await GscConfig.addIgnoredFilePath(workspaceUri, filePath);
void vscode.window.showInformationMessage(`Added '${filePath}' to ignored file paths.`);
} catch (error) {
Issues.handleError(error);
}
}));

context.subscriptions.push(vscode.commands.registerCommand('gsc.addAllMissingFilePathsIntoIgnored', async (workspaceUri: vscode.Uri) => {
const allDiagnostics = vscode.languages.getDiagnostics();
const paths = new Set<string>();
for (const [uri, diagnostics] of allDiagnostics) {
for (const diagnostic of diagnostics) {
if (typeof diagnostic.code !== "string") {
continue;
}
const code = diagnostic.code.toString();
if (code.startsWith("unknown_file_path_")) {
const filePath = diagnostic.code.substring("unknown_file_path_".length);
paths.add(filePath);
try {
const allDiagnostics = vscode.languages.getDiagnostics();
const paths = new Set<string>();
for (const [uri, diagnostics] of allDiagnostics) {
for (const diagnostic of diagnostics) {
if (typeof diagnostic.code !== "string") {
continue;
}
const code = diagnostic.code.toString();
if (code.startsWith("unknown_file_path_")) {
const filePath = diagnostic.code.substring("unknown_file_path_".length);
paths.add(filePath);
}
}
}
};
await GscConfig.addIgnoredFilePath(workspaceUri, [...paths]);
void vscode.window.showInformationMessage(`Added all missing files to ignored file paths.`);
};
await GscConfig.addIgnoredFilePath(workspaceUri, [...paths]);
void vscode.window.showInformationMessage(`Added all missing files to ignored file paths.`);
} catch (error) {
Issues.handleError(error);
}
}));

context.subscriptions.push(vscode.commands.registerCommand('gsc.changeRootFolder', async (workspaceUri: vscode.Uri, rootFolder: string) => {
await GscConfig.changeRootFolder(workspaceUri, rootFolder);
void vscode.window.showInformationMessage(`Changed root folder to '${rootFolder}'.`);
try {
await GscConfig.changeRootFolder(workspaceUri, rootFolder);
void vscode.window.showInformationMessage(`Changed root folder to '${rootFolder}'.`);
} catch (error) {
Issues.handleError(error);
}
}));

context.subscriptions.push(vscode.commands.registerCommand('gsc.addIncludedWorkspaceFolders', async (workspace: vscode.WorkspaceFolder, otherWorkspace: vscode.WorkspaceFolder, rootFolder?: string) => {
if (rootFolder) {
await GscConfig.changeRootFolder(otherWorkspace.uri, rootFolder);
void vscode.window.showInformationMessage(`Changed root folder to '${rootFolder}'.`);
try {
if (rootFolder) {
await GscConfig.changeRootFolder(otherWorkspace.uri, rootFolder);
void vscode.window.showInformationMessage(`Changed root folder to '${rootFolder}'.`);
}
await GscConfig.addIncludedWorkspaceFolders(workspace.uri, otherWorkspace.name);
void vscode.window.showInformationMessage(`Added workspace folder '${otherWorkspace.name}' for file references.`);
} catch (error) {
Issues.handleError(error);
}
await GscConfig.addIncludedWorkspaceFolders(workspace.uri, otherWorkspace.name);
void vscode.window.showInformationMessage(`Added workspace folder '${otherWorkspace.name}' for file references.`);
}));
}


async provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken): Promise<vscode.CodeAction[]> {
return GscCodeActionProvider.getCodeActions(document.uri, context.diagnostics);
try {
return GscCodeActionProvider.getCodeActions(document.uri, context.diagnostics);
} catch (error) {
Issues.handleError(error);
return [];
}
}


Expand Down
19 changes: 12 additions & 7 deletions src/GscCompletionItemProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CodFunctions } from './CodFunctions';
import { GscConfig, GscGame } from './GscConfig';
import { GscFunctions, GscVariableDefinition } from './GscFunctions';
import { LoggerOutput } from './LoggerOutput';
import { Issues } from './Issues';

export interface CompletionConfig {
variableItems: boolean;
Expand All @@ -23,17 +24,21 @@ export class GscCompletionItemProvider implements vscode.CompletionItemProvider
async provideCompletionItems( document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken
): Promise<vscode.CompletionItem[] | vscode.CompletionList | undefined>
{
// This function is called when user types a character or presses ctrl+space
try {
// This function is called when user types a character or presses ctrl+space

// Get parsed file
const gscFile = await GscFiles.getFileData(document.uri);

// Get parsed file
const gscFile = await GscFiles.getFileData(document.uri);
const currentGame = GscConfig.getSelectedGame(document.uri);

const currentGame = GscConfig.getSelectedGame(document.uri);
const items = await GscCompletionItemProvider.getCompletionItems(gscFile, position, currentGame, undefined, document.uri);

const items = await GscCompletionItemProvider.getCompletionItems(gscFile, position, currentGame, undefined, document.uri);

return items;
return items;
} catch (error) {
Issues.handleError(error);
return undefined;
}
}


Expand Down
54 changes: 54 additions & 0 deletions src/GscConfig.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as vscode from 'vscode';
import { LoggerOutput } from './LoggerOutput';
import { Issues } from './Issues';

// These must match with package.json settings
export enum GscGame {
Expand All @@ -22,15 +24,60 @@ export type GscGameRootFolder = {
}


type ConfigChangeHandler = () => Promise<void> | void;


export class GscConfig {

public static game: GscGame = GscGame.UniversalGame;

private static configChangeSubscribers: ConfigChangeHandler[] = [];


static async activate(context: vscode.ExtensionContext) {
vscode.workspace.onDidChangeConfiguration((e) => this.onDidChangeConfiguration(e), null, context.subscriptions);
}


/**
* Handle vscode configuration change event
*/
private static async onDidChangeConfiguration(e: vscode.ConfigurationChangeEvent) {
if (e.affectsConfiguration('gsc')) {
LoggerOutput.log("[GscConfig] GSC configuration changed.");
await GscConfig.emitConfigChange();
}
}


/**
* Subscribe to configuration changes. The handler will be called whenever the configuration changes. Subscribers are called in the order they were added.
* @param handler
*/
public static onDidConfigChange(handler: ConfigChangeHandler): void {
this.configChangeSubscribers.push(handler);
}



/**
* Emit a configuration change event. This will call all subscribers in the order they were added.
*/
private static async emitConfigChange(): Promise<void> {
for (const handler of this.configChangeSubscribers) {
try {
const result = handler();
if (result instanceof Promise) {
await result;
}
} catch (error) {
Issues.handleError(error);
}
}
}



/**
* Get path to game root folder. By default the game root folder is the workspace path. It can be changed in settings. Each folder can also have custom settings.
*/
Expand All @@ -54,6 +101,7 @@ export class GscConfig {


public static changeRootFolder(uri: vscode.Uri, rootFolder: string) {
LoggerOutput.log("[GscConfig] Changing game root folder to: " + rootFolder, vscode.workspace.asRelativePath(uri));
const config = vscode.workspace.getConfiguration('gsc', uri);
return config.update('gameRootFolder', rootFolder, vscode.ConfigurationTarget.WorkspaceFolder);
}
Expand All @@ -69,6 +117,7 @@ export class GscConfig {
return ignoredFunctionNames;
}
public static addIgnoredFunctionName(uri: vscode.Uri, value: string) {
LoggerOutput.log("[GscConfig] Adding ignored function name: " + value, vscode.workspace.asRelativePath(uri));
const config = vscode.workspace.getConfiguration('gsc', uri);
const ignoredFunctionNames: string[] = config.get('ignoredFunctionNames', []);
ignoredFunctionNames.push(value);
Expand All @@ -86,6 +135,7 @@ export class GscConfig {
return ignoredFunctionNames;
}
public static addIgnoredFilePath(uri: vscode.Uri, value: string | string[]) {
LoggerOutput.log("[GscConfig] Adding ignored file path: " + value, vscode.workspace.asRelativePath(uri));
const config = vscode.workspace.getConfiguration('gsc', uri);
const ignoredFilePaths: string[] = config.get('ignoredFilePaths', []);
if (typeof value === 'string') {
Expand All @@ -105,6 +155,7 @@ export class GscConfig {
return GscConfig.errorDiagnosticsStringToEnum(selectedOption, ConfigErrorDiagnostics.Enable);
}
public static async updateErrorDiagnostics(uri: vscode.Uri, value: ConfigErrorDiagnostics) {
LoggerOutput.log("[GscConfig] Changing error diagnostics to: " + value, vscode.workspace.asRelativePath(uri));
// Load ignored function names
const config = vscode.workspace.getConfiguration('gsc', uri);
await config.update("errorDiagnostics", value, vscode.ConfigurationTarget.WorkspaceFolder);
Expand All @@ -131,6 +182,8 @@ export class GscConfig {
return includedWorkspaceFolders;
}
public static addIncludedWorkspaceFolders(uri: vscode.Uri, value: string | string[]) {
const valueStr = (typeof value === 'string') ? value : value.join(", ");
LoggerOutput.log("[GscConfig] Adding included workspace folder: " + valueStr, vscode.workspace.asRelativePath(uri));
const config = vscode.workspace.getConfiguration('gsc', uri);
const includedWorkspaceFolders: string[] = config.get('includedWorkspaceFolders', []);
if (typeof value === 'string') {
Expand Down Expand Up @@ -168,6 +221,7 @@ export class GscConfig {
}

public static async updateSelectedGame(uri: vscode.Uri, game: GscGame) {
LoggerOutput.log("[GscConfig] Changing selected game to: " + game, vscode.workspace.asRelativePath(uri));
// Check if the URI is part of the workspace
if (!vscode.workspace.getWorkspaceFolder(uri)) {
throw new Error("The file is not part of the workspace.");
Expand Down
Loading

0 comments on commit 3924803

Please sign in to comment.