polishing in many ways
authorroot <root@brendanfh.com>
Mon, 19 Jul 2021 13:21:23 +0000 (13:21 +0000)
committerroot <root@brendanfh.com>
Mon, 19 Jul 2021 13:21:23 +0000 (13:21 +0000)
static/css/index.css
static/src/index.js
static/src/vendor/ace/theme-github.js [new file with mode: 0644]
static/src/vendor/ace/theme-monokai.js [new file with mode: 0644]
static/src/vendor/ace/theme-tomorrow-night-bright.js [new file with mode: 0644]
templates/index.html

index b2e3c2b219e6527cc80d98c30e2cd8c8b4552c25..e123f8ec4df4772a78b14ea07f7bc87e2a1da5e1 100644 (file)
@@ -1,3 +1,7 @@
+:root {
+    --menu-bar-height: 32px;
+}
+
 * {
     margin: 0;
     padding: 0;
@@ -10,6 +14,40 @@ body {
     overflow: hidden;
 }
 
+select {
+    margin: calc((var(--menu-bar-height) - 24px) / 2);
+    height: 24px;
+    min-width: 64px;
+
+    border: none;
+    color: white;
+    background: #222;
+
+    transition: all 0.5s;
+}
+
+select:hover {
+    background: #444;
+    cursor: pointer;
+}
+
+button {
+    margin: calc((var(--menu-bar-height) - 24px) / 2);
+    height: 24px;
+    min-width: 64px;
+
+    border: none;
+    color: white;
+    background: #222;
+
+    transition: all 0.5s;
+}
+
+button:hover {
+    background: #444;
+    cursor: pointer;
+}
+
 .left-half, .right-half {
     width: 50%;
     height: 100%;
@@ -24,11 +62,11 @@ body {
 }
 
 .top-half {
-    height: 24px;
+    height: var(--menu-bar-height);
 }
 
 .bottom-half {
-    height: calc(100% - 24px);
+    height: calc(100% - var(--menu-bar-height));
 }
 
 #code-editor {
@@ -37,7 +75,7 @@ body {
 
 #code-result {
     height: 100%;
-    max-height: 100%;
+    max-height: calc(100% - 24px);  /* subtract the padding */
     background: #000;
     color: #fff;
     font-size: 16px;
@@ -45,5 +83,7 @@ body {
 
     overflow-y: auto;
     overflow-x: auto;
+
+    padding: 12px;
 }
 
index ddf652c7c74d2fd8a91ffb9ddae64ef481b182a3..99c2c1c1ed232a189cc00e50a90ad7e1bcfea46b 100644 (file)
@@ -1,21 +1,6 @@
 let wasm_worker = null;
-
-function update_running_msg() {
-    let elem = document.getElementById('running-msg');
-    if (wasm_worker == null) {
-        elem.innerHTML = "";
-
-    } else {
-        elem.innerHTML = "Running...";
-    }
-}
-
-function change_editor_theme() {
-    let editor = ace.edit('code-editor');
-    let elem = document.getElementById('code-editor-theme');
-
-    editor.setTheme(`ace/theme/${elem.value}`);
-}
+let editor_keybind_mode = "normal";
+let editor_theme = "chrome";
 
 async function clear_output() {
     let elem = document.getElementById('code-result');
@@ -88,6 +73,62 @@ async function kill_code() {
     update_running_msg();
 }
 
+function update_running_msg() {
+    let elem = document.getElementById('running-msg');
+    if (wasm_worker == null) {
+        elem.innerHTML = "";
+
+    } else {
+        elem.innerHTML = "Running...";
+    }
+}
+
+function change_editor_theme(value) {
+    let editor = ace.edit('code-editor');
+    let elem = document.getElementById('code-editor-theme');
+
+    if (value == null) {
+        value = elem.value;
+    } else {
+        document.querySelector(`#code-editor-theme option[value="${value}"]`).selected = true;
+    }
+
+    editor.setTheme(`ace/theme/${value}`);
+
+    editor_theme = value;
+    persist_settings();
+}
+
+function change_keybindings(value) {
+    let editor = ace.edit('code-editor');
+    let elem = document.getElementById('code-editor-keybindings');
+
+    if (value == null) {
+        value = elem.value;
+    } else {
+        document.querySelector(`#code-editor-keybindings option[value="${value}"]`).selected = true;
+    }
+
+    if (value == "normal") editor.setKeyboardHandler("");
+    else                   editor.setKeyboardHandler(`ace/keyboard/${value}`);
+
+    editor_keybind_mode = value;
+    persist_settings();
+}
+
+function persist_settings() {
+    localStorage["editor_theme"] = editor_theme;
+    localStorage["editor_keybind_mode"] = editor_keybind_mode;
+}
+
+function load_settings() {
+    editor_theme = localStorage["editor_theme"];
+    editor_keybind_mode = localStorage["editor_keybind_mode"];
+
+    change_editor_theme(editor_theme);
+    change_keybindings(editor_keybind_mode);
+}
+
 window.onload = () => {
     let editor = ace.edit('code-editor');
 
@@ -95,5 +136,6 @@ window.onload = () => {
     editor.setShowPrintMargin(false);
     editor.setFontSize(16);
     editor.session.setMode('ace/mode/onyx');
-    editor.setKeyboardHandler("ace/keyboard/vim");
+
+    load_settings();
 };
diff --git a/static/src/vendor/ace/theme-github.js b/static/src/vendor/ace/theme-github.js
new file mode 100644 (file)
index 0000000..65ba23d
--- /dev/null
@@ -0,0 +1,137 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright 2011 Irakli Gozalishvili. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ * ***** END LICENSE BLOCK ***** */
+
+define("ace/theme/github",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
+
+exports.isDark = true;
+exports.cssClass = "ace-gruvbox";
+exports.cssText = `.ace-gruvbox .ace_gutter-active-line {
+  background-color: #3C3836;
+}
+
+.ace-gruvbox {
+  color: #EBDAB4;
+  background-color: #1D2021;
+}
+
+.ace-gruvbox .ace_invisible {
+  color: #504945;
+}
+
+.ace-gruvbox .ace_marker-layer .ace_selection {
+  background: rgba(179, 101, 57, 0.75)
+}
+
+.ace-gruvbox.ace_multiselect .ace_selection.ace_start {
+  box-shadow: 0 0 3px 0px #002240;
+}
+
+.ace-gruvbox .ace_keyword {
+  color: #8ec07c;
+}
+
+.ace-gruvbox .ace_comment {
+  font-style: italic;
+  color: #928375;
+}
+
+.ace-gruvbox .ace-statement {
+  color: red;
+}
+
+.ace-gruvbox .ace_variable {
+  color: #84A598;
+}
+
+.ace-gruvbox .ace_variable.ace_language {
+  color: #D2879B;
+}
+
+.ace-gruvbox .ace_constant {
+  color: #C2859A;
+}
+
+.ace-gruvbox .ace_constant.ace_language {
+  color: #C2859A;
+}
+
+.ace-gruvbox .ace_constant.ace_numeric {
+  color: #C2859A;
+}
+
+.ace-gruvbox .ace_string {
+  color: #B8BA37;
+}
+
+.ace-gruvbox .ace_support {
+  color: #F9BC41;
+}
+
+.ace-gruvbox .ace_support.ace_function {
+  color: #F84B3C;
+}
+
+.ace-gruvbox .ace_storage {
+  color: #8FBF7F;
+}
+
+.ace-gruvbox .ace_keyword.ace_operator {
+  color: #EBDAB4;
+}
+
+.ace-gruvbox .ace_punctuation.ace_operator {
+  color: yellow;
+}
+
+.ace-gruvbox .ace_marker-layer .ace_active-line {
+  background: #3C3836;
+}
+
+.ace-gruvbox .ace_marker-layer .ace_selected-word {
+  border-radius: 4px;
+  border: 8px solid #3f475d;
+}
+
+.ace-gruvbox .ace_print-margin {
+  width: 5px;
+  background: #3C3836;
+}
+
+.ace-gruvbox .ace_indent-guide {
+  background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNQUFD4z6Crq/sfAAuYAuYl+7lfAAAAAElFTkSuQmCC") right repeat-y;
+}
+`;
+
+var dom = require("../lib/dom");
+dom.importCssString(exports.cssText, exports.cssClass);
+
+});
+
+                (function() {
+                    window.require(["ace/theme/github"], function(m) {
+                        if (typeof module == "object" && typeof exports == "object" && module) {
+                            module.exports = m;
+                        }
+                    });
+                })();
+    
diff --git a/static/src/vendor/ace/theme-monokai.js b/static/src/vendor/ace/theme-monokai.js
new file mode 100644 (file)
index 0000000..55e498d
--- /dev/null
@@ -0,0 +1,168 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Ajax.org B.V. nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+define("ace/theme/monokai", ["require","exports","module","ace/lib/dom"], function(require, exports, module) {
+    exports.isDark = true;
+    exports.cssClass = "ace-monokai";
+    exports.cssText = `.ace-monokai .ace_gutter {
+  background: #2F3129;
+  color: #8F908A
+}
+
+.ace-monokai .ace_print-margin {
+  width: 1px;
+  background: #555651
+}
+
+.ace-monokai {
+  background-color: #272822;
+  color: #F8F8F2
+}
+
+.ace-monokai .ace_cursor {
+  color: #F8F8F0
+}
+
+.ace-monokai .ace_marker-layer .ace_selection {
+  background: #49483E
+}
+
+.ace-monokai.ace_multiselect .ace_selection.ace_start {
+  box-shadow: 0 0 3px 0px #272822;
+}
+
+.ace-monokai .ace_marker-layer .ace_step {
+  background: rgb(102, 82, 0)
+}
+
+.ace-monokai .ace_marker-layer .ace_bracket {
+  margin: -1px 0 0 -1px;
+  border: 1px solid #49483E
+}
+
+.ace-monokai .ace_marker-layer .ace_active-line {
+  background: #202020
+}
+
+.ace-monokai .ace_gutter-active-line {
+  background-color: #272727
+}
+
+.ace-monokai .ace_marker-layer .ace_selected-word {
+  border: 1px solid #49483E
+}
+
+.ace-monokai .ace_invisible {
+  color: #52524d
+}
+
+.ace-monokai .ace_entity.ace_name.ace_tag,
+.ace-monokai .ace_keyword,
+.ace-monokai .ace_meta.ace_tag,
+.ace-monokai .ace_storage {
+  color: #F92672
+}
+
+.ace-monokai .ace_punctuation,
+.ace-monokai .ace_punctuation.ace_tag {
+  color: #fff
+}
+
+.ace-monokai .ace_constant.ace_character,
+.ace-monokai .ace_constant.ace_language,
+.ace-monokai .ace_constant.ace_numeric,
+.ace-monokai .ace_constant.ace_other {
+  color: #AE81FF
+}
+
+.ace-monokai .ace_invalid {
+  color: #F8F8F0;
+  background-color: #F92672
+}
+
+.ace-monokai .ace_invalid.ace_deprecated {
+  color: #F8F8F0;
+  background-color: #AE81FF
+}
+
+.ace-monokai .ace_support.ace_constant,
+.ace-monokai .ace_support.ace_function {
+  color: #66D9EF
+}
+
+.ace-monokai .ace_fold {
+  background-color: #A6E22E;
+  border-color: #F8F8F2
+}
+
+.ace-monokai .ace_storage.ace_type,
+.ace-monokai .ace_support.ace_class,
+.ace-monokai .ace_support.ace_type {
+  font-style: italic;
+  color: #66D9EF
+}
+
+.ace-monokai .ace_entity.ace_name.ace_function,
+.ace-monokai .ace_entity.ace_other,
+.ace-monokai .ace_entity.ace_other.ace_attribute-name,
+.ace-monokai .ace_variable {
+  color: #A6E22E
+}
+
+.ace-monokai .ace_variable.ace_parameter {
+  font-style: italic;
+  color: #FD971F
+}
+
+.ace-monokai .ace_string {
+  color: #E6DB74
+}
+
+.ace-monokai .ace_comment {
+  color: #75715E
+}
+
+.ace-monokai .ace_indent-guide {
+  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWPQ0FD0ZXBzd/wPAAjVAoxeSgNeAAAAAElFTkSuQmCC) right repeat-y
+}`;
+
+
+    var dom = require("../lib/dom");
+    dom.importCssString(exports.cssText, exports.cssClass);
+});
+
+                (function() {
+                    window.require(["ace/theme/monokai"], function(m) {
+                        if (typeof module == "object" && typeof exports == "object" && module) {
+                            module.exports = m;
+                        }
+                    });
+                })();
+    
diff --git a/static/src/vendor/ace/theme-tomorrow-night-bright.js b/static/src/vendor/ace/theme-tomorrow-night-bright.js
new file mode 100644 (file)
index 0000000..ef0da6b
--- /dev/null
@@ -0,0 +1,187 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Ajax.org B.V. nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+define("ace/theme/tomorrow-night-bright",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
+
+exports.isDark = true;
+exports.cssClass = "ace-tomorrow-night-bright";
+exports.cssText = `.ace-tomorrow-night-bright .ace_gutter {
+  background: #1a1a1a;
+  color: #DEDEDE
+}
+
+.ace-tomorrow-night-bright .ace_print-margin {
+  width: 1px;
+  background: #1a1a1a
+}
+
+.ace-tomorrow-night-bright {
+  background-color: #000000;
+  color: #DEDEDE
+}
+
+.ace-tomorrow-night-bright .ace_cursor {
+  color: #9F9F9F
+}
+
+.ace-tomorrow-night-bright .ace_marker-layer .ace_selection {
+  background: #424242
+}
+
+.ace-tomorrow-night-bright.ace_multiselect .ace_selection.ace_start {
+  box-shadow: 0 0 3px 0px #000000;
+}
+
+.ace-tomorrow-night-bright .ace_marker-layer .ace_step {
+  background: rgb(102, 82, 0)
+}
+
+.ace-tomorrow-night-bright .ace_marker-layer .ace_bracket {
+  margin: -1px 0 0 -1px;
+  border: 1px solid #888888
+}
+
+.ace-tomorrow-night-bright .ace_marker-layer .ace_highlight {
+  border: 1px solid rgb(110, 119, 0);
+  border-bottom: 0;
+  box-shadow: inset 0 -1px rgb(110, 119, 0);
+  margin: -1px 0 0 -1px;
+  background: rgba(255, 235, 0, 0.1)
+}
+
+.ace-tomorrow-night-bright .ace_marker-layer .ace_active-line {
+  background: #2A2A2A
+}
+
+.ace-tomorrow-night-bright .ace_gutter-active-line {
+  background-color: #2A2A2A
+}
+
+.ace-tomorrow-night-bright .ace_stack {
+  background-color: rgb(66, 90, 44)
+}
+
+.ace-tomorrow-night-bright .ace_marker-layer .ace_selected-word {
+  border: 1px solid #888888
+}
+
+.ace-tomorrow-night-bright .ace_invisible {
+  color: #343434
+}
+
+.ace-tomorrow-night-bright .ace_keyword,
+.ace-tomorrow-night-bright .ace_meta,
+.ace-tomorrow-night-bright .ace_storage,
+.ace-tomorrow-night-bright .ace_storage.ace_type,
+.ace-tomorrow-night-bright .ace_support.ace_type {
+  color: #C397D8
+}
+
+.ace-tomorrow-night-bright .ace_keyword.ace_operator {
+  color: #70C0B1
+}
+
+.ace-tomorrow-night-bright .ace_constant.ace_character,
+.ace-tomorrow-night-bright .ace_constant.ace_language,
+.ace-tomorrow-night-bright .ace_constant.ace_numeric,
+.ace-tomorrow-night-bright .ace_keyword.ace_other.ace_unit,
+.ace-tomorrow-night-bright .ace_support.ace_constant,
+.ace-tomorrow-night-bright .ace_variable.ace_parameter {
+  color: #E78C45
+}
+
+.ace-tomorrow-night-bright .ace_constant.ace_other {
+  color: #EEEEEE
+}
+
+.ace-tomorrow-night-bright .ace_invalid {
+  color: #CED2CF;
+  background-color: #DF5F5F
+}
+
+.ace-tomorrow-night-bright .ace_invalid.ace_deprecated {
+  color: #CED2CF;
+  background-color: #B798BF
+}
+
+.ace-tomorrow-night-bright .ace_fold {
+  background-color: #7AA6DA;
+  border-color: #DEDEDE
+}
+
+.ace-tomorrow-night-bright .ace_entity.ace_name.ace_function,
+.ace-tomorrow-night-bright .ace_support.ace_function,
+.ace-tomorrow-night-bright .ace_variable {
+  color: #7AA6DA
+}
+
+.ace-tomorrow-night-bright .ace_support.ace_class,
+.ace-tomorrow-night-bright .ace_support.ace_type {
+  color: #E7C547
+}
+
+.ace-tomorrow-night-bright .ace_heading,
+.ace-tomorrow-night-bright .ace_markup.ace_heading,
+.ace-tomorrow-night-bright .ace_string {
+  color: #B9CA4A
+}
+
+.ace-tomorrow-night-bright .ace_entity.ace_name.ace_tag,
+.ace-tomorrow-night-bright .ace_entity.ace_other.ace_attribute-name,
+.ace-tomorrow-night-bright .ace_meta.ace_tag,
+.ace-tomorrow-night-bright .ace_string.ace_regexp,
+.ace-tomorrow-night-bright .ace_variable {
+  color: #D54E53
+}
+
+.ace-tomorrow-night-bright .ace_comment {
+  color: #969896
+}
+
+.ace-tomorrow-night-bright .ace_c9searchresults.ace_keyword {
+  color: #C2C280
+}
+
+.ace-tomorrow-night-bright .ace_indent-guide {
+  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYFBXV/8PAAJoAXX4kT2EAAAAAElFTkSuQmCC) right repeat-y
+}
+`;
+
+var dom = require("../lib/dom");
+dom.importCssString(exports.cssText, exports.cssClass);
+});
+                (function() {
+                    window.require(["ace/theme/tomorrow-night-bright"], function(m) {
+                        if (typeof module == "object" && typeof exports == "object" && module) {
+                            module.exports = m;
+                        }
+                    });
+                })();
+    
index 7a7715a2f03047ae1da5c8357a897c9214467f6c..e3a38859c736d7bd3650a472413bde73a0af9427 100644 (file)
     <body>
         <div class="left-half">
             <div class="top-half">
-                <label for="editor-theme">Theme:</label>
-                <select name="editor-theme" id="code-editor-theme" onchange="change_editor_theme()">
+                <select aria-label="Keybindings" name="keybindings" id="code-editor-keybindings" onchange="change_keybindings()">
+                    <option value="normal">Normal</option>
+                    <option value="vim">Vim</option>
+                    <option value="emacs">Emacs</option>
+                    <option value="sublime">Sublime Text</option>
+                    <option value="vscode">VS Code</option>
+                </select>
+
+                <select aria-label="Theme" name="editor-theme" id="code-editor-theme" onchange="change_editor_theme()">
                     <option value="ambiance">Ambiance</option>
                     <option value="chaos">Chaos</option>
-                    <option selected value="chrome">Chrome</option>
+                    <option value="chrome">Chrome</option>
                     <option value="clouds">Clouds</option>
+                    <option value="github">Github</option>
+                    <option selected value="monokai">Monokai</option>
+                    <option value="tomorrow-night-bright">Tomorrow Night Bright</option>
                 </select>
+
+                <button onclick="submit_code()">Run</button>
+                <button onclick="kill_code()">Stop</button>
+
+                <span id="running-msg"></span>
             </div>
 
             <div class="bottom-half">
@@ -36,10 +51,6 @@ main :: (args: [] cstr) {
 
         <div class="right-half">
             <div class="top-half">
-                <input type="button" value="Run" onclick="submit_code()" />
-                <input type="button" value="Stop" onclick="kill_code()" />
-
-                <span id="running-msg"></span>
             </div>
 
             <div class="bottom-half">