Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
153 changes: 145 additions & 8 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@
"syntax": "js-yaml ./syntaxes/systemverilog.tmLanguage.yaml >./syntaxes/systemverilog.tmLanguage.json"
},
"dependencies": {
"@vscode/test-cli": "^0.0.12",
"@logtape/logtape": "^2.0.0",
"js-yaml": "^4.1.1",
"semver": "^7.7.3",
"vscode-languageclient": "^9.0.1",
Expand All @@ -695,6 +695,7 @@
"@types/which": "^3.0.4",
"@typescript-eslint/eslint-plugin": "^8.39.1",
"@typescript-eslint/parser": "^8.39.1",
"@vscode/test-cli": "^0.0.12",
"@vscode/test-electron": "^2.5.2",
"esbuild": "^0.27.2",
"eslint": "9.39.2",
Expand Down
13 changes: 8 additions & 5 deletions src/commands/ModuleInstantiation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
import { Ctags, Symbol } from '../ctags';
import { logger } from '../extension';
import { getExtensionLogger } from '../logging';

const logger = () => getExtensionLogger('Command', 'ModuleInstantiation');

export function instantiateModuleInteract() {
if (!isCtagsEnabled()) {
Expand Down Expand Up @@ -41,8 +43,9 @@ export async function instantiateModule(srcpath: string): Promise<vscode.Snippet
return undefined;
}
const file: vscode.TextDocument = vscode.window.activeTextEditor.document;
const ctags: ModuleTags = new ModuleTags(logger, file);
logger.info('Executing ctags for module instantiation');
const log = logger();
const ctags: ModuleTags = new ModuleTags(log, file);
log.info`Executing ctags for module instantiation`;
const output = await ctags.execCtags(srcpath);
await ctags.buildSymbolsList(output);
let module: Symbol | undefined;
Expand Down Expand Up @@ -83,12 +86,12 @@ export async function instantiateModule(srcpath: string): Promise<vscode.Snippet
tag.type === 'parameter' && tag.parentType === 'module' && tag.parentScope === scope
);
parametersName = params.map((tag) => tag.name);
logger.info(`Module name: ${ module.name}`);
log.info`Module name: ${module.name}`;
let paramString = ``;
if (parametersName.length > 0) {
paramString = `\n#(\n${instantiatePort(parametersName)})\n`;
}
logger.info(`portsName: ${ portsName.toString()}`);
log.info`portsName: ${portsName.toString()}`;
return new vscode.SnippetString()
.appendText(`${module.name } `)
.appendText(paramString)
Expand Down
41 changes: 17 additions & 24 deletions src/ctags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import * as vscode from 'vscode';
import {exec as execNonPromise} from 'child_process';
import * as util from 'util';
import { Logger } from './logger';
import { type Logger } from '@logtape/logtape';
import { getExtensionLogger } from './logging';
import { END_OF_LINE } from './constants';
const exec = util.promisify(execNonPromise);

Expand Down Expand Up @@ -237,21 +238,18 @@ export class Ctags {
*/
async execCtags(filepath: string): Promise<string> {
const command: string = `${this.ctagBinPath } -f - --fields=+K --sort=no --excmd=n --fields-SystemVerilog=+{parameter} "${ filepath }"`;
this.logger.info(`Executing Command: ${ command}`);
this.logger.info`Executing Command: ${command}`;
try {
const {stdout, stderr} = await exec(command);
if(stdout) {
return stdout.toString();
}
if(stderr) {
this.logger.error(`stderr> ${ stderr}`);
this.logger.error`stderr> ${stderr}`;
}
}
catch (err) {
this.logger.error(`Exception caught: ${ err instanceof Error ? err.message : String(err)}`);
if (err instanceof Error && err.stack) {
this.logger.error(err.stack);
}
this.logger.error`Exception caught: ${err}`;
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error logging loses stack trace information. The previous implementation logged both the error message and stack trace separately, which is helpful for debugging. Consider including stack trace in the properties object when err is an Error instance.

Suggested change
this.logger.error`Exception caught: ${err}`;
if (err instanceof Error) {
this.logger.error`Exception caught while executing ctags: ${err.message} ${{ error: err, stack: err.stack, name: err.name }}`;
}
else {
this.logger.error`Exception caught while executing ctags: ${String(err)}`;
}

Copilot uses AI. Check for mistakes.
}

// Return empty promise if ctags path is not set to avoid errors when indexing
Expand Down Expand Up @@ -287,8 +285,8 @@ export class Ctags {
const lineNo = Number(lineNoStr.slice(0, -2)) - 1;
return new Symbol(name, type, pattern, lineNo, parentScope, parentType, lineNo, false);
} catch (err) {
this.logger.error(`Line Parser: ${ err}`);
this.logger.error(`Line: ${ line}`);
this.logger.error`Line Parser: ${err}`;
this.logger.error`Line: ${line}`;
}
return undefined;
}
Expand All @@ -301,9 +299,9 @@ export class Ctags {
async buildSymbolsList(tags: string): Promise<void> {
try {
if (this.isDirty) {
this.logger.info('building symbols');
this.logger.info`building symbols`;
if (tags === '') {
this.logger.error('No output from ctags');
this.logger.error`No output from ctags`;
return;
}
// Parse ctags output
Expand Down Expand Up @@ -353,18 +351,15 @@ export class Ctags {
this.isDirty = false;
}
} catch (err) {
this.logger.error(String(err));
if (err instanceof Error && err.stack) {
this.logger.error(err.stack);
}
this.logger.error`${err}`;
}
}

/**
* Indexes the document by running ctags and building the symbols list.
*/
async index(): Promise<void> {
this.logger.info('indexing ', this.doc.uri.fsPath);
this.logger.info`indexing ${this.doc.uri.fsPath}`;

const output = await this.execCtags(this.doc.uri.fsPath);
await this.buildSymbolsList(output);
Expand All @@ -377,16 +372,14 @@ export class Ctags {
*/
export class CtagsManager {
private filemap: Map<vscode.TextDocument, Ctags> = new Map();
private logger!: Logger;
private readonly logger = getExtensionLogger('Ctags', 'Manager');
private enabled = false;

/**
* Configures the CtagsManager with a logger and sets up event listeners.
* @param logger - The logger instance for output
* Configures the CtagsManager and sets up event listeners.
*/
configure(logger: Logger) {
this.logger = logger;
this.logger.info('ctags manager configure');
configure() {
this.logger.info`ctags manager configure`;
this.updateConfig();
vscode.workspace.onDidSaveTextDocument(this.onSave.bind(this));
vscode.workspace.onDidCloseTextDocument(this.onClose.bind(this));
Expand All @@ -402,7 +395,7 @@ export class CtagsManager {
const nextEnabled = <boolean>config.get('enabled', false);
if (this.enabled !== nextEnabled) {
this.enabled = nextEnabled;
this.logger.info(`ctags enabled: ${ this.enabled}`);
this.logger.info`ctags enabled: ${this.enabled}`;
this.invalidateCache();
}
}
Expand Down Expand Up @@ -440,7 +433,7 @@ export class CtagsManager {
* @param doc - The document that was saved
*/
onSave(doc: vscode.TextDocument) {
this.logger.info('on save');
this.logger.info`on save`;
if (!this.enabled) {
return;
}
Expand Down
47 changes: 21 additions & 26 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,31 @@ import * as ModuleInstantiation from './commands/ModuleInstantiation';
import * as FormatProvider from './providers/FormatProvider';
import { ExtensionManager } from './extensionManager';
import { initAllLanguageClients, stopAllLanguageClients } from './languageServer';
import { createLogger, Logger } from './logger';
import { bootstrapLogging, disposeLogging, getExtensionLogger } from './logging';
import { FliplotPanel } from './fliplot/FliplotPanel';
import { FliplotCustomEditor } from './fliplot/FliplotCustomEditor';

export let logger: Logger; // Global logger
const ctagsManager = new CtagsManager();
let ctagsManager: CtagsManager | undefined;
const extensionID: string = 'mshr-h.veriloghdl';

let lintManager: LintManager;

export function activate(context: vscode.ExtensionContext) {
logger = createLogger('Verilog');
logger.info(`${extensionID } is now active.`);
export async function activate(context: vscode.ExtensionContext) {
await bootstrapLogging();

const extMgr = new ExtensionManager(context, extensionID, logger.getChild('ExtensionManager'));
const logger = getExtensionLogger();
logger.info("Extension activating", { extensionId: extensionID });

const extMgr = new ExtensionManager(context, extensionID);
if (extMgr.isVersionUpdated()) {
extMgr.showChangelogNotification();
}

// Configure ctags
ctagsManager.configure(logger);
ctagsManager = new CtagsManager();
ctagsManager.configure();

// Configure Document Symbol Provider
const verilogDocumentSymbolProvider = new DocumentSymbolProvider.VerilogDocumentSymbolProvider(
logger.getChild('VerilogDocumentSymbolProvider'),
ctagsManager,
);
context.subscriptions.push(
Expand All @@ -54,7 +54,6 @@ export function activate(context: vscode.ExtensionContext) {
// Configure Completion Item Provider
// Trigger on ".", "(", "="
const verilogCompletionItemProvider = new CompletionItemProvider.VerilogCompletionItemProvider(
logger.getChild('VerilogCompletionItemProvider'),
ctagsManager,
);
context.subscriptions.push(
Expand All @@ -78,7 +77,6 @@ export function activate(context: vscode.ExtensionContext) {

// Configure Hover Providers
const verilogHoverProvider = new HoverProvider.VerilogHoverProvider(
logger.getChild('VerilogHoverProvider'),
ctagsManager,
);
context.subscriptions.push(
Expand All @@ -96,7 +94,6 @@ export function activate(context: vscode.ExtensionContext) {

// Configure Definition Providers
const verilogDefinitionProvider = new DefinitionProvider.VerilogDefinitionProvider(
logger.getChild('VerilogDefinitionProvider'),
ctagsManager
);
context.subscriptions.push(
Expand All @@ -113,18 +110,14 @@ export function activate(context: vscode.ExtensionContext) {
);

// Configure Format Provider
const verilogFormatProvider = new FormatProvider.VerilogFormatProvider(
logger.getChild('VerilogFormatProvider')
);
const verilogFormatProvider = new FormatProvider.VerilogFormatProvider();
context.subscriptions.push(
vscode.languages.registerDocumentFormattingEditProvider(
{ scheme: 'file', language: 'verilog' },
verilogFormatProvider
)
);
const systemVerilogFormatProvider = new FormatProvider.SystemVerilogFormatProvider(
logger.getChild('SystemVerilogFormatProvider')
);
const systemVerilogFormatProvider = new FormatProvider.SystemVerilogFormatProvider();
context.subscriptions.push(
vscode.languages.registerDocumentFormattingEditProvider(
{ scheme: 'file', language: 'systemverilog' },
Expand All @@ -141,21 +134,21 @@ export function activate(context: vscode.ExtensionContext) {
);

// Register command for manual linting
lintManager = new LintManager(logger.getChild('LintManager'));
lintManager = new LintManager();
context.subscriptions.push(
vscode.commands.registerCommand('verilog.lint', lintManager.runLintTool, lintManager)
);

context.subscriptions.push(
vscode.commands.registerCommand('verilog.openFliplot', () => {
FliplotPanel.show(context, logger.getChild('Fliplot'));
FliplotPanel.show(context);
})
);

context.subscriptions.push(
vscode.window.registerCustomEditorProvider(
FliplotCustomEditor.viewType,
new FliplotCustomEditor(context, logger.getChild('Fliplot')),
new FliplotCustomEditor(context),
{
webviewOptions: { retainContextWhenHidden: true },
}
Expand All @@ -168,15 +161,17 @@ export function activate(context: vscode.ExtensionContext) {
return;
}
stopAllLanguageClients().finally(() => {
initAllLanguageClients(logger);
initAllLanguageClients();
});
});
initAllLanguageClients(logger);
initAllLanguageClients();

logger.info(`${extensionID } activation finished.`);
logger.info("Extension activated", { extensionId: extensionID });
}

export async function deactivate(): Promise<void> {
logger.info('Deactivated');
const logger = getExtensionLogger();
logger.info("Extension deactivating");
await stopAllLanguageClients();
await disposeLogging();
}
21 changes: 10 additions & 11 deletions src/extensionManager.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
import * as vscode from 'vscode';
import { SemVer } from 'semver';
import { Logger } from './logger';
import { getExtensionLogger } from './logging';

interface PackageJSON {
version: string;
Expand All @@ -13,15 +13,16 @@ export class ExtensionManager {
private extensionID: string;
private packageJSON: PackageJSON;
private extensionPath: string;
private logger: Logger;
private readonly logger = getExtensionLogger('Core', 'ExtensionManager');

constructor(context: vscode.ExtensionContext, extensionID: string, logger: Logger) {
constructor(context: vscode.ExtensionContext, extensionID: string) {
this.context = context;
this.extensionID = extensionID;
this.logger = logger;
const extension = vscode.extensions.getExtension(this.extensionID);
if (!extension) {
throw new Error(`Extension ${extensionID} not found`);
const errorMessage = `Extension ${extensionID} not found`;
this.logger.fatal("Extension not found", { extensionId: extensionID });
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fatal log is issued after the error message variable is created but the variable is never used in the thrown Error. The logging happens but the actual Error thrown uses a redundant string literal instead of errorMessage variable.

Suggested change
this.logger.fatal("Extension not found", { extensionId: extensionID });
this.logger.fatal(errorMessage, { extensionId: extensionID });

Copilot uses AI. Check for mistakes.
throw new Error(errorMessage);
}
this.packageJSON = extension.packageJSON;
this.extensionPath = extension.extensionPath;
Expand All @@ -33,12 +34,10 @@ export class ExtensionManager {

// update version value
this.context.globalState.update('version', currentVersion.version);
this.logger.info(
`previousVersion: ${
JSON.stringify(previousVersion.version)
}, currentVersion: ${
JSON.stringify(currentVersion.version)}`
);
this.logger.info("Version check", {
previousVersion: previousVersion.version,
currentVersion: currentVersion.version,
});

return previousVersion < currentVersion;
}
Expand Down
10 changes: 4 additions & 6 deletions src/fliplot/FliplotCustomEditor.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
// SPDX-License-Identifier: MIT
import * as path from 'path';
import * as vscode from 'vscode';

import { Logger } from '../logger';
import { getExtensionLogger } from '../logging';
import { FliplotPanel } from './FliplotPanel';

export class FliplotCustomEditor implements vscode.CustomTextEditorProvider {
static readonly viewType = 'verilog.fliplotEditor';

private readonly context: vscode.ExtensionContext;
private readonly logger: Logger;
private readonly logger = getExtensionLogger('Fliplot', 'CustomEditor');

constructor(context: vscode.ExtensionContext, logger: Logger) {
constructor(context: vscode.ExtensionContext) {
this.context = context;
this.logger = logger;
}

async resolveCustomTextEditor(
Expand Down Expand Up @@ -68,6 +66,6 @@ export class FliplotCustomEditor implements vscode.CustomTextEditorProvider {
changeDisposable.dispose();
});

this.logger.info(`Fliplot custom editor opened: ${document.uri.fsPath}`);
this.logger.info("Custom editor opened", { path: document.uri.fsPath });
}
}
Loading
Loading