From 380d1da258b3dde032ab53ad4334cab06f2971ac Mon Sep 17 00:00:00 2001 From: Jared Krinke Date: Mon, 21 Nov 2022 13:44:28 -0800 Subject: [PATCH 1/2] Always use HTTPS --- documentation.html | 2 +- index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation.html b/documentation.html index 10521206..4670f6d1 100644 --- a/documentation.html +++ b/documentation.html @@ -4,7 +4,7 @@ Elevator Saga - help and API documentation - + diff --git a/index.html b/index.html index 7f39c39a..46707c46 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ Elevator Saga - the elevator programming game - + From e78403411bc1106a4e2cf3b144fdec49cd285092 Mon Sep 17 00:00:00 2001 From: Jared Krinke Date: Mon, 21 Nov 2022 15:20:21 -0800 Subject: [PATCH 2/2] Switch to Monaco Editor and add auto-complete --- app.js | 434 +- documentation.html | 5 +- index.html | 20 +- libs/codemirror/addon/edit/closebrackets.js | 159 - libs/codemirror/codemirror.css | 309 - libs/codemirror/codemirror.js | 8045 ----------------- libs/codemirror/mode/javascript/index.html | 114 - libs/codemirror/mode/javascript/javascript.js | 692 -- libs/codemirror/mode/javascript/json-ld.html | 72 - libs/codemirror/mode/javascript/test.js | 200 - .../mode/javascript/typescript.html | 61 - libs/codemirror/themes/solarized.css | 170 - style.css | 10 +- types.js | 91 + 14 files changed, 323 insertions(+), 10059 deletions(-) delete mode 100644 libs/codemirror/addon/edit/closebrackets.js delete mode 100644 libs/codemirror/codemirror.css delete mode 100644 libs/codemirror/codemirror.js delete mode 100644 libs/codemirror/mode/javascript/index.html delete mode 100644 libs/codemirror/mode/javascript/javascript.js delete mode 100644 libs/codemirror/mode/javascript/json-ld.html delete mode 100644 libs/codemirror/mode/javascript/test.js delete mode 100644 libs/codemirror/mode/javascript/typescript.html delete mode 100644 libs/codemirror/themes/solarized.css create mode 100644 types.js diff --git a/app.js b/app.js index 7a101a76..ffdf171e 100644 --- a/app.js +++ b/app.js @@ -1,113 +1,101 @@ - -var createEditor = function() { +const createEditorAsync = () => new Promise((resolve, reject) => { var lsKey = "elevatorCrushCode_v5"; - var cm = CodeMirror.fromTextArea(document.getElementById("code"), { - lineNumbers: true, - indentUnit: 4, - indentWithTabs: false, - theme: "solarized light", - mode: "javascript", - autoCloseBrackets: true, - extraKeys: { - // the following Tab key mapping is from http://codemirror.net/doc/manual.html#keymaps - Tab: function(cm) { - var spaces = new Array(cm.getOption("indentUnit") + 1).join(" "); - cm.replaceSelection(spaces); - } - } - }); - - // reindent on paste (adapted from https://github.com/ahuth/brackets-paste-and-indent/blob/master/main.js) - cm.on("change", function(codeMirror, change) { - if(change.origin !== "paste") { - return; - } - - var lineFrom = change.from.line; - var lineTo = change.from.line + change.text.length; - - function reindentLines(codeMirror, lineFrom, lineTo) { - codeMirror.operation(function() { - codeMirror.eachLine(lineFrom, lineTo, function(lineHandle) { - codeMirror.indentLine(lineHandle.lineNo(), "smart"); - }); - }); + // Load Monaco Editor from CDN + require.config({ paths: { "vs": "https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.29.1/min/vs/" }}); + window.MonacoEnvironment = { + getWorkerUrl: function(workerId, label) { + return `data:text/javascript;charset=utf-8,${encodeURIComponent(` + self.MonacoEnvironment = { baseUrl: "https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.29.1/min/" }; + importScripts("https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.29.1/min/vs/base/worker/workerMain.min.js");` + )}`; } - - reindentLines(codeMirror, lineFrom, lineTo); - }); - - var reset = function() { - cm.setValue($("#default-elev-implementation").text().trim()); }; - var saveCode = function() { - localStorage.setItem(lsKey, cm.getValue()); - $("#save_message").text("Code saved " + new Date().toTimeString()); - returnObj.trigger("change"); - }; - - var existingCode = localStorage.getItem(lsKey); - if(existingCode) { - cm.setValue(existingCode); - } else { - reset(); - } - - $("#button_save").click(function() { - saveCode(); - cm.focus(); - }); + + require(["vs/editor/editor.main"], function () { + // Create the editor with some sample JavaScript code + const cm = monaco.editor.create(document.getElementById("editor"), { + theme: "vs-dark", + folding: false, + minimap: { enabled: false }, + language: "javascript", + value: "// code goes here\n" + }); - $("#button_reset").click(function() { - if(confirm("Do you really want to reset to the default implementation?")) { - localStorage.setItem("develevateBackupCode", cm.getValue()); + // Add type declarations + monaco.languages.typescript.javascriptDefaults.addExtraLib(typeDeclarations); + + // Original setup code + var reset = function() { + cm.setValue($("#default-elev-implementation").text().trim()); + }; + var saveCode = function() { + localStorage.setItem(lsKey, cm.getValue()); + $("#save_message").text("Code saved " + new Date().toTimeString()); + returnObj.trigger("change"); + }; + + var existingCode = localStorage.getItem(lsKey); + if(existingCode) { + cm.setValue(existingCode); + } else { reset(); } - cm.focus(); - }); - - $("#button_resetundo").click(function() { - if(confirm("Do you want to bring back the code as before the last reset?")) { - cm.setValue(localStorage.getItem("develevateBackupCode") || ""); + + $("#button_save").click(function() { + saveCode(); + cm.focus(); + }); + + $("#button_reset").click(function() { + if(confirm("Do you really want to reset to the default implementation?")) { + localStorage.setItem("develevateBackupCode", cm.getValue()); + reset(); + } + cm.focus(); + }); + + $("#button_resetundo").click(function() { + if(confirm("Do you want to bring back the code as before the last reset?")) { + cm.setValue(localStorage.getItem("develevateBackupCode") || ""); + } + cm.focus(); + }); + + var returnObj = riot.observable({}); + var autoSaver = _.debounce(saveCode, 1000); + cm.onDidChangeModelContent = autoSaver; + + returnObj.getCodeObj = function() { + console.log("Getting code..."); + var code = cm.getValue(); + var obj; + try { + obj = getCodeObjFromCode(code); + returnObj.trigger("code_success"); + } catch(e) { + returnObj.trigger("usercode_error", e); + return null; + } + return obj; + }; + returnObj.setCode = function(code) { + cm.setValue(code); + }; + returnObj.getCode = function() { + return cm.getValue(); } - cm.focus(); - }); - - var returnObj = riot.observable({}); - var autoSaver = _.debounce(saveCode, 1000); - cm.on("change", function() { - autoSaver(); - }); - - returnObj.getCodeObj = function() { - console.log("Getting code..."); - var code = cm.getValue(); - var obj; - try { - obj = getCodeObjFromCode(code); - returnObj.trigger("code_success"); - } catch(e) { - returnObj.trigger("usercode_error", e); - return null; + returnObj.setDevTestCode = function() { + cm.setValue($("#devtest-elev-implementation").text().trim()); } - return obj; - }; - returnObj.setCode = function(code) { - cm.setValue(code); - }; - returnObj.getCode = function() { - return cm.getValue(); - } - returnObj.setDevTestCode = function() { - cm.setValue($("#devtest-elev-implementation").text().trim()); - } - - $("#button_apply").click(function() { - returnObj.trigger("apply_code"); + + $("#button_apply").click(function() { + returnObj.trigger("apply_code"); + }); + + resolve(returnObj); }); - return returnObj; -}; +}); var createParamsUrl = function(current, overrides) { @@ -120,133 +108,133 @@ var createParamsUrl = function(current, overrides) { $(function() { var tsKey = "elevatorTimeScale"; - var editor = createEditor(); - - var params = {}; - - var $world = $(".innerworld"); - var $stats = $(".statscontainer"); - var $feedback = $(".feedbackcontainer"); - var $challenge = $(".challenge"); - var $codestatus = $(".codestatus"); - - var floorTempl = document.getElementById("floor-template").innerHTML.trim(); - var elevatorTempl = document.getElementById("elevator-template").innerHTML.trim(); - var elevatorButtonTempl = document.getElementById("elevatorbutton-template").innerHTML.trim(); - var userTempl = document.getElementById("user-template").innerHTML.trim(); - var challengeTempl = document.getElementById("challenge-template").innerHTML.trim(); - var feedbackTempl = document.getElementById("feedback-template").innerHTML.trim(); - var codeStatusTempl = document.getElementById("codestatus-template").innerHTML.trim(); - - var app = riot.observable({}); - app.worldController = createWorldController(1.0 / 60.0); - app.worldController.on("usercode_error", function(e) { - console.log("World raised code error", e); - editor.trigger("usercode_error", e); - }); - - console.log(app.worldController); - app.worldCreator = createWorldCreator(); - app.world = undefined; - - app.currentChallengeIndex = 0; - - app.startStopOrRestart = function() { - if(app.world.challengeEnded) { - app.startChallenge(app.currentChallengeIndex); - } else { - app.worldController.setPaused(!app.worldController.isPaused); - } - }; - - app.startChallenge = function(challengeIndex, autoStart) { - if(typeof app.world !== "undefined") { - app.world.unWind(); - // TODO: Investigate if memory leaks happen here - } - app.currentChallengeIndex = challengeIndex; - app.world = app.worldCreator.createWorld(challenges[challengeIndex].options); - window.world = app.world; - - clearAll([$world, $feedback]); - presentStats($stats, app.world); - presentChallenge($challenge, challenges[challengeIndex], app, app.world, app.worldController, challengeIndex + 1, challengeTempl); - presentWorld($world, app.world, floorTempl, elevatorTempl, elevatorButtonTempl, userTempl); - - app.worldController.on("timescale_changed", function() { - localStorage.setItem(tsKey, app.worldController.timeScale); - presentChallenge($challenge, challenges[challengeIndex], app, app.world, app.worldController, challengeIndex + 1, challengeTempl); + createEditorAsync().then(editor => { + var params = {}; + + var $world = $(".innerworld"); + var $stats = $(".statscontainer"); + var $feedback = $(".feedbackcontainer"); + var $challenge = $(".challenge"); + var $codestatus = $(".codestatus"); + + var floorTempl = document.getElementById("floor-template").innerHTML.trim(); + var elevatorTempl = document.getElementById("elevator-template").innerHTML.trim(); + var elevatorButtonTempl = document.getElementById("elevatorbutton-template").innerHTML.trim(); + var userTempl = document.getElementById("user-template").innerHTML.trim(); + var challengeTempl = document.getElementById("challenge-template").innerHTML.trim(); + var feedbackTempl = document.getElementById("feedback-template").innerHTML.trim(); + var codeStatusTempl = document.getElementById("codestatus-template").innerHTML.trim(); + + var app = riot.observable({}); + app.worldController = createWorldController(1.0 / 60.0); + app.worldController.on("usercode_error", function(e) { + console.log("World raised code error", e); + editor.trigger("usercode_error", e); }); - - app.world.on("stats_changed", function() { - var challengeStatus = challenges[challengeIndex].condition.evaluate(app.world); - if(challengeStatus !== null) { - app.world.challengeEnded = true; - app.worldController.setPaused(true); - if(challengeStatus) { - presentFeedback($feedback, feedbackTempl, app.world, "Success!", "Challenge completed", createParamsUrl(params, { challenge: (challengeIndex + 2)})); - } else { - presentFeedback($feedback, feedbackTempl, app.world, "Challenge failed", "Maybe your program needs an improvement?", ""); - } + + console.log(app.worldController); + app.worldCreator = createWorldCreator(); + app.world = undefined; + + app.currentChallengeIndex = 0; + + app.startStopOrRestart = function() { + if(app.world.challengeEnded) { + app.startChallenge(app.currentChallengeIndex); + } else { + app.worldController.setPaused(!app.worldController.isPaused); } + }; + + app.startChallenge = function(challengeIndex, autoStart) { + if(typeof app.world !== "undefined") { + app.world.unWind(); + // TODO: Investigate if memory leaks happen here + } + app.currentChallengeIndex = challengeIndex; + app.world = app.worldCreator.createWorld(challenges[challengeIndex].options); + window.world = app.world; + + clearAll([$world, $feedback]); + presentStats($stats, app.world); + presentChallenge($challenge, challenges[challengeIndex], app, app.world, app.worldController, challengeIndex + 1, challengeTempl); + presentWorld($world, app.world, floorTempl, elevatorTempl, elevatorButtonTempl, userTempl); + + app.worldController.on("timescale_changed", function() { + localStorage.setItem(tsKey, app.worldController.timeScale); + presentChallenge($challenge, challenges[challengeIndex], app, app.world, app.worldController, challengeIndex + 1, challengeTempl); + }); + + app.world.on("stats_changed", function() { + var challengeStatus = challenges[challengeIndex].condition.evaluate(app.world); + if(challengeStatus !== null) { + app.world.challengeEnded = true; + app.worldController.setPaused(true); + if(challengeStatus) { + presentFeedback($feedback, feedbackTempl, app.world, "Success!", "Challenge completed", createParamsUrl(params, { challenge: (challengeIndex + 2)})); + } else { + presentFeedback($feedback, feedbackTempl, app.world, "Challenge failed", "Maybe your program needs an improvement?", ""); + } + } + }); + + var codeObj = editor.getCodeObj(); + console.log("Starting..."); + app.worldController.start(app.world, codeObj, window.requestAnimationFrame, autoStart); + }; + + editor.on("apply_code", function() { + app.startChallenge(app.currentChallengeIndex, true); }); - - var codeObj = editor.getCodeObj(); - console.log("Starting..."); - app.worldController.start(app.world, codeObj, window.requestAnimationFrame, autoStart); - }; - - editor.on("apply_code", function() { - app.startChallenge(app.currentChallengeIndex, true); - }); - editor.on("code_success", function() { - presentCodeStatus($codestatus, codeStatusTempl); - }); - editor.on("usercode_error", function(error) { - presentCodeStatus($codestatus, codeStatusTempl, error); - }); - editor.on("change", function() { - $("#fitness_message").addClass("faded"); - var codeStr = editor.getCode(); - // fitnessSuite(codeStr, true, function(results) { - // var message = ""; - // if(!results.error) { - // message = "Fitness avg wait times: " + _.map(results, function(r){ return r.options.description + ": " + r.result.avgWaitTime.toPrecision(3) + "s" }).join("   "); - // } else { - // message = "Could not compute fitness due to error: " + results.error; - // } - // $("#fitness_message").html(message).removeClass("faded"); - // }); - }); - editor.trigger("change"); - - riot.route(function(path) { - params = _.reduce(path.split(","), function(result, p) { - var match = p.match(/(\w+)=(\w+$)/); - if(match) { result[match[1]] = match[2]; } return result; - }, {}); - var requestedChallenge = 0; - var autoStart = false; - var timeScale = parseFloat(localStorage.getItem(tsKey)) || 2.0; - _.each(params, function(val, key) { - if(key === "challenge") { - requestedChallenge = _.parseInt(val) - 1; - if(requestedChallenge < 0 || requestedChallenge >= challenges.length) { - console.log("Invalid challenge index", requestedChallenge); - console.log("Defaulting to first challenge"); - requestedChallenge = 0; + editor.on("code_success", function() { + presentCodeStatus($codestatus, codeStatusTempl); + }); + editor.on("usercode_error", function(error) { + presentCodeStatus($codestatus, codeStatusTempl, error); + }); + editor.on("change", function() { + $("#fitness_message").addClass("faded"); + var codeStr = editor.getCode(); + // fitnessSuite(codeStr, true, function(results) { + // var message = ""; + // if(!results.error) { + // message = "Fitness avg wait times: " + _.map(results, function(r){ return r.options.description + ": " + r.result.avgWaitTime.toPrecision(3) + "s" }).join("   "); + // } else { + // message = "Could not compute fitness due to error: " + results.error; + // } + // $("#fitness_message").html(message).removeClass("faded"); + // }); + }); + editor.trigger("change"); + + riot.route(function(path) { + params = _.reduce(path.split(","), function(result, p) { + var match = p.match(/(\w+)=(\w+$)/); + if(match) { result[match[1]] = match[2]; } return result; + }, {}); + var requestedChallenge = 0; + var autoStart = false; + var timeScale = parseFloat(localStorage.getItem(tsKey)) || 2.0; + _.each(params, function(val, key) { + if(key === "challenge") { + requestedChallenge = _.parseInt(val) - 1; + if(requestedChallenge < 0 || requestedChallenge >= challenges.length) { + console.log("Invalid challenge index", requestedChallenge); + console.log("Defaulting to first challenge"); + requestedChallenge = 0; + } + } else if(key === "autostart") { + autoStart = val === "false" ? false : true; + } else if(key === "timescale") { + timeScale = parseFloat(val); + } else if(key === "devtest") { + editor.setDevTestCode(); + } else if(key === "fullscreen") { + makeDemoFullscreen(); } - } else if(key === "autostart") { - autoStart = val === "false" ? false : true; - } else if(key === "timescale") { - timeScale = parseFloat(val); - } else if(key === "devtest") { - editor.setDevTestCode(); - } else if(key === "fullscreen") { - makeDemoFullscreen(); - } + }); + app.worldController.setTimeScale(timeScale); + app.startChallenge(requestedChallenge, autoStart); }); - app.worldController.setTimeScale(timeScale); - app.startChallenge(requestedChallenge, autoStart); }); }); diff --git a/documentation.html b/documentation.html index 4670f6d1..b570daf9 100644 --- a/documentation.html +++ b/documentation.html @@ -46,7 +46,8 @@

Basics

Your code must declare an object containing at least two functions called init and update. Like this:

-
{
+            
/** @type {Solution} */
+({
     init: function(elevators, floors) {
         // Do stuff with the elevators and floors, which are both arrays of objects
     },
@@ -54,7 +55,7 @@ 

Basics

// Do more stuff with the elevators and floors // dt is the number of game seconds that passed since the last time update was called } -}
+})

These functions will then be called by the game during the challenge.
init will be called when the challenge starts, and update repeatedly during the challenge.

diff --git a/index.html b/index.html index 46707c46..42131a72 100644 --- a/index.html +++ b/index.html @@ -13,10 +13,6 @@ - - - - @@ -29,6 +25,7 @@ + @@ -84,7 +81,8 @@
-{ +/** @type {Solution} */ +({ init: function(elevators, floors) { var elevator = elevators[0]; // Let's use the first elevator @@ -98,10 +96,11 @@
-{ +/** @type {Solution} */ +({ init: function(elevators, floors) { var selectElevatorForFloorPickup = function(floorNum) { return _.max(elevators, function(e) { @@ -130,7 +129,7 @@
- +
@@ -188,6 +187,9 @@

Run tests

+ + + - - - - - - - -
-

JavaScript mode

- - -
- - - -

- JavaScript mode supports several configuration options: -

    -
  • json which will set the mode to expect JSON - data rather than a JavaScript program.
  • -
  • jsonld which will set the mode to expect - JSON-LD linked data rather - than a JavaScript program (demo).
  • -
  • typescript which will activate additional - syntax highlighting and some other things for TypeScript code - (demo).
  • -
  • statementIndent which (given a number) will - determine the amount of indentation to use for statements - continued on a new line.
  • -
  • wordCharacters, a regexp that indicates which - characters should be considered part of an identifier. - Defaults to /[\w$]/, which does not handle - non-ASCII identifiers. Can be set to something more elaborate - to improve Unicode support.
  • -
-

- -

MIME types defined: text/javascript, application/json, application/ld+json, text/typescript, application/typescript.

-
diff --git a/libs/codemirror/mode/javascript/javascript.js b/libs/codemirror/mode/javascript/javascript.js deleted file mode 100644 index 93df06d1..00000000 --- a/libs/codemirror/mode/javascript/javascript.js +++ /dev/null @@ -1,692 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE - -// TODO actually recognize syntax of TypeScript constructs - -(function(mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); -})(function(CodeMirror) { -"use strict"; - -CodeMirror.defineMode("javascript", function(config, parserConfig) { - var indentUnit = config.indentUnit; - var statementIndent = parserConfig.statementIndent; - var jsonldMode = parserConfig.jsonld; - var jsonMode = parserConfig.json || jsonldMode; - var isTS = parserConfig.typescript; - var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; - - // Tokenizer - - var keywords = function(){ - function kw(type) {return {type: type, style: "keyword"};} - var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); - var operator = kw("operator"), atom = {type: "atom", style: "atom"}; - - var jsKeywords = { - "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, - "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C, - "var": kw("var"), "const": kw("var"), "let": kw("var"), - "function": kw("function"), "catch": kw("catch"), - "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), - "in": operator, "typeof": operator, "instanceof": operator, - "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, - "this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"), - "yield": C, "export": kw("export"), "import": kw("import"), "extends": C - }; - - // Extend the 'normal' keywords with the TypeScript language extensions - if (isTS) { - var type = {type: "variable", style: "variable-3"}; - var tsKeywords = { - // object-like things - "interface": kw("interface"), - "extends": kw("extends"), - "constructor": kw("constructor"), - - // scope modifiers - "public": kw("public"), - "private": kw("private"), - "protected": kw("protected"), - "static": kw("static"), - - // types - "string": type, "number": type, "bool": type, "any": type - }; - - for (var attr in tsKeywords) { - jsKeywords[attr] = tsKeywords[attr]; - } - } - - return jsKeywords; - }(); - - var isOperatorChar = /[+\-*&%=<>!?|~^]/; - var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; - - function readRegexp(stream) { - var escaped = false, next, inSet = false; - while ((next = stream.next()) != null) { - if (!escaped) { - if (next == "/" && !inSet) return; - if (next == "[") inSet = true; - else if (inSet && next == "]") inSet = false; - } - escaped = !escaped && next == "\\"; - } - } - - // Used as scratch variables to communicate multiple values without - // consing up tons of objects. - var type, content; - function ret(tp, style, cont) { - type = tp; content = cont; - return style; - } - function tokenBase(stream, state) { - var ch = stream.next(); - if (ch == '"' || ch == "'") { - state.tokenize = tokenString(ch); - return state.tokenize(stream, state); - } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { - return ret("number", "number"); - } else if (ch == "." && stream.match("..")) { - return ret("spread", "meta"); - } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { - return ret(ch); - } else if (ch == "=" && stream.eat(">")) { - return ret("=>", "operator"); - } else if (ch == "0" && stream.eat(/x/i)) { - stream.eatWhile(/[\da-f]/i); - return ret("number", "number"); - } else if (/\d/.test(ch)) { - stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); - return ret("number", "number"); - } else if (ch == "/") { - if (stream.eat("*")) { - state.tokenize = tokenComment; - return tokenComment(stream, state); - } else if (stream.eat("/")) { - stream.skipToEnd(); - return ret("comment", "comment"); - } else if (state.lastType == "operator" || state.lastType == "keyword c" || - state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) { - readRegexp(stream); - stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla - return ret("regexp", "string-2"); - } else { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator", stream.current()); - } - } else if (ch == "`") { - state.tokenize = tokenQuasi; - return tokenQuasi(stream, state); - } else if (ch == "#") { - stream.skipToEnd(); - return ret("error", "error"); - } else if (isOperatorChar.test(ch)) { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator", stream.current()); - } else if (wordRE.test(ch)) { - stream.eatWhile(wordRE); - var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; - return (known && state.lastType != ".") ? ret(known.type, known.style, word) : - ret("variable", "variable", word); - } - } - - function tokenString(quote) { - return function(stream, state) { - var escaped = false, next; - if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ - state.tokenize = tokenBase; - return ret("jsonld-keyword", "meta"); - } - while ((next = stream.next()) != null) { - if (next == quote && !escaped) break; - escaped = !escaped && next == "\\"; - } - if (!escaped) state.tokenize = tokenBase; - return ret("string", "string"); - }; - } - - function tokenComment(stream, state) { - var maybeEnd = false, ch; - while (ch = stream.next()) { - if (ch == "/" && maybeEnd) { - state.tokenize = tokenBase; - break; - } - maybeEnd = (ch == "*"); - } - return ret("comment", "comment"); - } - - function tokenQuasi(stream, state) { - var escaped = false, next; - while ((next = stream.next()) != null) { - if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) { - state.tokenize = tokenBase; - break; - } - escaped = !escaped && next == "\\"; - } - return ret("quasi", "string-2", stream.current()); - } - - var brackets = "([{}])"; - // This is a crude lookahead trick to try and notice that we're - // parsing the argument patterns for a fat-arrow function before we - // actually hit the arrow token. It only works if the arrow is on - // the same line as the arguments and there's no strange noise - // (comments) in between. Fallback is to only notice when we hit the - // arrow, and not declare the arguments as locals for the arrow - // body. - function findFatArrow(stream, state) { - if (state.fatArrowAt) state.fatArrowAt = null; - var arrow = stream.string.indexOf("=>", stream.start); - if (arrow < 0) return; - - var depth = 0, sawSomething = false; - for (var pos = arrow - 1; pos >= 0; --pos) { - var ch = stream.string.charAt(pos); - var bracket = brackets.indexOf(ch); - if (bracket >= 0 && bracket < 3) { - if (!depth) { ++pos; break; } - if (--depth == 0) break; - } else if (bracket >= 3 && bracket < 6) { - ++depth; - } else if (wordRE.test(ch)) { - sawSomething = true; - } else if (/["'\/]/.test(ch)) { - return; - } else if (sawSomething && !depth) { - ++pos; - break; - } - } - if (sawSomething && !depth) state.fatArrowAt = pos; - } - - // Parser - - var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true}; - - function JSLexical(indented, column, type, align, prev, info) { - this.indented = indented; - this.column = column; - this.type = type; - this.prev = prev; - this.info = info; - if (align != null) this.align = align; - } - - function inScope(state, varname) { - for (var v = state.localVars; v; v = v.next) - if (v.name == varname) return true; - for (var cx = state.context; cx; cx = cx.prev) { - for (var v = cx.vars; v; v = v.next) - if (v.name == varname) return true; - } - } - - function parseJS(state, style, type, content, stream) { - var cc = state.cc; - // Communicate our context to the combinators. - // (Less wasteful than consing up a hundred closures on every call.) - cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; - - if (!state.lexical.hasOwnProperty("align")) - state.lexical.align = true; - - while(true) { - var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; - if (combinator(type, content)) { - while(cc.length && cc[cc.length - 1].lex) - cc.pop()(); - if (cx.marked) return cx.marked; - if (type == "variable" && inScope(state, content)) return "variable-2"; - return style; - } - } - } - - // Combinator utils - - var cx = {state: null, column: null, marked: null, cc: null}; - function pass() { - for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); - } - function cont() { - pass.apply(null, arguments); - return true; - } - function register(varname) { - function inList(list) { - for (var v = list; v; v = v.next) - if (v.name == varname) return true; - return false; - } - var state = cx.state; - if (state.context) { - cx.marked = "def"; - if (inList(state.localVars)) return; - state.localVars = {name: varname, next: state.localVars}; - } else { - if (inList(state.globalVars)) return; - if (parserConfig.globalVars) - state.globalVars = {name: varname, next: state.globalVars}; - } - } - - // Combinators - - var defaultVars = {name: "this", next: {name: "arguments"}}; - function pushcontext() { - cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; - cx.state.localVars = defaultVars; - } - function popcontext() { - cx.state.localVars = cx.state.context.vars; - cx.state.context = cx.state.context.prev; - } - function pushlex(type, info) { - var result = function() { - var state = cx.state, indent = state.indented; - if (state.lexical.type == "stat") indent = state.lexical.indented; - else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) - indent = outer.indented; - state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); - }; - result.lex = true; - return result; - } - function poplex() { - var state = cx.state; - if (state.lexical.prev) { - if (state.lexical.type == ")") - state.indented = state.lexical.indented; - state.lexical = state.lexical.prev; - } - } - poplex.lex = true; - - function expect(wanted) { - function exp(type) { - if (type == wanted) return cont(); - else if (wanted == ";") return pass(); - else return cont(exp); - }; - return exp; - } - - function statement(type, value) { - if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); - if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); - if (type == "keyword b") return cont(pushlex("form"), statement, poplex); - if (type == "{") return cont(pushlex("}"), block, poplex); - if (type == ";") return cont(); - if (type == "if") { - if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) - cx.state.cc.pop()(); - return cont(pushlex("form"), expression, statement, poplex, maybeelse); - } - if (type == "function") return cont(functiondef); - if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); - if (type == "variable") return cont(pushlex("stat"), maybelabel); - if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), - block, poplex, poplex); - if (type == "case") return cont(expression, expect(":")); - if (type == "default") return cont(expect(":")); - if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), - statement, poplex, popcontext); - if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex); - if (type == "class") return cont(pushlex("form"), className, poplex); - if (type == "export") return cont(pushlex("form"), afterExport, poplex); - if (type == "import") return cont(pushlex("form"), afterImport, poplex); - return pass(pushlex("stat"), expression, expect(";"), poplex); - } - function expression(type) { - return expressionInner(type, false); - } - function expressionNoComma(type) { - return expressionInner(type, true); - } - function expressionInner(type, noComma) { - if (cx.state.fatArrowAt == cx.stream.start) { - var body = noComma ? arrowBodyNoComma : arrowBody; - if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext); - else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext); - } - - var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; - if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); - if (type == "function") return cont(functiondef, maybeop); - if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression); - if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop); - if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); - if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); - if (type == "{") return contCommasep(objprop, "}", null, maybeop); - if (type == "quasi") { return pass(quasi, maybeop); } - return cont(); - } - function maybeexpression(type) { - if (type.match(/[;\}\)\],]/)) return pass(); - return pass(expression); - } - function maybeexpressionNoComma(type) { - if (type.match(/[;\}\)\],]/)) return pass(); - return pass(expressionNoComma); - } - - function maybeoperatorComma(type, value) { - if (type == ",") return cont(expression); - return maybeoperatorNoComma(type, value, false); - } - function maybeoperatorNoComma(type, value, noComma) { - var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; - var expr = noComma == false ? expression : expressionNoComma; - if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); - if (type == "operator") { - if (/\+\+|--/.test(value)) return cont(me); - if (value == "?") return cont(expression, expect(":"), expr); - return cont(expr); - } - if (type == "quasi") { return pass(quasi, me); } - if (type == ";") return; - if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); - if (type == ".") return cont(property, me); - if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); - } - function quasi(type, value) { - if (type != "quasi") return pass(); - if (value.slice(value.length - 2) != "${") return cont(quasi); - return cont(expression, continueQuasi); - } - function continueQuasi(type) { - if (type == "}") { - cx.marked = "string-2"; - cx.state.tokenize = tokenQuasi; - return cont(quasi); - } - } - function arrowBody(type) { - findFatArrow(cx.stream, cx.state); - return pass(type == "{" ? statement : expression); - } - function arrowBodyNoComma(type) { - findFatArrow(cx.stream, cx.state); - return pass(type == "{" ? statement : expressionNoComma); - } - function maybelabel(type) { - if (type == ":") return cont(poplex, statement); - return pass(maybeoperatorComma, expect(";"), poplex); - } - function property(type) { - if (type == "variable") {cx.marked = "property"; return cont();} - } - function objprop(type, value) { - if (type == "variable" || cx.style == "keyword") { - cx.marked = "property"; - if (value == "get" || value == "set") return cont(getterSetter); - return cont(afterprop); - } else if (type == "number" || type == "string") { - cx.marked = jsonldMode ? "property" : (cx.style + " property"); - return cont(afterprop); - } else if (type == "jsonld-keyword") { - return cont(afterprop); - } else if (type == "[") { - return cont(expression, expect("]"), afterprop); - } - } - function getterSetter(type) { - if (type != "variable") return pass(afterprop); - cx.marked = "property"; - return cont(functiondef); - } - function afterprop(type) { - if (type == ":") return cont(expressionNoComma); - if (type == "(") return pass(functiondef); - } - function commasep(what, end) { - function proceed(type) { - if (type == ",") { - var lex = cx.state.lexical; - if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; - return cont(what, proceed); - } - if (type == end) return cont(); - return cont(expect(end)); - } - return function(type) { - if (type == end) return cont(); - return pass(what, proceed); - }; - } - function contCommasep(what, end, info) { - for (var i = 3; i < arguments.length; i++) - cx.cc.push(arguments[i]); - return cont(pushlex(end, info), commasep(what, end), poplex); - } - function block(type) { - if (type == "}") return cont(); - return pass(statement, block); - } - function maybetype(type) { - if (isTS && type == ":") return cont(typedef); - } - function typedef(type) { - if (type == "variable"){cx.marked = "variable-3"; return cont();} - } - function vardef() { - return pass(pattern, maybetype, maybeAssign, vardefCont); - } - function pattern(type, value) { - if (type == "variable") { register(value); return cont(); } - if (type == "[") return contCommasep(pattern, "]"); - if (type == "{") return contCommasep(proppattern, "}"); - } - function proppattern(type, value) { - if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { - register(value); - return cont(maybeAssign); - } - if (type == "variable") cx.marked = "property"; - return cont(expect(":"), pattern, maybeAssign); - } - function maybeAssign(_type, value) { - if (value == "=") return cont(expressionNoComma); - } - function vardefCont(type) { - if (type == ",") return cont(vardef); - } - function maybeelse(type, value) { - if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); - } - function forspec(type) { - if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); - } - function forspec1(type) { - if (type == "var") return cont(vardef, expect(";"), forspec2); - if (type == ";") return cont(forspec2); - if (type == "variable") return cont(formaybeinof); - return pass(expression, expect(";"), forspec2); - } - function formaybeinof(_type, value) { - if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } - return cont(maybeoperatorComma, forspec2); - } - function forspec2(type, value) { - if (type == ";") return cont(forspec3); - if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } - return pass(expression, expect(";"), forspec3); - } - function forspec3(type) { - if (type != ")") cont(expression); - } - function functiondef(type, value) { - if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} - if (type == "variable") {register(value); return cont(functiondef);} - if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext); - } - function funarg(type) { - if (type == "spread") return cont(funarg); - return pass(pattern, maybetype); - } - function className(type, value) { - if (type == "variable") {register(value); return cont(classNameAfter);} - } - function classNameAfter(type, value) { - if (value == "extends") return cont(expression, classNameAfter); - if (type == "{") return cont(pushlex("}"), classBody, poplex); - } - function classBody(type, value) { - if (type == "variable" || cx.style == "keyword") { - cx.marked = "property"; - if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody); - return cont(functiondef, classBody); - } - if (value == "*") { - cx.marked = "keyword"; - return cont(classBody); - } - if (type == ";") return cont(classBody); - if (type == "}") return cont(); - } - function classGetterSetter(type) { - if (type != "variable") return pass(); - cx.marked = "property"; - return cont(); - } - function afterModule(type, value) { - if (type == "string") return cont(statement); - if (type == "variable") { register(value); return cont(maybeFrom); } - } - function afterExport(_type, value) { - if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } - if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } - return pass(statement); - } - function afterImport(type) { - if (type == "string") return cont(); - return pass(importSpec, maybeFrom); - } - function importSpec(type, value) { - if (type == "{") return contCommasep(importSpec, "}"); - if (type == "variable") register(value); - return cont(); - } - function maybeFrom(_type, value) { - if (value == "from") { cx.marked = "keyword"; return cont(expression); } - } - function arrayLiteral(type) { - if (type == "]") return cont(); - return pass(expressionNoComma, maybeArrayComprehension); - } - function maybeArrayComprehension(type) { - if (type == "for") return pass(comprehension, expect("]")); - if (type == ",") return cont(commasep(maybeexpressionNoComma, "]")); - return pass(commasep(expressionNoComma, "]")); - } - function comprehension(type) { - if (type == "for") return cont(forspec, comprehension); - if (type == "if") return cont(expression, comprehension); - } - - function isContinuedStatement(state, textAfter) { - return state.lastType == "operator" || state.lastType == "," || - isOperatorChar.test(textAfter.charAt(0)) || - /[,.]/.test(textAfter.charAt(0)); - } - - // Interface - - return { - startState: function(basecolumn) { - var state = { - tokenize: tokenBase, - lastType: "sof", - cc: [], - lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), - localVars: parserConfig.localVars, - context: parserConfig.localVars && {vars: parserConfig.localVars}, - indented: 0 - }; - if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") - state.globalVars = parserConfig.globalVars; - return state; - }, - - token: function(stream, state) { - if (stream.sol()) { - if (!state.lexical.hasOwnProperty("align")) - state.lexical.align = false; - state.indented = stream.indentation(); - findFatArrow(stream, state); - } - if (state.tokenize != tokenComment && stream.eatSpace()) return null; - var style = state.tokenize(stream, state); - if (type == "comment") return style; - state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; - return parseJS(state, style, type, content, stream); - }, - - indent: function(state, textAfter) { - if (state.tokenize == tokenComment) return CodeMirror.Pass; - if (state.tokenize != tokenBase) return 0; - var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; - // Kludge to prevent 'maybelse' from blocking lexical scope pops - if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { - var c = state.cc[i]; - if (c == poplex) lexical = lexical.prev; - else if (c != maybeelse) break; - } - if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; - if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") - lexical = lexical.prev; - var type = lexical.type, closing = firstChar == type; - - if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0); - else if (type == "form" && firstChar == "{") return lexical.indented; - else if (type == "form") return lexical.indented + indentUnit; - else if (type == "stat") - return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0); - else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) - return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); - else if (lexical.align) return lexical.column + (closing ? 0 : 1); - else return lexical.indented + (closing ? 0 : indentUnit); - }, - - electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, - blockCommentStart: jsonMode ? null : "/*", - blockCommentEnd: jsonMode ? null : "*/", - lineComment: jsonMode ? null : "//", - fold: "brace", - - helperType: jsonMode ? "json" : "javascript", - jsonldMode: jsonldMode, - jsonMode: jsonMode - }; -}); - -CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); - -CodeMirror.defineMIME("text/javascript", "javascript"); -CodeMirror.defineMIME("text/ecmascript", "javascript"); -CodeMirror.defineMIME("application/javascript", "javascript"); -CodeMirror.defineMIME("application/x-javascript", "javascript"); -CodeMirror.defineMIME("application/ecmascript", "javascript"); -CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); -CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); -CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true}); -CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); -CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); - -}); diff --git a/libs/codemirror/mode/javascript/json-ld.html b/libs/codemirror/mode/javascript/json-ld.html deleted file mode 100644 index 3a37f0bc..00000000 --- a/libs/codemirror/mode/javascript/json-ld.html +++ /dev/null @@ -1,72 +0,0 @@ - - -CodeMirror: JSON-LD mode - - - - - - - - - - - - -
-

JSON-LD mode

- - -
- - - -

This is a specialization of the JavaScript mode.

-
diff --git a/libs/codemirror/mode/javascript/test.js b/libs/codemirror/mode/javascript/test.js deleted file mode 100644 index 91b0e89a..00000000 --- a/libs/codemirror/mode/javascript/test.js +++ /dev/null @@ -1,200 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE - -(function() { - var mode = CodeMirror.getMode({indentUnit: 2}, "javascript"); - function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } - - MT("locals", - "[keyword function] [variable foo]([def a], [def b]) { [keyword var] [def c] [operator =] [number 10]; [keyword return] [variable-2 a] [operator +] [variable-2 c] [operator +] [variable d]; }"); - - MT("comma-and-binop", - "[keyword function](){ [keyword var] [def x] [operator =] [number 1] [operator +] [number 2], [def y]; }"); - - MT("destructuring", - "([keyword function]([def a], [[[def b], [def c] ]]) {", - " [keyword let] {[def d], [property foo]: [def c][operator =][number 10], [def x]} [operator =] [variable foo]([variable-2 a]);", - " [[[variable-2 c], [variable y] ]] [operator =] [variable-2 c];", - "})();"); - - MT("class_body", - "[keyword class] [variable Foo] {", - " [property constructor]() {}", - " [property sayName]() {", - " [keyword return] [string-2 `foo${][variable foo][string-2 }oo`];", - " }", - "}"); - - MT("class", - "[keyword class] [variable Point] [keyword extends] [variable SuperThing] {", - " [property get] [property prop]() { [keyword return] [number 24]; }", - " [property constructor]([def x], [def y]) {", - " [keyword super]([string 'something']);", - " [keyword this].[property x] [operator =] [variable-2 x];", - " }", - "}"); - - MT("module", - "[keyword module] [string 'foo'] {", - " [keyword export] [keyword let] [def x] [operator =] [number 42];", - " [keyword export] [keyword *] [keyword from] [string 'somewhere'];", - "}"); - - MT("import", - "[keyword function] [variable foo]() {", - " [keyword import] [def $] [keyword from] [string 'jquery'];", - " [keyword module] [def crypto] [keyword from] [string 'crypto'];", - " [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];", - "}"); - - MT("const", - "[keyword function] [variable f]() {", - " [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];", - "}"); - - MT("for/of", - "[keyword for]([keyword let] [variable of] [keyword of] [variable something]) {}"); - - MT("generator", - "[keyword function*] [variable repeat]([def n]) {", - " [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])", - " [keyword yield] [variable-2 i];", - "}"); - - MT("quotedStringAddition", - "[keyword let] [variable f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];"); - - MT("quotedFatArrow", - "[keyword let] [variable f] [operator =] [variable a] [operator +] [string '=>'] [operator +] [variable c];"); - - MT("fatArrow", - "[variable array].[property filter]([def a] [operator =>] [variable-2 a] [operator +] [number 1]);", - "[variable a];", // No longer in scope - "[keyword let] [variable f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];", - "[variable c];"); - - MT("spread", - "[keyword function] [variable f]([def a], [meta ...][def b]) {", - " [variable something]([variable-2 a], [meta ...][variable-2 b]);", - "}"); - - MT("comprehension", - "[keyword function] [variable f]() {", - " [[([variable x] [operator +] [number 1]) [keyword for] ([keyword var] [def x] [keyword in] [variable y]) [keyword if] [variable pred]([variable-2 x]) ]];", - " ([variable u] [keyword for] ([keyword var] [def u] [keyword of] [variable generateValues]()) [keyword if] ([variable-2 u].[property color] [operator ===] [string 'blue']));", - "}"); - - MT("quasi", - "[variable re][string-2 `fofdlakj${][variable x] [operator +] ([variable re][string-2 `foo`]) [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]"); - - MT("quasi_no_function", - "[variable x] [operator =] [string-2 `fofdlakj${][variable x] [operator +] [string-2 `foo`] [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]"); - - MT("indent_statement", - "[keyword var] [variable x] [operator =] [number 10]", - "[variable x] [operator +=] [variable y] [operator +]", - " [atom Infinity]", - "[keyword debugger];"); - - MT("indent_if", - "[keyword if] ([number 1])", - " [keyword break];", - "[keyword else] [keyword if] ([number 2])", - " [keyword continue];", - "[keyword else]", - " [number 10];", - "[keyword if] ([number 1]) {", - " [keyword break];", - "} [keyword else] [keyword if] ([number 2]) {", - " [keyword continue];", - "} [keyword else] {", - " [number 10];", - "}"); - - MT("indent_for", - "[keyword for] ([keyword var] [variable i] [operator =] [number 0];", - " [variable i] [operator <] [number 100];", - " [variable i][operator ++])", - " [variable doSomething]([variable i]);", - "[keyword debugger];"); - - MT("indent_c_style", - "[keyword function] [variable foo]()", - "{", - " [keyword debugger];", - "}"); - - MT("indent_else", - "[keyword for] (;;)", - " [keyword if] ([variable foo])", - " [keyword if] ([variable bar])", - " [number 1];", - " [keyword else]", - " [number 2];", - " [keyword else]", - " [number 3];"); - - MT("indent_funarg", - "[variable foo]([number 10000],", - " [keyword function]([def a]) {", - " [keyword debugger];", - "};"); - - MT("indent_below_if", - "[keyword for] (;;)", - " [keyword if] ([variable foo])", - " [number 1];", - "[number 2];"); - - MT("multilinestring", - "[keyword var] [variable x] [operator =] [string 'foo\\]", - "[string bar'];"); - - MT("scary_regexp", - "[string-2 /foo[[/]]bar/];"); - - MT("indent_strange_array", - "[keyword var] [variable x] [operator =] [[", - " [number 1],,", - " [number 2],", - "]];", - "[number 10];"); - - var jsonld_mode = CodeMirror.getMode( - {indentUnit: 2}, - {name: "javascript", jsonld: true} - ); - function LD(name) { - test.mode(name, jsonld_mode, Array.prototype.slice.call(arguments, 1)); - } - - LD("json_ld_keywords", - '{', - ' [meta "@context"]: {', - ' [meta "@base"]: [string "http://example.com"],', - ' [meta "@vocab"]: [string "http://xmlns.com/foaf/0.1/"],', - ' [property "likesFlavor"]: {', - ' [meta "@container"]: [meta "@list"]', - ' [meta "@reverse"]: [string "@beFavoriteOf"]', - ' },', - ' [property "nick"]: { [meta "@container"]: [meta "@set"] },', - ' [property "nick"]: { [meta "@container"]: [meta "@index"] }', - ' },', - ' [meta "@graph"]: [[ {', - ' [meta "@id"]: [string "http://dbpedia.org/resource/John_Lennon"],', - ' [property "name"]: [string "John Lennon"],', - ' [property "modified"]: {', - ' [meta "@value"]: [string "2010-05-29T14:17:39+02:00"],', - ' [meta "@type"]: [string "http://www.w3.org/2001/XMLSchema#dateTime"]', - ' }', - ' } ]]', - '}'); - - LD("json_ld_fake", - '{', - ' [property "@fake"]: [string "@fake"],', - ' [property "@contextual"]: [string "@identifier"],', - ' [property "user@domain.com"]: [string "@graphical"],', - ' [property "@ID"]: [string "@@ID"]', - '}'); -})(); diff --git a/libs/codemirror/mode/javascript/typescript.html b/libs/codemirror/mode/javascript/typescript.html deleted file mode 100644 index 2cfc5381..00000000 --- a/libs/codemirror/mode/javascript/typescript.html +++ /dev/null @@ -1,61 +0,0 @@ - - -CodeMirror: TypeScript mode - - - - - - - - - -
-

TypeScript mode

- - -
- - - -

This is a specialization of the JavaScript mode.

-
diff --git a/libs/codemirror/themes/solarized.css b/libs/codemirror/themes/solarized.css deleted file mode 100644 index b764f95e..00000000 --- a/libs/codemirror/themes/solarized.css +++ /dev/null @@ -1,170 +0,0 @@ -/* -Solarized theme for code-mirror -http://ethanschoonover.com/solarized -*/ - -/* -Solarized color pallet -http://ethanschoonover.com/solarized/img/solarized-palette.png -*/ - -.solarized.base03 { color: #002b36; } -.solarized.base02 { color: #073642; } -.solarized.base01 { color: #586e75; } -.solarized.base00 { color: #657b83; } -.solarized.base0 { color: #839496; } -.solarized.base1 { color: #93a1a1; } -.solarized.base2 { color: #eee8d5; } -.solarized.base3 { color: #fdf6e3; } -.solarized.solar-yellow { color: #b58900; } -.solarized.solar-orange { color: #cb4b16; } -.solarized.solar-red { color: #dc322f; } -.solarized.solar-magenta { color: #d33682; } -.solarized.solar-violet { color: #6c71c4; } -.solarized.solar-blue { color: #268bd2; } -.solarized.solar-cyan { color: #2aa198; } -.solarized.solar-green { color: #859900; } - -/* Color scheme for code-mirror */ - -.cm-s-solarized { - line-height: 1.45em; - color-profile: sRGB; - rendering-intent: auto; -} -.cm-s-solarized.cm-s-dark { - color: #839496; - background-color: #002b36; - text-shadow: #002b36 0 1px; -} -.cm-s-solarized.cm-s-light { - background-color: #fdf6e3; - color: #657b83; - text-shadow: #eee8d5 0 1px; -} - -.cm-s-solarized .CodeMirror-widget { - text-shadow: none; -} - - -.cm-s-solarized .cm-keyword { color: #cb4b16 } -.cm-s-solarized .cm-atom { color: #d33682; } -.cm-s-solarized .cm-number { color: #d33682; } -.cm-s-solarized .cm-def { color: #2aa198; } - -.cm-s-solarized .cm-variable { color: #268bd2; } -.cm-s-solarized .cm-variable-2 { color: #b58900; } -.cm-s-solarized .cm-variable-3 { color: #6c71c4; } - -.cm-s-solarized .cm-property { color: #2aa198; } -.cm-s-solarized .cm-operator {color: #6c71c4;} - -.cm-s-solarized .cm-comment { color: #586e75; font-style:italic; } - -.cm-s-solarized .cm-string { color: #859900; } -.cm-s-solarized .cm-string-2 { color: #b58900; } - -.cm-s-solarized .cm-meta { color: #859900; } -.cm-s-solarized .cm-qualifier { color: #b58900; } -.cm-s-solarized .cm-builtin { color: #d33682; } -.cm-s-solarized .cm-bracket { color: #cb4b16; } -.cm-s-solarized .CodeMirror-matchingbracket { color: #859900; } -.cm-s-solarized .CodeMirror-nonmatchingbracket { color: #dc322f; } -.cm-s-solarized .cm-tag { color: #93a1a1 } -.cm-s-solarized .cm-attribute { color: #2aa198; } -.cm-s-solarized .cm-header { color: #586e75; } -.cm-s-solarized .cm-quote { color: #93a1a1; } -.cm-s-solarized .cm-hr { - color: transparent; - border-top: 1px solid #586e75; - display: block; -} -.cm-s-solarized .cm-link { color: #93a1a1; cursor: pointer; } -.cm-s-solarized .cm-special { color: #6c71c4; } -.cm-s-solarized .cm-em { - color: #999; - text-decoration: underline; - text-decoration-style: dotted; -} -.cm-s-solarized .cm-strong { color: #eee; } -.cm-s-solarized .cm-tab:before { - content: "➤"; /*visualize tab character*/ - color: #586e75; - position: absolute; -} -.cm-s-solarized .cm-error, -.cm-s-solarized .cm-invalidchar { - color: #586e75; - border-bottom: 1px dotted #dc322f; -} - -.cm-s-solarized.cm-s-dark .CodeMirror-selected { - background: #073642; -} - -.cm-s-solarized.cm-s-light .CodeMirror-selected { - background: #eee8d5; -} - -/* Editor styling */ - - - -/* Little shadow on the view-port of the buffer view */ -.cm-s-solarized.CodeMirror { - -moz-box-shadow: inset 7px 0 12px -6px #000; - -webkit-box-shadow: inset 7px 0 12px -6px #000; - box-shadow: inset 7px 0 12px -6px #000; -} - -/* Gutter border and some shadow from it */ -.cm-s-solarized .CodeMirror-gutters { - border-right: 1px solid; -} - -/* Gutter colors and line number styling based of color scheme (dark / light) */ - -/* Dark */ -.cm-s-solarized.cm-s-dark .CodeMirror-gutters { - background-color: #002b36; - border-color: #00232c; -} - -.cm-s-solarized.cm-s-dark .CodeMirror-linenumber { - text-shadow: #021014 0 -1px; -} - -/* Light */ -.cm-s-solarized.cm-s-light .CodeMirror-gutters { - background-color: #fdf6e3; - border-color: #eee8d5; -} - -/* Common */ -.cm-s-solarized .CodeMirror-linenumber { - color: #586e75; - padding: 0 5px; -} -.cm-s-solarized .CodeMirror-guttermarker-subtle { color: #586e75; } -.cm-s-solarized.cm-s-dark .CodeMirror-guttermarker { color: #ddd; } -.cm-s-solarized.cm-s-light .CodeMirror-guttermarker { color: #cb4b16; } - -.cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text { - color: #586e75; -} - -.cm-s-solarized .CodeMirror-lines .CodeMirror-cursor { - border-left: 1px solid #819090; -} - -/* -Active line. Negative margin compensates left padding of the text in the -view-port -*/ -.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background { - background: rgba(255, 255, 255, 0.10); -} -.cm-s-solarized.cm-s-light .CodeMirror-activeline-background { - background: rgba(0, 0, 0, 0.10); -} diff --git a/style.css b/style.css index 7d2ee6ff..a07acdab 100644 --- a/style.css +++ b/style.css @@ -157,13 +157,17 @@ button.right { padding-top: 10px; } -.CodeMirror { +.code { font: 14px Consolas, Monaco, monospace; +} + +#editor { + border: solid 1px darkgray; + overflow: hidden; width: 1220px; + height: 575px; margin: 10px auto; - height: 320px; } - .world { position: relative; width: 1220px; diff --git a/types.js b/types.js new file mode 100644 index 00000000..1bf9be5e --- /dev/null +++ b/types.js @@ -0,0 +1,91 @@ +// Created by Josef Wittmann: https://gist.github.com/Josef37/e075b6a005a47d146c7e7ab9ed7ae893 +var typeDeclarations = `interface Solution { + init: (elevators: Elevator[], floors: Floor[]) => void; + update: (dt: number, elevators: Elevator[], floors: Floor[]) => void; +} +interface Elevator { + /** + * Queue the elevator to go to specified floor number. + * If you specify true as second argument, the elevator will go to that floor directly, and then go to any other queued floors. + */ + goToFloor(floor: number, forceNow?: boolean): void; + /** + * Clear the destination queue and stop the elevator if it is moving. + * Note that you normally don't need to stop elevators - it is intended for advanced solutions with in-transit rescheduling logic. + * Also, note that the elevator will probably not stop at a floor, so passengers will not get out. + */ + stop(): void; + /** + * Gets the floor number that the elevator currently is on. + */ + currentFloor(): number; + /** + * Gets or sets the going up indicator, which will affect passenger behaviour when stopping at floors. + */ + goingUpIndicator(): boolean; + goingUpIndicator(state: boolean): Elevator; + /** + * Gets or sets the going down indicator, which will affect passenger behaviour when stopping at floors. + */ + goingDownIndicator(): boolean; + goingDownIndicator(state: boolean): Elevator; + /** + * Gets the maximum number of passengers that can occupy the elevator at the same time. + */ + maxPassengerCount(): number; + /** + * Gets the load factor of the elevator. 0 means empty, 1 means full. Varies with passenger weights, which vary - not an exact measure. + */ + loadFactor(): number; + /** + * Gets the direction the elevator is currently going to move toward. Can be \"up\", \"down\" or \"stopped\". + */ + destinationDirection(): "up" | "down" | "stopped"; + /** + * The current destination queue, meaning the floor numbers the elevator is scheduled to go to. + * Can be modified and emptied if desired. Note that you need to call checkDestinationQueue() for the change to take effect immediately. + */ + destinationQueue: number[]; + /** + * Checks the destination queue for any new destinations to go to. + * Note that you only need to call this if you modify the destination queue explicitly. + */ + checkDestinationQueue(): void; + /** + * Gets the currently pressed floor numbers as an array. + */ + getPressedFloors(): number[]; + /** + * Triggered when the elevator has completed all its tasks and is not doing anything. + */ + on(event: "idle", callback: () => void): Elevator; + /** + * Triggered when a passenger has pressed a button inside the elevator. + */ + on(event: "floor_button_pressed", callback: (floorNum: number) => void): Elevator; + /** + * Triggered slightly before the elevator will pass a floor. A good time to decide whether to stop at that floor. + * Note that this event is not triggered for the destination floor. Direction is either "up" or "down". + */ + on(event: "passing_floor", callback: (floorNum: number, direction: "up" | "down") => void): Elevator; + /** + * Triggered when the elevator has arrived at a floor. + */ + on(event: "stopped_at_floor", callback: (floorNum: number) => void): Elevator; +} +interface Floor { + /** + * Gets the floor number of the floor object. + */ + floorNum(): number; + /** + * Triggered when someone has pressed the up button at a floor. + * Note that passengers will press the button again if they fail to enter an elevator. + */ + on(event: "up_button_pressed", callback: () => void): Floor; + /** + * Triggered when someone has pressed the down button at a floor. + * Note that passengers will press the button again if they fail to enter an elevator. + */ + on(event: "down_button_pressed", callback: () => void): Floor; +}`;