From 14f2e5138fbd9cfa14a1f68c17e4c06a8c490261 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Thu, 16 Apr 2026 07:37:40 +0100 Subject: [PATCH 1/6] refactor: move init methods into the `activate` function. - Moved `logger.setupOutputChannel`, `addDevEnvVariables`, `ExtensionData`, and `Configuration` initialisations into the extension's `activate` function. - Added a conditional around `addDevEnvVariables` util function call to check to see if the extension is running in development mode before accessing a .env and adding the dev environment variables. This uses the `context.extensionMode`, which is only available inside the `activate` function which is why everything outside of the function had to be moved into it. The reason for the conditional is because if for some reason there is a .env in a production environment, then this .env file and it's variables would be added to the environment all the time. This could potentially cause a security risk, so we prevent this by only adding the dev env variables when not in production, so in development mode. --- src/extension.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 95c8bb7..7f6ac08 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -7,15 +7,20 @@ import {logger} from "./logger"; import {ExtensionData} from "./extensionData"; import {addDevEnvVariables} from "./utils"; -logger.setupOutputChannel(); -addDevEnvVariables(); - -const extensionData = new ExtensionData(); -let configuration = new Configuration(); - const disposables: vscode.Disposable[] = []; export function activate(context: vscode.ExtensionContext) { + // Setup logger first + logger.setupOutputChannel(); + + // Only load dev environment variables when not in production + if (context.extensionMode !== vscode.ExtensionMode.Production) { + addDevEnvVariables(); + } + + // Initialize extension data and configuration + const extensionData = new ExtensionData(); + const configuration = new Configuration(); const configureCommentBlocksDisposable = configuration.configureCommentBlocks(); configuration.registerCommands(context); From b887b1177645f26ed53ffbeabff6eb3de578ecd6 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Fri, 17 Apr 2026 06:11:01 +0100 Subject: [PATCH 2/6] refactor: group the variable initialisation at the top of `activate`. - Move the `extensionName`, `extensionDisplayName` variables up to the top of `activate` function so they are grouped with the rest of the variable initialisation. - Move the `disposables` array variable into the `activate` function. --- src/extension.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 7f6ac08..140a672 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -7,8 +7,6 @@ import {logger} from "./logger"; import {ExtensionData} from "./extensionData"; import {addDevEnvVariables} from "./utils"; -const disposables: vscode.Disposable[] = []; - export function activate(context: vscode.ExtensionContext) { // Setup logger first logger.setupOutputChannel(); @@ -21,16 +19,17 @@ export function activate(context: vscode.ExtensionContext) { // Initialize extension data and configuration const extensionData = new ExtensionData(); const configuration = new Configuration(); + const extensionName = extensionData.get("namespace"); + const extensionDisplayName = extensionData.get("displayName"); + + // Store disposables for cleanup + const disposables: vscode.Disposable[] = []; const configureCommentBlocksDisposable = configuration.configureCommentBlocks(); configuration.registerCommands(context); disposables.push(...configureCommentBlocksDisposable); - const extensionName = extensionData.get("namespace"); - - const extensionDisplayName = extensionData.get("displayName"); - let disabledLangConfig: string[] = configuration.getConfigurationValue("disabledLanguages"); if (disabledLangConfig.length > 0) { From d61ef244ece1d705b00fc00888aad274239c5e6c Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Sun, 19 Apr 2026 01:53:18 +0100 Subject: [PATCH 3/6] refactor: simplify configuration change handling in `activate` function There is a lot of duplication in the configuration change handling in the extension's `activate` function, with the `showInformationMessage` and reloading the window code. - Replaced all the configuration change event handlers that required extension reload: `disabledLanguages`, `overrideDefaultLanguageMultiLineComments`, `multiLineStyleBlocks`, `slashStyleBlocks`, `hashStyleBlocks`, and `semicolonStyleBlocks`, with an array to define the setting names. - Added a `for...of` loop to loop through the new settings array and applies the change event handler, which uses the new `showReloadMessage` function. This makes the code DRY. - Added new `showReloadMessage` function to show the reload info message and code to reload the extensions. This prevents duplication of the message and reload code as it was previously. --- src/extension.ts | 136 +++++++++++++---------------------------------- 1 file changed, 37 insertions(+), 99 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 140a672..e7a5c62 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -44,13 +44,10 @@ export function activate(context: vscode.ExtensionContext) { // TODO: Work on automatically updating the languages instead of making the user reload the extension. /** - * Blade Override Comments + * Blade Override Comments - can be updated without reload */ - // If the affected setting is bladeOverrideComments... if (event.affectsConfiguration(`${extensionName}.bladeOverrideComments`)) { - // Get the setting. - let bladeOverrideComments: boolean = configuration.getConfigurationValue("bladeOverrideComments"); - + const bladeOverrideComments: boolean = configuration.getConfigurationValue("bladeOverrideComments"); configuration.setBladeComments(bladeOverrideComments); if (!configuration.isLangIdDisabled("blade")) { @@ -58,103 +55,26 @@ export function activate(context: vscode.ExtensionContext) { } } - /** - * Disabled Languages - */ - if (event.affectsConfiguration(`${extensionName}.disabledLanguages`)) { - vscode.window - .showInformationMessage( - `The ${extensionName}.disabledLanguages setting has been changed. Please reload the Extension Host to take effect.`, - "Reload" - ) - .then((selection) => { - if (selection === "Reload") { - vscode.commands.executeCommand("workbench.action.restartExtensionHost"); - } - }); - } - - /** - * Override Default Language Block Comments - */ - if (event.affectsConfiguration(`${extensionName}.overrideDefaultLanguageMultiLineComments`)) { - vscode.window - .showInformationMessage( - `The ${extensionName}.overrideDefaultLanguageMultiLineComments setting has been changed. Please reload the Extension Host to take effect.`, - "Reload" - ) - .then((selection) => { - if (selection === "Reload") { - vscode.commands.executeCommand("workbench.action.restartExtensionHost"); - } - }); - } - - /** - * Multi-line style Block Comments - */ - if (event.affectsConfiguration(`${extensionName}.multiLineStyleBlocks`)) { - vscode.window - .showInformationMessage( - `The ${extensionName}.multiLineStyleBlocks setting has been changed. Please reload the Extension Host to take effect.`, - "Reload" - ) - .then((selection) => { - if (selection === "Reload") { - vscode.commands.executeCommand("workbench.action.restartExtensionHost"); - } - }); - } - - /** - * //-style single-line comments - */ - if (event.affectsConfiguration(`${extensionName}.slashStyleBlocks`)) { - vscode.window - .showInformationMessage( - `The ${extensionName}.slashStyleBlocks setting has been changed. Please reload the Extension Host to take effect.`, - "Reload" - ) - .then((selection) => { - if (selection === "Reload") { - vscode.commands.executeCommand("workbench.action.restartExtensionHost"); - } - }); - } - - /** - * #-style single-line comments - */ - if (event.affectsConfiguration(`${extensionName}.hashStyleBlocks`)) { - vscode.window - .showInformationMessage( - `The ${extensionName}.hashStyleBlocks setting has been changed. Please reload the Extension Host to take effect.`, - "Reload" - ) - .then((selection) => { - if (selection === "Reload") { - vscode.commands.executeCommand("workbench.action.restartExtensionHost"); - } - }); - } - - /** - * ;-style single-line comments - */ - if (event.affectsConfiguration(`${extensionName}.semicolonStyleBlocks`)) { - vscode.window - .showInformationMessage( - `The ${extensionName}.semicolonStyleBlocks setting has been changed. Please reload the Extension Host to take effect.`, - "Reload" - ) - .then((selection) => { - if (selection === "Reload") { - vscode.commands.executeCommand("workbench.action.restartExtensionHost"); - } - }); + // Settings that require an extension host reload when changed. + const reloadRequiredSettings = [ + "disabledLanguages", + "overrideDefaultLanguageMultiLineComments", + "multiLineStyleBlocks", + "slashStyleBlocks", + "hashStyleBlocks", + "semicolonStyleBlocks", + ]; + + // Settings that require extension host reload + for (const setting of reloadRequiredSettings) { + if (event.affectsConfiguration(`${extensionName}.${setting}`)) { + showReloadMessage(extensionName, setting); + break; // Only show one reload message at a time + } } }); + // An event that is emitted when a text document is opened or when the // language id of a text document has been changed. As described in // https://github.com/microsoft/vscode/blob/4e8fbaef741afebd24684b88cac47c2f44dfb8eb/src/vscode-dts/vscode.d.ts#L13716-L13728 @@ -171,3 +91,21 @@ export function activate(context: vscode.ExtensionContext) { export function deactivate() { logger.disposeLogger(); } + +/** + * Shows a message prompting the user to reload the extension host. + * @param extensionName The namespace of the extension + * @param settingName The name of the setting that was changed + */ +function showReloadMessage(extensionName: string, settingName: string): void { + vscode.window + .showInformationMessage( + `The ${extensionName}.${settingName} setting has been changed. Please reload the Extension Host to take effect.`, + "Reload" + ) + .then((selection) => { + if (selection === "Reload") { + vscode.commands.executeCommand("workbench.action.restartExtensionHost"); + } + }); +} From 423316421e848739ca50343c3d56dcb0f6c2b3c6 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Sun, 19 Apr 2026 06:00:09 +0100 Subject: [PATCH 4/6] refactor: move pushing `configureCommentBlocksDisposable` up a few lines - Move the array pushing of the `configureCommentBlocksDisposable` variable up a few lines to where it's defined. --- src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extension.ts b/src/extension.ts index e7a5c62..0cfc0ce 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -25,10 +25,10 @@ export function activate(context: vscode.ExtensionContext) { // Store disposables for cleanup const disposables: vscode.Disposable[] = []; const configureCommentBlocksDisposable = configuration.configureCommentBlocks(); + disposables.push(...configureCommentBlocksDisposable); configuration.registerCommands(context); - disposables.push(...configureCommentBlocksDisposable); let disabledLangConfig: string[] = configuration.getConfigurationValue("disabledLanguages"); From 3cb61c36f5650fdb2410826020736421befc53ec Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Sun, 19 Apr 2026 06:08:50 +0100 Subject: [PATCH 5/6] fix: add proper disposable management for events. - Added proper disposable management for the `onDidChangeConfiguration` and `onDidOpenTextDocument` events, to ensure they are properly discarded once we're done with them. --- src/extension.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 0cfc0ce..95f7c9a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -40,7 +40,7 @@ export function activate(context: vscode.ExtensionContext) { * When the configuration/user settings are changed, set the extension * to reflect the settings and output a message to the user. */ - vscode.workspace.onDidChangeConfiguration((event: vscode.ConfigurationChangeEvent) => { + const configChangeDisposable = vscode.workspace.onDidChangeConfiguration((event: vscode.ConfigurationChangeEvent) => { // TODO: Work on automatically updating the languages instead of making the user reload the extension. /** @@ -74,20 +74,26 @@ export function activate(context: vscode.ExtensionContext) { } }); + disposables.push(configChangeDisposable); - // An event that is emitted when a text document is opened or when the - // language id of a text document has been changed. As described in - // https://github.com/microsoft/vscode/blob/4e8fbaef741afebd24684b88cac47c2f44dfb8eb/src/vscode-dts/vscode.d.ts#L13716-L13728 - - // Called when active editor language is changed, so re-configure the comment blocks. - vscode.workspace.onDidOpenTextDocument(() => { + /** + * An event that is emitted when a text document is opened or when the + * language id of a text document has been changed. As described in + * https://github.com/microsoft/vscode/blob/4e8fbaef741afebd24684b88cac47c2f44dfb8eb/src/vscode-dts/vscode.d.ts#L13716-L13728 + * + * Called when active editor language is changed, so re-configure the comment blocks. + */ + const documentOpenDisposable = vscode.workspace.onDidOpenTextDocument(() => { logger.info("Active editor language changed, re-configuring comment blocks."); const configureCommentBlocksDisposable = configuration.configureCommentBlocks(); disposables.push(...configureCommentBlocksDisposable); }); + disposables.push(documentOpenDisposable); + context.subscriptions.push(...disposables); } + export function deactivate() { logger.disposeLogger(); } From 9e3353233dbe8f785d42656265f8ca7e4fea0a33 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Sun, 19 Apr 2026 06:17:04 +0100 Subject: [PATCH 6/6] perf: fix potential memory leak for old comment block configurations. - Added new `commentBlocksDisposables` disposable array to keep track of the comment blocks. - Changed the variable name for the comment block disposable to `commentBlocksDisposables`. - Fixed potential memory leak in the `onDidOpenTextDocument` event handler. On each document opening, we reconfigure the comment blocks configs which pushes new disposables everytime. This could lead to memory leaks over time. Fixed by looping through the `commentBlocksDisposables` array and disposing of each configuration, before new ones are created. --- src/extension.ts | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 95f7c9a..6acf50b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -24,14 +24,16 @@ export function activate(context: vscode.ExtensionContext) { // Store disposables for cleanup const disposables: vscode.Disposable[] = []; - const configureCommentBlocksDisposable = configuration.configureCommentBlocks(); - disposables.push(...configureCommentBlocksDisposable); - - configuration.registerCommands(context); + let commentBlocksDisposables: vscode.Disposable[] = []; + // Initial configuration + commentBlocksDisposables = configuration.configureCommentBlocks(); + disposables.push(...commentBlocksDisposables); - let disabledLangConfig: string[] = configuration.getConfigurationValue("disabledLanguages"); + configuration.registerCommands(context); + // Show disabled languages message + const disabledLangConfig: string[] = configuration.getConfigurationValue("disabledLanguages"); if (disabledLangConfig.length > 0) { vscode.window.showInformationMessage(`${disabledLangConfig.join(", ")} languages are disabled for ${extensionDisplayName}.`); } @@ -85,8 +87,14 @@ export function activate(context: vscode.ExtensionContext) { */ const documentOpenDisposable = vscode.workspace.onDidOpenTextDocument(() => { logger.info("Active editor language changed, re-configuring comment blocks."); - const configureCommentBlocksDisposable = configuration.configureCommentBlocks(); - disposables.push(...configureCommentBlocksDisposable); + + // Dispose of old comment block configurations to prevent memory leaks + commentBlocksDisposables.forEach((disposable) => disposable.dispose()); + commentBlocksDisposables = []; + + // Create new comment block configurations + commentBlocksDisposables = configuration.configureCommentBlocks(); + disposables.push(...commentBlocksDisposables); }); disposables.push(documentOpenDisposable);