| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| import * as li_internal from 'li_internal'; |
| |
| (function(global) { |
| var readBuffer; |
| var repl; |
| var stdinFd; |
| |
| // called when the shell is launched (with option -l) |
| // creates the C++ Repl object and sets the read handler on stdin |
| function InitRepl() { |
| repl = li_internal.createRepl(); |
| stdinFd = std.in.fileno(); |
| |
| global['repl'] = { |
| autocompletionCallback, |
| evalScriptAwaitsPromise, |
| repl, |
| }; |
| |
| // a handler on std.in |
| readBuffer = new Uint8Array(64); |
| os.setReadHandler(stdinFd, readHandler); |
| } |
| |
| // Read handler, set on stdin by InitRepl |
| // Transfers all input to the C++ Repl object and deletes the Repl object when the \q exit |
| // command is detected in input |
| function readHandler() { |
| var l = os.read(stdinFd, readBuffer.buffer, 0, readBuffer.length); |
| var exitShell = li_internal.onInput(repl, readBuffer.buffer, l); |
| if (exitShell) { |
| std.out.flush(); |
| os.setReadHandler(stdinFd, null); // remove read handler |
| li_internal.closeRepl(repl); |
| } |
| std.gc(); // running it every now and then |
| } |
| |
| // Called by the C++ Repl to evaluate commands |
| // Runs the command and if the result is a promise, sets showing the prompt again as callback |
| function evalScriptAwaitsPromise() { |
| let eval_result = li_internal.getAndEvalCmd(repl); |
| let error_in_script = eval_result[0]; |
| if (!error_in_script) { |
| let script_result = eval_result[1]; |
| let f = function(output) { |
| li_internal.showOutput(repl, output); |
| li_internal.showPrompt(repl); |
| }; |
| if (script_result instanceof Promise) { |
| script_result.then(f).catch(f); |
| } else { |
| f(script_result); |
| } |
| } else { // there was an error and it has been printed out by the getAndEvalCmd function |
| li_internal.showPrompt(repl); |
| }; |
| } |
| |
| function autocompletionCallback() { |
| let line = li_internal.getLine(repl); |
| let dot_separated_ids = line.match(/([A-Za-z0-9$_]*\.)*[A-Za-z0-9$_]*$/); |
| let list_ids = dot_separated_ids[0].split('.'); |
| let incomplete_part = ""; |
| if(list_ids.length > 0){ |
| incomplete_part = list_ids[list_ids.length - 1]; |
| } |
| |
| function evalId(posId) { |
| if (posId < 0) { |
| return global; |
| } |
| if (["false", "true", "null", "this", "undefined"].includes(list_ids[posId]) |
| || !isNaN(list_ids[posId])) { |
| return eval(list_ids[posId]); |
| } |
| let parent = evalId(posId - 1); |
| if (parent === null || parent === undefined){ |
| return parent; |
| } |
| return parent[list_ids[posId]]; |
| } |
| |
| let obj = evalId(list_ids.length - 2); // as the last element of list_ids is the incomplete part |
| let property_names = []; |
| while (obj != null && obj != undefined) { |
| Object.getOwnPropertyNames(obj).forEach(name => { |
| if (name.startsWith(incomplete_part) |
| && !property_names.includes(name.substring(incomplete_part.length))) |
| property_names.push(name.substring(incomplete_part.length)); |
| }); |
| obj = Object.getPrototypeOf(obj); |
| } |
| |
| //a / separated concatenated string of all property_names |
| return (property_names.join('/') + "/"); |
| } |
| |
| InitRepl(); |
| })(globalThis); |