diff --git a/README.md b/README.md index 1fe7fae..2c7d003 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://img.shields.io/github/workflow/status/mfornet/acmx/vscode-ext-test)](https://img.shields.io/github/workflow/status/mfornet/acmx/vscode-ext-test) [![Visual Studio Marketplace Installs](https://img.shields.io/visual-studio-marketplace/i/marx24.acmx)](https://marketplace.visualstudio.com/items?itemName=marx24.acmx) [![Telegram chat](https://img.shields.io/badge/telegram-chat-blue?logo=telegram)](https://t.me/acm_x) [![Version](https://img.shields.io/github/package-json/v/mfornet/acmx?color=green&logo=visual-studio-code&logoColor=blue)](https://github.com/mfornet/acmx/releases) -**acmX** is tool that empower contestants to solve competitive programming problems easily. +**acmX** is a tool that empower contestants to solve competitive programming problems easily. ### Features diff --git a/package.json b/package.json index 8b1470b..a795fc6 100644 --- a/package.json +++ b/package.json @@ -44,25 +44,25 @@ }, "acmx.execution.showRunIconInEditorTitleMenu": { "type": "boolean", - "default": true, + "default": false, "description": "Whether to show 'Run File' icon in editor title menu.", "scope": "resource" }, "acmx.execution.showCompileIconInEditorTitleMenu": { "type": "boolean", - "default": true, + "default": false, "description": "Whether to show 'Compile File' icon in editor title menu.", "scope": "resource" }, "acmx.execution.showUpgradeIconInEditorTitleMenu": { "type": "boolean", - "default": true, + "default": false, "description": "Whether to show 'Upgrade' icon in editor title menu.", "scope": "resource" }, "acmx.execution.showStressIconInEditorTitleMenu": { "type": "boolean", - "default": true, + "default": false, "description": "Whether to show 'Upgrade' icon in editor title menu.", "scope": "resource" }, @@ -164,6 +164,10 @@ "command": "acmx.coding", "title": "ACMX: View: Code" }, + { + "command": "acmx.editLanguage", + "title": "ACMX: Edit Language" + }, { "command": "acmx.stress", "title": "ACMX: Stress", diff --git a/src/companion.ts b/src/companion.ts index 09b6b6a..30706f1 100644 --- a/src/companion.ts +++ b/src/companion.ts @@ -24,11 +24,21 @@ export function startCompetitiveCompanionService() { const data = req.body; res.sendStatus(200); - let contestPath = newProblemFromCompanion(data); - await vscode.commands.executeCommand( - "vscode.openFolder", - vscode.Uri.file(contestPath) + let problmeInContest = newProblemFromCompanion(data); + + let contestPath = problmeInContest.contestPath; + let mainSolution = problmeInContest.problemConfig.mainSolution.unwrapOr( + "" ); + + await vscode.commands + .executeCommand("vscode.openFolder", vscode.Uri.file(contestPath)) + .then(async () => { + await vscode.commands.executeCommand( + "vscode.open", + vscode.Uri.file(mainSolution) + ); + }); }); app.listen(port, (err: any) => { diff --git a/src/core.ts b/src/core.ts index ea9a964..1555f2b 100644 --- a/src/core.ts +++ b/src/core.ts @@ -27,6 +27,7 @@ import { ConfigFile, CHECKER_BINARY, GENERATED_TEST_CASE, + ProblemInContest, } from "./primitives"; import { substituteArgWith, @@ -166,6 +167,10 @@ export function globalHomePath(testPath?: string): string { return path; } +export function globalLanguagePath() { + return join(globalHomePath(), LANGUAGES); +} + /** * Initialize acmx environment. */ @@ -175,7 +180,7 @@ export function initAcmX(testPath?: string) { createFolder(globalHome); // Copy default languages config - let languagesFolder = join(globalHome, LANGUAGES); + let languagesFolder = globalLanguagePath(); let languageStaticFolder = join(pathToStatic(), LANGUAGES); // TODO: Check for each languages, and copy if don't exist. // Rationale: If we add a new language by default, users that already have this @@ -269,7 +274,7 @@ function populateMainSolution(path: string, override: boolean): string { return copyFromTemplate(path, templatePath, override); } -export function newArena(path: string) { +export function newArena(path: string): ConfigFile { debug("newArena", `path: ${path}`); createFolder(path); @@ -286,6 +291,8 @@ export function newArena(path: string) { } config.dump(path); + + return config; } export function testCasesName(path: string) { @@ -403,8 +410,12 @@ function copyDefaultFilesToWorkspace(path: string) { } } -function newProblem(path: string, problem: Problem, isWorkspace: boolean) { - newArena(path); +function newProblem( + path: string, + problem: Problem, + isWorkspace: boolean +): ConfigFile { + let config = newArena(path); if (isWorkspace) { copyDefaultFilesToWorkspace(path); @@ -421,6 +432,8 @@ function newProblem(path: string, problem: Problem, isWorkspace: boolean) { writeSync(fd, value); closeSync(fd); }); + + return config; } export function newProblemFromId( @@ -455,6 +468,13 @@ export function getSolutionPath() { return path; } +/** + * Create new problem with configuration from competitive companion. + * + * @param config Json file with all data received from competitive companion. + * + * TODO: Change type of config(any) to a class with explicit arguments. + */ export function newProblemFromCompanion(config: any) { let path = getSolutionPath(); @@ -472,13 +492,13 @@ export function newProblemFromCompanion(config: any) { copyDefaultFilesToWorkspace(contestPath); - newProblem( + let problemConfig = newProblem( problemPath, new Problem(config.name, config.name, inputs, outputs), false ); - return contestPath; + return new ProblemInContest(problemConfig, contestPath); } /** diff --git a/src/extension.ts b/src/extension.ts index 2b013ef..411fb5a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -24,6 +24,7 @@ import { testSolution, upgradeArena, mainSolution, + globalLanguagePath, } from "./core"; import { SiteDescription, @@ -61,15 +62,6 @@ async function addProblem() { "vscode.openFolder", vscode.Uri.file(problemPath) ); - - // TODO(#42): Run two commands below - // await vscode.commands.executeCommand( - // "vscode.open", - // vscode.Uri.file(mainSolution(problemPath)) - // ); - // vscode.window.showInformationMessage( - // `Add problem ${site}/${id} at ${path}` - // ); } function parseNumberOfProblems(numberOfProblems: string | undefined) { @@ -367,34 +359,38 @@ async function stress() { let path = path_.unwrap(); - let stressTimes: number | undefined = vscode.workspace + let _stressTimes: number | undefined = vscode.workspace .getConfiguration("acmx.stress", null) .get("times"); - // Use default - if (stressTimes === undefined) { - stressTimes = 10; + // Default stress times is 10 + let stressTimes = 10; + + if (_stressTimes !== undefined) { + stressTimes = _stressTimes; } - let result_ = stressSolution(path, stressTimes); + await vscode.window.activeTextEditor?.document.save().then(() => { + let result_ = stressSolution(path, stressTimes); - if (result_.isNone()) { - return; - } + if (result_.isNone()) { + return; + } - let result = result_.unwrap(); + let result = result_.unwrap(); - if (result.isOk()) { - vscode.window.showInformationMessage( - `OK. Time ${result.getMaxTime()}ms` - ); - } else { - let failTestCaseId = result.getFailTestCaseId(); - vscode.window.showErrorMessage( - `${verdictName(result.status)} on test ${failTestCaseId}` - ); - debugTestCase(path, failTestCaseId); - } + if (result.isOk()) { + vscode.window.showInformationMessage( + `OK. Time ${result.getMaxTime()}ms` + ); + } else { + let failTestCaseId = result.getFailTestCaseId(); + vscode.window.showErrorMessage( + `${verdictName(result.status)} on test ${failTestCaseId}` + ); + debugTestCase(path, failTestCaseId); + } + }); } async function upgrade() { @@ -521,6 +517,34 @@ async function copySubmissionToClipboard() { vscode.window.showInformationMessage("Submission copied to clipboard!"); } +async function editLanguage() { + let languages: any[] = []; + + readdirSync(globalLanguagePath()) + .filter(function (testCasePath) { + return extname(testCasePath) === ".json"; + }) + .map(function (testCasePath) { + let name = removeExtension(testCasePath); + + languages.push({ + label: name, + target: testCasePath, + }); + }); + + let selectedLanguage = await vscode.window.showQuickPick(languages, { + placeHolder: "Select language", + }); + + if (selectedLanguage !== undefined) { + await vscode.commands.executeCommand( + "vscode.open", + vscode.Uri.file(join(globalLanguagePath(), selectedLanguage.target)) + ); + } +} + async function debugTest() { vscode.window.showInformationMessage(String.fromCharCode(65)); } @@ -573,6 +597,10 @@ export function activate(context: vscode.ExtensionContext) { "acmx.copyToClipboard", copySubmissionToClipboard ); + let editLanguageCommand = vscode.commands.registerCommand( + "acmx.editLanguage", + editLanguage + ); let debugTestCommand = vscode.commands.registerCommand( "acmx.debugTest", @@ -591,6 +619,7 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(setCheckerCommand); context.subscriptions.push(selectDebugTestCaseCommand); context.subscriptions.push(copySubmissionToClipboardCommand); + context.subscriptions.push(editLanguageCommand); context.subscriptions.push(debugTestCommand); } diff --git a/src/primitives.ts b/src/primitives.ts index 63991a7..68d16ad 100644 --- a/src/primitives.ts +++ b/src/primitives.ts @@ -364,6 +364,16 @@ export class ConfigFile { } } +export class ProblemInContest { + problemConfig: ConfigFile; + contestPath: string; + + constructor(problemConfig: ConfigFile, contestPath: string) { + this.problemConfig = problemConfig; + this.contestPath = contestPath; + } +} + export function verdictName(verdict: Verdict) { switch (verdict) { case Verdict.OK: diff --git a/src/runner.ts b/src/runner.ts index 6c1e69a..03489c4 100644 --- a/src/runner.ts +++ b/src/runner.ts @@ -1,12 +1,6 @@ import { spawnSync } from "child_process"; -import { - Execution, - LanguageCommand, - Option, - LANGUAGES, - ATTIC, -} from "./primitives"; -import { globalHomePath } from "./core"; +import { Execution, LanguageCommand, Option, ATTIC } from "./primitives"; +import { globalLanguagePath } from "./core"; import { join, basename } from "path"; import { readdirSync, readFileSync, existsSync } from "fs"; import { extension, substituteArgsWith, debug, writeToFileSync } from "./utils"; @@ -14,7 +8,7 @@ import { onCompilationError } from "./errors"; import md5File = require("md5-file"); function loadConfig(extension: string): LanguageCommand { - let languagesPath = join(globalHomePath(), LANGUAGES); + let languagesPath = globalLanguagePath(); let candidates: string[] = []; let filtered = readdirSync(languagesPath).filter((file) => {