bw-hspc-contest-env/extension/bwcontest/src/problemPanel.ts

227 lines
6.4 KiB
TypeScript
Raw Normal View History

2023-05-06 00:01:27 -04:00
import * as vscode from 'vscode';
import { getNonce } from './getNonce';
2023-05-07 16:30:42 -04:00
import { runJava } from './run/java';
import { extensionSettings } from './extension';
import { join } from 'path';
2023-05-08 14:37:52 -04:00
import { submitProblem } from './submit';
2023-05-06 00:01:27 -04:00
export class BWPanel {
/**
* Track the currently panel. Only allow a single panel to exist at a time.
*/
public static currentPanel: BWPanel | undefined;
public static readonly viewType = 'bwpanel';
private readonly _panel: vscode.WebviewPanel;
private readonly _extensionUri: vscode.Uri;
private _disposables: vscode.Disposable[] = [];
2023-05-07 11:01:27 -04:00
private static _context?: vscode.ExtensionContext;
2023-05-06 00:01:27 -04:00
2023-05-08 14:37:52 -04:00
public static createOrShow(context: vscode.ExtensionContext) {
2023-05-07 11:01:27 -04:00
this._context = context;
2023-05-06 00:01:27 -04:00
const column = vscode.window.activeTextEditor
? vscode.window.activeTextEditor.viewColumn
: undefined;
// If we already have a panel, show it.
if (BWPanel.currentPanel) {
BWPanel.currentPanel._panel.reveal(column);
return;
}
// Otherwise, create a new panel.
const panel = vscode.window.createWebviewPanel(
BWPanel.viewType,
'BWContest',
2023-05-06 00:01:27 -04:00
column || vscode.ViewColumn.One,
{
// Enable javascript in the webview
enableScripts: true,
2023-05-07 16:30:42 -04:00
retainContextWhenHidden: true,
2023-05-06 00:01:27 -04:00
// And restrict the webview to only loading content from our extension's `media` directory.
localResourceRoots: [
2023-05-08 14:37:52 -04:00
vscode.Uri.joinPath(context.extensionUri, 'media'),
vscode.Uri.joinPath(context.extensionUri, 'out/compiled')
2023-05-06 00:01:27 -04:00
]
}
);
2023-05-08 14:37:52 -04:00
BWPanel.currentPanel = new BWPanel(panel, context.extensionUri);
2023-05-06 00:01:27 -04:00
}
public static kill() {
BWPanel.currentPanel?.dispose();
BWPanel.currentPanel = undefined;
}
public static revive(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
BWPanel.currentPanel = new BWPanel(panel, extensionUri);
}
private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
this._panel = panel;
this._extensionUri = extensionUri;
this._update();
this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
}
public dispose() {
BWPanel.currentPanel = undefined;
this._panel.dispose();
while (this._disposables.length) {
const x = this._disposables.pop();
if (x) {
x.dispose();
}
}
}
private async _update() {
const webview = this._panel.webview;
this._panel.webview.html = this._getHtmlForWebview(webview);
webview.onDidReceiveMessage(async (data) => {
switch (data.type) {
2023-05-08 14:37:52 -04:00
case 'onSubmit': {
if (!data.value) {
return;
}
const ans = await vscode.window.showInformationMessage(
`Are you sure you want to submit ${data.value.problemName}?`,
'Yes',
'No'
);
if (ans !== 'Yes') {
break;
}
try {
await submitProblem(
data.value.sessionToken,
data.value.contestId,
data.value.teamId,
data.value.problemId
);
} catch (err: any) {
vscode.window.showErrorMessage(err.message ?? 'Submission unsuccessful');
2023-05-08 14:37:52 -04:00
break;
}
vscode.window.showInformationMessage('Submitted!');
break;
}
2023-05-07 16:30:42 -04:00
case 'onRun': {
if (!data.value) {
return;
}
const repoDir = extensionSettings().repoClonePath;
2023-05-08 14:37:52 -04:00
runJava(
2023-05-07 16:30:42 -04:00
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
)
.then((output) => {
this._panel.webview.postMessage({ type: 'onOutput', value: output });
})
.catch(() => {
this._panel.webview.postMessage({
type: 'onOutput',
value: '[An error occurred while running]'
});
});
2023-05-07 16:30:42 -04:00
break;
}
2023-05-07 11:01:27 -04:00
case 'onStartup': {
const token: string | undefined = BWPanel._context?.globalState.get('token');
if (token) {
this._panel.webview.postMessage({
type: 'onSession',
value: token
});
}
break;
}
2023-05-06 00:01:27 -04:00
case 'onInfo': {
if (!data.value) {
return;
}
vscode.window.showInformationMessage(data.value);
break;
}
case 'onError': {
if (!data.value) {
return;
}
vscode.window.showErrorMessage(data.value);
break;
}
// case "tokens": {
// await Util.globalState.update(accessTokenKey, data.accessToken);
// await Util.globalState.update(refreshTokenKey, data.refreshToken);
// break;
// }
}
});
}
private _getHtmlForWebview(webview: vscode.Webview) {
// // And the uri we use to load this script in the webview
const scriptUri = webview.asWebviewUri(
2023-05-07 11:01:27 -04:00
vscode.Uri.joinPath(this._extensionUri, 'out/compiled', 'problemPanel.js')
2023-05-06 00:01:27 -04:00
);
// Uri to load styles into webview
const stylesResetUri = webview.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, 'media', 'reset.css')
);
const stylesMainUri = webview.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, 'media', 'vscode.css')
);
2023-05-07 11:01:27 -04:00
const cssUri = webview.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, 'out/compiled', 'problemPanel.css')
);
2023-05-06 00:01:27 -04:00
// // Use a nonce to only allow specific scripts to be run
const nonce = getNonce();
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--
Use a content security policy to only allow loading images from https or from our extension directory,
and only allow scripts that have a specific nonce.
-->
<meta http-equiv="Content-Security-Policy" content="img-src https: data:; style-src 'unsafe-inline' ${webview.cspSource}; script-src 'nonce-${nonce}';">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="${stylesResetUri}" rel="stylesheet">
<link href="${stylesMainUri}" rel="stylesheet">
2023-05-07 11:01:27 -04:00
<link href="${cssUri}" rel="stylesheet">
<script nonce="${nonce}">
const vscode = acquireVsCodeApi();
</script>
2023-05-06 00:01:27 -04:00
</head>
<body>
</body>
<script src=${scriptUri} nonce="${nonce}">
</script>
</html>`;
}
}