diff --git a/src/executors/CExecutor.ts b/src/executors/CExecutor.ts index c0d143b..ec857f1 100644 --- a/src/executors/CExecutor.ts +++ b/src/executors/CExecutor.ts @@ -9,6 +9,11 @@ export default class CExecutor extends ClingExecutor { } override run(codeBlockContent: string, outputter: Outputter, cmd: string, cmdArgs: string, ext: string) { - return super.run(codeBlockContent, outputter, cmd, `-x c ${cmdArgs}`, "cpp"); + const install_path = this.settings[`clingPath`]; + if (install_path.endsWith("cling") || install_path.endsWith("cling.exe")) { + return super.run(codeBlockContent, outputter, cmd, this.settings[`cArgs`], "cpp"); + } else { + return super.run(codeBlockContent, outputter, cmd, this.settings[`cArgs`], "c"); + } } } diff --git a/src/executors/ClingExecutor.ts b/src/executors/ClingExecutor.ts index 54813eb..2da6f66 100644 --- a/src/executors/ClingExecutor.ts +++ b/src/executors/ClingExecutor.ts @@ -13,18 +13,21 @@ export default abstract class ClingExecutor extends NonInteractiveCodeExecutor { } override run(codeBlockContent: string, outputter: Outputter, cmd: string, args: string, ext: string) { - // Run code with a main block if (this.settings[`${this.language}UseMain`]) { // Generate a new temp file id and don't set to undefined to super.run() uses the same file id this.getTempFile(ext); - // Cling expects the main function to have the same name as the file - const code = codeBlockContent.replace(/main\(\)/g, `temp_${this.tempFileId}()`); - + // Cling expects the main function to have the same name as the file / the extension is only c when gcc is used + let code: string; + if (ext != "c") { + code = codeBlockContent.replace(/main\(\)/g, `temp_${this.tempFileId}()`); + } else { + code = codeBlockContent; + } return super.run(code, outputter, this.settings.clingPath, args, ext); } - // Run code without a main block + // Run code without a main block (cling only) return new Promise((resolve, reject) => { const childArgs = [...args.split(" "), ...codeBlockContent.split("\n")]; const child = child_process.spawn(this.settings.clingPath, childArgs, {env: process.env, shell: this.usesShell}); diff --git a/src/executors/Executor.ts b/src/executors/Executor.ts index 15c2a43..954e2cc 100644 --- a/src/executors/Executor.ts +++ b/src/executors/Executor.ts @@ -63,6 +63,6 @@ export default abstract class Executor extends EventEmitter { protected getTempFile(ext: string) { if (this.tempFileId === undefined) this.tempFileId = Date.now().toString(); - return `${os.tmpdir()}/temp_${this.tempFileId}.${ext}`; + return `${os.tmpdir()}\\temp_${this.tempFileId}.${ext}`; } } diff --git a/src/executors/NonInteractiveCodeExecutor.ts b/src/executors/NonInteractiveCodeExecutor.ts index 6f33ff7..a6cc23c 100644 --- a/src/executors/NonInteractiveCodeExecutor.ts +++ b/src/executors/NonInteractiveCodeExecutor.ts @@ -6,6 +6,7 @@ import {Outputter} from "src/Outputter"; import {LanguageId} from "src/main"; import { ExecutorSettings } from "../settings/Settings.js"; import windowsPathToWsl from "../transforms/windowsPathToWsl.js"; +import { error } from "console"; export default class NonInteractiveCodeExecutor extends Executor { usesShell: boolean @@ -44,16 +45,38 @@ export default class NonInteractiveCodeExecutor extends Executor { } else { args.push(tempFileName); } - - const child = child_process.spawn(cmd, args, {env: process.env, shell: this.usesShell}); - - this.handleChildOutput(child, outputter, tempFileName).then(() => { - this.tempFileId = undefined; // Reset the file id to use a new file next time - }); + + + let child: child_process.ChildProcessWithoutNullStreams; + + // check if compiled by gcc + if (cmd.endsWith("gcc") || cmd.endsWith("gcc.exe")) { + // remove .c from tempFileName and add .out for the compiled output and add output path to args + const tempFileNameWExe: string = tempFileName.slice(0, -2) + ".out"; + args.push("-o", tempFileNameWExe); + + // compile c file with gcc and handle possible output + const childGCC = child_process.spawn(cmd, args, {env: process.env, shell: this.usesShell}); + this.handleChildOutput(childGCC, outputter, tempFileName); + childGCC.on('exit', (code) => { + if (code === 0) { + // executing the compiled file + child = child_process.spawn(tempFileNameWExe, { env: process.env, shell: this.usesShell }); + this.handleChildOutput(child, outputter, tempFileNameWExe).then(() => { + this.tempFileId = undefined; // Reset the file id to use a new file next time + }); + } + }); + } else { + child = child_process.spawn(cmd, args, { env: process.env, shell: this.usesShell }); + this.handleChildOutput(child, outputter, tempFileName).then(() => { + this.tempFileId = undefined; // Reset the file id to use a new file next time + }); + } // We don't resolve the promise here - 'handleChildOutput' registers a listener // For when the child_process closes, and will resolve the promise there - this.resolveRun = resolve; + this.resolveRun = resolve; }).catch((err) => { this.notifyError(cmd, cmdArgs, tempFileName, err, outputter); resolve(); diff --git a/src/main.ts b/src/main.ts index 99ee793..f009bfc 100644 --- a/src/main.ts +++ b/src/main.ts @@ -23,7 +23,7 @@ import ExecutorManagerView, { import runAllCodeBlocks from './runAllCodeBlocks'; -export const languageAliases = ["javascript", "typescript", "bash", "csharp", "wolfram", "nb", "wl", "hs", "py", "scpt"] as const; +export const languageAliases = ["javascript", "typescript", "bash", "csharp", "wolfram", "nb", "wl", "hs", "py"] as const; export const canonicalLanguages = ["js", "ts", "cs", "lean", "lua", "python", "cpp", "prolog", "shell", "groovy", "r", "go", "rust", "java", "powershell", "kotlin", "mathematica", "haskell", "scala", "racket", "fsharp", "c", "dart", "ruby", "batch", "sql", "octave", "maxima", "applescript", "zig"] as const; @@ -59,7 +59,7 @@ export default class ExecuteCodePlugin extends Plugin { supportedLanguages.forEach(l => { console.debug(`Registering renderer for ${l}.`) this.registerMarkdownCodeBlockProcessor(`run-${l}`, async (src, el, _ctx) => { - await MarkdownRenderer.renderMarkdown('```' + l + '\n' + src + (src.endsWith('\n') ? '' : '\n') + '```', el, _ctx.sourcePath, null); + await MarkdownRenderer.renderMarkdown('```' + l + '\n' + src + (src.endsWith('\n') ? '' : '\n') + '```', el, '', null); }); }); @@ -212,7 +212,7 @@ export default class ExecuteCodePlugin extends Plugin { button.className = runButtonDisabledClass; let transformedCode = await new CodeInjector(this.app, this.settings, language).injectCode(srcCode); transformedCode = addMagicToJS(transformedCode); - this.runCode(transformedCode, out, button, this.settings.nodePath, this.settings.nodeArgs, this.settings.jsFileExtension, language, file); + this.runCode(transformedCode, out, button, this.settings.nodePath, this.settings.nodeArgs, "js", language, file); }); } else if (language === "java") { @@ -231,7 +231,7 @@ export default class ExecuteCodePlugin extends Plugin { transformedCode = addInlinePlotsToPython(transformedCode, TOGGLE_HTML_SIGIL); transformedCode = addMagicToPython(transformedCode); - this.runCode(transformedCode, out, button, this.settings.pythonPath, this.settings.pythonArgs, this.settings.pythonFileExtension, language, file); + this.runCode(transformedCode, out, button, this.settings.pythonPath, this.settings.pythonArgs, "py", language, file); }); } else if (language === "shell") { @@ -259,7 +259,7 @@ export default class ExecuteCodePlugin extends Plugin { button.addEventListener("click", async () => { button.className = runButtonDisabledClass; const transformedCode = await new CodeInjector(this.app, this.settings, language).injectCode(srcCode); - this.runCode(transformedCode, out, button, this.settings.clingPath, `-std=${this.settings.clingStd} ${this.settings.clingArgs}`, this.settings.cppFileExtension, language, file); + this.runCode(transformedCode, out, button, this.settings.clingPath, `-std=${this.settings.clingStd} ${this.settings.clingArgs}`, "cpp", language, file); }); } else if (language === "prolog") { @@ -289,7 +289,7 @@ export default class ExecuteCodePlugin extends Plugin { button.className = runButtonDisabledClass; let transformedCode = await new CodeInjector(this.app, this.settings, language).injectCode(srcCode); transformedCode = addInlinePlotsToR(transformedCode); - this.runCode(transformedCode, out, button, this.settings.RPath, this.settings.RArgs, this.settings.RFileExtension, language, file); + this.runCode(transformedCode, out, button, this.settings.RPath, this.settings.RArgs, "R", language, file); }); } else if (language === "go") { @@ -317,21 +317,21 @@ export default class ExecuteCodePlugin extends Plugin { button.addEventListener("click", async () => { button.className = runButtonDisabledClass; const transformedCode = await new CodeInjector(this.app, this.settings, language).injectCode(srcCode); - this.runCodeInShell(transformedCode, out, button, this.settings.luaPath, this.settings.luaArgs, this.settings.luaFileExtension, language, file); + this.runCodeInShell(transformedCode, out, button, this.settings.luaPath, this.settings.luaArgs, "lua", language, file); }); } else if (language === "dart") { button.addEventListener("click", async () => { button.className = runButtonDisabledClass; const transformedCode = await new CodeInjector(this.app, this.settings, language).injectCode(srcCode); - this.runCodeInShell(transformedCode, out, button, this.settings.dartPath, this.settings.dartArgs, this.settings.dartFileExtension, language, file); + this.runCodeInShell(transformedCode, out, button, this.settings.dartPath, this.settings.dartArgs, "dart", language, file); }); } else if (language === "cs") { button.addEventListener("click", async () => { button.className = runButtonDisabledClass; const transformedCode = await new CodeInjector(this.app, this.settings, language).injectCode(srcCode); - this.runCodeInShell(transformedCode, out, button, this.settings.csPath, this.settings.csArgs, this.settings.csFileExtension, language, file); + this.runCodeInShell(transformedCode, out, button, this.settings.csPath, this.settings.csArgs, "csx", language, file); }); } else if (language === "haskell") { @@ -363,7 +363,7 @@ export default class ExecuteCodePlugin extends Plugin { button.addEventListener("click", async () => { button.className = runButtonDisabledClass; const transformedCode = await new CodeInjector(this.app, this.settings, language).injectCode(srcCode); - this.runCodeInShell(transformedCode, out, button, this.settings.rubyPath, this.settings.rubyArgs, this.settings.rubyFileExtension, language, file); + this.runCodeInShell(transformedCode, out, button, this.settings.rubyPath, this.settings.rubyArgs, "rb", language, file); }) } else if (language === "sql") { button.addEventListener("click", async () => { @@ -376,26 +376,14 @@ export default class ExecuteCodePlugin extends Plugin { button.className = runButtonDisabledClass; let transformedCode = await new CodeInjector(this.app, this.settings, language).injectCode(srcCode); transformedCode = addInlinePlotsToOctave(transformedCode); - this.runCodeInShell(transformedCode, out, button, this.settings.octavePath, this.settings.octaveArgs, this.settings.octaveFileExtension, language, file); + this.runCodeInShell(transformedCode, out, button, this.settings.octavePath, this.settings.octaveArgs, "octave", language, file); }) } else if (language === "maxima") { button.addEventListener("click", async () => { button.className = runButtonDisabledClass; let transformedCode = await new CodeInjector(this.app, this.settings, language).injectCode(srcCode); transformedCode = addInlinePlotsToMaxima(transformedCode); - this.runCodeInShell(transformedCode, out, button, this.settings.maximaPath, this.settings.maximaArgs, this.settings.maximaFileExtension, language, file); - }) - }else if (language === "racket") { - button.addEventListener("click", async () => { - button.className = runButtonDisabledClass; - const transformedCode = await new CodeInjector(this.app, this.settings, language).injectCode(srcCode); - this.runCodeInShell(transformedCode, out, button, this.settings.racketPath, this.settings.racketArgs, this.settings.racketFileExtension, language, file); - }) - } else if (language === "applescript") { - button.addEventListener("click", async () => { - button.className = runButtonDisabledClass; - const transformedCode = await new CodeInjector(this.app, this.settings, language).injectCode(srcCode); - this.runCodeInShell(transformedCode, out, button, this.settings.applescriptPath, this.settings.applescriptArgs, this.settings.applescriptFileExtension, language, file); + this.runCodeInShell(transformedCode, out, button, this.settings.maximaPath, this.settings.maximaArgs, "maxima", language, file); }) } else if (language === "zig") { button.addEventListener("click", async () => { diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 05ae4aa..323e432 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -13,7 +13,6 @@ export interface ExecutorSettings { onlyCurrentBlock: boolean; nodePath: string; nodeArgs: string; - jsFileExtension: string; jsInject: string; tsPath: string; tsArgs: string; @@ -23,20 +22,16 @@ export interface ExecutorSettings { leanInject: string; luaPath: string; luaArgs: string; - luaFileExtension: string; luaInject: string; dartPath: string; dartArgs: string; - dartFileExtension: string; dartInject: string; csPath: string; csArgs: string; - csFileExtension: string; csInject: string; pythonPath: string; pythonArgs: string; pythonEmbedPlots: boolean; - pythonFileExtension: string; pythonInject: string; shellPath: string; shellArgs: string; @@ -77,7 +72,6 @@ export interface ExecutorSettings { cargoEvalArgs: string; rustInject: string; cppRunner: string; - cppFileExtension: string; cppInject: string; cppArgs: string; cppUseMain: boolean; @@ -88,7 +82,6 @@ export interface ExecutorSettings { RPath: string; RArgs: string; REmbedPlots: boolean; - RFileExtension: string; rInject: string; kotlinPath: string; kotlinArgs: string; @@ -120,7 +113,6 @@ export interface ExecutorSettings { cInject: string; rubyPath: string; rubyArgs: string; - rubyFileExtension: string; rubyInject: string; sqlPath: string; sqlArgs: string; @@ -180,7 +172,6 @@ export const DEFAULT_SETTINGS: ExecutorSettings = { onlyCurrentBlock: false, nodePath: "node", nodeArgs: "", - jsFileExtension: "js", jsInject: "", tsPath: "ts-node", tsArgs: "", @@ -190,20 +181,16 @@ export const DEFAULT_SETTINGS: ExecutorSettings = { leanInject: "", luaPath: "lua", luaArgs: "", - luaFileExtension: "lua", luaInject: "", dartPath: "dart", dartArgs: "", - dartFileExtension: "dart", dartInject: "", csPath: "dotnet-script", csArgs: "", - csFileExtension: "csx", csInject: "", pythonPath: "python", pythonArgs: "", pythonEmbedPlots: true, - pythonFileExtension: "py", pythonInject: "", shellPath: "bash", shellArgs: "", @@ -236,7 +223,6 @@ export const DEFAULT_SETTINGS: ExecutorSettings = { cargoEvalArgs: "", rustInject: "", cppRunner: "cling", - cppFileExtension: "cpp", cppInject: "", cppArgs: "", cppUseMain: false, @@ -247,7 +233,6 @@ export const DEFAULT_SETTINGS: ExecutorSettings = { RPath: "Rscript", RArgs: "", REmbedPlots: true, - RFileExtension: "R", rInject: "", kotlinPath: "kotlinc", kotlinArgs: "-script", @@ -279,7 +264,6 @@ export const DEFAULT_SETTINGS: ExecutorSettings = { cInject: "", rubyPath: "ruby", rubyArgs: "", - rubyFileExtension: "rb", rubyInject: "", sqlPath: "psql", sqlArgs: "-d -U -f", diff --git a/src/settings/per-lang/makeCSettings.ts b/src/settings/per-lang/makeCSettings.ts index 5618a7e..f18d79b 100644 --- a/src/settings/per-lang/makeCSettings.ts +++ b/src/settings/per-lang/makeCSettings.ts @@ -4,27 +4,27 @@ import { SettingsTab } from "../SettingsTab"; export default (tab: SettingsTab, containerEl: HTMLElement) => { containerEl.createEl('h3', { text: 'C Settings' }); new Setting(containerEl) - .setName('Cling path') - .setDesc('The path to your Cling installation.') + .setName('gcc / Cling path') + .setDesc('The path to your gcc / Cling installation.') .addText(text => text .setValue(tab.plugin.settings.clingPath) .onChange(async (value) => { const sanitized = tab.sanitizePath(value); tab.plugin.settings.clingPath = sanitized; - console.log('Cling path set to: ' + sanitized); + console.log('gcc / Cling path set to: ' + sanitized); await tab.plugin.saveSettings(); })); new Setting(containerEl) - .setName('Cling arguments for C') + .setName('gcc / Cling arguments for C') .addText(text => text .setValue(tab.plugin.settings.cArgs) .onChange(async (value) => { tab.plugin.settings.cArgs = value; - console.log('Cling args set to: ' + value); + console.log('gcc / Cling args set to: ' + value); await tab.plugin.saveSettings(); })); new Setting(containerEl) - .setName('Cling std') + .setName('Cling std (ignored for gcc)') .addDropdown(dropdown => dropdown .addOption('c++98', 'C++ 98') .addOption('c++11', 'C++ 11') @@ -38,7 +38,7 @@ export default (tab: SettingsTab, containerEl: HTMLElement) => { await tab.plugin.saveSettings(); })); new Setting(containerEl) - .setName('Use main function') + .setName('Use main function (mandatory for gcc)') .setDesc('If enabled, will use a main() function as the code block entrypoint.') .addToggle((toggle) => toggle .setValue(tab.plugin.settings.cUseMain) diff --git a/src/transforms/Magic.ts b/src/transforms/Magic.ts index 46e4425..7313553 100644 --- a/src/transforms/Magic.ts +++ b/src/transforms/Magic.ts @@ -12,7 +12,6 @@ */ import * as os from "os"; -import {Platform} from 'obsidian'; import { TOGGLE_HTML_SIGIL } from "src/Outputter"; // Regex for all languages. @@ -42,8 +41,8 @@ const MAXIMA_PLOT_REGEX = /^plot2d\s*\(.*\[.+\]\)\s*[$;]/gm; */ export function insertVaultPath(source: string, vaultPath: string): string { source = source.replace(VAULT_PATH_REGEX, `"${vaultPath.replace(/\\/g, "/")}"`); - source = source.replace(VAULT_URL_REGEX, `"${Platform.resourcePathPrefix + vaultPath.replace(/\\/g, "/")}"`); - source = source.replace(VAULT_REGEX, `"${Platform.resourcePathPrefix + vaultPath.replace(/\\/g, "/")}"`); + source = source.replace(VAULT_URL_REGEX, `"app://local/${vaultPath.replace(/\\/g, "/")}"`); + source = source.replace(VAULT_REGEX, `"app://local/${vaultPath.replace(/\\/g, "/")}"`); return source; } @@ -58,8 +57,8 @@ export function insertVaultPath(source: string, vaultPath: string): string { */ export function insertNotePath(source: string, notePath: string): string { source = source.replace(CURRENT_NOTE_PATH_REGEX, `"${notePath.replace(/\\/g, "/")}"`); - source = source.replace(CURRENT_NOTE_URL_REGEX, `"${Platform.resourcePathPrefix + notePath.replace(/\\/g, "/")}"`); - source = source.replace(CURRENT_NOTE_REGEX, `"${Platform.resourcePathPrefix + notePath.replace(/\\/g, "/")}"`); + source = source.replace(CURRENT_NOTE_URL_REGEX, `"app://local/${notePath.replace(/\\/g, "/")}"`); + source = source.replace(CURRENT_NOTE_REGEX, `"app://local/${notePath.replace(/\\/g, "/")}"`); return source; } @@ -142,7 +141,7 @@ export function addInlinePlotsToR(source: string): string { const matches = source.matchAll(R_PLOT_REGEX); for (const match of matches) { const tempFile = `${os.tmpdir()}/temp_${Date.now()}.png`.replace(/\\/g, "/"); - const substitute = `png("${tempFile}"); ${match[0]}; dev.off(); cat('${TOGGLE_HTML_SIGIL}${TOGGLE_HTML_SIGIL}')`; + const substitute = `png("${tempFile}"); ${match[0]}; dev.off(); cat('${TOGGLE_HTML_SIGIL}${TOGGLE_HTML_SIGIL}')`; source = source.replace(match[0], substitute); } @@ -247,7 +246,7 @@ export function addInlinePlotsToOctave(source: string): string { const matches = source.matchAll(OCTAVE_PLOT_REGEX); for (const match of matches) { const tempFile = `${os.tmpdir()}/temp_${Date.now()}.png`.replace(/\\/g, "/"); - const substitute = `${match[0]}; print -dpng ${tempFile}; disp('${TOGGLE_HTML_SIGIL}${TOGGLE_HTML_SIGIL}');`; + const substitute = `${match[0]}; print -dpng ${tempFile}; disp('${TOGGLE_HTML_SIGIL}${TOGGLE_HTML_SIGIL}');`; source = source.replace(match[0], substitute); } @@ -260,7 +259,7 @@ export function addInlinePlotsToMaxima(source: string): string { for (const match of matches) { const tempFile = `${os.tmpdir()}/temp_${Date.now()}.png`.replace(/\\/g, "/"); const updated_plot_call = match[0].substring(0, match[0].lastIndexOf(')')) + `, [png_file, "${tempFile}"])`; - const substitute = `${updated_plot_call}; print ('${TOGGLE_HTML_SIGIL}${TOGGLE_HTML_SIGIL}');`; + const substitute = `${updated_plot_call}; print ('${TOGGLE_HTML_SIGIL}${TOGGLE_HTML_SIGIL}');`; source = source.replace(match[0], substitute); } diff --git a/src/transforms/TransformCode.ts b/src/transforms/TransformCode.ts index ba9f4c0..f3ae7cc 100644 --- a/src/transforms/TransformCode.ts +++ b/src/transforms/TransformCode.ts @@ -22,7 +22,6 @@ export function getLanguageAlias(language: string | undefined): LanguageId | und case "nb": return "mathematica"; case "wl": "mathematica"; case "hs": return "haskell"; - case "scpt": return "applescript"; } if ((canonicalLanguages as readonly string[]).includes(language)) return language as LanguageId;