MAN page from RedHat EL 6 rlwrap-0.42-1.el6.x86_64.rpm


Section: User Contributed Perl Documentation (3pm)
Updated: 2014-09-11


RlwrapFilter - Perl class for rlwrap filters 


  use lib $ENV{RLWRAP_FILTERDIR};  use RlwrapFilter;  $filter = new RlwrapFilter;  $filter -> output_handler(sub {s/apple/orange/; $_}); # re-write output  $filter -> prompt_handler(\&pimp_the_prompt); # change prompt  $filter -> history_handler(sub {s/with password \w+/with password ****/; $_}); # keep passwords out of history  $filter -> run;


rlwrap (1) (<>) is a tinyutility that sits between the user and any console command, in orderto bestow readline capabilities (line editing, history recall) tocommands that don't have them.

Since version 0.32, rlwrap can use filters to script almost everyaspect of rlwrap's interaction with the user: changing the history,re-writing output and input, calling a pager or computing completionword lists from the current input.

RlwrapFilter makes it very simple to write rlwrapfilters in perl. A filter only needs to instantiate a RlwrapFilterobject, change a few of its default handlers and then call its 'run'method. 




$f = new RlwrapFilter
$f = RlwrapFilter -> new(prompt_handler => sub {Hi! > }, minimal_rlwrap_version => 0.35, ...)
Return a new RlwrapFilter object.


Handlers are user-defined callbacks that get called from the'run' method with a message (i.e. the un-filtered input,output, prompt) as their first argument. For convenience, $_ is set to the samevalue. They should return the re-written message text. They get calledin a fixed cyclic order: prompt, completion, history, input, echo,output, prompt, ... etc ad infinitum. Rlwrap may always skip a handler when in direct mode,on the other hand, completion and output handlers may get called morethan once in succession. If a handler is left undefined, the result isas if the message text were returned unaltered.

It is important to note that the filter, and hence all its handlers,are bypassed when command is in direct mode, i.e. when it asks forsingle keystrokes (and also, for security reasons, when it doesn'techo, e.g. when asking for a password). If you don't want this to happen, userlwrap -a to force rlwrap to remain in readline mode and toapply the filter to all of command's in- and output. This willmake editors and pagers (which respond to single keystrokes) unusable,unless you use rlwrap's -N option (linux only)

The getters/setters for the respective handlers are listed below:

$handler = $f -> prompt_handler, $f -> prompt_handler(\&handler)
The prompt handler re-writes prompts and gets called when rlwrapdecides it is time to ``cook'' the prompt, by default some 40 ms afterthe last output has arrived. Of course, rlwrap cannot read the mindof command, so what looks like a prompt to rlwrap may actuallybe the beginning of an output line that took command a littlelonger to formulate. If this is a problem, specify a longer ``cooking''time with rlwrap's -w option, use the prompts_are_never_emptymethod or ``reject'' the prompt (cf. the prompt_rejected method)
$handler = $f -> completion_handler, $f -> completion_handler(\&handler)
The completion handler gets called with the the entire input line, theprefix (partial word to complete), and rlwrap's own completion list asarguments. It should return a (possibly revised) list of completions. Asan example, suppose the user has typed ``She played forA<TAB>''. The handler will be called like this:

     myhandler("She played for A", "A", "Arsenal", "Arendal", "Anderlecht")

it could then return a list of stronger clubs: (``Ajax'', ``AZ67'', ``Arnhem'')

$handler = $f -> history_handler, $f -> history_handler(\&handler)
Every input line is submitted to this handler, the return value is putin rlwrap's history. Returning an empty or undefined value will keepthe input line out of the history.
$handler = $f -> input_handler, $f -> input_handler(\&handler)
Every input line is submitted to this handler, The handler's returnvalue is written to command's pty (pseudo-terminal).
$handler = $f -> echo_handler, $f -> echo_handler(\&handler)
The first line of output that is read back from command's pty isthe echo'ed input line. If your input handler alters the input line,it is the altered input that will be echo'ed back. If you don't wantto confuse the user, use an echo handler that returns your originalinput.

If you use rlwrap in --multi-line mode, additional echo lines willhave to be handled by the output handler

$handler = $f -> output_handler, $f -> output_handler(\&handler)
All command output after the echo line is submitted to the outputhandler (including newlines). This handler may get called many times in succession,dependent on the size of command's write() calls, and the whims ofyour system's scheduler. Therefore your handler should be prepared torewrite your output in ``chunks'', where you even don't have theguarantee that the chunks contain entire unbroken lines.

If you want to handle command's entire output in one go, you canspecify an output handler that returns an empty string, and then use$filter -> cumulative_output in your prompt handler to send there-written output ``out-of-band'' just before the prompt:

    $filter -> output_handler(sub {""});    $filter -> prompt_handler(                  sub{ $filter -> send_output_oob(mysub($filter -> cumulative_output));                       "Hi there > "                     });

Note that when rlwrap is run in --multi-line mode the echo handler will stillonly handle the first echo line. The remainder will generallybe echoed back preceded by a continuation prompt; it is up to theoutput handler what to do with it.

$handler = $f -> message_handler, $f -> message_handler(\&handler)
This handler gets called (as handler($message, $tag)) for everyincoming message, and every tag (including out-of-band tags), beforeall other handlers. Its return value is ignored, but it may be usefulfor logging and debugging purposes. The $tag is an integer that can beconverted to a tag name by the 'tag2name' method


$f -> help_text(Usage...)
Set the help text for this filter. It will be displayed by rlwrap -z<filter>. The second line of the help text is used by "rlwrap -z listing";it should be a short description of what the filter does.
$f -> minimal_rlwrap_version(x.yy)
Die unless rlwrap is version x.yy or newer
$dir = $f -> cwd
return the name of command's current working directory. This usesthe /proc filesystem, and may only work on newer linux systems (onolder linux and on Solaris, it will return something like``/proc/12345/cwd'', useful to find the contents of command's workingdirectory, but not its name)
$text = $f -> cumulative_output
return the current cumulative output. All (untreated) output getsappended to the cumulative output after the output_handler has beencalled. The cumulative output starts with a fresh slate with everyOUTPUT message that directly follows an INPUT message (ignoring out-of-bandmessages and rejected prompts)

When necessary (i.e. when rlwrap is in ``impatient mode'') the promptis removed from $filter->cumulative_output by the time the prompthandler is called.

$tag = $f -> previous_tag
The tag of the last preceding in-band message. A tag is an integer between 0 and255, its name can be found with the following method:
$name = $f -> tag2name($tag)
Convert the tag (an integer) to its name (e.g. ``TAG_PROMPT'')
$name = $f -> name2tag($tag)
Convert a valid tag name like ``TAG_PROMPT'' to a tag (an integer)
$f -> send_output_oob($text)
Make rlwrap display $text. $text is sent ``out-of-band'':rlwrap will not see it until just after it has sent the nextmessage to the filter
$f -> send_ignore_oob($text)
Send an out-of-band TAG_IGNORE message to rlwrap. rlwrap will silentlydiscard it, but it can be useful when debugging filters
$f -> add_to_completion_list(@words)
$f -> remove_from_completion_list(@words)
Permanently add or remove the words in @words to/from rlwrap's completion list.
$f -> cloak_and_dagger($question, $prompt, $timeout);
Send $question to command's input and read back everything thatcomes back until $prompt is seen at ``end-of-chunk'', or no newchunks arrive for $timeout seconds, whichever comes first. Return theresponse (without the final $prompt). rlwrap remains completelyunaware of this conversation.
$f -> cloak_and_dagger_verbose($verbosity)
If $verbosity evaluates to a true value, make rlwrap print allquestions sent to command by the "cloak_and_dagger" method, andcommand's responses. By default, $verbosity = 0; setting it to1 will mess up the screen but greatly facilitate the (otherwise rather tricky) use of"cloak_and_dagger"
$self -> prompt_rejected
A special text (``_THIS_CANNOT_BE_A_PROMPT_'') to be returned by aprompt handler to ``reject'' the prompt. This will make rlwrap skipcooking the prompt. $self->previous_tag and $self->cumulative_outputwill not be touched.
$text = $f -> prompts_are_never_empty($val)
If $val evaluates to a true value, automatically reject empty prompts.
$f -> command_line
In scalar context: the rlwrapped command and its arguments as a string (``command -v blah'')in list context: the same as a list (``command'', ``-v'', ``blah'')
$f -> running_under_rlwrap
Whether the filter is run by rlwrap, or directly from the command line
$f -> run
Start an event loop that reads rlwrap's messages from the input pipe,calls the appropriate handlers and writes the result to the outputpipe. This method never returns.


rlwrap communicates with a filter through messages consisting of a tagbyte (TAG_OUTPUT, TAG_PROMPT etc. - to inform the filter of what isbeing sent), an unsigned 32-bit integer containing the length of themessage, the message text and an extra newline. For every messagesent, rlwrap expects, and waits for an answer message with the sametag. Sending back a different (in-band) tag is an error and instantlykills rlwrap, though filters may precede their answer message with``out-of-band'' messages to output text (TAG_OUTPUT_OUT_OF_BAND), reporterrors (TAG_ERROR), and to manipulate the completion word list(TAG_ADD_TO_COMPLETION_LIST and TAG_REMOVE_FROM_COMPLETION_LIST)Out-of-band messages are not serviced by rlwrap until right afterit has sent the next in-band message - the communication with thefilter is synchronous and driven by rlwrap.

Messages are received and sent via two pipes. STDIN, STDOUT and STDERRare still connected to the user's terminal, and you can read and writethem directly, though this may mess up the screen and confuse the userunless you are careful. A filter can even communicate with therlwrapped command behind rlwrap's back (cf the cloak_and_dagger()method)

The protocol uses the following tags (tags > 128 are out-of-band)

 TAG_INPUT       0 TAG_OUTPUT      1 TAG_HISTORY     2 TAG_COMPLETION  3 TAG_PROMPT      4 TAG_IGNORE                      251 TAG_ADD_TO_COMPLETION_LIST      252 TAG_REMOVE_FROM_COMPLETION_LIST 253 TAG_OUTPUT_OUT_OF_BAND          254 TAG_ERROR                       255

To see how this works, you can eavesdrop on the protocolusing the 'logger' filter.

The constants TAG_INPUT, ... are exported by the module. 


As STDIN is still connected to the users teminal, one might expect the filterto receive SIGINT, SIGTERM, SIGTSTP directly from the terminal driver ifthe user presses CTRL-C, CTRL-Z etc Normally, we don't want this - itwould confuse rlwrap, and the user (who thinks she is talking straightto the rlwapped command) probably meant those signals to be sent tothe command itself. For this reason the filter starts with all signals blocked.

Filters that interact with the users terminal (e.g. to run a pager)should unblock signals like SIGTERM, SIGWINCH. 


The filter is started by rlwrap after command, and stays aliveas long as rlwrap runs. Filter methods are immediately usable. Whencommand exits, the filter stays around for a little longer in orderto process command's last words. As calling the cwd andcloak_and_dagger methods at that time will make the filter die with anerror, it may be advisable to wrap those calls in eval{}

If a filter calls die() it will send an (out-of-band) TAG_ERRORmessage to rlwrap before exiting. rlwrap will then report the messageand exit (just after its next in-band message - out-of-band messagesare not always processed immediately)

die() within an eval() sets $@ as usual. 


Before calling a filter, rlwrap sets the following environment variables:

    RLWRAP_FILTERDIR      directory where and most filters live (set by B<rlwrap>, can be                          overridden by the user before calling rlwrap)    PATH                  rlwrap automatically adds $RLWRAP_FILTERDIR to the front of filter's PATH    RLWRAP_VERSION        rlwrap version (e.g. "0.35")    RLWRAP_COMMAND_PID    process ID of the rlwrapped command    RLWRAP_COMMAND_LINE   command line of the rlwrapped command    RLWRAP_IMPATIENT      whether rlwrap is in "impatient mode" (cf B<rlwrap (1)>). In impatient mode,                          the candidate prompt is filtered through the output handler (and displayed before                          being overwritten by the cooked prompt).    RLWRAP_INPUT_PIPE_FD  File descriptor of input pipe. For internal use only    RLWRAP_OUTPUT_PIPE_FD File descriptor of output pipe. For internal use only    RLWRAP_MASTER_PTY_FD File descriptor of I<command>'s pty.


While makes it easy to write simple filters, debuggingthem can be a problem. A couple of useful tricks: 


When running a filter, the in- and outgoing messages can be logged bythe logger filter, using a pipeline:

  rlwrap -z 'pipeline logger incoming : my_filter : logger outgoing' command


When called by rlwrap, filters get their input from $RLWRAP_INPUT_PIPE_FD and write their output to$RLWRAP_OUTPUT_PIPE_FD, and expect and write messages consisting of atag byte, a 32-bit length and the message proper. This is not terriblyuseful when running a filter directly from the command line (outsiderlwrap), even if we set the RLWRAP_*_FD ourselves.

Therefore, when run directly from the command line, a filter expectsinput messages on its standard input of the form

TAG_PROMPT myprompt >

(i.a. a tag name, one space and a message followed by a newline) and it will respond in thesame way on its standard output 


rlwrap (1), readline (3)




This document was created byman2html,using the manual pages.