381f69026cb0e4c11f6b0761694d7d540943935f
[p5sagit/Devel-REPL.git] / lib / Devel / REPL / Plugin / Interrupt.pm
1 use strict;
2 use warnings;
3 package Devel::REPL::Plugin::Interrupt;
4 # ABSTRACT: Traps SIGINT to kill long-running lines
5
6 our $VERSION = '1.003029';
7
8 use Devel::REPL::Plugin;
9 use Sys::SigAction qw(set_sig_handler);
10 use namespace::autoclean;
11
12 around 'run' => sub {
13     my ($orig, $self) = (shift, shift);
14
15     local $SIG{INT} = 'IGNORE';
16
17     return $self->$orig(@_);
18 };
19
20 around 'run_once' => sub {
21     my ($orig, $self) = (shift, shift);
22
23     # We have to use Sys::SigAction: Perl 5.8+ has safe signal handling by
24     # default, and Term::ReadLine::Gnu restarts the interrupted system calls.
25     # The result is that the signal handler is not fired until you hit Enter.
26     my $sig_action = set_sig_handler INT => sub {
27         die "Interrupted.\n";
28     };
29
30     return $self->$orig(@_);
31 };
32
33 around 'read' => sub {
34     my ($orig, $self) = (shift, shift);
35
36     # here SIGINT is caught and only kills the line being edited
37     while (1) {
38         my $line = eval { $self->$orig(@_) };
39         return $line unless $@;
40
41         die unless $@ =~ /^Interrupted\./;
42
43         # (Term::ReadLine::Gnu kills the line by default, but needs a LF -
44         # maybe I missed something?)
45         print "\n";
46     }
47 };
48
49 1;
50
51 __END__
52
53 =pod
54
55 =head1 DESCRIPTION
56
57 By default L<Devel::REPL> exits on SIGINT (usually Ctrl-C). If you load this
58 module, SIGINT will be trapped and used to kill long-running commands
59 (statements) and also to kill the line being edited (like eg. BASH do). (You
60 can still use Ctrl-D to exit.)
61
62 =head1 AUTHOR
63
64 Shawn M Moore, C<< <sartak at gmail dot com> >>
65
66 =cut