[gjs/ewlsh/nova-repl: 114/114] Update Cliffy, improve Repl UX




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]