My Favorite Modules:
Term::ReadLine is a core module (since Perl 5.002) that provides an extremely limited text interface of the prompt-and-type variety. Its main virtue is that you can add a back end which gives it things like command history, editing, and completion.
The back ends live in the
Term::ReadLine::* name space, and you can control which one you get by defining the
PERL_RL environment variable as documented at
Term::ReadLine. If this is not defined, various undocumented things are tried; if none works you get the bundled minimal interface,
The preferred back end (at least, according to
Bundle::CPAN as of this writing) is
Term::ReadLine::Perl. This is a shy, retiring module, with no POD documentation at all, which provides readline-style history, editing, and completion. By default the only completion you get is file name completion, but with some work you can expand this to do whatever you can figure out.
At this point, some words of caution are probably in order.
Term::ReadLine::Perl is itself a wrapper for
Term::ReadLine::readline, which is partially-converted Perl 4, undocumented except for comments in the code. The copy in my Perl 5.34.0 installation is dated October 28 2009.
The comments in the code seem to assume a public interface documented elsewhere, but I have not been able to find any documentation specific to Perl. They also speak of certain facilities being available to code outside the module. It is those facilities (or some of them) that are the subject of the remainder of this note.
The key to customizing completion is to provide your own completion code by placing a reference to it into
$readline::rl_completion_function. The comments specify a symbolic reference (that is, the fully-qualified name of the routine), and that is what the
CPAN module does, but I believe a
CODE reference will work as well, at least in any semi-modern Perl. Note that unless you localize, this will affect all readline operations in the entire script.
Your completion code will be called with three arguments:
$text (the word being completed),
$line (the input line as it stood when completion was invoked), and
$start (the position of the start of the word being completed). Your code returns a list of possible completions. If there is only one, it will be used to complete the word; if more than one they will be displayed as possible completions. Note that your completions can be anything; there is no requirement that their initial characters match the word being completed.
If your completion code ends up returning only one completion, the contents of
$readline::rl_completer_terminator_character will be appended to it. Before your completion code is called this is initialized to a single space. You can change this to whatever you like. I like to change it to
'' (the empty string) when doing file name completion if the file name ends in
'/'. Note that you do not localize this before changing it; if you do, your change will be lost when you return from your completion code.
Completion of the first token is easy: the already-typed portion of it is in
0. If you are completing a subsequent token, you may have to pick apart
$line to determine what completions are possible.
Term::ReadLine::Perl's view of what characters cause word breaks is available in
$readline::rl_completer_word_break_characters, should you decide to use it. You could delegate the actual splitting of
Text::ParseWords, but if you do you will need to allow for the possibility that the line being completed may have unclosed quotes.