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
					
				
					 1 changed files with 40 additions and 0 deletions
				
			
		| 
						 | 
					@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue