Skip to content

Commit

Permalink
Merge pull request #305 from melo-afk/feature/gcc_support
Browse files Browse the repository at this point in the history
Added support for other C compiler: gcc
  • Loading branch information
twibiral committed Apr 14, 2024
2 parents 6ee175e + 7ccf3c9 commit 7a68511
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 70 deletions.
7 changes: 6 additions & 1 deletion src/executors/CExecutor.ts
Expand Up @@ -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");
}
}
}
13 changes: 8 additions & 5 deletions src/executors/ClingExecutor.ts
Expand Up @@ -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<void>((resolve, reject) => {
const childArgs = [...args.split(" "), ...codeBlockContent.split("\n")];
const child = child_process.spawn(this.settings.clingPath, childArgs, {env: process.env, shell: this.usesShell});
Expand Down
2 changes: 1 addition & 1 deletion src/executors/Executor.ts
Expand Up @@ -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}`;
}
}
37 changes: 30 additions & 7 deletions src/executors/NonInteractiveCodeExecutor.ts
Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down
36 changes: 12 additions & 24 deletions src/main.ts
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
});
});

Expand Down Expand Up @@ -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") {
Expand All @@ -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") {
Expand Down Expand Up @@ -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") {
Expand Down Expand Up @@ -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") {
Expand Down Expand Up @@ -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") {
Expand Down Expand Up @@ -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 () => {
Expand All @@ -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 () => {
Expand Down
16 changes: 0 additions & 16 deletions src/settings/Settings.ts
Expand Up @@ -13,7 +13,6 @@ export interface ExecutorSettings {
onlyCurrentBlock: boolean;
nodePath: string;
nodeArgs: string;
jsFileExtension: string;
jsInject: string;
tsPath: string;
tsArgs: string;
Expand All @@ -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;
Expand Down Expand Up @@ -77,7 +72,6 @@ export interface ExecutorSettings {
cargoEvalArgs: string;
rustInject: string;
cppRunner: string;
cppFileExtension: string;
cppInject: string;
cppArgs: string;
cppUseMain: boolean;
Expand All @@ -88,7 +82,6 @@ export interface ExecutorSettings {
RPath: string;
RArgs: string;
REmbedPlots: boolean;
RFileExtension: string;
rInject: string;
kotlinPath: string;
kotlinArgs: string;
Expand Down Expand Up @@ -120,7 +113,6 @@ export interface ExecutorSettings {
cInject: string;
rubyPath: string;
rubyArgs: string;
rubyFileExtension: string;
rubyInject: string;
sqlPath: string;
sqlArgs: string;
Expand Down Expand Up @@ -180,7 +172,6 @@ export const DEFAULT_SETTINGS: ExecutorSettings = {
onlyCurrentBlock: false,
nodePath: "node",
nodeArgs: "",
jsFileExtension: "js",
jsInject: "",
tsPath: "ts-node",
tsArgs: "",
Expand All @@ -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: "",
Expand Down Expand Up @@ -236,7 +223,6 @@ export const DEFAULT_SETTINGS: ExecutorSettings = {
cargoEvalArgs: "",
rustInject: "",
cppRunner: "cling",
cppFileExtension: "cpp",
cppInject: "",
cppArgs: "",
cppUseMain: false,
Expand All @@ -247,7 +233,6 @@ export const DEFAULT_SETTINGS: ExecutorSettings = {
RPath: "Rscript",
RArgs: "",
REmbedPlots: true,
RFileExtension: "R",
rInject: "",
kotlinPath: "kotlinc",
kotlinArgs: "-script",
Expand Down Expand Up @@ -279,7 +264,6 @@ export const DEFAULT_SETTINGS: ExecutorSettings = {
cInject: "",
rubyPath: "ruby",
rubyArgs: "",
rubyFileExtension: "rb",
rubyInject: "",
sqlPath: "psql",
sqlArgs: "-d <database> -U <user> -f",
Expand Down
14 changes: 7 additions & 7 deletions src/settings/per-lang/makeCSettings.ts
Expand Up @@ -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')
Expand All @@ -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)
Expand Down

0 comments on commit 7a68511

Please sign in to comment.