[extension] Run java files
This commit is contained in:
parent
a4c0258d3f
commit
8ace5a0061
@ -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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -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() {
|
||||
|
@ -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');
|
||||
|
||||
|
51
extension/bwcontest/src/run/java.ts
Normal file
51
extension/bwcontest/src/run/java.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
}
|
@ -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>
|
Loading…
Reference in New Issue
Block a user