1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
|
package IO::Pager::less;
our $VERSION = 2.00; #Untouched since 2.00
use strict;
use warnings;
use base qw( IO::Pager::Unbuffered );
BEGIN{
die "Windows is currently unsupported" if $^O =~ /MSWin32/;
my $PAGER;
#Required for test 16
our $BLIB;
#local $ENV{PATHEXT} .= ";.PL"
foreach my $lib ( @INC ){
$PAGER = File::Spec->catfile($lib, 'IO', 'Pager', 'tp');
if( -e $PAGER ){
#Required for test 16
$ENV{PAGER} = $^X.($BLIB?' -Mblib ':' ').$PAGER;
last;
}
}
}
1;
__DATA__
package IO::Pager::less;
our $VERSION = 1.00;
use strict;
use base qw( IO::Pager );
use SelectSaver;
use IO::Pager::Perl;
our %CFG;
sub new(;$) { # [FH], procedural
my($class, $tied_fh);
eval { ($class, $tied_fh) = &IO::Pager::_init };
#We're not on a TTY so...
if( defined($class) && $class eq '0' or $@ =~ '!TTY' ){
#...leave filehandle alone if procedural
return $_[1] if defined($_[2]) && $_[2] eq 'procedural';
#...fall back to IO::Handle for transparent OO programming
eval "require IO::Handle" or die $@;
return IO::Handle->new_from_fd(fileno($_[1]), 'w');
}
$!=$@, return 0 if $@ =~ 'pipe';
my $self = tie *$tied_fh, $class, $tied_fh or return 0;
#XXX use Data::Dumper; print Dumper 'TIED: ', $$, $self;
#XXX CORE::print {$self->{real_fh}} "BOO!";
{ # Truly unbuffered
my $saver = SelectSaver->new($self->{real_fh});
$|=1;
}
return $self;
}
#Punt to base, preserving FH ($_[0]) for pass by reference to gensym
sub open(;$) { # [FH]
&new('IO::Pager::procedural', $_[0], 'procedural');
}
sub PRINT {
my ($self, @args) = @_;
CORE::print {$self->{LOG}} @args if exists($self->{LOG});
CORE::syswrite({$self->{real_fh}},
join('', @args) ) or die "Could not print to PAGER: $!\n";
}
sub flush {
$_[0]->refresh();
}
sub _pipe_to_fork ($) {
pipe(my $READ, my $WRITE=shift) or die;
{ # Unbuffer!
my $saver = SelectSaver->new($WRITE);
$|=1;
}
warn "$READ $WRITE"; #XXX
my $pid = fork();
die "fork() failed: $!" unless defined $pid;
#Parent is reader to maintain STDIN/STDOUT
if( $pid ){
warn "Parent: $$, Child: $pid";
close $WRITE;
my $tmp;
sysread($READ, $tmp, 1024);
warn 'WTF? ', $tmp;
open(STDIN, "<&=" . fileno($READ)) or die $!; }
else{
syswrite($WRITE, "MUAHAHAHA\n"); #XXX
close $READ; }
$pid;
}
sub TIEHANDLE {
my ($class, $tied_fh) = @_;
my($real_fh, $child);
#Parent is interface, child does work
if( $child = _pipe_to_fork( $real_fh=Symbol::gensym() ) ){
my $t = IO::Pager::Perl->new();
#Customize interfaces
foreach my $key ( keys(%CFG) ){
$t->add_func($key, $CFG{$key}) if $key;
}
while( eval{ $t->more(RT=>.05) } ){
my $tmp;
$t->add_text($tmp) if sysread($real_fh, $tmp, 1024);
}
#XXX exit or die?! SIGPIPE?!
}
else{
my $X = bless {
'real_fh' => $real_fh,
'tied_fh' => "$tied_fh", #Avoid self-reference leak
'child' => $child, #XXX Actually, we want the parent?!
'pager' => 'IO::Pager::less', #XXX tp
}, $class;
use Data::Dumper; warn Dumper ['BLESSED: ', $$, $X];
return $X;
}
}
1;
__END__
=pod
=head1 NAME
IO::Pager::less - No pager? Pipe output to Perl-based pager a TTY
=head1 SYNOPSIS
=cut
#!!! CURRENT IMPLEMENTATION REQUIRES Term::ReadKey
##Required if you want unbuffered output
use Term::ReadKey;
{
#!!! NOT AVAILABLE WITH CURRENT IMPLEMENTATION
#Configure extra shortcuts, add an embedded shell
%IO::Pager::less::CFG = ( '!' => sub{ "REPL implementation" } );
=pod
{
#Can be instantiated functionally or OO, same as other sub-classes.
my $token = new IO::Pager::less;
$token->print("Pure perl goodness...\n") while 1;
}
=head1 DESCRIPTION
IO::Pager::less is a simple, extensible, perl-based pager.
=cut
If you want behavior similar to IO::Pager::Buffer do not load Term::ReadKey,
and output will be buffered between keypresses.
=pod
See L<IO::Pager> for method details.
=cut
= head1 CONFIGURATION
I<%IO::Pager::less::CFG> elements are passed to Term::Pager's add_func method.
The hash keys are single key shortcut definitions, and values a callback to be
invoked when said key is pressed e.g;
#Forego default left-right scrolling for more less-like seeking
%IO::Pager::less::CFG = (
'<' => \&Term::Pager::to_top, #not move_left
'>' => \&Term::Pager::to_bottom #not move_right
);
Because IO::Pager::less forks, the callback functions must exist prior to
instantiation of the IO::Pager object to work properly.
=pod
=head1 METHODS
All methods are inherited from IO::Pager; except for instantiation and print.
=cut
= head1 CAVEATS
You probably want to do something with SIGPIPE eg;
eval {
local $SIG{PIPE} = sub { die };
local $STDOUT = IO::Pager::open(*STDOUT);
while (1) {
# Do something
}
}
# Do something else
=pod
=head1 SEE ALSO
L<IO::Pager>, L<Term::Pager>, L<IO::Pager::Buffered>, L<IO::Pager::Page>,
=head1 AUTHOR
Jerrad Pierce <jpierce@cpan.org>
Significant proddage provided by Tye McQueen.
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2003-2018 Jerrad Pierce
=over
=item * Thou shalt not claim ownership of unmodified materials.
=item * Thou shalt not claim whole ownership of modified materials.
=item * Thou shalt grant the indemnity of the provider of materials.
=item * Thou shalt use and dispense freely without other restrictions.
=back
Or, if you prefer:
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.0 or,
at your option, any later version of Perl 5 you may have available.
=cut
|