diff options
27 files changed, 311 insertions, 315 deletions
@@ -117,14 +117,12 @@ var CompileHandler = require('./lib/compile-handler').CompileHandler, // in hidden object props.properties var ceProps = props.propsFor("compiler-explorer"); -var languages = require('./lib/languages'); +const languages = require('./lib/languages').list; // Instantiate a function to access records concerning the chosen language // in hidden object props.properties var compilerPropsFuncsL = {}; -_.each(languages.list(), function (lang) { - compilerPropsFuncsL[lang.id] = props.propsFor(lang.id); -}); +_.each(languages, lang => compilerPropsFuncsL[lang.id] = props.propsFor(lang.id)); // Get a property from the specified langId, and if not found, use defaults from CE, // and at last return whatever default value was set by the caller @@ -139,16 +137,16 @@ function compilerPropsL(lang, property, defaultValue) { // For every lang passed, get its corresponding compiler property function compilerPropsA(langs, property, defaultValue) { - const forLanguages = {}; + let forLanguages = {}; _.each(langs, lang => { forLanguages[lang.id] = compilerPropsL(lang.id, property, defaultValue); }); return forLanguages; } -// Same as A version, but transfrom each value by fn(original, lang) +// Same as A version, but transfroms each value by fn(original, lang) function compilerPropsAT(langs, transform, property, defaultValue) { - var forLanguages = {}; + let forLanguages = {}; _.each(langs, lang => { forLanguages[lang.id] = transform(compilerPropsL(lang.id, property, defaultValue), lang); }); @@ -208,18 +206,16 @@ function compareOn(key) { // instantiate a function that generate javascript code, function ClientOptionsHandler(fileSources) { - var sources = fileSources.map(function (source) { + const sources = fileSources.map(function (source) { return {name: source.name, urlpart: source.urlpart}; - }); + }).sort(compareOn("name")); // sort source file alphabetically - sources = sources.sort(compareOn("name")); - var langs = languages.toArray(); - var supportsBinary = compilerPropsAT(langs, res => !!res, "supportsBinary", true); - var supportsExecute = supportsBinary && !!compilerPropsAT(langs, (res, lang) => supportsBinary[lang.id] && !!res, "supportsExecute", true); + var supportsBinary = compilerPropsAT(languages, res => !!res, "supportsBinary", true); + var supportsExecute = supportsBinary && !!compilerPropsAT(languages, (res, lang) => supportsBinary[lang.id] && !!res, "supportsExecute", true); var libs = {}; - var baseLibs = compilerPropsA(langs, "libs"); + var baseLibs = compilerPropsA(languages, "libs"); _.each(baseLibs, function (forLang, lang) { if (lang && forLang) { libs[lang] = {}; @@ -257,11 +253,11 @@ function ClientOptionsHandler(fileSources) { defaultSource: ceProps('defaultSource', ''), compilers: [], libs: libs, - defaultCompiler: compilerPropsA(langs, 'defaultCompiler', ''), - compileOptions: compilerPropsA(langs, 'defaultOptions', ''), + defaultCompiler: compilerPropsA(languages, 'defaultCompiler', ''), + compileOptions: compilerPropsA(languages, 'defaultOptions', ''), supportsBinary: supportsBinary, supportsExecute: supportsExecute, - languages: languages.list(), + languages: languages, sources: sources, raven: ceProps('ravenUrl', ''), release: gitReleaseName, @@ -336,23 +332,21 @@ function retryPromise(promiseFunc, name, maxFails, retryMs) { } function findCompilers() { - var exes = compilerPropsAT(languages.toArray(), exs => { - return exs.split(":").filter(x => x); - }, "compilers", "/usr/bin/g++"); + let exes = compilerPropsAT(languages, exs => { + return exs.split(":").filter(_.identity); + }, "compilers", ""); - var ndk = compilerPropsA(languages.toArray(), 'androidNdk'); + const ndk = compilerPropsA(languages, 'androidNdk'); _.each(ndk, (ndkPath, langId) => { if (ndkPath) { - var toolchains = fs.readdirSync(ndkPath + "/toolchains"); - toolchains.forEach(function (v, i, a) { - var path = ndkPath + "/toolchains/" + v + "/prebuilt/linux-x86_64/bin/"; + let toolchains = fs.readdirSync(ndkPath + "/toolchains"); + toolchains.forEach((version, index, a) => { + const path = ndkPath + "/toolchains/" + version + "/prebuilt/linux-x86_64/bin/"; if (fs.existsSync(path)) { - var cc = fs.readdirSync(path).filter(function (filename) { - return filename.indexOf("g++") !== -1; - }); - a[i] = path + cc[0]; + const cc = fs.readdirSync(path).filter(filename => filename.indexOf("g++") !== -1); + a[index] = path + cc[0]; } else { - a[i] = null; + a[index] = null; } }); toolchains = toolchains.filter(x => x !== null); @@ -362,40 +356,38 @@ function findCompilers() { function fetchRemote(host, port, props) { logger.info("Fetching compilers from remote source " + host + ":" + port); - return retryPromise(function () { - return new Promise(function (resolve, reject) { - var request = http.get({ + return retryPromise(() => { + return new Promise((resolve, reject) => { + let request = http.get({ hostname: host, port: port, path: "/api/compilers", headers: { 'Accept': 'application/json' } - }, function (res) { - var str = ''; - res.on('data', function (chunk) { + }, res => { + let str = ''; + res.on('data', chunk => { str += chunk; }); - res.on('end', function () { - var compilers = JSON.parse(str).map(function (compiler) { + res.on('end', () => { + let compilers = JSON.parse(str).map(compiler => { compiler.exe = null; compiler.remote = "http://" + host + ":" + port; return compiler; }); resolve(compilers); }); - }).on('error', function (e) { - reject(e); - }).on('timeout', function () { - reject("timeout"); - }); + }) + .on('error', reject) + .on('timeout', () => reject("timeout")); request.setTimeout(awsProps('proxyTimeout', 1000)); }); }, host + ":" + port, props('proxyRetries', 5), props('proxyRetryMs', 500)) - .catch(function () { + .catch(() => { logger.warn("Unable to contact " + host + ":" + port + "; skipping"); return []; }); @@ -403,10 +395,10 @@ function findCompilers() { function fetchAws() { logger.info("Fetching instances from AWS"); - return awsInstances().then(function (instances) { - return Promise.all(instances.map(function (instance) { + return awsInstances().then(instances => { + return Promise.all(instances.map(instance => { logger.info("Checking instance " + instance.InstanceId); - var address = instance.PrivateDnsName; + let address = instance.PrivateDnsName; if (awsProps("externalTestMode", false)) { address = instance.PublicDnsName; } @@ -419,16 +411,16 @@ function findCompilers() { const base = "compiler." + compilerName + "."; function props(propName, def) { - var propsForCompiler = parentProps(langId, base + propName, undefined); + let propsForCompiler = parentProps(langId, base + propName, undefined); if (propsForCompiler === undefined) { propsForCompiler = parentProps(langId, propName, def); } return propsForCompiler; } - var supportsBinary = !!props("supportsBinary", true); - var supportsExecute = supportsBinary && !!props("supportsExecute", true); - var compilerInfo = { + const supportsBinary = !!props("supportsBinary", true); + const supportsExecute = supportsBinary && !!props("supportsExecute", true); + const compilerInfo = { id: compilerName, exe: props("exe", compilerName), name: props("name", compilerName), @@ -469,20 +461,16 @@ function findCompilers() { const compilerExes = props(langId, 'compilers', '').split(":").filter(_.identity); logger.debug("Processing compilers from group " + groupName); - return Promise.all(compilerExes.map(function (compiler) { - return recurseGetCompilers(langId, compiler, props); - })); + return Promise.all(compilerExes.map(compiler => recurseGetCompilers(langId, compiler, props))); } if (compilerName === "AWS") return fetchAws(); return compilerConfigFor(langId, compilerName, parentProps); } function getCompilers() { - var compilers = []; + let compilers = []; _.each(exes, (exs, langId) => { - _.each(exs, exe => { - compilers.push(recurseGetCompilers(langId, exe, compilerPropsL)); - }); + _.each(exs, exe => compilers.push(recurseGetCompilers(langId, exe, compilerPropsL))); }); return compilers; } @@ -517,12 +505,12 @@ function ApiHandler(compileHandler) { this.compilers = compilers; }; this.handler = express.Router(); - this.handler.use(function (req, res, next) { + this.handler.use((req, res, next) => { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); }); - this.handler.get('/compilers', _.bind(function (req, res) { + this.handler.get('/compilers', _.bind((req, res) => { if (req.accepts(['text', 'json']) === 'json') { res.set('Content-Type', 'application/json'); res.end(JSON.stringify(this.compilers)); @@ -531,13 +519,13 @@ function ApiHandler(compileHandler) { var title = 'Compiler Name'; var maxLength = _.max(_.pluck(_.pluck(this.compilers, 'id').concat([title]), 'length')); res.write(utils.padRight(title, maxLength) + ' | Description\n'); - res.end(_.map(this.compilers, function (compiler) { + res.end(_.map(this.compilers, compiler => { return utils.padRight(compiler.id, maxLength) + ' | ' + compiler.name; }).join("\n")); } }, this)); this.handler.get('/asm/:opcode', asm_doc_api.asmDocsHandler); - this.handler.param('compiler', _.bind(function (req, res, next, compilerName) { + this.handler.param('compiler', _.bind((req, res, next, compilerName) => { req.compiler = compilerName; next(); }, this)); @@ -554,12 +542,10 @@ function shortUrlHandler(req, res, next) { var key = aws.getConfig('googleApiKey'); var googleApiUrl = 'https://www.googleapis.com/urlshortener/v1/url?shortUrl=http://goo.gl/' + encodeURIComponent(bits[1]) + '&key=' + key; - https.get(googleApiUrl, function (response) { + https.get(googleApiUrl, response => { var responseText = ''; - response.on('data', function (d) { - responseText += d; - }); - response.on('end', function () { + response.on('data', d => responseText += d); + response.on('end', () => { if (response.statusCode !== 200) { logger.error("Failed to resolve short URL " + bits[1] + " - got response " + response.statusCode + " : " + responseText); @@ -591,7 +577,7 @@ function shortUrlHandler(req, res, next) { Promise.all([findCompilers(), aws.initConfig(awsProps)]) - .then(function (args) { + .then(args => { let compilers = args[0]; var prevCompilers; diff --git a/etc/config/builtin.d.properties b/etc/config/builtin.d.properties deleted file mode 100644 index bfc5e8548..000000000 --- a/etc/config/builtin.d.properties +++ /dev/null @@ -1,2 +0,0 @@ -sourcepath=./examples/d/ -extensionRe=.*\.d$ diff --git a/etc/config/builtin.default.properties b/etc/config/builtin.default.properties new file mode 100644 index 000000000..0ebf27c6a --- /dev/null +++ b/etc/config/builtin.default.properties @@ -0,0 +1 @@ +sourcePath=./examples/
\ No newline at end of file diff --git a/etc/config/builtin.go.properties b/etc/config/builtin.go.properties deleted file mode 100644 index 1fd2bfefc..000000000 --- a/etc/config/builtin.go.properties +++ /dev/null @@ -1,2 +0,0 @@ -sourcepath=./examples/go/ -extensionRe=.*\.go$ diff --git a/etc/config/builtin.haskell.properties b/etc/config/builtin.haskell.properties deleted file mode 100644 index c865078c3..000000000 --- a/etc/config/builtin.haskell.properties +++ /dev/null @@ -1,2 +0,0 @@ -sourcepath=./examples/haskell/ -extensionRe=.*\.hs$ diff --git a/etc/config/builtin.ispc.properties b/etc/config/builtin.ispc.properties deleted file mode 100644 index eff778fcc..000000000 --- a/etc/config/builtin.ispc.properties +++ /dev/null @@ -1,2 +0,0 @@ -sourcepath=./examples/ispc/ -extensionRe=.*\.ispc$ diff --git a/etc/config/builtin.pascal.properties b/etc/config/builtin.pascal.properties deleted file mode 100644 index 79dea28bb..000000000 --- a/etc/config/builtin.pascal.properties +++ /dev/null @@ -1,2 +0,0 @@ -sourcepath=./examples/pascal/ -extensionRe=.*\.pas$ diff --git a/etc/config/builtin.rust.properties b/etc/config/builtin.rust.properties deleted file mode 100644 index c61faaa7c..000000000 --- a/etc/config/builtin.rust.properties +++ /dev/null @@ -1,2 +0,0 @@ -sourcepath=./examples/rust/ -extensionRe=.*\.rs$ diff --git a/etc/config/builtin.swift.properties b/etc/config/builtin.swift.properties deleted file mode 100644 index 77f22f08e..000000000 --- a/etc/config/builtin.swift.properties +++ /dev/null @@ -1,2 +0,0 @@ -sourcepath=./examples/swift/ -extensionRe=.*\.swift$ diff --git a/examples/c++/default.cpp b/examples/c++/default.cpp new file mode 100644 index 000000000..e8c4fe4ec --- /dev/null +++ b/examples/c++/default.cpp @@ -0,0 +1,4 @@ +// Type your code here, or load an example. +int square(int num) { + return num * num; +}
\ No newline at end of file diff --git a/examples/c/default.c b/examples/c/default.c new file mode 100644 index 000000000..e8c4fe4ec --- /dev/null +++ b/examples/c/default.c @@ -0,0 +1,4 @@ +// Type your code here, or load an example. +int square(int num) { + return num * num; +}
\ No newline at end of file diff --git a/examples/cppx/default.cpp b/examples/cppx/default.cpp new file mode 100644 index 000000000..503cffe41 --- /dev/null +++ b/examples/cppx/default.cpp @@ -0,0 +1,47 @@ +//==================================================================== +// Library code: implementing the metaclass (once) + +$class basic_value { + basic_value() = default; + basic_value(const basic_value& that) = default; + basic_value(basic_value&& that) = default; + basic_value& operator=(const basic_value& that) = default; + basic_value& operator=(basic_value&& that) = default; + + constexpr { + for... (auto f : $basic_value.variables()) + if (!f.has_access()) f.make_private(); + for... (auto f : $basic_value.functions()) { + if (!f.has_access()) f.make_public(); + compiler.require(!f.is_protected(), "a value type may not have a protected function"); + compiler.require(!f.is_virtual(), "a value type may not have a virtual function"); + compiler.require(!f.is_destructor() || f.is_public(), "a value destructor must be public"); + } + } +}; + +$class value : basic_value { }; + + +//==================================================================== +// User code: using the metaclass to write a type (many times) + +value Point { + int x = 0, y = 0; + Point(int xx, int yy) : x{xx}, y{yy} { } +}; + +Point get_some_point() { return {1,1}; } + +int main() { + + Point p1(50,100), p2; + p2 = get_some_point(); + p2.x = 42; + +} + +// Compiler Explorer note: Click the "triangle ! icon" to see the output: +constexpr { + compiler.debug($Point); +} diff --git a/examples/d/default.d b/examples/d/default.d new file mode 100644 index 000000000..3cb5a30c3 --- /dev/null +++ b/examples/d/default.d @@ -0,0 +1,4 @@ +// Type your code here, or load an example. +int square(int num) { + return num * num; +} diff --git a/examples/go/default.go b/examples/go/default.go new file mode 100644 index 000000000..65be52b7a --- /dev/null +++ b/examples/go/default.go @@ -0,0 +1,9 @@ +// Type your code here, or load an example. +// Your function name should start with a capital letter. +package main + +func Square(x int) int { + return x * x +} + +func main() {} diff --git a/examples/haskell/default.hs b/examples/haskell/default.hs new file mode 100644 index 000000000..97106284d --- /dev/null +++ b/examples/haskell/default.hs @@ -0,0 +1,5 @@ +module Example where + +sumOverArray :: [Int] -> Int +sumOverArray (x:xs) = x + sumOverArray xs +sumOverArray [] = 0 diff --git a/examples/ispc/default.ispc b/examples/ispc/default.ispc new file mode 100644 index 000000000..0924dc0b6 --- /dev/null +++ b/examples/ispc/default.ispc @@ -0,0 +1,4 @@ +// Type your code here, or load an example. +uniform int square(uniform int num) { + return num * num; +} diff --git a/examples/pascal/max_array.pas b/examples/pascal/Max_array.pas index ebacc2b3b..ebacc2b3b 100644 --- a/examples/pascal/max_array.pas +++ b/examples/pascal/Max_array.pas diff --git a/examples/pascal/sum_over_array.pas b/examples/pascal/Sum_over_array.pas index 714a4f6c9..714a4f6c9 100644 --- a/examples/pascal/sum_over_array.pas +++ b/examples/pascal/Sum_over_array.pas diff --git a/examples/pascal/default.pas b/examples/pascal/default.pas new file mode 100644 index 000000000..eddb3978a --- /dev/null +++ b/examples/pascal/default.pas @@ -0,0 +1,16 @@ +unit output; + +interface + +function Square(const num: Integer): Integer; + +implementation + +// Type your code here, or load an example. + +function Square(const num: Integer): Integer; +begin + Square := num * num; +end; + +end. diff --git a/examples/rust/default.rs b/examples/rust/default.rs new file mode 100644 index 000000000..ff272bd4d --- /dev/null +++ b/examples/rust/default.rs @@ -0,0 +1,4 @@ +// Type your code here, or load an example. +pub fn square(num: i32) -> i32 { + num * num +} diff --git a/examples/swift/default.swift b/examples/swift/default.swift new file mode 100644 index 000000000..af4a0979c --- /dev/null +++ b/examples/swift/default.swift @@ -0,0 +1,4 @@ +// Type your code here, or load an example. +func square(n: Int) -> Int { + return n * n +}
\ No newline at end of file diff --git a/lib/base-compiler.js b/lib/base-compiler.js index 94e7504ab..76ad5b5fc 100644 --- a/lib/base-compiler.js +++ b/lib/base-compiler.js @@ -25,8 +25,7 @@ /*jslint node: true */ "use strict"; -var child_process = require('child_process'), - temp = require('temp'), +var temp = require('temp'), path = require('path'), fs = require('fs-extra'), Promise = require('promise'), // jshint ignore:line @@ -38,12 +37,12 @@ var child_process = require('child_process'), compilerOptInfo = require("compiler-opt-info"), argumentParsers = require("./compilers/argument-parsers"), cfg = require('./cfg'), - languages = require('./languages'); + languages = require('./languages').list; function Compile(compiler, env, langId) { this.compiler = compiler; this.lang = langId; - this.langInfo = languages.list()[langId]; + this.langInfo = languages[langId]; if (!this.langInfo) { throw new Error("Missing language info for " + langId); } diff --git a/lib/languages.js b/lib/languages.js index 0f5665de1..55dbc275e 100644 --- a/lib/languages.js +++ b/lib/languages.js @@ -35,178 +35,81 @@ Leading point is needed Used in: Save to file extension */ -function languages() { - return { - 'c++': { - id: 'c++', - name: 'C++', - monaco: 'cppp', - extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], - example: "// Type your code here, or load an example.\n" + - "int square(int num) {\n" + - " return num * num;\n" + - "}\n" - }, - cppx: { - id: 'cppx', - name: 'Cppx', - monaco: 'cppp', - extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'], - example: "//====================================================================\n" + - "// Library code: implementing the metaclass (once)\n" + - "\n" + - "$class basic_value {\n" + - " basic_value() = default;\n" + - " basic_value(const basic_value& that) = default;\n" + - " basic_value(basic_value&& that) = default;\n" + - " basic_value& operator=(const basic_value& that) = default;\n" + - " basic_value& operator=(basic_value&& that) = default;\n" + - "\n" + - " constexpr {\n" + - " for... (auto f : $basic_value.variables())\n" + - " if (!f.has_access()) f.make_private();\n" + - " for... (auto f : $basic_value.functions()) {\n" + - " if (!f.has_access()) f.make_public();\n" + - " compiler.require(!f.is_protected(), \"a value type may not have a protected function\");\n" + - " compiler.require(!f.is_virtual(), \"a value type may not have a virtual function\");\n" + - " compiler.require(!f.is_destructor() || f.is_public(), \"a value destructor must be public\");\n" + - " }\n" + - " }\n" + - "};\n" + - "\n" + - "$class value : basic_value { };\n" + - "\n" + - "\n" + - "//====================================================================\n" + - "// User code: using the metaclass to write a type (many times)\n" + - "\n" + - "value Point {\n" + - " int x = 0, y = 0;\n" + - " Point(int xx, int yy) : x{xx}, y{yy} { }\n" + - "};\n" + - "\n" + - "Point get_some_point() { return {1,1}; }\n" + - "\n" + - "int main() {\n" + - "\n" + - " Point p1(50,100), p2;\n" + - " p2 = get_some_point();\n" + - " p2.x = 42;\n" + - "\n" + - "}\n" + - "\n" + - "// Compiler Explorer note: Click the \"triangle ! icon\" to see the output:\n" + - "constexpr {\n" + - " compiler.debug($Point);\n" + - "}\n" - }, - c: { - id: 'c', - name: 'C', - monaco: 'c', - extensions: ['.c', '.h'], - example: "// Type your code here, or load an example.\n" + - "int square(int num) {\n" + - " return num * num;\n" + - "}\n" - }, - rust: { - id: 'rust', - name: 'Rust', - monaco: 'rust', - extensions: ['.rs'], - example: "// Type your code here, or load an example.\n" + - "pub fn square(num: i32) -> i32 {\n" + - " num * num\n" + - "}\n" - }, - d: { - id: 'd', - name: 'D', - monaco: 'd', - extensions: ['.d'], - example: "// Type your code here, or load an example.\n" + - "int square(int num) {\n" + - " return num * num;\n" + - "}\n" - }, - go: { - id: 'go', - name: 'Go', - monaco: 'go', - extensions: ['.go'], - example: "// Type your code here, or load an example.\n" + - "// Your function name should start with a capital letter.\n" + - "package main\n" + - "\n" + - "func Square(x int) int {\n" + - " return x * x\n" + - "}\n" + - "\n" + - "func main() {}\n" - }, - ispc: { - id: 'ispc', - name: 'ispc', - monaco: 'ispc', - extensions: ['.ispc'], - example: "// Type your code here, or load an example.\n" + - "uniform int square(uniform int num) {\n" + - " return num * num;\n" + - "}\n" - }, - haskell: { - id: 'haskell', - name: 'Haskell', - monaco: 'haskell', - extensions: ['.hs', '.haskell'], - example: "module Example where\n" + - "\n" + - "sumOverArray :: [Int] -> Int\n" + - "sumOverArray (x:xs) = x + sumOverArray xs\n" + - "sumOverArray [] = 0\n" - }, - swift: { - id: 'swift', - name: 'Swift', - monaco: 'swift', - extensions: ['.swift'], - example: "// Type your code here, or load an example.\n" + - "func square(n: Int) -> Int {\n" + - " return n * n\n" + - "}" - }, - pascal: { - id: 'pascal', - name: 'Pascal', - monaco: 'pascal', - extenions: ['.pas'], - example: "unit output;\n" + - "\n" + - "interface\n" + - "\n" + - "function Square(const num: Integer): Integer;\n" + - "\n" + - "implementation\n" + - "\n" + - "// Type your code here, or load an example.\n" + - "\n" + - "function Square(const num: Integer): Integer;\n" + - "begin\n" + - " Square := num * num;\n" + - "end;\n" + - "\n" + - "end.\n" - } - }; -} -var _ = require('underscore-node'); +const languages = { + 'c++': { + id: 'c++', + name: 'C++', + monaco: 'cppp', + extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'] + }, + cppx: { + id: 'cppx', + name: 'Cppx', + monaco: 'cppp', + extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'] + }, + c: { + id: 'c', + name: 'C', + monaco: 'c', + extensions: ['.c', '.h'] + }, + rust: { + id: 'rust', + name: 'Rust', + monaco: 'rust', + extensions: ['.rs'] + }, + d: { + id: 'd', + name: 'D', + monaco: 'd', + extensions: ['.d'] + }, + go: { + id: 'go', + name: 'Go', + monaco: 'go', + extensions: ['.go'] + }, + ispc: { + id: 'ispc', + name: 'ispc', + monaco: 'ispc', + extensions: ['.ispc'] + }, + haskell: { + id: 'haskell', + name: 'Haskell', + monaco: 'haskell', + extensions: ['.hs', '.haskell'] + }, + swift: { + id: 'swift', + name: 'Swift', + monaco: 'swift', + extensions: ['.swift'] + }, + pascal: { + id: 'pascal', + name: 'Pascal', + monaco: 'pascal', + extensions: ['.pas'] + } +}; + +const fs = require('fs-extra'); +const _ = require('underscore-node'); +_.each(languages, lang => { + try { + const example = fs.readFileSync('examples/' + lang.id + '/default' + lang.extensions[0], 'utf8'); + lang.example = example; + } catch (error) { + lang.example = "Oops, something went wrong and we could not get the default code for this language."; + } +}); -function asArray() { - return _.map(languages(), _.identity); -} module.exports = { - list: languages, - toArray: asArray + list: languages }; diff --git a/lib/sources/builtin.js b/lib/sources/builtin.js index bab8f74f2..4baaa49f5 100644 --- a/lib/sources/builtin.js +++ b/lib/sources/builtin.js @@ -24,34 +24,33 @@ (function () { - var props = require('../properties.js'), + const props = require('../properties.js'), path = require('path'), - fs = require('fs'); - - var sourcePath = props.get('builtin', 'sourcepath', './examples/c++'); - var sourceMatch = new RegExp(props.get('builtin', 'extensionRe', '.*\\.cpp$')); - var examples = fs.readdirSync(sourcePath) - .filter(function (file) { - return file.match(sourceMatch); - }) - .map(function (file) { - var nicename = file.replace(/\.cpp$/, ''); - return {urlpart: nicename, name: nicename.replace(/_/g, ' '), path: path.join(sourcePath, file)}; - }).sort(function (x, y) { - return x.name.localeCompare(y.name); - }); - var byUrlpart = {}; - examples.forEach(function (e) { - byUrlpart[e.urlpart] = e.path; - }); + fs = require('fs'), + _ = require('underscore-node'); + const basePath = props.get('builtin', 'sourcePath', './examples/'); + const replacer = new RegExp('_', 'g'); + const examples = _.flatten( + fs.readdirSync(basePath) + .map(folder => { + const folerPath = path.join(basePath, folder); + return fs.readdirSync(folerPath) + .map(file => { + const filePath = path.join(folerPath, file); + const fileName = path.parse(file).name; + return {lang: folder, name: fileName.replace(replacer, ' '), path: filePath, file: fileName}; + }) + .filter(descriptor => descriptor.name !== "default") + .sort((x, y) => x.name.localeCompare(y.name)) + })); - function load(filename, callback) { - var path = byUrlpart[filename]; - if (!path) { + function load(lang, filename, callback) { + const example = _.find(examples, example => example.lang === lang && example.file === filename); + if (!example) { callback("No such path"); return; } - fs.readFile(path, 'utf-8', function (err, res) { + fs.readFile(example.path, 'utf-8', (err, res) => { if (err) { callback(err); return; @@ -61,8 +60,8 @@ } function list(callback) { - callback(null, examples.map(function (example) { - return {urlpart: example.urlpart, name: example.name}; + callback(null, examples.map(example => { + return {file: example.file, name: example.name, lang: example.lang}; })); } diff --git a/static/compiler.js b/static/compiler.js index 4f1b61ebe..cfd0eabb3 100644 --- a/static/compiler.js +++ b/static/compiler.js @@ -127,12 +127,14 @@ define(function (require) { items: this.compiler ? [this.compiler.id] : [] }).on('change', _.bind(function (e) { var val = $(e.target).val(); - ga('send', { - hitType: 'event', - eventCategory: 'SelectCompiler', - eventAction: val - }); - this.onCompilerChange(val); + if (val) { + ga('send', { + hitType: 'event', + eventCategory: 'SelectCompiler', + eventAction: val + }); + this.onCompilerChange(val); + } }, this)); var optionsChange = _.debounce(_.bind(function (e) { this.onOptionsChange($(e.target).val()); diff --git a/static/editor.js b/static/editor.js index e820db208..4dc58a4d7 100644 --- a/static/editor.js +++ b/static/editor.js @@ -96,6 +96,8 @@ define(function (require) { this.updateEditorCode(); } + this.initLoadSaver(); + var startFolded = /^[/*#;]+\s*setup.*/; if (state.source && state.source.match(startFolded)) { var foldAction = this.editor.getAction('editor.fold'); @@ -291,6 +293,7 @@ define(function (require) { this.container.layoutManager.root.contentItems[0]; insertPoint.addChild(conformanceConfig); }, this)); + this.container.setTitle(this.currentLanguage.name + " source #" + this.id); this.updateState(); } @@ -485,22 +488,26 @@ define(function (require) { } }; + Editor.prototype.initLoadSaver = function () { + this.domRoot.find('.load-save') + .off('click') + .click(_.bind(function () { + loadSave.run(_.bind(function (text) { + this.setSource(text); + this.updateState(); + this.maybeEmitChange(); + }, this), this.getSource(), this.currentLanguage); + }, this)); + }; + Editor.prototype.onLanguageChange = function (newLangId) { if (newLangId !== this.currentLanguage.id && languages[newLangId]) { var oldLangId = this.currentLanguage.id; // Save the current source, so we can come back to it later this.editorSourceByLang[oldLangId] = this.getSource(); this.currentLanguage = languages[newLangId]; + this.initLoadSaver(); monaco.editor.setModelLanguage(this.editor.getModel(), this.currentLanguage.monaco); - this.domRoot.find('.load-save') - .off('click') - .click(_.bind(function () { - loadSave.run(_.bind(function (text) { - this.setSource(text); - this.updateState(); - this.maybeEmitChange(); - }, this), this.getSource(), this.currentLanguage.extensions); - }, this)); // And now set the editor value to either the saved one or the default to the new lang this.updateEditorCode(); this.container.setTitle(this.currentLanguage.name + " source #" + this.id); diff --git a/static/loadSave.js b/static/loadSave.js index 884e87088..371df3eaa 100644 --- a/static/loadSave.js +++ b/static/loadSave.js @@ -52,21 +52,29 @@ define(function (require) { this.modal.find('.save-button').click(_.bind(this.onSaveToBrowserStorage, this)); this.modal.find('.save-file').click(_.bind(this.onSaveToFile, this)); - this.populateBuiltins(); + this.fetchBuiltins(); } - LoadSave.prototype.populateBuiltins = function () { + LoadSave.prototype.fetchBuiltins = function () { $.getJSON('source/builtin/list', _.bind(function (list) { - this.populate( - this.modal.find('.examples'), - _.map(list, _.bind(function (elem) { - return { - name: elem.name, load: _.bind(function () { - this.doLoad(elem.urlpart); - }, this) - }; - }, this))); - }, this)); + this.savedBuiltins = list; + }, this)) + }; + + LoadSave.prototype.populateBuiltins = function () { + var isVisible = _.bind(function (entry) { + return this.currentLanguage && this.currentLanguage.id === entry.lang; + }, this); + this.populate(this.modal.find('.examples'), + _.map(_.filter(this.savedBuiltins, isVisible), _.bind(function (elem) { + return { + name: elem.name, + load: _.bind(function () { + this.doLoad(elem); + }, this) + }; + }, this)) + ); }; LoadSave.prototype.populateLocalStorage = function () { @@ -108,13 +116,15 @@ define(function (require) { this.modal.modal('hide'); }; - LoadSave.prototype.run = function (onLoad, editorText, extensions) { + LoadSave.prototype.run = function (onLoad, editorText, currentLanguage) { this.populateLocalStorage(); this.onLoad = onLoad; this.editorText = editorText; // In case we don't send anything... - this.extension = extensions[0] || '.txt'; - this.modal.find('.local-file').attr('accept', _.map(extensions, function (extension) { + this.currentLanguage = currentLanguage; + this.populateBuiltins(); + this.extension = currentLanguage.extensions[0] || '.txt'; + this.modal.find('.local-file').attr('accept', _.map(currentLanguage.extensions, function (extension) { return extension + ', '; }, this)); this.modal.modal(); @@ -126,6 +136,7 @@ define(function (require) { this.alert.alert("Save name", "Invalid save name"); return; } + name += " (" + this.currentLanguage.name + ")"; var done = _.bind(function () { setLocalFile(name, this.editorText); }, this); @@ -153,11 +164,12 @@ define(function (require) { } }; - LoadSave.prototype.doLoad = function (urlpart) { + LoadSave.prototype.doLoad = function (element) { // TODO: handle errors. consider promises... - $.getJSON('source/builtin/load/' + urlpart, _.bind(function (response) { - this.onLoad(response.file); - }, this)); + $.getJSON('source/builtin/load/' + element.lang + '/' + element.file, + _.bind(function (response) { + this.onLoad(response.file); + }, this)); this.modal.modal('hide'); }; |