added basic standard input with "read_line"
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 1 Sep 2021 01:16:46 +0000 (20:16 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 1 Sep 2021 01:16:46 +0000 (20:16 -0500)
read_line.onyx [new file with mode: 0644]
serve.py
static/css/index.css
static/src/index.js
static/src/worker.js
templates/index.html

diff --git a/read_line.onyx b/read_line.onyx
new file mode 100644 (file)
index 0000000..a972273
--- /dev/null
@@ -0,0 +1,16 @@
+package builtin
+
+read_line :: () -> str {
+    #persist buffer: [1024] u8;
+
+    (package core).__flush_stdio();
+    
+    read_line_available :: () -> bool #foreign "host" "read_line_available" ---
+    read_line           :: (buffer: [] u8) -> u32 #foreign "host" "read_line" ---
+    
+    read_line_available();
+    length := read_line(~~buffer);
+    
+    return str.{ ~~buffer, length };
+}
+
index be64eb4d49a0fb4462cf24dc41190ee9f081e249..3d270247aa5f20a4afb9f878bfd4310c42ac8ea8 100644 (file)
--- a/serve.py
+++ b/serve.py
@@ -8,9 +8,17 @@ app = Flask(
 
 app.config.from_object("config.default")
 
+@app.after_request
+def require_coep(response):
+    response.headers['Cross-Origin-Embedder-Policy'] = "require-corp"
+    return response
+
 @app.route("/")
 def get_homepage():
-    return flask.render_template("index.html")
+    response = flask.Response(flask.render_template("index.html"))
+    response.headers['Cross-Origin-Embedder-Policy'] = "require-corp"
+    response.headers['Cross-Origin-Opener-Policy'] = "same-origin"
+    return response
 
 
 @app.route("/compile", methods=['POST'])
@@ -24,7 +32,7 @@ def post_compile_onyx():
     with os.fdopen(code_file_desc, "w+b") as code_file:
         code_file.write(code.encode('utf-8'))
 
-    compile_process = subprocess.run(f"timeout -s KILL 10s onyx -r js --no-file-contents --no-colors -o {wasm_file_name} {code_file_name}", shell=True, capture_output=True)
+    compile_process = subprocess.run(f"timeout -s KILL 10s onyx -r js --no-file-contents --no-colors -o {wasm_file_name} {code_file_name} ./read_line.onyx", shell=True, capture_output=True)
 
     os.remove(code_file_name)
 
index 3cb273b4f5d07d7abed6f9f1f31c1e3f9d68507f..b6401b669b8464ef60960a26a97139c8289e2e0d 100644 (file)
@@ -1,5 +1,6 @@
 :root {
     --menu-bar-height: 32px;
+    --input-bar-height: 32px;
     --divider-size: 4px;
     --left-half-width: 70%;
 }
@@ -80,7 +81,7 @@ button:hover {
 
 #code-result {
     height: 100%;
-    max-height: calc(100% - 24px);  /* subtract the padding */
+    max-height: calc(100% - var(--menu-bar-height) - var(--input-bar-height));  /* subtract the padding */
     background: #070707;
     color: #fff;
     font-size: 16px;
@@ -105,3 +106,42 @@ button:hover {
     display: inline-block;
     float: left;
 }
+
+#input-bar {
+    background-color: #181818;
+    color: #fff;
+    outline: none;
+    border: none;
+
+    min-height: var(--input-bar-height);
+    width: 80%;
+    padding: 8px;
+    float: left;
+
+    font-size: 16px;
+    font-family: Monaco, Menlo, "Ubuntu Mono", Consolas, source-code-pro, monospace;
+}
+
+#input-submit {
+    background-color: #272727;
+    color: #fff;
+    outline: none;
+    border: none;
+
+    float: left;
+    width: 20%;
+    padding: 8px;
+    margin: 0;
+    min-height: var(--input-bar-height);
+
+    font-size: 16px;
+    font-family: Monaco, Menlo, "Ubuntu Mono", Consolas, source-code-pro, monospace;
+
+    transition: all 0.5s;
+}
+
+#input-submit:hover {
+    background: #444;
+    cursor: pointer;
+}
+
index 830352fd4aaab54b108b2d7d083187dcb35e8a91..f5a85e7886885d30e14e6e92b0ed63cce754d869 100644 (file)
@@ -2,6 +2,8 @@ let wasm_worker = null;
 let editor_keybind_mode = "normal";
 let editor_theme = "chrome";
 
+let input_shared_buffer = new SharedArrayBuffer(1024 * Uint8Array.BYTES_PER_ELEMENT);
+
 async function clear_output() {
     let elem = document.getElementById('code-result');
     elem.className = "";   // NOTE: This clears all the classes, not just the "errored" one!
@@ -21,6 +23,7 @@ async function run_wasm(wasm_bytes) {
     }
     update_running_msg();
 
+    input_shared_buffer = new SharedArrayBuffer(1024 * Uint8Array.BYTES_PER_ELEMENT);
     wasm_worker = new Worker(window.ROOT_ENDPOINT + '/static/src/worker.js');
 
     wasm_worker.onmessage = (e) => {
@@ -40,10 +43,25 @@ async function run_wasm(wasm_bytes) {
                 update_running_msg();
                 break;
             }
+
+            case 'input': {
+                let input_array = new Uint8Array(input_shared_buffer);
+                Atomics.store(input_array, 0, 0);
+                let msg = prompt("Line: ");
+                input_array.fill(0);
+
+                for (let i=0; i<msg.length && i<input_array.length - 1; i++) {
+                    input_array[i + 1] = msg.charCodeAt(i);
+                }
+
+                Atomics.store(input_array, 0, 1);
+                break;
+            }
         }
     };
 
-    wasm_worker.postMessage({ type: 'start', data: wasm_bytes });
+    wasm_worker.postMessage({ type: 'set_buffer', data: input_shared_buffer });
+    wasm_worker.postMessage({ type: 'start',      data: wasm_bytes });
     update_running_msg();
 }
 
@@ -195,6 +213,24 @@ function prompt_download() {
     download_link.remove();
 }
 
+function submit_input() {
+    let inputbar = document.getElementById("input-bar");
+    let input = inputbar.value;
+
+    write_output(input + "\n", false);
+
+    let input_array = new Uint8Array(input_shared_buffer);
+    Atomics.store(input_array, 0, 0);
+    input_array.fill(0);
+
+    for (let i=0; i<input.length && i<input_array.length - 1; i++) {
+        input_array[i + 1] = input.charCodeAt(i);
+    }
+
+    Atomics.store(input_array, 0, 1);
+    inputbar.value = "";
+}
+
 window.onload = () => {
     let editor = ace.edit('code-editor');
 
@@ -208,4 +244,10 @@ window.onload = () => {
     make_resizer("horizontal-divider", "--left-half-width", (e) => {
         editor.resize(true);
     });
+
+    document.getElementById("input-bar").addEventListener("keyup", (ev) => {
+        if (ev.keyCode === 13) {
+            submit_input();
+        }
+    });
 };
index 716eaff5abc4a2b3d255f4a5962eca025fe32bf2..453e9082da9fc1361de3062773b0a349a2343828 100644 (file)
@@ -1,3 +1,4 @@
+let input_shared_buffer = null;
 let wasm_memory = null;
 
 let import_obj = {
@@ -12,6 +13,27 @@ let import_obj = {
             return Date.now();
         },
 
+        read_line_available: async function() {
+            let input_array = new Uint8Array(input_shared_buffer);
+            while (Atomics.load(input_array, 0) == 0);
+        },
+
+        read_line(msgptr, msglen) { // Returns actual length
+            let data = new Uint8Array(wasm_memory.buffer, msgptr, msglen);
+            let input_array = new Uint8Array(input_shared_buffer);
+            console.log(Atomics.load(input_array, 0), " == 1");
+
+            let i;
+            for (i=0; input_array[i + 1] != 0 && i<msglen; i++) {
+                console.log(input_array[i + 1]);
+                data[i] = input_array[i + 1];
+            }
+
+            Atomics.store(input_array, 0, 0);
+
+            return i;
+        },
+
         exit(code) {
             self.postMessage({ type: 'terminated' });
             self.close();
@@ -21,6 +43,11 @@ let import_obj = {
 
 onmessage = function(m) {
     switch (m.data.type) {
+        case 'set_buffer': {
+            input_shared_buffer = m.data.data;
+            break;
+        }
+
         case 'start': {
             WebAssembly.instantiate(m.data.data, import_obj)
             .then(response => {
index 83cb65aeb2a0e6500be54f7cf8d092c6c7a12e52..e87824af7d351de86c93798937f403766d9b923f 100644 (file)
@@ -54,6 +54,8 @@ main :: (args: [] cstr) {
         <div class="right-half">
             <pre id="code-result">
             </pre>
+            <input type="textbox" id="input-bar" />
+            <input type="button" id="input-submit" value="Enter" />
         </div>
     </body>
 </html>