The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

POE::Wheel::ReadLine - prompted terminal input

SYNOPSIS

  # 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();

DESCRIPTION

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.

CONSTRUCTOR

new

new() creates a new wheel, returning the wheels reference.

PUBLIC METHODS

History List Management

addhistory LIST_OF_LINES

Adds a list of lines, presumably from previous input, into the ReadLine wheel's input history.

GetHistory

Returns the list of all currently known history lines.

WriteHistory FILE

writes the current history to FILENAME, overwriting FILENAME if necessary. If FILENAME is false, then write the history list to ~/.history. Returns true if successful, or false if not.

ReadHistory FILE FROM TO

adds the contents of FILENAME to the history list, a line at a time. If FILENAME is false, then read from ~/.history. Start reading at line FROM and end at TO. If FROM is omitted or zero, start at the beginning. If TO is omitted or less than FROM, then read until the end of the file. Returns true if successful, or false if not.

history_truncate_file FILE LINES

Truncate the number of lines within FILE to be at most that specified by LINES. FILE defaults to ~/.history. If LINES is not specified, then the history file is cleared.

Miscellaneous Methods

clear

Clears the terminal.

terminal_size

Returns what ReadLine thinks are the current dimensions of the terminal. The return value is a list of two elements: the number of columns and number of rows respectively.

get PROMPT

Provide a prompt and enable input. The wheel will display the prompt and begin paying attention to the console keyboard after this method is called. Once a line or an exception is returned, the wheel will resume its quiescent state wherein it ignores keystrokes.

The quiet period between input events gives a program the opportunity to change the prompt or process lines before the next one arrives.

put TEXT

Print the given text to the terminal.

Attribs

Returns a reference to a hash of options that can be configured to modify the readline behaviour.

bind_key KEY FN

Bind a function to a named key sequence. The key sequence can be in any of the forms defined within readline(3). The function should either be a pre-registered name such as 'self-insert', or it should be a reference to a function. The binding is made in the current keymap. If you wish to change keymaps, then use the rl_set_keymap method.

add_defun NAME FN

Create a new (global) function definition which may be then bound to a key.

option NAME

Returns the option named NAME or an empty string.

EVENTS AND PARAMETERS

InputEvent

InputEvent contains the name of the event that will be fired upon successful (or unsuccessful) terminal input. Every InputEvent handler receives two additional parameters, only one of which is ever defined at a time. 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.

PutMode

PutMode specifies how the wheel will display text when its 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.

IdleTime

IdleTime specifies how long the keyboard must be idle before put() becomes immediate or buffered text is flushed to the display. It is only meaningful when InputMode is "idle". IdleTime defaults to two seconds.

appname

Registers an application name which is used to get appl-specific keybindings from the .inputrc. If not defined, then the default value is 'poe-readline'. You may use this in a standard inputrc file to define application specific settings. For example:

  $if poe-readline
  # bind the following sequence in emacs mode
  set keymap emacs
  # display poe debug data
  Control-xP: poe-wheel-debug
  $endif

CUSTOM BINDINGS

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.

CUSTOM COMPLETION

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.

IMPLEMENTATION DIFFERENCES

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.

SEE ALSO

POE::Wheel, readline(3), Term::ReadKey, Term::Visual.

The SEE ALSO section in POE contains a table of contents covering the entire POE distribution.

BUGS

POE::Wheel::ReadLine has some known issues:

Perl 5.8.0 is Broken

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;

Non-optimal code2

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.

Unimplemented features

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.

GOTCHAS / FAQ

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.

Q: Why doesn't POE::Wheel::ReadLine work on Windows? Term::ReadLine does.

A: POE::Wheel::ReadLine requires select(), because that's what POE uses by default to detect keystrokes without blocking. About half the flavors of Perl on Windows implement select() in terms of the same function in the WinSock library, which limits select() to working only with sockets. Your console isn't a socket, so select() doesn't work with your version of Perl on Windows.

Really good workarounds are possible but don't exist as of this writing. They involve writing a special POE::Loop for Windows that either uses a Win32-specific module for better multiplexing, that polls for input, or that uses blocking I/O watchers in separate threads.

AUTHORS & COPYRIGHTS

Rocco Caputo - Original author. Nick Williams - Heavy edits, making it gnu readline-alike.

Please see POE for more information about other authors and contributors.