[gjs/ewlsh/nova-repl: 114/114] Update Cliffy, improve Repl UX
- From: Evan Welsh <ewlsh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/ewlsh/nova-repl: 114/114] Update Cliffy, improve Repl UX
- Date: Mon, 17 Jan 2022 00:24:29 +0000 (UTC)
commit 2dd4a18ac5fa578ab7963112f632d01a36aca5db
Author: Evan Welsh <contact evanwelsh com>
Date: Sun Jan 16 16:24:21 2022 -0800
Update Cliffy, improve Repl UX
modules/console.cpp | 15 +-
modules/esm/_repl/cliffy.js | 325 +++++++++++++++++++-------------------------
modules/esm/repl.js | 82 +++++++----
modules/system.cpp | 9 +-
tools/cliffy/ansi.js | 10 +-
tools/cliffy/lib.js | 1 -
tools/cliffy/transform.js | 2 +-
7 files changed, 211 insertions(+), 233 deletions(-)
---
diff --git a/modules/console.cpp b/modules/console.cpp
index edc99112b..46eb42710 100644
--- a/modules/console.cpp
+++ b/modules/console.cpp
@@ -94,10 +94,8 @@ public:
options.setFileAndLine("typein", lineno);
JS::RootedValue eval_result(cx);
- if (!JS::Evaluate(cx, options, source, &eval_result)) {
- if (!JS_IsExceptionPending(cx))
- return false;
- }
+ if (!JS::Evaluate(cx, options, source, &eval_result))
+ return false;
GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx);
gjs->schedule_gc_if_needed();
@@ -152,12 +150,7 @@ static bool gjs_console_eval_js(JSContext* cx, unsigned argc, JS::Value* vp) {
"lineNumber", &lineno))
return false;
- bool ok;
- {
- AutoReportException are(cx);
- ok = gjs_console_eval(cx, std::string(expr.get()), lineno, args.rval());
- }
- return ok;
+ return gjs_console_eval(cx, std::string(expr.get()), lineno, args.rval());
}
GJS_JSAPI_RETURN_CONVENTION
@@ -184,7 +177,7 @@ GJS_JSAPI_RETURN_CONVENTION
static bool gjs_console_clear_terminal(JSContext* cx, unsigned argc,
JS::Value* vp) {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
- if (!gjs_parse_call_args(cx, "eval", args, ""))
+ if (!gjs_parse_call_args(cx, "clearTerminal", args, ""))
return false;
if (!Gjs::Console::is_tty(Gjs::Console::stdout_fd)) {
diff --git a/modules/esm/_repl/cliffy.js b/modules/esm/_repl/cliffy.js
index 844ef1adb..9c59d47c2 100644
--- a/modules/esm/_repl/cliffy.js
+++ b/modules/esm/_repl/cliffy.js
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-// SPDX-FileCopyrightText: 2020 Benjamin Fischer <c4spar gmx de>
+// SPDX-FileCopyrightText: 2022 Benjamin Fischer <c4spar gmx de>
// Inject our shim for the Deno global...
import * as Deno from './deno.js';
@@ -68,7 +68,7 @@ const base64abc = [
"8",
"9",
"+",
- "/"
+ "/",
];
function encode(data) {
const uint8 = typeof data === "string" ? new TextEncoder().encode(data) : data instanceof Uint8Array ?
data : new Uint8Array(data);
@@ -197,40 +197,38 @@ function image(buffer, options) {
}
return ret + ":" + encode(buffer) + bel;
}
-const mod = function() {
- return {
- bel: bel,
- cursorPosition: cursorPosition,
- cursorTo: cursorTo,
- cursorMove: cursorMove,
- cursorUp: cursorUp,
- cursorDown: cursorDown,
- cursorForward: cursorForward,
- cursorBackward: cursorBackward,
- cursorNextLine: cursorNextLine,
- cursorPrevLine: cursorPrevLine,
- cursorLeft: cursorLeft,
- cursorHide: cursorHide,
- cursorShow: cursorShow,
- cursorSave: cursorSave,
- cursorRestore: cursorRestore,
- scrollUp: scrollUp,
- scrollDown: scrollDown,
- eraseScreen: eraseScreen,
- eraseUp: eraseUp,
- eraseDown: eraseDown,
- eraseLine: eraseLine,
- eraseLineEnd: eraseLineEnd,
- eraseLineStart: eraseLineStart,
- eraseLines: eraseLines,
- clearScreen: clearScreen,
- clearTerminal: clearTerminal,
- link: link,
- image: image
- };
-}();
-const ansi = factory1();
-function factory1() {
+const mod = {
+ bel: bel,
+ cursorPosition: cursorPosition,
+ cursorTo: cursorTo,
+ cursorMove: cursorMove,
+ cursorUp: cursorUp,
+ cursorDown: cursorDown,
+ cursorForward: cursorForward,
+ cursorBackward: cursorBackward,
+ cursorNextLine: cursorNextLine,
+ cursorPrevLine: cursorPrevLine,
+ cursorLeft: cursorLeft,
+ cursorHide: cursorHide,
+ cursorShow: cursorShow,
+ cursorSave: cursorSave,
+ cursorRestore: cursorRestore,
+ scrollUp: scrollUp,
+ scrollDown: scrollDown,
+ eraseScreen: eraseScreen,
+ eraseUp: eraseUp,
+ eraseDown: eraseDown,
+ eraseLine: eraseLine,
+ eraseLineEnd: eraseLineEnd,
+ eraseLineStart: eraseLineStart,
+ eraseLines: eraseLines,
+ clearScreen: clearScreen,
+ clearTerminal: clearTerminal,
+ link: link,
+ image: image
+};
+const ansi = factory();
+function factory() {
let result = [];
let stack = [];
const ansi1 = function(...args) {
@@ -241,7 +239,7 @@ function factory1() {
}
return this.toString();
}
- return factory1();
+ return factory();
};
ansi1.text = function(text) {
stack.push([
@@ -260,8 +258,8 @@ function factory1() {
return new TextEncoder().encode(this.toString());
};
const methodList = Object.entries(mod);
- for (const [name, method] of methodList){
- Object.defineProperty(ansi1, name, {
+ for (const [name1, method] of methodList){
+ Object.defineProperty(ansi1, name1, {
get () {
stack.push([
method,
@@ -272,14 +270,14 @@ function factory1() {
});
}
return ansi1;
- function update(args) {
+ function update(args1) {
if (!stack.length) {
return;
}
- if (args) {
- stack[stack.length - 1][1] = args;
+ if (args1) {
+ stack[stack.length - 1][1] = args1;
}
- result.push(...stack.map(([prop, args1])=>typeof prop === "string" ? prop : prop.call(ansi1,
...args1)
+ result.push(...stack.map(([prop, args])=>typeof prop === "string" ? prop : prop.call(ansi1, ...args)
));
stack = [];
}
@@ -569,58 +567,56 @@ const ANSI_PATTERN = new RegExp([
function stripColor(string) {
return string.replace(ANSI_PATTERN, "");
}
-const mod1 = function() {
- return {
- setColorEnabled: setColorEnabled,
- getColorEnabled: getColorEnabled,
- reset: reset,
- bold: bold,
- dim: dim,
- italic: italic,
- underline: underline,
- inverse: inverse,
- hidden: hidden,
- strikethrough: strikethrough,
- black: black,
- red: red,
- green: green,
- yellow: yellow,
- blue: blue,
- magenta: magenta,
- cyan: cyan,
- white: white,
- gray: gray,
- brightBlack: brightBlack,
- brightRed: brightRed,
- brightGreen: brightGreen,
- brightYellow: brightYellow,
- brightBlue: brightBlue,
- brightMagenta: brightMagenta,
- brightCyan: brightCyan,
- brightWhite: brightWhite,
- bgBlack: bgBlack,
- bgRed: bgRed,
- bgGreen: bgGreen,
- bgYellow: bgYellow,
- bgBlue: bgBlue,
- bgMagenta: bgMagenta,
- bgCyan: bgCyan,
- bgWhite: bgWhite,
- bgBrightBlack: bgBrightBlack,
- bgBrightRed: bgBrightRed,
- bgBrightGreen: bgBrightGreen,
- bgBrightYellow: bgBrightYellow,
- bgBrightBlue: bgBrightBlue,
- bgBrightMagenta: bgBrightMagenta,
- bgBrightCyan: bgBrightCyan,
- bgBrightWhite: bgBrightWhite,
- rgb8: rgb8,
- bgRgb8: bgRgb8,
- rgb24: rgb24,
- bgRgb24: bgRgb24,
- stripColor: stripColor
- };
-}();
+const mod1 = {
+ setColorEnabled: setColorEnabled,
+ getColorEnabled: getColorEnabled,
+ reset: reset,
+ bold: bold,
+ dim: dim,
+ italic: italic,
+ underline: underline,
+ inverse: inverse,
+ hidden: hidden,
+ strikethrough: strikethrough,
+ black: black,
+ red: red,
+ green: green,
+ yellow: yellow,
+ blue: blue,
+ magenta: magenta,
+ cyan: cyan,
+ white: white,
+ gray: gray,
+ brightBlack: brightBlack,
+ brightRed: brightRed,
+ brightGreen: brightGreen,
+ brightYellow: brightYellow,
+ brightBlue: brightBlue,
+ brightMagenta: brightMagenta,
+ brightCyan: brightCyan,
+ brightWhite: brightWhite,
+ bgBlack: bgBlack,
+ bgRed: bgRed,
+ bgGreen: bgGreen,
+ bgYellow: bgYellow,
+ bgBlue: bgBlue,
+ bgMagenta: bgMagenta,
+ bgCyan: bgCyan,
+ bgWhite: bgWhite,
+ bgBrightBlack: bgBrightBlack,
+ bgBrightRed: bgBrightRed,
+ bgBrightGreen: bgBrightGreen,
+ bgBrightYellow: bgBrightYellow,
+ bgBrightBlue: bgBrightBlue,
+ bgBrightMagenta: bgBrightMagenta,
+ bgBrightCyan: bgBrightCyan,
+ bgBrightWhite: bgBrightWhite,
+ rgb8: rgb8,
+ bgRgb8: bgRgb8,
+ rgb24: rgb24,
+ bgRgb24: bgRgb24,
+ stripColor: stripColor
+};
const proto = Object.create(null);
const methodNames = Object.keys(mod1);
for (const name of methodNames){
@@ -629,30 +625,30 @@ for (const name of methodNames){
}
Object.defineProperty(proto, name, {
get () {
- return factory2([
+ return factory1([
...this._stack,
name
]);
}
});
}
-const colors = factory2();
-function factory2(stack = []) {
- const colors1 = function(str, ...args) {
- if (str) {
+const colors = factory1();
+function factory1(stack = []) {
+ const colors1 = function(str1, ...args) {
+ if (str1) {
const lastIndex = stack.length - 1;
- return stack.reduce((str1, name1, index)=>index === lastIndex ? mod1[name1](str1, ...args) :
mod1[name1](str1)
- , str);
+ return stack.reduce((str, name, index)=>index === lastIndex ? mod1[name](str, ...args) :
mod1[name](str)
+ , str1);
}
const tmp = stack.slice();
stack = [];
- return factory2(tmp);
+ return factory1(tmp);
};
Object.setPrototypeOf(colors1, proto);
colors1._stack = stack;
return colors1;
}
-function getCursorPosition2({ stdin =Deno.stdin , stdout =Deno.stdout } = {
+function getCursorPosition({ stdin =Deno.stdin , stdout =Deno.stdout } = {
}) {
const data = new Uint8Array(8);
Deno.setRaw(stdin.rid, true);
@@ -668,42 +664,40 @@ function getCursorPosition2({ stdin =Deno.stdin , stdout =Deno.stdout } = {
y
};
}
-const mod2 = function() {
- return {
- ansi,
- bel,
- cursorPosition,
- cursorTo,
- cursorMove,
- cursorUp,
- cursorDown,
- cursorForward,
- cursorBackward,
- cursorNextLine,
- cursorPrevLine,
- cursorLeft,
- cursorHide,
- cursorShow,
- cursorSave,
- cursorRestore,
- scrollUp,
- scrollDown,
- eraseScreen,
- eraseUp,
- eraseDown,
- eraseLine,
- eraseLineEnd,
- eraseLineStart,
- eraseLines,
- clearScreen,
- clearTerminal,
- link,
- image,
- colors,
- getCursorPosition: getCursorPosition2,
- mod
- };
-}();
+const mod2 = {
+ ansi,
+ bel,
+ cursorPosition,
+ cursorTo,
+ cursorMove,
+ cursorUp,
+ cursorDown,
+ cursorForward,
+ cursorBackward,
+ cursorNextLine,
+ cursorPrevLine,
+ cursorLeft,
+ cursorHide,
+ cursorShow,
+ cursorSave,
+ cursorRestore,
+ scrollUp,
+ scrollDown,
+ eraseScreen,
+ eraseUp,
+ eraseDown,
+ eraseLine,
+ eraseLineEnd,
+ eraseLineStart,
+ eraseLines,
+ clearScreen,
+ clearTerminal,
+ link,
+ image,
+ colors,
+ getCursorPosition,
+ mod
+};
const KeyMap = {
"[P": "f1",
"[Q": "f2",
@@ -911,52 +905,13 @@ function charLengthAt(str, i) {
}
return pos >= 65536 ? 2 : 1;
}
-const mod3 = function() {
- return {
- parse,
- KeyMap,
- KeyMapShift,
- KeyMapCtrl,
- SpecialKeyMap
- };
-}();
-const main = {
- ARROW_UP: "↑",
- ARROW_DOWN: "↓",
- ARROW_LEFT: "←",
- ARROW_RIGHT: "→",
- ARROW_UP_LEFT: "↖",
- ARROW_UP_RIGHT: "↗",
- ARROW_DOWN_RIGHT: "↘",
- ARROW_DOWN_LEFT: "↙",
- RADIO_ON: "◉",
- RADIO_OFF: "◯",
- TICK: "✔",
- CROSS: "✘",
- ELLIPSIS: "…",
- POINTER_SMALL: "›",
- LINE: "─",
- POINTER: "❯",
- INFO: "ℹ",
- TAB_LEFT: "⇤",
- TAB_RIGHT: "⇥",
- ESCAPE: "⎋",
- BACKSPACE: "⌫",
- PAGE_UP: "⇞",
- PAGE_DOWN: "⇟",
- ENTER: "↵",
- SEARCH: "⌕"
-};
-const win = {
- ...main,
- RADIO_ON: "(*)",
- RADIO_OFF: "( )",
- TICK: "√",
- CROSS: "×",
- POINTER_SMALL: "»"
+const mod3 = {
+ parse,
+ KeyMap,
+ KeyMapShift,
+ KeyMapCtrl,
+ SpecialKeyMap
};
-const Figures1 = Deno.build.os === "windows" ? win : main;
-export { Figures1 as Figures };
function getCursorPosition1({ stdin , stdout }) {
stdout.write_bytes(new TextEncoder().encode(cursorPosition), null);
const data = stdin.read_bytes(8, null).toArray();
diff --git a/modules/esm/repl.js b/modules/esm/repl.js
index 67f593095..b02d99024 100644
--- a/modules/esm/repl.js
+++ b/modules/esm/repl.js
@@ -4,7 +4,7 @@
import GLib from 'gi://GLib';
let Gio;
-import {Ansi, Keycode, Figures} from './_repl/cliffy.js';
+import {Ansi, Keycode} from './_repl/cliffy.js';
const Console = import.meta.importSync('_consoleNative');
@@ -38,14 +38,14 @@ class ReplInput {
* @param {Gio.UnixOutputStream} _.stdout the output stream to treat as stdout
* @param {Gio.UnixOutputStream} _.stderr the output stream to treat as stderr
* @param {boolean} _.enableColor whether to print ANSI color codes
- * @param {string} _.prompt the prompt prefix
*/
- constructor({stdin, stdout, stderr, enableColor, prompt = 'gjs'}) {
+ constructor({stdin, stdout, stderr, enableColor}) {
this.stdin = stdin;
this.stdout = stdout;
this.stderr = stderr;
+ this.enableColor = enableColor;
- this._prompt = this._buildPrompt(prompt, enableColor);
+ this._prompt = this._buildPrompt();
this._cancelled = false;
/**
@@ -90,19 +90,13 @@ class ReplInput {
}
/**
- * @param {string} prompt a string to tag each new line with
- * @param {boolean} enableColors whether to print with color
+ * @param {string} pointer the pointer to prefix the line with
*/
- _buildPrompt(prompt, enableColors) {
- const prefix = prompt;
- const pointer = Figures.POINTER_SMALL;
- const noColor = `${prefix} ${pointer} `;
- const length = noColor.length;
- const withColor = `${Ansi.colors.yellow(prefix)} ${pointer} `;
- const renderedPrompt = enableColors ? withColor : noColor;
+ _buildPrompt(pointer = '>') {
+ const renderedPrompt = `${pointer} `;
+ const length = renderedPrompt.length;
return {
- prefix,
pointer,
length,
renderedPrompt,
@@ -439,9 +433,8 @@ class ReplInput {
getPrompt() {
if (this.pendingInputLines.length > 0) {
- // Create a prefix like '... ' that matches the current
- // prompt length...
- return ' '.padStart(this._prompt.length, '.');
+ // Create a prefix like '... '
+ return ' '.padStart(4, '.');
}
return this._prompt.renderedPrompt;
@@ -458,7 +451,7 @@ class ReplInput {
this.writeSync(prompt + value);
this.updateInputIndex(value);
- this.writeSync(Ansi.cursorTo(this._prompt.length + this.cursorColumn + 1));
+ this.writeSync(Ansi.cursorTo(prompt.length + this.cursorColumn + 1));
this.writeSync(Ansi.cursorShow);
this.flush();
}
@@ -574,6 +567,7 @@ export class Repl {
constructor() {
({Gio} = imports.gi);
+ this._version = imports.system.versionString;
this.lineNumber = 0;
this.isRaw = false;
@@ -616,24 +610,52 @@ export class Repl {
return true;
}
- evaluate(lines) {
- this.lineNumber++;
-
+ _evaluate(lines) {
try {
const result = Console.eval(lines, this.lineNumber);
- if (result !== undefined) {
- const encoded = new TextEncoder().encode(
- `${toString(result)}${this.isRaw ? '\n' : ''}`
- );
- this.input.writeSync(encoded);
- this.input.flush();
- }
+ if (result !== undefined)
+ this._print(`${toString(result)}`);
+
+ return null;
} catch (error) {
- console.error(error);
+ return error;
}
}
+ _printError(error) {
+ if (error.message)
+ this._print(`Uncaught ${error.name}: ${error.message}`);
+ else
+ this._print(`${toString(error)}`);
+ }
+
+ evaluate(lines) {
+ this.lineNumber++;
+
+ // TODO(ewlsh): Object/code block detection similar to Node
+ let wrappedLines = lines.trim();
+ if (wrappedLines.startsWith('{') &&
+ !wrappedLines.endsWith(';'))
+ wrappedLines = `(${wrappedLines})\n`;
+
+ // Attempt to evaluate any object literals in () first
+ let error = this._evaluate(wrappedLines);
+ if (!error)
+ return;
+
+ error = this._evaluate(lines);
+ if (!error)
+ return;
+
+ this._printError(error);
+ }
+
+ _print(string) {
+ this.input.writeSync(`${string}${this.isRaw ? '\n' : ''}`);
+ this.input.flush();
+ }
+
_registerInputHandler() {
// Start accepting input and rendering...
this.input.prompt(lines => {
@@ -677,6 +699,8 @@ export class Repl {
this.exit();
});
+ this._print(`GJS v${this._version}`);
+
this._registerInputHandler();
// Install our default mainloop...
diff --git a/modules/system.cpp b/modules/system.cpp
index 0cd16b6e4..8941ec1ed 100644
--- a/modules/system.cpp
+++ b/modules/system.cpp
@@ -327,6 +327,10 @@ gjs_js_define_system_stuff(JSContext *context,
return false;
}
+ JS::RootedValue v_gjs_version_string(context);
+ if (!gjs_string_from_utf8(context, VERSION, &v_gjs_version_string))
+ return false;
+
JS::RootedObject program_args_getter(
context,
JS_GetFunctionObject(js::NewFunctionByIdWithReserved(
@@ -349,5 +353,8 @@ gjs_js_define_system_stuff(JSContext *context,
GJS_MODULE_PROP_FLAGS | JSPROP_GETTER) &&
JS_DefinePropertyById(context, module, gjs->atoms().version(),
GJS_VERSION,
- GJS_MODULE_PROP_FLAGS | JSPROP_READONLY);
+ GJS_MODULE_PROP_FLAGS | JSPROP_READONLY) &&
+ JS_DefineProperty(context, module, "versionString",
+ v_gjs_version_string,
+ GJS_MODULE_PROP_FLAGS | JSPROP_READONLY);
}
diff --git a/tools/cliffy/ansi.js b/tools/cliffy/ansi.js
index c7cf0c8ce..27e8b12db 100644
--- a/tools/cliffy/ansi.js
+++ b/tools/cliffy/ansi.js
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2021 Evan Welsh <contact evanwelsh com>
-export * from 'https://deno.land/x/cliffy@v0.19.5/ansi/ansi.ts';
-export * from 'https://deno.land/x/cliffy@v0.19.5/ansi/ansi_escapes.ts';
-export * from 'https://deno.land/x/cliffy@v0.19.5/ansi/chain.ts';
-export * from 'https://deno.land/x/cliffy@v0.19.5/ansi/colors.ts';
-export * from 'https://deno.land/x/cliffy@v0.19.5/ansi/cursor_position.ts';
+export * from 'https://deno.land/x/cliffy@v0.20.1/ansi/ansi.ts';
+export * from 'https://deno.land/x/cliffy@v0.20.1/ansi/ansi_escapes.ts';
+export * from 'https://deno.land/x/cliffy@v0.20.1/ansi/chain.ts';
+export * from 'https://deno.land/x/cliffy@v0.20.1/ansi/colors.ts';
+export * from 'https://deno.land/x/cliffy@v0.20.1/ansi/cursor_position.ts';
diff --git a/tools/cliffy/lib.js b/tools/cliffy/lib.js
index f0e27bfb7..557b058db 100644
--- a/tools/cliffy/lib.js
+++ b/tools/cliffy/lib.js
@@ -5,7 +5,6 @@
export * as Ansi from './ansi.js';
export * as Keycode from 'https://deno.land/x/cliffy@v0.19.5/keycode/mod.ts';
-export {Figures} from 'https://deno.land/x/cliffy@v0.19.5/prompt/figures.ts';
import {cursorPosition} from './ansi.js';
diff --git a/tools/cliffy/transform.js b/tools/cliffy/transform.js
index 6aefb7f91..2c2a1b902 100644
--- a/tools/cliffy/transform.js
+++ b/tools/cliffy/transform.js
@@ -12,7 +12,7 @@ let source = new TextDecoder().decode(contents);
source = source.replace(/#/g, '$');
source =
`// SPDX-License-Identifier: MIT
-// SPDX-FileCopyrightText: 2020 Benjamin Fischer <c4spar gmx de>
+// SPDX-FileCopyrightText: 2022 Benjamin Fischer <c4spar gmx de>
// Inject our shim for the Deno global...
import * as Deno from './deno.js';
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]