1=head1 NAME 2 3Term::ReadLine - Perl interface to various C<readline> packages. 4If no real package is found, substitutes stubs instead of basic functions. 5 6=head1 SYNOPSIS 7 8 use Term::ReadLine; 9 my $term = new Term::ReadLine 'Simple Perl calc'; 10 my $prompt = "Enter your arithmetic expression: "; 11 my $OUT = $term->OUT || \*STDOUT; 12 while ( defined ($_ = $term->readline($prompt)) ) { 13 my $res = eval($_); 14 warn $@ if $@; 15 print $OUT $res, "\n" unless $@; 16 $term->addhistory($_) if /\S/; 17 } 18 19=head1 DESCRIPTION 20 21This package is just a front end to some other packages. It's a stub to 22set up a common interface to the various ReadLine implementations found on 23CPAN (under the C<Term::ReadLine::*> namespace). 24 25=head1 Minimal set of supported functions 26 27All the supported functions should be called as methods, i.e., either as 28 29 $term = new Term::ReadLine 'name'; 30 31or as 32 33 $term->addhistory('row'); 34 35where $term is a return value of Term::ReadLine-E<gt>new(). 36 37=over 12 38 39=item C<ReadLine> 40 41returns the actual package that executes the commands. Among possible 42values are C<Term::ReadLine::Gnu>, C<Term::ReadLine::Perl>, 43C<Term::ReadLine::Stub>. 44 45=item C<new> 46 47returns the handle for subsequent calls to following 48functions. Argument is the name of the application. Optionally can be 49followed by two arguments for C<IN> and C<OUT> filehandles. These 50arguments should be globs. 51 52=item C<readline> 53 54gets an input line, I<possibly> with actual C<readline> 55support. Trailing newline is removed. Returns C<undef> on C<EOF>. 56 57=item C<addhistory> 58 59adds the line to the history of input, from where it can be used if 60the actual C<readline> is present. 61 62=item C<IN>, C<OUT> 63 64return the filehandles for input and output or C<undef> if C<readline> 65input and output cannot be used for Perl. 66 67=item C<MinLine> 68 69If argument is specified, it is an advice on minimal size of line to 70be included into history. C<undef> means do not include anything into 71history. Returns the old value. 72 73=item C<findConsole> 74 75returns an array with two strings that give most appropriate names for 76files for input and output using conventions C<"E<lt>$in">, C<"E<gt>out">. 77 78=item Attribs 79 80returns a reference to a hash which describes internal configuration 81of the package. Names of keys in this hash conform to standard 82conventions with the leading C<rl_> stripped. 83 84=item C<Features> 85 86Returns a reference to a hash with keys being features present in 87current implementation. Several optional features are used in the 88minimal interface: C<appname> should be present if the first argument 89to C<new> is recognized, and C<minline> should be present if 90C<MinLine> method is not dummy. C<autohistory> should be present if 91lines are put into history automatically (maybe subject to 92C<MinLine>), and C<addhistory> if C<addhistory> method is not dummy. 93 94If C<Features> method reports a feature C<attribs> as present, the 95method C<Attribs> is not dummy. 96 97=back 98 99=head1 Additional supported functions 100 101Actually C<Term::ReadLine> can use some other package, that will 102support a richer set of commands. 103 104All these commands are callable via method interface and have names 105which conform to standard conventions with the leading C<rl_> stripped. 106 107The stub package included with the perl distribution allows some 108additional methods: 109 110=over 12 111 112=item C<tkRunning> 113 114makes Tk event loop run when waiting for user input (i.e., during 115C<readline> method). 116 117=item C<ornaments> 118 119makes the command line stand out by using termcap data. The argument 120to C<ornaments> should be 0, 1, or a string of a form 121C<"aa,bb,cc,dd">. Four components of this string should be names of 122I<terminal capacities>, first two will be issued to make the prompt 123standout, last two to make the input line standout. 124 125=item C<newTTY> 126 127takes two arguments which are input filehandle and output filehandle. 128Switches to use these filehandles. 129 130=back 131 132One can check whether the currently loaded ReadLine package supports 133these methods by checking for corresponding C<Features>. 134 135=head1 EXPORTS 136 137None 138 139=head1 ENVIRONMENT 140 141The environment variable C<PERL_RL> governs which ReadLine clone is 142loaded. If the value is false, a dummy interface is used. If the value 143is true, it should be tail of the name of the package to use, such as 144C<Perl> or C<Gnu>. 145 146As a special case, if the value of this variable is space-separated, 147the tail might be used to disable the ornaments by setting the tail to 148be C<o=0> or C<ornaments=0>. The head should be as described above, say 149 150If the variable is not set, or if the head of space-separated list is 151empty, the best available package is loaded. 152 153 export "PERL_RL=Perl o=0" # Use Perl ReadLine without ornaments 154 export "PERL_RL= o=0" # Use best available ReadLine without ornaments 155 156(Note that processing of C<PERL_RL> for ornaments is in the discretion of the 157particular used C<Term::ReadLine::*> package). 158 159=head1 CAVEATS 160 161It seems that using Term::ReadLine from Emacs minibuffer doesn't work 162quite right and one will get an error message like 163 164 Cannot open /dev/tty for read at ... 165 166One possible workaround for this is to explicitly open /dev/tty like this 167 168 open (FH, "/dev/tty" ) 169 or eval 'sub Term::ReadLine::findConsole { ("&STDIN", "&STDERR") }'; 170 die $@ if $@; 171 close (FH); 172 173or you can try using the 4-argument form of Term::ReadLine->new(). 174 175=cut 176 177use strict; 178 179package Term::ReadLine::Stub; 180our @ISA = qw'Term::ReadLine::Tk Term::ReadLine::TermCap'; 181 182$DB::emacs = $DB::emacs; # To peacify -w 183our @rl_term_set; 184*rl_term_set = \@Term::ReadLine::TermCap::rl_term_set; 185 186sub PERL_UNICODE_STDIN () { 0x0001 } 187 188sub ReadLine {'Term::ReadLine::Stub'} 189sub readline { 190 my $self = shift; 191 my ($in,$out,$str) = @$self; 192 my $prompt = shift; 193 print $out $rl_term_set[0], $prompt, $rl_term_set[1], $rl_term_set[2]; 194 $self->register_Tk 195 if not $Term::ReadLine::registered and $Term::ReadLine::toloop 196 and defined &Tk::DoOneEvent; 197 #$str = scalar <$in>; 198 $str = $self->get_line; 199 $str =~ s/^\s*\Q$prompt\E// if ($^O eq 'MacOS'); 200 utf8::upgrade($str) 201 if (${^UNICODE} & PERL_UNICODE_STDIN || defined ${^ENCODING}) && 202 utf8::valid($str); 203 print $out $rl_term_set[3]; 204 # bug in 5.000: chomping empty string creats length -1: 205 chomp $str if defined $str; 206 $str; 207} 208sub addhistory {} 209 210sub findConsole { 211 my $console; 212 213 if ($^O eq 'MacOS') { 214 $console = "Dev:Console"; 215 } elsif (-e "/dev/tty") { 216 $console = "/dev/tty"; 217 } elsif (-e "con" or $^O eq 'MSWin32') { 218 $console = "con"; 219 } else { 220 $console = "sys\$command"; 221 } 222 223 if (($^O eq 'amigaos') || ($^O eq 'beos') || ($^O eq 'epoc')) { 224 $console = undef; 225 } 226 elsif ($^O eq 'os2') { 227 if ($DB::emacs) { 228 $console = undef; 229 } else { 230 $console = "/dev/con"; 231 } 232 } 233 234 my $consoleOUT = $console; 235 $console = "&STDIN" unless defined $console; 236 if (!defined $consoleOUT) { 237 $consoleOUT = defined fileno(STDERR) ? "&STDERR" : "&STDOUT"; 238 } 239 ($console,$consoleOUT); 240} 241 242sub new { 243 die "method new called with wrong number of arguments" 244 unless @_==2 or @_==4; 245 #local (*FIN, *FOUT); 246 my ($FIN, $FOUT, $ret); 247 if (@_==2) { 248 my($console, $consoleOUT) = $_[0]->findConsole; 249 250 open(FIN, "<$console"); 251 open(FOUT,">$consoleOUT"); 252 #OUT->autoflush(1); # Conflicts with debugger? 253 my $sel = select(FOUT); 254 $| = 1; # for DB::OUT 255 select($sel); 256 $ret = bless [\*FIN, \*FOUT]; 257 } else { # Filehandles supplied 258 $FIN = $_[2]; $FOUT = $_[3]; 259 #OUT->autoflush(1); # Conflicts with debugger? 260 my $sel = select($FOUT); 261 $| = 1; # for DB::OUT 262 select($sel); 263 $ret = bless [$FIN, $FOUT]; 264 } 265 if ($ret->Features->{ornaments} 266 and not ($ENV{PERL_RL} and $ENV{PERL_RL} =~ /\bo\w*=0/)) { 267 local $Term::ReadLine::termcap_nowarn = 1; 268 $ret->ornaments(1); 269 } 270 return $ret; 271} 272 273sub newTTY { 274 my ($self, $in, $out) = @_; 275 $self->[0] = $in; 276 $self->[1] = $out; 277 my $sel = select($out); 278 $| = 1; # for DB::OUT 279 select($sel); 280} 281 282sub IN { shift->[0] } 283sub OUT { shift->[1] } 284sub MinLine { undef } 285sub Attribs { {} } 286 287my %features = (tkRunning => 1, ornaments => 1, 'newTTY' => 1); 288sub Features { \%features } 289 290package Term::ReadLine; # So late to allow the above code be defined? 291 292our $VERSION = '1.02'; 293 294my ($which) = exists $ENV{PERL_RL} ? split /\s+/, $ENV{PERL_RL} : undef; 295if ($which) { 296 if ($which =~ /\bgnu\b/i){ 297 eval "use Term::ReadLine::Gnu;"; 298 } elsif ($which =~ /\bperl\b/i) { 299 eval "use Term::ReadLine::Perl;"; 300 } else { 301 eval "use Term::ReadLine::$which;"; 302 } 303} elsif (defined $which and $which ne '') { # Defined but false 304 # Do nothing fancy 305} else { 306 eval "use Term::ReadLine::Gnu; 1" or eval "use Term::ReadLine::Perl; 1"; 307} 308 309#require FileHandle; 310 311# To make possible switch off RL in debugger: (Not needed, work done 312# in debugger). 313our @ISA; 314if (defined &Term::ReadLine::Gnu::readline) { 315 @ISA = qw(Term::ReadLine::Gnu Term::ReadLine::Stub); 316} elsif (defined &Term::ReadLine::Perl::readline) { 317 @ISA = qw(Term::ReadLine::Perl Term::ReadLine::Stub); 318} elsif (defined $which && defined &{"Term::ReadLine::$which\::readline"}) { 319 @ISA = "Term::ReadLine::$which"; 320} else { 321 @ISA = qw(Term::ReadLine::Stub); 322} 323 324package Term::ReadLine::TermCap; 325 326# Prompt-start, prompt-end, command-line-start, command-line-end 327# -- zero-width beautifies to emit around prompt and the command line. 328our @rl_term_set = ("","","",""); 329# string encoded: 330our $rl_term_set = ',,,'; 331 332our $terminal; 333sub LoadTermCap { 334 return if defined $terminal; 335 336 require Term::Cap; 337 $terminal = Tgetent Term::Cap ({OSPEED => 9600}); # Avoid warning. 338} 339 340sub ornaments { 341 shift; 342 return $rl_term_set unless @_; 343 $rl_term_set = shift; 344 $rl_term_set ||= ',,,'; 345 $rl_term_set = 'us,ue,md,me' if $rl_term_set eq '1'; 346 my @ts = split /,/, $rl_term_set, 4; 347 eval { LoadTermCap }; 348 unless (defined $terminal) { 349 warn("Cannot find termcap: $@\n") unless $Term::ReadLine::termcap_nowarn; 350 $rl_term_set = ',,,'; 351 return; 352 } 353 @rl_term_set = map {$_ ? $terminal->Tputs($_,1) || '' : ''} @ts; 354 return $rl_term_set; 355} 356 357 358package Term::ReadLine::Tk; 359 360our($count_handle, $count_DoOne, $count_loop); 361$count_handle = $count_DoOne = $count_loop = 0; 362 363our($giveup); 364sub handle {$giveup = 1; $count_handle++} 365 366sub Tk_loop { 367 # Tk->tkwait('variable',\$giveup); # needs Widget 368 $count_DoOne++, Tk::DoOneEvent(0) until $giveup; 369 $count_loop++; 370 $giveup = 0; 371} 372 373sub register_Tk { 374 my $self = shift; 375 $Term::ReadLine::registered++ 376 or Tk->fileevent($self->IN,'readable',\&handle); 377} 378 379sub tkRunning { 380 $Term::ReadLine::toloop = $_[1] if @_ > 1; 381 $Term::ReadLine::toloop; 382} 383 384sub get_c { 385 my $self = shift; 386 $self->Tk_loop if $Term::ReadLine::toloop && defined &Tk::DoOneEvent; 387 return getc $self->IN; 388} 389 390sub get_line { 391 my $self = shift; 392 $self->Tk_loop if $Term::ReadLine::toloop && defined &Tk::DoOneEvent; 393 my $in = $self->IN; 394 local ($/) = "\n"; 395 return scalar <$in>; 396} 397 3981; 399 400