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



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

    Support Ctrl+C guard in Repl

 modules/esm/repl.js | 31 +++++++++++++++++++++++++++++--
 util/console.cpp    |  3 ++-
 2 files changed, 31 insertions(+), 3 deletions(-)
---
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/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]