Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ Use `/*!` in all file types that support the normal `/*` comments to start a QDo

#### Normal comment blocks

Using the normal comment block `/* */` either typing manually or the native VScode command "Toggle Block Comment" (`editor.action.blockComment`, native keybinding `shift + alt + a`), the block will have the same on enter functionality as described above.
Using the normal comment block `/* */` either typing manually or the native VScode command "Toggle Block Comment" (`editor.action.blockComment`, native keybinding <kbd>shift + alt + a</kbd> (macOS: <kbd>shift + option + a</kbd>)), the block will have the same on enter functionality as described above.

![block-comments](https://raw.githubusercontent.com/yCodeTech/auto-comment-blocks/master/img/block-comments.gif)

Expand Down Expand Up @@ -156,9 +156,9 @@ Reload the extension after changing any settings.

- `auto-comment-blocks.multiLineStyleBlocks`: Add language IDs here to enable multi-line comment blocks support for that language, allowing unsupported languages to have comment completion. The default is `['blade', 'html']`"

- `auto-comment-blocks.overrideDefaultLanguageMultiLineComments`: A key : value pairing of language IDs and the beginning portion of a multi-line comment style, to override the default comment style for the vscode "Toggle Block Comment" `editor.action.blockComment` command (native Keybinding `shift + alt + a`). eg. `{'php': '/*!'}`
- `auto-comment-blocks.overrideDefaultLanguageMultiLineComments`: A key : value pairing of language IDs and the beginning portion of a multi-line comment style, to override the default comment style for the vscode "Toggle Block Comment" `editor.action.blockComment` command (native Keybinding <kbd>shift + alt + a</kbd> (macOS: <kbd>shift + option + a</kbd>)). eg. `{'php': '/*!'}`

- `auto-comment-blocks.bladeOverrideComments`: When enabled, Blade-style block comments will be used in Blade contexts. Ie. `{{-- --}}` comments will be used instead of the HTML `<!-- -->` comments. Keybinding to enable/disable, default `ctrl + shift + m`. If `blade` language ID is set in the disabledLanguages, then the HTML `<!-- -->` comments will be used.
- `auto-comment-blocks.bladeOverrideComments`: When enabled, Blade-style block comments will be used in Blade contexts. Ie. `{{-- --}}` comments will be used instead of the HTML `<!-- -->` comments. Keybinding to enable/disable, default <kbd>ctrl + shift + m</kbd> (macOS: <kbd>cmd + shift + m</kbd>). If `blade` language ID is set in the disabledLanguages, then the HTML `<!-- -->` comments will be used.

## Known Issues

Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@
"auto-comment-blocks.overrideDefaultLanguageMultiLineComments": {
"type": "object",
"default": {},
"markdownDescription": "A key : value pairing of language IDs and the beginning portion of a multi-line comment style, to override the default comment style for the vscode `command editor.action.blockComment` (native Keybinding `shift + alt + a`). eg. `{'php': '/*!'}`"
"markdownDescription": "A key : value pairing of language IDs and the beginning portion of a multi-line comment style, to override the default comment style for the vscode `command editor.action.blockComment` (native Keybinding `shift + alt + a` (macOS: `shift + option + a`)). eg. `{'php': '/*!'}`"
},
"auto-comment-blocks.bladeOverrideComments": {
"scope": "resource",
"type": "boolean",
"default": false,
"markdownDescription": "When enabled, Blade style block comments will be used in Blade contexts. Ie. `{{-- --}}` comments will be used instead of the HTML `<!-- -->` comments. Keybinding to enable/disable, default `ctrl + shift + m`. If `blade` language ID is set in the disabledLanguages, then the HTML `<!-- -->` comments will be used."
"markdownDescription": "When enabled, Blade style block comments will be used in Blade contexts. Ie. `{{-- --}}` comments will be used instead of the HTML `<!-- -->` comments. Keybinding to enable/disable, default `ctrl + shift + m` (macOS: `cmd + shift + m`). If `blade` language ID is set in the disabledLanguages, then the HTML `<!-- -->` comments will be used."
}
}
},
Expand All @@ -90,6 +90,7 @@
{
"command": "auto-comment-blocks.changeBladeMultiLineBlock",
"key": "ctrl+shift+m",
"mac": "cmd+shift+m",
"when": "editorTextFocus"
}
]
Expand All @@ -108,6 +109,7 @@
"typescript": "^5.7"
},
"dependencies": {
"is-wsl": "^3.1.0",
"jsonc-parser": "^3.3.1"
}
}
232 changes: 197 additions & 35 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as vscode from "vscode";
import * as fs from "node:fs";
import * as jsonc from "jsonc-parser";
import * as path from "path";
import isWsl from "is-wsl";

import {Rules} from "./rules";
import {Logger} from "./logger";
Expand All @@ -21,6 +22,11 @@ export class Configuration {
*/
private logger: Logger;

/**
* This extension details in the form of a key:value Map object, for ease of use.
*/
private extensionDetails = new Map<string, any>();

/**
* A key:value Map object of language IDs and their config file paths.
*/
Expand Down Expand Up @@ -60,25 +66,12 @@ export class Configuration {
public constructor(logger: Logger) {
this.logger = logger;

// Always output extension information to channel on activate.
const extensionId = this.getExtensionNames().id;
const extensionVersion = vscode.extensions.getExtension(extensionId)?.packageJSON.version;
this.logger.info(`Extension: ${extensionId} (${extensionVersion})`);
this.setExtensionData();

const env = {
"OS": process.platform,
"Platform": process.platform,
"VS Code Version": vscode.version,
"VS Code Root Path": vscode.env.appRoot,
"VS Code Built-in Extensions Path": `${vscode.env.appRoot}\\extensions`,
"VS Code Host": vscode.env.appHost,
"VS Code Remote Name": vscode.env.remoteName || "local",
"Other System Env Variables": process.env,
};
this.logger.debug("Environment:", env);

// Log the extension's user configuration settings.
this.logger.debug("Configuration settings:", this.getConfiguration());
// Always output extension information to channel on activate.
const id = this.getExtensionData("id");
const version = this.getExtensionData("version");
this.logger.debug(`Extension details:`, this.extensionDetails);

this.findAllLanguageConfigFilePaths();
this.setLanguageConfigDefinitions();
Expand All @@ -87,11 +80,7 @@ export class Configuration {
this.setSingleLineCommentLanguageDefinitions();
this.writeCommentLanguageDefinitionsToJsonFile();

// Log the objects for debugging purposes.
this.logger.debug("The language config filepaths found are:", this.languageConfigFilePaths);
this.logger.debug("The language configs found are:", this.languageConfigs);
this.logger.debug("The supported languages for multi-line blocks:", this.multiLineBlocksMap);
this.logger.debug("The supported languages single-line blocks:", this.singleLineBlocksMap);
this.logDebugInfo();
}

/**
Expand Down Expand Up @@ -212,22 +201,76 @@ export class Configuration {
}

/**
* Get the names and ids of this extension from package.json.
* Get the names, id, and version of this extension from package.json.
*
* @returns {object} An object containing the extension id, name, and display name.
* @returns {object} An object containing the extension id, name, display name, and version.
*/
public getExtensionNames(): {id: string; name: string; displayName: string} {
const packageJSON = JSON.parse(fs.readFileSync(__dirname + "/../../package.json").toString());
private getExtensionPackageJsonData(): {id: string; name: string; displayName: string; version: string} {
const packageJSON = this.readJsonFile(__dirname + "/../../package.json");

const displayName: string = packageJSON.displayName;
const fullname: string = packageJSON.name;
const id: string = `${packageJSON.publisher}.${fullname}`;
const version: string = packageJSON.version;

let nameParts = fullname.split("-");
nameParts[0] = "auto";
const name = nameParts.join("-");

return {id: id, name: name, displayName: displayName};
return {id: id, name: name, displayName: displayName, version: version};
}

/**
* Set the extension data into the extensionDetails Map.
*/
private setExtensionData() {
const extensionPackageJsonData = this.getExtensionPackageJsonData();

const id = extensionPackageJsonData.id;
const name = extensionPackageJsonData.name;
const displayName = extensionPackageJsonData.displayName;
const version = extensionPackageJsonData.version;

// The path to the user extensions.
const userExtensionsPath = isWsl
? path.join(vscode.env.appRoot, "../../", "extensions")
: path.join(vscode.extensions.getExtension(id).extensionPath, "../");

// The path to the built-in extensions.
// This env variable changes when on WSL to it's WSL-built-in extensions path.
const builtInExtensionsPath = path.join(vscode.env.appRoot, "extensions");

this.extensionDetails.set("id", id);
this.extensionDetails.set("name", name);
this.extensionDetails.set("displayName", displayName);
this.extensionDetails.set("version", version);
this.extensionDetails.set("userExtensionsPath", userExtensionsPath);
this.extensionDetails.set("builtInExtensionsPath", builtInExtensionsPath);

if (isWsl) {
// Get the root path to VS Code from the env variable, and use it to get
// the Windows built-in extensions.
const windowsBuiltInExtensionsPathFromWsl = path.join(process.env.VSCODE_CWD, "resources/app/extensions");

// Get the Windows user extensions path from env variable.
const windowsUserExtensionsPathFromWsl = path.dirname(process.env.VSCODE_WSL_EXT_LOCATION);

this.extensionDetails.set("WindowsUserExtensionsPathFromWsl", windowsUserExtensionsPathFromWsl);
this.extensionDetails.set("WindowsBuiltInExtensionsPathFromWsl", windowsBuiltInExtensionsPathFromWsl);
}
}

/**
* Get the extension's details.
*
* @param {string} key The key of the specific extension detail to get.
*
* @returns {any} Returns a value of a specific key.
*/
public getExtensionData(key: string): any {
if (this.extensionDetails.has(key)) {
return this.extensionDetails.get(key);
}
}

/**
Expand All @@ -236,7 +279,7 @@ export class Configuration {
* @returns {vscode.WorkspaceConfiguration}
*/
public getConfiguration(): vscode.WorkspaceConfiguration {
return vscode.workspace.getConfiguration(this.getExtensionNames().name, null);
return vscode.workspace.getConfiguration(this.getExtensionData("name"), null);
}

/**
Expand Down Expand Up @@ -322,8 +365,28 @@ export class Configuration {
* (built-in and 3rd party).
*/
private findAllLanguageConfigFilePaths() {
const extensions: any[] = [];

// If running in WSL...
if (isWsl) {
// Get the Windows user and built-in extensions paths.
const windowsUserExtensionsPath = this.getExtensionData("WindowsUserExtensionsPathFromWsl");
const windowsBuiltInExtensionsPath = this.getExtensionData("WindowsBuiltInExtensionsPathFromWsl");

// Read the paths and create arrays of the extensions.
const builtInExtensions = this.readExtensionsFromDirectory(windowsBuiltInExtensionsPath);
const userExtensions = this.readExtensionsFromDirectory(windowsUserExtensionsPath);

// Combine the built-in and user extensions into the extensions array.
extensions.push(...builtInExtensions, ...userExtensions);
}

// Add all installed extensions (including built-in ones) into the extensions array.
// If running WSL, these will be the WSL-installed extensions.
extensions.push(...vscode.extensions.all);

// Loop through all installed extensions, including built-in extensions
for (let extension of vscode.extensions.all) {
for (let extension of extensions) {
const packageJSON = extension.packageJSON;

// If an extension package.json has "contributes" key,
Expand Down Expand Up @@ -443,6 +506,46 @@ export class Configuration {
fs.writeFileSync(filepath, JSON.stringify(data, null, "\t"));
}

/**
* Read the directory in the given path and return an array of objects with the data of
* all extensions found in the directory.
*
* @param {string} extensionsPath The path where extensions are stored.
*
* @returns {Array<{ id: string; extensionPath: string; packageJSON: any }>}
*/
private readExtensionsFromDirectory(extensionsPath: string): Array<{id: string; extensionPath: string; packageJSON: any}> {
// Create an array to hold the found extensions.
const foundExtensions: Array<{id: string; extensionPath: string; packageJSON: any}> = [];

fs.readdirSync(extensionsPath).forEach((extensionName) => {
const extensionPath = path.join(extensionsPath, extensionName);

// If the extensionName is a directory...
if (fs.statSync(extensionPath).isDirectory()) {
// If the extensionName starts with a dot, skip it.
if (extensionName.startsWith(".")) {
return;
}

// Get the package.json file path.
const packageJSONPath = path.join(extensionPath, "package.json");

// If the package.json file exists...
if (fs.existsSync(packageJSONPath)) {
const packageJSON = this.readJsonFile(packageJSONPath);

const id = `${packageJSON.publisher}.${packageJSON.name}`;

// Push the extension data object into the array.
foundExtensions.push({id, extensionPath, packageJSON});
}
}
});

return foundExtensions;
}

/**
* Get the multi-line languages from the Map.
*
Expand Down Expand Up @@ -519,16 +622,24 @@ export class Configuration {
// If the config object has own property of comments AND the comments key has
// own property of lineComment...
if (Object.hasOwn(config, "comments") && Object.hasOwn(config.comments, "lineComment")) {
let lineComment = config.comments.lineComment;

// Line comments can be a string or an object with a "comment" key.
// If the lineComment is an object, get the "comment" key value.
if (Object.hasOwn(lineComment, "comment")) {
lineComment = lineComment.comment;
}

// If the lineComment is "//"...
if (config.comments.lineComment === "//") {
if (lineComment === "//") {
style = "//";
}
// If the lineComment is "#"...
else if (config.comments.lineComment === "#") {
else if (lineComment === "#") {
style = "#";
}
// If the lineComment includes a ";" (; or ;;)...
else if (config.comments.lineComment.includes(";")) {
else if (lineComment.includes(";")) {
style = ";";
}

Expand Down Expand Up @@ -961,7 +1072,7 @@ export class Configuration {
*/
private handleChangeBladeMultiLineBlock(textEditor: vscode.TextEditor) {
let langId = textEditor.document.languageId;
const extensionNames = this.getExtensionNames();
const extensionName = this.getExtensionData("name");

// Only carry out function if languageId is blade.
if (langId === "blade" && !this.isLangIdDisabled(langId)) {
Expand All @@ -985,12 +1096,63 @@ export class Configuration {
// then output a message to the user.
else if (langId == "blade" && this.isLangIdDisabled(langId)) {
vscode.window.showInformationMessage(
`Blade is set as disabled in the "${extensionNames.name}.disabledLanguages" setting. The "${extensionNames.name}.bladeOverrideComments" setting will have no affect.`,
`Blade is set as disabled in the "${extensionName}.disabledLanguages" setting. The "${extensionName}.bladeOverrideComments" setting will have no affect.`,
"OK"
);

// Set the comments for blade language.
this.setBladeComments(false);
}
}

/**
* Logs the environment, configuration settings, and language configs for debugging purposes.
*/
private logDebugInfo() {
// The path to the built-in extensions. The env variable changes when on WSL.
// So we can use it for both Windows and WSL.
const builtInExtensionsPath = this.getExtensionData("builtInExtensionsPath");

let extensionsPaths = {};

if (isWsl) {
// Get the Windows user and built-in extensions paths.
const windowsUserExtensionsPath = this.getExtensionData("WindowsUserExtensionsPathFromWsl");
const windowsBuiltInExtensionsPath = this.getExtensionData("WindowsBuiltInExtensionsPathFromWsl");

extensionsPaths = {
"Windows-installed Built-in Extensions Path": windowsBuiltInExtensionsPath,
"Windows-installed User Extensions Path": windowsUserExtensionsPath,
"WSL-installed Built-in Extensions Path": builtInExtensionsPath,
"WSL-installed User Extensions Path": this.getExtensionData("userExtensionsPath"),
};
} else {
extensionsPaths = {
"Built-in Extensions Path": builtInExtensionsPath,
"User Extensions Path": this.getExtensionData("userExtensionsPath"),
};
}

const env = {
"OS": process.platform,
"Platform": process.platform,
"VS Code Details": {
"Version": vscode.version,
"Remote Name": vscode.env.remoteName || "local",
"Host": vscode.env.appHost,
...extensionsPaths,
},
"Other System Env Variables": process.env,
};
this.logger.debug("Environment:", env);

// Log the extension's user configuration settings.
this.logger.debug("Configuration settings:", this.getConfiguration());

// Log the objects for debugging purposes.
this.logger.debug("The language config filepaths found are:", this.languageConfigFilePaths);
this.logger.debug("The language configs found are:", this.languageConfigs);
this.logger.debug("The supported languages for multi-line blocks:", this.readJsonFile(this.multiLineLangDefinitionFilePath));
this.logger.debug("The supported languages for single-line blocks:", this.readJsonFile(this.singleLineLangDefinitionFilePath));
}
}
6 changes: 2 additions & 4 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ export function activate(context: vscode.ExtensionContext) {

disposables.push(...configureCommentBlocksDisposable, ...registerCommandsDisposable);

const extensionNames = configuration.getExtensionNames();

const extensionName = extensionNames.name;
const extensionDisplayName = extensionNames.displayName;
const extensionName = configuration.getExtensionData("name");
const extensionDisplayName = configuration.getExtensionData("displayName");

let disabledLangConfig: string[] = configuration.getConfigurationValue<string[]>("disabledLanguages");

Expand Down
Loading