blob: aee31fef8443dd412f1888a6caf608a1febe1cde [file] [log] [blame]
// 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);