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




commit 458a8faa3ff05d918c0c71b9dad0a807a3e5485b
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 +-
 meson.build                      |  2 +-
 modules/console.cpp              | 30 ++++++------------------------
 modules/esm/repl.js              | 31 +++++++++++++++++++++++++++++--
 test/check-pch.sh                |  1 -
 tools/run_iwyu.sh                |  3 +--
 util/console.cpp                 |  5 +++--
 util/{console.hxx => console.hh} |  0
 8 files changed, 41 insertions(+), 33 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/meson.build b/meson.build
index 795ee985..0a0bf8d0 100644
--- a/meson.build
+++ b/meson.build
@@ -429,7 +429,7 @@ libgjs_jsapi_sources = [
     'gjs/jsapi-util-root.h',
     'gjs/jsapi-util-string.cpp',
     'gjs/jsapi-util.cpp', 'gjs/jsapi-util.h',
-    'util/console.cpp', 'util/console.h', 'util/console.hxx',
+    'util/console.cpp', 'util/console.h', 'util/console.hh',
     'util/log.cpp', 'util/log.h',
     'util/misc.cpp', 'util/misc.h',
 ]
diff --git a/modules/console.cpp b/modules/console.cpp
index 905d71e7..5099b9c2 100644
--- a/modules/console.cpp
+++ b/modules/console.cpp
@@ -3,49 +3,35 @@
 // 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"
 #include "modules/console.h"
-#include "util/console.hxx"
+#include "util/console.hh"
 
 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 5862637c..e1c31216 100644
--- a/modules/esm/repl.js
+++ b/modules/esm/repl.js
@@ -29,6 +29,8 @@ function toString(value) {
 }
 
 const sInputHandler = Symbol('input handler');
+const sExitHandler = Symbol('exit handler');
+const sExitWarning = Symbol('exit warning');
 class ReplInput {
     /**
      * @param {object} _ _
@@ -79,6 +81,8 @@ class ReplInput {
              * @param {string} _input the inputted line or lines (separated by \n)
              */
             _input => { };
+
+        this[sExitWarning] = false;
     }
 
     [Symbol.toStringTag]() {
@@ -147,6 +151,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++;
@@ -199,7 +214,7 @@ class ReplInput {
         if (this.cursorColumn < editableValue.length - 1)
             editableValue.splice(this.cursorColumn, 1);
         else
-            this.stop();
+            this.exit();
     }
 
     deleteToBeginning() {
@@ -308,6 +323,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...
@@ -318,6 +334,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;
@@ -450,7 +469,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')
@@ -513,6 +532,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/test/check-pch.sh b/test/check-pch.sh
index 606502fb..fd27b10f 100755
--- a/test/check-pch.sh
+++ b/test/check-pch.sh
@@ -122,7 +122,6 @@ INCLUDED_FILES=(
     \*.c
     \*.cpp
     \*.h
-    \*.hxx
 )
 
 grep_include_lines() {
diff --git a/tools/run_iwyu.sh b/tools/run_iwyu.sh
index 458578f0..ab4c99bc 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"
diff --git a/util/console.cpp b/util/console.cpp
index d2283d63..e3fbfdbe 100644
--- a/util/console.cpp
+++ b/util/console.cpp
@@ -19,7 +19,7 @@
 #include <glib.h>
 
 #include "util/console.h"
-#include "util/console.hxx"
+#include "util/console.hh"
 
 /**
  * ANSI escape code sequences to manipulate terminals.
@@ -98,8 +98,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)
diff --git a/util/console.hxx b/util/console.hh
similarity index 100%
rename from util/console.hxx
rename to util/console.hh


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