From 17bb94f7b5f20fcf417241b8db1fe07176509ccf Mon Sep 17 00:00:00 2001 From: Yusuf Salk Date: Thu, 15 Jan 2026 10:03:44 +0300 Subject: [PATCH 1/4] fix: robustly convert Windows paths to WSL format --- src/transforms/windowsPathToWsl.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/transforms/windowsPathToWsl.ts b/src/transforms/windowsPathToWsl.ts index cf7237a8..4e1039a7 100644 --- a/src/transforms/windowsPathToWsl.ts +++ b/src/transforms/windowsPathToWsl.ts @@ -1,10 +1,9 @@ import { join } from "path/posix"; -import { sep } from "path"; export default (windowsPath: string) => { const driveLetter = windowsPath[0].toLowerCase(); const posixyPath = windowsPath.replace(/^[^:]*:/, "") //remove drive letter - .split(sep).join("/"); //force / as separator + .replace(/\\/g, "/"); //force / as separator return join("/mnt/", driveLetter, posixyPath); } \ No newline at end of file From 9511e7659b2466bac2e0277f6a582ca38310e4b2 Mon Sep 17 00:00:00 2001 From: Yusuf Salk Date: Thu, 15 Jan 2026 10:03:55 +0300 Subject: [PATCH 2/4] fix: sanitize command args and conditionalize C++ std flag --- src/executors/ClingExecutor.ts | 2 +- src/executors/CppExecutor.ts | 3 ++- src/executors/LatexExecutor.ts | 2 +- src/executors/NodeJSExecutor.ts | 5 +---- src/executors/NonInteractiveCodeExecutor.ts | 2 +- src/executors/PowerShellOnWindowsExecutor.ts | 2 +- src/executors/RExecutor.ts | 2 +- src/executors/python/PythonExecutor.ts | 2 +- 8 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/executors/ClingExecutor.ts b/src/executors/ClingExecutor.ts index 1585c682..2392cf38 100644 --- a/src/executors/ClingExecutor.ts +++ b/src/executors/ClingExecutor.ts @@ -29,7 +29,7 @@ export default abstract class ClingExecutor extends NonInteractiveCodeExecutor { // Run code without a main block (cling only) return new Promise((resolve, reject) => { - const childArgs = [...args.split(" "), ...codeBlockContent.split("\n")]; + const childArgs = [...args.split(" ").filter(arg => arg.length > 0), ...codeBlockContent.split("\n")]; const child = child_process.spawn(this.settings.clingPath, childArgs, {env: process.env, shell: this.usesShell}); // Set resolve callback to resolve the promise in the child_process.on('close', ...) listener from super.handleChildOutput this.resolveRun = resolve; diff --git a/src/executors/CppExecutor.ts b/src/executors/CppExecutor.ts index 8232f24e..de7a54dd 100644 --- a/src/executors/CppExecutor.ts +++ b/src/executors/CppExecutor.ts @@ -9,6 +9,7 @@ export default class CppExecutor extends ClingExecutor { } override run(codeBlockContent: string, outputter: Outputter, cmd: string, cmdArgs: string, ext: string) { - return super.run(codeBlockContent, outputter, cmd, `-std=${this.settings.clingStd} ${cmdArgs}`, "cpp"); + const args = this.settings.clingStd ? `-std=${this.settings.clingStd} ${cmdArgs}` : cmdArgs; + return super.run(codeBlockContent, outputter, cmd, args, "cpp"); } } diff --git a/src/executors/LatexExecutor.ts b/src/executors/LatexExecutor.ts index 18da6527..05245402 100644 --- a/src/executors/LatexExecutor.ts +++ b/src/executors/LatexExecutor.ts @@ -93,7 +93,7 @@ export default class LaTeXExecutor extends NonInteractiveCodeExecutor { private async compileAndRerun(compilerPath: string, args: string, exec: ExecutionContext): Promise { for (let attempt = 0; attempt <= MAX_COMPILER_RERUNS; attempt++) { const isLastAttempt = attempt == MAX_COMPILER_RERUNS; - const result = await this.runChildProcess(compilerPath, args.split(' '), 'o.pdf', exec, { skipWriteFileLink: true, outFileArg: "", doDetectRerun: !isLastAttempt }); + const result = await this.runChildProcess(compilerPath, args.split(' ').filter(arg => arg.length > 0), 'o.pdf', exec, { skipWriteFileLink: true, outFileArg: "", doDetectRerun: !isLastAttempt }); const hasRequestedRerun = result === undefined; if (!hasRequestedRerun) return result; } diff --git a/src/executors/NodeJSExecutor.ts b/src/executors/NodeJSExecutor.ts index 24011ebd..d14a8abb 100644 --- a/src/executors/NodeJSExecutor.ts +++ b/src/executors/NodeJSExecutor.ts @@ -8,10 +8,7 @@ export default class NodeJSExecutor extends ReplExecutor { process: ChildProcessWithoutNullStreams constructor(settings: ExecutorSettings, file: string) { - const args = settings.nodeArgs ? settings.nodeArgs.split(" ") : []; - - args.unshift(`-e`, `require("repl").start({prompt: "", preview: false, ignoreUndefined: true}).on("exit", ()=>process.exit())`); - + const args = settings.nodeArgs ? settings.nodeArgs.split(" ").filter(arg => arg.length > 0) : []; super(settings, settings.nodePath, args, file, "js"); } diff --git a/src/executors/NonInteractiveCodeExecutor.ts b/src/executors/NonInteractiveCodeExecutor.ts index 465a4c3f..b6bdf308 100644 --- a/src/executors/NonInteractiveCodeExecutor.ts +++ b/src/executors/NonInteractiveCodeExecutor.ts @@ -36,7 +36,7 @@ export default class NonInteractiveCodeExecutor extends Executor { const tempFileName = this.getTempFile(ext); fs.promises.writeFile(tempFileName, codeBlockContent).then(() => { - const args = cmdArgs ? cmdArgs.split(" ") : []; + const args = cmdArgs ? cmdArgs.split(" ").filter(arg => arg.length > 0) : []; if (this.isWSLEnabled()) { args.unshift("-e", cmd); diff --git a/src/executors/PowerShellOnWindowsExecutor.ts b/src/executors/PowerShellOnWindowsExecutor.ts index 6285aa91..33312055 100644 --- a/src/executors/PowerShellOnWindowsExecutor.ts +++ b/src/executors/PowerShellOnWindowsExecutor.ts @@ -35,7 +35,7 @@ export default class PowerShellOnWindowsExecutor extends NonInteractiveCodeExecu const tempFileName = this.getTempFile(ext); fs.promises.writeFile(tempFileName, codeBlockContent, this.settings.powershellEncoding).then(() => { - const args = cmdArgs ? cmdArgs.split(" ") : []; + const args = cmdArgs ? cmdArgs.split(" ").filter(arg => arg.length > 0) : []; if (this.settings.wslMode) { args.unshift("-e", cmd); diff --git a/src/executors/RExecutor.ts b/src/executors/RExecutor.ts index 8319aac7..aaac033f 100644 --- a/src/executors/RExecutor.ts +++ b/src/executors/RExecutor.ts @@ -11,7 +11,7 @@ export default class RExecutor extends ReplExecutor { constructor(settings: ExecutorSettings, file: string) { //use empty array for empty string, instead of [""] - const args = settings.RArgs ? settings.RArgs.split(" ") : []; + const args = settings.RArgs ? settings.RArgs.split(" ").filter(arg => arg.length > 0) : []; let conArgName = `notebook_connection_${Math.random().toString(16).substring(2)}`; diff --git a/src/executors/python/PythonExecutor.ts b/src/executors/python/PythonExecutor.ts index cbdc052f..34723985 100644 --- a/src/executors/python/PythonExecutor.ts +++ b/src/executors/python/PythonExecutor.ts @@ -27,7 +27,7 @@ export default class PythonExecutor extends ReplExecutor { constructor(settings: ExecutorSettings, file: string) { - const args = settings.pythonArgs ? settings.pythonArgs.split(" ") : []; + const args = settings.pythonArgs ? settings.pythonArgs.split(" ").filter(arg => arg.length > 0) : []; args.unshift("-i"); From 8425e3f371224f6a2275203f7c447807e001c8d3 Mon Sep 17 00:00:00 2001 From: Yusuf Salk Date: Thu, 15 Jan 2026 11:55:45 +0300 Subject: [PATCH 3/4] fix: use stdin for Cling execution without main to support WSL --- src/executors/ClingExecutor.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/executors/ClingExecutor.ts b/src/executors/ClingExecutor.ts index 2392cf38..726e4857 100644 --- a/src/executors/ClingExecutor.ts +++ b/src/executors/ClingExecutor.ts @@ -29,11 +29,21 @@ export default abstract class ClingExecutor extends NonInteractiveCodeExecutor { // Run code without a main block (cling only) return new Promise((resolve, reject) => { - const childArgs = [...args.split(" ").filter(arg => arg.length > 0), ...codeBlockContent.split("\n")]; - const child = child_process.spawn(this.settings.clingPath, childArgs, {env: process.env, shell: this.usesShell}); + const childArgs = args.split(" ").filter(arg => arg.length > 0); + + let cmd = this.settings.clingPath; + if (this.settings.wslMode) { + childArgs.unshift("-e", cmd); + cmd = "wsl"; + } + + const child = child_process.spawn(cmd, childArgs, {env: process.env, shell: this.usesShell}); // Set resolve callback to resolve the promise in the child_process.on('close', ...) listener from super.handleChildOutput this.resolveRun = resolve; this.handleChildOutput(child, outputter, this.tempFileId); + + child.stdin.write(codeBlockContent); + child.stdin.end(); }); } From e3be636c37b7cb85ba1da1ba7ded5d558ebe6301 Mon Sep 17 00:00:00 2001 From: goddamnparticle Date: Thu, 15 Jan 2026 13:51:02 +0300 Subject: [PATCH 4/4] fix: suppress Cling startup banner with --nologo --- src/executors/ClingExecutor.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/executors/ClingExecutor.ts b/src/executors/ClingExecutor.ts index 726e4857..d3cf5f2b 100644 --- a/src/executors/ClingExecutor.ts +++ b/src/executors/ClingExecutor.ts @@ -30,6 +30,9 @@ export default abstract class ClingExecutor extends NonInteractiveCodeExecutor { // Run code without a main block (cling only) return new Promise((resolve, reject) => { const childArgs = args.split(" ").filter(arg => arg.length > 0); + if (!childArgs.includes("--nologo")) { + childArgs.push("--nologo"); + } let cmd = this.settings.clingPath; if (this.settings.wslMode) {