Skip to content

Commit

Permalink
Adds the option diagnosticMode.
Browse files Browse the repository at this point in the history
This option allows to choose whether to diagnose the open files
or all files in the workspace.

Fixed #149
  • Loading branch information
LuqueDaniel committed Mar 14, 2023
1 parent 056cd7f commit d73f761
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 16 deletions.
13 changes: 13 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,19 @@
"default": true,
"description": "Show Automatic Images in the displayable auto-completion list. If not checked (false), only images defined in the script will be shown. If checked (true), both script-defined images and images detected in the images folders will be shown."
},
"renpy.diagnostics.diagnosticMode": {
"type": "string",
"default": "openFilesOnly",
"enum": [
"openFilesOnly",
"workspace"
],
"enumDescriptions": [
"Only diagnoses open files.",
"Diagnose all Ren'Py files in the workspace. This mode applies recursive expressions that can be resource-intensive in projects with a large codebase."
],
"description": "Select whether to analyze all Ren'Py files in the workspace or only open files (default)."
},
"renpy.diagnostics.warnOnObsoleteMethods": {
"type": "boolean",
"default": true,
Expand Down
80 changes: 64 additions & 16 deletions src/diagnostics.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Diagnostics (warnings and errors)
"use strict";

import { commands, Diagnostic, DiagnosticCollection, DiagnosticSeverity, ExtensionContext, languages, Range, TextDocument, window, workspace } from "vscode";
import { commands, Diagnostic, DiagnosticCollection, DiagnosticSeverity, Disposable, ExtensionContext, FileType, languages, Range, TextDocument, Uri, window, workspace } from "vscode";
import { NavigationData } from "./navigation-data";
import { getAllOpenTabInputTextUri } from "./utilities/functions";
import { extractFilename } from "./workspace";

// Renpy Store Variables (https://www.renpy.org/doc/html/store_variables.html)
Expand Down Expand Up @@ -52,8 +53,10 @@ const rxStoreCheck = /\s+store\.(\w+)[^a-zA-Z_]?/g;
const rxTabCheck = /^(\t+)/g;
const rsComparisonCheck = /\s+(if|while)\s+(\w+)\s*(=)\s*(\w+)\s*/g;

const diagnosticModeEvents: Disposable[] = [];

/**
* Set up diagnostics
* Init diagnostics
* @param context extension context
*/
export function diagnosticsInit(context: ExtensionContext) {
Expand All @@ -68,7 +71,19 @@ export function diagnosticsInit(context: ExtensionContext) {
});
context.subscriptions.push(refreshDiagnosticsCommand);

subscribeToDocumentChanges(context, diagnostics);
// Listen to diagnosticMode changes
context.subscriptions.push(
workspace.onDidChangeConfiguration((e) => {
if (e.affectsConfiguration("renpy.diagnostics.diagnosticMode")) {
updateDiagnosticMode(context, diagnostics);
}
})
);

const onDidChangeTextDocument = workspace.onDidChangeTextDocument((doc) => refreshDiagnostics(doc.document, diagnostics));
context.subscriptions.push(onDidChangeTextDocument);

updateDiagnosticMode(context, diagnostics);
}

/**
Expand Down Expand Up @@ -186,22 +201,55 @@ function refreshDiagnostics(doc: TextDocument, diagnosticCollection: DiagnosticC
diagnosticCollection.set(doc.uri, diagnostics);
}

function subscribeToDocumentChanges(context: ExtensionContext, diagnostics: DiagnosticCollection): void {
if (window.activeTextEditor) {
refreshDiagnostics(window.activeTextEditor.document, diagnostics);
}
function refreshOpenDocuments(diagnosticCollection: DiagnosticCollection) {
diagnosticCollection.clear();
const tabInputTextUris = getAllOpenTabInputTextUri();
tabInputTextUris.forEach((uri) => {
diagnoseFromUri(uri, diagnosticCollection);
});
}

context.subscriptions.push(
window.onDidChangeActiveTextEditor((editor) => {
if (editor) {
refreshDiagnostics(editor.document, diagnostics);
}
})
);
function diagnoseFromUri(uri: Uri, diagnosticCollection: DiagnosticCollection) {
workspace.fs.stat(uri).then((stat) => {
if (stat.type === FileType.File) {
workspace.openTextDocument(uri).then((document) => refreshDiagnostics(document, diagnosticCollection));
}
});
}

context.subscriptions.push(workspace.onDidChangeTextDocument((e) => refreshDiagnostics(e.document, diagnostics)));
function onDeleteFromWorkspace(uri: Uri, diagnosticCollection: DiagnosticCollection) {
diagnosticCollection.forEach((diagnosticUri) => {
if (diagnosticUri.fsPath.startsWith(uri.fsPath)) {
diagnosticCollection.delete(diagnosticUri);
}
});
}

context.subscriptions.push(workspace.onDidCloseTextDocument((doc) => diagnostics.delete(doc.uri)));
function updateDiagnosticMode(context: ExtensionContext, diagnosticCollection: DiagnosticCollection): void {
diagnosticModeEvents.forEach((e) => e.dispose());
if (workspace.getConfiguration("renpy.diagnostics").get<string>("diagnosticMode") === "openFilesOnly") {
context.subscriptions.push(window.onDidChangeVisibleTextEditors(() => refreshOpenDocuments(diagnosticCollection), undefined, diagnosticModeEvents));
// There is no guarantee that this event fires when an editor tab is closed
context.subscriptions.push(
workspace.onDidCloseTextDocument(
(doc) => {
if (diagnosticCollection.has(doc.uri)) {
diagnosticCollection.delete(doc.uri);
}
},
undefined,
diagnosticModeEvents
)
);
refreshOpenDocuments(diagnosticCollection);
} else {
const fsWatcher = workspace.createFileSystemWatcher("**/*");
diagnosticModeEvents.push(fsWatcher);
fsWatcher.onDidChange((uri) => diagnoseFromUri(uri, diagnosticCollection));
fsWatcher.onDidCreate((uri) => diagnoseFromUri(uri, diagnosticCollection));
fsWatcher.onDidDelete((uri) => onDeleteFromWorkspace(uri, diagnosticCollection));
workspace.findFiles("**/*.rpy").then((uris) => uris.forEach((uri) => diagnoseFromUri(uri, diagnosticCollection)));
}
}

function checkObsoleteMethods(diagnostics: Diagnostic[], line: string, lineIndex: number) {
Expand Down
17 changes: 17 additions & 0 deletions src/utilities/functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { TabInputText, Uri, window } from "vscode";

/**
* Gets the URIs of the tabs opened in the editor whose input is of type TabInputText.
* @returns An array of URIs
*/
export function getAllOpenTabInputTextUri(): Uri[] {
const uris: Uri[] = [];
const tabGroups = window.tabGroups.all;
const tabs = tabGroups.flatMap((group) => group.tabs.map((tab) => tab));
tabs.forEach((tab) => {
if (tab.input instanceof TabInputText) {
uris.push(tab.input.uri);
}
});
return uris;
}

0 comments on commit d73f761

Please sign in to comment.