forked from lix-project/lix
repl: Restore CTRL-C behaviour
Install signal handler during `readline` to handle SIGINT to abort partially typed expressions.
This commit is contained in:
parent
56f1ed5579
commit
fcd7660976
|
@ -192,6 +192,14 @@ static int listPossibleCallback(char *s, char ***avp) {
|
||||||
return ac;
|
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)
|
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)
|
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());
|
char * s = readline(prompt.c_str());
|
||||||
Finally doFree([&]() { free(s); });
|
Finally doFree([&]() { free(s); });
|
||||||
|
restoreSignals();
|
||||||
|
|
||||||
|
if (g_signal_received) {
|
||||||
|
g_signal_received = 0;
|
||||||
|
input.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!s)
|
if (!s)
|
||||||
return false;
|
return false;
|
||||||
input += s;
|
input += s;
|
||||||
|
|
Loading…
Reference in a new issue