From: Norbert Buchmuller Date: Mon, 8 Feb 2010 23:32:14 +0000 (+0100) Subject: SIGINT does not quit the REPL. X-Git-Tag: v1.003015~52 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=54fea9b0966ec7b5f91bc0567a41503c2e4e283b;p=p5sagit%2FDevel-REPL.git SIGINT does not quit the REPL. It just kills the line being edited. resolve rt.cpan#44231 Ctrl-C behavior is inconsistent with other shells/interpreters --- diff --git a/Changes b/Changes index 56aa5d8..e93388c 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,5 @@ +1.3.8 + - resolve rt.cpan#44231 SIGINT does not quit the REPL just kills the line being edited 1.3.7 - resolve rt.cpan#44919 fix deprecated use of compute_all_applicable_methods 1.3.6 diff --git a/Makefile.PL b/Makefile.PL index 481d378..6f37ee1 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -36,6 +36,10 @@ feature 'INC completion driver - tab complete module names in use and require', -default => 0, 'File::Next' => 0; +feature 'Interrupt plugin - traps SIGINT to kill long-running lines', + -default => 0, + 'Sys::SigAction' => 0; + feature 'Keywords completion driver - tab complete Perl keywords and operators', -default => 0, 'B::Keywords' => 0; diff --git a/lib/Devel/REPL/Plugin/Interrupt.pm b/lib/Devel/REPL/Plugin/Interrupt.pm index 0df8cb0..d7d7d76 100644 --- a/lib/Devel/REPL/Plugin/Interrupt.pm +++ b/lib/Devel/REPL/Plugin/Interrupt.pm @@ -1,17 +1,44 @@ package Devel::REPL::Plugin::Interrupt; use Devel::REPL::Plugin; +use Sys::SigAction qw(set_sig_handler); use namespace::clean -except => [ 'meta' ]; -around 'eval' => sub { - my $orig = shift; - my ($self, $line) = @_; +around 'run' => sub { + my ($orig, $self) = (shift, shift); - local $SIG{INT} = sub { + local $SIG{INT} = 'IGNORE'; + + return $self->$orig(@_); +}; + +around 'run_once' => sub { + my ($orig, $self) = (shift, shift); + + # We have to use Sys::SigAction: Perl 5.8+ has safe signal handling by + # default, and Term::ReadLine::Gnu restarts the interrupted system calls. + # The result is that the signal handler is not fired until you hit Enter. + my $sig_action = set_sig_handler INT => sub { die "Interrupted.\n"; }; - return $self->$orig($line); + return $self->$orig(@_); +}; + +around 'read' => sub { + my ($orig, $self) = (shift, shift); + + # here SIGINT is caught and only kills the line being edited + while (1) { + my $line = eval { $self->$orig(@_) }; + return $line unless $@; + + die unless $@ =~ /^Interrupted\./; + + # (Term::ReadLine::Gnu kills the line by default, but needs a LF - + # maybe I missed something?) + print "\n"; + } }; 1; @@ -22,9 +49,19 @@ __END__ Devel::REPL::Plugin::Interrupt - traps SIGINT to kill long-running lines +=head1 DESCRIPTION + +By default L exits on SIGINT (usually Ctrl-C). If you load this +module, SIGINT will be trapped and used to kill long-running commands +(statements) and also to kill the line being edited (like eg. BASH do). (You +can still use Ctrl-D to exit.) + =head1 AUTHOR Shawn M Moore, C<< >> -=cut +=head1 CONTRIBUTORS + +Norbert Buchmuller C<< >> +=cut