aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxbreak <rosenquist.calle@gmail.com>2019-03-24 09:39:48 +0000
committerxbreak <rosenquist.calle@gmail.com>2019-03-24 09:39:48 +0000
commitfcd766097636943ff11b84747d11a4e52d3d8e38 (patch)
tree4491ef41fec337ee48348b9af78d296216684688
parent56f1ed55791fc7e8671f10263baa7a9d15b47c4b (diff)
repl: Restore CTRL-C behaviour
Install signal handler during `readline` to handle SIGINT to abort partially typed expressions.
-rw-r--r--src/nix/repl.cc40
1 files changed, 40 insertions, 0 deletions
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index 227affc60..d8f812149 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -192,6 +192,14 @@ static int listPossibleCallback(char *s, char ***avp) {
return ac;
}
+namespace {
+ // Used to communicate to NixRepl::getLine whether a signal occurred in ::readline.
+ volatile sig_atomic_t g_signal_received = 0;
+
+ void sigintHandler(int signo) {
+ g_signal_received = signo;
+ }
+}
void NixRepl::mainLoop(const std::vector<std::string> & files)
{
@@ -251,8 +259,40 @@ void NixRepl::mainLoop(const std::vector<std::string> & files)
bool NixRepl::getLine(string & input, const std::string &prompt)
{
+ struct sigaction act, old;
+ sigset_t savedSignalMask, set;
+
+ auto setupSignals = [&]() {
+ act.sa_handler = sigintHandler;
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0;
+ if (sigaction(SIGINT, &act, &old))
+ throw SysError("installing handler for SIGINT");
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGINT);
+ if (sigprocmask(SIG_UNBLOCK, &set, &savedSignalMask))
+ throw SysError("unblocking SIGINT");
+ };
+ auto restoreSignals = [&]() {
+ if (sigprocmask(SIG_SETMASK, &savedSignalMask, nullptr))
+ throw SysError("restoring signals");
+
+ if (sigaction(SIGINT, &old, 0))
+ throw SysError("restoring handler for SIGINT");
+ };
+
+ setupSignals();
char * s = readline(prompt.c_str());
Finally doFree([&]() { free(s); });
+ restoreSignals();
+
+ if (g_signal_received) {
+ g_signal_received = 0;
+ input.clear();
+ return true;
+ }
+
if (!s)
return false;
input += s;