Skip to content
Open
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
151 changes: 151 additions & 0 deletions .github/instructions/commit-message-generation.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
---
description: Apply only when generating a suggested git commit message from the VS Code Source Control "Generate Commit Message" action. Do not use for staging files or running git commits.
---

# Commit Message Generation

Use this instruction only to generate a commit message suggestion from the current git changes shown in Source Control. It must not stage files, create a commit, or perform any git action that changes repository state.

## Workflow

- Base the message on the currently staged changes when staged changes exist.
- If nothing is staged, base the message on the current unstaged working tree changes.
- Summarise the actual change, not the user's intent or ticket title.
- Only use a scope on `docs`, `chore`, `build`, and `ci` commits, and only when it meaningfully narrows the audience or area. Omit the scope on all other types.
- Return only the proposed commit message.

## Output Quality Examples

The following shows the same diff handled correctly and incorrectly.

**Bad** — raw diff tokens leaked into the message:

```
refactor(U pouvoirs Ret coins): update config methods to use helper traits 文 আ obстоятельsspaq Tritur disposto மற்றும்...
```

**Good** — high-level summary inferred from file paths and clear hunks only:

```
refactor: extract repeated config resolution logic into helper methods
```

If the diff is too noisy to summarise accurately, use a safe generic fallback:

```
chore: update project files
```

## Format

```
<type>[optional scope]: <description>

[optional body]

[optional footer(s)]
```

- **Present tense, imperative mood**: "add feature" not "added feature"
- **Scope**: lowercase, in parentheses — only permitted on `docs`, `chore`, `build`, and `ci` types; omit on all others
- **Description**: under 72 characters, concise, and in sentence case; preserve original casing for code/class references in backticks

## Commit Types

This repository extends the standard Conventional Commits types with additional project-specific types.

| Type | When to use |
| ----------- | ----------------------------------------------------------- |
| `feat` | New feature |
| `fix` | Bug fix |
| `docs` | Documentation and docblocks only |
| `style` | Formatting/whitespace, missing semi-colons, no logic change |
| `refactor` | Code restructuring, no behaviour change |
| `perf` | Performance improvement |
| `test` | Add or update tests |
| `build` | Build system or dependency changes |
| `chore` | Maintenance, tooling, config, version bumps |
| `ci` | CI/CD pipeline |
| `revert` | Revert a previous commit |
| `remove` | Remove code or files |
| `security` | Security-related changes |
| `deprecate` | Deprecation-related changes |

## Custom Type Examples

Prefer these extended types when they describe the change more accurately than `refactor`, `fix`, or `chore`.

- Use `remove` only when code or files are actually deleted, not when they are merely moved or refactored.
- Use `security` when security risk reduction is the primary intent and outcome, not for unrelated fixes.
- Use `deprecate` only when introducing or documenting a deprecation path, not when fully removing the deprecated code.

```
remove(drivers): delete legacy driver compatibility shim

security(nginx): harden fastcgi param handling for site isolation

deprecate(config): mark `php_port` as deprecated in favour of `php81_port`
```

## Breaking Changes

Use `!` after type/scope and add a `BREAKING CHANGE:` footer:

```
feat!: rename PHP port config key

BREAKING CHANGE: `php_port` renamed to `php_port_override`
```

## Body & Footers

Add a body when the _why_ is not obvious from the subject line.

Body guidance:

- Explain why the change was needed when it is not already obvious.
- Include relevant technical context only when it improves clarity.
- Use sentence case and proper punctuation.
- Use bullet points only when listing multiple distinct changes.
- Always separate each bullet point with a blank line.
- When referring to methods across multiple classes, prefix them with the class name, for example `ClassName::methodName`.

Footer guidance:

- Put issue references in the footer, for example `Closes #36` or `Refs #36`.

**Bad** — wrong case, missing backticks, footer buried in body, no blank line before footer:

```
fix - Fixed the field variable

fixed $field to $correctField in Config getValue method. also updated tests. closes #36
```

**Good**:

```
fix: correct variable replacement

Variable was missed when replacement happened, causing errors.

- Fixed incorrect `$field` variable name to `$correctField` in `Config::getValue` method.

- Updated tests to cover this case.

Closes #36
```

## Best Practices

- Review the current Source Control changes before generating the message.
- Ensure the entire message is professional and clearly communicates the purpose of the commit.
- Important: Use `docs` for JSDoc additions/changes, not `refactor`.
- Use **British English** spelling for commit messages (e.g. "optimise" not "optimize", "colour", not "color") to maintain consistency with existing messages.
- Always enclose code references in backticks (e.g. `php_port`).
- Always separate each bullet point with a blank line.

## Safety Rules

- Never stage files, commit changes, amend commits, or push.
- Never suggest including secrets, credentials, or private keys in a commit.
18 changes: 18 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,24 @@
"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` (macOS: `cmd + shift + m`). If `blade` language ID is set in the disabledLanguages, then the HTML `<!-- -->` comments will be used."
},
"auto-comment-blocks.logLevel": {
"scope": "resource",
"type": "string",
"enum": [
"debug",
"info",
"error",
"off"
],
"markdownEnumDescriptions": [
"Log debug, info, and errors",
"Log info and errors",
"Log errors only",
"Disable logging"
],
"default": "debug",
"markdownDescription": "Set the logging level. `debug` is the most verbose, and `off` disables all logging, except for those special few labelled as 'important'."
}
}
},
Expand Down
9 changes: 5 additions & 4 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,6 @@ export class Configuration {
***********/

public constructor() {
// Always output extension information to channel on activate.
logger.debug(`Extension details:`, this.extensionData.getAll());
logger.debug(`Extension Discovery Paths:`, this.extensionData.getAllExtensionDiscoveryPaths());

this.findAllLanguageConfigFilePaths();
this.setLanguageConfigDefinitions();

Expand Down Expand Up @@ -985,6 +981,11 @@ export class Configuration {
* Logs the environment, configuration settings, and language configs for debugging purposes.
*/
private logDebugInfo() {
// If debug logging is not enabled, exit early.
if (!logger.isDebugEnabled()) {
return;
}

// 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.extensionData.getExtensionDiscoveryPath("builtInExtensionsPath");
Expand Down
29 changes: 27 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,28 @@ import {Configuration} from "./configuration";
import {logger} from "./logger";
import {ExtensionData} from "./extensionData";
import {addDevEnvVariables} from "./utils";
import {LogLevel} from "./interfaces/utils";

export function activate(context: vscode.ExtensionContext) {
// Setup logger first
logger.setupOutputChannel();

const initialLogLevel = vscode.workspace.getConfiguration("auto-comment-blocks").get<LogLevel>("logLevel", "debug");
logger.setLogLevel(initialLogLevel);

// 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(null, true);

// Always output extension information to channel on activate.
logger.important(`Activating ${extensionData.get("id")} v${extensionData.get("version")}`);
logger.debug(`Extension details:`, extensionData.getAll(true));
logger.debug(`Extension Discovery Paths:`, extensionData.getAllExtensionDiscoveryPaths());

const configuration = new Configuration();
const extensionName = extensionData.get("namespace");
const extensionDisplayName = extensionData.get("displayName");
Expand Down Expand Up @@ -57,6 +67,14 @@ export function activate(context: vscode.ExtensionContext) {
}
}

/**
* Logging Level
*/
if (event.affectsConfiguration(`${extensionName}.logLevel`)) {
const logLevel = configuration.getConfigurationValue("logLevel");
logger.setLogLevel(logLevel);
}

// Settings that require an extension host reload when changed.
const reloadRequiredSettings = [
"disabledLanguages",
Expand Down Expand Up @@ -85,8 +103,15 @@ export function activate(context: vscode.ExtensionContext) {
*
* 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 documentOpenDisposable = vscode.workspace.onDidOpenTextDocument((e) => {
// If the document is not a file or untitled scheme, then return early for
// virtual documents (e.g. git, output, etc. panels), as we only need to
// re-configure comment blocks for normal files.
if (e.uri.scheme !== "file" && e.uri.scheme !== "untitled") {
return;
}

logger.info(`Document opened or language changed to "${e.languageId}", re-configuring comment blocks.`);

// Dispose of old comment block configurations to prevent memory leaks
commentBlocksDisposables.forEach((disposable) => disposable.dispose());
Expand Down
22 changes: 20 additions & 2 deletions src/extensionData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,13 +310,31 @@ export class ExtensionData {
*
* @returns {ExtensionMetaData} A plain object containing all extension details.
*/
public getAll(): ExtensionMetaData | null {
public getAll(prepareForLogging: boolean = false): ExtensionMetaData | null {
// If no data, return null
if (this.extensionData.size === 0) {
return null;
}

return Object.fromEntries(this.extensionData) as unknown as ExtensionMetaData;
const data = prepareForLogging ? this.prepareForLogging() : this.extensionData;

return Object.fromEntries(data) as unknown as ExtensionMetaData;
}

/**
* Prepare the extension data for logging by cloning it and removing irrelevant
* information, without mutating the original data.
*
* @returns {Map<keyof ExtensionMetaData, ExtensionMetaDataValue>}
* The cloned, redacted extension data Map.
*/
private prepareForLogging(): Map<keyof ExtensionMetaData, ExtensionMetaDataValue> {
const extensionDataClone = new Map(this.extensionData);

// Remove the packageJSON entry to avoid logging irrelevant information.
extensionDataClone.delete("packageJSON");

return extensionDataClone;
}

/**
Expand Down
3 changes: 3 additions & 0 deletions src/interfaces/settings.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {LogLevel} from "./utils";

export interface Settings {
singleLineBlockOnEnter: boolean;
disabledLanguages: string[];
Expand All @@ -7,4 +9,5 @@ export interface Settings {
multiLineStyleBlocks: string[];
overrideDefaultLanguageMultiLineComments: Record<string, string>;
bladeOverrideComments: boolean;
logLevel: LogLevel;
}
15 changes: 15 additions & 0 deletions src/interfaces/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,18 @@ export interface MultiLineLanguageDefinitions extends JsonObject {
* Language ID
*/
export type LanguageId = string;

/**
* Log levels
*/
export const logLevels = {
debug: "debug",
info: "info",
error: "error",
off: "off",
} as const;

/**
* Log level union type, derived from the keys of the logLevels object.
*/
export type LogLevel = (typeof logLevels)[keyof typeof logLevels];
Loading
Loading