about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nix-repl.cc42
1 files changed, 37 insertions, 5 deletions
diff --git a/nix-repl.cc b/nix-repl.cc
index 0b84834491e7..bb205211793f 100644
--- a/nix-repl.cc
+++ b/nix-repl.cc
@@ -1,6 +1,8 @@
 #include <iostream>
 #include <cstdlib>
 
+#include <setjmp.h>
+
 #include <readline/readline.h>
 #include <readline/history.h>
 
@@ -42,13 +44,41 @@ void printHelp()
 }
 
 
+/* Apparently, the only way to get readline() to return on Ctrl-C
+   (SIGINT) is to use siglongjmp().  That's fucked up... */
+static sigjmp_buf sigintJmpBuf;
+
+
+static void sigintHandler(int signo)
+{
+    siglongjmp(sigintJmpBuf, 1);
+}
+
+
 bool getLine(string & line)
 {
-    char * s = readline("nix-repl> ");
-    if (!s) return false;
-    line = chomp(string(s));
-    free(s);
-    if (line != "") add_history(line.c_str());
+    struct sigaction act, old;
+    act.sa_handler = sigintHandler;
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0;
+    if (sigaction(SIGINT, &act, &old))
+        throw SysError("installing handler for SIGINT");
+
+    if (sigsetjmp(sigintJmpBuf, 1))
+        line = "";
+    else {
+        char * s = readline("nix-repl> ");
+        if (!s) return false;
+        line = chomp(string(s));
+        free(s);
+        if (line != "") add_history(line.c_str());
+    }
+
+    _isInterrupted = 0;
+
+    if (sigaction(SIGINT, &old, 0))
+        throw SysError("restoring handler for SIGINT");
+
     return true;
 }
 
@@ -98,6 +128,8 @@ void NixRepl::mainLoop()
 
 void NixRepl::processLine(string line)
 {
+    if (line == "") return;
+
     if (string(line, 0, 2) == ":a") {
         Value v;
         evalString(string(line, 2), v);