Skip to content

Commit 7021943

Browse files
authored
Added logger that can also output logs for the end user (#336)
* Added logger that can also output logs for the end user * Bump version to 2.3.2
1 parent 83d2731 commit 7021943

10 files changed

+341
-68
lines changed

package.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "languague-renpy",
33
"displayName": "Ren'Py Language",
44
"description": "Adds rich support for the Ren'Py programming language to Visual Studio Code.",
5-
"version": "2.3.1",
5+
"version": "2.3.2",
66
"publisher": "LuqueDaniel",
77
"license": "MIT",
88
"homepage": "https://github.com/LuqueDaniel/vscode-language-renpy",
@@ -60,6 +60,14 @@
6060
"light": "./renpy.svg",
6161
"dark": "./renpy.svg"
6262
}
63+
},
64+
{
65+
"id": "renpy-log",
66+
"aliases": [
67+
"Ren'Py Log"
68+
],
69+
"configuration": "./language-configuration.json",
70+
"scopeName": "text.renpy-log"
6371
}
6472
],
6573
"grammars": [
@@ -79,6 +87,11 @@
7987
{
8088
"scopeName": "source.renpy.python",
8189
"path": "./syntaxes/renpy.python.tmLanguage.json"
90+
},
91+
{
92+
"language": "renpy-log",
93+
"scopeName": "text.renpy-log",
94+
"path": "./syntaxes/renpy.log.tmLanguage.json"
8295
}
8396
],
8497
"snippets": [

src/decorator.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ConfigurationTarget, workspace } from "vscode";
22
import util = require("util");
33
import { IEquatable, ValueEqualsSet } from "./utilities/hashset";
4+
import { LogLevel, logMessage } from "./logger";
45

56
export class TextMateRule implements IEquatable<TextMateRule> {
67
public scope: string | string[];
@@ -63,10 +64,10 @@ export function injectCustomTextmateTokens(rules: ValueEqualsSet<TextMateRule>)
6364
tokenColorCustomizations.textMateRules = newRules.toArray();
6465
tokensConfig.update("tokenColorCustomizations", tokenColorCustomizations, ConfigurationTarget.Workspace).then(
6566
() => {
66-
console.log("Successfully updated the tokenColorCustomizations config");
67+
logMessage(LogLevel.Info, "Successfully updated the tokenColorCustomizations config");
6768
},
6869
(reason) => {
69-
console.error("Failed to update the tokenColorCustomizations config! : " + reason);
70+
logMessage(LogLevel.Error, "Failed to update the tokenColorCustomizations config! : " + reason);
7071
}
7172
);
7273
}

src/extension.ts

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,18 @@ import { findAllReferences } from "./references";
5454
import { registerDebugDecorator, unregisterDebugDecorator } from "./tokenizer/debug-decorator";
5555
import { clearTokenCache } from "./tokenizer/tokenizer";
5656
import { getSignatureHelp } from "./signature";
57+
import { LogCategory, LogLevel, logCatMessage, logMessage, logToast } from "./logger";
5758

5859
const selector: DocumentSelector = { scheme: "file", language: "renpy" };
5960
let myStatusBarItem: StatusBarItem;
6061

6162
export async function activate(context: ExtensionContext): Promise<void> {
62-
console.log("Ren'Py extension activated");
63+
logMessage(LogLevel.Info, "Ren'Py extension activated");
6364

6465
const filepath = getNavigationJsonFilepath();
6566
const jsonFileExists = fs.existsSync(filepath);
6667
if (!jsonFileExists) {
67-
console.log("Navigation.json file is missing.");
68+
logMessage(LogLevel.Warning, "Navigation.json file is missing.");
6869
}
6970

7071
// hide rpyc files if the setting is enabled
@@ -224,7 +225,7 @@ export async function activate(context: ExtensionContext): Promise<void> {
224225
try {
225226
await NavigationData.refresh(true);
226227
} catch (error) {
227-
console.log(error);
228+
logMessage(LogLevel.Error, error as string);
228229
} finally {
229230
updateStatusBar(getStatusBarText());
230231
}
@@ -238,7 +239,7 @@ export async function activate(context: ExtensionContext): Promise<void> {
238239
try {
239240
window.showTextDocument(uri, { selection: range });
240241
} catch (error) {
241-
window.showWarningMessage(`Could not jump to the location (error: ${error})`);
242+
logToast(LogLevel.Warning, `Could not jump to the location (error: ${error})`);
242243
}
243244
});
244245
context.subscriptions.push(gotoFileLocationCommand);
@@ -291,7 +292,7 @@ export async function activate(context: ExtensionContext): Promise<void> {
291292
const runCommand = commands.registerCommand("renpy.runCommand", () => {
292293
//EsLint recommends config be removed as it has already been declared in a previous scope
293294
if (!config || !isValidExecutable(config.renpyExecutableLocation)) {
294-
window.showErrorMessage("Ren'Py executable location not configured or is invalid.");
295+
logToast(LogLevel.Error, "Ren'Py executable location not configured or is invalid.");
295296
} else {
296297
//this is kinda a hob botched together attempt that I'm like 30% certain has a chance of working
297298
debug.startDebugging(
@@ -308,7 +309,7 @@ export async function activate(context: ExtensionContext): Promise<void> {
308309
//call renpy
309310
const result = RunWorkspaceFolder();
310311
if (result) {
311-
window.showInformationMessage("Ren'Py is running successfully");
312+
logToast(LogLevel.Info, "Ren'Py is running successfully");
312313
}
313314
}
314315
});
@@ -320,16 +321,16 @@ export async function activate(context: ExtensionContext): Promise<void> {
320321
// Call Ren'Py with the workspace folder and the json-dump argument
321322
const config = workspace.getConfiguration("renpy");
322323
if (!config) {
323-
window.showErrorMessage("Ren'Py executable location not configured or is invalid.");
324+
logToast(LogLevel.Error, "Ren'Py executable location not configured or is invalid.");
324325
} else {
325326
if (isValidExecutable(config.renpyExecutableLocation)) {
326327
// call renpy
327328
const result = ExecuteRenpyCompile();
328329
if (result) {
329-
window.showInformationMessage("Ren'Py compilation has completed.");
330+
logToast(LogLevel.Info, "Ren'Py compilation has completed.");
330331
}
331332
} else {
332-
window.showErrorMessage("Ren'Py executable location not configured or is invalid.");
333+
logToast(LogLevel.Error, "Ren'Py executable location not configured or is invalid.");
333334
}
334335
}
335336
});
@@ -349,50 +350,50 @@ export async function activate(context: ExtensionContext): Promise<void> {
349350
try {
350351
fs.watch(getNavigationJsonFilepath(), async (event, filename) => {
351352
if (filename) {
352-
console.log(`${filename} changed`);
353+
logMessage(LogLevel.Debug, `${filename} changed`);
353354
updateStatusBar("$(sync~spin) Refreshing Ren'Py navigation data...");
354355
try {
355356
await NavigationData.refresh();
356357
} catch (error) {
357-
console.log(`${Date()}: error refreshing NavigationData: ${error}`);
358+
logMessage(LogLevel.Error, `${Date()}: error refreshing NavigationData: ${error}`);
358359
} finally {
359360
updateStatusBar(getStatusBarText());
360361
}
361362
}
362363
});
363364
} catch (error) {
364-
console.log(`Watch navigation.json file error: ${error}`);
365+
logMessage(LogLevel.Error, `Watch navigation.json file error: ${error}`);
365366
}
366367

367368
if (config && config.watchFoldersForChanges) {
368-
console.log("Starting Watcher for images folder.");
369+
logMessage(LogLevel.Info, "Starting Watcher for images folder.");
369370
try {
370371
fs.watch(getImagesFolder(), { recursive: true }, async (event, filename) => {
371372
if (filename && event === "rename") {
372-
console.log(`${filename} created/deleted`);
373+
logMessage(LogLevel.Debug, `${filename} created/deleted`);
373374
await NavigationData.scanForImages();
374375
}
375376
});
376377
} catch (error) {
377-
console.log(`Watch image folder error: ${error}`);
378+
logMessage(LogLevel.Error, `Watch image folder error: ${error}`);
378379
}
379380

380-
console.log("Starting Watcher for audio folder.");
381+
logMessage(LogLevel.Info, "Starting Watcher for audio folder.");
381382
try {
382383
fs.watch(getAudioFolder(), { recursive: true }, async (event, filename) => {
383384
if (filename && event === "rename") {
384-
console.log(`${filename} created/deleted`);
385+
logMessage(LogLevel.Debug, `${filename} created/deleted`);
385386
await NavigationData.scanForAudio();
386387
}
387388
});
388389
} catch (error) {
389-
console.log(`Watch audio folder error: ${error}`);
390+
logMessage(LogLevel.Error, `Watch audio folder error: ${error}`);
390391
}
391392
}
392393
}
393394

394395
export function deactivate() {
395-
console.log("Ren'Py extension deactivating");
396+
logMessage(LogLevel.Info, "Ren'Py extension deactivating");
396397
fs.unwatchFile(getNavigationJsonFilepath());
397398
}
398399

@@ -426,6 +427,7 @@ function updateStatusBar(text: string) {
426427
if (text === "") {
427428
myStatusBarItem.hide();
428429
} else {
430+
logCatMessage(LogLevel.Info, LogCategory.Status, text);
429431
myStatusBarItem.text = text;
430432
myStatusBarItem.show();
431433
}
@@ -468,15 +470,15 @@ function RunWorkspaceFolder(): boolean {
468470
env: { PATH: process.env.PATH },
469471
});
470472
if (result.error) {
471-
console.log(`renpy spawn error: ${result.error}`);
473+
logMessage(LogLevel.Error, `renpy spawn error: ${result.error}`);
472474
return false;
473475
}
474476
if (result.stderr && result.stderr.length > 0) {
475-
console.log(`renpy spawn stderr: ${result.stderr}`);
477+
logMessage(LogLevel.Error, `renpy spawn stderr: ${result.stderr}`);
476478
return false;
477479
}
478480
} catch (error) {
479-
console.log(`renpy spawn error: ${error}`);
481+
logMessage(LogLevel.Error, `renpy spawn error: ${error}`);
480482
return false;
481483
} finally {
482484
updateStatusBar(getStatusBarText());
@@ -485,7 +487,7 @@ function RunWorkspaceFolder(): boolean {
485487
}
486488
return false;
487489
} else {
488-
console.log("config for rennpy does not exist");
490+
logMessage(LogLevel.Warning, "config for rennpy does not exist");
489491
return false;
490492
}
491493
}
@@ -514,15 +516,15 @@ function ExecuteRenpyCompile(): boolean {
514516
windowsHide: true,
515517
});
516518
if (result.error) {
517-
console.log(`renpy spawn error: ${result.error}`);
519+
logMessage(LogLevel.Error, `renpy spawn error: ${result.error}`);
518520
return false;
519521
}
520522
if (result.stderr && result.stderr.length > 0) {
521-
console.log(`renpy spawn stderr: ${result.stderr}`);
523+
logMessage(LogLevel.Error, `renpy spawn stderr: ${result.stderr}`);
522524
return false;
523525
}
524526
} catch (error) {
525-
console.log(`renpy spawn error: ${error}`);
527+
logMessage(LogLevel.Error, `renpy spawn error: ${error}`);
526528
return false;
527529
} finally {
528530
NavigationData.isCompiling = false;

src/logger.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { window } from "vscode";
2+
3+
const outputChannel = window.createOutputChannel("Ren'Py Language Extension", "renpy-log");
4+
5+
// eslint-disable-next-line no-shadow
6+
export const enum LogLevel {
7+
Debug,
8+
Info,
9+
Warning,
10+
Error,
11+
}
12+
13+
// eslint-disable-next-line no-shadow
14+
export const enum LogCategory {
15+
Default,
16+
Status,
17+
Parser,
18+
Tokenizer,
19+
}
20+
21+
function getLogLevelPrefix(level: LogLevel): string {
22+
switch (level) {
23+
case LogLevel.Debug:
24+
return "[Debug]";
25+
case LogLevel.Info:
26+
return "[Info]";
27+
case LogLevel.Warning:
28+
return "[Warning]";
29+
case LogLevel.Error:
30+
return "[Error]";
31+
}
32+
}
33+
34+
function getLogCategoryPrefix(category: LogCategory): string {
35+
switch (category) {
36+
case LogCategory.Default:
37+
return "[Default]";
38+
case LogCategory.Status:
39+
return "[Status]";
40+
case LogCategory.Parser:
41+
return "[Parser]";
42+
case LogCategory.Tokenizer:
43+
return "[Tokenizer]";
44+
}
45+
}
46+
47+
export function logMessage(level: LogLevel, message: string, developersOnly = false): void {
48+
logCatMessage(level, LogCategory.Default, message, developersOnly);
49+
}
50+
51+
export function logCatMessage(level: LogLevel, category: LogCategory, message: string, developersOnly = false): void {
52+
const outputMsg = `${getLogLevelPrefix(level)} ${getLogCategoryPrefix(category)} > ${message}`;
53+
54+
switch (level) {
55+
case LogLevel.Debug:
56+
console.debug(outputMsg);
57+
break;
58+
case LogLevel.Info:
59+
console.log(outputMsg);
60+
break;
61+
case LogLevel.Warning:
62+
console.warn(outputMsg);
63+
break;
64+
case LogLevel.Error:
65+
console.error(outputMsg);
66+
break;
67+
}
68+
69+
if (!developersOnly && level >= LogLevel.Info) {
70+
outputChannel.appendLine(outputMsg);
71+
}
72+
}
73+
74+
export function logToast(level: LogLevel, message: string): void {
75+
logMessage(level, message);
76+
77+
switch (level) {
78+
case LogLevel.Debug:
79+
case LogLevel.Info:
80+
window.showInformationMessage(message);
81+
break;
82+
case LogLevel.Warning:
83+
window.showWarningMessage(message);
84+
break;
85+
case LogLevel.Error:
86+
window.showErrorMessage(message);
87+
break;
88+
}
89+
}

0 commit comments

Comments
 (0)