Skip to content

Commit c1625b4

Browse files
committed
Bundled Chart.js locally, fixed: stack frame regex, deadlock cycle reconstruction and cold start with auto-refresh
1 parent e76466f commit c1625b4

15 files changed

Lines changed: 318 additions & 47 deletions

File tree

.github/workflows/ci.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- uses: actions/setup-node@v4
16+
with:
17+
node-version: 20
18+
cache: npm
19+
20+
- run: npm ci
21+
22+
- run: npm run copy-chartjs
23+
24+
- run: npm run compile
25+
26+
- run: npm test
27+
28+
- run: npx vsce package
29+
if: github.ref == 'refs/heads/main'
30+
31+
- uses: actions/upload-artifact@v4
32+
if: github.ref == 'refs/heads/main'
33+
with:
34+
name: vsix
35+
path: "*.vsix"

.vscodeignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ samples/**
1111
**/*.map
1212
**/*.ts
1313
!assets/icon.png
14+
!assets/chart.umd.js

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Fast Java Thread
22

3-
[![VS Code Marketplace](https://vsmarketplacebadges.dev/version-short/MartinCaminoa.fast-java-thread.svg)](https://marketplace.visualstudio.com/items?itemName=MartinCaminoa.fast-java-thread) [![Installs](https://vsmarketplacebadges.dev/installs-short/MartinCaminoa.fast-java-thread.svg)](https://marketplace.visualstudio.com/items?itemName=MartinCaminoa.fast-java-thread)
3+
[![VS Code Marketplace](https://vsmarketplacebadges.dev/version-short/MartinCaminoa.fast-java-thread.png)](https://marketplace.visualstudio.com/items?itemName=MartinCaminoa.fast-java-thread) [![Installs](https://vsmarketplacebadges.dev/installs-short/MartinCaminoa.fast-java-thread.png)](https://marketplace.visualstudio.com/items?itemName=MartinCaminoa.fast-java-thread)
44

55
VS Code extension for analyzing JVM thread dumps (`.tdump` files).
66

assets/chart.umd.js

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assets/main.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
// @ts-nocheck
1+
// @ts-check
22
(function () {
3+
// @ts-ignore - acquireVsCodeApi is provided by the VS Code webview runtime
34
const vscode = acquireVsCodeApi();
45

6+
/** @param {Record<string, number>} stateGroups */
57
function renderChart(stateGroups) {
68
const canvas = document.getElementById('stateChart');
9+
// @ts-ignore - Chart is loaded globally from chart.umd.js
710
if (!canvas || typeof Chart === 'undefined') return;
811

912
const labels = Object.keys(stateGroups);
@@ -18,6 +21,7 @@
1821
UNKNOWN: '#795548',
1922
};
2023

24+
// @ts-ignore
2125
new Chart(canvas, {
2226
type: 'pie',
2327
data: {
@@ -41,6 +45,7 @@
4145
});
4246
}
4347

48+
/** @param {Array<{method: string, count: number}>} methods */
4449
function renderHotMethods(methods) {
4550
const container = document.getElementById('hotMethods');
4651
if (!container || !methods.length) return;
@@ -53,13 +58,15 @@
5358
container.innerHTML = html;
5459
}
5560

61+
/** @param {Array<{threads: Array<{name: string, state: string}>, locks: Array<{lockId: string, className: string}>}>} deadlocks */
5662
function renderDeadlocks(deadlocks) {
5763
const container = document.getElementById('deadlocks');
5864
if (!container) return;
5965
if (!deadlocks || deadlocks.length === 0) {
60-
container.style.display = 'none';
66+
container.classList.add('hidden');
6167
return;
6268
}
69+
container.classList.remove('hidden');
6370

6471
let html = '<h2>Deadlock Detected!</h2>';
6572
deadlocks.forEach((cycle, i) => {
@@ -72,6 +79,10 @@
7279
container.innerHTML = html;
7380
}
7481

82+
/**
83+
* @param {Record<string, number>} stateGroups
84+
* @param {number} totalThreads
85+
*/
7586
function renderSummary(stateGroups, totalThreads) {
7687
const container = document.getElementById('summary');
7788
if (!container) return;
@@ -84,6 +95,7 @@
8495
container.innerHTML = html;
8596
}
8697

98+
/** @param {string} text */
8799
function escapeHtml(text) {
88100
const div = document.createElement('div');
89101
div.textContent = text;

assets/styles.css

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,20 @@ h1 {
9292
color: var(--vscode-descriptionForeground);
9393
font-size: 0.85em;
9494
}
95+
96+
.hidden {
97+
display: none;
98+
}
99+
100+
.empty-state {
101+
text-align: center;
102+
padding: 48px 16px;
103+
color: var(--vscode-descriptionForeground);
104+
font-size: 1.1em;
105+
}
106+
107+
.empty-state code {
108+
background-color: var(--vscode-textCodeBlock-background);
109+
padding: 2px 6px;
110+
border-radius: 3px;
111+
}

package-lock.json

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "fast-java-thread",
33
"displayName": "Fast Java Thread",
44
"description": "Analyze JVM thread dumps with tree view, dashboard, and click-to-navigate",
5-
"version": "0.1.0",
5+
"version": "0.1.1",
66
"publisher": "MartinCaminoa",
77
"repository": {
88
"type": "git",
@@ -80,10 +80,12 @@
8080
}
8181
},
8282
"scripts": {
83+
"copy-chartjs": "cp node_modules/chart.js/dist/chart.umd.js assets/",
8384
"compile": "tsc -p ./",
8485
"watch": "tsc -watch -p ./",
8586
"test": "jest",
86-
"vscode:prepublish": "npm run compile"
87+
"package": "npm run copy-chartjs && npm run compile && vsce package",
88+
"vscode:prepublish": "npm run copy-chartjs && npm run compile"
8789
},
8890
"devDependencies": {
8991
"@types/jest": "^29.5.12",
@@ -92,5 +94,8 @@
9294
"jest": "^29.7.0",
9395
"ts-jest": "^29.1.2",
9496
"typescript": "^5.3.3"
97+
},
98+
"dependencies": {
99+
"chart.js": "^4.5.1"
95100
}
96101
}

src/commands/registerCommands.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,27 @@ import { ThreadTreeProvider } from '../views/ThreadTreeProvider';
77
import { AnalysisWebview } from '../views/AnalysisWebview';
88
import { AnalysisResult } from '../models/types';
99

10-
let lastResult: AnalysisResult | undefined;
11-
1210
export function registerCommands(
1311
context: vscode.ExtensionContext,
1412
treeProvider: ThreadTreeProvider,
1513
output: vscode.OutputChannel,
1614
): void {
15+
let lastResult: AnalysisResult | undefined;
1716
const webview = new AnalysisWebview(context.extensionUri);
17+
context.subscriptions.push(webview);
18+
19+
// Clear lastResult when editor changes; auto-refresh dashboard on .tdump open
20+
context.subscriptions.push(
21+
vscode.window.onDidChangeActiveTextEditor(editor => {
22+
lastResult = undefined;
23+
if (editor && editor.document.uri.fsPath.endsWith('.tdump') && webview.isVisible) {
24+
const text = editor.document.getText();
25+
lastResult = analyze(text, output);
26+
treeProvider.update(lastResult.dump.threads, editor.document.uri);
27+
webview.update(lastResult);
28+
}
29+
}),
30+
);
1831

1932
context.subscriptions.push(
2033
vscode.commands.registerCommand('fast-java-thread.analyzeThreadDump', async () => {
@@ -45,13 +58,10 @@ export function registerCommands(
4558
vscode.commands.registerCommand('fast-java-thread.showDashboard', () => {
4659
if (!lastResult) {
4760
const editor = vscode.window.activeTextEditor;
48-
if (editor) {
61+
if (editor && editor.document.uri.fsPath.endsWith('.tdump')) {
4962
const text = editor.document.getText();
5063
lastResult = analyze(text, output);
5164
treeProvider.update(lastResult.dump.threads, editor.document.uri);
52-
} else {
53-
vscode.window.showWarningMessage('No thread dump analyzed yet. Open and analyze a .tdump file first.');
54-
return;
5565
}
5666
}
5767
webview.show(lastResult);
@@ -74,6 +84,3 @@ function analyze(text: string, output: vscode.OutputChannel): AnalysisResult {
7484
return { dump, stateGroups, hotMethods, deadlocks };
7585
}
7686

77-
export function getLastResult(): AnalysisResult | undefined {
78-
return lastResult;
79-
}

src/extension.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,28 @@ export function activate(context: vscode.ExtensionContext): void {
2020
context.subscriptions.push(
2121
vscode.window.onDidChangeActiveTextEditor(editor => {
2222
if (editor && editor.document.uri.fsPath.endsWith('.tdump')) {
23-
const text = editor.document.getText();
24-
const dump = parseThreadDump(text);
25-
treeProvider.update(dump.threads, editor.document.uri);
26-
output.appendLine(`Auto-parsed ${dump.threads.length} threads from ${editor.document.uri.fsPath}`);
23+
try {
24+
const text = editor.document.getText();
25+
const dump = parseThreadDump(text);
26+
treeProvider.update(dump.threads, editor.document.uri);
27+
output.appendLine(`Auto-parsed ${dump.threads.length} threads from ${editor.document.uri.fsPath}`);
28+
} catch (err) {
29+
output.appendLine(`Failed to parse thread dump: ${err}`);
30+
}
2731
}
2832
}),
2933
);
3034

3135
// Parse if already open
3236
const activeEditor = vscode.window.activeTextEditor;
3337
if (activeEditor && activeEditor.document.uri.fsPath.endsWith('.tdump')) {
34-
const text = activeEditor.document.getText();
35-
const dump = parseThreadDump(text);
36-
treeProvider.update(dump.threads, activeEditor.document.uri);
38+
try {
39+
const text = activeEditor.document.getText();
40+
const dump = parseThreadDump(text);
41+
treeProvider.update(dump.threads, activeEditor.document.uri);
42+
} catch (err) {
43+
output.appendLine(`Failed to parse thread dump: ${err}`);
44+
}
3745
}
3846

3947
output.appendLine('Fast Java Thread extension activated');

0 commit comments

Comments
 (0)