[gjs/ewlsh/nova-repl] Support Ctrl+C guard in Repl




commit d01f1fe85fc6ea37d9b3414bd42fb8bb9ed77ba7
Author: Evan Welsh <contact evanwelsh com>
Date:   Fri Sep 3 12:35:57 2021 -0700

    Support Ctrl+C guard in Repl

 gjs/console.cpp     |  2 +-
 modules/console.cpp | 28 +++++-----------------------
 modules/esm/repl.js | 31 +++++++++++++++++++++++++++++--
 tools/run_iwyu.sh   |  5 ++---
 util/console.cpp    |  3 ++-
 5 files changed, 39 insertions(+), 30 deletions(-)
---
diff --git a/gjs/console.cpp b/gjs/console.cpp
index 632416f6..d51a98ac 100644
--- a/gjs/console.cpp
+++ b/gjs/console.cpp
@@ -44,7 +44,7 @@ static GOptionEntry entries[] = {
     { "command", 'c', 0, G_OPTION_ARG_STRING, &command, "Program passed in as a string", "COMMAND" },
     { "coverage-prefix", 'C', 0, G_OPTION_ARG_STRING_ARRAY, &coverage_prefixes, "Add the prefix PREFIX to 
the list of files to generate coverage info for", "PREFIX" },
     { "coverage-output", 0, 0, G_OPTION_ARG_STRING, &coverage_output_path, "Write coverage output to a 
directory DIR. This option is mandatory when using --coverage-prefix", "DIR", },
-    { "interactive",'i', 0, G_OPTION_ARG_NONE, &use_interactive_repl,
+    { "interactive", 'i', 0, G_OPTION_ARG_NONE, &use_interactive_repl,
         "Start the interactive repl"},
     { "include-path", 'I', 0, G_OPTION_ARG_STRING_ARRAY, &include_path, "Add the directory DIR to the list 
of directories to search for js files.", "DIR" },
     { "module", 'm', 0, G_OPTION_ARG_NONE, &exec_as_module, "Execute the file as a module." },
diff --git a/modules/console.cpp b/modules/console.cpp
index ccef2bc3..63d013af 100644
--- a/modules/console.cpp
+++ b/modules/console.cpp
@@ -3,35 +3,25 @@
 // SPDX-License-Identifier: MPL-1.1 OR GPL-2.0-or-later OR LGPL-2.1-or-later
 // SPDX-FileCopyrightText: 1998 Netscape Communications Corporation
 
-#include <config.h>  // for HAVE_READLINE_READLINE_H
-
-#ifdef HAVE_SIGNAL_H
-#    include <setjmp.h>
-#    include <signal.h>
-#    ifdef _WIN32
-#        define sigjmp_buf jmp_buf
-#        define siglongjmp(e, v) longjmp (e, v)
-#        define sigsetjmp(v, m) setjmp (v)
-#    endif
-#endif
+#include <config.h>
 
 #include <string>
 
 #include <glib.h>
-#include <glib/gprintf.h>  // for g_fprintf
+#include <stdio.h>
 
 #include <js/CallArgs.h>
 #include <js/CompilationAndEvaluation.h>
 #include <js/CompileOptions.h>
 #include <js/ErrorReport.h>
 #include <js/Exception.h>
+#include <js/PropertySpec.h>
 #include <js/RootingAPI.h>
 #include <js/SourceText.h>
 #include <js/TypeDecls.h>
-#include <js/Warnings.h>
+#include <js/Utility.h>
 #include <jsapi.h>  // for JS_IsExceptionPending, Exce...
 
-#include "gjs/atoms.h"
 #include "gjs/context-private.h"
 #include "gjs/jsapi-util-args.h"
 #include "gjs/jsapi-util.h"
@@ -42,10 +32,6 @@ namespace mozilla {
 union Utf8Unit;
 }
 
-static void gjs_console_warning_reporter(JSContext* cx, JSErrorReport* report) {
-    JS::PrintError(cx, stderr, report, /* reportWarnings = */ true);
-}
-
 /* Based on js::shell::AutoReportException from SpiderMonkey. */
 class AutoReportException {
     JSContext *m_cx;
@@ -124,16 +110,13 @@ GJS_JSAPI_RETURN_CONVENTION
 static bool gjs_console_interact(JSContext* context, unsigned argc,
                                  JS::Value* vp) {
     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
-    JS::RootedObject global(context, gjs_get_import_global(context));
-
     JS::UniqueChars prompt;
     if (!gjs_parse_call_args(context, "interact", args, "s", "prompt", &prompt))
         return false;
 
     GjsAutoChar buffer;
-    if (!gjs_console_readline(buffer.out(), prompt.get())) {
+    if (!gjs_console_readline(buffer.out(), prompt.get()))
         return true;
-    }
 
     return gjs_string_from_utf8(context, buffer, args.rval());
 }
@@ -182,7 +165,6 @@ static bool gjs_console_is_valid_js(JSContext* cx, unsigned argc,
                                     JS::Value* vp) {
     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     JS::RootedString str(cx);
-
     if (!gjs_parse_call_args(cx, "isValid", args, "S", "code", &str))
         return false;
 
diff --git a/modules/esm/repl.js b/modules/esm/repl.js
index 648f0b66..698ec148 100644
--- a/modules/esm/repl.js
+++ b/modules/esm/repl.js
@@ -31,6 +31,8 @@ function toString(value) {
 }
 
 const sInputHandler = Symbol('input handler');
+const sExitHandler = Symbol('exit handler');
+const sExitWarning = Symbol('exit warning');
 class ReplInput {
     /**
      * @param {object} _ _
@@ -81,6 +83,8 @@ class ReplInput {
              * @param {string} _input the inputted line or lines (separated by \n)
              */
             _input => { };
+
+        this[sExitWarning] = false;
     }
 
     [Symbol.toStringTag]() {
@@ -149,6 +153,17 @@ class ReplInput {
         this.writeSync(Ansi.eraseDown(lines));
     }
 
+    exit() {
+        if (this[sExitWarning]) {
+            this[sExitWarning] = false;
+            this[sExitHandler]?.();
+        } else {
+            this[sExitWarning] = true;
+            this.writeSync('\n(To exit, press Ctrl+C again or Ctrl+D)\n');
+            this.flush();
+        }
+    }
+
     historyUp() {
         if (this.historyIndex < this.history.length - 1) {
             this.historyIndex++;
@@ -201,7 +216,7 @@ class ReplInput {
         if (this.cursorColumn < editableValue.length - 1)
             editableValue.splice(this.cursorColumn, 1);
         else
-            this.stop();
+            this.exit();
     }
 
     deleteToBeginning() {
@@ -310,6 +325,7 @@ class ReplInput {
         if (this.validate(js)) {
             // Reset lines before input is triggered
             this.pendingInputLines = [];
+            this[sExitWarning] = false;
             this[sInputHandler]?.(js);
         } else {
             // Buffer the input until a compilable unit is found...
@@ -320,6 +336,9 @@ class ReplInput {
     handleEvent(key) {
         if (key.ctrl && !key.meta && !key.shift) {
             switch (key.name) {
+            case 'c':
+                this.exit();
+                return;
             case 'h':
                 this.deleteChar();
                 return;
@@ -452,7 +471,7 @@ class ReplInput {
     }
 
     /**
-     * @param {Uint8Array} buffer a string or Uint8Array to write to stdout
+     * @param {Uint8Array | string} buffer a string or Uint8Array to write to stdout
      */
     writeSync(buffer) {
         if (typeof buffer === 'string')
@@ -515,6 +534,10 @@ class ReplInput {
         this._cancelled = false;
         this.read();
     }
+
+    onExit(exitHandler) {
+        this[sExitHandler] = exitHandler;
+    }
 }
 
 class FallbackReplInput extends ReplInput {
@@ -651,6 +674,10 @@ export class Repl {
                 enableColor: this[sSupportsColor],
             });
 
+            this.input.onExit(() => {
+                this.exit();
+            });
+
             this._registerInputHandler();
 
             // Install our default mainloop...
diff --git a/tools/run_iwyu.sh b/tools/run_iwyu.sh
index 458578f0..9a2b2f3a 100755
--- a/tools/run_iwyu.sh
+++ b/tools/run_iwyu.sh
@@ -28,7 +28,6 @@ should_analyze () {
         all) return 0 ;;
         *$file*) return 0 ;;
         *${file%.cpp}.h*) return 0 ;;
-        *${file%.cpp}.hxx*) return 0 ;;
         *${file%.cpp}-inl.h*) return 0 ;;
         *${file%.cpp}-private.h*) return 0 ;;
         *${file%.c}.h*) return 0 ;;
@@ -44,7 +43,7 @@ fi
 
 echo "files: $files"
 
-IWYU="python3 $(which iwyu_tool || which iwyu_tool.py) -p ."
+IWYU="python3 $(which iwyu_tool || which iwyu-tool || which iwyu_tool.py) -p ."
 IWYU_RAW="include-what-you-use -xc++ -std=c++17 -Xiwyu --keep=config.h"
 IWYU_RAW_INC="-I. -I.. $(pkg-config --cflags gobject-introspection-1.0 mozjs-78)"
 PRIVATE_MAPPING="-Xiwyu --mapping_file=$SRCDIR/tools/gjs-private-iwyu.imp -Xiwyu --keep=config.h"
@@ -57,7 +56,7 @@ EXIT=0
 for FILE in $SRCDIR/gi/arg-types-inl.h $SRCDIR/gi/js-value-inl.h \
     $SRCDIR/gi/utils-inl.h $SRCDIR/gjs/enum-utils.h \
     $SRCDIR/gjs/jsapi-util-args.h $SRCDIR/gjs/jsapi-util-root.h \
-    $SRCDIR/modules/cairo-module.h
+    $SRCDIR/modules/cairo-module.h $SRCDIR/util/console.hxx
 do
     if should_analyze $FILE; then
         if ! $IWYU_RAW $(realpath --relative-to=. $FILE) $IWYU_RAW_INC 2>&1 \
diff --git a/util/console.cpp b/util/console.cpp
index 4498d165..3c0b7649 100644
--- a/util/console.cpp
+++ b/util/console.cpp
@@ -97,8 +97,9 @@ bool enable_raw_mode() {
     // Disable echoing (terminal reprinting input)
     // Disable canonical mode (output reflects input)
     // Disable "extensions" that allow users to inject
+    // Disable C signal handling
     // https://www.gnu.org/software/libc/manual/html_node/Other-Special.html
-    raw.c_lflag &= ~(ECHO | ICANON | IEXTEN);
+    raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
     // Set 0 characters required for a read
     raw.c_cc[VMIN] = 0;
     // Set the read timeout to 1 decisecond (0.1 seconds)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]