Improve REPL directive support (#348)

* Improve REPL directive support

- use . on column 0 as directive prefix
- use `directives` object properties for genericity
- accept non ambiguous directive abbreviations
- reject invalid directive with extra characters
- simplify `handle_directive` and `handle_cmd`
- document ".help" instead of "\h"
- document ".load"
This commit is contained in:
Charlie Gordon 2024-04-08 15:34:30 +02:00 committed by GitHub
parent d308a13579
commit f62b90daa2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 7081 additions and 7062 deletions

14011
gen/repl.c

File diff suppressed because it is too large Load diff

130
repl.js
View file

@ -217,7 +217,7 @@ import * as os from "os";
var style = style_names[i = j];
while (++j < str.length && style_names[j] == style)
continue;
std.puts(colors[styles[style] || 'default']);
std.puts(colors[styles[style] || 'none']);
std.puts(str.substring(i, j));
std.puts(colors['none']);
}
@ -561,11 +561,11 @@ import * as os from "os";
if (pos <= 0)
return g;
var c = line[pos - 1];
if (pos === 1 && c === '\\')
if (pos === 1 && (c === '\\' || c === '.'))
return directives;
if ("'\"`@#)]}\\".indexOf(c) >= 0)
return void 0;
if (pos >= 2 && c === ".") {
if (c === ".") {
pos--;
switch (c = line[pos - 1]) {
case '\'':
@ -1003,59 +1003,72 @@ import * as os from "os";
print_rec(a);
}
function extract_directive(a) {
/* return true if the string was a directive */
function handle_directive(a) {
var pos;
if (a[0] !== '\\')
return "";
for (pos = 1; pos < a.length; pos++) {
if (!is_alpha(a[pos]))
break;
}
return a.substring(1, pos);
}
/* return true if the string after cmd can be evaluted as JS */
function handle_directive(cmd, expr) {
if (cmd === "h" || cmd === "?" || cmd == "help") {
if (a === "?") {
help();
} else if (cmd === "load") {
var filename = expr.substring(cmd.length + 1).trim();
if (filename.lastIndexOf(".") <= filename.lastIndexOf("/"))
filename += ".js";
std.loadScript(filename);
return true;
}
if (a[0] !== '\\' && a[0] !== '.')
return false;
} else if (cmd === "x") {
hex_mode = true;
} else if (cmd === "d") {
hex_mode = false;
} else if (cmd === "t") {
show_time = !show_time;
} else if (cmd === "clear") {
std.puts("\x1b[H\x1b[J");
} else if (cmd === "q") {
std.exit(0);
var pos = 1;
while (pos < a.length && a[pos] !== ' ') {
pos++;
}
var cmd = a.substring(1, pos);
var partial = 0;
var fun;
for (var p in directives) {
if (p.startsWith(cmd)) {
fun = directives[p];
partial++;
if (p === cmd) {
partial = 0;
break;
}
}
}
if (fun && partial < 2) {
fun(a.substring(pos).trim());
} else {
std.puts("Unknown directive: " + cmd + "\n");
return false;
std.puts(`Unknown directive: ${cmd}\n`);
}
return true;
}
function help() {
function sel(n) {
return n ? "*": " ";
}
std.puts("\\h this help\n" +
"\\x " + sel(hex_mode) + "hexadecimal number display\n" +
"\\d " + sel(!hex_mode) + "decimal number display\n" +
"\\t " + sel(show_time) + "toggle timing display\n" +
"\\clear clear the terminal\n" +
"\\q exit\n");
var sel = (n) => n ? "*": " ";
std.puts(".help print this help\n" +
".x " + sel(hex_mode) + "hexadecimal number display\n" +
".dec " + sel(!hex_mode) + "decimal number display\n" +
".time " + sel(show_time) + "toggle timing display\n" +
".color " + sel(show_colors) + "toggle colored output\n" +
".clear clear the terminal\n" +
".load load source code from a file\n" +
".quit exit\n");
}
function load(s) {
if (s.lastIndexOf(".") <= s.lastIndexOf("/"))
s += ".js";
std.loadScript(s);
}
function to_bool(s, def) {
return s ? "1 true yes Yes".includes(s) : def;
}
var directives = Object.setPrototypeOf({
h: "h", help: "help", load: "load", x: "x", d: "d", t: "t",
clear: "clear", q: "q" }, null);
"help": help,
"load": load,
"x": (s) => { hex_mode = to_bool(s, true); },
"dec": (s) => { hex_mode = !to_bool(s, true); },
"time": (s) => { show_time = to_bool(s, !show_time); },
"color": (s) => { show_colors = to_bool(s, !show_colors); },
"clear": () => { std.puts("\x1b[H\x1b[J") },
"quit": () => { std.exit(0); },
}, null);
function eval_and_print(expr) {
var result;
@ -1089,7 +1102,7 @@ import * as os from "os";
}
function cmd_start() {
std.puts('QuickJS-ng - Type "\\h" for help\n');
std.puts('QuickJS-ng - Type ".help" for help\n');
cmd_readline_start();
}
@ -1103,28 +1116,15 @@ import * as os from "os";
}
function handle_cmd(expr) {
var colorstate, cmd;
if (expr === null) {
expr = "";
if (!expr)
return;
}
if (expr === "?") {
help();
return;
}
cmd = extract_directive(expr);
if (cmd.length > 0) {
if (!handle_directive(cmd, expr))
return;
expr = expr.substring(cmd.length + 1);
}
if (expr === "")
return;
if (mexpr)
if (mexpr) {
expr = mexpr + '\n' + expr;
colorstate = colorize_js(expr);
} else {
if (handle_directive(expr))
return;
}
var colorstate = colorize_js(expr);
pstate = colorstate[0];
level = colorstate[1];
if (pstate) {