Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add module statistics viewer #19

Merged
merged 34 commits into from
Nov 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
52e3fb5
Add initial stat viewer and message broadcasting
malmeloo Aug 19, 2023
83e96c0
Fix webview tracking memory leak
malmeloo Aug 21, 2023
6a224fe
Improve typing
malmeloo Aug 21, 2023
0958608
Improve statistics viewer
malmeloo Aug 22, 2023
65be7a8
Refactor + custom module overview headers
malmeloo Aug 30, 2023
df27ee7
More column control buttons
malmeloo Aug 30, 2023
f9c2370
Avoid unnecessary re-renders + fix element events
malmeloo Aug 30, 2023
f20dac8
Merge branch 'main' into add-yosys-stat-viewer
malmeloo Sep 16, 2023
46c6390
Update module focus message to contain breadcrumbs
malmeloo Sep 16, 2023
0e1742d
Implement storing of permanent data from views
malmeloo Sep 23, 2023
1cb2a13
Focus statistics from digitaljs view
malmeloo Sep 23, 2023
739047e
Save module overview table settings
malmeloo Sep 23, 2023
eaffbe1
Add module count stats to overview
malmeloo Sep 23, 2023
11b9c20
(WIP) Make circuit explorer columns more interactive
malmeloo Sep 30, 2023
b5966a2
Show actual module stats in explorer
malmeloo Oct 7, 2023
535a64e
Make events scope specific to elements
malmeloo Oct 7, 2023
df56190
Adopt breadcrumbs header into module explorer element
malmeloo Oct 7, 2023
1a04c11
Fix columns disappearing when switching between modules
malmeloo Oct 7, 2023
61d8cd7
Use tabs instead of vertical stacking
malmeloo Oct 8, 2023
8a48e23
Add primitives tab to stats viewer
malmeloo Oct 14, 2023
dce3937
Add wire stats
malmeloo Oct 14, 2023
8491c3d
Show default count col in overview tab
malmeloo Oct 14, 2023
a4a7464
Reverse rows and columns
malmeloo Oct 14, 2023
7687584
refactor stat viewer elements into separate files
malmeloo Oct 14, 2023
20f565b
Add initial interactive datagrid settings support
malmeloo Oct 15, 2023
0101a31
Better support for stat viewer grid headers
malmeloo Oct 22, 2023
5530f63
Add module count to primitives overview
malmeloo Oct 22, 2023
090d0c9
Add more settings to interactive data grids
malmeloo Oct 22, 2023
022aa6e
Correctly save and restore grid table configs
malmeloo Oct 28, 2023
d6a54b9
Add warning message when missing broadcast targets
malmeloo Oct 29, 2023
040ef8f
Focus explorer tab when called from digitaljs
malmeloo Oct 29, 2023
f6448c9
Merge branch 'main' into add-yosys-stat-viewer
malmeloo Nov 4, 2023
c122b80
Merge branch 'main' into add-yosys-stat-viewer
DanielleHuisman Nov 26, 2023
5b62488
Enable type checked ESLint config
DanielleHuisman Nov 26, 2023
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
8 changes: 6 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
{
"root": true,
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended-type-checked"],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"parserOptions": {
"project": true
},
"rules": {
"@typescript-eslint/consistent-type-imports": [
"warn",
Expand All @@ -11,6 +14,7 @@
"fixStyle": "inline-type-imports"
}
],
"@typescript-eslint/no-unused-vars": ["warn", {"argsIgnorePattern": "^_"}]
"@typescript-eslint/no-unused-vars": ["warn", {"argsIgnorePattern": "^_"}],
"@typescript-eslint/require-await": "off"
}
}
3 changes: 0 additions & 3 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
dist/

# TODO: un-ignore this file once we find a solution to the jquery import reordering situation
views/digitaljs/src/main.ts
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@
"compile-web": "npm run build-views && tsc && webpack",
"package-web": "npm run build-views && tsc && webpack --mode production --devtool hidden-source-map",
"vscode:prepublish": "npm run package-web",
"lint": "eslint ./src ./workers/src --ext ts",
"lint": "eslint ./src --ext ts",
"test": "vscode-test-web --browserType=chromium --extensionDevelopmentPath=. --extensionTestsPath=dist/extension/test/suite/index.js",
"pretest": "npm run compile-web"
},
Expand All @@ -301,7 +301,7 @@
"process": "^0.11.10",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.1",
"typescript": "^5.3.2",
"typescript": "5.2.2",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4"
},
Expand Down
56 changes: 29 additions & 27 deletions scripts/run-each-view.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
import {spawnSync} from 'child_process';
import {readdir} from 'fs/promises';
import path from 'path';
import {fileURLToPath} from 'url';

const command = process.argv.slice(2);
const commandName = ['npm'].concat(command).join(' ');
// eslint-disable-next-line @typescript-eslint/no-floating-promises
(async () => {
const command = process.argv.slice(2);
const commandName = ['npm'].concat(command).join(' ');

const currentDirectory = path.dirname(fileURLToPath(import.meta.url));
const viewsDirectory = path.resolve(currentDirectory, '..', 'views');
const failedDirectories: string[] = [];
const currentDirectory = path.dirname(__filename);
const viewsDirectory = path.resolve(currentDirectory, '..', 'views');
const failedDirectories: string[] = [];

console.log(`Executing command "${commandName}" for all views.`);
console.log();
console.log(`Executing command "${commandName}" for all views.`);
console.log();

for (const directory of await readdir(viewsDirectory)) {
const directoryName = `./views/${directory}`;
for (const directory of await readdir(viewsDirectory)) {
const directoryName = `./views/${directory}`;

console.log(`Executing command "${commandName}" in views "${directoryName}"`);
console.log(`Executing command "${commandName}" in views "${directoryName}"`);

const {status} = spawnSync('npm', command, {
cwd: path.resolve(viewsDirectory, directory),
stdio: ['inherit', 'inherit', 'inherit']
});
console.log();
const {status} = spawnSync('npm', command, {
cwd: path.resolve(viewsDirectory, directory),
stdio: ['inherit', 'inherit', 'inherit']
});
console.log();

if (status !== 0) {
failedDirectories.push(directoryName);
}
}

if (status !== 0) {
failedDirectories.push(directoryName);
if (failedDirectories.length === 0) {
console.log(`Executing command "${commandName}" was successful for all views.`);
} else {
console.log(`Executing command "${commandName}" failed for these views:`);
console.log(failedDirectories.map((directory) => ` - ${directory}`).join('\n'));
console.log('See the logs above for more details.');
}
}

if (failedDirectories.length === 0) {
console.log(`Executing command "${commandName}" was successful for all views.`);
} else {
console.log(`Executing command "${commandName}" failed for these views:`);
console.log(failedDirectories.map((directory) => ` - ${directory}`).join('\n'));
console.log('See the logs above for more details.');
}
})();
4 changes: 4 additions & 0 deletions src/common/universal-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ type WorkerThreadsModule = typeof import('worker_threads');
type WorkerThreadsWorker = import('worker_threads').Worker;
/* eslint-enable @typescript-eslint/consistent-type-imports */

/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call */
const module: WorkerThreadsModule | undefined =
typeof Worker === 'undefined' ? __non_webpack_require__('worker_threads') : undefined;
/* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call */

type InternalNodeWorker = {
type: 'node';
Expand Down Expand Up @@ -40,6 +42,7 @@ export const onEvent = <E extends keyof EventCallbacks>(event: E, callback: Even
if (module) {
module.parentPort?.on(event, callback);
} else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
addEventListener(event, (event) => callback(extractData(event)));
}
};
Expand Down Expand Up @@ -77,6 +80,7 @@ export class UniversalWorker {

public onEvent<E extends keyof EventCallbacks>(event: E, callback: EventCallbacks[E]): void {
if (this.worker.type === 'web') {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
this.worker.worker.addEventListener(event, (event) => callback(extractData(event)));
} else {
this.worker.worker.on(event, callback);
Expand Down
8 changes: 4 additions & 4 deletions src/extension/commands/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class OpenProjectConfigurationCommand extends CurrentProjectCommand {

async executeForCurrentProject(project: Project) {
// Open project file
vscode.commands.executeCommand('vscode.openWith', project.getUri(), ProjectEditor.getViewType());
await vscode.commands.executeCommand('vscode.openWith', project.getUri(), ProjectEditor.getViewType());
}
}

Expand All @@ -31,14 +31,14 @@ abstract class RunTaskCommand extends CurrentProjectCommand {
return false;
}

const uri = vscode.Uri.joinPath(task.scope.uri, task.definition.project);
const uri = vscode.Uri.joinPath(task.scope.uri, task.definition.project as string);
return uri.toString() === project.getUri().toString();
});

if (task) {
vscode.tasks.executeTask(task);
await vscode.tasks.executeTask(task);
} else {
vscode.window.showErrorMessage('No task could be found for the current EDA project.');
await vscode.window.showErrorMessage('No task could be found for the current EDA project.');
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/extension/commands/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export abstract class CurrentProjectCommand extends BaseCommand {
async execute(...args: unknown[]) {
const project = this.projects.getCurrent();
if (!project) {
vscode.window.showWarningMessage('No EDA project selected.');
await vscode.window.showWarningMessage('No EDA project selected.');
return;
}

Expand Down
28 changes: 17 additions & 11 deletions src/extension/commands/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,13 @@ export class NewProjectCommand extends BaseCommand {
// Check if the project is within the workspace folder
const [workspaceRelativePath] = getWorkspaceRelativePath(projectWorkspace, projectUri);
if (!workspaceRelativePath) {
vscode.window.showErrorMessage('Selected project location must be within the selected workspace folder.', {
detail: `File "${projectUri.path}" is not in folder "${projectWorkspace.path}".`,
modal: true
});
await vscode.window.showErrorMessage(
'Selected project location must be within the selected workspace folder.',
{
detail: `File "${projectUri.path}" is not in folder "${projectWorkspace.path}".`,
modal: true
}
);
return;
}

Expand All @@ -126,7 +129,7 @@ export class NewProjectCommand extends BaseCommand {
await this.projects.add(projectUri, true, true);

// Open project file
vscode.commands.executeCommand('vscode.openWith', projectUri, ProjectEditor.getViewType());
await vscode.commands.executeCommand('vscode.openWith', projectUri, ProjectEditor.getViewType());
}
}

Expand Down Expand Up @@ -187,18 +190,21 @@ export class OpenProjectCommand extends BaseCommand {
// Check if the project is within the workspace folder
const [workspaceRelativePath] = getWorkspaceRelativePath(projectWorkspace, projectUri);
if (!workspaceRelativePath) {
vscode.window.showErrorMessage('Selected project location must be within the selected workspace folder.', {
detail: `File "${projectUri.path}" is not in folder "${projectWorkspace.path}".`,
modal: true
});
await vscode.window.showErrorMessage(
'Selected project location must be within the selected workspace folder.',
{
detail: `File "${projectUri.path}" is not in folder "${projectWorkspace.path}".`,
modal: true
}
);
return;
}

// Add project
await this.projects.add(projectUri, true, false);

// Open project file
vscode.commands.executeCommand('vscode.openWith', projectUri, ProjectEditor.getViewType());
await vscode.commands.executeCommand('vscode.openWith', projectUri, ProjectEditor.getViewType());
}
}

Expand All @@ -218,6 +224,6 @@ export class SelectProject extends BaseCommand {
}

async execute(project: Project) {
await this.projects.setCurrent(project);
this.projects.setCurrent(project);
}
}
60 changes: 46 additions & 14 deletions src/extension/editors/base.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as vscode from 'vscode';

import type {Projects} from '../projects/index.js';
import {type ViewMessage} from '../types.js';
import type {GlobalStoreMessage, ViewMessage} from '../types.js';
import {BaseWebview} from '../webview.js';

export interface EditorWebviewArgs {
Expand All @@ -26,57 +26,89 @@ export abstract class BaseEditor extends BaseWebview<EditorWebviewArgs> implemen
_token: vscode.CancellationToken
): void | Thenable<void> {
const disposables: vscode.Disposable[] = [];
const webview = webviewPanel.webview;

// Render webview
webviewPanel.webview.options = {
webview.options = {
enableScripts: true
};
webviewPanel.webview.html = this.getHtmlForWebview(webviewPanel.webview, {document});
webview.html = this.getHtmlForWebview(webview, {document});

// Add message listener
webviewPanel.webview.onDidReceiveMessage(this.onDidReceiveMessage.bind(this, document, webviewPanel.webview));
webview.onDidReceiveMessage(this.onDidReceiveMessage.bind(this, document, webview));

// Add text document listener
disposables.push(
vscode.workspace.onDidChangeTextDocument((event) => {
if (event.document.uri.toString() === document.uri.toString()) {
this.update(document, webviewPanel.webview, true);
this.update(document, webview, true);
}
})
);
disposables.push(
vscode.workspace.onDidSaveTextDocument((event) => {
if (event.uri.toString() === document.uri.toString()) {
this.onSave(document, webviewPanel.webview);
this.onSave(document, webview);
}
})
);

// Create file system watcher
const watcher = vscode.workspace.createFileSystemWatcher(document.uri.fsPath);
watcher.onDidCreate(() => this.update(document, webviewPanel.webview, true));
watcher.onDidChange(() => this.update(document, webviewPanel.webview, true));
watcher.onDidDelete(() => this.update(document, webviewPanel.webview, true));
watcher.onDidCreate(() => this.update(document, webview, true));
watcher.onDidChange(() => this.update(document, webview, true));
watcher.onDidDelete(() => this.update(document, webview, true));
disposables.push(watcher);

// Add dispose listener
webviewPanel.onDidDispose(() => {
this.onClose(document, webview);

for (const disposable of disposables) {
disposable.dispose();
}
});

// Update document
this.update(document, webviewPanel.webview, false);
this.update(document, webview, false);
}

protected abstract onDidReceiveMessage(
document: vscode.TextDocument,
protected async onDidReceiveMessage(
_document: vscode.TextDocument,
webview: vscode.Webview,
message: ViewMessage
): void;
message: ViewMessage | GlobalStoreMessage
): Promise<boolean> {
if (message.type === 'globalStore') {
if (message.action === 'set') {
await this.context.globalState.update(message.name, message.value);
const response: GlobalStoreMessage = {
type: 'globalStore',
action: 'result',
transaction: message.transaction
};
await webview.postMessage(response);

return true;
} else if (message.action === 'get') {
const value = this.context.globalState.get(message.name) || ({} as object);
const response: GlobalStoreMessage = {
type: 'globalStore',
action: 'result',
transaction: message.transaction,
result: value
};
await webview.postMessage(response);

return true;
}
}

return false;
}

protected abstract onSave(document: vscode.TextDocument, webview: vscode.Webview): void;

protected abstract onClose(document: vscode.TextDocument, webview: vscode.Webview): void;

protected abstract update(document: vscode.TextDocument, webview: vscode.Webview, isDocumentChange: boolean): void;
}
2 changes: 1 addition & 1 deletion src/extension/editors/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './digitaljs.js';
export * from './yosys.js';
export * from './nextpnr.js';
export * from './project.js';
Loading