diff --git a/extension/bwcontest/package.json b/extension/bwcontest/package.json index 74a1419..cfa80d1 100644 --- a/extension/bwcontest/package.json +++ b/extension/bwcontest/package.json @@ -24,6 +24,11 @@ "type": "string", "default": "", "description": "The path where the repos are cloned to" + }, + "BWContest.javaPath": { + "type": "string", + "default": "", + "description": "Path of java bin folder" } } }, diff --git a/extension/bwcontest/src/SidebarProvider.ts b/extension/bwcontest/src/SidebarProvider.ts index 2cc9422..4631dfb 100644 --- a/extension/bwcontest/src/SidebarProvider.ts +++ b/extension/bwcontest/src/SidebarProvider.ts @@ -1,6 +1,7 @@ import * as vscode from 'vscode'; import { getNonce } from './getNonce'; import { cloneAndOpenRepo } from './extension'; +import { BWPanel } from './problemPanel'; export class SidebarProvider implements vscode.WebviewViewProvider { _view?: vscode.WebviewView; @@ -24,6 +25,12 @@ export class SidebarProvider implements vscode.WebviewViewProvider { webviewView.webview.onDidReceiveMessage(async (data) => { switch (data.type) { + case 'onTestAndSubmit': { + if (this._context) { + BWPanel.createOrShow(this._context?.extensionUri, this._context); + } + break; + } case 'onStartup': { const token: string | undefined = this._context?.globalState.get('token'); if (token) { diff --git a/extension/bwcontest/src/extension.ts b/extension/bwcontest/src/extension.ts index 2e546f2..fc1fd1a 100644 --- a/extension/bwcontest/src/extension.ts +++ b/extension/bwcontest/src/extension.ts @@ -2,10 +2,16 @@ import * as vscode from 'vscode'; import { SidebarProvider } from './SidebarProvider'; import * as child_process from 'child_process'; import * as fs from 'fs-extra'; +import { BWPanel } from './problemPanel'; -interface BWContestSettings { +export interface BWContestSettings { repoBaseUrl: string; repoClonePath: string; + javaPath: string; +} + +export function extensionSettings(): BWContestSettings { + return vscode.workspace.getConfiguration().get('BWContest')!; } function closeAllWorkspaces() { @@ -42,7 +48,9 @@ export async function cloneAndOpenRepo(contestId: number, teamId: number) { fs.mkdirSync(`${currentSettings.repoClonePath}/BWContest/${contestId.toString()}`); } - const clonedRepoPath = `${currentSettings.repoClonePath}/BWContest/${contestId.toString()}/${repoName}`; + const clonedRepoPath = `${ + currentSettings.repoClonePath + }/BWContest/${contestId.toString()}/${repoName}`; if (fs.existsSync(clonedRepoPath)) { const confirm = await vscode.window.showWarningMessage( @@ -88,7 +96,11 @@ export function activate(context: vscode.ExtensionContext) { vscode.window.registerWebviewViewProvider('bwcontest-sidebar', sidebarProvider) ); - context.subscriptions.push(vscode.commands.registerCommand('bwcontest.helloWorld', () => {})); + context.subscriptions.push( + vscode.commands.registerCommand('bwcontest.helloWorld', () => { + BWPanel.createOrShow(context.extensionUri, context); + }) + ); context.subscriptions.push( vscode.commands.registerCommand('bwcontest.askQuestion', async () => { diff --git a/extension/bwcontest/src/BWPanel.ts b/extension/bwcontest/src/problemPanel.ts similarity index 73% rename from extension/bwcontest/src/BWPanel.ts rename to extension/bwcontest/src/problemPanel.ts index 5dcf8ee..ac4dffe 100644 --- a/extension/bwcontest/src/BWPanel.ts +++ b/extension/bwcontest/src/problemPanel.ts @@ -1,5 +1,8 @@ import * as vscode from 'vscode'; import { getNonce } from './getNonce'; +import { runJava } from './run/java'; +import { extensionSettings } from './extension'; +import { join } from 'path'; export class BWPanel { /** @@ -12,8 +15,10 @@ export class BWPanel { private readonly _panel: vscode.WebviewPanel; private readonly _extensionUri: vscode.Uri; private _disposables: vscode.Disposable[] = []; + private static _context?: vscode.ExtensionContext; - public static createOrShow(extensionUri: vscode.Uri) { + public static createOrShow(extensionUri: vscode.Uri, context: vscode.ExtensionContext) { + this._context = context; const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined; @@ -34,6 +39,8 @@ export class BWPanel { // Enable javascript in the webview enableScripts: true, + retainContextWhenHidden: true, + // And restrict the webview to only loading content from our extension's `media` directory. localResourceRoots: [ vscode.Uri.joinPath(extensionUri, 'media'), @@ -99,6 +106,44 @@ export class BWPanel { this._panel.webview.html = this._getHtmlForWebview(webview); webview.onDidReceiveMessage(async (data) => { switch (data.type) { + case 'onRun': { + if (!data.value) { + return; + } + const repoDir = extensionSettings().repoClonePath; + const output = await runJava( + join( + repoDir, + 'BWContest', + data.value.contestId.toString(), + data.value.teamId.toString(), + data.value.problemPascalName.toString() + ), + join( + repoDir, + 'BWContest', + data.value.contestId.toString(), + data.value.teamId.toString(), + data.value.problemPascalName.toString(), + `${data.value.problemPascalName}.java` + ), + data.value.problemPascalName, + data.value.input + ); + this._panel.webview.postMessage({ type: 'onOutput', value: output }); + break; + } + case 'onStartup': { + const token: string | undefined = BWPanel._context?.globalState.get('token'); + + if (token) { + this._panel.webview.postMessage({ + type: 'onSession', + value: token + }); + } + break; + } case 'onInfo': { if (!data.value) { return; @@ -125,7 +170,7 @@ export class BWPanel { private _getHtmlForWebview(webview: vscode.Webview) { // // And the uri we use to load this script in the webview const scriptUri = webview.asWebviewUri( - vscode.Uri.joinPath(this._extensionUri, 'out/compiled', 'HelloWorld.js') + vscode.Uri.joinPath(this._extensionUri, 'out/compiled', 'problemPanel.js') ); // Uri to load styles into webview @@ -135,9 +180,9 @@ export class BWPanel { const stylesMainUri = webview.asWebviewUri( vscode.Uri.joinPath(this._extensionUri, 'media', 'vscode.css') ); - // const cssUri = webview.asWebviewUri( - // vscode.Uri.joinPath(this._extensionUri, 'out', 'compiled/swiper.css') - // ); + const cssUri = webview.asWebviewUri( + vscode.Uri.joinPath(this._extensionUri, 'out/compiled', 'problemPanel.css') + ); // // Use a nonce to only allow specific scripts to be run const nonce = getNonce(); @@ -154,6 +199,10 @@ export class BWPanel { + + diff --git a/extension/bwcontest/src/run/java.ts b/extension/bwcontest/src/run/java.ts new file mode 100644 index 0000000..b03fc57 --- /dev/null +++ b/extension/bwcontest/src/run/java.ts @@ -0,0 +1,51 @@ +import * as fs from 'fs-extra'; +import { join } from 'path'; +import os = require('os'); +import { exec, spawn } from 'child_process'; +import { extensionSettings } from '../extension'; +import { error } from 'console'; +import util = require('node:util'); + +const execPromise = util.promisify(exec); + +export async function runJava( + srcDir: string, + mainFile: string, + mainClass: string, + input: string +): Promise { + const javaPath = extensionSettings().javaPath; + if (javaPath == '') { + throw error('Java path not set'); + } + const tempDir = os.tmpdir(); + const buildDir = join(tempDir, 'bwcontest_java'); + if (fs.existsSync(buildDir)) { + fs.removeSync(buildDir); + } + fs.mkdirSync(buildDir); + + const compileCommand = `${join(javaPath, 'javac')} -cp ${srcDir} ${mainFile} -d ${buildDir}`; + await execPromise(compileCommand); + + const runCommand = `${join(javaPath, 'java')} -cp "${buildDir}" ${mainClass}`; + + return new Promise((resolve) => { + let outputBuffer = ''; + const child = spawn(runCommand, { shell: true }); + child.stdout.setEncoding('utf8'); + child.stdout.on('data', (data) => { + outputBuffer += data.toString(); + }); + child.stderr.setEncoding('utf8'); + child.stderr.on('data', (data) => { + outputBuffer += data.toString(); + }); + child.stdin.write(input); + child.stdin.end(); + + child.on('close', () => { + resolve(outputBuffer); + }); + }); +} diff --git a/extension/bwcontest/webviews/components/HelloWorld.svelte b/extension/bwcontest/webviews/components/HelloWorld.svelte deleted file mode 100644 index 1ff133f..0000000 --- a/extension/bwcontest/webviews/components/HelloWorld.svelte +++ /dev/null @@ -1,4 +0,0 @@ - - -

Test!

\ No newline at end of file diff --git a/extension/bwcontest/webviews/components/ProblemPanel.svelte b/extension/bwcontest/webviews/components/ProblemPanel.svelte new file mode 100644 index 0000000..4c15cd2 --- /dev/null +++ b/extension/bwcontest/webviews/components/ProblemPanel.svelte @@ -0,0 +1,172 @@ + + +

Test & Submit Problems

+ +{#if problemData} +
+ {#each problemData as problem} + + {/each} +
+{/if} + +{#if activeProblem} +

{activeProblem.name}

+
+
+

Sample Input (You can edit this!)

+