[extension] Run java files

This commit is contained in:
orosmatthew 2023-05-07 16:30:42 -04:00
parent a4c0258d3f
commit 8ace5a0061
5 changed files with 160 additions and 5 deletions

View File

@ -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"
}
}
},

View File

@ -4,9 +4,14 @@ 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<BWContestSettings>('BWContest')!;
}
function closeAllWorkspaces() {

View File

@ -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 {
/**
@ -36,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'),
@ -101,6 +106,33 @@ 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');

View File

@ -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<string> {
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);
});
});
}

View File

@ -8,15 +8,21 @@
type ProblemData = {
id: number,
name: string,
pascalName: string,
sampleInput: string,
sampleOutput: string
}[];
let savedInputs: Map<number, {input: string, output: string}> = new Map();
let activeProblem: ProblemData[0];
let sessionToken: string | undefined;
let problemData: ProblemData | undefined;
let sampleInputText: HTMLTextAreaElement;
let outputText: HTMLTextAreaElement;
let running = false;
$: if (problemData && problemData.length !== 0) {
let first = problemData.at(0);
@ -29,12 +35,34 @@
sampleInputText.value = activeProblem.sampleInput;
}
let contestId: number | undefined;
let teamId: number | undefined;
function onRun() {
if (!running && contestId && teamId) {
postMessage({type: 'onRun', value: {problemPascalName: activeProblem.pascalName, contestId: contestId, teamId: teamId, input: sampleInputText.value}});
running = true;
}
}
function updateTextBoxes() {
if (savedInputs.has(activeProblem.id)) {
sampleInputText.value = savedInputs.get(activeProblem.id)!.input;
outputText.value = savedInputs.get(activeProblem.id)!.output;
} else {
sampleInputText.value = activeProblem.sampleInput;
outputText.value = "[Run to get output]";
}
}
async function fetchProblemData() {
if (sessionToken) {
const res = await fetch(`http://localhost:5173/api/contest/${sessionToken}`);
const data = await res.json();
if (data.success === true) {
problemData = data.problems as ProblemData;
contestId = data.contestId;
teamId = data.teamId;
}
}
}
@ -45,7 +73,11 @@
if (message.value !== "") {
sessionToken = message.value;
await fetchProblemData();
updateTextBoxes();
}
} else if (message.type === 'onOutput') {
outputText.value = message.value;
running = false;
}
})
@ -61,7 +93,11 @@
<div class="tab-container">
{#each problemData as problem}
<button on:click={() => {
activeProblem = problem;
if (!running) {
savedInputs.set(activeProblem.id, {input: sampleInputText.value, output: outputText.value});
activeProblem = problem;
updateTextBoxes();
}
}} id={`problem_${problem.id}`} type="button" class={"tab " + (activeProblem.id == problem.id ? "active" : "")}>{problem.name}</button>
{/each}
</div>
@ -72,12 +108,18 @@
<div style="display:flex">
<div style="flex:1; margin-right:20px">
<h3>Sample Input (You can edit this!)</h3>
<textarea bind:this={sampleInputText}>{activeProblem.sampleInput}</textarea>
<textarea bind:this={sampleInputText} />
<button style="margin-top:5px" on:click={resetInput} type="button">Reset Input</button>
</div>
<div style="flex:1">
<h3>Output</h3>
<textarea disabled>{activeProblem.sampleOutput}</textarea>
<div style="display:flex">
<h3 style="margin-right:5px">Output</h3>
{#if running}
<span class="loader"></span>
{/if}
</div>
<textarea bind:this={outputText} disabled />
<button style="margin-top:5px" on:click={onRun} type="button">Run</button>
</div>
</div>
{/if}
@ -107,4 +149,24 @@
.tab.active {
background-color: rgb(95, 103, 118);
}
.loader {
width: 16px;
height: 16px;
border: 3px solid #FFF;
border-bottom-color: transparent;
border-radius: 50%;
display: inline-block;
box-sizing: border-box;
animation: rotation 1s linear infinite;
}
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>