Fix various points raised after code reviews

Some fixes, a great slam and then some
This commit is contained in:
RabsRincon
2017-12-09 11:19:45 +01:00
parent 030cffffff
commit 43279a61ca
27 changed files with 313 additions and 317 deletions

120
app.js
View File

@@ -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;

View File

@@ -1,2 +0,0 @@
sourcepath=./examples/d/
extensionRe=.*\.d$

View File

@@ -0,0 +1 @@
sourcePath=./examples/

View File

@@ -1,2 +0,0 @@
sourcepath=./examples/go/
extensionRe=.*\.go$

View File

@@ -1,2 +0,0 @@
sourcepath=./examples/haskell/
extensionRe=.*\.hs$

View File

@@ -1,2 +0,0 @@
sourcepath=./examples/ispc/
extensionRe=.*\.ispc$

View File

@@ -1,2 +0,0 @@
sourcepath=./examples/pascal/
extensionRe=.*\.pas$

View File

@@ -1,2 +0,0 @@
sourcepath=./examples/rust/
extensionRe=.*\.rs$

View File

@@ -1,2 +0,0 @@
sourcepath=./examples/swift/
extensionRe=.*\.swift$

4
examples/c++/default.cpp Normal file
View File

@@ -0,0 +1,4 @@
// Type your code here, or load an example.
int square(int num) {
return num * num;
}

4
examples/c/default.c Normal file
View File

@@ -0,0 +1,4 @@
// Type your code here, or load an example.
int square(int num) {
return num * num;
}

47
examples/cppx/default.cpp Normal file
View File

@@ -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);
}

4
examples/d/default.d Normal file
View File

@@ -0,0 +1,4 @@
// Type your code here, or load an example.
int square(int num) {
return num * num;
}

9
examples/go/default.go Normal file
View File

@@ -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() {}

View File

@@ -0,0 +1,5 @@
module Example where
sumOverArray :: [Int] -> Int
sumOverArray (x:xs) = x + sumOverArray xs
sumOverArray [] = 0

View File

@@ -0,0 +1,4 @@
// Type your code here, or load an example.
uniform int square(uniform int num) {
return num * num;
}

View File

@@ -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.

4
examples/rust/default.rs Normal file
View File

@@ -0,0 +1,4 @@
// Type your code here, or load an example.
pub fn square(num: i32) -> i32 {
num * num
}

View File

@@ -0,0 +1,4 @@
// Type your code here, or load an example.
func square(n: Int) -> Int {
return n * n
}

View File

@@ -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);
}

View File

@@ -35,178 +35,81 @@
Leading point is needed
Used in: Save to file extension
*/
function languages() {
return {
const languages = {
'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"
extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c']
},
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"
extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c']
},
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"
extensions: ['.c', '.h']
},
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"
extensions: ['.rs']
},
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"
extensions: ['.d']
},
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"
extensions: ['.go']
},
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"
extensions: ['.ispc']
},
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"
extensions: ['.hs', '.haskell']
},
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" +
"}"
extensions: ['.swift']
},
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"
extensions: ['.pas']
}
};
}
var _ = require('underscore-node');
function asArray() {
return _.map(languages(), _.identity);
}
module.exports = {
list: languages,
toArray: asArray
};
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.";
}
});
module.exports = {
list: languages
};

View File

@@ -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);
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};
})
.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;
});
.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};
}));
}

View File

@@ -127,12 +127,14 @@ define(function (require) {
items: this.compiler ? [this.compiler.id] : []
}).on('change', _.bind(function (e) {
var val = $(e.target).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());

View File

@@ -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,13 +488,7 @@ define(function (require) {
}
};
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];
monaco.editor.setModelLanguage(this.editor.getModel(), this.currentLanguage.monaco);
Editor.prototype.initLoadSaver = function () {
this.domRoot.find('.load-save')
.off('click')
.click(_.bind(function () {
@@ -499,8 +496,18 @@ define(function (require) {
this.setSource(text);
this.updateState();
this.maybeEmitChange();
}, this), this.getSource(), this.currentLanguage.extensions);
}, 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);
// 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);

View File

@@ -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) {
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.urlpart);
name: elem.name,
load: _.bind(function () {
this.doLoad(elem);
}, this)
};
}, this)));
}, 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,9 +164,10 @@ 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) {
$.getJSON('source/builtin/load/' + element.lang + '/' + element.file,
_.bind(function (response) {
this.onLoad(response.file);
}, this));
this.modal.modal('hide');