POE::Wheel::ReadLine - prompted terminal input |
POE::Wheel::ReadLine - prompted terminal input
# Create the wheel. $heap->{wheel} = POE::Wheel::ReadLine->new( InputEvent => got_input, appname => 'mycli' );
# Trigger the wheel to read a line of input. $heap->{wheel}->get( 'Prompt: ' );
# Add a line to the wheel's input history. $heap->{wheel}->addhistory( $input );
# Input handler. If $input is defined, then it contains a line of # input. Otherwise $exception contains a word describing some kind # of user exception. Currently these are 'interrupt' and 'cancel'. sub got_input_handler { my ($heap, $input, $exception) = @_[HEAP, ARG0, ARG1]; if (defined $input) { $heap->{wheel}->addhistory($input); $heap->{wheel}->put("\tGot: $input"); $heap->{wheel}->get('Prompt: '); # get another line } else { $heap->{wheel}->put("\tException: $exception"); } }
# Clear the terminal. $heap->{wheel}->clear();
ReadLine performs non-blocking, event-driven console input, using Term::Cap to interact with the terminal display and Term::ReadKey to interact with its keyboard.
ReadLine handles almost all common input editing keys; it provides an
input history list; it has both vi and emacs modes; it provides
incremental search facilities; it is fully customizable and it is
compatible with standard readline(3)
implementations such as
Term::ReadLine::Gnu.
ReadLine is configured by placing commands in an initialization file (the inputrc file). The name of this file is taken from the value of the INPUTRC environment variable. If that variable is unset, the default is ~/.inputrc. When the wheel is instantiated, the init file is read and the key bindings and variables are set. There are only a few basic constructs allowed in the readline init file. Blank lines are ignored. Lines beginning with a '#' are comments. Lines beginning with a '$' indicate conditional constructs. Other lines denote key bindings and variable settings. Each program using this library may add its own commands and bindings. For more detail on the inputrc file, see readline(3).
The default editing mode will be emacs-style, although this can be configured by setting the 'editing-mode' variable within the inputrc, or by setting the EDITOR environment variable.
new()
creates a new wheel, returning the wheels reference.
The quiet period between input events gives a program the opportunity to change the prompt or process lines before the next one arrives.
ARG0
contains the input line, if one was present. If
ARG0
is not defined, then ARG1
contains a word describing a
user-generated exception:
The 'interrupt' exception means a user pressed C-c (^C) to interrupt the program. It's up to the input event's handler to decide what to do next.
The 'cancel' exception means a user pressed C-g (^G) to cancel a line of input.
The 'eot' exception means the user pressed C-d (^D) while the input line was empty. EOT is the ASCII name for ^D.
Finally, ARG2
contains the ReadLine wheel's unique ID.
put()
method is called.
put()
displays text immediately when the user isn't being prompted
for input. It will also pre-empt the user to display text right away
when PutMode is ``immediate''.
When PutMode is ``after'', all put()
text is held until after the
user enters or cancels (See C-g) her input.
PutMode can also be ``idle''. In this mode, text is displayed right away if the keyboard has been idle for a certain period (see the IdleTime parameter). Otherwise it's held as in ``after'' mode until input is completed or canceled, or until the keyboard becomes idle for at least IdleTime seconds. This is ReadLine's default mode.
put()
becomes immediate or buffered text is flushed to the display. It is
only meaningful when InputMode is ``idle''. IdleTime defaults to two
seconds.
$if poe-readline # bind the following sequence in emacs mode set keymap emacs # display poe debug data Control-xP: poe-wheel-debug $endif
To bind keys to your own functions, the function name has to be made visible to the wheel before the binding is attempted. To register a function, use the method POE::Wheel::ReadLine::add_defun:
POE::Wheel::ReadLine->add_defun('reverse-line', \&reverse_line);
The function will be called with three parameters: a reference to the wheel object itself, the key sequence in a printable form, and the raw key sequence. When adding a new defun, an optional third parameter may be provided which is a key sequence to bind to. This should be in the same format as that understood by the inputrc parsing.
To configure completion, you need to modify the 'completion_function' value to be a reference to a function. The function should take three scalar parameters: the word being completed, the entire input text and the position within the input text of the word. The return result is expected to be a list of possible matches. An example usage is as follows:
my $attribs = $wheel->Attribs; $attribs->{completion_function} = sub { my ($text, $line, $start) = @_; return qw(a list of candidates to complete); }
This is the only form of completion currently supported.
Although modeled after the readline(3)
library, there are some areas
which have not been implemented. The only option settings which have
effect in this implementation are: bell-style, editing-mode,
isearch-terminators, comment-begin, print-completions-horizontally,
show-all-if-ambiguous and completion_function.
The function 'tab-insert' is not implemented, nor are tabs displayed properly.
POE::Wheel, readline(3), Term::ReadKey, Term::Visual.
The SEE ALSO section in POE contains a table of contents covering the entire POE distribution.
POE::Wheel::ReadLine has some known issues:
Non-blocking input with Term::ReadKey does not work with Perl 5.8.0. The problem usually appears on Linux systems. See: http://rt.cpan.org/Ticket/Display.html?id=4524 and all the tickets related to it.
If you suspect your system is one where Term::ReadKey fails, you can run this test program to be sure. If you can, upgrade Perl to fix it. If you can't upgrade Perl, consider alternative input methods, such as Term::Visual.
#!/usr/bin/perl use Term::ReadKey; print "Press 'q' to quit this test.\n"; ReadMode 5; # Turns off controls keys while (1) { while (not defined ($key = ReadKey(-1))) { print "Didn't get a key. Sleeping 1 second.\015\012"; sleep (1); } print "Got key: $key\015\012"; ($key eq 'q') and last; } ReadMode 0; # Reset tty mode before exiting exit;
Dissociating the input and display cursors introduced a lot of code. Much of this code was thrown in hastily, and things can probably be done with less work. To do: Apply some thought to what's already been done.
The screen should update as quickly as possible, especially on slow systems. Do little or no calculation during displaying; either put it all before or after the display. Do it consistently for each handled keystroke, so that certain pairs of editing commands don't have extra perceived latency.
Input editing is not kept on one line. If it wraps, and a terminal cannot wrap back through a line division, the cursor will become lost. This bites, and it's the next against the wall in my bug hunting.
Unicode, or at least European code pages. I feel real bad about throwing away native representation of all the 8th-bit-set characters. I also have no idea how to do this, and I don't have a system to test this. Patches are recommended.
Q: Why do I lose my ReadLine prompt every time I send output to the screen?
A: You probably are using print or printf to write screen output.
ReadLine doesn't track STDOUT itself, so it doesn't know when to
refresh the prompt after you do this. Use ReadLine's put()
method to
write lines to the console.
Q: None of the editing keystrokes work. Ctrl-C displays ``^c'' rather than generating an interrupt. The arrow keys don't scroll through my input history. It's generally a bad experience.
A: You're probably a vi/vim user. In the absence of a ~/.inputrc file, POE::Wheel::ReadLine checks your EDITOR environment variable for clues about your editing preference. If it sees /vi/ in there, it starts in vi mode. You can override this by creating a ~/.inputrc file containing the line ``set editing-mode emacs'', or adding that line to your existing ~/.inputrc. While you're in there, you should totally get acquainted with all the other cool stuff you can do with .inputrc files.
Rocco Caputo - Original author. Nick Williams - Heavy edits, making it gnu readline-alike.
Please see POE for more information about other authors and contributors.
POE::Wheel::ReadLine - prompted terminal input |