Visual modifications and fixes

This commit is contained in:
2025-08-06 23:15:38 +02:00
parent 272812a815
commit 663c085f34
5 changed files with 105 additions and 66 deletions
+7 -7
View File
@@ -31,19 +31,19 @@
"viewsContainers": { "viewsContainers": {
"panel": [ "panel": [
{ {
"id": "myCustomPanel", "id": "speedCodeResultPanel",
"title": "My Custom Panel", "title": "Speed Code",
"icon": "$(file-code)" "icon": "./timer.svg"
} }
] ]
}, },
"views": { "views": {
"myCustomPanel": [ "speedCodeResultPanel": [
{ {
"type": "tree", "type": "tree",
"id": "myCustomTab", "id": "speedCodeResultTab",
"name": "My Tab", "name": "Speed Code",
"icon": "$(file-code)" "icon": "./timer.svg"
} }
] ]
} }
+28 -5
View File
@@ -28,6 +28,12 @@ function isPalindrome(s) {
} }
`; `;
const treeDataProvider = new MyTreeDataProvider();
const treeView = vscode.window.createTreeView("speedCodeResultTab", {
treeDataProvider,
});
export function activate(context: vscode.ExtensionContext) { export function activate(context: vscode.ExtensionContext) {
const statusBarItem = vscode.window.createStatusBarItem( const statusBarItem = vscode.window.createStatusBarItem(
vscode.StatusBarAlignment.Left, vscode.StatusBarAlignment.Left,
@@ -45,10 +51,6 @@ export function activate(context: vscode.ExtensionContext) {
timer: NodeJS.Timeout; timer: NodeJS.Timeout;
}; };
const treeDataProvider = new MyTreeDataProvider();
vscode.window.registerTreeDataProvider("myCustomTab", treeDataProvider);
resetTimer = () => { resetTimer = () => {
if (run) { if (run) {
clearInterval(run.timer); clearInterval(run.timer);
@@ -58,6 +60,7 @@ export function activate(context: vscode.ExtensionContext) {
}; };
resetTimer(); resetTimer();
updateTreeMessage();
context.subscriptions.push( context.subscriptions.push(
vscode.commands.registerCommand("speed-code.submitSpeedRun", () => { vscode.commands.registerCommand("speed-code.submitSpeedRun", () => {
@@ -84,6 +87,7 @@ export function activate(context: vscode.ExtensionContext) {
} }
treeDataProvider.refresh(); treeDataProvider.refresh();
updateTreeMessage();
} catch (e) { } catch (e) {
treeDataProvider.blunders.push([run.elapsed, String(e)]); treeDataProvider.blunders.push([run.elapsed, String(e)]);
} }
@@ -96,6 +100,7 @@ export function activate(context: vscode.ExtensionContext) {
treeDataProvider.testSummary = undefined; treeDataProvider.testSummary = undefined;
treeDataProvider.testResults = []; treeDataProvider.testResults = [];
treeDataProvider.blunders = []; treeDataProvider.blunders = [];
updateTreeMessage();
const runFilePath = path.join(speedCodePath, "isPalindrome.js"); const runFilePath = path.join(speedCodePath, "isPalindrome.js");
fs.writeFileSync(runFilePath, ""); fs.writeFileSync(runFilePath, "");
openAndFocusFile(runFilePath); openAndFocusFile(runFilePath);
@@ -119,7 +124,13 @@ export function activate(context: vscode.ExtensionContext) {
); );
context.subscriptions.push( context.subscriptions.push(
vscode.commands.registerCommand("speed-code.cancelSpeedRun", resetTimer), vscode.commands.registerCommand("speed-code.cancelSpeedRun", () => {
resetTimer();
treeDataProvider.testSummary = undefined;
treeDataProvider.testResults = [];
treeDataProvider.blunders = [];
treeDataProvider.refresh();
}),
statusBarItem statusBarItem
); );
} }
@@ -127,3 +138,15 @@ export function activate(context: vscode.ExtensionContext) {
export function deactivate() { export function deactivate() {
resetTimer(); resetTimer();
} }
function updateTreeMessage() {
if (
!treeDataProvider.testResults.length &&
!treeDataProvider.blunders.length &&
!treeDataProvider.testSummary
) {
treeView.message = "No results yet. Start a speedrun!";
} else {
treeView.message = "";
}
}
+47 -38
View File
@@ -1,42 +1,51 @@
import vm from 'vm'; import vm from "vm";
import assert from 'assert'; import assert from "assert";
export interface TestCase { input: any[], expected: any }; export interface TestCase {
export interface TestResult extends TestCase { result: any, valid: boolean }; input: any[];
expected: any;
export default function testCode(code: string, testCases: TestCase[]): [boolean, TestResult[]] { }
const context: Record<string, any> = {}; export interface TestResult extends TestCase {
vm.createContext(context); result: any;
valid: boolean;
const beforeKeys = new Set(Object.keys(context)); }
const script = new vm.Script(code); export default function testCode(
script.runInContext(context); code: string,
testCases: TestCase[]
const afterKeys = Object.keys(context); ): [boolean, TestResult[]] {
const newKeys = afterKeys.filter(k => !beforeKeys.has(k)); const context: Record<string, any> = {};
vm.createContext(context);
// Find the last function defined
const funcs = newKeys const beforeKeys = new Set(Object.keys(context));
.map(k => context[k])
.filter(v => typeof v === 'function'); const script = new vm.Script(code);
script.runInContext(context);
if (funcs.length === 0) {
throw new Error("No function was defined in the code."); const afterKeys = Object.keys(context);
const newKeys = afterKeys.filter((k) => !beforeKeys.has(k));
// Find the last function defined
const funcs = newKeys
.map((k) => context[k])
.filter((v) => typeof v === "function");
if (funcs.length === 0) {
throw new Error("No function was defined in the code.");
}
const targetFn = funcs[funcs.length - 1];
const tests = testCases.map((t) => {
const result = targetFn(...t.input);
try {
assert.strictEqual(result, t.expected);
return { ...t, valid: true, result };
} catch {
return { ...t, valid: false, result };
} }
});
const targetFn = funcs[funcs.length - 1];
const tests = testCases.map((t) => {
const result = targetFn(...t.input);
try {
assert.strictEqual(result, t.expected);
return { ...t, valid: true, result };
} catch {
return { ...t, valid: false, result };
}
});
return [tests.every(t => t.valid), tests]; return [tests.every((t) => t.valid), tests];
} }
+22 -16
View File
@@ -1,17 +1,23 @@
export function format(timeSeconds: number): string { export function format(timeSeconds: number): string {
if (timeSeconds > 86400) { if (timeSeconds > 86400) {
const days = Math.floor(timeSeconds / 86400); const days = Math.floor(timeSeconds / 86400);
const hours = Math.floor(timeSeconds / 3600); const hours = Math.floor(timeSeconds / 3600);
const minutes = Math.floor(timeSeconds / 60); const minutes = Math.floor(timeSeconds / 60);
return `${days}:${hours - (days * 24)}:${minutes - (hours * 60)}:${(timeSeconds - (minutes * 60)).toFixed(3)}`; return `${days}:${hours - days * 24}:${minutes - hours * 60}:${(
} else if (timeSeconds >= 3600) { timeSeconds -
const hours = Math.floor(timeSeconds / 3600); minutes * 60
const minutes = Math.floor(timeSeconds / 60); ).toFixed(3)}`;
return `${hours}:${minutes - (hours * 60)}:${(timeSeconds - (minutes * 60)).toFixed(3)}`; } else if (timeSeconds >= 3600) {
} else if (timeSeconds >= 60) { const hours = Math.floor(timeSeconds / 3600);
const minutes = Math.floor(timeSeconds / 60); const minutes = Math.floor(timeSeconds / 60);
return `${minutes}:${(timeSeconds - (minutes * 60)).toFixed(3)}`; return `${hours}:${minutes - hours * 60}:${(
} else { timeSeconds -
return `${timeSeconds}`; minutes * 60
} ).toFixed(3)}`;
} } else if (timeSeconds >= 60) {
const minutes = Math.floor(timeSeconds / 60);
return `${minutes}:${(timeSeconds - minutes * 60).toFixed(3)}`;
} else {
return `${timeSeconds}`;
}
}
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-timer-icon lucide-timer"><line x1="10" x2="14" y1="2" y2="2"/><line x1="12" x2="15" y1="14" y2="11"/><circle cx="12" cy="14" r="8"/></svg>

After

Width:  |  Height:  |  Size: 340 B