aboutsummaryrefslogtreecommitdiff
path: root/plugin/src/runner.js
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-13 08:21:59 +0000
committer_ov4 <ov4@ov4.org>2026-10-13 08:21:59 +0000
commita33ac452ba4bcfb9e7154a23a9ea38c93ed0c38d (patch)
tree2c039610874b5b5f570ec0cf232e17a7c7938ec7 /plugin/src/runner.js
parent664e84149501a978bb5f63368c86ae2f53fe4cb8 (diff)
feat(plugin): run pseudocode files in the integrated terminal
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'plugin/src/runner.js')
-rw-r--r--plugin/src/runner.js79
1 files changed, 79 insertions, 0 deletions
diff --git a/plugin/src/runner.js b/plugin/src/runner.js
new file mode 100644
index 0000000..a327c58
--- /dev/null
+++ b/plugin/src/runner.js
@@ -0,0 +1,79 @@
+'use strict';
+
+const path = require('node:path');
+
+function quote(value, shell) {
+ if (/[\r\n\0]/.test(value)) throw new Error('Run paths must not contain line breaks or NUL characters.');
+ if (shell === 'cmd') return `"${value}"`;
+ return "'" + value.replace(/'/g, shell === 'powershell' ? "''" : "'\\''") + "'";
+}
+
+function buildRunCommand(compiler, file, cwd, shell) {
+ const run = `${shell === 'powershell' ? '& ' : ''}${quote(compiler, shell)} ${quote(file, shell)} -r`;
+ if (shell === 'powershell') return `Set-Location -LiteralPath ${quote(cwd, shell)}; if ($?) { ${run} }`;
+ return `cd ${shell === 'cmd' ? '/d ' : ''}${quote(cwd, shell)} && ${run}`;
+}
+
+// Adapted from Code Runner's isPowershellOnWindows; also recognize pwsh and named profiles.
+function terminalShell(vscode, platform) {
+ if (platform !== 'win32') return 'posix';
+ const config = vscode.workspace.getConfiguration('terminal');
+ const profileName = config.get('integrated.defaultProfile.windows');
+ const profile = config.get('integrated.profiles.windows', {})[profileName];
+ const profilePath = Array.isArray(profile?.path) ? profile.path[0] : profile?.path;
+ const shell = profilePath || profile?.source || profileName || vscode.env.shell;
+ if (/(?:powershell|pwsh)/i.test(shell)) return 'powershell';
+ if (/(?:^|[\\/])cmd(?:\.exe)?$|^Command Prompt$/i.test(shell)) return 'cmd';
+ throw new Error('Choose PowerShell or Command Prompt as the default Windows terminal profile.');
+}
+
+function registerRunner(vscode, context, platform = process.platform) {
+ let terminal = null;
+ let shell;
+ let preparing = false;
+ const command = vscode.commands.registerCommand('cie-pseudocode.runFile', async uri => {
+ if (preparing) return;
+ preparing = true;
+ try {
+ let document = uri ? await vscode.workspace.openTextDocument(uri) : vscode.window.activeTextEditor?.document;
+ if (!document || document.languageId !== 'cie-pseudocode') {
+ vscode.window.showErrorMessage('Open a CIE pseudocode file to run.');
+ return;
+ }
+ const wasUntitled = document.isUntitled;
+ if (wasUntitled) await vscode.window.showTextDocument(document);
+ if (!(await document.save())) return;
+ // Saving an untitled document replaces it with a new file-backed document.
+ if (wasUntitled) document = vscode.window.activeTextEditor?.document;
+ if (!document || document.isUntitled || document.uri.scheme !== 'file') {
+ vscode.window.showErrorMessage('Save the pseudocode to a local file before running.');
+ return;
+ }
+ const cwd = vscode.workspace.getWorkspaceFolder(document.uri)?.uri.fsPath || path.dirname(document.uri.fsPath);
+ const compiler = vscode.workspace.getConfiguration('cie-pseudocode', document.uri).get('compilerPath', 'cpsc');
+ if (!compiler.trim()) throw new Error('Set CIE Pseudocode: Compiler Path to cpsc or its full path.');
+ const runShell = terminal ? shell : terminalShell(vscode, platform);
+ const text = buildRunCommand(compiler, document.uri.fsPath, cwd, runShell);
+ // Adapted from Code Runner's executeCommandInTerminal (see ThirdPartyNotices.md).
+ if (terminal === null) {
+ terminal = vscode.window.createTerminal('CIE Pseudocode');
+ shell = runShell;
+ }
+ terminal.show(false);
+ terminal.sendText(text);
+ } catch (error) {
+ vscode.window.showErrorMessage(`Could not run pseudocode: ${error.message}`);
+ } finally {
+ preparing = false;
+ }
+ });
+ context.subscriptions.push(
+ command,
+ vscode.window.onDidCloseTerminal(closed => {
+ if (closed === terminal) terminal = null;
+ }),
+ { dispose() { terminal?.dispose(); } }
+ );
+}
+
+module.exports = { buildRunCommand, registerRunner };